initial commit
[goodguy/history.git] / cinelerra-5.0 / plugins / bluebanana / bluebananaslider.C
1 /*
2  * Cinelerra :: Blue Banana - color modification plugin for Cinelerra-CV
3  * Copyright (C) 2012-2013 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 "bluebananaslider.h"
22
23 #undef CLAMP
24 #define CLAMP(x, y, z) ((x) < (y) ? (y) : ((x) > (z) ? (z) : (x)))
25
26 #define CW (get_h()/2+2)
27 #define SW (get_h()*2/5+1)
28 #define Z1 (get_h()/7+2)
29 #define Z2 (get_h()*2/5+1)
30 #define Z3 (get_h()-Z2-1)
31 #define Z4 (get_h()-Z1-1)
32 #define ZC ((Z3+Z2)/2)
33
34 #define ZS 3
35 #define ZL 1
36 #define ZR 3
37
38 #include <math.h>
39
40 static int scale_color(int color, float scale){
41   int r = ((color >> 16) & 0xff)*scale;
42   int g = ((color >> 8) & 0xff)*scale;
43   int b = (color & 0xff)*scale;
44
45   if(r>255)r=255;
46   if(g>255)g=255;
47   if(b>255)b=255;
48   return (r<<16)|(g<<8)|b;
49 }
50 #if 0
51 static int mix_color(int c1, float s1, int c2, float s2){
52   int r = ((c1 >> 16) & 0xff)*s1 + ((c2 >> 16) & 0xff)*s2;
53   int g = ((c1 >> 8) & 0xff)*s1 + ((c2 >> 8) & 0xff)*s2;
54   int b = (c1 & 0xff)*s1 + (c2 & 0xff)*s2;
55
56   if(r>255)r=255;
57   if(g>255)g=255;
58   if(b>255)b=255;
59   return (r<<16)|(g<<8)|b;
60 }
61 #endif
62 BluebananaSlider::BluebananaSlider(BluebananaMain *plugin,
63                                    BluebananaWindow *gui,
64                                    int x,
65                                    int y,
66                                    int w,
67                                    int h,
68                                    float minval,
69                                    float maxval)
70   : BC_SubWindow(x, y, w, h){
71
72   this->plugin = plugin;
73   this->gui = gui;
74   this->minval = minval;
75   this->maxval = maxval;
76   histval=NULL;
77   histred=NULL;
78   histgreen=NULL;
79   histblue=NULL;
80   drag = 0;
81   light = -1;
82
83   int bg_c = get_resources()->get_bg_color();
84   int bg_r = ((bg_c >> 16) & 0xff);
85   int bg_g = ((bg_c >> 8) & 0xff);
86   int bg_b = (bg_c & 0xff);
87   int bg_v = (bg_r * 76 + bg_g *150 + bg_b *29) >> 8;
88
89   int dt_c = get_resources()->default_text_color;
90   int dt_r = ((dt_c >> 16) & 0xff);
91   int dt_g = ((dt_c >> 8) & 0xff);
92   int dt_b = (dt_c & 0xff);
93   int dt_v = (dt_r * 76 + dt_g *150 + dt_b *29) >> 8;
94
95   if(dt_v>bg_v){
96     /* light text, dark background */
97     int dg_c = get_resources()->default_text_color;
98     int dg_r = (((dg_c >> 16) & 0xff) + bg_r*2) /3;
99     int dg_g = (((dg_c >> 8) & 0xff) + bg_g*2) /3;
100     int dg_b = ((dg_c & 0xff) + bg_b*2) /3;
101     dg_c = (dg_r<<16) | (dg_g<<8) | dg_b;
102
103     active_bordercolor = get_resources()->default_text_color;
104     inactive_bordercolor = dg_c;
105     dimtextcolor = dg_c;
106     troughcolor = scale_color(dg_c,.5);
107     slidercolor = (bg_v > 0xa0 ? 0x606060 : 0xa0a0a0);
108     sliderlit = (bg_v > 0xa0 ? 0x909070 : 0xd0d0b0);
109     outline = 0x000000;
110   }else{
111     /* dark text, light background */
112     active_bordercolor = scale_color(bg_c,1.25);
113     inactive_bordercolor = scale_color(bg_c,1.01);
114     troughcolor = scale_color(bg_c,.8);
115     dimtextcolor = this->troughcolor;
116     sliderlit =  scale_color(bg_c,1.75);
117     slidercolor = scale_color(this->sliderlit,.90);
118     outline = 0x606060;
119   }
120
121   needlecolor = 0xe07000;
122   needlelit = 0xff9000;
123   highlight = 0;
124   trough = NULL;
125   troughlines = Z4-Z1-1;
126   troughcols = w-CW-CW-ZR-ZL;
127 }
128
129 BluebananaSlider::~BluebananaSlider(){
130   if(trough) delete trough;
131   if(histval) delete[] histval;
132   if(histred) delete[] histred;
133   if(histgreen) delete[] histgreen;
134   if(histblue) delete[] histblue;
135 }
136
137 void BluebananaSlider::reposition(int x, int y, int w, int h){
138   BC_WindowBase::reposition_window(x,y,w,h);
139   if(trough) delete trough;
140   trough=NULL;
141   if(histval) delete[] histval;
142   histval=NULL;
143   if(histred) delete[] histred;
144   histred=NULL;
145   if(histgreen) delete[] histgreen;
146   histgreen=NULL;
147   if(histblue) delete[] histblue;
148   histblue=NULL;
149   troughlines = Z4-Z1-1;
150   troughcols = w-CW-CW-ZR-ZL;
151   update();
152 }
153
154 int BluebananaSlider::fraction_to_pixel(float input){
155   return (int)rint((input*(troughcols-1)+CW+ZL)+.001);
156 }
157
158 int BluebananaSlider::value_to_pixel(float input){
159   return fraction_to_pixel((input-minval)/(maxval-minval));
160 }
161
162 float BluebananaSlider::pixel_to_fraction(int pixel){
163   return (float)((pixel-CW-ZL)/(float)(troughcols-1));
164 }
165
166 float BluebananaSlider::pixel_to_value(int pixel){
167   float fraction=((pixel-CW-ZL)/(float)(troughcols-1));
168   return fraction*(maxval-minval)+minval;
169 }
170 #if 0
171 static int inside_box(int cx, int cy, int x, int y, int w, int h){
172   return (cx>=x && cx<x+w && cy>=y && cy<y+h);
173 }
174 #endif
175 static int inside_vline(int cx, int cy, int x, int y0, int y1){
176   if(cx==x){
177     if(cy>=y0 && cy<=y1)return 1;
178     if(cy>=y1 && cy<=y0)return 1;
179   }
180   return 0;
181 }
182
183 static int inside_hline(int cx, int cy, int x0, int x1, int y){
184   if(cy==y){
185     if(cx>=x0 && cx<=x1)return 1;
186     if(cx>=x1 && cx<=x0)return 1;
187   }
188   return 0;
189 }
190
191 int BluebananaSlider::in_midslider(int x, int cx,int cy){
192   int h = get_h();
193   int y = (Z4-Z1+h)/2;
194   int r = Z1-2;
195   if( (cx-x)*(cx-x) + (cy-y)*(cy-y) < r*r ) return 1;
196   return 0;
197 }
198
199 int BluebananaSlider::in_leftslider(int x,int cx, int cy){
200   int i;
201   int h = get_h();
202
203   if(inside_hline(cx,cy,x-1,x-Z1*2-1,Z4)) return 1;
204   for(i=1;i<Z1+1;i++){
205     if(inside_hline(cx,cy,x-(i*2),x-Z1*2-1,Z4-i)) return 1;
206     if(inside_hline(cx,cy,x-(i*2),x-Z1*2-1,Z4+i)) return 1;
207   }
208
209   if(inside_vline(cx,cy,x-Z1*2-2,Z4-Z1+1,Z4+Z1-1))return 1;
210   if(inside_vline(cx,cy,x,Z1+1,h-1))return 1;
211
212   return 0;
213 }
214
215 int BluebananaSlider::in_rightslider(int x, int cx, int cy){
216   int i;
217   int h = get_h();
218
219   if(inside_hline(cx,cy,x+1,x+Z1*2+1,Z4)) return 1;
220   for(i=1;i<Z1+1;i++){
221     if(inside_hline(cx,cy,x+(i*2),x+Z1*2+1,Z4-i)) return 1;
222     if(inside_hline(cx,cy,x+(i*2),x+Z1*2+1,Z4+i)) return 1;
223   }
224
225   if(inside_vline(cx,cy,x+Z1*2+2,Z4-Z1+1,Z4+Z1-1))return 1;
226   if(inside_vline(cx,cy,x,Z1+1,h-1))return 1;
227   return 0;
228 }
229
230 int BluebananaSlider::in_topslider(int x, int cx, int cy){
231   int i;
232   //int h = get_h();
233   if(inside_vline(cx,cy,x,Z1*2,1))return 1;
234   for(i=1;i<Z1+1;i++){
235     if(inside_vline(cx,cy,x+i,1,Z1*2-i*2+1))return 1;
236     if(inside_vline(cx,cy,x-i,1,Z1*2-i*2+1))return 1;
237     }
238   if(inside_hline(cx,cy,x-Z1+1,x+Z1-1,0)) return 1;
239   return 0;
240 }
241
242 int BluebananaSlider::in_overslider(int x,int cx, int cy){
243   //int i;
244   //int h = get_h();
245   //int y0 = 0;
246   //int y1 = Z1*2-1;
247   int w2 = CW;//Z1*2-1;
248   if(cy<=Z1 && cx>=x-w2 && cx<=x+w2) return 1;
249   return 0;
250 }
251
252 int BluebananaSlider::in_bottomslider(int x,int cx, int cy){
253   int i;
254   int h = get_h();
255
256   if(inside_vline(cx,cy,x,h-Z1*2-1,h-2))return 1;
257   for(i=1;i<Z1+1;i++){
258     if(inside_vline(cx,cy,x+i,h-2,h-Z1*2+i*2-2))return 1;
259     if(inside_vline(cx,cy,x-i,h-2,h-Z1*2+i*2-2))return 1;
260   }
261   if(inside_hline(cx,cy,x-Z1+1,x+Z1-1,h-1)) return 1;
262   return 0;
263 }
264
265 int BluebananaSlider::in_leftslider2(int x,int cx){
266   if(cx<=x+2 && cx>x-CW) return 1;
267   return 0;
268 }
269
270 int BluebananaSlider::in_rightslider2(int x,int cx){
271   if(cx<x+CW && cx>=x-2) return 1;
272   return 0;
273 }
274
275 int BluebananaSlider::in_midslider2(int x,int cx){
276   if(cx>x-CW/2 && cx<x+CW/2) return 1;
277   return 0;
278 }
279
280 int BluebananaSlider::in_overslider2(int x,int cx, int cy){
281   if(cx>x-CW/2 && cx<x+CW/2 && cy<=(Z1+Z4)/2) return 1;
282   return 0;
283 }
284
285 void BluebananaSlider::draw_midslider(int x,int lit){
286   //int i;
287   int h = get_h();
288   int y0 = Z4-Z1+2;
289   int y1 = h-2;
290
291   set_color(lit?sliderlit:slidercolor);
292   draw_disc(x-Z1+2,y0,Z1*2-3,y1-y0+1);
293
294   set_color(outline);
295   draw_circle(x-Z1+2,y0,Z1*2-3,y1-y0+1);
296 }
297
298 void BluebananaSlider::draw_leftslider(int x, int lit){
299   int i;
300   //int h = get_h();
301
302   set_color(lit?sliderlit:slidercolor);
303   draw_line(x-1,Z4,x-Z1*2-1,Z4);
304   for(i=1;i<Z1+1;i++){
305     draw_line(x-(i*2),Z4-i,x-Z1*2-1,Z4-i);
306     draw_line(x-(i*2),Z4+i,x-Z1*2-1,Z4+i);
307   }
308
309   set_color(outline);
310   draw_line(x-1,Z4,x-1,Z4);
311   draw_line(x-Z1*2-2,Z4-Z1+1,x-Z1*2-2,Z4+Z1-1);
312   for(i=1;i<Z1+1;i++){
313     draw_line(x-(i*2),Z4-i,x-(i*2)-1,Z4-i);
314     draw_line(x-(i*2),Z4+i,x-(i*2)-1,Z4+i);
315   }
316
317   set_color(lit?needlelit:needlecolor);
318   draw_line(x,Z4-Z1,x,Z4+Z1);
319 }
320
321 void BluebananaSlider::draw_rightslider(int x, int lit){
322   int i;
323   //int h = get_h();
324
325   set_color(lit?sliderlit:slidercolor);
326   draw_line(x+1,Z4,x+Z1*2+1,Z4);
327   for(i=1;i<Z1+1;i++){
328     draw_line(x+(i*2),Z4-i,x+Z1*2+1,Z4-i);
329     draw_line(x+(i*2),Z4+i,x+Z1*2+1,Z4+i);
330   }
331
332   set_color(outline);
333   draw_line(x+1,Z4,x+1,Z4);
334   draw_line(x+Z1*2+2,Z4-Z1+1,x+Z1*2+2,Z4+Z1-1);
335   for(i=1;i<Z1+1;i++){
336     draw_line(x+(i*2),Z4-i,x+(i*2)+1,Z4-i);
337     draw_line(x+(i*2),Z4+i,x+(i*2)+1,Z4+i);
338   }
339
340   set_color(lit?needlelit:needlecolor);
341   draw_line(x,Z4-Z1,x,Z4+Z1);
342 }
343
344 void BluebananaSlider::draw_topslider(int x, int lit){
345   int i;
346   //int h = get_h();
347
348   set_color(lit?sliderlit:slidercolor);
349   draw_line(x,Z1*2,x,1);
350   for(i=1;i<Z1+1;i++){
351     draw_line(x+i,1,x+i,Z1*2-i*2+1);
352     draw_line(x-i,1,x-i,Z1*2-i*2+1);
353   }
354
355   set_color(outline);
356   draw_line(x-Z1+1,0,x+Z1-1,0);
357   draw_line(x,Z1*2+1,x,Z1*2+1);
358   for(i=1;i<Z1+1;i++){
359     draw_line(x+i, Z1*2-i*2+1, x+i, Z1*2-i*2+2);
360     draw_line(x-i, Z1*2-i*2+1, x-i, Z1*2-i*2+2);
361   }
362 }
363
364 void BluebananaSlider::draw_bottomslider(int x, int lit){
365   int i;
366   int h = get_h();
367
368   set_color(lit?sliderlit:slidercolor);
369   draw_line(x,h-Z1*2-1,x,h-2);
370   for(i=1;i<Z1+1;i++){
371     draw_line(x+i,h-2,x+i,h-Z1*2+i*2-2);
372     draw_line(x-i,h-2,x-i,h-Z1*2+i*2-2);
373   }
374
375   set_color(outline);
376   draw_line(x-Z1+1,h-1,x+Z1-1,h-1);
377   draw_line(x,h-Z1*2-2,x,h-Z1*2-2);
378   for(i=1;i<Z1+1;i++){
379     draw_line(x+i,h-Z1*2+i*2-2,x+i,h-Z1*2+i*2-3);
380     draw_line(x-i,h-Z1*2+i*2-2,x-i,h-Z1*2+i*2-3);
381   }
382 }
383
384 void BluebananaSlider::draw_overslider(int x, int lit){
385   //int i;
386   //int h = get_h();
387   //int y0 = 0;
388   //int y1 = Z1*2-1;
389   int w2 = CW+1;
390
391   int bg_c = get_resources()->get_bg_color();
392   int bg_r = ((bg_c >> 16) & 0xff);
393   int bg_g = ((bg_c >> 8) & 0xff);
394   int bg_b = (bg_c & 0xff);
395   float del = lit ? 1. : .9;
396   set_color(((int)(bg_r*del) << 16) | ((int)(bg_g*del) << 8) | ((int)(bg_b*del)));
397   draw_box(x-w2+1,0,w2*2-2,Z1);
398   draw_box(x-w2,1,w2*2+1,Z1-2);
399
400   set_color(lit?sliderlit:slidercolor);
401   draw_box(x-w2+2,1,w2*2-3,Z1-2);
402   draw_box(x-w2+1,2,w2*2-1,Z1-4);
403
404   set_color(((int)(bg_r*del) << 16) | ((int)(bg_g*del) << 8) | ((int)(bg_b*del)));
405   draw_line(x,2,x,Z1-3);
406 }
407
408 int BluebananaSlider::button_release_event(){
409   if(is_event_win()){
410     if(drag>0) {
411       drag = 0;
412       update();
413       cursor_motion_event();
414     }
415     return 1;
416   }
417   return 0;
418 }
419
420 void BluebananaSlider::update(){
421   int w = get_w();
422   int h = get_h();
423   int bg_c = get_resources()->get_bg_color();
424   int bg_r = ((bg_c >> 16) & 0xff);
425   int bg_g = ((bg_c >> 8) & 0xff);
426   int bg_b = (bg_c & 0xff);
427   int b_c = highlight ? active_bordercolor : inactive_bordercolor;
428   int b_r = ((b_c >> 16) & 0xff);
429   int b_g = ((b_c >> 8) & 0xff);
430   int b_b = (b_c & 0xff);
431   int tb_c = troughcolor;
432   int tb_r = ((tb_c >> 16) & 0xff);
433   int tb_g = ((tb_c >> 8) & 0xff);
434   int tb_b = (tb_c & 0xff);
435
436   int ZH = Z4-Z1+1;
437   //int ZHC = Z4-ZC+1;
438
439   int i,j;
440
441   clear_box(0, 0, w, h);
442
443   /* trough shadow */
444   float del = .9;
445   int shadow_c = ((int)(bg_r*del) << 16) | ((int)(bg_g*del) << 8) | ((int)(bg_b*del));
446   set_color(shadow_c);
447   draw_box (0,Z1,w,ZH+2);
448   draw_box (1,Z1-1,w-2,ZH+4);
449
450   del = .8;
451   shadow_c = ((int)(bg_r*del) << 16) | ((int)(bg_g*del) << 8) | ((int)(bg_b*del));
452   set_color(shadow_c);
453   draw_box (1,Z1+1,w-2,ZH);
454   draw_box (2,Z1,w-4,ZH+2);
455
456   del = .7;
457   shadow_c = ((int)(bg_r*del) << 16) | ((int)(bg_g*del) << 8) | ((int)(bg_b*del));
458   set_color(shadow_c);
459   draw_box (2,Z1+2,w-4,ZH-2);
460   draw_box (3,Z1+1,w-6,ZH);
461
462   /* trough border */
463   set_color(b_c);
464   draw_box (1,Z1+1,w-4,ZH-2);
465   draw_box (2,Z1,w-6,ZH);
466
467   /* trough inner */
468   int ntw = troughcols;
469   int nth = troughlines;
470   int ntx = CW+ZL;
471   int nty = Z1+1;
472
473   if(!trough){
474     trough = new VFrame(ntw,nth,BC_RGBA8888);
475   }
476
477   if(!trough){
478     fprintf(stderr,"Bluebanana: Unable to create Frame for slider\n");
479   }else{
480     unsigned char *data = trough->get_data();
481     long bpr = trough->get_bytes_per_line();
482     float ha = 1.;
483     if(!highlight){
484       ha*=.25;
485       tb_r = bg_r;
486       tb_g = bg_g;
487       tb_b = bg_b;
488     }
489
490     if(histval){ // trough is a histogram and has data
491       long bpp = trough->get_bytes_per_pixel();
492       float rr,gg,bb,aa;
493
494       for(i=0;i<ntw;i++){
495
496         unsigned char *row = data;
497         float y = nth-histval[i];
498         float y0 = i>0?nth-histval[i-1]:y;
499         float y1 = i+1<ntw?nth-histval[i+1]:y;
500         float yp = MIN(y,MIN(y0+1,y1+1));
501         float y3 = (y0+y+y1)*.333f;
502         float r,g,b,a;
503
504         trough_color((i+.5f)/ntw,0.f,rr,gg,bb,aa);
505         rr*=255;
506         gg*=255;
507         bb*=255;
508         rr = CLAMP((rr+b_r*3)/4,0,255);
509         gg = CLAMP((gg+b_g*3)/4,0,255);
510         bb = CLAMP((bb+b_b*3)/4,0,255);
511
512         if(histred){
513           r=histred[i];
514           g=histgreen[i];
515           b=histblue[i];
516         }else{
517           trough_color((i+.5)/ntw,0,r,g,b,a);
518           r=CLAMP(r,0,255);
519           g=CLAMP(g,0,255);
520           b=CLAMP(b,0,255);
521         }
522
523         for(j=0;j<yp-1 && j<nth;j++){
524           row[0] = tb_r;
525           row[1] = tb_g;
526           row[2] = tb_b;
527           row[3] = 0xff;
528           row+=bpr;
529         }
530
531         a=.75*ha;
532         for(;j<y && j<nth;j++){
533           row[0] = rint(rr*a + tb_r*(1-a));
534           row[1] = rint(gg*a + tb_g*(1-a));
535           row[2] = rint(bb*a + tb_b*(1-a));
536           row[3] = 0xff;
537           row+=bpr;
538         }
539
540         a=ha;
541         for(;j<nth;j++){
542           float a = CLAMP(1. - .3*(float)(j-y3)/(nth-y3+1),0.f,1.f)*ha;
543           row[0] = rint(r*a*255.f + tb_r*(1-a));
544           row[1] = rint(g*a*255.f + tb_g*(1-a));
545           row[2] = rint(b*a*255.f + tb_b*(1-a));
546           row[3] = 0xff;
547           row+=bpr;
548         }
549
550         data+=bpp;
551       }
552     }else{
553       for(i=0;i<ntw;i++){
554         unsigned char *row = data + i*trough->get_bytes_per_pixel();
555         for(j=0;j<nth;j++){
556           float r,g,b,a;
557           trough_color((i+.5f)/ntw,(j+.5)/nth,r,g,b,a);
558           r=CLAMP(r,0,255);
559           g=CLAMP(g,0,255);
560           b=CLAMP(b,0,255);
561
562           a*=ha;
563           row[0] = rint(r*a*255 + tb_r*(1-a));
564           row[1] = rint(g*a*255 + tb_g*(1-a));
565           row[2] = rint(b*a*255 + tb_b*(1-a));
566           row[3] = 0xff;
567           row+=bpr;
568         }
569       }
570     }
571     draw_vframe(trough,ntx,nty);
572   }
573 }
574
575 // quick/dirty unnormalized linear resample from native -> display size
576 static void resample_histogram(float *raw, float *raw_red, float *raw_green, float *raw_blue,
577                                float *out, float *out_red, float *out_green, float *out_blue,
578                                int raw_n, int raw_off, int out_n, int out_start, int out_end){
579   float coverage = (float)raw_n/out_n;
580   float scale = coverage;
581   if(coverage<1.)coverage=1.;
582   float icoverage = 1./coverage;
583
584   float raw_center = out_start*scale+raw_off;
585   float raw_start = raw_center-coverage;
586   float raw_end = raw_center+coverage;
587
588   for(int i=out_start; i<out_end; i++){
589     int j = raw_start+1;
590     int e = raw_end;
591     if(j<0)j=0;
592     if(e>HISTSIZE)e=HISTSIZE;
593     //int jj=j;
594     float k = (j-raw_start)*icoverage-1.f;
595     float a = 0;
596
597     for(; j<=e; j++){
598       float ik = 1.-fabs(k);
599       a += raw[j]*ik;
600       k += icoverage;
601     }
602     out[i] = a;
603     raw_start += scale;
604     raw_end += scale;
605   }
606
607   if(raw_red){
608     coverage = (float)raw_n/out_n;
609     scale = coverage;
610     if(coverage<(1<<HRGBSHIFT))coverage=(1<<HRGBSHIFT);
611     icoverage = 1./coverage;
612
613     raw_center = out_start*scale+raw_off;
614     raw_start = raw_center-coverage;
615     raw_end = raw_center+coverage;
616
617     for(int i=out_start; i<out_end; i++){
618       int j = raw_start+1;
619       int e = raw_end;
620       if(j<0)j=0;
621       if(e>HISTSIZE)e=HISTSIZE;
622       //int jj=j;
623       float k = (j-raw_start)*icoverage-1.f;
624       float r=0.f, g=0.f, b=0.f, a=0.f;
625       for(; j<=e; j++){
626         float ik = 1.-fabs(k);
627         int sj = (j>>HRGBSHIFT);
628         int sjs = sj<<HRGBSHIFT;
629
630 #if (HRGBSHIFT==0)
631         a += raw[sjs]*ik;
632 #endif
633 #if (HRGBSHIFT==1)
634         a += (raw[sjs] +
635               raw[sjs+1])*ik;
636 #endif
637 #if (HRGBSHIFT==2)
638         a += (raw[sjs] +
639               raw[sjs+1] +
640               raw[sjs+2] +
641               raw[sjs+3])*ik;
642 #endif
643 #if (HRGBSHIFT==3)
644         a += (raw[sjs] +
645               raw[sjs+1] +
646               raw[sjs+2] +
647               raw[sjs+3] +
648               raw[sjs+4] +
649               raw[sjs+5] +
650               raw[sjs+6] +
651               raw[sjs+7])*ik;
652 #endif
653         r += raw_red[sj]*ik;
654         g += raw_green[sj]*ik;
655         b += raw_blue[sj]*ik;
656         k += icoverage;
657       }
658
659       a = a?1.f/a:0;
660       out_red[i] = CLAMP(r*a,0.f,1.f);
661       out_green[i] = CLAMP(g*a,0.f,1.f);
662       out_blue[i] = CLAMP(b*a,0.f,1.f);
663       raw_start += scale;
664       raw_end += scale;
665     }
666   }
667 }
668
669 void BluebananaSlider::update_histogram(float *raw, float *red, float *green, float *blue, int n){
670   int i;
671   int h = troughlines;
672   int w = troughcols;
673   float il2n = 1./log2(n);
674
675   if(!histval)
676     histval = new float[w];
677
678   if(!histred && red){
679     histred = new float[w];
680     histgreen = new float[w];
681     histblue = new float[w];
682   }
683
684   /* resample center */
685   resample_histogram(raw, red, green, blue, histval, histred, histgreen, histblue,
686                      HISTSIZE, 0, w, 0, w);
687
688   /* select value normalization */
689   for(i=0;i<w;i++){
690     if(histval[i]<=.0001f){
691       histval[i]=-2;
692     }else{
693       float val = log2(histval[i])*il2n;
694       val = pow(val<0?0:val,.75)*h;
695       if(val<0)val=0;
696       if(val>h)val=h;
697       histval[i]=val;
698     }
699   }
700   render();
701 }
702
703 // ---------------------------- Single ----------------------------------
704
705 BluebananaSliderSingle::BluebananaSliderSingle(BluebananaMain *plugin,
706                                                BluebananaWindow *gui,
707                                                int x,
708                                                int y,
709                                                int w,
710                                                int h,
711                                                float minval,
712                                                float maxval)
713   : BluebananaSlider(plugin,gui,x,y,w,h,minval,maxval){
714   val = (minval+maxval)/2;
715   increment = 1;
716 }
717
718 int BluebananaSliderSingle::button_press_event(){
719   if(is_event_win() && cursor_inside()){
720     //int min;
721     //int max;
722     int cx = get_cursor_x();
723
724     gui->deactivate();
725
726     if(get_buttonpress() == 4){
727       set_val(val - increment);
728       return 1;
729     }else if(get_buttonpress() == 5){
730       set_val(val + increment);
731       return 1;
732     }
733
734     switch(light){
735     case 0:
736       xoff = cx-value_to_pixel(val);
737       break;
738     default:
739       return 1;
740     }
741
742     drag = 1;
743     update();
744     return 1;
745   }
746   return 0;
747 }
748
749 int BluebananaSliderSingle::cursor_motion_event(){
750   int cx = get_cursor_x();
751   //int cy = get_cursor_y();
752
753   if(drag){
754     switch(light){
755     case 0:
756       set_val(pixel_to_value(cx - xoff));
757       break;
758     default:
759       drag = 0;
760       light = -1;
761       update();
762       break;
763     }
764     return 1;
765   }else{
766     if(is_event_win() && cursor_inside()){
767
768       if(in_midslider2(value_to_pixel(val),cx)){
769         if(light!=0){
770           light = 0;
771           update();
772         }
773       }else{
774         if(light!=-1){
775           light = -1;
776           update();
777         }
778       }
779       return 1;
780     }else{
781       if(light!=-1){
782         light = -1;
783         update();
784       }
785     }
786   }
787   return 0;
788 }
789
790 void BluebananaSliderSingle::set_val(float v){
791   val=v;
792   if(val<minval)val=minval;
793   if(val>maxval)val=maxval;
794   handle_event();
795   update();
796 }
797
798 void BluebananaSliderSingle::update(){
799   BluebananaSlider::update();
800   draw_bottomslider(value_to_pixel(val),light==0);
801   flash();
802   flush();
803 }
804
805 // ---------------------------- Bracket ----------------------------------
806
807 BluebananaSliderBracket::BluebananaSliderBracket(BluebananaMain *plugin,
808                                                  BluebananaWindow *gui,
809                                                  int x,
810                                                  int y,
811                                                  int w,
812                                                  int h,
813                                                  float minval,
814                                                  float maxval)
815   : BluebananaSlider(plugin,gui,x,y,w,h,minval,maxval){
816   loval = minval;
817   midval = (minval+maxval)/2;
818   hival = maxval;
819   overval = minval;
820   increment = 1;
821 }
822
823 int BluebananaSliderBracket::button_press_event(){
824   if(is_event_win() && cursor_inside()){
825     //int min;
826     //int max;
827     int cx = get_cursor_x();
828
829     gui->deactivate();
830
831     if(shift_down()){
832         /* narrow/widen range */
833       if(get_buttonpress() == 4){
834         set_delta(increment*2);
835         return 1;
836       }else if(get_buttonpress() == 5){
837         set_delta(-increment*2);
838         return 1;
839       }
840     }else if (ctrl_down()){
841       /* shift all vals up/down */
842       if(get_buttonpress() == 4){
843         set_mid(midval-increment);
844         return 1;
845       }else if(get_buttonpress() == 5){
846         set_mid(midval+increment);
847         return 1;
848       }
849     }else{
850       /* increase/decrease overlap */
851       if(get_buttonpress() == 4){
852         set_over(overval-1);
853         return 1;
854       }else if(get_buttonpress() == 5){
855         set_over(overval+1);
856         return 1;
857       }
858     }
859
860     switch(light){
861     case 0:
862       xoff = cx-value_to_pixel(loval);
863       break;
864     case 1:
865       xoff = cx-value_to_pixel(midval);
866       break;
867     case 2:
868       xoff = cx-value_to_pixel(hival);
869       break;
870     case 3:
871       xoff = cx-value_to_pixel(overval);
872       break;
873     default:
874       return 1;
875     }
876
877     drag = 1;
878     update();
879     return 1;
880   }
881   return 0;
882 }
883
884 int BluebananaSliderBracket::cursor_motion_event(){
885   int cx = get_cursor_x();
886   int cy = get_cursor_y();
887
888   if(drag){
889     switch(light){
890     case 0:
891       set_lo(pixel_to_value(cx - xoff));
892       break;
893     case 1:
894       set_mid(pixel_to_value(cx - xoff));
895       break;
896     case 2:
897       set_hi(pixel_to_value(cx - xoff));
898       break;
899     case 3:
900       set_over(pixel_to_value(cx - xoff));
901       break;
902     default:
903       drag = 0;
904       light = -1;
905       update();
906       break;
907     }
908     return 1;
909   }else{
910     if(is_event_win() && cursor_inside()){
911       if(in_overslider(value_to_pixel(overval),cx,cy)){
912         if(light!=3){
913           light = 3;
914           update();
915         }
916       }else if(in_midslider(value_to_pixel(midval),cx,cy)){
917         if(light!=1){
918           light = 1;
919           update();
920         }
921       }else if(in_leftslider(value_to_pixel(loval),cx,cy)){
922         if(light!=0){
923           light = 0;
924           update();
925         }
926       }else if(in_rightslider(value_to_pixel(hival),cx,cy)){
927         if(light!=2){
928           light = 2;
929           update();
930         }
931       }else if(in_midslider2(value_to_pixel(midval),cx)){
932         if(light!=1){
933           light = 1;
934           update();
935         }
936       }else if(in_rightslider2(value_to_pixel(hival),cx)){
937         if(light!=2){
938           light = 2;
939           update();
940         }
941       }else if(in_leftslider2(value_to_pixel(loval),cx)){
942         if(light!=0){
943           light = 0;
944           update();
945         }
946       }else if(in_overslider2(value_to_pixel(overval),cx,cy)){
947         if(light!=3){
948           light = 3;
949           update();
950         }
951       }else{
952         if(light!=-1){
953           light = -1;
954           update();
955         }
956       }
957       return 1;
958     }else{
959       if(light!=-1){
960         light = -1;
961         update();
962       }
963     }
964   }
965   return 0;
966 }
967
968 void BluebananaSliderBracket::set_lo(float val){
969   if(val<minval)val=minval;
970   if(val>maxval)val=maxval;
971   if(val > hival) val=hival;
972   loval=val;
973
974   if(hival<loval)hival+=(maxval-minval);
975   if(midval<loval)midval+=(maxval-minval);
976   midval = (hival+loval)/2.;
977   if(hival>maxval)hival-=(maxval-minval);
978   if(midval>maxval)midval-=(maxval-minval);
979   if(loval>maxval)loval-=(maxval-minval);
980   if(hival<minval)hival+=(maxval-minval);
981   if(midval<minval)midval+=(maxval-minval);
982   if(loval<minval)loval+=(maxval-minval);
983   handle_event();
984   update();
985 }
986
987 void BluebananaSliderBracket::set_mid(float val){
988   //float oldmid=midval;
989   if(val<minval)val=minval;
990   if(val>maxval)val=maxval;
991   midval=val;
992
993   float delta = (hival+loval)/2.;
994   hival+=midval-delta;
995   loval+=midval-delta;
996   if(hival>maxval){
997     loval += maxval-hival;
998     midval += maxval-hival;
999     hival = maxval;
1000   }
1001   if(loval<minval){
1002     hival-=loval;
1003     midval-=loval;
1004     loval=minval;
1005   }
1006   handle_event();
1007   update();
1008 }
1009
1010 void BluebananaSliderBracket::set_hi(float val){
1011   if(val<minval)val=minval;
1012   if(val>maxval)val=maxval;
1013   if(val<loval)val=loval;
1014   hival=val;
1015
1016   if(loval>hival)loval-=(maxval-minval);
1017   if(midval>hival)midval-=(maxval-minval);
1018   midval=(hival+loval)/2.;
1019   if(hival>maxval)hival-=(maxval-minval);
1020   if(midval>maxval)midval-=(maxval-minval);
1021   if(loval>maxval)loval-=(maxval-minval);
1022   if(hival<minval)hival+=(maxval-minval);
1023   if(midval<minval)midval+=(maxval-minval);
1024   if(loval<minval)loval+=(maxval-minval);
1025
1026   handle_event();
1027   update();
1028 }
1029
1030 void BluebananaSliderBracket::set_delta(float incr){
1031   float delta = (hival-loval)+incr;
1032   if(delta<minval)delta=minval;
1033   if(delta>maxval)delta=maxval;
1034   loval = midval-delta/2;
1035   hival = loval+delta;
1036
1037   if(loval<minval){
1038     hival-=loval;
1039     midval-=loval;
1040     loval=minval;
1041   }
1042   if(hival>maxval){
1043     loval-=(hival-maxval);
1044     midval-=(hival-maxval);
1045     hival=maxval;
1046   }
1047   handle_event();
1048   update();
1049 }
1050
1051 void BluebananaSliderBracket::set_over(float val){
1052   if(val<minval)val=minval;
1053   if(val>maxval)val=maxval;
1054   overval=val;
1055   handle_event();
1056   update();
1057 }
1058
1059
1060 void BluebananaSliderBracket::update(){
1061   BluebananaSlider::update();
1062   draw_overslider(value_to_pixel(overval),light==3);
1063   draw_leftslider(value_to_pixel(loval),light==0);
1064   draw_rightslider(value_to_pixel(hival),light==2);
1065   draw_midslider(value_to_pixel(midval),light==1);
1066   flash();
1067   flush();
1068 }
1069
1070 // ----------------------- Circular Bracket -----------------------------
1071
1072 BluebananaSliderCircular::BluebananaSliderCircular(BluebananaMain *plugin,
1073                                                    BluebananaWindow *gui,
1074                                                    int x,
1075                                                    int y,
1076                                                    int w,
1077                                                    int h,
1078                                                    float minval,
1079                                                    float maxval)
1080   : BluebananaSliderBracket(plugin,gui,x,y,w,h,minval,maxval){}
1081
1082 void BluebananaSliderCircular::set_lo(float val){
1083   if(val<minval)val=minval;
1084   if(val>maxval)val=maxval;
1085   loval=val;
1086
1087   if(hival<loval)hival+=(maxval-minval);
1088   if(midval<loval)midval+=(maxval-minval);
1089   midval = (hival+loval)/2.;
1090   if(hival>maxval)hival-=(maxval-minval);
1091   if(midval>maxval)midval-=(maxval-minval);
1092   if(loval>maxval)loval-=(maxval-minval);
1093   if(hival<minval)hival+=(maxval-minval);
1094   if(midval<minval)midval+=(maxval-minval);
1095   if(loval<minval)loval+=(maxval-minval);
1096
1097   handle_event();
1098   update();
1099 }
1100
1101 void BluebananaSliderCircular::set_mid(float val){
1102   float oldmid=midval;
1103   if(val<minval)val=minval;
1104   if(val>maxval)val=maxval;
1105   midval=val;
1106   if(hival<oldmid)hival+=(maxval-minval);
1107   if(loval>oldmid)loval-=(maxval-minval);
1108   float delta = hival-loval;
1109   loval = midval-delta/2;
1110   hival = loval+delta;
1111   if(hival>maxval)hival-=(maxval-minval);
1112   if(loval>maxval)loval-=(maxval-minval);
1113   if(hival<minval)hival+=(maxval-minval);
1114   if(loval<minval)loval+=(maxval-minval);
1115   handle_event();
1116   update();
1117 }
1118
1119 void BluebananaSliderCircular::set_hi(float val){
1120   if(val<minval)val=minval;
1121   if(val>maxval)val=maxval;
1122   hival=val;
1123   if(loval>hival)loval-=(maxval-minval);
1124   if(midval>hival)midval-=(maxval-minval);
1125   midval = (hival+loval)/2.;
1126   if(hival>maxval)hival-=(maxval-minval);
1127   if(midval>maxval)midval-=(maxval-minval);
1128   if(loval>maxval)loval-=(maxval-minval);
1129   if(hival<minval)hival+=(maxval-minval);
1130   if(midval<minval)midval+=(maxval-minval);
1131   if(loval<minval)loval+=(maxval-minval);
1132   handle_event();
1133   update();
1134 }
1135
1136 void BluebananaSliderCircular::set_delta(float incr){
1137   if(hival<midval)hival+=(maxval-minval);
1138   if(loval>midval)loval-=(maxval-minval);
1139
1140   float delta = (hival-loval)+incr;
1141   if(delta<minval)delta=minval;
1142   if(delta>maxval)delta=maxval;
1143   loval = midval-delta/2;
1144   hival = loval+delta;
1145
1146   if(hival>maxval)hival-=(maxval-minval);
1147   if(loval>maxval)loval-=(maxval-minval);
1148   if(hival<minval)hival+=(maxval-minval);
1149   if(loval<minval)loval+=(maxval-minval);
1150   handle_event();
1151   update();
1152 }
1153
1154 void BluebananaSliderCircular::update(){
1155   BluebananaSliderBracket::update();
1156   flash();
1157   flush();
1158 }
1159
1160 // -------------------------- In + Out + Gamma --------------------------------
1161
1162 #define mG2 (2.f-2.f*MIN_GAMMA)
1163 #define MG2 (2.f*MAX_GAMMA-2.f)
1164
1165 float BluebananaSliderChannel::pixel_to_gamma(float pixel){
1166   float unit = (1.-pixel_to_fraction(pixel)-FRAC0)/(FRAC100-FRAC0);
1167   return (unit > .5f ?
1168           (1.f-unit) * mG2 + MIN_GAMMA :
1169           (.5f-unit) * MG2 + 1.f );
1170 }
1171
1172 float BluebananaSliderChannel::gamma_to_pixel(float gamma){
1173   float fraction =
1174     gamma<1 ? 1.f - (gamma-MIN_GAMMA) / mG2 :
1175     .5f - (gamma-1.f) / MG2 ;
1176   return fraction_to_pixel((1.-fraction) * (FRAC100-FRAC0) + FRAC0);
1177 }
1178
1179 float BluebananaSliderChannel::pixel_to_value(float pixel){
1180   if(pixel<t_x1){
1181     return (t_x0-pixel)/t_w01*MIN_HISTBRACKET+MIN_HISTBRACKET;
1182   }else if (pixel<t_x2){
1183     return (pixel-t_x1)/t_w12*100;
1184   }else{
1185     return (pixel-t_x2)/t_w23*(MAX_HISTBRACKET-100)+100;
1186   }
1187 }
1188
1189 float BluebananaSliderChannel::value_to_pixel(float val){
1190   if(val<0){
1191     return rint(MIN_HISTBRACKET-val)/MIN_HISTBRACKET*t_w01+t_x0;
1192   }else if(val<100){
1193     return rint(val/100.*t_w12+t_x1+.01);
1194   }else{
1195     return rint((val-100)/(MAX_HISTBRACKET-100.)*t_w23+t_x2);
1196   }
1197 }
1198
1199 BluebananaSliderChannel::BluebananaSliderChannel(BluebananaMain *plugin,
1200                                              BluebananaWindow *gui,
1201                                              int x,
1202                                              int y,
1203                                              int w,
1204                                              int h)
1205   : BluebananaSlider(plugin,gui,x,y,w,h,0,100){
1206   loval = 0;
1207   gamma = 1.;
1208   hival = 100.;
1209 }
1210
1211 BluebananaSliderChannel::~BluebananaSliderChannel(){}
1212
1213 int BluebananaSliderChannel::button_press_event(){
1214   if(is_event_win() && cursor_inside()){
1215     //int min;
1216     //int max;
1217     int cx = get_cursor_x();
1218     //int cy = get_cursor_y();
1219
1220     gui->deactivate();
1221
1222     if(shift_down()){
1223       /* narrow/widen range */
1224       if(get_buttonpress() == 4){
1225         set_range(hival-loval-2);
1226         return 1;
1227       }else if(get_buttonpress() == 5){
1228         if(loval<hival){
1229           set_range(hival-loval+2);
1230         }
1231         return 1;
1232       }
1233     }else if (ctrl_down()){
1234       /* shift all vals up/down */
1235       if(get_buttonpress() == 4){
1236         set_mid((loval+hival)/2+1);
1237         return 1;
1238       }else if(get_buttonpress() == 5){
1239         set_mid((loval+hival)/2-1);
1240         return 1;
1241       }
1242     }else{
1243       /* increase/decrease gamma */
1244       if(get_buttonpress() == 4){
1245         set_gamma(gamma-.01);
1246         return 1;
1247       }else if(get_buttonpress() == 5){
1248         set_gamma(gamma+.01);
1249         return 1;
1250       }
1251     }
1252
1253     switch(light){
1254     case 0:
1255       xoff = cx-value_to_pixel(loval);
1256       break;
1257     case 1:
1258       xoff = cx-value_to_pixel((loval+hival)/2);
1259       break;
1260     case 2:
1261       xoff = cx-value_to_pixel(hival);
1262       break;
1263     case 3:
1264       xoff = cx-gamma_to_pixel(gamma);
1265       break;
1266     default:
1267       return 1;
1268     }
1269
1270     drag = 1;
1271     update();
1272     return 1;
1273   }
1274   return 0;
1275 }
1276
1277 int BluebananaSliderChannel::cursor_motion_event(){
1278   int cx = get_cursor_x();
1279   int cy = get_cursor_y();
1280
1281   if(drag){
1282     switch(light){
1283     case 0:
1284       set_lo(pixel_to_value(cx - xoff));
1285       break;
1286     case 1:
1287       set_mid(pixel_to_value(cx - xoff));
1288       break;
1289     case 2:
1290       set_hi(pixel_to_value(cx - xoff));
1291       break;
1292     case 3:
1293       set_gamma(pixel_to_gamma(cx - xoff));
1294       break;
1295     default:
1296       drag = 0;
1297       light = -1;
1298       update();
1299       break;
1300     }
1301     return 1;
1302   }else{
1303     if(is_event_win() && cursor_inside()){
1304       if(in_topslider(gamma_to_pixel(gamma),cx,cy)){
1305         if(light!=3){
1306           light = 3;
1307           update();
1308         }
1309       }else if(in_midslider(value_to_pixel((loval+hival)/2),cx,cy)){
1310         if(light!=1){
1311           light = 1;
1312           update();
1313         }
1314       }else if(in_leftslider(value_to_pixel(loval),cx,cy)){
1315         if(light!=0){
1316           light = 0;
1317           update();
1318         }
1319       }else if(in_rightslider(value_to_pixel(hival),cx,cy)){
1320         if(light!=2){
1321           light = 2;
1322           update();
1323         }
1324       }else if(in_bottomslider(value_to_pixel(hival),cx,cy)){
1325         if(light!=2){
1326           light = 2;
1327           update();
1328         }
1329       }else if(in_bottomslider(value_to_pixel(loval),cx,cy)){
1330         if(light!=0){
1331           light = 0;
1332           update();
1333         }
1334       }else if(in_midslider2(value_to_pixel((loval+hival)/2),cx)){
1335         if(light!=1){
1336           light = 1;
1337           update();
1338         }
1339       }else if(in_overslider2(gamma_to_pixel(gamma),cx,cy)){
1340         if(light!=3){
1341           light = 3;
1342           update();
1343         }
1344       }else{
1345         if(light!=-1){
1346           light = -1;
1347           update();
1348         }
1349       }
1350       return 1;
1351     }else{
1352       if(light!=-1){
1353         light = -1;
1354         update();
1355       }
1356     }
1357   }
1358   return 0;
1359 }
1360
1361 void BluebananaSliderChannel::set_lo(float v){
1362   if(v>hival)v=hival;
1363   if(v<-100)v=-100;
1364   if(v>100)v=100;
1365   loval=rint(v);
1366   handle_event();
1367   update();
1368 }
1369
1370 void BluebananaSliderChannel::set_hi(float v){
1371   if(v<loval)v=loval;
1372   if(v<0)v=0;
1373   if(v>200)v=200;
1374   hival=rint(v);
1375   handle_event();
1376   update();
1377 }
1378
1379 void BluebananaSliderChannel::set_mid(float v){
1380   float mid = (hival+loval)*.5;
1381   float range = hival-loval;
1382   float del = v-mid;
1383
1384   if(hival+del>200)del=200-hival;
1385   if(hival+del<0)del=0-hival;
1386   if(loval+del>100)del=100-loval;
1387   if(loval+del<-100)del=-100-loval;
1388
1389   loval+=rint(del);
1390   hival=loval+rint(range);
1391   handle_event();
1392   update();
1393 }
1394
1395 void BluebananaSliderChannel::set_range(float v){
1396   //float mid = (hival+loval)*.5;
1397   float range = hival-loval;
1398
1399   if(v>200)v=200;
1400   if(v<0)v=0;
1401
1402   float del = (v-range)/2;
1403
1404   if(hival+del>200)del=200-hival;
1405   if(hival+del<0)del=0-hival;
1406
1407   if(loval-del>100)del=loval-100;
1408   if(loval-del<-100)del=loval+100;
1409
1410   loval-=rint(del);
1411   hival=rint(loval+v);
1412   handle_event();
1413   update();
1414 }
1415
1416 void BluebananaSliderChannel::set_gamma(float v){
1417   if(v>MAX_GAMMA)v=MAX_GAMMA;
1418   if(v<MIN_GAMMA)v=MIN_GAMMA;
1419   gamma=v;
1420   handle_event();
1421   update();
1422 }
1423
1424 void BluebananaSliderChannel::update(){
1425   int w = get_w();
1426   int h = get_h();
1427   int bg_c = get_resources()->get_bg_color();
1428   int bg_r = ((bg_c >> 16) & 0xff);
1429   int bg_g = ((bg_c >> 8) & 0xff);
1430   int bg_b = (bg_c & 0xff);
1431   int b_c = highlight ? active_bordercolor : inactive_bordercolor;
1432   int b_r = ((b_c >> 16) & 0xff);
1433   int b_g = ((b_c >> 8) & 0xff);
1434   int b_b = (b_c & 0xff);
1435   int tb_c = troughcolor;
1436   int tb_r = ((tb_c >> 16) & 0xff);
1437   int tb_g = ((tb_c >> 8) & 0xff);
1438   int tb_b = (tb_c & 0xff);
1439
1440   int ZH = Z4-Z1+1;
1441   //int ZHC = Z4-ZC+1;
1442
1443   int i,j;
1444
1445   t_x0 = fraction_to_pixel(0);
1446   t_x1 = fraction_to_pixel(FRAC0);
1447   t_x2 = fraction_to_pixel(FRAC100);
1448   t_x3 = fraction_to_pixel(1.);
1449   t_w01 = t_x1-t_x0;
1450   t_w12 = t_x2-t_x1;
1451   t_w23 = t_x3-t_x2;
1452
1453
1454   int ntw = troughcols-6;
1455   int nth = troughlines;
1456   int ntx = t_x0;
1457   int nty = Z1+1;
1458
1459   clear_box(0, 0, w, h);
1460
1461   /* trough shadow */
1462
1463   /* w+4 h+4 x-1 y-1 */
1464   float del = .9;
1465   int shadow_c = ((int)(bg_r*del) << 16) | ((int)(bg_g*del) << 8) | ((int)(bg_b*del));
1466   set_color(shadow_c);
1467   draw_box (0,Z1,t_x1+3,ZH+2);
1468   draw_box (1,Z1-1,t_x1+1,ZH+4);
1469   draw_box (t_x1,Z1,t_w12+3,ZH+2);
1470   draw_box (t_x1+1,Z1-1,t_w12+1,ZH+4);
1471   draw_box (t_x2,Z1,w-t_x2,ZH-2+2);
1472   draw_box (t_x2+1,Z1-1,w-t_x2-2,ZH+4);
1473
1474   /* w+2 h+2 x y */
1475   del = .8;
1476   shadow_c = ((int)(bg_r*del) << 16) | ((int)(bg_g*del) << 8) | ((int)(bg_b*del));
1477   set_color(shadow_c);
1478   draw_box (1,Z1+1,t_x1+1,ZH);
1479   draw_box (2,Z1,t_x1-1,ZH+2);
1480   draw_box (t_x1+1,Z1+1,t_w12+1,ZH);
1481   draw_box (t_x1+2,Z1,t_w12-1,ZH+2);
1482   draw_box (t_x2+1,Z1+1,w-t_x2-2,ZH);
1483   draw_box (t_x2+2,Z1,w-t_x2-4,ZH+2);
1484
1485   /* w h x+1 y+1 */
1486   del = .7;
1487   shadow_c = ((int)(bg_r*del) << 16) | ((int)(bg_g*del) << 8) | ((int)(bg_b*del));
1488   set_color(shadow_c);
1489   draw_box (2,Z1+2,t_x1-1,ZH-2);
1490   draw_box (3,Z1+1,t_x1-3,ZH);
1491   draw_box (t_x1+2,Z1+2,t_w12-1,ZH-2);
1492   draw_box (t_x1+3,Z1+1,t_w12-3,ZH);
1493   draw_box (t_x2+2,Z1+2,w-t_x2-4,ZH-2);
1494   draw_box (t_x2+3,Z1+1,w-t_x2-6,ZH);
1495
1496   /* trough border */
1497   set_color(b_c);
1498   draw_box (1,Z1+1,t_x1-1,ZH-2);
1499   draw_box (2,Z1,t_x1-3,ZH);
1500   draw_box (t_x1+1,Z1+1,t_w12-1,ZH-2);
1501   draw_box (t_x1+2,Z1,t_w12-3,ZH);
1502   draw_box (t_x2+1,Z1+1,w-t_x2-4,ZH-2);
1503   draw_box (t_x2+2,Z1,w-t_x2-6,ZH);
1504
1505   /* trough inner */
1506   /* the trough in the three-part hist slider is slightly smaller than
1507      the full slider range, and cut into three sections */
1508   if(!trough){
1509     trough = new VFrame(ntw,nth,BC_RGBA8888);
1510   }
1511
1512   if(!trough){
1513     fprintf(stderr,"Bluebanana: Unable to create Frame for slider\n");
1514   }else{
1515     unsigned char *data = trough->get_data();
1516     float ha = 1.;
1517     long bpp = trough->get_bytes_per_pixel();
1518     long bpr = trough->get_bytes_per_line();
1519     float r,g,b,a,rr,gg,bb;
1520
1521     if(!highlight){
1522       ha*=.25;
1523       tb_r = bg_r;
1524       tb_g = bg_g;
1525       tb_b = bg_b;
1526     }
1527
1528     if(!histval){
1529
1530       for(i=0;i<ntw;i++){
1531         unsigned char *row = data;
1532         for(j=0;j<nth;j++){
1533           row[0] = tb_r;
1534           row[1] = tb_g;
1535           row[2] = tb_b;
1536           row[3] = 0xff;
1537           row+=bpr;
1538         }
1539       }
1540
1541     }else{
1542
1543       trough_color(1.,rr,gg,bb);
1544       rr*=255;
1545       gg*=255;
1546       bb*=255;
1547       rr = CLAMP((rr+b_r*3)/4,0,255);
1548       gg = CLAMP((gg+b_g*3)/4,0,255);
1549       bb = CLAMP((bb+b_b*3)/4,0,255);
1550
1551       for(i=0;i<ntw;i++){
1552         unsigned char *row = data;
1553         float y = nth-histval[i];
1554         float y0 = i>0?nth-histval[i-1]:y;
1555         float y1 = i+1<ntw?nth-histval[i+1]:y;
1556         float yp = MIN(y,MIN(y0+1,y1+1));
1557         float y3 = (y0+y+y1)*.333f;
1558
1559         if(histred){
1560           r=histred[i];
1561           g=histgreen[i];
1562           b=histblue[i];
1563         }else{
1564           float val = (i < t_w01-1 ?
1565                        ((MIN_HISTBRACKET/100.f) - i/(t_w01-1.f)*(MIN_HISTBRACKET/100.f)) :
1566                        (i<t_w01+t_w12-4 ?
1567                         ((i - t_w01 + 1) / (t_w12-4.f)) :
1568                         ((i - t_w01 - t_w12 + 5) / (t_w23-1.f)*((MAX_HISTBRACKET/100.f)-1.f)+1.f)));
1569
1570           trough_color(val,r,g,b);
1571           r=CLAMP(r,0,255);
1572           g=CLAMP(g,0,255);
1573           b=CLAMP(b,0,255);
1574
1575         }
1576
1577         for(j=0;j<yp-1 && j<nth;j++){
1578           row[0] = tb_r;
1579           row[1] = tb_g;
1580           row[2] = tb_b;
1581           row[3] = 0xff;
1582           row+=bpr;
1583         }
1584
1585         a=.75*ha;
1586         for(;j<y && j<nth;j++){
1587           row[0] = rint(rr*a + tb_r*(1-a));
1588           row[1] = rint(gg*a + tb_g*(1-a));
1589           row[2] = rint(bb*a + tb_b*(1-a));
1590           row[3] = 0xff;
1591           row+=bpr;
1592         }
1593
1594         a=ha;
1595         for(;j<nth;j++){
1596           float a = CLAMP(1. - .3*(float)(j-y3)/(nth-y3+1),0.f,1.f)*ha;
1597           row[0] = rint(r*a*255.f + tb_r*(1-a));
1598           row[1] = rint(g*a*255.f + tb_g*(1-a));
1599           row[2] = rint(b*a*255.f + tb_b*(1-a));
1600           row[3] = 0xff;
1601           row+=bpr;
1602         }
1603
1604         data+=bpp;
1605       }
1606     }
1607
1608     draw_vframe(trough, ntx,    nty,       t_w01-2, 1,     0,             0,     t_w01-2, 1);
1609     draw_vframe(trough, ntx,    nty+1,     t_w01-1, nth-2, 0,             1,     t_w01-1, nth-2);
1610     draw_vframe(trough, ntx,    nty+nth-1, t_w01-2, 1,     0,             nth-1, t_w01-2, 1);
1611
1612     draw_vframe(trough, t_x1+3, nty,       t_w12-5, 1,     t_w01,         0,     t_w12-5, 1);
1613     draw_vframe(trough, t_x1+2, nty+1,     t_w12-3, nth-2, t_w01-1,       1,     t_w12-3, nth-2);
1614     draw_vframe(trough, t_x1+3, nty+nth-1, t_w12-5, 1,     t_w01,         nth-1, t_w12-5, 1);
1615
1616     draw_vframe(trough, t_x2+3, nty,       t_w23-2, 1,     t_w01+t_w12-3, 0,     t_w23-2, 1);
1617     draw_vframe(trough, t_x2+2, nty+1,     t_w23-1, nth-2, t_w01+t_w12-4, 1,     t_w23-1, nth-2);
1618     draw_vframe(trough, t_x2+3, nty+nth-1, t_w23-2, 1,     t_w01+t_w12-3, nth-1, t_w23-2, 1);
1619   }
1620
1621   draw_topslider(rint(gamma_to_pixel(gamma)),light==3);
1622
1623   draw_bottomslider(rint(value_to_pixel(loval)),light==0);
1624   draw_bottomslider(rint(value_to_pixel(hival)),light==2);
1625   draw_midslider(rint(value_to_pixel((loval+hival)/2.)),light==1);
1626
1627   flash();
1628   flush();
1629 }
1630
1631 void BluebananaSliderChannel::update_histogram(float *raw, float *red, float *green, float *blue, int n){
1632   int i;
1633   //int h = troughlines;
1634   int w = troughcols-6;
1635   float il2n = 1./log2(n);
1636   int w0 = t_w01-1;
1637   int w1 = t_w12-4;
1638   int w2 = t_w23-1;
1639
1640   if(!histval)
1641     histval = new float[w];
1642
1643   if(!histred && red){
1644     histred = new float[w];
1645     histgreen = new float[w];
1646     histblue = new float[w];
1647   }
1648
1649   /* resample left */
1650   int span0 = rint((0.f-MIN_HISTBRACKET) / (MAX_HISTBRACKET-MIN_HISTBRACKET) * HISTSIZE);
1651   resample_histogram(raw, red, green, blue, histval, histred, histgreen, histblue,
1652                      span0, 0, w0, 0, w0);
1653
1654   /* resample center */
1655   int span1 = rint(100.f/(MAX_HISTBRACKET-MIN_HISTBRACKET) * HISTSIZE);
1656   resample_histogram(raw, red, green, blue, histval+w0, histred+w0, histgreen+w0, histblue+w0,
1657                      span1, span0, w1, 0, w1+1);
1658
1659   /* resample right */
1660   int span2 = rint((MAX_HISTBRACKET-100.f) / (MAX_HISTBRACKET-MIN_HISTBRACKET) * HISTSIZE);
1661   resample_histogram(raw, red, green, blue, histval+w0+w1, histred+w0+w1, histgreen+w0+w1, histblue+w0+w1,
1662                      span2, span0+span1, w2, 1, w2+1);
1663
1664   /* select value normalization */
1665   for(i=0;i<w;i++){
1666     if(histval[i]<=.0001f){
1667       histval[i]=-2;
1668     }else{
1669       float val = log2(histval[i])*il2n;
1670       val = pow(val<0?0:val,.75)*troughlines;
1671       if(val<0)val=0;
1672       if(val>troughlines)val=troughlines;
1673       histval[i]=val;
1674     }
1675   }
1676   render();
1677 }
1678
1679 // ---------------------------- Fill ----------------------------------
1680
1681 int BluebananaSliderFill::over_to_pixel(float input){
1682   return fraction_to_pixel(input/maxover);
1683 }
1684
1685 float BluebananaSliderFill::pixel_to_over(int pixel){
1686   return pixel_to_fraction(pixel)*maxover;
1687 }
1688
1689 BluebananaSliderFill::BluebananaSliderFill(BluebananaMain *plugin,
1690                                            BluebananaWindow *gui,
1691                                            int x,
1692                                            int y,
1693                                            int w,
1694                                            int h,
1695                                            float minval,
1696                                            float maxval,
1697                                            float maxover)
1698   : BluebananaSlider(plugin,gui,x,y,w,h,minval,maxval){
1699   loval = -2;
1700   midval = 0;
1701   hival = 2;
1702   overval = 0;
1703   this->maxover = maxover;
1704 }
1705
1706 int BluebananaSliderFill::button_press_event(){
1707   if(is_event_win() && cursor_inside()){
1708     //int min;
1709     //int max;
1710     int cx = get_cursor_x();
1711
1712     gui->deactivate();
1713
1714     if(shift_down()){
1715         /* narrow/widen range */
1716       if(get_buttonpress() == 4){
1717         set_delta(1);
1718         return 1;
1719       }else if(get_buttonpress() == 5){
1720         set_delta(-1);
1721         return 1;
1722       }
1723     }else if (ctrl_down()){
1724       /* shift all vals up/down */
1725       if(get_buttonpress() == 4){
1726         if(loval-increment>minval)
1727           set_fill(loval-1,midval-1,hival-1);
1728         return 1;
1729       }else if(get_buttonpress() == 5){
1730         if(hival+increment<maxval)
1731           set_fill(loval+1,midval+1,hival+1);
1732         return 1;
1733       }
1734     }else{
1735       /* increase/decrease feather */
1736       if(get_buttonpress() == 4){
1737         set_over(overval-1);
1738         return 1;
1739       }else if(get_buttonpress() == 5){
1740         set_over(overval+1);
1741         return 1;
1742       }
1743     }
1744
1745     switch(light){
1746     case 0:
1747       xoff = cx-value_to_pixel(loval);
1748       break;
1749     case 1:
1750       xoff = cx-value_to_pixel(midval);
1751       break;
1752     case 2:
1753       xoff = cx-value_to_pixel(hival);
1754       break;
1755     case 3:
1756       xoff = cx-over_to_pixel(overval);
1757       break;
1758     default:
1759       return 1;
1760     }
1761
1762     drag = 1;
1763     update();
1764     return 1;
1765   }
1766   return 0;
1767 }
1768
1769 int BluebananaSliderFill::cursor_motion_event(){
1770   int cx = get_cursor_x();
1771   int cy = get_cursor_y();
1772
1773   if(drag){
1774     switch(light){
1775     case 0:
1776       set_fill(pixel_to_value(cx - xoff),midval,hival);
1777       break;
1778     case 1:
1779       set_fill(loval,pixel_to_value(cx - xoff),hival);
1780       break;
1781     case 2:
1782       set_fill(loval,midval,pixel_to_value(cx - xoff));
1783       break;
1784     case 3:
1785       set_over(pixel_to_over(cx - xoff));
1786       break;
1787     default:
1788       drag = 0;
1789       light = -1;
1790       update();
1791       break;
1792     }
1793     return 1;
1794   }else{
1795     if(is_event_win() && cursor_inside()){
1796       if(in_overslider(over_to_pixel(overval),cx,cy)){
1797         if(light!=3){
1798           light = 3;
1799           update();
1800         }
1801       }else if(in_bottomslider(value_to_pixel(midval),cx,cy)){
1802         if(light!=1){
1803           light = 1;
1804           update();
1805         }
1806       }else if(in_leftslider(value_to_pixel(loval),cx,cy)){
1807         if(light!=0){
1808           light = 0;
1809           update();
1810         }
1811       }else if(in_rightslider(value_to_pixel(hival),cx,cy)){
1812         if(light!=2){
1813           light = 2;
1814           update();
1815         }
1816       }else if(in_midslider2(value_to_pixel(midval),cx)){
1817         if(light!=1){
1818           light = 1;
1819           update();
1820         }
1821       }else if(in_rightslider2(value_to_pixel(hival),cx)){
1822         if(light!=2){
1823           light = 2;
1824           update();
1825         }
1826       }else if(in_leftslider2(value_to_pixel(loval),cx)){
1827         if(light!=0){
1828           light = 0;
1829           update();
1830         }
1831       }else if(in_overslider2(over_to_pixel(overval),cx,cy)){
1832         if(light!=3){
1833           light = 3;
1834           update();
1835         }
1836       }else{
1837         if(light!=-1){
1838           light = -1;
1839           update();
1840         }
1841       }
1842       return 1;
1843     }else{
1844       if(light!=-1){
1845         light = -1;
1846         update();
1847       }
1848     }
1849   }
1850   return 0;
1851 }
1852
1853 void BluebananaSliderFill::set_fill(float lo, float mid, float hi){
1854   if(lo<minval)lo=minval;
1855   if(mid<minval)mid=minval;
1856   if(hi<0)hi=0;
1857   if(lo>0)lo=0;
1858   if(mid>maxval)mid=maxval;
1859   if(hi>maxval)hi=maxval;
1860
1861   if(lo>midval)mid=lo;
1862   if(mid<loval)lo=mid;
1863   if(mid>hival)hi=mid;
1864   if(hi<midval)mid=hi;
1865
1866   loval=lo;
1867   midval=mid;
1868   hival=hi;
1869
1870   handle_event();
1871   update();
1872 }
1873
1874 void BluebananaSliderFill::set_delta(float del){
1875   if(loval+del>=minval && hival+del<=maxval){
1876     loval-=del;
1877     hival+=del;
1878     if(loval>hival)
1879       loval=hival=rint((loval+hival)/2);
1880     if(midval<loval)midval=loval;
1881     if(midval>hival)midval=hival;
1882     handle_event();
1883     update();
1884   }
1885 }
1886
1887 void BluebananaSliderFill::set_over(float over){
1888   if(over>=0 && over<=maxover){
1889     overval=over;
1890     handle_event();
1891     update();
1892   }
1893 }
1894
1895 void BluebananaSliderFill::update(){
1896   int w = get_w();
1897   int h = get_h();
1898   int bg_c = get_resources()->get_bg_color();
1899   int bg_r = ((bg_c >> 16) & 0xff);
1900   int bg_g = ((bg_c >> 8) & 0xff);
1901   int bg_b = (bg_c & 0xff);
1902   int b_c = highlight ? active_bordercolor : inactive_bordercolor;
1903   //int b_r = ((b_c >> 16) & 0xff);
1904   //int b_g = ((b_c >> 8) & 0xff);
1905   //int b_b = (b_c & 0xff);
1906   int tb_c = troughcolor;
1907   int tb_r = ((tb_c >> 16) & 0xff);
1908   int tb_g = ((tb_c >> 8) & 0xff);
1909   int tb_b = (tb_c & 0xff);
1910
1911   int ZH = Z4-Z1+1;
1912   //int ZHC = Z4-ZC+1;
1913
1914   int i,j;
1915
1916   int xC = value_to_pixel(0);
1917   int ntw = troughcols;
1918   int nth = troughlines;
1919   int ntx = CW+ZL;
1920   int nty = Z1+1;
1921
1922   clear_box(0, 0, w, h);
1923
1924   /* trough shadow */
1925
1926   /* w+4 h+4 x-1 y-1 */
1927   float del = .9;
1928   int shadow_c = ((int)(bg_r*del) << 16) | ((int)(bg_g*del) << 8) | ((int)(bg_b*del));
1929   set_color(shadow_c);
1930   draw_box (0,Z1,xC+3,ZH+2);
1931   draw_box (1,Z1-1,xC+1,ZH+4);
1932   draw_box (xC,Z1,w-xC,ZH+2);
1933   draw_box (xC+1,Z1-1,w-xC-2,ZH+4);
1934
1935   /* w+2 h+2 x y */
1936   del = .8;
1937   shadow_c = ((int)(bg_r*del) << 16) | ((int)(bg_g*del) << 8) | ((int)(bg_b*del));
1938   set_color(shadow_c);
1939   draw_box (1,Z1+1,xC+1,ZH);
1940   draw_box (2,Z1,xC-1,ZH+2);
1941   draw_box (xC+1,Z1+1,w-xC-2,ZH);
1942   draw_box (xC+2,Z1,w-xC-4,ZH+2);
1943
1944   /* w h x+1 y+1 */
1945   del = .7;
1946   shadow_c = ((int)(bg_r*del) << 16) | ((int)(bg_g*del) << 8) | ((int)(bg_b*del));
1947   set_color(shadow_c);
1948   draw_box (2,Z1+2,xC-1,ZH-2);
1949   draw_box (3,Z1+1,xC-3,ZH);
1950   draw_box (xC+2,Z1+2,w-xC-4,ZH-2);
1951   draw_box (xC+3,Z1+1,w-xC-6,ZH);
1952
1953   /* trough border */
1954   set_color(b_c);
1955   draw_box (1,Z1+1,xC-1,ZH-2);
1956   draw_box (2,Z1,xC-3,ZH);
1957   draw_box (xC+1,Z1+1,w-xC-4,ZH-2);
1958   draw_box (xC+2,Z1,w-xC-6,ZH);
1959
1960   /* trough inner */
1961   /* the trough in the two-part contour slider is slightly smaller than
1962      the full slider range, and cut into two sections */
1963   if(!trough){
1964     trough = new VFrame(ntw,nth,BC_RGBA8888);
1965   }
1966
1967   /* Unlike the hist slider, we just drop the three pixel columns in the center */
1968   if(!trough){
1969     fprintf(stderr,"Bluebanana: Unable to create Frame for slider\n");
1970   }else{
1971     unsigned char *data = trough->get_data();
1972     long bpr = trough->get_bytes_per_line();
1973     float ha = 1.;
1974     if(!highlight){
1975       ha*=.25;
1976       tb_r = bg_r;
1977       tb_g = bg_g;
1978       tb_b = bg_b;
1979     }
1980
1981     for(i=0;i<ntw;i++){
1982       unsigned char *row = data + i*trough->get_bytes_per_pixel();
1983       for(j=0;j<nth;j++){
1984         float r,g,b,a;
1985         trough_color((i+.5f)/ntw,(j+.5)/nth,r,g,b,a);
1986         r=CLAMP(r,0,255);
1987         g=CLAMP(g,0,255);
1988         b=CLAMP(b,0,255);
1989         a*=ha;
1990         row[0] = rint(r*a*255 + tb_r*(1-a));
1991         row[1] = rint(g*a*255 + tb_g*(1-a));
1992         row[2] = rint(b*a*255 + tb_b*(1-a));
1993         row[3] = 0xff;
1994         row+=bpr;
1995       }
1996     }
1997
1998     draw_vframe(trough, ntx,  nty,       xC-ntx-2, 1,     0,        0,     xC-ntx-2, 1);
1999     draw_vframe(trough, ntx,  nty+1,     xC-ntx-1, nth-2, 0,        1,     xC-ntx-1, nth-2);
2000     draw_vframe(trough, ntx,  nty+nth-1, xC-ntx-2, 1,     0,        nth-1, xC-ntx-2, 1);
2001
2002     draw_vframe(trough, xC+3, nty,       ntw-xC+ntx-3, 1,     xC-ntx+2, 0,     ntw-xC+ntx-3, 1);
2003     draw_vframe(trough, xC+2, nty+1,     ntw-xC+ntx-2, nth-2, xC-ntx+1, 1,     ntx-xC+ntx-2, nth-2);
2004     draw_vframe(trough, xC+3, nty+nth-1, ntw-xC+ntx-3, 1,     xC-ntx+2, nth-1, ntw-xC+ntx-3, 1);
2005   }
2006
2007   draw_overslider(over_to_pixel(overval),light==3);
2008   draw_leftslider(value_to_pixel(loval),light==0);
2009   draw_rightslider(value_to_pixel(hival),light==2);
2010   draw_bottomslider(value_to_pixel(midval),light==1);
2011   flash();
2012   flush();
2013 }