no longer need ffmpeg patch0 which was for Termux
[goodguy/cinelerra.git] / cinelerra-5.1 / plugins / histogram_bezier / bistogramwindow.C
1
2 /*
3  * CINELERRA
4  * Copyright (C) 2008 Adam Williams <broadcast at earthling dot net>
5  *
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.
10  *
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.
15  *
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
19  *
20  */
21
22 #include "bcdisplayinfo.h"
23 #include "bcsignals.h"
24 #include "bistogram.h"
25 #include "bistogramconfig.h"
26 #include "bistogramwindow.h"
27 #include "keys.h"
28 #include "language.h"
29
30
31 #include <unistd.h>
32 #include <string.h>
33
34 HistogramWindow::HistogramWindow(HistogramMain *plugin)
35  : PluginClientWindow(plugin, xS(480), yS(480), xS(480), yS(480), 0)
36 {
37         this->plugin = plugin;
38         max_picon = 0;
39         mid_picon = 0;
40         min_picon = 0;
41 }
42
43 HistogramWindow::~HistogramWindow()
44 {
45         delete max_picon;
46         delete mid_picon;
47         delete min_picon;
48 }
49
50 #include "min_picon_png.h"
51 #include "mid_picon_png.h"
52 #include "max_picon_png.h"
53 static VFramePng max_picon_image(max_picon_png);
54 static VFramePng mid_picon_image(mid_picon_png);
55 static VFramePng min_picon_image(min_picon_png);
56
57 void HistogramWindow::create_objects()
58 {
59         int xs10 = xS(10), xs15 = xS(15), xs20 = xS(20), xs80 = xS(80), xs100 = xS(100), xs120 = xS(120), xs150 = xS(150);
60         int ys6 = yS(6), ys10 =  yS(10), ys20 = yS(20), ys30 = yS(30), ys40 = yS(40), ys170 = yS(170);
61         int x = xs10, y = ys10, x1 = xs10;
62         BC_Title *title = 0;
63
64         max_picon = create_pixmap(&max_picon_image);
65         mid_picon = create_pixmap(&mid_picon_image);
66         min_picon = create_pixmap(&min_picon_image);
67         add_subwindow(mode_v = new HistogramMode(plugin, x, y,
68                 HISTOGRAM_VALUE, _("Value")));
69         x += xs80;
70         add_subwindow(mode_r = new HistogramMode(plugin, x, y,
71                 HISTOGRAM_RED, _("Red")));
72         x += xs80;
73         add_subwindow(mode_g = new HistogramMode(plugin, x, y,
74                 HISTOGRAM_GREEN, _("Green")));
75         x += xs80;
76         add_subwindow(mode_b = new HistogramMode(plugin, x, y,
77                 HISTOGRAM_BLUE, _("Blue")));
78 //      x += xs80;
79 //      add_subwindow(mode_a = new HistogramMode(plugin, x, y,
80 //              HISTOGRAM_ALPHA, _("Alpha")));
81
82         x = get_w() - HistogramClear::calculate_w(this, _("Clear")) - xs15;
83         add_subwindow(clear = new HistogramClear(plugin, x, y, _("Clear")));
84
85         x = x1;
86         y += ys30;
87         add_subwindow(title = new BC_Title(x, y, _("Input X:")));
88         x += title->get_w() + xs10;
89         input_x = new HistogramInputText(plugin, this, x, y, 1);
90         input_x->create_objects();
91
92         x += input_x->get_w() + xs10;
93         add_subwindow(title = new BC_Title(x, y, _("Input Y:")));
94         x += title->get_w() + xs10;
95         input_y = new HistogramInputText(plugin, this, x, y, 0);
96         input_y->create_objects();
97
98         y += ys30;
99         x = x1;
100
101         canvas_w = get_w() - x - x;
102         canvas_h = get_h() - y - ys170;
103         title1_x = x;
104         title2_x = x + (int)(canvas_w * -HIST_MIN_INPUT / FLOAT_RANGE);
105         title3_x = x + (int)(canvas_w * (1.0 - HIST_MIN_INPUT) / FLOAT_RANGE);
106         title4_x = x + (int)(canvas_w);
107         add_subwindow(canvas = new HistogramCanvas(plugin, this,
108                         x, y, canvas_w, canvas_h));
109         draw_canvas_overlay();
110         canvas->flash();
111
112         y += canvas->get_h() + 1;
113         add_subwindow(new BC_Title(title1_x, y, "-10%"));
114         add_subwindow(new BC_Title(title2_x, y, "0%"));
115         add_subwindow(new BC_Title(title3_x - get_text_width(MEDIUMFONT, "100"), y, "100%"));
116         add_subwindow(new BC_Title(title4_x - get_text_width(MEDIUMFONT, "110"), y, "110%"));
117
118         y += ys20;
119         add_subwindow(title = new BC_Title(x, y, _("Output min:")));
120         x += title->get_w() + xs10;
121         output_min = new HistogramOutputText(plugin, this,
122                 x, y, &plugin->config.output_min[plugin->mode]);
123         output_min->create_objects();
124         x += output_min->get_w() + xs10;
125         add_subwindow(new BC_Title(x, y, _("Output Max:")));
126         x += title->get_w() + xs10;
127         output_max = new HistogramOutputText(plugin, this,
128                 x, y, &plugin->config.output_max[plugin->mode]);
129         output_max->create_objects();
130
131         x = x1;
132         y += ys30;
133
134         add_subwindow(output = new HistogramSlider(plugin, this,
135                 x, y, get_w() - xs20, ys30, 0));
136         output->update();
137         y += ys40;
138
139
140         add_subwindow(automatic = new HistogramAuto(plugin, x, y));
141
142         x += xs120;
143         add_subwindow(new HistogramReset(plugin, x, y));
144         x += xs100;
145         add_subwindow(new BC_Title(x, y, _("Threshold:")));
146         x += xs100;
147         threshold = new HistogramOutputText(plugin, this,
148                 x, y, &plugin->config.threshold);
149         threshold->create_objects();
150         x = x1;
151         y += ys40;
152         add_subwindow(split = new HistogramSplit(plugin, x, y));
153         y += ys6;
154         x += xs150;
155         add_subwindow(new BC_Title(x,y, _("Interpolation:")));
156         x += xs120;
157         add_subwindow(smoothModeChoser = new HistogramSmoothMode(plugin, this, x, y));
158         smoothModeChoser->create_objects();
159
160         show_window();
161 }
162
163 int HistogramWindow::delete_current_point()
164 {
165         if( plugin->current_point < 0 ) return 0;
166         HistogramPoint *current =
167                 plugin->config.points[plugin->mode].get_item_number(plugin->current_point);
168         delete current;
169         plugin->current_point = -1;
170         return 1;
171 }
172
173 int HistogramWindow::keypress_event()
174 {
175         int result = 0;
176         if( get_keypress() == BACKSPACE ||
177             get_keypress() == DELETE ) {
178                 if( delete_current_point() ) {
179                         update_input();
180                         update_canvas();
181                         plugin->send_configure_change();
182                         result = 1;
183                 }
184         }
185         if( !result )
186                 result = context_help_check_and_show();
187         return result;
188 }
189
190 void HistogramWindow::update(int do_input)
191 {
192         automatic->update(plugin->config.automatic);
193         threshold->update(plugin->config.threshold);
194         update_mode();
195         split->set_value(plugin->config.split);
196         if( do_input ) update_input();
197         update_output();
198         if( smoothModeChoser->set_mode(plugin->config.smoothMode) )
199                 update_canvas();
200 }
201
202 void HistogramWindow::update_input()
203 {
204         input_x->update();
205         input_y->update();
206 }
207
208 void HistogramWindow::update_output()
209 {
210         output->update();
211         output_min->update(plugin->config.output_min[plugin->mode]);
212         output_max->update(plugin->config.output_max[plugin->mode]);
213 }
214
215 void HistogramWindow::update_mode()
216 {
217         mode_v->update(plugin->mode == HISTOGRAM_VALUE ? 1 : 0);
218         mode_r->update(plugin->mode == HISTOGRAM_RED ? 1 : 0);
219         mode_g->update(plugin->mode == HISTOGRAM_GREEN ? 1 : 0);
220         mode_b->update(plugin->mode == HISTOGRAM_BLUE ? 1 : 0);
221         output_min->output = &plugin->config.output_min[plugin->mode];
222         output_max->output = &plugin->config.output_max[plugin->mode];
223 }
224
225 void HistogramWindow::draw_canvas_overlay()
226 {
227         int y1;
228
229 // Calculate output curve
230         plugin->tabulate_curve(plugin->mode, 0);
231
232 // Draw output line
233         canvas->set_color(0xffff00);
234         for( int i=0; i<canvas_w; ++i ) {
235                 float input = (float)i / canvas_w * FLOAT_RANGE + HIST_MIN_INPUT;
236                 float output = plugin->calculate_smooth(input, plugin->mode);
237
238                 int y2 = canvas_h - (int)(output * canvas_h);
239                 if( i > 0 ) {
240                         canvas->draw_line(i - 1, y1, i, y2);
241                 }
242                 y1 = y2;
243         }
244
245         int x0 = 0, y0 = 0;
246 // Draw output points
247         HistogramPoint *current = plugin->config.points[plugin->mode].first;
248         int number = 0;
249         while( current ) {
250                 canvas->set_color(0x00ff00);
251                 int x = (int)((current->x - HIST_MIN_INPUT) * canvas_w / FLOAT_RANGE);
252                 int y = (int)(canvas_h - current->y * canvas_h);
253                 if(number == plugin->current_point)
254                         canvas->draw_box(x - BOX_SIZE / 2, y - BOX_SIZE / 2, BOX_SIZE, BOX_SIZE);
255                 else
256                         canvas->draw_rectangle(x - BOX_SIZE / 2, y - BOX_SIZE / 2, BOX_SIZE, BOX_SIZE);
257
258                 if( number > 0 )
259                         canvas->draw_line(x0, y0, x, y);
260                 x0 = x;  y0 = y;
261 //Draw gradients
262                 if (plugin->config.smoothMode > HISTOGRAM_LINEAR) {
263                         int x1,x2,y1,y2;
264                         canvas->set_color(0xffffff);
265                         x2 = (int)((current->x + current->xoffset_right - HIST_MIN_INPUT) * canvas_w / FLOAT_RANGE);
266                         x1 = (int)((current->x + current->xoffset_left - HIST_MIN_INPUT) * canvas_w / FLOAT_RANGE);
267                         y2 = (int)(canvas_h - (current->y + current->xoffset_right * current->gradient) * canvas_h);
268                         y1 = (int)(canvas_h - (current->y + current->xoffset_left * current->gradient) * canvas_h);
269 /*                      x2 = x + (title3_x - title2_x)/20;
270                         x1 = x - (title3_x - title2_x)/20;
271                         y1 = y + (int)(current->gradient * (float)(canvas_h)/20.0);
272                         y2 = y - (int)(current->gradient * (float)(canvas_h)/20.0);
273                         int y2 = (int)(canvas_h - canvas_h * (current->y + current->gradient /10));*/
274                         canvas->draw_line(x1,y1,x2,y2);
275
276                         canvas->draw_circle(x1 - BOX_SIZE / 4, y1 - BOX_SIZE / 4, BOX_SIZE/2, BOX_SIZE/2);
277                         canvas->draw_circle(x2 - BOX_SIZE / 4, y2 - BOX_SIZE / 4, BOX_SIZE/2, BOX_SIZE/2);
278                 }
279
280                 current = NEXT;
281                 number++;
282         }
283
284
285 // Draw 0 and 100% lines.
286         canvas->set_color(0xff0000);
287         canvas->draw_line(title2_x - canvas->get_x(), 0,
288                 title2_x - canvas->get_x(), canvas_h);
289         canvas->draw_line(title3_x - canvas->get_x(), 0,
290                 title3_x - canvas->get_x(), canvas_h);
291 }
292
293 void HistogramWindow::update_canvas()
294 {
295         int bins = plugin->slots * (HISTOGRAM_MAX-HISTOGRAM_MIN)/100;
296         int *accum = plugin->accum[plugin->mode];
297         int normalize = 0;
298         int max = 0;
299
300         if( accum ) {
301                 for( int i=0; i<bins; ++i )
302                         if( accum[i] > normalize )
303                                 normalize = accum[i];
304         }
305
306
307         if( normalize ) {
308                 int accum_start = 0;
309                 for( int i=0; i<canvas_w; ++i ) {
310                         int accum_end = bins*i / canvas_w;
311                         max = 0;
312                         for( int j=accum_start; j<accum_end; ++j ) {
313                                 max = MAX(accum[j], max);
314                         }
315
316 //                      max = max * canvas_h / normalize;
317                         max = (int)(log(max) / log(normalize) * canvas_h);
318
319                         canvas->set_color(0x333333);
320                         canvas->draw_line(i, 0, i, canvas_h - max);
321                         canvas->set_color(0x848484);
322                         canvas->draw_line(i, canvas_h - max, i, canvas_h);
323                         accum_start = accum_end;
324                 }
325         }
326         else {
327                 canvas->set_color(0x333333);
328                 canvas->draw_box(0, 0, canvas_w, canvas_h);
329         }
330
331
332         draw_canvas_overlay();
333         canvas->flash();
334 }
335
336
337 HistogramCanvas::HistogramCanvas(HistogramMain *plugin, HistogramWindow *gui,
338         int x, int y, int w, int h)
339  : BC_SubWindow(x, y, w, h, 0x333333)
340 {
341         this->plugin = plugin;
342         this->gui = gui;
343 }
344
345 int HistogramCanvas::button_press_event()
346 {
347         int result = 0;
348         if( is_event_win() && cursor_inside() ) {
349                 if( !plugin->dragging_point ) {
350                         HistogramPoint *new_point = 0;
351                         gui->deactivate();
352 // Search for existing point under cursor
353                         HistogramPoint *current = plugin->config.points[plugin->mode].first;
354                         plugin->current_point = -1;
355                         int dragID = 0;
356                         while( current ) {
357                                 int x = (int)((current->x - HIST_MIN_INPUT) * gui->canvas_w / FLOAT_RANGE);
358                                 int y = (int)(gui->canvas_h - current->y * gui->canvas_h);
359
360 /* Check for click on main point */
361                                 if( get_cursor_x() >= x - BOX_SIZE / 2 &&
362                                     get_cursor_y() >= y - BOX_SIZE / 2 &&
363                                     get_cursor_x() < x + BOX_SIZE / 2 &&
364                                     get_cursor_y() < y + BOX_SIZE / 2 ) {
365                                         plugin->current_point =
366                                                 plugin->config.points[plugin->mode].number_of(current);
367                                         plugin->point_x_offset = get_cursor_x() - x;
368                                         plugin->point_y_offset = get_cursor_y() - y;
369                                         dragID = 1;
370                                         break;
371                                 }
372 //                              if (plugin->config.smoothMode == HISTOGRAM_LINEAR)
373 //                                break;
374
375                                 int xright =
376                                   (int)((current->x + current->xoffset_right - HIST_MIN_INPUT) * gui->canvas_w / FLOAT_RANGE);
377                                 int yright =
378                                   (int)(gui->canvas_h - (current->y + current->xoffset_right * current->gradient) *
379                                   gui->canvas_h);
380
381 /* Check for click on right handle */
382                                 if( get_cursor_x() >= xright - BOX_SIZE / 2 &&
383                                     get_cursor_y() >= yright - BOX_SIZE / 2 &&
384                                     get_cursor_x() <  xright + BOX_SIZE / 2 &&
385                                     get_cursor_y() <  yright + BOX_SIZE / 2 ) {
386                                         plugin->current_point =
387                                                 plugin->config.points[plugin->mode].number_of(current);
388                                         plugin->point_x_offset = get_cursor_x() - xright;
389                                         plugin->point_y_offset = get_cursor_y() - yright;
390                                         dragID = 2;
391                                         break;
392                                 }
393
394 /* Check for click on left handle */
395                                 int xleft =
396                                   (int)((current->x + current->xoffset_left - HIST_MIN_INPUT) * gui->canvas_w / FLOAT_RANGE);
397                                 int yleft =
398                                   (int)(gui->canvas_h - (current->y + current->xoffset_left * current->gradient) *
399                                   gui->canvas_h);
400                                 if( get_cursor_x() >= xleft - BOX_SIZE / 2 &&
401                                     get_cursor_y() >= yleft - BOX_SIZE / 2 &&
402                                     get_cursor_x() <  xleft + BOX_SIZE / 2 &&
403                                     get_cursor_y() <  yleft + BOX_SIZE / 2 ) {
404                                         plugin->current_point =
405                                                 plugin->config.points[plugin->mode].number_of(current);
406                                         plugin->point_x_offset = get_cursor_x() - xleft;
407                                         plugin->point_y_offset = get_cursor_y() - yleft;
408                                         dragID = 3;
409                                         break;
410                                 }
411
412                                 current = NEXT;
413                         }
414
415                         if( plugin->current_point < 0 ) {
416 // Create new point under cursor
417                                 float current_x = (float)get_cursor_x() * FLOAT_RANGE / get_w() + HIST_MIN_INPUT;
418                                 float current_y = 1.0 - (float)get_cursor_y() / get_h();
419                                 new_point =
420                                         plugin->config.points[plugin->mode].insert(current_x, current_y);
421                                 plugin->current_point =
422                                         plugin->config.points[plugin->mode].number_of(new_point);
423                                 plugin->point_x_offset = 0;
424                                 plugin->point_y_offset = 0;
425
426 // Default gradient
427 // Get 2 points surrounding current position
428                                 float x1 = 0, x2 = 1, y1 = 0, y2 = 1;
429
430                                 HistogramPoint *current = plugin->config.points[plugin->mode].first;
431                                 int done = 0;
432                                 while( current && !done ) {
433                                         if( current->x > current_x ) {
434                                                 x2 = current->x;
435                                                 y2 = current->y;
436                                                 done = 1;
437                                         }
438                                         else
439                                                 current = NEXT;
440                                 }
441
442                                 current = plugin->config.points[plugin->mode].last;
443                                 done = 0;
444                                 while( current && !done ) {
445                                         if( current->x <= current_x ) {
446                                                 x1 = current->x;
447                                                 y1 = current->y;
448                                                 done = 1;
449                                         }
450                                         else
451                                                 current = PREVIOUS;
452                                 }
453                                 new_point->gradient = (y2 - y1) / (x2 - x1);
454                                 dragID = 1;
455                         }
456                         else if( dragID == 1 && get_buttonpress() == RIGHT_BUTTON ) {
457                                 if( gui->delete_current_point() ) {
458                                         plugin->send_configure_change();
459                                         dragID = 0;
460                                 }
461                         }
462
463                         plugin->dragging_point = dragID;
464                         result = 1;
465
466                         plugin->config.boundaries();
467                         gui->update_input();
468                         gui->update_canvas();
469                         if( new_point ) {
470                                 plugin->send_configure_change();
471                         }
472                 }
473         }
474         return result;
475 }
476
477 int HistogramCanvas::cursor_motion_event()
478 {
479         if( plugin->dragging_point ) {
480                 HistogramPoints *mode_points = &plugin->config.points[plugin->mode];
481                 HistogramPoint *current_point = mode_points->get_item_number(plugin->current_point);
482
483                 float current_x =
484                         (float)(get_cursor_x() - plugin->point_x_offset) * FLOAT_RANGE / get_w() + HIST_MIN_INPUT;
485                 float current_y = 1.0 - (float)(get_cursor_y() - plugin->point_y_offset) / get_h();
486
487                 switch( plugin->dragging_point ) {
488                 case 1: /* Main point dragged */
489                         current_point->x = current_x;
490                         current_point->y = current_y;
491                         break;
492                 case 2: /* Right control point dragged */
493                         if( current_x - current_point->x > 0 ) {
494                                 current_point->xoffset_right = current_x - current_point->x;
495                                 current_point->gradient = (current_y - current_point->y) / (current_x - current_point->x);
496                         }
497                         break;
498                 case 3: /* Left control point dragged */
499                         if( current_x - current_point->x < 0 ) {
500                                 current_point->xoffset_left = current_x - current_point->x;
501                                 current_point->gradient = (current_point->y - current_y) / (current_point->x - current_x);
502                         }
503                         break;
504                 }
505
506                 plugin->config.boundaries();
507                 gui->update_input();
508                 gui->update_canvas();
509                 plugin->send_configure_change();
510                 return 1;
511         }
512         return 0;
513 }
514
515 int HistogramCanvas::button_release_event()
516 {
517         if(plugin->dragging_point)
518         {
519 // Test for out of order points to delete.
520                 HistogramPoint *current =
521                         plugin->config.points[plugin->mode].get_item_number(plugin->current_point);
522                 HistogramPoint *prev = PREVIOUS;
523                 HistogramPoint *next = NEXT;
524
525                 if( (prev && prev->x >= current->x) ||
526                     (next && next->x <= current->x) ) {
527                         delete current;
528                         plugin->current_point = -1;
529                         plugin->config.boundaries();
530                         gui->update_input();
531                         gui->update_canvas();
532                 }
533
534                 plugin->send_configure_change();
535                 plugin->dragging_point = 0;
536         }
537         return 0;
538 }
539
540
541 HistogramReset::HistogramReset(HistogramMain *plugin, int x, int y)
542  : BC_GenericButton(x, y, _("Reset"))
543 {
544         this->plugin = plugin;
545 }
546 int HistogramReset::handle_event()
547 {
548         plugin->config.reset(1);
549         HistogramWindow *window = (HistogramWindow *)plugin->thread->window;
550         window->update(1);
551         window->update_canvas();
552         plugin->send_configure_change();
553         return 1;
554 }
555
556
557 HistogramSlider::HistogramSlider(HistogramMain *plugin, HistogramWindow *gui,
558                 int x, int y, int w, int h, int is_input)
559  : BC_SubWindow(x, y, w, h)
560 {
561         this->plugin = plugin;
562         this->gui = gui;
563         this->is_input = is_input;
564         operation = NONE;
565 }
566
567 int HistogramSlider::input_to_pixel(float input)
568 {
569         return (int)((input - HIST_MIN_INPUT) / FLOAT_RANGE * get_w());
570 }
571
572 int HistogramSlider::button_press_event()
573 {
574         if( is_event_win() && cursor_inside() ) {
575 //              int w = get_w();
576                 int h = get_h();
577                 int half_h = get_h() / 2;
578
579                 gui->deactivate();
580
581                 if( operation == NONE ) {
582                         int x1 = input_to_pixel(plugin->config.output_min[plugin->mode]) -
583                                 gui->mid_picon->get_w() / 2;
584                         int x2 = x1 + gui->mid_picon->get_w();
585                         if( get_cursor_x() >= x1 && get_cursor_x() < x2 &&
586                             get_cursor_y() >= half_h && get_cursor_y() < h ) {
587                                 operation = DRAG_MIN_OUTPUT;
588                         }
589                 }
590
591                 if( operation == NONE ) {
592                         int x1 = input_to_pixel(plugin->config.output_max[plugin->mode]) -
593                                 gui->mid_picon->get_w() / 2;
594                         int x2 = x1 + gui->mid_picon->get_w();
595                         if( get_cursor_x() >= x1 && get_cursor_x() < x2 &&
596                             get_cursor_y() >= half_h && get_cursor_y() < h ) {
597                                 operation = DRAG_MAX_OUTPUT;
598                         }
599                 }
600                 return 1;
601         }
602         return 0;
603 }
604
605 int HistogramSlider::button_release_event()
606 {
607         if( operation == NONE ) return 0;
608         operation = NONE;
609         return 1;
610 }
611
612 int HistogramSlider::cursor_motion_event()
613 {
614         if( operation == NONE ) return 0;
615
616         float value = (float)get_cursor_x() / get_w() * FLOAT_RANGE + HIST_MIN_INPUT;
617         CLAMP(value, HIST_MIN_INPUT, HIST_MAX_INPUT);
618
619         switch( operation ) {
620         case DRAG_MIN_OUTPUT:
621                 value = MIN(plugin->config.output_max[plugin->mode], value);
622                 plugin->config.output_min[plugin->mode] = value;
623                 break;
624         case DRAG_MAX_OUTPUT:
625                 value = MAX(plugin->config.output_min[plugin->mode], value);
626                 plugin->config.output_max[plugin->mode] = value;
627                 break;
628         }
629
630         plugin->config.boundaries();
631         gui->update_output();
632
633         plugin->send_configure_change();
634         return 1;
635 }
636
637 void HistogramSlider::update()
638 {
639         int w = get_w(), h = get_h();
640         int half_h = get_h() / 2;
641 //      int quarter_h = get_h() / 4;
642         int mode = plugin->mode;
643         int r = 0, g = 0, b = 0;
644
645         clear_box(0, 0, w, h);
646
647         switch( mode ) {
648         case HISTOGRAM_RED:     r = 0xff;  break;
649         case HISTOGRAM_GREEN:   g = 0xff;  break;
650         case HISTOGRAM_BLUE:    b = 0xff;  break;
651         case HISTOGRAM_VALUE:   r = g = b = 0xff;  break;
652         }
653
654         for( int i=0; i<w; ++i ) {
655                 int color = (int)(i * 0xff / w);
656                 set_color(((r * color / 0xff) << 16) |
657                         ((g * color / 0xff) << 8) |
658                         (b * color / 0xff));
659
660                 draw_line(i, 0, i, half_h);
661         }
662
663         float min = plugin->config.output_min[plugin->mode];
664         draw_pixmap(gui->min_picon,
665                 input_to_pixel(min) - gui->min_picon->get_w() / 2,
666                 half_h + 1);
667         float max = plugin->config.output_max[plugin->mode];
668         draw_pixmap(gui->max_picon,
669                 input_to_pixel(max) - gui->max_picon->get_w() / 2,
670                 half_h + 1);
671
672         flash();
673         flush();
674 }
675
676
677 HistogramAuto::HistogramAuto(HistogramMain *plugin, int x, int y)
678  : BC_CheckBox(x, y, plugin->config.automatic, _("Automatic"))
679 {
680         this->plugin = plugin;
681 }
682
683 int HistogramAuto::handle_event()
684 {
685         plugin->config.automatic = get_value();
686         plugin->send_configure_change();
687         return 1;
688 }
689
690
691 HistogramSplit::HistogramSplit(HistogramMain *plugin, int x, int y)
692  : BC_CheckBox(x, y, plugin->config.split, _("Split picture"))
693 {
694         this->plugin = plugin;
695 }
696
697 int HistogramSplit::handle_event()
698 {
699         plugin->config.split = get_value();
700         plugin->send_configure_change();
701         return 1;
702 }
703
704
705 HistogramMode::HistogramMode(HistogramMain *plugin, int x, int y,
706         int value, const char *text)
707  : BC_Radial(x, y, plugin->mode == value, text)
708 {
709         this->plugin = plugin;
710         this->value = value;
711 }
712 int HistogramMode::handle_event()
713 {
714         plugin->mode = value;
715         plugin->current_point= -1;
716         HistogramWindow *window = (HistogramWindow *)plugin->thread->window;
717         window->update_mode();
718         window->update_canvas();
719         window->update_input();
720         window->update_output();
721         window->output->update();
722 //      plugin->send_configure_change();
723         return 1;
724 }
725
726
727 HistogramClear::HistogramClear(HistogramMain *plugin, int x, int y, const char *text)
728  : BC_GenericButton(x, y, text)
729 {
730         this->plugin = plugin;
731 }
732
733 int HistogramClear::handle_event()
734 {
735         HistogramPoints *mode_points = &plugin->config.points[plugin->mode];
736         mode_points->clear();
737         plugin->config.output_min[plugin->mode] = 0.0;
738         plugin->config.output_max[plugin->mode] = 1.0;
739         HistogramWindow *window = (HistogramWindow *)plugin->thread->window;
740         window->update(1);
741         window->update_canvas();
742         plugin->send_configure_change();
743         return 1;
744 }
745
746
747 HistogramOutputText::HistogramOutputText(HistogramMain *plugin,
748         HistogramWindow *gui, int x, int y, float *output)
749  : BC_TumbleTextBox(gui, output ? (float)*output : 0.0,
750                 (float)HIST_MIN_INPUT, (float)HIST_MAX_INPUT,
751                 x, y, xS(60))
752 {
753         this->plugin = plugin;
754         this->output = output;
755         set_precision(DIGITS);
756         set_increment(PRECISION);
757 }
758
759 int HistogramOutputText::handle_event()
760 {
761         if( output ) {
762                 *output = atof(get_text());
763         }
764
765         HistogramWindow *window = (HistogramWindow *)plugin->thread->window;
766         window->output->update();
767         plugin->send_configure_change();
768         return 1;
769 }
770
771
772 HistogramInputText::HistogramInputText(HistogramMain *plugin,
773         HistogramWindow *gui, int x, int y, int do_x)
774  : BC_TumbleTextBox(gui, 0.0,
775                 (float)HIST_MIN_INPUT, (float)HIST_MAX_INPUT,
776                 x, y, xS(60))
777 {
778         this->do_x = do_x;
779         this->plugin = plugin;
780         this->gui = gui;
781         set_precision(DIGITS);
782         set_increment(PRECISION);
783 }
784
785 int HistogramInputText::handle_event()
786 {
787         if( plugin->current_point >= 0 &&
788             plugin->current_point < plugin->config.points[plugin->mode].total() ) {
789                 HistogramPoints *mode_points = &plugin->config.points[plugin->mode];
790                 HistogramPoint *point = mode_points->get_item_number(plugin->current_point);
791
792                 if( point ) {
793                         if( do_x )
794                                 point->x = atof(get_text());
795                         else
796                                 point->y = atof(get_text());
797
798                         plugin->config.boundaries();
799                         gui->update_canvas();
800
801                         HistogramWindow *window = (HistogramWindow *)plugin->thread->window;
802                         window->output->update();
803                         plugin->send_configure_change();
804                 }
805         }
806         return 1;
807 }
808
809 void HistogramInputText::update()
810 {
811         if( plugin->current_point >= 0 &&
812             plugin->current_point < plugin->config.points[plugin->mode].total() ) {
813                 HistogramPoints *mode_points = &plugin->config.points[plugin->mode];
814                 HistogramPoint *point = mode_points->get_item_number(plugin->current_point);
815
816                 if( point ) {
817                         if( do_x )
818                                 BC_TumbleTextBox::update(point->x);
819                         else
820                                 BC_TumbleTextBox::update(point->y);
821                 }
822                 else {
823                         BC_TumbleTextBox::update((float)0.0);
824                 }
825         }
826         else {
827                 BC_TumbleTextBox::update((float)0.0);
828         }
829
830 }
831
832
833 HistogramSmoothMode::HistogramSmoothMode(HistogramMain*plugin,
834         HistogramWindow *gui, int x, int y)
835  : BC_PopupMenu(x, y, xS(180), to_text(plugin->config.smoothMode), 1)
836 {
837         this->plugin = plugin;
838         this->gui = gui;
839 }
840 void HistogramSmoothMode::create_objects()
841 {
842         add_item(new BC_MenuItem(to_text(HISTOGRAM_LINEAR)));
843         add_item(new BC_MenuItem(to_text(HISTOGRAM_POLYNOMINAL)));
844         add_item(new BC_MenuItem(to_text(HISTOGRAM_BEZIER)));
845 }
846
847 char* HistogramSmoothMode::to_text(int mode)
848 {
849         switch( mode ) {
850         case HISTOGRAM_LINEAR:          return _("Linear");
851         case HISTOGRAM_POLYNOMINAL:     return _("Polynominal");
852         case HISTOGRAM_BEZIER:          return _("Bezier");
853         }
854         return _("None");
855 }
856 int HistogramSmoothMode::set_mode(int mode)
857 {
858         const char *tp = to_text(mode);
859         if( strcmp(tp, get_text()) ) {
860                 set_text(tp);
861                 return 1;
862         }
863         return 0;
864 }
865
866
867 int HistogramSmoothMode::from_text(char *text)
868 {
869         if( !strcmp(text, to_text(HISTOGRAM_LINEAR)) ) return HISTOGRAM_LINEAR;
870         if( !strcmp(text, to_text(HISTOGRAM_POLYNOMINAL)) ) return HISTOGRAM_POLYNOMINAL;
871         if( !strcmp(text, to_text(HISTOGRAM_BEZIER)) ) return HISTOGRAM_BEZIER;
872         return HISTOGRAM_LINEAR;
873 }
874 int HistogramSmoothMode::get_mode()
875 {
876         return from_text(get_text());
877 }
878
879 int HistogramSmoothMode::handle_event()
880 {
881         plugin->config.smoothMode = get_mode();
882         gui->update_canvas();
883         plugin->send_configure_change();
884         return 1;
885 }
886