igor ru.po
[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   BluebananaAASlider(BluebananaMain *plugin, BluebananaWindow *gui,
1354                      int x, int y, int w, int h)
1355     : BluebananaSliderSingle(plugin,gui,x,y,w,h,0,100) {}
1356   virtual int handle_event() {
1357     plugin->config.Aadj_val = val;
1358     return 1;
1359   }
1360   void reset(){
1361     plugin->config.Aadj_val=100;
1362     update();
1363   }
1364   void update(){
1365     val = plugin->config.Aadj_val;
1366     if( BC_CModels::has_alpha(plugin->colormodel) ) {
1367       if( is_hidden() ) show_window();
1368     }else{
1369       if( !is_hidden() ) hide_window();
1370     }
1371     if( is_hidden() ) return;
1372     highlight = plugin->config.active && plugin->config.Aadj_active;
1373     gui->Aadj_readout->update(plugin->config.Aadj_val);
1374     gui->slider_labels[11]->set_color(highlight  && plugin->config.Aadj_val != 100 ?
1375          get_resources()->default_text_color : dimtextcolor);
1376     gui->enter_config_change();
1377     gui->commit_config_change();
1378   }
1379   void trough_color(float hdel, float vdel, float &r, float &g, float &b, float &a){
1380     r=g=b=.8;
1381     a=1-cos(hdel*M_PI*.5);
1382   }
1383 };
1384
1385 int BluebananaAAReadout::value_event(){
1386   float val = get_value();
1387   plugin->config.Aadj_val = val;
1388   gui->Aadj_slider->update();
1389   return 1;
1390 }
1391
1392 // ------------------------------------- picker buttons -----------------------------------------
1393 class BluebananaHPicker : public BC_GenericButton{
1394  public:
1395   BluebananaHPicker(BluebananaWindow *gui, int w) : BC_GenericButton(-1, -1, w, _("Pick")){
1396     this->gui = gui;
1397   }
1398   int handle_event() { gui->Hsel_slider->pick(); return 1; }
1399   BluebananaWindow *gui;
1400 };
1401 class BluebananaSPicker : public BC_GenericButton{
1402  public:
1403   BluebananaSPicker(BluebananaWindow *gui, int w) : BC_GenericButton(-1, -1, w, _("Pick")){
1404     this->gui = gui;
1405   }
1406   int handle_event() { gui->Ssel_slider->pick(); return 1; }
1407   BluebananaWindow *gui;
1408 };
1409 class BluebananaVPicker : public BC_GenericButton{
1410  public:
1411   BluebananaVPicker(BluebananaWindow *gui, int w) : BC_GenericButton(-1, -1, w, _("Pick")){
1412     this->gui = gui;
1413   }
1414   int handle_event() { gui->Vsel_slider->pick(); return 1; }
1415   BluebananaWindow *gui;
1416 };
1417
1418 // -------------------------------------- reset buttons -----------------------------------------
1419
1420 class BluebananaHAReset : public BC_GenericButton{
1421  public:
1422   BluebananaHAReset(BluebananaWindow *gui, int w) : BC_GenericButton(-1, -1, w, _("Reset")){
1423     this->gui = gui;
1424   }
1425   int handle_event() { gui->Hadj_slider->reset(); return 1;}
1426   BluebananaWindow *gui;
1427 };
1428 class BluebananaSAReset : public BC_GenericButton{
1429  public:
1430   BluebananaSAReset(BluebananaWindow *gui, int w) : BC_GenericButton(-1, -1, w, _("Reset")){
1431     this->gui = gui;
1432   }
1433   int handle_event() { gui->Sadj_slider->reset(); return 1;}
1434   BluebananaWindow *gui;
1435 };
1436 class BluebananaVAReset : public BC_GenericButton{
1437  public:
1438   BluebananaVAReset(BluebananaWindow *gui, int w) : BC_GenericButton(-1, -1, w, _("Reset")){
1439     this->gui = gui;
1440   }
1441   int handle_event() { gui->Vadj_slider->reset(); return 1;}
1442   BluebananaWindow *gui;
1443 };
1444 class BluebananaRAReset : public BC_GenericButton{
1445  public:
1446   BluebananaRAReset(BluebananaWindow *gui, int w) : BC_GenericButton(-1, -1, w, _("Reset")){
1447     this->gui = gui;
1448   }
1449   int handle_event() { gui->Radj_slider->reset(); return 1;}
1450   BluebananaWindow *gui;
1451 };
1452 class BluebananaGAReset : public BC_GenericButton{
1453  public:
1454   BluebananaGAReset(BluebananaWindow *gui, int w) : BC_GenericButton(-1, -1, w, _("Reset")){
1455     this->gui = gui;
1456   }
1457   int handle_event() { gui->Gadj_slider->reset(); return 1;}
1458   BluebananaWindow *gui;
1459 };
1460 class BluebananaBAReset : public BC_GenericButton{
1461  public:
1462   BluebananaBAReset(BluebananaWindow *gui, int w) : BC_GenericButton(-1, -1, w, _("Reset")){
1463     this->gui = gui;
1464   }
1465   int handle_event() { gui->Badj_slider->reset(); return 1;}
1466   BluebananaWindow *gui;
1467 };
1468 class BluebananaOAReset : public BC_GenericButton{
1469  public:
1470   BluebananaOAReset(BluebananaWindow *gui, int w) : BC_GenericButton(-1, -1, w, _("Reset")){
1471     this->gui = gui;
1472   }
1473   int handle_event() { gui->Oadj_slider->reset(); return 1;}
1474   BluebananaWindow *gui;
1475 };
1476 class BluebananaAAReset : public BC_GenericButton{
1477  public:
1478   BluebananaAAReset(BluebananaWindow *gui, int w) : BC_GenericButton(-1, -1, w, _("Reset")){
1479     this->gui = gui;
1480   }
1481   int handle_event() { gui->Aadj_slider->reset(); return 1;}
1482   BluebananaWindow *gui;
1483 };
1484
1485 // ----------------------------------- slider active buttons ------------------------------------
1486
1487 BluebananaHActive::BluebananaHActive(BluebananaMain *plugin, BluebananaWindow *gui)
1488   : BC_CheckBox(-1, -1, &plugin->config.Hsel_active, ""){
1489   this->plugin = plugin;
1490   this->gui = gui;
1491 }
1492 int BluebananaHActive::handle_event(){
1493   plugin->config.Hsel_active = get_value();
1494   update();
1495   return 1;
1496 }
1497 void BluebananaHActive::update(){
1498   this->BC_CheckBox::update(plugin->config.Hsel_active,1);
1499   gui->Hsel_slider->update();
1500 }
1501
1502 BluebananaSActive::BluebananaSActive(BluebananaMain *plugin, BluebananaWindow *gui)
1503   : BC_CheckBox(-1, -1, &plugin->config.Ssel_active, ""){
1504   this->plugin = plugin;
1505   this->gui = gui;
1506 }
1507 int BluebananaSActive::handle_event(){
1508   plugin->config.Ssel_active = get_value();
1509   update();
1510   return 1;
1511 }
1512 void BluebananaSActive::update(){
1513   this->BC_CheckBox::update(plugin->config.Ssel_active,1);
1514   gui->Ssel_slider->update();
1515 }
1516
1517 BluebananaVActive::BluebananaVActive(BluebananaMain *plugin, BluebananaWindow *gui)
1518   : BC_CheckBox(-1, -1, &plugin->config.Vsel_active, ""){
1519   this->plugin = plugin;
1520   this->gui = gui;
1521 }
1522 int BluebananaVActive::handle_event(){
1523   plugin->config.Vsel_active = get_value();
1524   update();
1525   return 1;
1526 }
1527 void BluebananaVActive::update(){
1528   this->BC_CheckBox::update(plugin->config.Vsel_active,1);
1529   gui->Vsel_slider->update();
1530 }
1531
1532 class BluebananaFActive : public BC_CheckBox {
1533 public:
1534   BluebananaFActive(BluebananaMain *plugin, BluebananaWindow *gui)
1535   : BC_CheckBox(-1, -1, &plugin->config.Fsel_active, ""){
1536     this->plugin = plugin;
1537     this->gui = gui;
1538   }
1539   virtual int handle_event(){
1540     plugin->config.Fsel_active = get_value();
1541     update();
1542     return 1;
1543   }
1544   void update(){
1545     this->BC_CheckBox::update(plugin->config.Fsel_active,1);
1546     gui->Fsel_slider->update();
1547   }
1548   BluebananaMain *plugin;
1549   BluebananaWindow *gui;
1550 };
1551
1552 class BluebananaHAActive : public BC_CheckBox {
1553 public:
1554   BluebananaHAActive(BluebananaMain *plugin, BluebananaWindow *gui)
1555   : BC_CheckBox(-1, -1, &plugin->config.Hadj_active, ""){
1556     this->plugin = plugin;
1557     this->gui = gui;
1558   }
1559   virtual int handle_event(){
1560     plugin->config.Hadj_active = get_value();
1561     update();
1562     return 1;
1563   }
1564   void update(){
1565     this->BC_CheckBox::update(plugin->config.Hadj_active,1);
1566     gui->Hadj_slider->update();
1567   }
1568   BluebananaMain *plugin;
1569   BluebananaWindow *gui;
1570 };
1571
1572 class BluebananaSAActive : public BC_CheckBox {
1573 public:
1574   BluebananaSAActive(BluebananaMain *plugin, BluebananaWindow *gui)
1575   : BC_CheckBox(-1, -1, &plugin->config.Sadj_active, ""){
1576     this->plugin = plugin;
1577     this->gui = gui;
1578   }
1579   virtual int handle_event(){
1580     plugin->config.Sadj_active = get_value();
1581     update();
1582     return 1;
1583   }
1584   void update(){
1585     this->BC_CheckBox::update(plugin->config.Sadj_active,1);
1586     gui->Sadj_slider->update();
1587   }
1588   BluebananaMain *plugin;
1589   BluebananaWindow *gui;
1590 };
1591
1592 class BluebananaVAActive : public BC_CheckBox {
1593 public:
1594   BluebananaVAActive(BluebananaMain *plugin, BluebananaWindow *gui)
1595   : BC_CheckBox(-1, -1, &plugin->config.Vadj_active, ""){
1596     this->plugin = plugin;
1597     this->gui = gui;
1598   }
1599   virtual int handle_event(){
1600     plugin->config.Vadj_active = get_value();
1601     update();
1602     return 1;
1603   }
1604   void update(){
1605     this->BC_CheckBox::update(plugin->config.Vadj_active,1);
1606     gui->Vadj_slider->update();
1607   }
1608   BluebananaMain *plugin;
1609   BluebananaWindow *gui;
1610 };
1611
1612 class BluebananaRAActive : public BC_CheckBox {
1613 public:
1614   BluebananaRAActive(BluebananaMain *plugin, BluebananaWindow *gui)
1615   : BC_CheckBox(-1, -1, &plugin->config.Radj_active, ""){
1616     this->plugin = plugin;
1617     this->gui = gui;
1618   }
1619   virtual int handle_event(){
1620     plugin->config.Radj_active = get_value();
1621     update();
1622     return 1;
1623   }
1624   void update(){
1625     this->BC_CheckBox::update(plugin->config.Radj_active,1);
1626     gui->Radj_slider->update();
1627   }
1628   BluebananaMain *plugin;
1629   BluebananaWindow *gui;
1630 };
1631
1632 class BluebananaGAActive : public BC_CheckBox {
1633 public:
1634   BluebananaGAActive(BluebananaMain *plugin, BluebananaWindow *gui)
1635   : BC_CheckBox(-1, -1, &plugin->config.Gadj_active, ""){
1636     this->plugin = plugin;
1637     this->gui = gui;
1638   }
1639   virtual int handle_event(){
1640     plugin->config.Gadj_active = get_value();
1641     update();
1642     return 1;
1643   }
1644   void update(){
1645     this->BC_CheckBox::update(plugin->config.Gadj_active,1);
1646     gui->Gadj_slider->update();
1647   }
1648   BluebananaMain *plugin;
1649   BluebananaWindow *gui;
1650 };
1651
1652 class BluebananaBAActive : public BC_CheckBox {
1653 public:
1654   BluebananaBAActive(BluebananaMain *plugin, BluebananaWindow *gui)
1655   : BC_CheckBox(-1, -1, &plugin->config.Badj_active, ""){
1656     this->plugin = plugin;
1657     this->gui = gui;
1658   }
1659   virtual int handle_event(){
1660     plugin->config.Badj_active = get_value();
1661     update();
1662     return 1;
1663   }
1664   void update(){
1665     this->BC_CheckBox::update(plugin->config.Badj_active,1);
1666     gui->Badj_slider->update();
1667   }
1668   BluebananaMain *plugin;
1669   BluebananaWindow *gui;
1670 };
1671
1672 class BluebananaOAActive : public BC_CheckBox {
1673 public:
1674   BluebananaOAActive(BluebananaMain *plugin, BluebananaWindow *gui)
1675   : BC_CheckBox(-1, -1, &plugin->config.Oadj_active, ""){
1676     this->plugin = plugin;
1677     this->gui = gui;
1678   }
1679   virtual int handle_event(){
1680     plugin->config.Oadj_active = get_value();
1681     update();
1682     return 1;
1683   }
1684   void update(){
1685     this->BC_CheckBox::update(plugin->config.Oadj_active,1);
1686     gui->Oadj_slider->update();
1687   }
1688   BluebananaMain *plugin;
1689   BluebananaWindow *gui;
1690 };
1691
1692 class BluebananaAAActive : public BC_CheckBox {
1693 public:
1694
1695   BluebananaAAActive(BluebananaMain *plugin, BluebananaWindow *gui)
1696   : BC_CheckBox(-1, -1, &plugin->config.Aadj_active, ""){
1697     this->plugin = plugin;
1698     this->gui = gui;
1699   }
1700   virtual int handle_event(){
1701     plugin->config.Aadj_active =
1702       !BC_CModels::has_alpha(plugin->colormodel) ? 0 : get_value();
1703     update();
1704     return 1;
1705   }
1706   void update(){
1707     this->BC_CheckBox::update(plugin->config.Aadj_active,1);
1708     if( BC_CModels::has_alpha(plugin->colormodel) ) {
1709       if( is_hidden() ) show_window();
1710     }else{
1711       if( !is_hidden() ) hide_window();
1712     }
1713     if( is_hidden() ) return;
1714     gui->Aadj_slider->update();
1715   }
1716   BluebananaMain *plugin;
1717   BluebananaWindow *gui;
1718 };
1719
1720 // -------------------------------------------- Erode --------------------------------------------
1721 class BluebananaErode : public BC_CheckBox {
1722 public:
1723   BluebananaErode(BluebananaMain *plugin, BluebananaWindow *gui)
1724   : BC_CheckBox(-1, -1, &plugin->config.Fsel_erode, ""){
1725     this->plugin = plugin;
1726     this->gui = gui;
1727   }
1728   virtual int handle_event(){
1729     plugin->config.Fsel_erode = get_value();
1730     update();
1731     return 1;
1732   }
1733   void update(){
1734     this->BC_CheckBox::update(plugin->config.Fsel_erode,1);
1735     gui->Fsel_slider->update();
1736   }
1737   BluebananaMain *plugin;
1738   BluebananaWindow *gui;
1739 };
1740
1741
1742 // -------------------------------------- Invert Selection ---------------------------------------
1743 class BluebananaIS : public BC_CheckBox {
1744 public:
1745   BluebananaIS(BluebananaMain *plugin, BluebananaWindow *gui)
1746   : BC_CheckBox(-1, -1, &plugin->config.invert_selection, ""){
1747     this->plugin = plugin;
1748     this->gui = gui;
1749   }
1750   virtual int handle_event(){
1751     plugin->config.invert_selection = get_value();
1752     update();
1753     return 1;
1754   }
1755   void update(){
1756     this->BC_CheckBox::update(plugin->config.invert_selection,1);
1757     gui->enter_config_change();
1758     gui->commit_config_change();
1759   }
1760   BluebananaMain *plugin;
1761   BluebananaWindow *gui;
1762 };
1763
1764
1765 // -------------------------------------------- Mark --------------------------------------------
1766 class BluebananaMark : public BC_CheckBox {
1767 public:
1768   BluebananaMark(BluebananaMain *plugin, BluebananaWindow *gui)
1769     : BC_CheckBox(-1, -1, 0, ""){
1770     this->plugin = plugin;
1771     this->gui = gui;
1772   }
1773   virtual int handle_event() {
1774     if(plugin->config.mark != get_value()){
1775       plugin->config.mark = get_value();
1776       plugin->save_nonauto();
1777       if(plugin->config.mark){
1778         gui->set_repeat(207);
1779       }else{
1780         gui->unset_repeat(207);
1781       }
1782       plugin->server->mwindow->sync_parameters();
1783     }
1784     return 1;
1785   }
1786   void update (){
1787     if(plugin->config.mark != get_value()){
1788       this->BC_CheckBox::update(plugin->config.mark,1);
1789       if(plugin->config.mark){
1790         gui->set_repeat(207);
1791       }else{
1792         gui->unset_repeat(207);
1793       }
1794     }
1795   };
1796   BluebananaMain *plugin;
1797   BluebananaWindow *gui;
1798 };
1799
1800 // ------------------------------------------- Active -------------------------------------------
1801 class BluebananaActive : public BC_CheckBox {
1802 public:
1803   BluebananaActive(BluebananaMain *plugin, BluebananaWindow *gui)
1804     : BC_CheckBox(-1, -1, &plugin->config.active, ""){
1805     this->plugin = plugin;
1806     this->gui = gui;
1807     active=-1;
1808   }
1809   virtual int handle_event(){
1810     active = get_value();
1811     update();
1812     return 1;
1813   }
1814   void update(){
1815     if(active != plugin->config.active){
1816       plugin->config.active = active;
1817       this->BC_CheckBox::update(plugin->config.active,1);
1818       gui->enter_config_change();
1819       gui->Hadj_slider->update();
1820       gui->Sadj_slider->update();
1821       gui->Vadj_slider->update();
1822       gui->Radj_slider->update();
1823       gui->Gadj_slider->update();
1824       gui->Badj_slider->update();
1825       gui->Oadj_slider->update();
1826       gui->Aadj_slider->update();
1827       gui->commit_config_change();
1828     }
1829   }
1830   BluebananaMain *plugin;
1831   BluebananaWindow *gui;
1832   int active;
1833 };
1834
1835 // ---------------------------------------- Capture mask ---------------------------------------
1836 class BluebananaUnmask : public BC_CheckBox {
1837 public:
1838   BluebananaUnmask(BluebananaMain *plugin, BluebananaWindow *gui,int padx)
1839     : BC_CheckBox(-1, -1, &plugin->config.capture_mask, ""){
1840     this->plugin = plugin;
1841     this->gui = gui;
1842     this->padx = padx;
1843     this->label = new BC_Title(-1,-1,_(" End Mask"));
1844     this->x=-1;
1845     this->y=-1;
1846     gui->add_subwindow(this->label);
1847     gui->add_subwindow(this);
1848   }
1849   virtual int handle_event(){
1850     plugin->config.capture_mask=get_value();
1851     plugin->save_nonauto();
1852     update();
1853     gui->enter_config_change();
1854     gui->commit_config_change();
1855     return 1;
1856   }
1857   int get_h(){
1858     return label->get_h();
1859   }
1860   int get_w(){
1861     return BC_CheckBox::get_w()+label->get_w()+padx*4;
1862   }
1863   void reposition_window(int x, int y){
1864     int h = label->get_h();
1865     this->x = x;
1866     this->y = y;
1867     label->reposition_window(x+padx,y);
1868     BC_CheckBox::reposition_window(x+padx*2+label->get_w(),y+(h-BC_CheckBox::get_h())/2);
1869     update();
1870   }
1871   void update(){
1872     int w = get_w();
1873     int h = get_h();
1874     int f=0;
1875     int hideme = !plugin->config.use_mask;
1876     switch(plugin->colormodel){
1877     case BC_RGB888:
1878     case BC_RGB_FLOAT:
1879     case BC_YUV888:
1880     case BC_RGB161616:
1881     case BC_YUV161616:
1882       hideme=1;
1883       break;
1884     }
1885
1886     if(hideme && !is_hidden()){
1887       hide_window();
1888       label->hide_window();
1889       gui->set_color(get_resources()->get_bg_color());
1890       gui->draw_box(x,y,w,h);
1891       gui->set_color(get_resources()->default_text_color);
1892       gui->draw_line(x,y+h/2,x+w,y+h/2);
1893       f=1;
1894     }
1895
1896     if(!hideme && is_hidden()){
1897       gui->set_color(get_resources()->get_bg_color());
1898       gui->draw_box(x,y,w,h);
1899       show_window();
1900       label->show_window();
1901       f=1;
1902     }
1903
1904     if(plugin->config.capture_mask != get_value())
1905       this->BC_CheckBox::update(plugin->config.capture_mask,1);
1906     if(f)
1907       gui->flash(x,y,w,h);
1908   }
1909   BluebananaMain *plugin;
1910   BluebananaWindow *gui;
1911   BC_Title *label;
1912   int x,y,padx;
1913 };
1914
1915 // ------------------------------------------ Use mask ----------------------------------------
1916 class BluebananaA2Sel : public BC_CheckBox {
1917 public:
1918   BluebananaA2Sel(BluebananaMain *plugin, BluebananaWindow *gui,int padx)
1919     : BC_CheckBox(-1, -1, &plugin->config.use_mask, ""){
1920     this->plugin = plugin;
1921     this->gui = gui;
1922     this->padx = padx;
1923     this->label = new BC_Title(-1,-1,_(" Mask Selection"));
1924     this->x=-1;
1925     this->y=-1;
1926     gui->add_subwindow(this->label);
1927     gui->add_subwindow(this);
1928   }
1929   virtual int handle_event(){
1930     plugin->config.use_mask=get_value();
1931     plugin->save_nonauto();
1932     update();
1933     gui->enter_config_change();
1934     gui->commit_config_change();
1935     return 1;
1936   }
1937   int get_h(){
1938     return label->get_h();
1939   }
1940   int get_w(){
1941     return BC_CheckBox::get_w()+label->get_w()+padx*4;
1942   }
1943   void reposition_window(int x, int y){
1944     int h = label->get_h();
1945     this->x = x;
1946     this->y = y;
1947     label->reposition_window(x+padx,y);
1948     BC_CheckBox::reposition_window(x+padx*2+label->get_w(),y+(h-BC_CheckBox::get_h())/2);
1949     update();
1950   }
1951   void update(){
1952     int w = get_w();
1953     int h = get_h();
1954     int f=0;
1955
1956     if(gui->capture_mask)
1957       gui->capture_mask->update();
1958
1959     switch(plugin->colormodel){
1960     case BC_RGB888:
1961     case BC_RGB_FLOAT:
1962     case BC_YUV888:
1963     case BC_RGB161616:
1964     case BC_YUV161616:
1965       if(!is_hidden()){
1966         hide_window();
1967         label->hide_window();
1968         gui->set_color(get_resources()->get_bg_color());
1969         gui->draw_box(x,y,w,h);
1970         gui->set_color(get_resources()->default_text_color);
1971         gui->draw_line(x,y+h/2,x+w,y+h/2);
1972         f=1;
1973       }
1974       break;
1975     case BC_RGBA8888:
1976     case BC_RGBA_FLOAT:
1977     case BC_YUVA8888:
1978     case BC_RGBA16161616:
1979     case BC_YUVA16161616:
1980       if(is_hidden()){
1981         gui->set_color(get_resources()->get_bg_color());
1982         gui->draw_box(x,y,w,h);
1983         show_window();
1984         label->show_window();
1985         f=1;
1986       }
1987       break;
1988     case -1:
1989       // not initialized yet
1990       return;
1991     default:
1992       fprintf(stderr,_("Unknown colormodel in BluebananaA2Sel:update()\n"));
1993       break;
1994     }
1995     if(plugin->config.use_mask != get_value())
1996       this->BC_CheckBox::update(plugin->config.use_mask,1);
1997     if(f)
1998       gui->flash(x,y,w,h);
1999   }
2000   BluebananaMain *plugin;
2001   BluebananaWindow *gui;
2002   BC_Title *label;
2003   int x,y,padx;
2004 };
2005
2006 // --------------------------------------- Main GUI window --------------------------------------
2007 BluebananaWindow::BluebananaWindow(BluebananaMain *plugin)
2008  : PluginClientWindow(plugin,1000,1000,0,1,1)
2009 {
2010   do_render=0;
2011   windowx = get_x();
2012   windowy = get_y();
2013   this->plugin = plugin;
2014   config_refcount=1; // suppress pushing config during startup
2015   config_change=0;
2016   config_produce=0;
2017   config_consume=0;
2018   config_pending=0;
2019
2020   Hsel_slider=NULL;
2021   Ssel_slider=NULL;
2022   Vsel_slider=NULL;
2023   Fsel_slider=NULL;
2024   Hadj_slider=NULL;
2025   Sadj_slider=NULL;
2026   Vadj_slider=NULL;
2027   Radj_slider=NULL;
2028   Gadj_slider=NULL;
2029   Badj_slider=NULL;
2030   Oadj_slider=NULL;
2031   Aadj_slider=NULL;
2032
2033   use_mask=0;
2034   capture_mask=0;
2035 }
2036
2037 BluebananaWindow::~BluebananaWindow()
2038 {
2039 }
2040
2041 void BluebananaWindow::create_objects()
2042 {
2043   int xmargin = 20, ymargin = 10;
2044   float row_padding = .1;
2045   float column_padding = .3;
2046   int padx=0;
2047
2048   int i;
2049   int row_h=0, row_adv=0;
2050   int label_x=0;
2051   int label_w=0;
2052   int slider_w=0;
2053   int picker_w=0;
2054   int reset_w=0;
2055   int tumbler_w=0,tumbler_ww=0,tumbler_h=0;
2056   int tumbler_col1_x=0,tumbler_col2_x=0,tumbler_col2_w=0;
2057   int y = ymargin;
2058
2059   //BluebananaHAReset *hareset=NULL;
2060
2061   config_refcount=0;
2062   enter_config_change();
2063
2064   /* window headline */
2065   {
2066     BC_Title *l = new BC_Title(xmargin,y,_("Color Selection"));
2067     BC_Title *l2 = new BC_Title(-1,-1,_(" Mark Selected Areas"));
2068     add_subwindow(mark = new BluebananaMark(plugin,this));
2069     add_subwindow(l);
2070     add_subwindow(l2);
2071     padx = l->get_h()*column_padding;
2072     label_x = xmargin + l->get_w();
2073
2074     int x0 = get_w()-xmargin-mark->get_w();
2075     mark->reposition_window(x0,y-(mark->get_h()-l->get_h())/2);
2076     x0 -= padx+l2->get_w();
2077     l2->reposition_window(x0,y);
2078     x0-=padx;
2079
2080     set_color(get_resources()->default_text_color);
2081     draw_line(label_x+padx, (int)(y+l->get_h()*.5), x0, (int)(y+l->get_h()*.5));
2082
2083     y += l->get_h()*(row_padding+1.);
2084   }
2085
2086   const char *labels[12]={_("hue"),_("saturation"),_("value"),_("fill"),_("red"),_("green"),_("blue"),_("hue"),_("saturation"),_("value"),_("fade"),_("alpha")};
2087   for(i=0;i<12;i++){
2088     add_subwindow(slider_labels[i] = new BC_Title(-1,-1,labels[i]));
2089     if(slider_labels[i]->get_w()>label_w)label_w=slider_labels[i]->get_w();
2090   }
2091
2092   int tumbler_text_ww = MAX(get_text_width(MEDIUMFONT,"-000"),get_text_width(MEDIUMFONT,"5.00"))+8;
2093   int tumbler_text_w = get_text_width(MEDIUMFONT,"50")+8;
2094   if(tumbler_text_w*3<tumbler_text_ww*2){
2095     tumbler_text_ww = (tumbler_text_ww*2+2)/3*3/2;
2096     tumbler_text_w=tumbler_text_ww*2/3;
2097   }
2098
2099   erode_label = new BC_Title(xmargin,y,_("pre-erode"));
2100   BluebananaErode *erode = new BluebananaErode(plugin,this);
2101   add_subwindow(erode_label);
2102   add_subwindow(erode);
2103
2104   for(i=0;i<12;i++){
2105     BC_GenericButton *p=NULL;
2106     BluebananaSlider *s=NULL;
2107     BB_Tumble *t0 = NULL, *t1=NULL, *t2=NULL;
2108     BC_Toggle *a = NULL;
2109     BC_Title *l = slider_labels[i];
2110
2111     switch(i){
2112     case 0:
2113
2114       add_subwindow(t0 = Hsel_readout0 = new BluebananaHSReadout0(plugin,this,tumbler_text_ww));
2115       add_subwindow(t1 = Hsel_readout1 = new BluebananaHSReadout1(plugin,this,tumbler_text_ww));
2116       add_subwindow(t2 = Hsel_readout2 = new BluebananaHSReadout2(plugin,this,tumbler_text_ww));
2117       add_subwindow(a = Hsel_active = new BluebananaHActive(plugin,this));
2118
2119       /* need a narrow and a wide wide tumbler */
2120       add_subwindow(Fsel_readout0 = new BluebananaFSReadout0(plugin,this,tumbler_text_w));
2121       add_subwindow(Fsel_readout1 = new BluebananaFSReadout1(plugin,this,tumbler_text_w));
2122       add_subwindow(Fsel_readout2 = new BluebananaFSReadout2(plugin,this,tumbler_text_w));
2123       add_subwindow(Fsel_readout3 = new BluebananaFSReadout3(plugin,this,tumbler_text_ww));
2124       tumbler_w = Fsel_readout0->get_w();
2125       tumbler_ww = t0->get_w();
2126       tumbler_h = t0->get_h();
2127
2128       /* need a reset button's width */
2129       reset_w = BC_GenericButton::calculate_w(this, _("Reset"));
2130       picker_w = BC_GenericButton::calculate_w(this, _("Pick"));
2131
2132       /* determine row spacing */
2133       row_h = 30; /* minimum widget height allowance for the row
2134                      (really, min height for the slider) */
2135       if(row_h<a->get_h())row_h=a->get_h();
2136       if(row_h<l->get_h())row_h=l->get_h();
2137       if(row_h<BC_GenericButton::calculate_h())row_h=BC_GenericButton::calculate_h();
2138       if(row_h<t2->get_h())row_h=t2->get_h();
2139       row_adv = row_h*(1.+row_padding);
2140
2141       /* determine horizontal element positioning; two main setups */
2142       /* setup 1: three tumblers + button */
2143       tumbler_col2_w = MAX(reset_w,picker_w);
2144
2145       /* setup 2: four tumblers + erode */
2146       {
2147         int threew = tumbler_ww*3 + padx*4 + tumbler_col2_w;
2148         int fourw = tumbler_w*3 + tumbler_ww + padx*5 + erode->get_w() + erode_label->get_w();
2149         if(fourw>threew) tumbler_col2_w += fourw-threew;
2150       }
2151
2152       tumbler_col2_x = get_w()-xmargin-tumbler_col2_w;
2153       tumbler_col1_x = tumbler_col2_x - tumbler_ww*3 - padx*5;
2154       slider_x = label_x+padx;
2155       slider_w = (tumbler_col1_x - slider_x - padx*3);
2156
2157       /* make sure the label x doesn't cause any labels to go off the
2158          left of the pane */
2159       {
2160         int lx = label_x - padx - a->get_w();
2161         if (lx-label_w < xmargin){
2162           slider_x += ((xmargin+label_w)-lx);
2163           label_x += ((xmargin+label_w)-lx);
2164           slider_w -= ((xmargin+label_w)-lx);
2165         }
2166       }
2167
2168       y += row_adv/3; /* extra half row spacing under headline */
2169       s = Hsel_slider = new BluebananaHSSlider(plugin,this,slider_x,y,slider_w,row_h);
2170       add_subwindow(p = new BluebananaHPicker(this,tumbler_col2_w));
2171
2172       /* Move the upper alpha <->selection config buttons into place */
2173       {
2174         int x0 = slider_x+slider_w+padx*2;
2175         invert_selection = new BluebananaIS(plugin,this);
2176         BC_Title *l = new BC_Title(xmargin,y,_(" Invert Selection"));
2177         add_subwindow(l);
2178         add_subwindow(invert_selection);
2179         int w0 = padx+l->get_w()+padx+invert_selection->get_w()+padx*2;
2180         set_color(get_resources()->get_bg_color());
2181         draw_box(x0-w0,ymargin,w0,ymargin+l->get_h());
2182         x0-=padx*2;
2183         x0-=invert_selection->get_w();
2184         invert_selection->reposition_window(x0,ymargin+(l->get_h()-invert_selection->get_h())/2);
2185         x0-=padx;
2186         x0-=l->get_w();
2187         l->reposition_window(x0,ymargin);
2188         x0-=padx;
2189         x0-=padx*5;
2190
2191         use_mask = new BluebananaA2Sel(plugin,this,padx);
2192         x0-=use_mask->get_w();
2193         use_mask->reposition_window(x0, ymargin);
2194         capture_mask = new BluebananaUnmask(plugin,this,padx);
2195         x0-=padx*5 + capture_mask->get_w();
2196         capture_mask->reposition_window(x0, ymargin);
2197       }
2198
2199       break;
2200
2201     case 1:
2202
2203       add_subwindow(t0 = Ssel_readout0 = new BluebananaSSReadout0(plugin,this,tumbler_text_ww));
2204       add_subwindow(t1 = Ssel_readout1 = new BluebananaSSReadout1(plugin,this,tumbler_text_ww));
2205       add_subwindow(t2 = Ssel_readout2 = new BluebananaSSReadout2(plugin,this,tumbler_text_ww));
2206       add_subwindow(a = Ssel_active = new BluebananaSActive(plugin,this));
2207       add_subwindow(p = new BluebananaSPicker(this,tumbler_col2_w));
2208       s = Ssel_slider = new BluebananaSSSlider(plugin,this,slider_x,y,slider_w,row_h);
2209       break;
2210
2211     case 2:
2212
2213       add_subwindow(t0 = Vsel_readout0 = new BluebananaVSReadout0(plugin,this,tumbler_text_ww));
2214       add_subwindow(t1 = Vsel_readout1 = new BluebananaVSReadout1(plugin,this,tumbler_text_ww));
2215       add_subwindow(t2 = Vsel_readout2 = new BluebananaVSReadout2(plugin,this,tumbler_text_ww));
2216       add_subwindow(a = Vsel_active = new BluebananaVActive(plugin,this));
2217       add_subwindow(p = new BluebananaVPicker(this,tumbler_col2_w));
2218       s = Vsel_slider = new BluebananaVSSlider(plugin,this,slider_x,y,slider_w,row_h);
2219       break;
2220
2221     case 3:
2222
2223       add_subwindow(a = Fsel_active = new BluebananaFActive(plugin,this));
2224       s = Fsel_slider = new BluebananaFSSlider(plugin,this,slider_x,y,slider_w,row_h);
2225
2226       Fsel_readout0->reposition_window(tumbler_col1_x, y + (row_h-tumbler_h)/2 + 1);
2227       Fsel_readout1->reposition_window(tumbler_col1_x+tumbler_w, y + (row_h-tumbler_h)/2 + 1);
2228       Fsel_readout2->reposition_window(tumbler_col1_x+tumbler_w*2, y + (row_h-tumbler_h)/2 + 1);
2229       Fsel_readout3->reposition_window(tumbler_col1_x+tumbler_w*3+padx*2,
2230                                        y + (row_h-tumbler_h)/2 + 1);
2231
2232       {
2233         int x = get_w() - xmargin - erode->get_w();
2234         erode->reposition_window(x,y+(row_h-erode->get_h())/2);
2235         erode_label->reposition_window(x-erode_label->get_w()-padx,y+(row_h-erode_label->get_h())/2);
2236       }
2237
2238       break;
2239
2240     case 4:
2241
2242       add_subwindow(t0 = Radj_readout0 = new BluebananaRAReadout0(plugin,this,tumbler_text_ww));
2243       add_subwindow(t1 = Radj_readout1 = new BluebananaRAReadout1(plugin,this,tumbler_text_ww));
2244       add_subwindow(t2 = Radj_readout2 = new BluebananaRAReadout2(plugin,this,tumbler_text_ww));
2245       add_subwindow(a = Radj_active = new BluebananaRAActive(plugin,this));
2246       add_subwindow(p = new BluebananaRAReset(this,tumbler_col2_w));
2247       s = Radj_slider = new BluebananaRASlider(plugin,this,slider_x,y,slider_w,row_h);
2248       break;
2249
2250     case 5:
2251
2252       add_subwindow(t0 = Gadj_readout0 = new BluebananaGAReadout0(plugin,this,tumbler_text_ww));
2253       add_subwindow(t1 = Gadj_readout1 = new BluebananaGAReadout1(plugin,this,tumbler_text_ww));
2254       add_subwindow(t2 = Gadj_readout2 = new BluebananaGAReadout2(plugin,this,tumbler_text_ww));
2255       add_subwindow(a = Gadj_active = new BluebananaGAActive(plugin,this));
2256       add_subwindow(p = new BluebananaGAReset(this,tumbler_col2_w));
2257       s = Gadj_slider = new BluebananaGASlider(plugin,this,slider_x,y,slider_w,row_h);
2258       break;
2259
2260     case 6:
2261
2262       add_subwindow(t0 = Badj_readout0 = new BluebananaBAReadout0(plugin,this,tumbler_text_ww));
2263       add_subwindow(t1 = Badj_readout1 = new BluebananaBAReadout1(plugin,this,tumbler_text_ww));
2264       add_subwindow(t2 = Badj_readout2 = new BluebananaBAReadout2(plugin,this,tumbler_text_ww));
2265       add_subwindow(a = Badj_active = new BluebananaBAActive(plugin,this));
2266       add_subwindow(p = new BluebananaBAReset(this,tumbler_col2_w));
2267       s = Badj_slider = new BluebananaBASlider(plugin,this,slider_x,y,slider_w,row_h);
2268       break;
2269
2270     case 7:
2271
2272       add_subwindow(t0 = Hadj_readout = new BluebananaHAReadout(plugin,this,tumbler_text_ww));
2273       add_subwindow(a = Hadj_active = new BluebananaHAActive(plugin,this));
2274       add_subwindow(p = new BluebananaHAReset(this,tumbler_col2_w));
2275       s = Hadj_slider = new BluebananaHASlider(plugin,this,slider_x,y,slider_w,row_h);
2276       break;
2277
2278     case 8:
2279
2280       add_subwindow(t0 = Sadj_readout0 = new BluebananaSAReadout0(plugin,this,tumbler_text_ww));
2281       add_subwindow(t1 = Sadj_readout1 = new BluebananaSAReadout1(plugin,this,tumbler_text_ww));
2282       add_subwindow(t2 = Sadj_readout2 = new BluebananaSAReadout2(plugin,this,tumbler_text_ww));
2283
2284       add_subwindow(a = Sadj_active = new BluebananaSAActive(plugin,this));
2285       add_subwindow(p = new BluebananaSAReset(this,tumbler_col2_w));
2286       s = Sadj_slider = new BluebananaSASlider(plugin,this,slider_x,y,slider_w,row_h);
2287       break;
2288
2289     case 9:
2290
2291       add_subwindow(t0 = Vadj_readout0 = new BluebananaVAReadout0(plugin,this,tumbler_text_ww));
2292       add_subwindow(t1 = Vadj_readout1 = new BluebananaVAReadout1(plugin,this,tumbler_text_ww));
2293       add_subwindow(t2 = Vadj_readout2 = new BluebananaVAReadout2(plugin,this,tumbler_text_ww));
2294       add_subwindow(a = Vadj_active = new BluebananaVAActive(plugin,this));
2295       add_subwindow(p = new BluebananaVAReset(this,tumbler_col2_w));
2296       s = Vadj_slider = new BluebananaVASlider(plugin,this,slider_x,y,slider_w,row_h);
2297       break;
2298
2299     case 10:
2300
2301       add_subwindow(t0 = Oadj_readout = new BluebananaOAReadout(plugin,this,tumbler_text_ww));
2302       add_subwindow(a = Oadj_active = new BluebananaOAActive(plugin,this));
2303       add_subwindow(p = new BluebananaOAReset(this,tumbler_col2_w));
2304       s = Oadj_slider = new BluebananaOASlider(plugin,this,slider_x,y,slider_w,row_h);
2305       break;
2306
2307     case 11:
2308
2309       add_subwindow(t0 = Aadj_readout = new BluebananaAAReadout(plugin,this,tumbler_text_ww));
2310       add_subwindow(a = Aadj_active = new BluebananaAAActive(plugin,this));
2311       add_subwindow(p = new BluebananaAAReset(this,tumbler_col2_w));
2312       s = Aadj_slider = new BluebananaAASlider(plugin,this,slider_x,y,slider_w,row_h);
2313       break;
2314
2315     }
2316     add_subwindow(s);
2317
2318     if(a)a->reposition_window(label_x - padx - a->get_w(), y + (row_h-a->get_h())/2 + 1);
2319     if(l)l->reposition(label_x - l->get_w() - padx*2 - a->get_w(), y + (row_h-l->get_h())/2 + 1);
2320
2321     if(p){
2322       p->BC_SubWindow::reposition_window(tumbler_col2_x, y + (row_h-p->get_h())/2 + 1,
2323                                          MAX(tumbler_col2_w,picker_w),p->get_h());
2324
2325       // work around bug; the reposition step does not fully redraw the button
2326       p->draw_face();
2327     }
2328
2329     if(t0)t0->reposition_window(tumbler_col1_x,
2330                                 y + (row_h-tumbler_h)/2 + 1);
2331
2332     if(t1)t1->reposition_window(tumbler_col1_x+tumbler_ww,
2333                                 y + (row_h-tumbler_h)/2 + 1);
2334
2335     if(t2)t2->reposition_window(tumbler_col1_x+tumbler_ww*2+padx*2+(tumbler_ww-t2->get_w())/2,
2336                                 y + (row_h-tumbler_h)/2 + 1);
2337
2338
2339     s->update();
2340
2341     y+=row_adv;
2342     if(i==3){
2343       y+=row_adv/3;
2344
2345       BC_Title *l = new BC_Title(xmargin,y,_("Color Adjustment"));
2346       BC_Title *l2 = new BC_Title(-1,-1,_(" Filter Active"));
2347       add_subwindow(l);
2348       add_subwindow(l2);
2349       add_subwindow(active = new BluebananaActive(plugin,this));
2350
2351       int x0 = get_w()-xmargin-mark->get_w();
2352       active->reposition_window(x0,y-(active->get_h()-l->get_h())/2);
2353       x0 -= padx+l2->get_w();
2354       l2->reposition_window(x0,y);
2355       x0 -= padx*2;
2356       set_color(get_resources()->default_text_color);
2357       draw_line(xmargin+l->get_w()+padx, y+l->get_h()*.5, x0, y+l->get_h()*.5);
2358
2359       y += l->get_h()*(row_padding+1.);
2360       y += row_adv/3;
2361     }
2362
2363
2364     if(i==6 || i==9){
2365       y+=row_adv/4;
2366
2367       set_color((s->dimtextcolor + get_resources()->default_text_color)/2);
2368       draw_line(slider_x+20, y+l->get_h()*.5, tumbler_col2_x-30, y+l->get_h()*.5);
2369
2370       y += l->get_h()*(row_padding+1.);
2371       y += row_adv/4;
2372     }
2373
2374
2375   }
2376   y += row_adv/2-4;
2377
2378   plugin->update_lookups(0);
2379   do_render=1;
2380
2381   resize_window(get_w(),y);
2382   show_window();
2383   reposition_window(windowx,windowy,get_w(),y);
2384   leave_config_change(); // also forces render
2385   plugin->server->mwindow->sync_parameters();
2386 }
2387
2388 int BluebananaWindow::close_event(){
2389   set_done(1);
2390   return 1;
2391 }
2392
2393 // adds one to config push refcount
2394 // updates any internal state immediately
2395 void BluebananaWindow::enter_config_change(){
2396   config_refcount++;
2397   if(!config_change && !plugin->update_cache.equivalent(plugin->config)){
2398     config_change=1;
2399   }
2400   plugin->update_lookups(0);
2401 }
2402
2403 // decrements one from config push refcount.  If refcount drops to
2404 // zero, pushes new config up to application
2405
2406 // also compresses events; waits 184ms for new events before pushing
2407 // configuration changes
2408 void BluebananaWindow::commit_config_change(){
2409   if(--config_refcount==0){
2410     if(config_change){
2411       config_change=0;
2412       config_produce++;
2413       config_pending=1;
2414       set_repeat(97);
2415     }
2416     render();
2417   }
2418 }
2419
2420 // decrements one from config push refcount.  Does not push config up
2421 // to application when refcount drops to zero (used to wrap update
2422 // requests coming from the application, not user-initiated state
2423 // changes)
2424 void BluebananaWindow::leave_config_change(){
2425   config_change=0;
2426   plugin->update_cache.copy_from(plugin->config);
2427   if(--config_refcount==0){
2428     render();
2429   }
2430 }
2431
2432 int BluebananaWindow::flush_config_change(){
2433   unset_repeat(97);
2434   if(config_pending){
2435     config_pending=0;
2436     plugin->update_cache.copy_from(plugin->config);
2437     plugin->send_configure_change();
2438   }
2439   config_consume=config_produce;
2440   return 0;
2441 }
2442
2443 int BluebananaWindow::repeat_event(int64_t d){
2444   if(d==97){
2445     if(config_consume==config_produce)
2446       flush_config_change();
2447     config_consume=config_produce;
2448   }
2449   if(d==207){
2450
2451     /* if background render is active and we're showing the zebra, mark
2452        the current frame uncached so that we can push zebra changes */
2453     if(plugin->config.mark && plugin->server->mwindow->brender)
2454       plugin->server->mwindow->brender->set_video_map(plugin->source_position, BRender::SCANNED);
2455
2456     /* push update request without an EDL update */
2457     plugin->server->mwindow->sync_parameters();
2458   }
2459   return 0;
2460 }
2461
2462 /* engine -> gui update; don't allow any EDL pushes */
2463 void BluebananaWindow::update(){
2464
2465   // called to suppress configuration pushes
2466   enter_config_change();
2467
2468   // full configuration recompute and redraw
2469   Hsel_slider->update();
2470   Ssel_slider->update();
2471   Vsel_slider->update();
2472   Fsel_slider->update();
2473   Hadj_slider->update();
2474   Sadj_slider->update();
2475   Vadj_slider->update();
2476   Radj_slider->update();
2477   Gadj_slider->update();
2478   Badj_slider->update();
2479   Oadj_slider->update();
2480   Aadj_slider->update();
2481
2482   active->update();
2483   mark->update();
2484   use_mask->update();
2485   capture_mask->update();
2486   invert_selection->update();
2487
2488   Hsel_active->update();
2489   Ssel_active->update();
2490   Vsel_active->update();
2491   Fsel_active->update();
2492
2493   Hadj_active->update();
2494   Sadj_active->update();
2495   Vadj_active->update();
2496   Radj_active->update();
2497   Gadj_active->update();
2498   Badj_active->update();
2499   Oadj_active->update();
2500   Aadj_active->update();
2501
2502   // called to release configuration without pushing
2503   leave_config_change();
2504 }
2505
2506 void BluebananaWindow::render(){
2507   if(do_render){
2508     Hsel_slider->render();
2509     Ssel_slider->render();
2510     Vsel_slider->render();
2511     Fsel_slider->render();
2512     Hadj_slider->render();
2513     Sadj_slider->render();
2514     Vadj_slider->render();
2515     Radj_slider->render();
2516     Gadj_slider->render();
2517     Badj_slider->render();
2518     Oadj_slider->render();
2519     Aadj_slider->render();
2520   }
2521 }
2522
2523 void BluebananaWindow::update_histograms(BluebananaMain *plugin){
2524   int w = plugin->frame->get_w();
2525   int h = plugin->frame->get_h();
2526
2527   if(Radj_slider)Radj_slider->update_histogram(plugin->red_histogram,0,0,0,w*h);
2528   if(Gadj_slider)Gadj_slider->update_histogram(plugin->green_histogram,0,0,0,w*h);
2529   if(Badj_slider)Badj_slider->update_histogram(plugin->blue_histogram,0,0,0,w*h);
2530
2531   if(Hadj_slider)
2532     Hadj_slider->update_histogram(plugin->hue_histogram,
2533                                   plugin->hue_histogram_red,
2534                                   plugin->hue_histogram_green,
2535                                   plugin->hue_histogram_blue,w*h);
2536
2537   if(Sadj_slider)
2538     Sadj_slider->update_histogram(plugin->sat_histogram,
2539                                   plugin->sat_histogram_red,
2540                                   plugin->sat_histogram_green,
2541                                   plugin->sat_histogram_blue,w*h);
2542
2543   if(Vadj_slider)
2544     Vadj_slider->update_histogram(plugin->value_histogram,
2545                                   plugin->value_histogram_red,
2546                                   plugin->value_histogram_green,
2547                                   plugin->value_histogram_blue,w*h);
2548
2549 }