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