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