1 #include "bcdisplayinfo.h"
5 #include "histogramconfig.h"
6 #include "histogramwindow.h"
13 PLUGIN_THREAD_OBJECT(HistogramMain, HistogramThread, HistogramWindow)
17 HistogramWindow::HistogramWindow(HistogramMain *plugin, int x, int y)
18 : BC_Window(plugin->gui_string,
29 this->plugin = plugin;
32 HistogramWindow::~HistogramWindow()
36 #include "max_picon_png.h"
37 #include "mid_picon_png.h"
38 #include "min_picon_png.h"
39 static VFrame max_picon_image(max_picon_png);
40 static VFrame mid_picon_image(mid_picon_png);
41 static VFrame min_picon_image(min_picon_png);
43 int HistogramWindow::create_objects()
45 int x = 10, y = 10, x1 = 10;
48 max_picon = new BC_Pixmap(this, &max_picon_image);
49 mid_picon = new BC_Pixmap(this, &mid_picon_image);
50 min_picon = new BC_Pixmap(this, &min_picon_image);
51 add_subwindow(mode_v = new HistogramMode(plugin,
57 add_subwindow(mode_r = new HistogramMode(plugin,
63 add_subwindow(mode_g = new HistogramMode(plugin,
69 add_subwindow(mode_b = new HistogramMode(plugin,
75 // add_subwindow(mode_a = new HistogramMode(plugin,
83 add_subwindow(title = new BC_Title(x, y, _("Input X:")));
84 x += title->get_w() + 10;
85 input_x = new HistogramInputText(plugin,
90 input_x->create_objects();
92 x += input_x->get_w() + 10;
93 add_subwindow(title = new BC_Title(x, y, _("Input Y:")));
94 x += title->get_w() + 10;
95 input_y = new HistogramInputText(plugin,
100 input_y->create_objects();
105 canvas_w = get_w() - x - x;
106 canvas_h = get_h() - y - 190;
108 title2_x = x + (int)(canvas_w * -MIN_INPUT / FLOAT_RANGE);
109 title3_x = x + (int)(canvas_w * (1.0 - MIN_INPUT) / FLOAT_RANGE);
110 title4_x = x + (int)(canvas_w);
111 add_subwindow(canvas = new HistogramCanvas(plugin,
117 // Calculate output curve with no value function
118 plugin->tabulate_curve(plugin->mode, 0);
119 draw_canvas_overlay();
122 y += canvas->get_h() + 1;
123 add_subwindow(new BC_Title(title1_x,
126 add_subwindow(new BC_Title(title2_x,
129 add_subwindow(new BC_Title(title3_x - get_text_width(MEDIUMFONT, "100"),
132 add_subwindow(new BC_Title(title4_x - get_text_width(MEDIUMFONT, "110"),
137 add_subwindow(title = new BC_Title(x, y, _("Output min:")));
138 x += title->get_w() + 10;
139 output_min = new HistogramOutputText(plugin,
143 &plugin->config.output_min[plugin->mode]);
144 output_min->create_objects();
145 x += output_min->get_w() + 10;
146 add_subwindow(new BC_Title(x, y, _("Output Max:")));
147 x += title->get_w() + 10;
148 output_max = new HistogramOutputText(plugin,
152 &plugin->config.output_max[plugin->mode]);
153 output_max->create_objects();
158 add_subwindow(output = new HistogramSlider(plugin,
169 add_subwindow(automatic = new HistogramAuto(plugin,
174 add_subwindow(new HistogramReset(plugin,
178 add_subwindow(new BC_Title(x, y, _("Threshold:")));
180 threshold = new HistogramOutputText(plugin,
184 &plugin->config.threshold);
185 threshold->create_objects();
189 add_subwindow(plot = new HistogramPlot(plugin,
193 y += plot->get_h() + 5;
194 add_subwindow(split = new HistogramSplit(plugin,
204 WINDOW_CLOSE_EVENT(HistogramWindow)
206 int HistogramWindow::keypress_event()
209 if(get_keypress() == BACKSPACE ||
210 get_keypress() == DELETE)
212 if(plugin->current_point >= 0)
214 HistogramPoint *current =
215 plugin->config.points[plugin->mode].get_item_number(plugin->current_point);
217 plugin->current_point = -1;
220 plugin->send_configure_change();
227 void HistogramWindow::update(int do_input)
229 automatic->update(plugin->config.automatic);
230 threshold->update(plugin->config.threshold);
233 if(do_input) update_input();
237 void HistogramWindow::update_input()
243 void HistogramWindow::update_output()
246 output_min->update(plugin->config.output_min[plugin->mode]);
247 output_max->update(plugin->config.output_max[plugin->mode]);
250 void HistogramWindow::update_mode()
252 mode_v->update(plugin->mode == HISTOGRAM_VALUE ? 1 : 0);
253 mode_r->update(plugin->mode == HISTOGRAM_RED ? 1 : 0);
254 mode_g->update(plugin->mode == HISTOGRAM_GREEN ? 1 : 0);
255 mode_b->update(plugin->mode == HISTOGRAM_BLUE ? 1 : 0);
256 output_min->output = &plugin->config.output_min[plugin->mode];
257 output_max->output = &plugin->config.output_max[plugin->mode];
258 plot->update(plugin->config.plot);
259 split->update(plugin->config.split);
262 void HistogramWindow::draw_canvas_overlay()
264 canvas->set_color(0x00ff00);
269 for(int i = 0; i < canvas_w; i++)
271 float input = (float)i /
275 float output = plugin->calculate_smooth(input, plugin->mode);
277 int y2 = canvas_h - (int)(output * canvas_h);
280 canvas->draw_line(i - 1, y1, i, y2);
285 // Draw output points
286 HistogramPoint *current = plugin->config.points[plugin->mode].first;
296 get_point_extents(current,
304 if(number == plugin->current_point)
305 canvas->draw_box(x1, y1, x2 - x1, y2 - y1);
307 canvas->draw_rectangle(x1, y1, x2 - x1, y2 - y1);
313 // Draw 0 and 100% lines.
314 canvas->set_color(0xff0000);
315 canvas->draw_line(title2_x - canvas->get_x(),
317 title2_x - canvas->get_x(),
319 canvas->draw_line(title3_x - canvas->get_x(),
321 title3_x - canvas->get_x(),
325 void HistogramWindow::update_canvas()
327 int *accum = plugin->accum[plugin->mode];
328 int accum_per_canvas_i = HISTOGRAM_SLOTS / canvas_w + 1;
329 float accum_per_canvas_f = (float)HISTOGRAM_SLOTS / canvas_w;
333 // Calculate output curve with no value function
334 plugin->tabulate_curve(plugin->mode, 0);
336 for(int i = 0; i < HISTOGRAM_SLOTS; i++)
338 if(accum && accum[i] > normalize) normalize = accum[i];
344 for(int i = 0; i < canvas_w; i++)
346 int accum_start = (int)(accum_per_canvas_f * i);
347 int accum_end = accum_start + accum_per_canvas_i;
349 for(int j = accum_start; j < accum_end; j++)
351 max = MAX(accum[j], max);
354 // max = max * canvas_h / normalize;
355 max = (int)(log(max) / log(normalize) * canvas_h);
357 canvas->set_color(0xffffff);
358 canvas->draw_line(i, 0, i, canvas_h - max);
359 canvas->set_color(0x000000);
360 canvas->draw_line(i, canvas_h - max, i, canvas_h);
365 canvas->set_color(0xffffff);
366 canvas->draw_box(0, 0, canvas_w, canvas_h);
370 draw_canvas_overlay();
374 void HistogramWindow::get_point_extents(HistogramPoint *current,
382 *x = (int)((current->x - MIN_INPUT) * canvas_w / FLOAT_RANGE);
383 *y = (int)(canvas_h - current->y * canvas_h);
384 *x1 = *x - BOX_SIZE / 2;
385 *y1 = *y - BOX_SIZE / 2;
386 *x2 = *x1 + BOX_SIZE;
387 *y2 = *y1 + BOX_SIZE;
396 HistogramCanvas::HistogramCanvas(HistogramMain *plugin,
397 HistogramWindow *gui,
408 this->plugin = plugin;
412 int HistogramCanvas::button_press_event()
415 if(is_event_win() && cursor_inside())
417 if(!plugin->dragging_point &&
418 (!plugin->config.automatic || plugin->mode == HISTOGRAM_VALUE))
420 HistogramPoint *new_point = 0;
422 // Search for existing point under cursor
423 HistogramPoint *current = plugin->config.points[plugin->mode].first;
424 plugin->current_point = -1;
427 int x = (int)((current->x - MIN_INPUT) * gui->canvas_w / FLOAT_RANGE);
428 int y = (int)(gui->canvas_h - current->y * gui->canvas_h);
430 if(get_cursor_x() >= x - BOX_SIZE / 2 &&
431 get_cursor_y() >= y - BOX_SIZE / 2 &&
432 get_cursor_x() < x + BOX_SIZE / 2 &&
433 get_cursor_y() < y + BOX_SIZE / 2)
435 plugin->current_point =
436 plugin->config.points[plugin->mode].number_of(current);
437 plugin->point_x_offset = get_cursor_x() - x;
438 plugin->point_y_offset = get_cursor_y() - y;
444 if(plugin->current_point < 0)
446 // Create new point under cursor
447 float current_x = (float)get_cursor_x() *
451 float current_y = 1.0 -
452 (float)get_cursor_y() /
455 plugin->config.points[plugin->mode].insert(current_x, current_y);
456 plugin->current_point =
457 plugin->config.points[plugin->mode].number_of(new_point);
458 plugin->point_x_offset = 0;
459 plugin->point_y_offset = 0;
462 plugin->dragging_point = 1;
465 plugin->config.boundaries();
467 gui->update_canvas();
470 plugin->send_configure_change();
477 int HistogramCanvas::cursor_motion_event()
479 if(plugin->dragging_point)
482 (float)(get_cursor_x() - plugin->point_x_offset) *
486 float current_y = 1.0 -
487 (float)(get_cursor_y() - plugin->point_y_offset) /
489 HistogramPoint *current_point =
490 plugin->config.points[plugin->mode].get_item_number(plugin->current_point);
491 current_point->x = current_x;
492 current_point->y = current_y;
493 plugin->config.boundaries();
495 gui->update_canvas();
496 plugin->send_configure_change();
500 if(is_event_win() && cursor_inside())
502 HistogramPoint *current = plugin->config.points[plugin->mode].first;
504 while(current && !done)
512 gui->get_point_extents(current,
519 int new_cursor = ARROW_CURSOR;
520 if(get_cursor_x() >= x1 &&
521 get_cursor_y() >= y1 &&
522 get_cursor_x() < x2 &&
525 new_cursor = UPRIGHT_ARROW_CURSOR;
529 if(new_cursor != get_cursor())
530 set_cursor(new_cursor);
539 int HistogramCanvas::button_release_event()
541 if(plugin->dragging_point)
543 // Test for out of order points to delete.
544 HistogramPoint *current =
545 plugin->config.points[plugin->mode].get_item_number(plugin->current_point);
546 HistogramPoint *prev = PREVIOUS;
547 HistogramPoint *next = NEXT;
549 if((prev && prev->x >= current->x) ||
550 (next && next->x <= current->x))
553 plugin->current_point = -1;
554 plugin->config.boundaries();
556 gui->update_canvas();
557 plugin->send_configure_change();
560 plugin->dragging_point = 0;
571 HistogramReset::HistogramReset(HistogramMain *plugin,
574 : BC_GenericButton(x, y, _("Reset"))
576 this->plugin = plugin;
578 int HistogramReset::handle_event()
580 plugin->config.reset(0);
581 plugin->thread->window->update(1);
582 plugin->thread->window->update_canvas();
583 plugin->send_configure_change();
595 HistogramSlider::HistogramSlider(HistogramMain *plugin,
596 HistogramWindow *gui,
602 : BC_SubWindow(x, y, w, h)
604 this->plugin = plugin;
606 this->is_input = is_input;
610 int HistogramSlider::input_to_pixel(float input)
612 return (int)((input - MIN_INPUT) / FLOAT_RANGE * get_w());
615 int HistogramSlider::button_press_event()
617 if(is_event_win() && cursor_inside())
623 int half_h = get_h() / 2;
627 if(operation == NONE)
629 int x1 = input_to_pixel(plugin->config.output_min[plugin->mode]) -
630 gui->mid_picon->get_w() / 2;
631 int x2 = x1 + gui->mid_picon->get_w();
632 if(get_cursor_x() >= x1 && get_cursor_x() < x2 &&
633 get_cursor_y() >= half_h && get_cursor_y() < h)
635 operation = DRAG_MIN_OUTPUT;
639 if(operation == NONE)
641 int x1 = input_to_pixel(plugin->config.output_max[plugin->mode]) -
642 gui->mid_picon->get_w() / 2;
643 int x2 = x1 + gui->mid_picon->get_w();
644 if(get_cursor_x() >= x1 && get_cursor_x() < x2 &&
645 get_cursor_y() >= half_h && get_cursor_y() < h)
647 operation = DRAG_MAX_OUTPUT;
655 int HistogramSlider::button_release_event()
657 if(operation != NONE)
665 int HistogramSlider::cursor_motion_event()
667 if(operation != NONE)
669 float value = (float)get_cursor_x() / get_w() * FLOAT_RANGE + MIN_INPUT;
670 CLAMP(value, MIN_INPUT, MAX_INPUT);
674 case DRAG_MIN_OUTPUT:
675 value = MIN(plugin->config.output_max[plugin->mode], value);
676 plugin->config.output_min[plugin->mode] = value;
678 case DRAG_MAX_OUTPUT:
679 value = MAX(plugin->config.output_min[plugin->mode], value);
680 plugin->config.output_max[plugin->mode] = value;
684 plugin->config.boundaries();
685 gui->update_output();
687 plugin->send_configure_change();
693 void HistogramSlider::update()
697 int half_h = get_h() / 2;
698 int quarter_h = get_h() / 4;
699 int mode = plugin->mode;
704 clear_box(0, 0, w, h);
711 case HISTOGRAM_GREEN:
719 for(int i = 0; i < w; i++)
721 int color = (int)(i * 0xff / w);
722 set_color(((r * color / 0xff) << 16) |
723 ((g * color / 0xff) << 8) |
726 draw_line(i, 0, i, half_h);
731 min = plugin->config.output_min[plugin->mode];
732 max = plugin->config.output_max[plugin->mode];
734 draw_pixmap(gui->min_picon,
735 input_to_pixel(min) - gui->min_picon->get_w() / 2,
737 draw_pixmap(gui->max_picon,
738 input_to_pixel(max) - gui->max_picon->get_w() / 2,
753 HistogramAuto::HistogramAuto(HistogramMain *plugin,
756 : BC_CheckBox(x, y, plugin->config.automatic, _("Automatic"))
758 this->plugin = plugin;
761 int HistogramAuto::handle_event()
763 plugin->config.automatic = get_value();
764 plugin->send_configure_change();
771 HistogramPlot::HistogramPlot(HistogramMain *plugin,
774 : BC_CheckBox(x, y, plugin->config.plot, _("Plot histogram"))
776 this->plugin = plugin;
779 int HistogramPlot::handle_event()
781 plugin->config.plot = get_value();
782 plugin->send_configure_change();
789 HistogramSplit::HistogramSplit(HistogramMain *plugin,
792 : BC_CheckBox(x, y, plugin->config.split, _("Split output"))
794 this->plugin = plugin;
797 int HistogramSplit::handle_event()
799 plugin->config.split = get_value();
800 plugin->send_configure_change();
806 HistogramMode::HistogramMode(HistogramMain *plugin,
811 : BC_Radial(x, y, plugin->mode == value, text)
813 this->plugin = plugin;
816 int HistogramMode::handle_event()
818 plugin->mode = value;
819 plugin->current_point= -1;
820 plugin->thread->window->update_canvas();
821 plugin->thread->window->update_mode();
822 plugin->thread->window->update_input();
823 plugin->thread->window->update_canvas();
824 plugin->thread->window->update_output();
825 plugin->thread->window->output->update();
826 // plugin->send_configure_change();
838 HistogramOutputText::HistogramOutputText(HistogramMain *plugin,
839 HistogramWindow *gui,
843 : BC_TumbleTextBox(gui,
844 output ? (float)*output : 0.0,
851 this->plugin = plugin;
852 this->output = output;
853 set_precision(DIGITS);
854 set_increment(PRECISION);
858 int HistogramOutputText::handle_event()
862 *output = atof(get_text());
865 plugin->thread->window->output->update();
866 plugin->send_configure_change();
877 HistogramInputText::HistogramInputText(HistogramMain *plugin,
878 HistogramWindow *gui,
882 : BC_TumbleTextBox(gui,
891 this->plugin = plugin;
893 set_precision(DIGITS);
894 set_increment(PRECISION);
898 int HistogramInputText::handle_event()
900 if(plugin->current_point >= 0 &&
901 plugin->current_point < plugin->config.points[plugin->mode].total())
903 HistogramPoint *point =
904 plugin->config.points[plugin->mode].get_item_number(
905 plugin->current_point);
910 point->x = atof(get_text());
912 point->y = atof(get_text());
914 plugin->config.boundaries();
915 gui->update_canvas();
917 plugin->thread->window->output->update();
918 plugin->send_configure_change();
924 void HistogramInputText::update()
926 if(plugin->current_point >= 0 &&
927 plugin->current_point < plugin->config.points[plugin->mode].total())
929 HistogramPoint *point =
931 plugin->config.points[plugin->mode].get_item_number(
932 plugin->current_point);
937 BC_TumbleTextBox::update(point->x);
939 BC_TumbleTextBox::update(point->y);
943 BC_TumbleTextBox::update((float)0.0);
948 BC_TumbleTextBox::update((float)0.0);