4 * Copyright (C) 1997-2011 Adam Williams <broadcast at earthling dot net>
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
22 #include "bcdisplayinfo.h"
23 #include "bcsignals.h"
25 #include "histogram.h"
26 #include "histogramconfig.h"
27 #include "histogramwindow.h"
37 HistogramWindow::HistogramWindow(HistogramMain *plugin)
38 : PluginClientWindow(plugin,
45 this->plugin = plugin;
49 HistogramWindow::~HistogramWindow()
54 void HistogramWindow::create_objects()
56 int margin = plugin->get_theme()->widget_border;
57 int x = margin, y = margin, x1 = margin;
59 add_subwindow(mode_v = new HistogramMode(plugin,
64 x += mode_v->get_w() + margin;
65 add_subwindow(mode_r = new HistogramMode(plugin,
70 x += mode_r->get_w() + margin;
71 add_subwindow(mode_g = new HistogramMode(plugin,
76 x += mode_g->get_w() + margin;
77 add_subwindow(mode_b = new HistogramMode(plugin,
84 x = get_w() - margin - plugin->get_theme()->get_image_set("histogram_rgb_toggle")[0]->get_w();
85 add_subwindow(parade_on = new HistogramParade(plugin,
90 x -= parade_on->get_w() + margin;
91 add_subwindow(parade_off = new HistogramParade(plugin,
99 y += parade_on->get_h() + margin;
100 add_subwindow(canvas_title1 = new BC_Title(margin,
103 add_subwindow(canvas_title2 = new BC_Title(get_w() - get_text_width(MEDIUMFONT, "110%") - margin,
107 y += canvas_title2->get_h() + margin;
109 canvas_h = get_h() - y - yS(210);
112 add_subwindow(low_input_carrot = new HistogramCarrot(plugin,
117 x = low_input_carrot->get_w() / 2 + x;
118 canvas_w = get_w() - x - x;
121 title2_x = x + (int)(canvas_w * -HIST_MIN_INPUT / FLOAT_RANGE);
122 title3_x = x + (int)(canvas_w * (1.0 - HIST_MIN_INPUT) / FLOAT_RANGE);
123 title4_x = x + (int)(canvas_w);
129 add_subwindow(canvas = new HistogramCanvas(plugin,
137 draw_3d_border(x - 2,
146 // Calculate output curve with no value function
147 plugin->tabulate_curve(plugin->mode, 0);
149 y += canvas->get_h();
152 add_subwindow(gamma_carrot = new HistogramCarrot(plugin,
155 canvas->get_w() / 2 -
156 low_input_carrot->get_w() / 2 ,
159 add_subwindow(high_input_carrot = new HistogramCarrot(plugin,
163 low_input_carrot->get_w() / 2,
165 y += low_input_carrot->get_h() + margin;
168 // add_subwindow(title = new BC_Title(x, y, _("Input:")));
169 // x += title->get_w() + margin;
170 low_input = new HistogramText(plugin, this, x, y);
171 low_input->create_objects();
173 x = get_w() / 2 - low_input->get_w() / 2;
174 gamma = new HistogramText(plugin, this, x, y, 0.01, 100.);
175 gamma->create_objects();
177 x = get_w() - low_input->get_w() - margin;
178 high_input = new HistogramText(plugin, this, x, y);
179 high_input->create_objects();
181 y += high_input->get_h() + margin;
184 add_subwindow(output = new HistogramSlider(plugin, this,
185 canvas->get_x(), y, canvas->get_w(), yS(20), 0));
189 draw_3d_border(output->get_x() - 2, output->get_y() - 2,
190 output->get_w() + 4, output->get_h() + 4,
191 get_bg_color(), BLACK, MDGREY, get_bg_color());
192 y += output->get_h();
194 add_subwindow(low_output_carrot = new HistogramCarrot(plugin,
197 add_subwindow(high_output_carrot = new HistogramCarrot(plugin,
198 this, canvas->get_x() + canvas->get_w() -
199 low_output_carrot->get_w() / 2, y));
200 y += high_output_carrot->get_h() + margin;
202 // add_subwindow(title = new BC_Title(x, y, _("Output:")));
203 // x += title->get_w() + margin;
204 low_output = new HistogramText(plugin, this, x, y);
205 low_output->create_objects();
206 high_output = new HistogramText(plugin, this,
207 get_w() - low_output->get_w() - margin, y);
208 high_output->create_objects();
211 y += high_output->get_h() + margin;
213 add_subwindow(bar = new BC_Bar(x, y, get_w() - margin * 2));
214 y += bar->get_h() + margin;
216 add_subwindow(automatic = new HistogramAuto(plugin, x, y));
220 add_subwindow(threshold_title = new BC_Title(x, y, _("Threshold:")));
221 x += threshold_title->get_w() + margin;
222 threshold = new HistogramText(plugin, this, x, y);
223 threshold->create_objects();
226 add_subwindow(reset = new HistogramReset(plugin,
227 x, y + threshold->get_h() + margin));
230 y += automatic->get_h() + margin;
231 add_subwindow(plot = new HistogramPlot(plugin, x, y));
233 y += plot->get_h() + yS(5);
234 add_subwindow(split = new HistogramSplit(plugin, x, y));
244 int HistogramWindow::resize_event(int w, int h)
246 int xdiff = w - get_w();
247 int ydiff = h - get_h();
249 parade_on->reposition_window(parade_on->get_x() + xdiff,
251 parade_off->reposition_window(parade_off->get_x() + xdiff,
253 canvas_title2->reposition_window(canvas_title2->get_x() + xdiff,
254 canvas_title2->get_y());
256 // Canvas follows window size
257 canvas_w = canvas_w + xdiff;
258 canvas_h = canvas_h + ydiff;
259 canvas->reposition_window(canvas->get_x(),
265 draw_3d_border(canvas->get_x() - 2,
274 low_input_carrot->reposition_window(low_input_carrot->get_x(),
275 low_input_carrot->get_y() + ydiff);
276 gamma_carrot->reposition_window(gamma_carrot->get_x(),
277 gamma_carrot->get_y() + ydiff);
278 high_input_carrot->reposition_window(high_input_carrot->get_x(),
279 high_input_carrot->get_y() + ydiff);
281 low_input->reposition_window(low_input->get_x(),
282 low_input->get_y() + ydiff);
283 gamma->reposition_window(w / 2 - gamma->get_w() / 2,
284 gamma->get_y() + ydiff);
285 high_input->reposition_window(high_input->get_x() + xdiff,
286 low_input->get_y() + ydiff);
288 output->reposition_window(output->get_x(),
289 output->get_y() + ydiff,
290 output->get_w() + xdiff,
295 draw_3d_border(output->get_x() - 2,
304 low_output_carrot->reposition_window(low_output_carrot->get_x(),
305 low_output_carrot->get_y() + ydiff);
306 high_output_carrot->reposition_window(high_output_carrot->get_x(),
307 high_output_carrot->get_y() + ydiff);
309 low_output->reposition_window(low_output->get_x(),
310 low_output->get_y() + ydiff);
311 high_output->reposition_window(high_output->get_x() + xdiff,
312 high_output->get_y() + ydiff);
314 bar->reposition_window(bar->get_x(),
315 bar->get_y() + ydiff,
316 bar->get_w() + xdiff);
318 automatic->reposition_window(automatic->get_x(),
319 automatic->get_y() + ydiff);
320 threshold_title->reposition_window(threshold_title->get_x(),
321 threshold_title->get_y() + ydiff);
322 threshold->reposition_window(threshold->get_x(),
323 threshold->get_y() + ydiff);
324 reset->reposition_window(reset->get_x(),
325 reset->get_y() + ydiff);
327 plot->reposition_window(plot->get_x(),
328 plot->get_y() + ydiff);
329 split->reposition_window(split->get_x(),
330 split->get_y() + ydiff);
342 int HistogramWindow::keypress_event()
349 for(int i = 0; i < HISTOGRAM_MODES; i++)
351 if(active_value == &plugin->config.gamma[i])
355 if(get_keypress() == RIGHT || get_keypress() == UP)
357 *active_value += sign * PRECISION;
358 plugin->config.boundaries();
360 plugin->send_configure_change();
364 if(get_keypress() == LEFT || get_keypress() == DOWN)
366 *active_value -= sign * PRECISION;
367 plugin->config.boundaries();
369 plugin->send_configure_change();
377 void HistogramWindow::update(int do_canvases,
384 automatic->update(plugin->config.automatic);
385 mode_v->update(plugin->mode == HISTOGRAM_VALUE ? 1 : 0);
386 mode_r->update(plugin->mode == HISTOGRAM_RED ? 1 : 0);
387 mode_g->update(plugin->mode == HISTOGRAM_GREEN ? 1 : 0);
388 mode_b->update(plugin->mode == HISTOGRAM_BLUE ? 1 : 0);
389 plot->update(plugin->config.plot);
390 split->update(plugin->config.split);
391 parade_on->update(plugin->parade ? 1 : 0);
392 parade_off->update(plugin->parade ? 0 : 1);
403 low_input_carrot->update();
404 high_input_carrot->update();
405 gamma_carrot->update();
406 low_output_carrot->update();
407 high_output_carrot->update();
414 high_input->update();
415 low_output->update();
416 high_output->update();
424 void HistogramWindow::draw_canvas_mode(int mode, int color, int y, int h)
426 int *accum = plugin->accum[mode];
427 int accum_per_canvas_i = HISTOGRAM_SLOTS / canvas_w + 1;
428 float accum_per_canvas_f = (float)HISTOGRAM_SLOTS / canvas_w;
434 for(int i = 0; i < HISTOGRAM_SLOTS; i++)
436 if(accum && accum[i] > normalize) normalize = accum[i];
442 for(int i = 0; i < canvas_w; i++)
444 int accum_start = (int)(accum_per_canvas_f * i);
445 int accum_end = accum_start + accum_per_canvas_i;
447 for(int j = accum_start; j < accum_end; j++)
449 max = MAX(accum[j], max);
452 // max = max * h / normalize;
453 max = (int)(log(max) / log(normalize) * h);
455 canvas->set_color(BLACK);
456 canvas->draw_line(i, y, i, y + h - max);
457 canvas->set_color(color);
458 canvas->draw_line(i, y + h - max, i, y + h);
463 canvas->set_color(BLACK);
464 canvas->draw_box(0, y, canvas_w, h);
468 canvas->set_color(WHITE);
469 canvas->set_line_width(2);
473 for(int i = 0; i < canvas_w; i++)
475 float input = (float)i /
479 float output = plugin->calculate_level(input,
483 int y2 = h - (int)(output * h);
486 canvas->draw_line(i - 1, y + y1, i, y + y2);
491 canvas->set_line_width(1);
496 void HistogramWindow::update_canvas()
500 draw_canvas_mode(HISTOGRAM_RED, RED, 0, canvas_h / 3);
501 draw_canvas_mode(HISTOGRAM_GREEN, GREEN, canvas_h / 3, canvas_h / 3);
502 draw_canvas_mode(HISTOGRAM_BLUE, BLUE, canvas_h * 2 / 3, canvas_h - canvas_h * 2 / 3);
506 draw_canvas_mode(plugin->mode, MEGREY, 0, canvas_h);
510 // Draw 0 and 100% lines.
511 canvas->set_color(RED);
512 int x = (int)(canvas_w * -HIST_MIN_INPUT / FLOAT_RANGE);
517 x = (int)(canvas_w * (1.0 - HIST_MIN_INPUT) / FLOAT_RANGE);
528 HistogramParade::HistogramParade(HistogramMain *plugin,
529 HistogramWindow *gui,
535 value ? plugin->get_theme()->get_image_set("histogram_rgb_toggle") :
536 plugin->get_theme()->get_image_set("histogram_toggle"),
539 this->plugin = plugin;
543 set_tooltip(_("RGB Parade on"));
545 set_tooltip(_("RGB Parade off"));
548 int HistogramParade::handle_event()
551 plugin->parade = value;
565 HistogramCanvas::HistogramCanvas(HistogramMain *plugin,
566 HistogramWindow *gui,
577 this->plugin = plugin;
581 int HistogramCanvas::button_press_event()
584 if(is_event_win() && cursor_inside())
586 if(!plugin->dragging_point &&
587 (!plugin->config.automatic || plugin->mode == HISTOGRAM_VALUE))
595 int HistogramCanvas::cursor_motion_event()
597 if(is_event_win() && cursor_inside())
603 int HistogramCanvas::button_release_event()
621 HistogramReset::HistogramReset(HistogramMain *plugin,
624 : BC_GenericButton(x, y, _("Reset"))
626 this->plugin = plugin;
628 int HistogramReset::handle_event()
630 plugin->config.reset(0);
631 ((HistogramWindow*)plugin->thread->window)->update(1, 1, 1, 1);
632 plugin->send_configure_change();
642 HistogramCarrot::HistogramCarrot(HistogramMain *plugin,
643 HistogramWindow *gui,
648 plugin->get_theme()->get_image_set("histogram_carrot"),
651 this->plugin = plugin;
656 HistogramCarrot::~HistogramCarrot()
660 float* HistogramCarrot::get_value()
662 if(this == gui->low_input_carrot)
664 return &plugin->config.low_input[plugin->mode];
667 if(this == gui->high_input_carrot)
669 return &plugin->config.high_input[plugin->mode];
672 if(this == gui->gamma_carrot)
674 return &plugin->config.gamma[plugin->mode];
677 if(this == gui->low_output_carrot)
679 return &plugin->config.low_output[plugin->mode];
682 if(this == gui->high_output_carrot)
684 return &plugin->config.high_output[plugin->mode];
689 void HistogramCarrot::update()
692 float *value = get_value();
694 if(this != gui->gamma_carrot)
696 new_x = (int)(gui->canvas->get_x() +
697 (*value - HIST_MIN_INPUT) *
698 gui->canvas->get_w() /
699 (HIST_MAX_INPUT - HIST_MIN_INPUT) -
704 float min = plugin->config.low_input[plugin->mode];
705 float max = plugin->config.high_input[plugin->mode];
706 float delta = (max - min) / 2.0;
707 float mid = min + delta;
708 float tmp = log10(1.0 / *value);
709 tmp = mid + delta * tmp;
711 //printf("HistogramCarrot::update %d %f %f\n", __LINE__, *value, tmp);
713 new_x = gui->canvas->get_x() -
715 (int)(gui->canvas->get_w() *
716 (tmp - HIST_MIN_INPUT) /
717 (HIST_MAX_INPUT - HIST_MIN_INPUT));
720 reposition_window(new_x, get_y());
723 int HistogramCarrot::button_press_event()
725 if(is_event_win() && get_buttonpress() == 1)
729 set_status(BC_Toggle::TOGGLE_DOWN);
731 BC_Toggle::update(0);
732 gui->active_value = get_value();
733 // Disable the other toggles
734 if(this != gui->low_input_carrot) gui->low_input_carrot->BC_Toggle::update(0);
735 if(this != gui->high_input_carrot) gui->high_input_carrot->BC_Toggle::update(0);
736 if(this != gui->gamma_carrot) gui->gamma_carrot->BC_Toggle::update(0);
737 if(this != gui->low_output_carrot) gui->low_output_carrot->BC_Toggle::update(0);
738 if(this != gui->high_output_carrot) gui->high_output_carrot->BC_Toggle::update(0);
739 starting_x = get_x();
740 offset_x = gui->get_relative_cursor_x();
741 offset_y = gui->get_relative_cursor_y();
742 //printf("HistogramCarrot::button_press_event %d %d %d\n", __LINE__, starting_x, offset_x);
750 int HistogramCarrot::button_release_event()
752 int result = BC_Toggle::button_release_event();
758 int HistogramCarrot::cursor_motion_event()
760 int cursor_x = gui->get_relative_cursor_x();
764 //printf("HistogramCarrot::cursor_motion_event %d %d\n", __LINE__, cursor_x);
765 int new_x = starting_x + cursor_x - offset_x;
769 float *value = get_value();
770 if(this == gui->gamma_carrot)
772 float min = gui->low_input_carrot->get_x();
773 float max = gui->high_input_carrot->get_x();
774 float delta = (max - min) / 2.0;
777 float mid = min + delta;
778 float tmp = (float)(new_x - mid) /
780 tmp = 1.0 / pow(10, tmp);
781 CLAMP(tmp, MIN_GAMMA, MAX_GAMMA);
783 //printf("HistogramCarrot::update %d %f\n", __LINE__, tmp);
788 int min_x = gui->canvas->get_x() - get_w() / 2;
789 int max_x = gui->canvas->get_x() + gui->canvas->get_w() - get_w() / 2;
790 CLAMP(new_x, min_x, max_x);
791 *value = HIST_MIN_INPUT +
792 (HIST_MAX_INPUT - HIST_MIN_INPUT) *
797 reposition_window(new_x, get_y());
801 (this == gui->low_input_carrot || this == gui->high_input_carrot),
804 plugin->send_configure_change();
818 HistogramSlider::HistogramSlider(HistogramMain *plugin,
819 HistogramWindow *gui,
825 : BC_SubWindow(x, y, w, h)
827 this->plugin = plugin;
829 this->is_input = is_input;
833 int HistogramSlider::input_to_pixel(float input)
835 return (int)((input - HIST_MIN_INPUT) / FLOAT_RANGE * get_w());
838 void HistogramSlider::update()
842 //int half_h = get_h() / 2;
843 //int quarter_h = get_h() / 4;
844 int mode = plugin->mode;
849 clear_box(0, 0, w, h);
856 case HISTOGRAM_GREEN:
864 for(int i = 0; i < w; i++)
866 int color = (int)(i * 0xff / w);
867 set_color(((r * color / 0xff) << 16) |
868 ((g * color / 0xff) << 8) |
871 draw_line(i, 0, i, h);
886 HistogramAuto::HistogramAuto(HistogramMain *plugin,
889 : BC_CheckBox(x, y, plugin->config.automatic, _("Automatic"))
891 this->plugin = plugin;
894 int HistogramAuto::handle_event()
896 plugin->config.automatic = get_value();
897 plugin->send_configure_change();
904 HistogramPlot::HistogramPlot(HistogramMain *plugin,
907 : BC_CheckBox(x, y, plugin->config.plot, _("Plot histogram"))
909 this->plugin = plugin;
912 int HistogramPlot::handle_event()
914 plugin->config.plot = get_value();
915 plugin->send_configure_change();
922 HistogramSplit::HistogramSplit(HistogramMain *plugin,
925 : BC_CheckBox(x, y, plugin->config.split, _("Split output"))
927 this->plugin = plugin;
930 int HistogramSplit::handle_event()
932 plugin->config.split = get_value();
933 plugin->send_configure_change();
939 HistogramMode::HistogramMode(HistogramMain *plugin,
944 : BC_Radial(x, y, plugin->mode == value, text)
946 this->plugin = plugin;
949 int HistogramMode::handle_event()
951 HistogramWindow *gui = (HistogramWindow*)plugin->thread->window;
952 plugin->mode = value;
953 plugin->current_point= -1;
954 gui->active_value = 0;
955 gui->low_input_carrot->BC_Toggle::update(0);
956 gui->gamma_carrot->BC_Toggle::update(0);
957 gui->high_input_carrot->BC_Toggle::update(0);
958 gui->low_output_carrot->BC_Toggle::update(0);
959 gui->high_output_carrot->BC_Toggle::update(0);
960 gui->update(1, 1, 1, 1);
961 // plugin->send_configure_change();
974 HistogramText::HistogramText(HistogramMain *plugin,
975 HistogramWindow *gui, int x, int y, float hist_min, float hist_max)
976 : BC_TumbleTextBox(gui, 0.0, hist_min, hist_max, x, y, xS(70))
978 this->plugin = plugin;
980 set_precision(DIGITS);
981 set_increment(PRECISION);
984 float* HistogramText::get_value()
986 if(this == gui->low_input)
988 return &plugin->config.low_input[plugin->mode];
991 if(this == gui->high_input)
993 return &plugin->config.high_input[plugin->mode];
996 if(this == gui->gamma)
998 return &plugin->config.gamma[plugin->mode];
1001 if(this == gui->low_output)
1003 return &plugin->config.low_output[plugin->mode];
1006 if(this == gui->high_output)
1008 return &plugin->config.high_output[plugin->mode];
1011 if(this == gui->threshold)
1013 return &plugin->config.threshold;
1019 int HistogramText::handle_event()
1021 float *output = get_value();
1024 *output = atof(get_text());
1027 gui->update(1, 1, 0, 0);
1028 plugin->send_configure_change();
1032 void HistogramText::update()
1034 float *output = get_value();
1037 BC_TumbleTextBox::update(*output);