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