add BC_SCALE env var for hi def monitors, cleanup theme data
[goodguy/cinelerra.git] / cinelerra-5.1 / plugins / bluebanana / bluebananawindow.C
1 /*
2  * Cinelerra :: Blue Banana - color modification plugin for Cinelerra-CV
3  * Copyright (C) 2012 Monty <monty@xiph.org>
4  *
5  * This program is free software; you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License as published by
7  * the Free Software Foundation; either version 2 of the License, or
8  * (at your option) any later version.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program; if not, write to the Free Software
17  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
18  *
19  */
20
21 #include <unistd.h>
22 #include <math.h>
23 #include "bcdisplayinfo.h"
24 #include "bcsignals.h"
25 #include "cursors.h"
26 #include "bluebanana.h"
27 #include "bluebananaconfig.h"
28 #include "bluebananaslider.h"
29 #include "bluebananawindow.h"
30 #include "keys.h"
31 #include "language.h"
32 #include "plugin.h"
33 #include "brender.h"
34
35 #include "bluebananacolor.c"
36
37
38 class BluebananaHActive : public BC_CheckBox {
39 public:
40   BluebananaHActive(BluebananaMain *plugin, BluebananaWindow *gui);
41   virtual int handle_event();
42   void update();
43   BluebananaMain *plugin;
44   BluebananaWindow *gui;
45 };
46
47 class BluebananaSActive : public BC_CheckBox {
48 public:
49   BluebananaSActive(BluebananaMain *plugin, BluebananaWindow *gui);
50   virtual int handle_event();
51   void update();
52   BluebananaMain *plugin;
53   BluebananaWindow *gui;
54 };
55
56 class BluebananaVActive : public BC_CheckBox {
57 public:
58   BluebananaVActive(BluebananaMain *plugin, BluebananaWindow *gui);
59   virtual int handle_event();
60   void update();
61   BluebananaMain *plugin;
62   BluebananaWindow *gui;
63 };
64
65
66 // -------------------------------------------------------------------------------
67 // The below code is because the stock TextTumbler trips too many bugs
68 // in guicast to be useful. If this plugin is to be shipped standalone
69 // and work, we need an independent version that avoids the bugs here.
70
71 BB_Tumble::BB_Tumble(BluebananaMain *plugin,
72                      BluebananaWindow *gui,
73                      float min,
74                      float mid,
75                      float max,
76                      int precision,
77                      float increment,
78                      int text_w)
79   : BC_TextBox(-1,-1,text_w,1,mid,1,MEDIUMFONT,precision){
80
81   // We must pass in the precision for initialization to get the
82   // geometry right.  But then bctextbox.C immediately clobbers it, so
83   // set it again
84   set_precision(precision);
85
86   this->gui = gui;
87   this->plugin = plugin;
88   this->x = -1;
89   this->y = -1;
90   this->min = min;
91   this->mid = mid;
92   this->max = max;
93   this->text_w = text_w;
94   this->precision = precision;
95   this->increment = increment;
96   this->active = 0;
97   this->suppress_events = 0;
98 }
99
100 float BB_Tumble::get_value(){
101   const char *text = get_text();
102   if(!text || text[0]==0) return 0;
103   return atof(text);
104 }
105
106 int BB_Tumble::handle_event(){
107   if(!suppress_events) value_event();
108   return 1;
109 }
110
111 int BB_Tumble::activate(){
112   // we want to restore the previous value on ESC
113   prev = get_value();
114   // the textbox active member is private, make our own
115   active = 1;
116   return BC_TextBox::activate();
117 }
118
119 int BB_Tumble::deactivate(){
120   if(active){
121     // only fire an event if the value changed; this makes 0/360
122     // behavior in the hue selection readout stick with what the user
123     // actually sets (as opposed to sanity checking flipping the value
124     // if an event fires)
125     if(get_value()!=prev)
126       value_event();
127     active = 0;
128     suppress_events=0;
129   }
130   return BC_TextBox::deactivate();
131 }
132
133 int BB_Tumble::button_press_event(){
134   if(is_event_win()){
135     if(get_buttonpress() < 4) return BC_TextBox::button_press_event();
136     if(get_buttonpress() == 4){
137       float v = get_value()+increment;
138       if(v>max)v=max;
139       update(v);
140       value_event();
141     }else if(get_buttonpress() == 5){
142       float v = get_value()-increment;
143       if(v<min)v=min;
144       update(v);
145       value_event();
146     }
147     return 1;
148   }
149   return 0;
150 }
151
152 int BB_Tumble::keypress_event(){
153   if(active && get_keypress()==ESC)
154     update(prev);
155
156   // don't fire update events from every keypress when editing; that
157   // will trigger slider updates, which will then sanity-check/clamp
158   // values, and then update/clobber the readout text while we're
159   // editing it.
160   suppress_events=1;
161   int ret = BC_TextBox::keypress_event();
162   suppress_events=0;
163   return ret;
164 }
165
166 // --------------------------------------------------------------------------------
167 //  initialization:
168 //    1) create_objects() constructs sliders and readouts with
169 //       limits but no values
170 //    2) create_objects() then calls slider update()
171 //       update computes and sets slider vals from config
172 //       update computes and sets readout vals from config
173 //
174 //  slider drag event:
175 //    1) slider calls handle_event(). This updates config.
176 //    2) slider calls update()
177 //       update computes and [re]sets slider vals from config;
178 //          this is where the snap-to-value behavior comes from
179 //       update computes and sets readout vals from config
180 //
181 //  readout event:
182 //    1) readout calls handle_event(). This updates config.
183 //    2) readout calls slider update() directly
184 //       slider update computes and sets slider vals from config
185 //       slider update computes and [re]sets readout vals from config;
186 //           this does not result in a further handle_event() call, so
187 //           no infinite recursion.
188 //
189 //  importantly, readout and slider values are set from the config
190 //  (and vice-versa) in only one place each.
191
192 // ---------------------------- hue adjustment slider -------------------------------
193
194 class BluebananaHAReadout : public BB_Tumble {
195  public:
196   BluebananaHAReadout(BluebananaMain *plugin, BluebananaWindow *gui, int w)
197     : BB_Tumble(plugin,gui,rint(-180),0,rint(180), 0,1,w){}
198   int value_event();
199 };
200
201 class BluebananaHASlider : public BluebananaSliderSingle {
202 public:
203   BluebananaHASlider(BluebananaMain *plugin, BluebananaWindow *gui,
204                      int x, int y, int w, int h)
205     : BluebananaSliderSingle(plugin,gui,x,y,w,h,-180,180){
206   }
207   virtual int handle_event() {
208     plugin->config.Hadj_val = val;
209     return 1;
210   }
211   void reset(){
212     plugin->config.Hadj_val=0;
213     update();
214   }
215   void update(){
216     val=plugin->config.Hadj_val;
217     highlight = plugin->config.active && plugin->config.Hadj_active;
218     gui->Hadj_readout->update(plugin->config.Hadj_val);
219     gui->slider_labels[7]->set_color(highlight && plugin->config.Hadj_val ?
220                                      get_resources()->default_text_color : dimtextcolor);
221     gui->enter_config_change();
222     gui->commit_config_change();
223   }
224   void trough_color(float hdel, float vdel, float &r, float &g, float &b, float &a){
225     float Hshift = plugin->config.Hsel_active ? (plugin->config.Hsel_lo + plugin->config.Hsel_hi)/720.f-.5f : 0.f;
226     float deg = hdel+Hshift;
227     if(deg<0)deg+=1;
228     if(deg>1)deg-=1;
229     HSpV_to_RGB(deg*6.f,1.,.2,r,g,b);
230     a=1.;
231   }
232 };
233
234 int BluebananaHAReadout::value_event(){
235   float val = get_value();
236   if(val<-180)val=-180;
237   if(val>180)val=180;
238   plugin->config.Hadj_val = val;
239   gui->Hadj_slider->update();
240   return 1;
241 }
242
243 // ------------------------------ Filter selection slider --------------------------------
244 class BluebananaFSReadout0 : public BB_Tumble {
245  public:
246   BluebananaFSReadout0(BluebananaMain *plugin, BluebananaWindow *gui, int w)
247     : BB_Tumble(plugin,gui,-FSrange,0,FSrange, 0,1,w){}
248   int value_event();
249 };
250 class BluebananaFSReadout1 : public BB_Tumble {
251  public:
252   BluebananaFSReadout1(BluebananaMain *plugin, BluebananaWindow *gui, int w)
253     : BB_Tumble(plugin,gui,-FSrange,0,FSrange, 0,1,w){}
254   int value_event();
255 };
256 class BluebananaFSReadout2 : public BB_Tumble {
257  public:
258   BluebananaFSReadout2(BluebananaMain *plugin, BluebananaWindow *gui, int w)
259     : BB_Tumble(plugin,gui,-FSrange,0,FSrange, 0,1,w){}
260   int value_event();
261 };
262 class BluebananaFSReadout3 : public BB_Tumble {
263  public:
264   BluebananaFSReadout3(BluebananaMain *plugin, BluebananaWindow *gui, int w)
265     : BB_Tumble(plugin,gui,0.,0,FSovermax, 0,1,w){}
266   int value_event();
267 };
268
269 static void paint_dot(float *array,int w, int h, float cx, float cy, float r, int inv){
270   int x,y;
271   int x0 = floor(cx-r);
272   int x1 = ceil(cx+r)+1;
273   int y0 = floor(cy-r);
274   int y1 = ceil(cy+r)+1;
275
276   if(x0<0)x0=0;
277   if(x1<0)x1=0;
278   if(y0<0)y0=0;
279   if(y1<0)y1=0;
280
281   if(x0>w)x0=w;
282   if(x1>w)x1=w;
283   if(y0>h)y0=h;
284   if(y1>h)y1=h;
285
286   for(y=y0;y<y1;y++){
287     float *row = array+y*w;
288     for(x=x0;x<x1;x++){
289       float rr = hypotf(x-cx,y-cy);
290       /* not correct, but this is merely cosmetic anyway */
291       float v = (r-rr+.5);
292       if(v>0){
293         if(inv){
294           row[x] -= v;
295           if(row[x]>1.)row[x]=0.;
296         }else{
297           row[x] += v;
298           if(row[x]>1.)row[x]=1.;
299         }
300       }
301     }
302   }
303 }
304
305 class BluebananaFSSlider : public BluebananaSliderFill {
306 public:
307   BluebananaFSSlider(BluebananaMain *plugin, BluebananaWindow *gui,
308                      int x, int y, int w, int h)
309     : BluebananaSliderFill(plugin,gui,x,y,w,h,-FSrange,FSrange,FSovermax) {
310     trough_alpha=0;
311     recompute_trough_alpha = 1;
312     erode=-1;
313   }
314   ~BluebananaFSSlider(){
315     if(trough_alpha)delete[] trough_alpha;
316   }
317   virtual int handle_event() {
318     plugin->config.Fsel_lo = (int)rint(loval);
319     plugin->config.Fsel_mid = (int)rint(midval);
320     plugin->config.Fsel_hi = (int)rint(hival);
321     plugin->config.Fsel_over = (int)rint(overval);
322     recompute_trough_alpha = 1;
323     return 1;
324   }
325   void update(){
326     if(plugin->config.Fsel_lo>0)plugin->config.Fsel_lo=0;
327     if(plugin->config.Fsel_hi<0)plugin->config.Fsel_hi=0;
328
329     if(highlight!=plugin->config.Fsel_active ||
330        erode!=plugin->config.Fsel_erode ||
331        loval!=plugin->config.Fsel_lo ||
332        midval!=plugin->config.Fsel_mid ||
333        hival!=plugin->config.Fsel_hi ||
334        overval!=plugin->config.Fsel_over){
335       recompute_trough_alpha = 1;
336     }
337     erode = plugin->config.Fsel_erode;
338     loval = plugin->config.Fsel_lo;
339     midval = plugin->config.Fsel_mid;
340     hival = plugin->config.Fsel_hi;
341     overval = plugin->config.Fsel_over;
342     highlight = plugin->config.Fsel_active;
343     gui->Fsel_readout0->update(plugin->config.Fsel_lo);
344     gui->Fsel_readout1->update(plugin->config.Fsel_mid);
345     gui->Fsel_readout2->update(plugin->config.Fsel_hi);
346     gui->Fsel_readout3->update(plugin->config.Fsel_over);
347     gui->slider_labels[3]->set_color
348       (highlight &&
349        (plugin->config.Hsel_active || plugin->config.Ssel_active || plugin->config.Vsel_active) &&
350        (plugin->config.Fsel_lo  != 0 ||
351         plugin->config.Fsel_mid != 0 ||
352         plugin->config.Fsel_hi  != 0 ||
353         plugin->config.Fsel_over!= 0 ) ?
354        get_resources()->default_text_color : dimtextcolor);
355
356     gui->erode_label->set_color
357       (highlight && plugin->config.Fsel_lo && plugin->config.Fsel_hi &&
358        (plugin->config.Hsel_active || plugin->config.Ssel_active || plugin->config.Vsel_active)?
359        get_resources()->default_text_color : dimtextcolor);
360
361     gui->enter_config_change();
362     gui->commit_config_change();
363   }
364   void trough_color(float hdel, float vdel, float &r, float &g, float &b, float &a){
365     int x = rint(hdel*troughcols-.5);
366     int y = rint(vdel*troughlines-.5);
367     float deg = plugin->config.Hsel_active ?
368       vdel*(plugin->config.Hsel_hi-plugin->config.Hsel_lo)+plugin->config.Hsel_lo :
369       vdel*360.f;
370     float sat = plugin->config.Ssel_active ?
371       (plugin->config.Ssel_hi+plugin->config.Ssel_lo)/200.:
372       .5;
373     float val = plugin->config.Vsel_active ?
374       (plugin->config.Vsel_hi*3+plugin->config.Vsel_lo)/400:
375       .75;
376
377     if(deg>=360)deg-=360.f;
378     HSpV_to_RGB(deg/60.,sat,val,r,g,b);
379     a = trough_alpha[troughcols*y+x];
380   }
381   void render(){
382
383     if(!trough_alpha)
384       trough_alpha = new float[troughcols*troughlines];
385
386     if(recompute_trough_alpha){
387       int trough_border = FSrange;
388       int tw = troughcols*3+trough_border*2;
389       int th = troughlines*3+trough_border*2;
390
391       float work1[tw*th];
392       float work2[tw*th];
393
394       memset(work1,0,sizeof(work1));
395
396       float loval=1;
397       float hival=FSrange*2-1;
398       float y0 = (th-1)/2.;
399       float y1 = (th-1)/2.;
400
401       int spacing=rint(FSrange)*2;
402       int rowflag=0;
403       int x,y;
404
405       while((y0+spacing*.5)>0){
406         for(x=(rowflag?spacing/2.:0.);x-spacing*.5<tw;x+=spacing){
407           float r = (((float)x/tw)*(hival-loval)+loval)*.5;
408           if(y0==y1){
409             paint_dot(work1,tw,th,x,y0,r,0);
410           }else{
411             paint_dot(work1,tw,th,x,y0,r,0);
412             paint_dot(work1,tw,th,x,y1,r,0);
413           }
414         }
415         y0-=spacing/2.;
416         y1+=spacing/2.;
417         rowflag = (rowflag+1)&1;
418       }
419
420       float *final = work1;
421       if(plugin->config.Fsel_active &&
422          (plugin->config.Fsel_lo || plugin->config.Fsel_hi || plugin->config.Fsel_over))
423         final=plugin->fill_selection(work1,work2,tw,th,NULL);
424
425       /* subsample into trough */
426       float *in = final + (tw+1)*trough_border;
427       for(y=0;y<troughlines;y++){
428         float *out = trough_alpha + troughcols*y;
429         for(x=0;x<troughcols;x++)
430           out[x] = (in[x*3]+in[x*3+1]+in[x*3+2]+
431                     in[tw+x*3]+in[tw+x*3+1]+in[x*3+2]+
432                     in[tw*2+x*3]+in[tw*2+x*3+1]+in[tw*2+x*3+2])*.1111;
433         in += tw*3;
434       }
435
436     }
437     recompute_trough_alpha=0;
438     BluebananaSliderFill::update();
439   }
440
441   float *trough_alpha;
442   int trough_border;
443   int recompute_trough_alpha;
444   int erode;
445 };
446
447 int BluebananaFSReadout0::value_event(){
448   float val = rint(get_value());
449   if(val<-FSrange)val=-FSrange;
450   if(val>0)val=0;
451   if(val>plugin->config.Fsel_mid) val = plugin->config.Fsel_mid;
452   plugin->config.Fsel_lo = val;
453   gui->Fsel_slider->update();
454   return 1;
455 }
456
457 int BluebananaFSReadout1::value_event(){
458   float val = rint(get_value());
459   if(val<-FSrange)val=-FSrange;
460   if(val>FSrange)val=FSrange;
461   if(val<plugin->config.Fsel_lo) plugin->config.Fsel_lo=val;
462   if(val>plugin->config.Fsel_hi) plugin->config.Fsel_hi=val;
463   plugin->config.Fsel_mid = val;
464   gui->Fsel_slider->update();
465   return 1;
466 }
467
468 int BluebananaFSReadout2::value_event(){
469   float val = rint(get_value());
470   if(val<0)val=0;
471   if(val>FSrange)val=FSrange;
472   if(val<plugin->config.Fsel_mid) val = plugin->config.Fsel_mid;
473   plugin->config.Fsel_hi = val;
474   gui->Fsel_slider->update();
475   return 1;
476 }
477
478 int BluebananaFSReadout3::value_event(){
479   float val = rint(get_value());
480   if(val<0)val=0;
481   if(val>FSovermax)val=FSovermax;
482   plugin->config.Fsel_over = val;
483   gui->Fsel_slider->update();
484   return 1;
485 }
486
487 // ------------------------------ value selection slider --------------------------------
488 class BluebananaVSReadout0 : public BB_Tumble {
489  public:
490   BluebananaVSReadout0(BluebananaMain *plugin, BluebananaWindow *gui, int w)
491     : BB_Tumble(plugin,gui,0.,0,100., 0,1,w){}
492   int value_event();
493 };
494 class BluebananaVSReadout1 : public BB_Tumble {
495  public:
496   BluebananaVSReadout1(BluebananaMain *plugin, BluebananaWindow *gui, int w)
497     : BB_Tumble(plugin,gui,0.,0,100., 0,1,w){}
498   int value_event();
499 };
500 class BluebananaVSReadout2 : public BB_Tumble {
501  public:
502   BluebananaVSReadout2(BluebananaMain *plugin, BluebananaWindow *gui, int w)
503     : BB_Tumble(plugin,gui,0.,0,100., 0,1,w){}
504   int value_event();
505 };
506
507 class BluebananaVSSlider : public BluebananaSliderBracket {
508 public:
509   BluebananaVSSlider(BluebananaMain *plugin, BluebananaWindow *gui,
510                      int x, int y, int w, int h)
511     : BluebananaSliderBracket(plugin,gui,x,y,w,h,0,100) { }
512   virtual int handle_event() {
513     plugin->config.Vsel_lo = rint(loval);
514     plugin->config.Vsel_hi = rint(hival);
515     plugin->config.Vsel_over = rint(overval);
516     return 1;
517   }
518   void pick(){
519     int delta = plugin->config.Vsel_hi - plugin->config.Vsel_lo;
520     float r = plugin->get_red();
521     float g = plugin->get_green();
522     float b = plugin->get_blue();
523     float h,s,v;
524     RGB_to_HSpV(r,g,b,h,s,v);
525     h*=60.f;
526     v=rint(v*100.f);
527     if(v<0)v=0;
528     if(v>100)v=100;
529     if(delta>25)delta=25;
530     int lo = v - delta/2;
531     int hi = lo + delta;
532     /* shrink the brackets if necessary */
533     if(lo<0){
534       lo=0;
535       if(hi-lo<10)hi=10;
536     }
537     if(hi>100){
538       hi=100;
539       if(hi-lo<10)lo=90;
540     }
541     plugin->config.Vsel_lo=lo;
542     plugin->config.Vsel_hi=hi;
543     plugin->config.Vsel_active=1;
544     gui->Vsel_active->update(); // this will also call the slider update
545   }
546   void update(){
547     loval = plugin->config.Vsel_lo;
548     hival = plugin->config.Vsel_hi;
549     midval = (loval+hival)/2.f;
550     overval = plugin->config.Vsel_over;
551     highlight = plugin->config.Vsel_active;
552
553     gui->Vsel_readout0->update(plugin->config.Vsel_lo);
554     gui->Vsel_readout1->update(plugin->config.Vsel_hi);
555     gui->Vsel_readout2->update(plugin->config.Vsel_over);
556     gui->slider_labels[2]->set_color
557       (highlight && (plugin->config.Vsel_lo != 0 || plugin->config.Vsel_hi != 100) ?
558        get_resources()->default_text_color : dimtextcolor);
559
560     gui->enter_config_change();
561     if(gui->Fsel_slider)gui->Fsel_slider->update();
562     gui->commit_config_change();
563   }
564   void trough_color(float hdel, float vdel, float &r, float &g, float &b, float &a){
565     float deg = plugin->config.Hsel_active ?
566       vdel*(plugin->config.Hsel_hi-plugin->config.Hsel_lo)+plugin->config.Hsel_lo :
567       vdel*360.f;
568     float sat = plugin->config.Ssel_active ?
569       (plugin->config.Ssel_hi*3+plugin->config.Ssel_lo)/400.:
570       .5;
571
572     if(deg>=360)deg-=360.f;
573     HSpV_to_RGB(deg/60.,sat,hdel,r,g,b);
574     a= plugin->val_select_alpha(hdel);
575   }
576 };
577
578 int BluebananaVSReadout0::value_event(){
579   float val = get_value();
580   if(val<0)val=0;
581   if(val>100)val=100;
582   if(val>plugin->config.Vsel_hi) val = plugin->config.Vsel_hi;
583   plugin->config.Vsel_lo = val;
584   gui->Vsel_slider->update();
585   return 1;
586 }
587
588 int BluebananaVSReadout1::value_event(){
589   float val = get_value();
590   if(val<0)val=0;
591   if(val>100)val=100;
592   if(val<plugin->config.Vsel_lo) val = plugin->config.Vsel_lo;
593   plugin->config.Vsel_hi = val;
594   gui->Vsel_slider->update();
595   return 1;
596 }
597
598 int BluebananaVSReadout2::value_event(){
599   float val = get_value();
600   if(val<0)val=0;
601   if(val>100)val=100;
602   plugin->config.Vsel_over = val;
603   gui->Vsel_slider->update();
604   return 1;
605 }
606
607 // ----------------------------- saturation selection slider -----------------------------
608 class BluebananaSSReadout0 : public BB_Tumble {
609  public:
610   BluebananaSSReadout0(BluebananaMain *plugin, BluebananaWindow *gui, int w)
611     : BB_Tumble(plugin,gui,0.,0,100., 0,1,w){}
612   int value_event();
613 };
614 class BluebananaSSReadout1 : public BB_Tumble {
615  public:
616   BluebananaSSReadout1(BluebananaMain *plugin, BluebananaWindow *gui, int w)
617     : BB_Tumble(plugin,gui,0.,0,100., 0,1,w){}
618   int value_event();
619 };
620 class BluebananaSSReadout2 : public BB_Tumble {
621  public:
622   BluebananaSSReadout2(BluebananaMain *plugin, BluebananaWindow *gui, int w)
623     : BB_Tumble(plugin,gui,0.,0,100., 0,1,w){}
624   int value_event();
625 };
626
627 class BluebananaSSSlider : public BluebananaSliderBracket {
628 public:
629   BluebananaSSSlider(BluebananaMain *plugin, BluebananaWindow *gui,
630                      int x, int y, int w, int h)
631     : BluebananaSliderBracket(plugin,gui,x,y,w,h,0,100) { }
632   int handle_event() {
633     plugin->config.Ssel_lo = rint(loval);
634     plugin->config.Ssel_hi = rint(hival);
635     plugin->config.Ssel_over = rint(overval);
636     return 1;
637   }
638   void pick(){
639     int delta = plugin->config.Ssel_hi - plugin->config.Ssel_lo;
640     float r = plugin->get_red();
641     float g = plugin->get_green();
642     float b = plugin->get_blue();
643     float h,s,v;
644     RGB_to_HSpV(r,g,b,h,s,v);
645     h*=60.f;
646     s=rint(s*100.f);
647     if(s<0)s=0;
648     if(s>100)s=100;
649     if(delta>25)delta=25;
650     int lo = s - delta/2;
651     int hi = lo + delta;
652     /* shrink the brackets if necessary */
653     if(lo<0){
654       lo=0;
655       if(hi-lo<10)hi=10;
656     }
657     if(hi>100){
658       hi=100;
659       if(hi-lo<10)lo=90;
660     }
661     plugin->config.Ssel_lo=lo;
662     plugin->config.Ssel_hi=hi;
663     plugin->config.Ssel_active=1;
664     gui->Ssel_active->update(); // this will also call the slider update
665   }
666   void update(){
667     loval = plugin->config.Ssel_lo;
668     hival = plugin->config.Ssel_hi;
669     midval = (loval+hival)/2.f;
670     overval = plugin->config.Ssel_over;
671     highlight = plugin->config.Ssel_active;
672
673     gui->Ssel_readout0->update(plugin->config.Ssel_lo);
674     gui->Ssel_readout1->update(plugin->config.Ssel_hi);
675     gui->Ssel_readout2->update(plugin->config.Ssel_over);
676     gui->slider_labels[1]->set_color(highlight  &&
677                                      (plugin->config.Ssel_lo != 0 || plugin->config.Ssel_hi != 100) ?
678                                      get_resources()->default_text_color : dimtextcolor);
679
680     gui->enter_config_change();
681     if(gui->Fsel_slider)gui->Fsel_slider->update();
682     gui->commit_config_change();
683   }
684   void trough_color(float hdel, float vdel, float &r, float &g, float &b, float &a){
685     float deg = plugin->config.Hsel_active ?
686       vdel*(plugin->config.Hsel_hi-plugin->config.Hsel_lo)+plugin->config.Hsel_lo :
687       vdel*360.;
688     if(deg>=360)deg-=360.f;
689     HSpV_to_RGB(deg/60.f,hdel,.7+.3*hdel,r,g,b);
690     a = plugin->sat_select_alpha(hdel);
691   }
692 };
693
694 int BluebananaSSReadout0::value_event(){
695   float val = get_value();
696   if(val<0)val=0;
697   if(val>100)val=100;
698   if(val>plugin->config.Ssel_hi) val = plugin->config.Ssel_hi;
699   plugin->config.Ssel_lo = val;
700   gui->Ssel_slider->update();
701   return 1;
702 }
703
704 int BluebananaSSReadout1::value_event(){
705   float val = get_value();
706   if(val<0)val=0;
707   if(val>100)val=100;
708   if(val<plugin->config.Ssel_lo) val = plugin->config.Ssel_lo;
709   plugin->config.Ssel_hi = val;
710   gui->Ssel_slider->update();
711   return 1;
712 }
713
714 int BluebananaSSReadout2::value_event(){
715   float val = get_value();
716   if(val<0)val=0;
717   if(val>100)val=100;
718   plugin->config.Ssel_over = val;
719   gui->Ssel_slider->update();
720   return 1;
721 }
722
723 // ----------------------------- hue selection slider ---------------------------------
724 class BluebananaHSReadout0 : public BB_Tumble {
725  public:
726   BluebananaHSReadout0(BluebananaMain *plugin, BluebananaWindow *gui, int w)
727     : BB_Tumble(plugin,gui,0.,0,360., 0,1,w){}
728   int value_event();
729 };
730 class BluebananaHSReadout1 : public BB_Tumble {
731  public:
732   BluebananaHSReadout1(BluebananaMain *plugin, BluebananaWindow *gui, int w)
733     : BB_Tumble(plugin,gui,0.,0,360., 0,1,w){}
734   int value_event();
735 };
736 class BluebananaHSReadout2 : public BB_Tumble {
737  public:
738   BluebananaHSReadout2(BluebananaMain *plugin, BluebananaWindow *gui, int w)
739     : BB_Tumble(plugin,gui,0.,360.,360., 0,1,w){}
740   int value_event();
741 };
742
743 class BluebananaHSSlider : public BluebananaSliderCircular {
744 public:
745   BluebananaHSSlider(BluebananaMain *plugin, BluebananaWindow *gui,
746                      int x, int y, int w, int h)
747     : BluebananaSliderCircular(plugin,gui,x,y,w,h,0,360) {
748   }
749   int handle_event() {
750     plugin->config.Hsel_lo = rint(loval);
751     plugin->config.Hsel_hi = plugin->config.Hsel_lo +
752       (midval<loval ? rint(midval*2-loval*2+720) : rint(midval*2-loval*2));
753     plugin->config.Hsel_over = rint(overval);
754     return 1;
755   }
756   void pick(){
757     int delta = plugin->config.Hsel_hi - plugin->config.Hsel_lo;
758     float r = plugin->get_red();
759     float g = plugin->get_green();
760     float b = plugin->get_blue();
761     float h,s,v;
762     RGB_to_HSpV(r,g,b,h,s,v);
763     h=rint(h*60.f);
764     if(h<0)h=0;
765     if(h>360)h=360;
766     if(delta>30)delta=30;
767     int lo = h - delta/2;
768     int hi = lo + delta;
769     if(lo<0){
770       lo+=360;
771       hi+=360;
772     }
773     plugin->config.Hsel_lo=lo;
774     plugin->config.Hsel_hi=hi;
775     plugin->config.Hsel_active=1;
776     gui->Hsel_active->update(); // this will also call the slider update
777   }
778   void update(){
779     // Significantly more complex than the other sliders due to the
780     // circular scale.
781     //float delta = (plugin->config.Hsel_hi - plugin->config.Hsel_lo);
782     loval = plugin->config.Hsel_lo;
783     overval = plugin->config.Hsel_over;
784     float newhival = plugin->config.Hsel_hi;
785     float newmidval = (loval+newhival)/2.;
786     if(loval<0)loval+=360.;
787     if(loval>360.)loval-=360.;
788     if(newmidval<0)newmidval+=360.;
789     if(newmidval>360.)newmidval-=360.;
790     if(newhival<0)newhival+=360.;
791     if(newhival>360.)newhival-=360.;
792     highlight = plugin->config.Hsel_active;
793
794     float checkhi = plugin->config.Hsel_hi;
795     if(checkhi>360)checkhi-=360;
796
797     // one last weirdness; 0 and 360 are technically the same value on
798     // the circular scale, but the user can set either.  This isn't a
799     // problem with lo as it doesn't wrap, but mid/hi is computed for
800     // the slider and could end up at 0 or 360, and then clobber the
801     // slider/readout.  To avoid annoying the user, don't override an
802     // existing readout/slider setting with its equivalent.
803     if(newhival==0 && hival==360.){
804       newhival=360.;
805       checkhi=360;
806     }else if(newhival==360 && hival==0.){
807       newhival=0.;
808       checkhi=0;
809     }else if(checkhi==0 && gui->Hsel_readout2->get_value()==360){
810       newhival=360.;
811       checkhi=360;
812     }else if(checkhi==360 && gui->Hsel_readout2->get_value()==0){
813       newhival=0.;
814       checkhi=0;
815     }
816
817     if(newmidval<1 && midval>359){
818       newmidval=360.;
819     }else if(newmidval>359.f && midval<1.){
820       newmidval=0.;
821     }
822     midval=newmidval;
823     hival=newhival;
824
825     gui->Hsel_readout0->update(plugin->config.Hsel_lo);
826     gui->Hsel_readout1->update(checkhi);
827     gui->Hsel_readout2->update(plugin->config.Hsel_over);
828     gui->slider_labels[0]->set_color(highlight &&
829                                      (plugin->config.Hsel_hi - plugin->config.Hsel_lo != 360) ?
830                                      get_resources()->default_text_color : dimtextcolor);
831
832     gui->enter_config_change();
833     if(gui->Fsel_slider)gui->Fsel_slider->update();
834     gui->commit_config_change();
835   }
836   void trough_color(float hdel, float vdel, float &r, float &g, float &b, float &a){
837     float deg = hdel*360.f;
838     if(deg>=360)deg-=360.f;
839
840     HSpV_to_RGB(deg/60.f,1.f,1.f,r,g,b);
841     a = plugin->hue_select_alpha(hdel*360.f);
842   }
843   friend class BluebananaHSReadout1;
844   friend class BluebananaHSReadout2;
845 };
846
847 int BluebananaHSReadout0::value_event(){
848   plugin->config.Hsel_lo = get_value();
849   if(plugin->config.Hsel_lo<0)plugin->config.Hsel_lo=0;
850   if(plugin->config.Hsel_lo>360)plugin->config.Hsel_lo=360;
851   if(plugin->config.Hsel_hi - plugin->config.Hsel_lo > 360)
852     plugin->config.Hsel_hi-=360;
853   if(plugin->config.Hsel_lo > plugin->config.Hsel_hi)
854     plugin->config.Hsel_hi+=360;
855   gui->Hsel_slider->update();
856   return 1;
857 }
858
859 int BluebananaHSReadout1::value_event(){
860   plugin->config.Hsel_hi = get_value();
861   if(plugin->config.Hsel_hi<0)plugin->config.Hsel_hi=0;
862   if(plugin->config.Hsel_hi>360)plugin->config.Hsel_hi=360;
863   if(plugin->config.Hsel_lo > plugin->config.Hsel_hi)
864     plugin->config.Hsel_hi+=360;
865   gui->Hsel_slider->hival=-1; /* force update to hival, not the hi readout */
866   gui->Hsel_slider->update();
867   return 1;
868 }
869
870 int BluebananaHSReadout2::value_event(){
871   float val = get_value();
872   if(val<0)val=0;
873   if(val>360)val=360;
874   plugin->config.Hsel_over=val;
875   gui->Hsel_slider->update();
876   return 1;
877 }
878
879 // ---------------------------- saturation adjustment slider ----------------------------
880 class BluebananaSAReadout0 : public BB_Tumble {
881  public:
882   BluebananaSAReadout0(BluebananaMain *plugin, BluebananaWindow *gui, int w)
883     : BB_Tumble(plugin,gui,-100,0,100., 0,1,w){}
884   int value_event();
885 };
886 class BluebananaSAReadout1 : public BB_Tumble {
887  public:
888   BluebananaSAReadout1(BluebananaMain *plugin, BluebananaWindow *gui, int w)
889     : BB_Tumble(plugin,gui,0.,0,200., 0,1,w){}
890   int value_event();
891 };
892 class BluebananaSAReadout2 : public BB_Tumble {
893  public:
894   BluebananaSAReadout2(BluebananaMain *plugin, BluebananaWindow *gui, int w)
895     : BB_Tumble(plugin,gui,MIN_GAMMA,0,MAX_GAMMA,2,.01,w){}
896   int value_event();
897 };
898
899 class BluebananaSASlider : public BluebananaSliderChannel {
900 public:
901   BluebananaSASlider(BluebananaMain *plugin, BluebananaWindow *gui,
902                      int x, int y, int w, int h)
903     : BluebananaSliderChannel(plugin,gui,x,y,w,h) { }
904   virtual int handle_event() {
905     plugin->config.Sadj_lo = loval;
906     plugin->config.Sadj_hi = hival;
907     plugin->config.Sadj_gamma = gamma;
908     return 1;
909   }
910   void reset(){
911     plugin->config.Sadj_lo=0.;
912     plugin->config.Sadj_hi=100.;
913     plugin->config.Sadj_gamma=1.;
914     update();
915   }
916   void update(){
917     loval = plugin->config.Sadj_lo;
918     hival = plugin->config.Sadj_hi;
919     gamma = plugin->config.Sadj_gamma;
920
921     highlight = plugin->config.active && plugin->config.Sadj_active;
922
923     gui->Sadj_readout0->update(plugin->config.Sadj_lo);
924     gui->Sadj_readout1->update(plugin->config.Sadj_hi);
925     gui->Sadj_readout2->update(plugin->config.Sadj_gamma);
926     gui->slider_labels[8]->set_color(highlight &&
927                                      (plugin->config.Sadj_lo != 0 ||
928                                       plugin->config.Sadj_hi != 100 ||
929                                       plugin->config.Sadj_gamma != 1.) ?
930                                      get_resources()->default_text_color : dimtextcolor);
931
932     gui->enter_config_change();
933     gui->commit_config_change();
934   }
935   void trough_color(float hdel, float &r, float &g, float &b){
936     r=g=b=0;
937   }
938 };
939
940 #define BBCLAMP(x,y,z) ((x)<(y) ? (y) : (x)>(z) ? (z) : (x))
941
942 int BluebananaSAReadout0::value_event(){
943   plugin->config.Sadj_lo = BBCLAMP(get_value(),-100,plugin->config.Sadj_hi);
944   plugin->config.Sadj_lo = BBCLAMP(get_value(),-100,100);
945   gui->Sadj_slider->update();
946   return 1;
947 }
948 int BluebananaSAReadout1::value_event(){
949   plugin->config.Sadj_hi = BBCLAMP(get_value(),plugin->config.Sadj_lo,200);
950   plugin->config.Sadj_hi = BBCLAMP(get_value(),0,200);
951   gui->Sadj_slider->update();
952   return 1;
953 }
954 int BluebananaSAReadout2::value_event(){
955   plugin->config.Sadj_gamma = BBCLAMP(get_value(),MIN_GAMMA,MAX_GAMMA);
956   gui->Sadj_slider->update();
957   return 1;
958 }
959
960 // ------------------------------- value adjustment slider -------------------------------
961 class BluebananaVAReadout0 : public BB_Tumble {
962  public:
963   BluebananaVAReadout0(BluebananaMain *plugin, BluebananaWindow *gui, int w)
964     : BB_Tumble(plugin,gui,-100.,0,100., 0,1,w){}
965   int value_event();
966 };
967 class BluebananaVAReadout1 : public BB_Tumble {
968  public:
969   BluebananaVAReadout1(BluebananaMain *plugin, BluebananaWindow *gui, int w)
970     : BB_Tumble(plugin,gui,0.,0,200., 0,1,w){}
971   int value_event();
972 };
973 class BluebananaVAReadout2 : public BB_Tumble {
974  public:
975   BluebananaVAReadout2(BluebananaMain *plugin, BluebananaWindow *gui, int w)
976     : BB_Tumble(plugin,gui,MIN_GAMMA,0,MAX_GAMMA,2,.01,w){}
977   int value_event();
978 };
979
980 class BluebananaVASlider : public BluebananaSliderChannel {
981 public:
982   BluebananaVASlider(BluebananaMain *plugin, BluebananaWindow *gui,
983                      int x, int y, int w, int h)
984     : BluebananaSliderChannel(plugin,gui,x,y,w,h) { }
985   virtual int handle_event() {
986     plugin->config.Vadj_lo = loval;
987     plugin->config.Vadj_hi = hival;
988     plugin->config.Vadj_gamma = gamma;
989     return 1;
990   }
991   void reset(){
992     plugin->config.Vadj_lo=0;
993     plugin->config.Vadj_hi=100;
994     plugin->config.Vadj_gamma=1;
995     update();
996   }
997   void update(){
998     loval = plugin->config.Vadj_lo;
999     hival = plugin->config.Vadj_hi;
1000     gamma = plugin->config.Vadj_gamma;
1001
1002     highlight = plugin->config.active && plugin->config.Vadj_active;
1003
1004     gui->Vadj_readout0->update(plugin->config.Vadj_lo);
1005     gui->Vadj_readout1->update(plugin->config.Vadj_hi);
1006     gui->Vadj_readout2->update(plugin->config.Vadj_gamma);
1007     gui->slider_labels[9]->set_color(highlight  &&
1008                                      (plugin->config.Vadj_lo != 0.f ||
1009                                       plugin->config.Vadj_hi != 100.f ||
1010                                       plugin->config.Vadj_gamma != 1.f) ?
1011                                      get_resources()->default_text_color : dimtextcolor);
1012
1013     gui->enter_config_change();
1014     gui->commit_config_change();
1015   }
1016   void trough_color(float hdel, float &r, float &g, float &b){
1017     r=g=b=0;
1018   }
1019 };
1020
1021 int BluebananaVAReadout0::value_event(){
1022   plugin->config.Vadj_lo = BBCLAMP(get_value(),-100,plugin->config.Vadj_hi);
1023   plugin->config.Vadj_lo = BBCLAMP(get_value(),-100,100);
1024   gui->Vadj_slider->update();
1025   return 1;
1026 }
1027 int BluebananaVAReadout1::value_event(){
1028   plugin->config.Vadj_hi = BBCLAMP(get_value(),plugin->config.Vadj_lo,200);
1029   plugin->config.Vadj_hi = BBCLAMP(get_value(),0,200);
1030   gui->Vadj_slider->update();
1031   return 1;
1032 }
1033 int BluebananaVAReadout2::value_event(){
1034   plugin->config.Vadj_gamma = BBCLAMP(get_value(),MIN_GAMMA,MAX_GAMMA);
1035   gui->Vadj_slider->update();
1036   return 1;
1037 }
1038
1039 // -------------------------------- red adjustment slider --------------------------------
1040 class BluebananaRAReadout0 : public BB_Tumble {
1041  public:
1042   BluebananaRAReadout0(BluebananaMain *plugin, BluebananaWindow *gui, int w)
1043     : BB_Tumble(plugin,gui,-100.,0,100., 0,1,w){}
1044   int value_event();
1045 };
1046 class BluebananaRAReadout1 : public BB_Tumble {
1047  public:
1048   BluebananaRAReadout1(BluebananaMain *plugin, BluebananaWindow *gui, int w)
1049     : BB_Tumble(plugin,gui,0.,0,200., 0,1,w){}
1050   int value_event();
1051 };
1052 class BluebananaRAReadout2 : public BB_Tumble {
1053  public:
1054   BluebananaRAReadout2(BluebananaMain *plugin, BluebananaWindow *gui, int w)
1055     : BB_Tumble(plugin,gui,MIN_GAMMA,0,MAX_GAMMA,2,.01,w){}
1056   int value_event();
1057 };
1058
1059 class BluebananaRASlider : public BluebananaSliderChannel {
1060 public:
1061   BluebananaRASlider(BluebananaMain *plugin, BluebananaWindow *gui,
1062                      int x, int y, int w, int h)
1063     : BluebananaSliderChannel(plugin,gui,x,y,w,h) { }
1064   virtual int handle_event() {
1065     plugin->config.Radj_lo = loval;
1066     plugin->config.Radj_hi = hival;
1067     plugin->config.Radj_gamma = gamma;
1068     return 1;
1069   }
1070   void reset(){
1071     plugin->config.Radj_lo=0;
1072     plugin->config.Radj_hi=100;
1073     plugin->config.Radj_gamma=1;
1074     update();
1075   }
1076   void update(){
1077     loval = plugin->config.Radj_lo;
1078     hival = plugin->config.Radj_hi;
1079     gamma = plugin->config.Radj_gamma;
1080
1081     highlight = plugin->config.active && plugin->config.Radj_active;
1082
1083     gui->Radj_readout0->update(plugin->config.Radj_lo);
1084     gui->Radj_readout1->update(plugin->config.Radj_hi);
1085     gui->Radj_readout2->update(plugin->config.Radj_gamma);
1086     gui->slider_labels[4]->set_color(highlight  &&
1087                                      (plugin->config.Radj_lo != 0 ||
1088                                       plugin->config.Radj_hi != 100 ||
1089                                       plugin->config.Radj_gamma != 1) ?
1090                                      get_resources()->default_text_color : dimtextcolor);
1091
1092     gui->enter_config_change();
1093     gui->commit_config_change();
1094   }
1095   void trough_color(float hdel, float &r, float &g, float &b){
1096     if(hdel<0){
1097       r=g=b=0.;
1098     }else if(hdel<=1.f){
1099       r=hdel;
1100       g=b=0.;
1101     }else{
1102       r=1.;
1103       g=b=0.;
1104     }
1105   }
1106 };
1107
1108 int BluebananaRAReadout0::value_event(){
1109   plugin->config.Radj_lo = BBCLAMP(get_value(),-100,plugin->config.Radj_hi);
1110   plugin->config.Radj_lo = BBCLAMP(get_value(),-100,100);
1111   gui->Radj_slider->update();
1112   return 1;
1113 }
1114 int BluebananaRAReadout1::value_event(){
1115   plugin->config.Radj_hi = BBCLAMP(get_value(),plugin->config.Radj_lo,200);
1116   plugin->config.Radj_hi = BBCLAMP(get_value(),0,200);
1117   gui->Radj_slider->update();
1118   return 1;
1119 }
1120 int BluebananaRAReadout2::value_event(){
1121   plugin->config.Radj_gamma = BBCLAMP(get_value(),MIN_GAMMA,MAX_GAMMA);
1122   gui->Radj_slider->update();
1123   return 1;
1124 }
1125
1126 // ---------------------------- green adjustment slider ----------------------------
1127 class BluebananaGAReadout0 : public BB_Tumble {
1128  public:
1129   BluebananaGAReadout0(BluebananaMain *plugin, BluebananaWindow *gui, int w)
1130     : BB_Tumble(plugin,gui,-100.,0,100., 0,1,w){}
1131   int value_event();
1132 };
1133 class BluebananaGAReadout1 : public BB_Tumble {
1134  public:
1135   BluebananaGAReadout1(BluebananaMain *plugin, BluebananaWindow *gui, int w)
1136     : BB_Tumble(plugin,gui,0.,0,200., 0,1,w){}
1137   int value_event();
1138 };
1139 class BluebananaGAReadout2 : public BB_Tumble {
1140  public:
1141   BluebananaGAReadout2(BluebananaMain *plugin, BluebananaWindow *gui, int w)
1142     : BB_Tumble(plugin,gui,MIN_GAMMA,0,MAX_GAMMA,2,.01,w){}
1143   int value_event();
1144 };
1145
1146 class BluebananaGASlider : public BluebananaSliderChannel {
1147 public:
1148   BluebananaGASlider(BluebananaMain *plugin, BluebananaWindow *gui,
1149                      int x, int y, int w, int h)
1150     : BluebananaSliderChannel(plugin,gui,x,y,w,h) { }
1151   virtual int handle_event() {
1152     plugin->config.Gadj_lo = loval;
1153     plugin->config.Gadj_hi = hival;
1154     plugin->config.Gadj_gamma = gamma;
1155     return 1;
1156   }
1157   void reset(){
1158     plugin->config.Gadj_lo=0;
1159     plugin->config.Gadj_hi=100;
1160     plugin->config.Gadj_gamma=1;
1161     update();
1162   }
1163   void update(){
1164     loval = plugin->config.Gadj_lo;
1165     hival = plugin->config.Gadj_hi;
1166     gamma = plugin->config.Gadj_gamma;
1167
1168     highlight = plugin->config.active && plugin->config.Gadj_active;
1169
1170     gui->Gadj_readout0->update(plugin->config.Gadj_lo);
1171     gui->Gadj_readout1->update(plugin->config.Gadj_hi);
1172     gui->Gadj_readout2->update(plugin->config.Gadj_gamma);
1173     gui->slider_labels[5]->set_color(highlight  &&
1174                                      (plugin->config.Gadj_lo != 0 ||
1175                                       plugin->config.Gadj_hi != 100 ||
1176                                       plugin->config.Gadj_gamma != 1) ?
1177                                      get_resources()->default_text_color : dimtextcolor);
1178
1179     gui->enter_config_change();
1180     gui->commit_config_change();
1181   }
1182   void trough_color(float hdel, float &r, float &g, float &b){
1183     if(hdel<0){
1184       r=g=b=0.;
1185     }else if(hdel<=1.f){
1186       g=hdel;
1187       r=b=0.;
1188     }else{
1189       g=1.;
1190       r=b=0.;
1191     }
1192   }
1193 };
1194
1195 int BluebananaGAReadout0::value_event(){
1196   plugin->config.Gadj_lo = BBCLAMP(get_value(),-100,plugin->config.Gadj_hi);
1197   plugin->config.Gadj_lo = BBCLAMP(get_value(),-100,100);
1198   gui->Gadj_slider->update();
1199   return 1;
1200 }
1201 int BluebananaGAReadout1::value_event(){
1202   plugin->config.Gadj_hi = BBCLAMP(get_value(),plugin->config.Gadj_lo,200);
1203   plugin->config.Gadj_hi = BBCLAMP(get_value(),0,200);
1204   gui->Gadj_slider->update();
1205   return 1;
1206 }
1207 int BluebananaGAReadout2::value_event(){
1208   plugin->config.Gadj_gamma = BBCLAMP(get_value(),MIN_GAMMA,MAX_GAMMA);
1209   gui->Gadj_slider->update();
1210   return 1;
1211 }
1212
1213 // ------------------------------- blue adjustment slider -------------------------------
1214 class BluebananaBAReadout0 : public BB_Tumble {
1215  public:
1216   BluebananaBAReadout0(BluebananaMain *plugin, BluebananaWindow *gui, int w)
1217     : BB_Tumble(plugin,gui,-100.,0,100., 0,1,w){}
1218   int value_event();
1219 };
1220 class BluebananaBAReadout1 : public BB_Tumble {
1221  public:
1222   BluebananaBAReadout1(BluebananaMain *plugin, BluebananaWindow *gui, int w)
1223     : BB_Tumble(plugin,gui,0.,0,200., 0,1,w){}
1224   int value_event();
1225 };
1226 class BluebananaBAReadout2 : public BB_Tumble {
1227  public:
1228   BluebananaBAReadout2(BluebananaMain *plugin, BluebananaWindow *gui, int w)
1229     : BB_Tumble(plugin,gui,MIN_GAMMA,0,MAX_GAMMA,2,.01,w){}
1230   int value_event();
1231 };
1232
1233 class BluebananaBASlider : public BluebananaSliderChannel {
1234 public:
1235   BluebananaBASlider(BluebananaMain *plugin, BluebananaWindow *gui,
1236                      int x, int y, int w, int h)
1237     : BluebananaSliderChannel(plugin,gui,x,y,w,h) { }
1238   virtual int handle_event() {
1239     plugin->config.Badj_lo = loval;
1240     plugin->config.Badj_hi = hival;
1241     plugin->config.Badj_gamma = gamma;
1242     return 1;
1243   }
1244   void reset(){
1245     plugin->config.Badj_lo=0;
1246     plugin->config.Badj_hi=100;
1247     plugin->config.Badj_gamma=1;
1248     update();
1249   }
1250   void update(){
1251     loval = plugin->config.Badj_lo;
1252     hival = plugin->config.Badj_hi;
1253     gamma = plugin->config.Badj_gamma;
1254
1255     highlight = plugin->config.active && plugin->config.Badj_active;
1256
1257     gui->Badj_readout0->update(plugin->config.Badj_lo);
1258     gui->Badj_readout1->update(plugin->config.Badj_hi);
1259     gui->Badj_readout2->update(plugin->config.Badj_gamma);
1260     gui->slider_labels[6]->set_color(highlight  &&
1261                                      (plugin->config.Badj_lo != 0 ||
1262                                       plugin->config.Badj_hi != 100 ||
1263                                       plugin->config.Badj_gamma != 1) ?
1264                                      get_resources()->default_text_color : dimtextcolor);
1265
1266     gui->enter_config_change();
1267     gui->commit_config_change();
1268   }
1269   void trough_color(float hdel, float &r, float &g, float &b){
1270     if(hdel<0){
1271       r=g=b=0.;
1272     }else if(hdel<=1.f){
1273       b=hdel;
1274       g=r=0.;
1275     }else{
1276       b=1.;
1277       g=r=0.;
1278     }
1279   }
1280 };
1281
1282 int BluebananaBAReadout0::value_event(){
1283   plugin->config.Badj_lo = BBCLAMP(get_value(),-100,plugin->config.Badj_hi);
1284   plugin->config.Badj_lo = BBCLAMP(get_value(),-100,100);
1285   gui->Badj_slider->update();
1286   return 1;
1287 }
1288 int BluebananaBAReadout1::value_event(){
1289   plugin->config.Badj_hi = BBCLAMP(get_value(),plugin->config.Badj_lo,200);
1290   plugin->config.Badj_hi = BBCLAMP(get_value(),0,200);
1291   gui->Badj_slider->update();
1292   return 1;
1293 }
1294 int BluebananaBAReadout2::value_event(){
1295   plugin->config.Badj_gamma = BBCLAMP(get_value(),MIN_GAMMA,MAX_GAMMA);
1296   gui->Badj_slider->update();
1297   return 1;
1298 }
1299
1300 // ---------------------------------- opacity slider ---------------------------------
1301 class BluebananaOAReadout : public BB_Tumble {
1302  public:
1303   BluebananaOAReadout(BluebananaMain *plugin, BluebananaWindow *gui, int w)
1304     : BB_Tumble(plugin,gui,0.,0,100., 0,1,w){}
1305   int value_event();
1306 };
1307
1308 class BluebananaOASlider : public BluebananaSliderSingle {
1309 public:
1310   BluebananaOASlider(BluebananaMain *plugin, BluebananaWindow *gui,
1311                      int x, int y, int w, int h)
1312     : BluebananaSliderSingle(plugin,gui,x,y,w,h,0,100) { }
1313   virtual int handle_event() {
1314     plugin->config.Oadj_val = val;
1315     return 1;
1316   }
1317   void reset(){
1318     plugin->config.Oadj_val=100;
1319     update();
1320   }
1321   void update(){
1322     val = plugin->config.Oadj_val;
1323     highlight = plugin->config.active && plugin->config.Oadj_active;
1324     gui->Oadj_readout->update(plugin->config.Oadj_val);
1325     gui->slider_labels[10]->set_color(highlight  &&
1326                                       plugin->config.Oadj_val != 100 ?
1327                                       get_resources()->default_text_color : dimtextcolor);
1328     gui->enter_config_change();
1329     gui->commit_config_change();
1330   }
1331   void trough_color(float hdel, float vdel, float &r, float &g, float &b, float &a){
1332     r=g=b=.8;
1333     a=1-cos(hdel*M_PI*.5);
1334   }
1335 };
1336
1337 int BluebananaOAReadout::value_event(){
1338   float val = get_value();
1339   plugin->config.Oadj_val = val;
1340   gui->Oadj_slider->update();
1341   return 1;
1342 }
1343
1344 // ---------------------------------- alpha slider ---------------------------------
1345 class BluebananaAAReadout : public BB_Tumble {
1346  public:
1347   BluebananaAAReadout(BluebananaMain *plugin, BluebananaWindow *gui, int w)
1348     : BB_Tumble(plugin,gui,0.,0,100., 0,1,w){}
1349   int value_event();
1350 };
1351
1352 class BluebananaAASlider : public BluebananaSliderSingle {
1353 public:
1354   BluebananaAASlider(BluebananaMain *plugin, BluebananaWindow *gui,
1355                      int x, int y, int w, int h)
1356     : BluebananaSliderSingle(plugin,gui,x,y,w,h,0,100) {}
1357   virtual int handle_event() {
1358     plugin->config.Aadj_val = val;
1359     return 1;
1360   }
1361   void reset(){
1362     plugin->config.Aadj_val=100;
1363     update();
1364   }
1365   void update(){
1366     val = plugin->config.Aadj_val;
1367     if( BC_CModels::has_alpha(plugin->colormodel) ) {
1368       if( is_hidden() ) show_window();
1369     }else{
1370       if( !is_hidden() ) hide_window();
1371     }
1372     if( is_hidden() ) return;
1373     highlight = plugin->config.active && plugin->config.Aadj_active;
1374     gui->Aadj_readout->update(plugin->config.Aadj_val);
1375     gui->slider_labels[11]->set_color(highlight  && plugin->config.Aadj_val != 100 ?
1376          get_resources()->default_text_color : dimtextcolor);
1377     gui->enter_config_change();
1378     gui->commit_config_change();
1379   }
1380   void trough_color(float hdel, float vdel, float &r, float &g, float &b, float &a){
1381     r=g=b=.8;
1382     a=1-cos(hdel*M_PI*.5);
1383   }
1384 };
1385
1386 int BluebananaAAReadout::value_event(){
1387   float val = get_value();
1388   plugin->config.Aadj_val = val;
1389   gui->Aadj_slider->update();
1390   return 1;
1391 }
1392
1393 // ------------------------------------- picker buttons -----------------------------------------
1394 class BluebananaHPicker : public BC_GenericButton{
1395  public:
1396   BluebananaHPicker(BluebananaWindow *gui, int w) : BC_GenericButton(-1, -1, w, _("Pick")){
1397     this->gui = gui;
1398   }
1399   int handle_event() { gui->Hsel_slider->pick(); return 1; }
1400   BluebananaWindow *gui;
1401 };
1402 class BluebananaSPicker : public BC_GenericButton{
1403  public:
1404   BluebananaSPicker(BluebananaWindow *gui, int w) : BC_GenericButton(-1, -1, w, _("Pick")){
1405     this->gui = gui;
1406   }
1407   int handle_event() { gui->Ssel_slider->pick(); return 1; }
1408   BluebananaWindow *gui;
1409 };
1410 class BluebananaVPicker : public BC_GenericButton{
1411  public:
1412   BluebananaVPicker(BluebananaWindow *gui, int w) : BC_GenericButton(-1, -1, w, _("Pick")){
1413     this->gui = gui;
1414   }
1415   int handle_event() { gui->Vsel_slider->pick(); return 1; }
1416   BluebananaWindow *gui;
1417 };
1418
1419 // -------------------------------------- reset buttons -----------------------------------------
1420
1421 class BluebananaHAReset : public BC_GenericButton{
1422  public:
1423   BluebananaHAReset(BluebananaWindow *gui, int w) : BC_GenericButton(-1, -1, w, _("Reset")){
1424     this->gui = gui;
1425   }
1426   int handle_event() { gui->Hadj_slider->reset(); return 1;}
1427   BluebananaWindow *gui;
1428 };
1429 class BluebananaSAReset : public BC_GenericButton{
1430  public:
1431   BluebananaSAReset(BluebananaWindow *gui, int w) : BC_GenericButton(-1, -1, w, _("Reset")){
1432     this->gui = gui;
1433   }
1434   int handle_event() { gui->Sadj_slider->reset(); return 1;}
1435   BluebananaWindow *gui;
1436 };
1437 class BluebananaVAReset : public BC_GenericButton{
1438  public:
1439   BluebananaVAReset(BluebananaWindow *gui, int w) : BC_GenericButton(-1, -1, w, _("Reset")){
1440     this->gui = gui;
1441   }
1442   int handle_event() { gui->Vadj_slider->reset(); return 1;}
1443   BluebananaWindow *gui;
1444 };
1445 class BluebananaRAReset : public BC_GenericButton{
1446  public:
1447   BluebananaRAReset(BluebananaWindow *gui, int w) : BC_GenericButton(-1, -1, w, _("Reset")){
1448     this->gui = gui;
1449   }
1450   int handle_event() { gui->Radj_slider->reset(); return 1;}
1451   BluebananaWindow *gui;
1452 };
1453 class BluebananaGAReset : public BC_GenericButton{
1454  public:
1455   BluebananaGAReset(BluebananaWindow *gui, int w) : BC_GenericButton(-1, -1, w, _("Reset")){
1456     this->gui = gui;
1457   }
1458   int handle_event() { gui->Gadj_slider->reset(); return 1;}
1459   BluebananaWindow *gui;
1460 };
1461 class BluebananaBAReset : public BC_GenericButton{
1462  public:
1463   BluebananaBAReset(BluebananaWindow *gui, int w) : BC_GenericButton(-1, -1, w, _("Reset")){
1464     this->gui = gui;
1465   }
1466   int handle_event() { gui->Badj_slider->reset(); return 1;}
1467   BluebananaWindow *gui;
1468 };
1469 class BluebananaOAReset : public BC_GenericButton{
1470  public:
1471   BluebananaOAReset(BluebananaWindow *gui, int w) : BC_GenericButton(-1, -1, w, _("Reset")){
1472     this->gui = gui;
1473   }
1474   int handle_event() { gui->Oadj_slider->reset(); return 1;}
1475   BluebananaWindow *gui;
1476 };
1477 class BluebananaAAReset : public BC_GenericButton{
1478  public:
1479   BluebananaAAReset(BluebananaWindow *gui, int w) : BC_GenericButton(-1, -1, w, _("Reset")){
1480     this->gui = gui;
1481   }
1482   int handle_event() { gui->Aadj_slider->reset(); return 1;}
1483   BluebananaWindow *gui;
1484 };
1485
1486 // ----------------------------------- slider active buttons ------------------------------------
1487
1488 BluebananaHActive::BluebananaHActive(BluebananaMain *plugin, BluebananaWindow *gui)
1489   : BC_CheckBox(-1, -1, &plugin->config.Hsel_active, ""){
1490   this->plugin = plugin;
1491   this->gui = gui;
1492 }
1493 int BluebananaHActive::handle_event(){
1494   plugin->config.Hsel_active = get_value();
1495   update();
1496   return 1;
1497 }
1498 void BluebananaHActive::update(){
1499   this->BC_CheckBox::update(plugin->config.Hsel_active,1);
1500   gui->Hsel_slider->update();
1501 }
1502
1503 BluebananaSActive::BluebananaSActive(BluebananaMain *plugin, BluebananaWindow *gui)
1504   : BC_CheckBox(-1, -1, &plugin->config.Ssel_active, ""){
1505   this->plugin = plugin;
1506   this->gui = gui;
1507 }
1508 int BluebananaSActive::handle_event(){
1509   plugin->config.Ssel_active = get_value();
1510   update();
1511   return 1;
1512 }
1513 void BluebananaSActive::update(){
1514   this->BC_CheckBox::update(plugin->config.Ssel_active,1);
1515   gui->Ssel_slider->update();
1516 }
1517
1518 BluebananaVActive::BluebananaVActive(BluebananaMain *plugin, BluebananaWindow *gui)
1519   : BC_CheckBox(-1, -1, &plugin->config.Vsel_active, ""){
1520   this->plugin = plugin;
1521   this->gui = gui;
1522 }
1523 int BluebananaVActive::handle_event(){
1524   plugin->config.Vsel_active = get_value();
1525   update();
1526   return 1;
1527 }
1528 void BluebananaVActive::update(){
1529   this->BC_CheckBox::update(plugin->config.Vsel_active,1);
1530   gui->Vsel_slider->update();
1531 }
1532
1533 class BluebananaFActive : public BC_CheckBox {
1534 public:
1535   BluebananaFActive(BluebananaMain *plugin, BluebananaWindow *gui)
1536   : BC_CheckBox(-1, -1, &plugin->config.Fsel_active, ""){
1537     this->plugin = plugin;
1538     this->gui = gui;
1539   }
1540   virtual int handle_event(){
1541     plugin->config.Fsel_active = get_value();
1542     update();
1543     return 1;
1544   }
1545   void update(){
1546     this->BC_CheckBox::update(plugin->config.Fsel_active,1);
1547     gui->Fsel_slider->update();
1548   }
1549   BluebananaMain *plugin;
1550   BluebananaWindow *gui;
1551 };
1552
1553 class BluebananaHAActive : public BC_CheckBox {
1554 public:
1555   BluebananaHAActive(BluebananaMain *plugin, BluebananaWindow *gui)
1556   : BC_CheckBox(-1, -1, &plugin->config.Hadj_active, ""){
1557     this->plugin = plugin;
1558     this->gui = gui;
1559   }
1560   virtual int handle_event(){
1561     plugin->config.Hadj_active = get_value();
1562     update();
1563     return 1;
1564   }
1565   void update(){
1566     this->BC_CheckBox::update(plugin->config.Hadj_active,1);
1567     gui->Hadj_slider->update();
1568   }
1569   BluebananaMain *plugin;
1570   BluebananaWindow *gui;
1571 };
1572
1573 class BluebananaSAActive : public BC_CheckBox {
1574 public:
1575   BluebananaSAActive(BluebananaMain *plugin, BluebananaWindow *gui)
1576   : BC_CheckBox(-1, -1, &plugin->config.Sadj_active, ""){
1577     this->plugin = plugin;
1578     this->gui = gui;
1579   }
1580   virtual int handle_event(){
1581     plugin->config.Sadj_active = get_value();
1582     update();
1583     return 1;
1584   }
1585   void update(){
1586     this->BC_CheckBox::update(plugin->config.Sadj_active,1);
1587     gui->Sadj_slider->update();
1588   }
1589   BluebananaMain *plugin;
1590   BluebananaWindow *gui;
1591 };
1592
1593 class BluebananaVAActive : public BC_CheckBox {
1594 public:
1595   BluebananaVAActive(BluebananaMain *plugin, BluebananaWindow *gui)
1596   : BC_CheckBox(-1, -1, &plugin->config.Vadj_active, ""){
1597     this->plugin = plugin;
1598     this->gui = gui;
1599   }
1600   virtual int handle_event(){
1601     plugin->config.Vadj_active = get_value();
1602     update();
1603     return 1;
1604   }
1605   void update(){
1606     this->BC_CheckBox::update(plugin->config.Vadj_active,1);
1607     gui->Vadj_slider->update();
1608   }
1609   BluebananaMain *plugin;
1610   BluebananaWindow *gui;
1611 };
1612
1613 class BluebananaRAActive : public BC_CheckBox {
1614 public:
1615   BluebananaRAActive(BluebananaMain *plugin, BluebananaWindow *gui)
1616   : BC_CheckBox(-1, -1, &plugin->config.Radj_active, ""){
1617     this->plugin = plugin;
1618     this->gui = gui;
1619   }
1620   virtual int handle_event(){
1621     plugin->config.Radj_active = get_value();
1622     update();
1623     return 1;
1624   }
1625   void update(){
1626     this->BC_CheckBox::update(plugin->config.Radj_active,1);
1627     gui->Radj_slider->update();
1628   }
1629   BluebananaMain *plugin;
1630   BluebananaWindow *gui;
1631 };
1632
1633 class BluebananaGAActive : public BC_CheckBox {
1634 public:
1635   BluebananaGAActive(BluebananaMain *plugin, BluebananaWindow *gui)
1636   : BC_CheckBox(-1, -1, &plugin->config.Gadj_active, ""){
1637     this->plugin = plugin;
1638     this->gui = gui;
1639   }
1640   virtual int handle_event(){
1641     plugin->config.Gadj_active = get_value();
1642     update();
1643     return 1;
1644   }
1645   void update(){
1646     this->BC_CheckBox::update(plugin->config.Gadj_active,1);
1647     gui->Gadj_slider->update();
1648   }
1649   BluebananaMain *plugin;
1650   BluebananaWindow *gui;
1651 };
1652
1653 class BluebananaBAActive : public BC_CheckBox {
1654 public:
1655   BluebananaBAActive(BluebananaMain *plugin, BluebananaWindow *gui)
1656   : BC_CheckBox(-1, -1, &plugin->config.Badj_active, ""){
1657     this->plugin = plugin;
1658     this->gui = gui;
1659   }
1660   virtual int handle_event(){
1661     plugin->config.Badj_active = get_value();
1662     update();
1663     return 1;
1664   }
1665   void update(){
1666     this->BC_CheckBox::update(plugin->config.Badj_active,1);
1667     gui->Badj_slider->update();
1668   }
1669   BluebananaMain *plugin;
1670   BluebananaWindow *gui;
1671 };
1672
1673 class BluebananaOAActive : public BC_CheckBox {
1674 public:
1675   BluebananaOAActive(BluebananaMain *plugin, BluebananaWindow *gui)
1676   : BC_CheckBox(-1, -1, &plugin->config.Oadj_active, ""){
1677     this->plugin = plugin;
1678     this->gui = gui;
1679   }
1680   virtual int handle_event(){
1681     plugin->config.Oadj_active = get_value();
1682     update();
1683     return 1;
1684   }
1685   void update(){
1686     this->BC_CheckBox::update(plugin->config.Oadj_active,1);
1687     gui->Oadj_slider->update();
1688   }
1689   BluebananaMain *plugin;
1690   BluebananaWindow *gui;
1691 };
1692
1693 class BluebananaAAActive : public BC_CheckBox {
1694 public:
1695
1696   BluebananaAAActive(BluebananaMain *plugin, BluebananaWindow *gui)
1697   : BC_CheckBox(-1, -1, &plugin->config.Aadj_active, ""){
1698     this->plugin = plugin;
1699     this->gui = gui;
1700   }
1701   virtual int handle_event(){
1702     plugin->config.Aadj_active =
1703       !BC_CModels::has_alpha(plugin->colormodel) ? 0 : get_value();
1704     update();
1705     return 1;
1706   }
1707   void update(){
1708     this->BC_CheckBox::update(plugin->config.Aadj_active,1);
1709     if( BC_CModels::has_alpha(plugin->colormodel) ) {
1710       if( is_hidden() ) show_window();
1711     }else{
1712       if( !is_hidden() ) hide_window();
1713     }
1714     if( is_hidden() ) return;
1715     gui->Aadj_slider->update();
1716   }
1717   BluebananaMain *plugin;
1718   BluebananaWindow *gui;
1719 };
1720
1721 // -------------------------------------------- Erode --------------------------------------------
1722 class BluebananaErode : public BC_CheckBox {
1723 public:
1724   BluebananaErode(BluebananaMain *plugin, BluebananaWindow *gui)
1725   : BC_CheckBox(-1, -1, &plugin->config.Fsel_erode, ""){
1726     this->plugin = plugin;
1727     this->gui = gui;
1728   }
1729   virtual int handle_event(){
1730     plugin->config.Fsel_erode = get_value();
1731     update();
1732     return 1;
1733   }
1734   void update(){
1735     this->BC_CheckBox::update(plugin->config.Fsel_erode,1);
1736     gui->Fsel_slider->update();
1737   }
1738   BluebananaMain *plugin;
1739   BluebananaWindow *gui;
1740 };
1741
1742
1743 // -------------------------------------- Invert Selection ---------------------------------------
1744 class BluebananaIS : public BC_CheckBox {
1745 public:
1746   BluebananaIS(BluebananaMain *plugin, BluebananaWindow *gui)
1747   : BC_CheckBox(-1, -1, &plugin->config.invert_selection, ""){
1748     this->plugin = plugin;
1749     this->gui = gui;
1750   }
1751   virtual int handle_event(){
1752     plugin->config.invert_selection = get_value();
1753     update();
1754     return 1;
1755   }
1756   void update(){
1757     this->BC_CheckBox::update(plugin->config.invert_selection,1);
1758     gui->enter_config_change();
1759     gui->commit_config_change();
1760   }
1761   BluebananaMain *plugin;
1762   BluebananaWindow *gui;
1763 };
1764
1765
1766 // -------------------------------------------- Op --------------------------------------------
1767 class BluebananaOp : public BC_CheckBox {
1768 public:
1769   BluebananaOp(BluebananaMain *plugin, BluebananaWindow *gui)
1770     : BC_CheckBox(-1, -1, &plugin->config.op, ""){
1771     this->plugin = plugin;
1772     this->gui = gui;
1773   }
1774   virtual int handle_event() {
1775     if(plugin->config.op != get_value()){
1776       plugin->config.op = get_value();
1777       gui->enter_config_change();
1778       gui->commit_config_change();
1779     }
1780     return 1;
1781   }
1782   void update (){
1783     if(plugin->config.op != get_value()){
1784       this->BC_CheckBox::update(plugin->config.op,1);
1785     }
1786   };
1787   BluebananaMain *plugin;
1788   BluebananaWindow *gui;
1789 };
1790
1791 // -------------------------------------------- Mark --------------------------------------------
1792 class BluebananaMark : public BC_CheckBox {
1793 public:
1794   BluebananaMark(BluebananaMain *plugin, BluebananaWindow *gui)
1795     : BC_CheckBox(-1, -1, 0, ""){
1796     this->plugin = plugin;
1797     this->gui = gui;
1798   }
1799   virtual int handle_event() {
1800     if(plugin->config.mark != get_value()){
1801       plugin->config.mark = get_value();
1802       plugin->save_nonauto();
1803       if(plugin->config.mark){
1804         gui->set_repeat(207);
1805       }else{
1806         gui->unset_repeat(207);
1807       }
1808       plugin->server->mwindow->sync_parameters();
1809     }
1810     return 1;
1811   }
1812   void update (){
1813     if(plugin->config.mark != get_value()){
1814       this->BC_CheckBox::update(plugin->config.mark,1);
1815       if(plugin->config.mark){
1816         gui->set_repeat(207);
1817       }else{
1818         gui->unset_repeat(207);
1819       }
1820     }
1821   };
1822   BluebananaMain *plugin;
1823   BluebananaWindow *gui;
1824 };
1825
1826 // ------------------------------------------- Active -------------------------------------------
1827 class BluebananaActive : public BC_CheckBox {
1828 public:
1829   BluebananaActive(BluebananaMain *plugin, BluebananaWindow *gui)
1830     : BC_CheckBox(-1, -1, &plugin->config.active, ""){
1831     this->plugin = plugin;
1832     this->gui = gui;
1833     active=-1;
1834   }
1835   virtual int handle_event(){
1836     active = get_value();
1837     update();
1838     return 1;
1839   }
1840   void update(){
1841     if(active != plugin->config.active){
1842       if(active>=0)
1843         plugin->config.active = active;
1844       else
1845         active = plugin->config.active;
1846       this->BC_CheckBox::update(active,1);
1847       gui->enter_config_change();
1848       gui->Hadj_slider->update();
1849       gui->Sadj_slider->update();
1850       gui->Vadj_slider->update();
1851       gui->Radj_slider->update();
1852       gui->Gadj_slider->update();
1853       gui->Badj_slider->update();
1854       gui->Oadj_slider->update();
1855       gui->Aadj_slider->update();
1856       gui->commit_config_change();
1857     }
1858   }
1859   BluebananaMain *plugin;
1860   BluebananaWindow *gui;
1861   int active;
1862 };
1863
1864 // ---------------------------------------- Capture mask ---------------------------------------
1865 class BluebananaUnmask : public BC_CheckBox {
1866 public:
1867   BluebananaUnmask(BluebananaMain *plugin, BluebananaWindow *gui,int padx)
1868     : BC_CheckBox(-1, -1, &plugin->config.capture_mask, ""){
1869     this->plugin = plugin;
1870     this->gui = gui;
1871     this->padx = padx;
1872     this->label = new BC_Title(-1,-1,_(" End Mask"));
1873     this->x=-1;
1874     this->y=-1;
1875     gui->add_subwindow(this->label);
1876     gui->add_subwindow(this);
1877   }
1878   virtual int handle_event(){
1879     plugin->config.capture_mask=get_value();
1880     plugin->save_nonauto();
1881     update();
1882     gui->enter_config_change();
1883     gui->commit_config_change();
1884     return 1;
1885   }
1886   int get_h(){
1887     return label->get_h();
1888   }
1889   int get_w(){
1890     return BC_CheckBox::get_w()+label->get_w()+padx*4;
1891   }
1892   void reposition_window(int x, int y){
1893     int h = label->get_h();
1894     this->x = x;
1895     this->y = y;
1896     label->reposition_window(x+padx,y);
1897     BC_CheckBox::reposition_window(x+padx*2+label->get_w(),y+(h-BC_CheckBox::get_h())/2);
1898     update();
1899   }
1900   void update(){
1901     int w = get_w();
1902     int h = get_h();
1903     int f=0;
1904     int hideme = !plugin->config.use_mask;
1905     switch(plugin->colormodel){
1906     case BC_RGB888:
1907     case BC_RGB_FLOAT:
1908     case BC_YUV888:
1909     case BC_RGB161616:
1910     case BC_YUV161616:
1911       hideme=1;
1912       break;
1913     }
1914
1915     if(hideme && !is_hidden()){
1916       hide_window();
1917       label->hide_window();
1918       gui->set_color(get_resources()->get_bg_color());
1919       gui->draw_box(x,y,w,h);
1920       gui->set_color(get_resources()->default_text_color);
1921       gui->draw_line(x,y+h/2,x+w,y+h/2);
1922       f=1;
1923     }
1924
1925     if(!hideme && is_hidden()){
1926       gui->set_color(get_resources()->get_bg_color());
1927       gui->draw_box(x,y,w,h);
1928       show_window();
1929       label->show_window();
1930       f=1;
1931     }
1932
1933     if(plugin->config.capture_mask != get_value())
1934       this->BC_CheckBox::update(plugin->config.capture_mask,1);
1935     if(f)
1936       gui->flash(x,y,w,h);
1937   }
1938   BluebananaMain *plugin;
1939   BluebananaWindow *gui;
1940   BC_Title *label;
1941   int x,y,padx;
1942 };
1943
1944 // ------------------------------------------ Use mask ----------------------------------------
1945 class BluebananaA2Sel : public BC_CheckBox {
1946 public:
1947   BluebananaA2Sel(BluebananaMain *plugin, BluebananaWindow *gui,int padx)
1948     : BC_CheckBox(-1, -1, &plugin->config.use_mask, ""){
1949     this->plugin = plugin;
1950     this->gui = gui;
1951     this->padx = padx;
1952     this->label = new BC_Title(-1,-1,_(" Mask Selection"));
1953     this->x=-1;
1954     this->y=-1;
1955     gui->add_subwindow(this->label);
1956     gui->add_subwindow(this);
1957   }
1958   virtual int handle_event(){
1959     plugin->config.use_mask=get_value();
1960     plugin->save_nonauto();
1961     update();
1962     gui->enter_config_change();
1963     gui->commit_config_change();
1964     return 1;
1965   }
1966   int get_h(){
1967     return label->get_h();
1968   }
1969   int get_w(){
1970     return BC_CheckBox::get_w()+label->get_w()+padx*4;
1971   }
1972   void reposition_window(int x, int y){
1973     int h = label->get_h();
1974     this->x = x;
1975     this->y = y;
1976     label->reposition_window(x+padx,y);
1977     BC_CheckBox::reposition_window(x+padx*2+label->get_w(),y+(h-BC_CheckBox::get_h())/2);
1978     update();
1979   }
1980   void update(){
1981     int w = get_w();
1982     int h = get_h();
1983     int f=0;
1984
1985     if(gui->capture_mask)
1986       gui->capture_mask->update();
1987
1988     switch(plugin->colormodel){
1989     case BC_RGB888:
1990     case BC_RGB_FLOAT:
1991     case BC_YUV888:
1992     case BC_RGB161616:
1993     case BC_YUV161616:
1994       if(!is_hidden()){
1995         hide_window();
1996         label->hide_window();
1997         gui->set_color(get_resources()->get_bg_color());
1998         gui->draw_box(x,y,w,h);
1999         gui->set_color(get_resources()->default_text_color);
2000         gui->draw_line(x,y+h/2,x+w,y+h/2);
2001         f=1;
2002       }
2003       break;
2004     case BC_RGBA8888:
2005     case BC_RGBA_FLOAT:
2006     case BC_YUVA8888:
2007     case BC_RGBA16161616:
2008     case BC_YUVA16161616:
2009       if(is_hidden()){
2010         gui->set_color(get_resources()->get_bg_color());
2011         gui->draw_box(x,y,w,h);
2012         show_window();
2013         label->show_window();
2014         f=1;
2015       }
2016       break;
2017     case -1:
2018       // not initialized yet
2019       return;
2020     default:
2021       fprintf(stderr,_("Unknown colormodel in BluebananaA2Sel:update()\n"));
2022       break;
2023     }
2024     if(plugin->config.use_mask != get_value())
2025       this->BC_CheckBox::update(plugin->config.use_mask,1);
2026     if(f)
2027       gui->flash(x,y,w,h);
2028   }
2029   BluebananaMain *plugin;
2030   BluebananaWindow *gui;
2031   BC_Title *label;
2032   int x,y,padx;
2033 };
2034
2035 // --------------------------------------- Main GUI window --------------------------------------
2036 BluebananaWindow::BluebananaWindow(BluebananaMain *plugin)
2037  : PluginClientWindow(plugin,xS(1000),yS(1000),0,1,1)
2038 {
2039   do_render=0;
2040   windowx = get_x();
2041   windowy = get_y();
2042   this->plugin = plugin;
2043   config_refcount=1; // suppress pushing config during startup
2044   config_change=0;
2045   config_produce=0;
2046   config_consume=0;
2047   config_pending=0;
2048
2049   Hsel_slider=NULL;
2050   Ssel_slider=NULL;
2051   Vsel_slider=NULL;
2052   Fsel_slider=NULL;
2053   Hadj_slider=NULL;
2054   Sadj_slider=NULL;
2055   Vadj_slider=NULL;
2056   Radj_slider=NULL;
2057   Gadj_slider=NULL;
2058   Badj_slider=NULL;
2059   Oadj_slider=NULL;
2060   Aadj_slider=NULL;
2061
2062   use_mask=0;
2063   capture_mask=0;
2064 }
2065
2066 BluebananaWindow::~BluebananaWindow()
2067 {
2068 }
2069
2070 void BluebananaWindow::create_objects()
2071 {
2072   int xmargin = 20, ymargin = 10;
2073   float row_padding = .1;
2074   float column_padding = .3;
2075   int padx=0;
2076
2077   int i;
2078   int row_h=0, row_adv=0;
2079   int label_x=0;
2080   int label_w=0;
2081   int slider_w=0;
2082   int picker_w=0;
2083   int reset_w=0;
2084   int tumbler_w=0,tumbler_ww=0,tumbler_h=0;
2085   int tumbler_col1_x=0,tumbler_col2_x=0,tumbler_col2_w=0;
2086   int y = ymargin;
2087
2088   //BluebananaHAReset *hareset=NULL;
2089
2090   config_refcount=0;
2091   enter_config_change();
2092
2093   /* window headline */
2094   {
2095     BC_Title *l = new BC_Title(xmargin,y,_("Combine Selection"));
2096     BC_Title *l2 = new BC_Title(-1,-1,_(" Mark Selected Areas"));
2097     add_subwindow(mark = new BluebananaMark(plugin,this));
2098     add_subwindow(l);
2099     add_subwindow(l2);
2100     padx = l->get_h()*column_padding;
2101     add_subwindow(op = new BluebananaOp(plugin,this));
2102     int x0 = xmargin + l->get_w() + padx;
2103     op->reposition_window(x0,y-(op->get_h()-l->get_h())/2);
2104     x0 += op->get_w() + padx;
2105     int x1 = get_w()-xmargin-mark->get_w();
2106     mark->reposition_window(x1,y-(mark->get_h()-l->get_h())/2);
2107     x1 -= padx+l2->get_w();
2108     l2->reposition_window(x1,y);
2109     x1-=padx;
2110
2111     set_color(get_resources()->default_text_color);
2112     int y0 = y+l->get_h()*.5;
2113     draw_line(x0,y0, x1,y0);
2114
2115     y += l->get_h()*(row_padding+1.);
2116   }
2117
2118   label_x = xmargin + 100 + padx;
2119   const char *labels[12]={_("hue"),_("saturation"),_("value"),_("fill"),_("red"),_("green"),_("blue"),_("hue"),_("saturation"),_("value"),_("fade"),_("alpha")};
2120   for(i=0;i<12;i++){
2121     add_subwindow(slider_labels[i] = new BC_Title(-1,-1,labels[i]));
2122     if(slider_labels[i]->get_w()>label_w)label_w=slider_labels[i]->get_w();
2123   }
2124
2125   int tumbler_text_ww = MAX(get_text_width(MEDIUMFONT,"-000"),get_text_width(MEDIUMFONT,"5.00"))+8;
2126   int tumbler_text_w = get_text_width(MEDIUMFONT,"50")+8;
2127   if(tumbler_text_w*3<tumbler_text_ww*2){
2128     tumbler_text_ww = (tumbler_text_ww*2+2)/3*3/2;
2129     tumbler_text_w=tumbler_text_ww*2/3;
2130   }
2131
2132   erode_label = new BC_Title(xmargin,y,_("pre-erode"));
2133   BluebananaErode *erode = new BluebananaErode(plugin,this);
2134   add_subwindow(erode_label);
2135   add_subwindow(erode);
2136
2137   for(i=0;i<12;i++){
2138     BC_GenericButton *p=NULL;
2139     BluebananaSlider *s=NULL;
2140     BB_Tumble *t0 = NULL, *t1=NULL, *t2=NULL;
2141     BC_Toggle *a = NULL;
2142     BC_Title *l = slider_labels[i];
2143
2144     switch(i){
2145     case 0:
2146
2147       add_subwindow(t0 = Hsel_readout0 = new BluebananaHSReadout0(plugin,this,tumbler_text_ww));
2148       add_subwindow(t1 = Hsel_readout1 = new BluebananaHSReadout1(plugin,this,tumbler_text_ww));
2149       add_subwindow(t2 = Hsel_readout2 = new BluebananaHSReadout2(plugin,this,tumbler_text_ww));
2150       add_subwindow(a = Hsel_active = new BluebananaHActive(plugin,this));
2151
2152       /* need a narrow and a wide wide tumbler */
2153       add_subwindow(Fsel_readout0 = new BluebananaFSReadout0(plugin,this,tumbler_text_w));
2154       add_subwindow(Fsel_readout1 = new BluebananaFSReadout1(plugin,this,tumbler_text_w));
2155       add_subwindow(Fsel_readout2 = new BluebananaFSReadout2(plugin,this,tumbler_text_w));
2156       add_subwindow(Fsel_readout3 = new BluebananaFSReadout3(plugin,this,tumbler_text_ww));
2157       tumbler_w = Fsel_readout0->get_w();
2158       tumbler_ww = t0->get_w();
2159       tumbler_h = t0->get_h();
2160
2161       /* need a reset button's width */
2162       reset_w = BC_GenericButton::calculate_w(this, _("Reset"));
2163       picker_w = BC_GenericButton::calculate_w(this, _("Pick"));
2164
2165       /* determine row spacing */
2166       row_h = 30; /* minimum widget height allowance for the row
2167                      (really, min height for the slider) */
2168       if(row_h<a->get_h())row_h=a->get_h();
2169       if(row_h<l->get_h())row_h=l->get_h();
2170       if(row_h<BC_GenericButton::calculate_h())row_h=BC_GenericButton::calculate_h();
2171       if(row_h<t2->get_h())row_h=t2->get_h();
2172       row_adv = row_h*(1.+row_padding);
2173
2174       /* determine horizontal element positioning; two main setups */
2175       /* setup 1: three tumblers + button */
2176       tumbler_col2_w = MAX(reset_w,picker_w);
2177
2178       /* setup 2: four tumblers + erode */
2179       {
2180         int threew = tumbler_ww*3 + padx*4 + tumbler_col2_w;
2181         int fourw = tumbler_w*3 + tumbler_ww + padx*5 + erode->get_w() + erode_label->get_w();
2182         if(fourw>threew) tumbler_col2_w += fourw-threew;
2183       }
2184
2185       tumbler_col2_x = get_w()-xmargin-tumbler_col2_w;
2186       tumbler_col1_x = tumbler_col2_x - tumbler_ww*3 - padx*5;
2187       slider_x = label_x+padx;
2188       slider_w = (tumbler_col1_x - slider_x - padx*3);
2189
2190       /* make sure the label x doesn't cause any labels to go off the
2191          left of the pane */
2192       {
2193         int lx = label_x - padx - a->get_w();
2194         if (lx-label_w < xmargin){
2195           slider_x += ((xmargin+label_w)-lx);
2196           label_x += ((xmargin+label_w)-lx);
2197           slider_w -= ((xmargin+label_w)-lx);
2198         }
2199       }
2200
2201       y += row_adv/3; /* extra half row spacing under headline */
2202       s = Hsel_slider = new BluebananaHSSlider(plugin,this,slider_x,y,slider_w,row_h);
2203       add_subwindow(p = new BluebananaHPicker(this,tumbler_col2_w));
2204
2205       /* Move the upper alpha <->selection config buttons into place */
2206       {
2207         int x0 = slider_x+slider_w+padx*2;
2208         invert_selection = new BluebananaIS(plugin,this);
2209         BC_Title *l = new BC_Title(xmargin,y,_(" Invert Selection"));
2210         add_subwindow(l);
2211         add_subwindow(invert_selection);
2212         int w0 = padx+l->get_w()+padx+invert_selection->get_w()+padx*2;
2213         set_color(get_resources()->get_bg_color());
2214         draw_box(x0-w0,ymargin,w0,ymargin+l->get_h());
2215         x0-=padx*2;
2216         x0-=invert_selection->get_w();
2217         invert_selection->reposition_window(x0,ymargin+(l->get_h()-invert_selection->get_h())/2);
2218         x0-=padx;
2219         x0-=l->get_w();
2220         l->reposition_window(x0,ymargin);
2221         x0-=padx;
2222         x0-=padx*5;
2223
2224         use_mask = new BluebananaA2Sel(plugin,this,padx);
2225         x0-=use_mask->get_w();
2226         use_mask->reposition_window(x0, ymargin);
2227         capture_mask = new BluebananaUnmask(plugin,this,padx);
2228         x0-=padx*5 + capture_mask->get_w();
2229         capture_mask->reposition_window(x0, ymargin);
2230       }
2231
2232       break;
2233
2234     case 1:
2235
2236       add_subwindow(t0 = Ssel_readout0 = new BluebananaSSReadout0(plugin,this,tumbler_text_ww));
2237       add_subwindow(t1 = Ssel_readout1 = new BluebananaSSReadout1(plugin,this,tumbler_text_ww));
2238       add_subwindow(t2 = Ssel_readout2 = new BluebananaSSReadout2(plugin,this,tumbler_text_ww));
2239       add_subwindow(a = Ssel_active = new BluebananaSActive(plugin,this));
2240       add_subwindow(p = new BluebananaSPicker(this,tumbler_col2_w));
2241       s = Ssel_slider = new BluebananaSSSlider(plugin,this,slider_x,y,slider_w,row_h);
2242       break;
2243
2244     case 2:
2245
2246       add_subwindow(t0 = Vsel_readout0 = new BluebananaVSReadout0(plugin,this,tumbler_text_ww));
2247       add_subwindow(t1 = Vsel_readout1 = new BluebananaVSReadout1(plugin,this,tumbler_text_ww));
2248       add_subwindow(t2 = Vsel_readout2 = new BluebananaVSReadout2(plugin,this,tumbler_text_ww));
2249       add_subwindow(a = Vsel_active = new BluebananaVActive(plugin,this));
2250       add_subwindow(p = new BluebananaVPicker(this,tumbler_col2_w));
2251       s = Vsel_slider = new BluebananaVSSlider(plugin,this,slider_x,y,slider_w,row_h);
2252       break;
2253
2254     case 3:
2255
2256       add_subwindow(a = Fsel_active = new BluebananaFActive(plugin,this));
2257       s = Fsel_slider = new BluebananaFSSlider(plugin,this,slider_x,y,slider_w,row_h);
2258
2259       Fsel_readout0->reposition_window(tumbler_col1_x, y + (row_h-tumbler_h)/2 + 1);
2260       Fsel_readout1->reposition_window(tumbler_col1_x+tumbler_w, y + (row_h-tumbler_h)/2 + 1);
2261       Fsel_readout2->reposition_window(tumbler_col1_x+tumbler_w*2, y + (row_h-tumbler_h)/2 + 1);
2262       Fsel_readout3->reposition_window(tumbler_col1_x+tumbler_w*3+padx*2,
2263                                        y + (row_h-tumbler_h)/2 + 1);
2264
2265       {
2266         int x = get_w() - xmargin - erode->get_w();
2267         erode->reposition_window(x,y+(row_h-erode->get_h())/2);
2268         erode_label->reposition_window(x-erode_label->get_w()-padx,y+(row_h-erode_label->get_h())/2);
2269       }
2270
2271       break;
2272
2273     case 4:
2274
2275       add_subwindow(t0 = Radj_readout0 = new BluebananaRAReadout0(plugin,this,tumbler_text_ww));
2276       add_subwindow(t1 = Radj_readout1 = new BluebananaRAReadout1(plugin,this,tumbler_text_ww));
2277       add_subwindow(t2 = Radj_readout2 = new BluebananaRAReadout2(plugin,this,tumbler_text_ww));
2278       add_subwindow(a = Radj_active = new BluebananaRAActive(plugin,this));
2279       add_subwindow(p = new BluebananaRAReset(this,tumbler_col2_w));
2280       s = Radj_slider = new BluebananaRASlider(plugin,this,slider_x,y,slider_w,row_h);
2281       break;
2282
2283     case 5:
2284
2285       add_subwindow(t0 = Gadj_readout0 = new BluebananaGAReadout0(plugin,this,tumbler_text_ww));
2286       add_subwindow(t1 = Gadj_readout1 = new BluebananaGAReadout1(plugin,this,tumbler_text_ww));
2287       add_subwindow(t2 = Gadj_readout2 = new BluebananaGAReadout2(plugin,this,tumbler_text_ww));
2288       add_subwindow(a = Gadj_active = new BluebananaGAActive(plugin,this));
2289       add_subwindow(p = new BluebananaGAReset(this,tumbler_col2_w));
2290       s = Gadj_slider = new BluebananaGASlider(plugin,this,slider_x,y,slider_w,row_h);
2291       break;
2292
2293     case 6:
2294
2295       add_subwindow(t0 = Badj_readout0 = new BluebananaBAReadout0(plugin,this,tumbler_text_ww));
2296       add_subwindow(t1 = Badj_readout1 = new BluebananaBAReadout1(plugin,this,tumbler_text_ww));
2297       add_subwindow(t2 = Badj_readout2 = new BluebananaBAReadout2(plugin,this,tumbler_text_ww));
2298       add_subwindow(a = Badj_active = new BluebananaBAActive(plugin,this));
2299       add_subwindow(p = new BluebananaBAReset(this,tumbler_col2_w));
2300       s = Badj_slider = new BluebananaBASlider(plugin,this,slider_x,y,slider_w,row_h);
2301       break;
2302
2303     case 7:
2304
2305       add_subwindow(t0 = Hadj_readout = new BluebananaHAReadout(plugin,this,tumbler_text_ww));
2306       add_subwindow(a = Hadj_active = new BluebananaHAActive(plugin,this));
2307       add_subwindow(p = new BluebananaHAReset(this,tumbler_col2_w));
2308       s = Hadj_slider = new BluebananaHASlider(plugin,this,slider_x,y,slider_w,row_h);
2309       break;
2310
2311     case 8:
2312
2313       add_subwindow(t0 = Sadj_readout0 = new BluebananaSAReadout0(plugin,this,tumbler_text_ww));
2314       add_subwindow(t1 = Sadj_readout1 = new BluebananaSAReadout1(plugin,this,tumbler_text_ww));
2315       add_subwindow(t2 = Sadj_readout2 = new BluebananaSAReadout2(plugin,this,tumbler_text_ww));
2316
2317       add_subwindow(a = Sadj_active = new BluebananaSAActive(plugin,this));
2318       add_subwindow(p = new BluebananaSAReset(this,tumbler_col2_w));
2319       s = Sadj_slider = new BluebananaSASlider(plugin,this,slider_x,y,slider_w,row_h);
2320       break;
2321
2322     case 9:
2323
2324       add_subwindow(t0 = Vadj_readout0 = new BluebananaVAReadout0(plugin,this,tumbler_text_ww));
2325       add_subwindow(t1 = Vadj_readout1 = new BluebananaVAReadout1(plugin,this,tumbler_text_ww));
2326       add_subwindow(t2 = Vadj_readout2 = new BluebananaVAReadout2(plugin,this,tumbler_text_ww));
2327       add_subwindow(a = Vadj_active = new BluebananaVAActive(plugin,this));
2328       add_subwindow(p = new BluebananaVAReset(this,tumbler_col2_w));
2329       s = Vadj_slider = new BluebananaVASlider(plugin,this,slider_x,y,slider_w,row_h);
2330       break;
2331
2332     case 10:
2333
2334       add_subwindow(t0 = Oadj_readout = new BluebananaOAReadout(plugin,this,tumbler_text_ww));
2335       add_subwindow(a = Oadj_active = new BluebananaOAActive(plugin,this));
2336       add_subwindow(p = new BluebananaOAReset(this,tumbler_col2_w));
2337       s = Oadj_slider = new BluebananaOASlider(plugin,this,slider_x,y,slider_w,row_h);
2338       break;
2339
2340     case 11:
2341
2342       add_subwindow(t0 = Aadj_readout = new BluebananaAAReadout(plugin,this,tumbler_text_ww));
2343       add_subwindow(a = Aadj_active = new BluebananaAAActive(plugin,this));
2344       add_subwindow(p = new BluebananaAAReset(this,tumbler_col2_w));
2345       s = Aadj_slider = new BluebananaAASlider(plugin,this,slider_x,y,slider_w,row_h);
2346       break;
2347
2348     }
2349     add_subwindow(s);
2350
2351     if(a)a->reposition_window(label_x - padx - a->get_w(), y + (row_h-a->get_h())/2 + 1);
2352     if(l)l->reposition(label_x - l->get_w() - padx*2 - a->get_w(), y + (row_h-l->get_h())/2 + 1);
2353
2354     if(p){
2355       p->BC_SubWindow::reposition_window(tumbler_col2_x, y + (row_h-p->get_h())/2 + 1,
2356                                          MAX(tumbler_col2_w,picker_w),p->get_h());
2357
2358       // work around bug; the reposition step does not fully redraw the button
2359       p->draw_face();
2360     }
2361
2362     if(t0)t0->reposition_window(tumbler_col1_x,
2363                                 y + (row_h-tumbler_h)/2 + 1);
2364
2365     if(t1)t1->reposition_window(tumbler_col1_x+tumbler_ww,
2366                                 y + (row_h-tumbler_h)/2 + 1);
2367
2368     if(t2)t2->reposition_window(tumbler_col1_x+tumbler_ww*2+padx*2+(tumbler_ww-t2->get_w())/2,
2369                                 y + (row_h-tumbler_h)/2 + 1);
2370
2371
2372     s->update();
2373
2374     y+=row_adv;
2375     if(i==3){
2376       y+=row_adv/3;
2377
2378       BC_Title *l = new BC_Title(xmargin,y,_("Color Adjustment"));
2379       BC_Title *l2 = new BC_Title(-1,-1,_(" Filter Active"));
2380       add_subwindow(l);
2381       add_subwindow(l2);
2382       add_subwindow(active = new BluebananaActive(plugin,this));
2383
2384       int x0 = get_w()-xmargin-mark->get_w();
2385       active->reposition_window(x0,y-(active->get_h()-l->get_h())/2);
2386       x0 -= padx+l2->get_w();
2387       l2->reposition_window(x0,y);
2388       x0 -= padx*2;
2389       set_color(get_resources()->default_text_color);
2390       draw_line(xmargin+l->get_w()+padx, y+l->get_h()*.5, x0, y+l->get_h()*.5);
2391
2392       y += l->get_h()*(row_padding+1.);
2393       y += row_adv/3;
2394     }
2395
2396
2397     if(i==6 || i==9){
2398       y+=row_adv/4;
2399
2400       set_color((s->dimtextcolor + get_resources()->default_text_color)/2);
2401       draw_line(slider_x+20, y+l->get_h()*.5, tumbler_col2_x-30, y+l->get_h()*.5);
2402
2403       y += l->get_h()*(row_padding+1.);
2404       y += row_adv/4;
2405     }
2406
2407
2408   }
2409   y += row_adv/2-4;
2410
2411   plugin->update_lookups(0);
2412   do_render=1;
2413
2414   resize_window(get_w(),y);
2415   show_window();
2416   reposition_window(windowx,windowy,get_w(),y);
2417   leave_config_change(); // also forces render
2418   plugin->server->mwindow->sync_parameters();
2419 }
2420
2421 int BluebananaWindow::close_event(){
2422   set_done(1);
2423   return 1;
2424 }
2425
2426 // adds one to config push refcount
2427 // updates any internal state immediately
2428 void BluebananaWindow::enter_config_change(){
2429   config_refcount++;
2430   if(!config_change && !plugin->update_cache.equivalent(plugin->config)){
2431     config_change=1;
2432   }
2433   plugin->update_lookups(0);
2434 }
2435
2436 // decrements one from config push refcount.  If refcount drops to
2437 // zero, pushes new config up to application
2438
2439 // also compresses events; waits 184ms for new events before pushing
2440 // configuration changes
2441 void BluebananaWindow::commit_config_change(){
2442   if(--config_refcount==0){
2443     if(config_change){
2444       config_change=0;
2445       config_produce++;
2446       config_pending=1;
2447       set_repeat(97);
2448     }
2449     render();
2450   }
2451 }
2452
2453 // decrements one from config push refcount.  Does not push config up
2454 // to application when refcount drops to zero (used to wrap update
2455 // requests coming from the application, not user-initiated state
2456 // changes)
2457 void BluebananaWindow::leave_config_change(){
2458   config_change=0;
2459   plugin->update_cache.copy_from(plugin->config);
2460   if(--config_refcount==0){
2461     render();
2462   }
2463 }
2464
2465 int BluebananaWindow::flush_config_change(){
2466   unset_repeat(97);
2467   if(config_pending){
2468     config_pending=0;
2469     plugin->update_cache.copy_from(plugin->config);
2470     plugin->send_configure_change();
2471   }
2472   config_consume=config_produce;
2473   return 0;
2474 }
2475
2476 int BluebananaWindow::repeat_event(int64_t d){
2477   if(d==97){
2478     if(config_consume!=config_produce)
2479       flush_config_change();
2480   }
2481   if(!plugin->server->plugin) return 0;
2482   if(!plugin->server->plugin->on) return 0;
2483   if(d==207){
2484
2485     /* if background render is active and we're showing the zebra, mark
2486        the current frame uncached so that we can push zebra changes */
2487     if(plugin->config.mark && plugin->server->mwindow->brender)
2488       plugin->server->mwindow->brender->set_video_map(plugin->source_position, BRender::SCANNED);
2489
2490     /* push update request without an EDL update */
2491     plugin->server->mwindow->sync_parameters();
2492   }
2493   return 0;
2494 }
2495
2496 /* engine -> gui update; don't allow any EDL pushes */
2497 void BluebananaWindow::update(){
2498
2499   // called to suppress configuration pushes
2500   enter_config_change();
2501
2502   // full configuration recompute and redraw
2503   Hsel_slider->update();
2504   Ssel_slider->update();
2505   Vsel_slider->update();
2506   Fsel_slider->update();
2507   Hadj_slider->update();
2508   Sadj_slider->update();
2509   Vadj_slider->update();
2510   Radj_slider->update();
2511   Gadj_slider->update();
2512   Badj_slider->update();
2513   Oadj_slider->update();
2514   Aadj_slider->update();
2515
2516   active->update();
2517   mark->update();
2518   use_mask->update();
2519   capture_mask->update();
2520   invert_selection->update();
2521
2522   Hsel_active->update();
2523   Ssel_active->update();
2524   Vsel_active->update();
2525   Fsel_active->update();
2526
2527   Hadj_active->update();
2528   Sadj_active->update();
2529   Vadj_active->update();
2530   Radj_active->update();
2531   Gadj_active->update();
2532   Badj_active->update();
2533   Oadj_active->update();
2534   Aadj_active->update();
2535
2536   // called to release configuration without pushing
2537   leave_config_change();
2538 }
2539
2540 void BluebananaWindow::render(){
2541   if(do_render){
2542     Hsel_slider->render();
2543     Ssel_slider->render();
2544     Vsel_slider->render();
2545     Fsel_slider->render();
2546     Hadj_slider->render();
2547     Sadj_slider->render();
2548     Vadj_slider->render();
2549     Radj_slider->render();
2550     Gadj_slider->render();
2551     Badj_slider->render();
2552     Oadj_slider->render();
2553     Aadj_slider->render();
2554   }
2555 }
2556
2557 void BluebananaWindow::update_histograms(BluebananaMain *plugin){
2558   int w = plugin->frame->get_w();
2559   int h = plugin->frame->get_h();
2560
2561   if(Radj_slider)Radj_slider->update_histogram(plugin->red_histogram,0,0,0,w*h);
2562   if(Gadj_slider)Gadj_slider->update_histogram(plugin->green_histogram,0,0,0,w*h);
2563   if(Badj_slider)Badj_slider->update_histogram(plugin->blue_histogram,0,0,0,w*h);
2564
2565   if(Hadj_slider)
2566     Hadj_slider->update_histogram(plugin->hue_histogram,
2567                                   plugin->hue_histogram_red,
2568                                   plugin->hue_histogram_green,
2569                                   plugin->hue_histogram_blue,w*h);
2570
2571   if(Sadj_slider)
2572     Sadj_slider->update_histogram(plugin->sat_histogram,
2573                                   plugin->sat_histogram_red,
2574                                   plugin->sat_histogram_green,
2575                                   plugin->sat_histogram_blue,w*h);
2576
2577   if(Vadj_slider)
2578     Vadj_slider->update_histogram(plugin->value_histogram,
2579                                   plugin->value_histogram_red,
2580                                   plugin->value_histogram_green,
2581                                   plugin->value_histogram_blue,w*h);
2582
2583 }