--- /dev/null
+/*
+ * Cinelerra :: Blue Banana - color modification plugin for Cinelerra-CV
+ * Copyright (C) 2012-2013 Monty <monty@xiph.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+
+#include "bluebananaslider.h"
+#include "language.h"
+
+#undef CLAMP
+#define CLAMP(x, y, z) ((x) < (y) ? (y) : ((x) > (z) ? (z) : (x)))
+
+#define CW (get_h()/2+2)
+#define SW (get_h()*2/5+1)
+#define Z1 (get_h()/7+2)
+#define Z2 (get_h()*2/5+1)
+#define Z3 (get_h()-Z2-1)
+#define Z4 (get_h()-Z1-1)
+#define ZC ((Z3+Z2)/2)
+
+#define ZS 3
+#define ZL 1
+#define ZR 3
+
+#include <math.h>
+
+static int scale_color(int color, float scale){
+ int r = ((color >> 16) & 0xff)*scale;
+ int g = ((color >> 8) & 0xff)*scale;
+ int b = (color & 0xff)*scale;
+
+ if(r>255)r=255;
+ if(g>255)g=255;
+ if(b>255)b=255;
+ return (r<<16)|(g<<8)|b;
+}
+#if 0
+static int mix_color(int c1, float s1, int c2, float s2){
+ int r = ((c1 >> 16) & 0xff)*s1 + ((c2 >> 16) & 0xff)*s2;
+ int g = ((c1 >> 8) & 0xff)*s1 + ((c2 >> 8) & 0xff)*s2;
+ int b = (c1 & 0xff)*s1 + (c2 & 0xff)*s2;
+
+ if(r>255)r=255;
+ if(g>255)g=255;
+ if(b>255)b=255;
+ return (r<<16)|(g<<8)|b;
+}
+#endif
+BluebananaSlider::BluebananaSlider(BluebananaMain *plugin,
+ BluebananaWindow *gui,
+ int x,
+ int y,
+ int w,
+ int h,
+ float minval,
+ float maxval)
+ : BC_SubWindow(x, y, w, h){
+
+ this->plugin = plugin;
+ this->gui = gui;
+ this->minval = minval;
+ this->maxval = maxval;
+ histval=NULL;
+ histred=NULL;
+ histgreen=NULL;
+ histblue=NULL;
+ drag = 0;
+ light = -1;
+
+ int bg_c = get_resources()->get_bg_color();
+ int bg_r = ((bg_c >> 16) & 0xff);
+ int bg_g = ((bg_c >> 8) & 0xff);
+ int bg_b = (bg_c & 0xff);
+ int bg_v = (bg_r * 76 + bg_g *150 + bg_b *29) >> 8;
+
+ int dt_c = get_resources()->default_text_color;
+ int dt_r = ((dt_c >> 16) & 0xff);
+ int dt_g = ((dt_c >> 8) & 0xff);
+ int dt_b = (dt_c & 0xff);
+ int dt_v = (dt_r * 76 + dt_g *150 + dt_b *29) >> 8;
+
+ if(dt_v>bg_v){
+ /* light text, dark background */
+ int dg_c = get_resources()->default_text_color;
+ int dg_r = (((dg_c >> 16) & 0xff) + bg_r*2) /3;
+ int dg_g = (((dg_c >> 8) & 0xff) + bg_g*2) /3;
+ int dg_b = ((dg_c & 0xff) + bg_b*2) /3;
+ dg_c = (dg_r<<16) | (dg_g<<8) | dg_b;
+
+ active_bordercolor = get_resources()->default_text_color;
+ inactive_bordercolor = dg_c;
+ dimtextcolor = dg_c;
+ troughcolor = scale_color(dg_c,.5);
+ slidercolor = (bg_v > 0xa0 ? 0x606060 : 0xa0a0a0);
+ sliderlit = (bg_v > 0xa0 ? 0x909070 : 0xd0d0b0);
+ outline = 0x000000;
+ }else{
+ /* dark text, light background */
+ active_bordercolor = scale_color(bg_c,1.25);
+ inactive_bordercolor = scale_color(bg_c,1.01);
+ troughcolor = scale_color(bg_c,.8);
+ dimtextcolor = this->troughcolor;
+ sliderlit = scale_color(bg_c,1.75);
+ slidercolor = scale_color(this->sliderlit,.90);
+ outline = 0x606060;
+ }
+
+ needlecolor = 0xe07000;
+ needlelit = 0xff9000;
+ highlight = 0;
+ trough = NULL;
+ troughlines = Z4-Z1-1;
+ troughcols = w-CW-CW-ZR-ZL;
+}
+
+BluebananaSlider::~BluebananaSlider(){
+ if(trough) delete trough;
+ if(histval) delete[] histval;
+ if(histred) delete[] histred;
+ if(histgreen) delete[] histgreen;
+ if(histblue) delete[] histblue;
+}
+
+void BluebananaSlider::reposition(int x, int y, int w, int h){
+ BC_WindowBase::reposition_window(x,y,w,h);
+ if(trough) delete trough;
+ trough=NULL;
+ if(histval) delete[] histval;
+ histval=NULL;
+ if(histred) delete[] histred;
+ histred=NULL;
+ if(histgreen) delete[] histgreen;
+ histgreen=NULL;
+ if(histblue) delete[] histblue;
+ histblue=NULL;
+ troughlines = Z4-Z1-1;
+ troughcols = w-CW-CW-ZR-ZL;
+ update();
+}
+
+int BluebananaSlider::fraction_to_pixel(float input){
+ return (int)rint((input*(troughcols-1)+CW+ZL)+.001);
+}
+
+int BluebananaSlider::value_to_pixel(float input){
+ return fraction_to_pixel((input-minval)/(maxval-minval));
+}
+
+float BluebananaSlider::pixel_to_fraction(int pixel){
+ return (float)((pixel-CW-ZL)/(float)(troughcols-1));
+}
+
+float BluebananaSlider::pixel_to_value(int pixel){
+ float fraction=((pixel-CW-ZL)/(float)(troughcols-1));
+ return fraction*(maxval-minval)+minval;
+}
+#if 0
+static int inside_box(int cx, int cy, int x, int y, int w, int h){
+ return (cx>=x && cx<x+w && cy>=y && cy<y+h);
+}
+#endif
+static int inside_vline(int cx, int cy, int x, int y0, int y1){
+ if(cx==x){
+ if(cy>=y0 && cy<=y1)return 1;
+ if(cy>=y1 && cy<=y0)return 1;
+ }
+ return 0;
+}
+
+static int inside_hline(int cx, int cy, int x0, int x1, int y){
+ if(cy==y){
+ if(cx>=x0 && cx<=x1)return 1;
+ if(cx>=x1 && cx<=x0)return 1;
+ }
+ return 0;
+}
+
+int BluebananaSlider::in_midslider(int x, int cx,int cy){
+ int h = get_h();
+ int y = (Z4-Z1+h)/2;
+ int r = Z1-2;
+ if( (cx-x)*(cx-x) + (cy-y)*(cy-y) < r*r ) return 1;
+ return 0;
+}
+
+int BluebananaSlider::in_leftslider(int x,int cx, int cy){
+ int i;
+ int h = get_h();
+
+ if(inside_hline(cx,cy,x-1,x-Z1*2-1,Z4)) return 1;
+ for(i=1;i<Z1+1;i++){
+ if(inside_hline(cx,cy,x-(i*2),x-Z1*2-1,Z4-i)) return 1;
+ if(inside_hline(cx,cy,x-(i*2),x-Z1*2-1,Z4+i)) return 1;
+ }
+
+ if(inside_vline(cx,cy,x-Z1*2-2,Z4-Z1+1,Z4+Z1-1))return 1;
+ if(inside_vline(cx,cy,x,Z1+1,h-1))return 1;
+
+ return 0;
+}
+
+int BluebananaSlider::in_rightslider(int x, int cx, int cy){
+ int i;
+ int h = get_h();
+
+ if(inside_hline(cx,cy,x+1,x+Z1*2+1,Z4)) return 1;
+ for(i=1;i<Z1+1;i++){
+ if(inside_hline(cx,cy,x+(i*2),x+Z1*2+1,Z4-i)) return 1;
+ if(inside_hline(cx,cy,x+(i*2),x+Z1*2+1,Z4+i)) return 1;
+ }
+
+ if(inside_vline(cx,cy,x+Z1*2+2,Z4-Z1+1,Z4+Z1-1))return 1;
+ if(inside_vline(cx,cy,x,Z1+1,h-1))return 1;
+ return 0;
+}
+
+int BluebananaSlider::in_topslider(int x, int cx, int cy){
+ int i;
+ //int h = get_h();
+ if(inside_vline(cx,cy,x,Z1*2,1))return 1;
+ for(i=1;i<Z1+1;i++){
+ if(inside_vline(cx,cy,x+i,1,Z1*2-i*2+1))return 1;
+ if(inside_vline(cx,cy,x-i,1,Z1*2-i*2+1))return 1;
+ }
+ if(inside_hline(cx,cy,x-Z1+1,x+Z1-1,0)) return 1;
+ return 0;
+}
+
+int BluebananaSlider::in_overslider(int x,int cx, int cy){
+ //int i;
+ //int h = get_h();
+ //int y0 = 0;
+ //int y1 = Z1*2-1;
+ int w2 = CW;//Z1*2-1;
+ if(cy<=Z1 && cx>=x-w2 && cx<=x+w2) return 1;
+ return 0;
+}
+
+int BluebananaSlider::in_bottomslider(int x,int cx, int cy){
+ int i;
+ int h = get_h();
+
+ if(inside_vline(cx,cy,x,h-Z1*2-1,h-2))return 1;
+ for(i=1;i<Z1+1;i++){
+ if(inside_vline(cx,cy,x+i,h-2,h-Z1*2+i*2-2))return 1;
+ if(inside_vline(cx,cy,x-i,h-2,h-Z1*2+i*2-2))return 1;
+ }
+ if(inside_hline(cx,cy,x-Z1+1,x+Z1-1,h-1)) return 1;
+ return 0;
+}
+
+int BluebananaSlider::in_leftslider2(int x,int cx){
+ if(cx<=x+2 && cx>x-CW) return 1;
+ return 0;
+}
+
+int BluebananaSlider::in_rightslider2(int x,int cx){
+ if(cx<x+CW && cx>=x-2) return 1;
+ return 0;
+}
+
+int BluebananaSlider::in_midslider2(int x,int cx){
+ if(cx>x-CW/2 && cx<x+CW/2) return 1;
+ return 0;
+}
+
+int BluebananaSlider::in_overslider2(int x,int cx, int cy){
+ if(cx>x-CW/2 && cx<x+CW/2 && cy<=(Z1+Z4)/2) return 1;
+ return 0;
+}
+
+void BluebananaSlider::draw_midslider(int x,int lit){
+ //int i;
+ int h = get_h();
+ int y0 = Z4-Z1+2;
+ int y1 = h-2;
+
+ set_color(lit?sliderlit:slidercolor);
+ draw_disc(x-Z1+2,y0,Z1*2-3,y1-y0+1);
+
+ set_color(outline);
+ draw_circle(x-Z1+2,y0,Z1*2-3,y1-y0+1);
+}
+
+void BluebananaSlider::draw_leftslider(int x, int lit){
+ int i;
+ //int h = get_h();
+
+ set_color(lit?sliderlit:slidercolor);
+ draw_line(x-1,Z4,x-Z1*2-1,Z4);
+ for(i=1;i<Z1+1;i++){
+ draw_line(x-(i*2),Z4-i,x-Z1*2-1,Z4-i);
+ draw_line(x-(i*2),Z4+i,x-Z1*2-1,Z4+i);
+ }
+
+ set_color(outline);
+ draw_line(x-1,Z4,x-1,Z4);
+ draw_line(x-Z1*2-2,Z4-Z1+1,x-Z1*2-2,Z4+Z1-1);
+ for(i=1;i<Z1+1;i++){
+ draw_line(x-(i*2),Z4-i,x-(i*2)-1,Z4-i);
+ draw_line(x-(i*2),Z4+i,x-(i*2)-1,Z4+i);
+ }
+
+ set_color(lit?needlelit:needlecolor);
+ draw_line(x,Z4-Z1,x,Z4+Z1);
+}
+
+void BluebananaSlider::draw_rightslider(int x, int lit){
+ int i;
+ //int h = get_h();
+
+ set_color(lit?sliderlit:slidercolor);
+ draw_line(x+1,Z4,x+Z1*2+1,Z4);
+ for(i=1;i<Z1+1;i++){
+ draw_line(x+(i*2),Z4-i,x+Z1*2+1,Z4-i);
+ draw_line(x+(i*2),Z4+i,x+Z1*2+1,Z4+i);
+ }
+
+ set_color(outline);
+ draw_line(x+1,Z4,x+1,Z4);
+ draw_line(x+Z1*2+2,Z4-Z1+1,x+Z1*2+2,Z4+Z1-1);
+ for(i=1;i<Z1+1;i++){
+ draw_line(x+(i*2),Z4-i,x+(i*2)+1,Z4-i);
+ draw_line(x+(i*2),Z4+i,x+(i*2)+1,Z4+i);
+ }
+
+ set_color(lit?needlelit:needlecolor);
+ draw_line(x,Z4-Z1,x,Z4+Z1);
+}
+
+void BluebananaSlider::draw_topslider(int x, int lit){
+ int i;
+ //int h = get_h();
+
+ set_color(lit?sliderlit:slidercolor);
+ draw_line(x,Z1*2,x,1);
+ for(i=1;i<Z1+1;i++){
+ draw_line(x+i,1,x+i,Z1*2-i*2+1);
+ draw_line(x-i,1,x-i,Z1*2-i*2+1);
+ }
+
+ set_color(outline);
+ draw_line(x-Z1+1,0,x+Z1-1,0);
+ draw_line(x,Z1*2+1,x,Z1*2+1);
+ for(i=1;i<Z1+1;i++){
+ draw_line(x+i, Z1*2-i*2+1, x+i, Z1*2-i*2+2);
+ draw_line(x-i, Z1*2-i*2+1, x-i, Z1*2-i*2+2);
+ }
+}
+
+void BluebananaSlider::draw_bottomslider(int x, int lit){
+ int i;
+ int h = get_h();
+
+ set_color(lit?sliderlit:slidercolor);
+ draw_line(x,h-Z1*2-1,x,h-2);
+ for(i=1;i<Z1+1;i++){
+ draw_line(x+i,h-2,x+i,h-Z1*2+i*2-2);
+ draw_line(x-i,h-2,x-i,h-Z1*2+i*2-2);
+ }
+
+ set_color(outline);
+ draw_line(x-Z1+1,h-1,x+Z1-1,h-1);
+ draw_line(x,h-Z1*2-2,x,h-Z1*2-2);
+ for(i=1;i<Z1+1;i++){
+ draw_line(x+i,h-Z1*2+i*2-2,x+i,h-Z1*2+i*2-3);
+ draw_line(x-i,h-Z1*2+i*2-2,x-i,h-Z1*2+i*2-3);
+ }
+}
+
+void BluebananaSlider::draw_overslider(int x, int lit){
+ //int i;
+ //int h = get_h();
+ //int y0 = 0;
+ //int y1 = Z1*2-1;
+ int w2 = CW+1;
+
+ int bg_c = get_resources()->get_bg_color();
+ int bg_r = ((bg_c >> 16) & 0xff);
+ int bg_g = ((bg_c >> 8) & 0xff);
+ int bg_b = (bg_c & 0xff);
+ float del = lit ? 1. : .9;
+ set_color(((int)(bg_r*del) << 16) | ((int)(bg_g*del) << 8) | ((int)(bg_b*del)));
+ draw_box(x-w2+1,0,w2*2-2,Z1);
+ draw_box(x-w2,1,w2*2+1,Z1-2);
+
+ set_color(lit?sliderlit:slidercolor);
+ draw_box(x-w2+2,1,w2*2-3,Z1-2);
+ draw_box(x-w2+1,2,w2*2-1,Z1-4);
+
+ set_color(((int)(bg_r*del) << 16) | ((int)(bg_g*del) << 8) | ((int)(bg_b*del)));
+ draw_line(x,2,x,Z1-3);
+}
+
+int BluebananaSlider::button_release_event(){
+ if(is_event_win()){
+ if(drag>0) {
+ drag = 0;
+ update();
+ cursor_motion_event();
+ }
+ return 1;
+ }
+ return 0;
+}
+
+void BluebananaSlider::update(){
+ int w = get_w();
+ int h = get_h();
+ int bg_c = get_resources()->get_bg_color();
+ int bg_r = ((bg_c >> 16) & 0xff);
+ int bg_g = ((bg_c >> 8) & 0xff);
+ int bg_b = (bg_c & 0xff);
+ int b_c = highlight ? active_bordercolor : inactive_bordercolor;
+ int b_r = ((b_c >> 16) & 0xff);
+ int b_g = ((b_c >> 8) & 0xff);
+ int b_b = (b_c & 0xff);
+ int tb_c = troughcolor;
+ int tb_r = ((tb_c >> 16) & 0xff);
+ int tb_g = ((tb_c >> 8) & 0xff);
+ int tb_b = (tb_c & 0xff);
+
+ int ZH = Z4-Z1+1;
+ //int ZHC = Z4-ZC+1;
+
+ int i,j;
+
+ clear_box(0, 0, w, h);
+
+ /* trough shadow */
+ float del = .9;
+ int shadow_c = ((int)(bg_r*del) << 16) | ((int)(bg_g*del) << 8) | ((int)(bg_b*del));
+ set_color(shadow_c);
+ draw_box (0,Z1,w,ZH+2);
+ draw_box (1,Z1-1,w-2,ZH+4);
+
+ del = .8;
+ shadow_c = ((int)(bg_r*del) << 16) | ((int)(bg_g*del) << 8) | ((int)(bg_b*del));
+ set_color(shadow_c);
+ draw_box (1,Z1+1,w-2,ZH);
+ draw_box (2,Z1,w-4,ZH+2);
+
+ del = .7;
+ shadow_c = ((int)(bg_r*del) << 16) | ((int)(bg_g*del) << 8) | ((int)(bg_b*del));
+ set_color(shadow_c);
+ draw_box (2,Z1+2,w-4,ZH-2);
+ draw_box (3,Z1+1,w-6,ZH);
+
+ /* trough border */
+ set_color(b_c);
+ draw_box (1,Z1+1,w-4,ZH-2);
+ draw_box (2,Z1,w-6,ZH);
+
+ /* trough inner */
+ int ntw = troughcols;
+ int nth = troughlines;
+ int ntx = CW+ZL;
+ int nty = Z1+1;
+
+ if(!trough){
+ trough = new VFrame(ntw,nth,BC_RGBA8888);
+ }
+
+ if(!trough){
+ fprintf(stderr,_("Bluebanana: Unable to create Frame for slider\n"));
+ }else{
+ unsigned char *data = trough->get_data();
+ long bpr = trough->get_bytes_per_line();
+ float ha = 1.;
+ if(!highlight){
+ ha*=.25;
+ tb_r = bg_r;
+ tb_g = bg_g;
+ tb_b = bg_b;
+ }
+
+ if(histval){ // trough is a histogram and has data
+ long bpp = trough->get_bytes_per_pixel();
+ float rr,gg,bb,aa;
+
+ for(i=0;i<ntw;i++){
+
+ unsigned char *row = data;
+ float y = nth-histval[i];
+ float y0 = i>0?nth-histval[i-1]:y;
+ float y1 = i+1<ntw?nth-histval[i+1]:y;
+ float yp = MIN(y,MIN(y0+1,y1+1));
+ float y3 = (y0+y+y1)*.333f;
+ float r,g,b,a;
+
+ trough_color((i+.5f)/ntw,0.f,rr,gg,bb,aa);
+ rr*=255;
+ gg*=255;
+ bb*=255;
+ rr = CLAMP((rr+b_r*3)/4,0,255);
+ gg = CLAMP((gg+b_g*3)/4,0,255);
+ bb = CLAMP((bb+b_b*3)/4,0,255);
+
+ if(histred){
+ r=histred[i];
+ g=histgreen[i];
+ b=histblue[i];
+ }else{
+ trough_color((i+.5)/ntw,0,r,g,b,a);
+ r=CLAMP(r,0,255);
+ g=CLAMP(g,0,255);
+ b=CLAMP(b,0,255);
+ }
+
+ for(j=0;j<yp-1 && j<nth;j++){
+ row[0] = tb_r;
+ row[1] = tb_g;
+ row[2] = tb_b;
+ row[3] = 0xff;
+ row+=bpr;
+ }
+
+ a=.75*ha;
+ for(;j<y && j<nth;j++){
+ row[0] = rint(rr*a + tb_r*(1-a));
+ row[1] = rint(gg*a + tb_g*(1-a));
+ row[2] = rint(bb*a + tb_b*(1-a));
+ row[3] = 0xff;
+ row+=bpr;
+ }
+
+ a=ha;
+ for(;j<nth;j++){
+ float a = CLAMP(1. - .3*(float)(j-y3)/(nth-y3+1),0.f,1.f)*ha;
+ row[0] = rint(r*a*255.f + tb_r*(1-a));
+ row[1] = rint(g*a*255.f + tb_g*(1-a));
+ row[2] = rint(b*a*255.f + tb_b*(1-a));
+ row[3] = 0xff;
+ row+=bpr;
+ }
+
+ data+=bpp;
+ }
+ }else{
+ for(i=0;i<ntw;i++){
+ unsigned char *row = data + i*trough->get_bytes_per_pixel();
+ for(j=0;j<nth;j++){
+ float r,g,b,a;
+ trough_color((i+.5f)/ntw,(j+.5)/nth,r,g,b,a);
+ r=CLAMP(r,0,255);
+ g=CLAMP(g,0,255);
+ b=CLAMP(b,0,255);
+
+ a*=ha;
+ row[0] = rint(r*a*255 + tb_r*(1-a));
+ row[1] = rint(g*a*255 + tb_g*(1-a));
+ row[2] = rint(b*a*255 + tb_b*(1-a));
+ row[3] = 0xff;
+ row+=bpr;
+ }
+ }
+ }
+ draw_vframe(trough,ntx,nty);
+ }
+}
+
+// quick/dirty unnormalized linear resample from native -> display size
+static void resample_histogram(float *raw, float *raw_red, float *raw_green, float *raw_blue,
+ float *out, float *out_red, float *out_green, float *out_blue,
+ int raw_n, int raw_off, int out_n, int out_start, int out_end){
+ float coverage = (float)raw_n/out_n;
+ float scale = coverage;
+ if(coverage<1.)coverage=1.;
+ float icoverage = 1./coverage;
+
+ float raw_center = out_start*scale+raw_off;
+ float raw_start = raw_center-coverage;
+ float raw_end = raw_center+coverage;
+
+ for(int i=out_start; i<out_end; i++){
+ int j = raw_start+1;
+ int e = raw_end;
+ if(j<0)j=0;
+ if(e>HISTSIZE)e=HISTSIZE;
+ //int jj=j;
+ float k = (j-raw_start)*icoverage-1.f;
+ float a = 0;
+
+ for(; j<=e; j++){
+ float ik = 1.-fabs(k);
+ a += raw[j]*ik;
+ k += icoverage;
+ }
+ out[i] = a;
+ raw_start += scale;
+ raw_end += scale;
+ }
+
+ if(raw_red){
+ coverage = (float)raw_n/out_n;
+ scale = coverage;
+ if(coverage<(1<<HRGBSHIFT))coverage=(1<<HRGBSHIFT);
+ icoverage = 1./coverage;
+
+ raw_center = out_start*scale+raw_off;
+ raw_start = raw_center-coverage;
+ raw_end = raw_center+coverage;
+
+ for(int i=out_start; i<out_end; i++){
+ int j = raw_start+1;
+ int e = raw_end;
+ if(j<0)j=0;
+ if(e>HISTSIZE)e=HISTSIZE;
+ //int jj=j;
+ float k = (j-raw_start)*icoverage-1.f;
+ float r=0.f, g=0.f, b=0.f, a=0.f;
+ for(; j<=e; j++){
+ float ik = 1.-fabs(k);
+ int sj = (j>>HRGBSHIFT);
+ int sjs = sj<<HRGBSHIFT;
+
+#if (HRGBSHIFT==0)
+ a += raw[sjs]*ik;
+#endif
+#if (HRGBSHIFT==1)
+ a += (raw[sjs] +
+ raw[sjs+1])*ik;
+#endif
+#if (HRGBSHIFT==2)
+ a += (raw[sjs] +
+ raw[sjs+1] +
+ raw[sjs+2] +
+ raw[sjs+3])*ik;
+#endif
+#if (HRGBSHIFT==3)
+ a += (raw[sjs] +
+ raw[sjs+1] +
+ raw[sjs+2] +
+ raw[sjs+3] +
+ raw[sjs+4] +
+ raw[sjs+5] +
+ raw[sjs+6] +
+ raw[sjs+7])*ik;
+#endif
+ r += raw_red[sj]*ik;
+ g += raw_green[sj]*ik;
+ b += raw_blue[sj]*ik;
+ k += icoverage;
+ }
+
+ a = a?1.f/a:0;
+ out_red[i] = CLAMP(r*a,0.f,1.f);
+ out_green[i] = CLAMP(g*a,0.f,1.f);
+ out_blue[i] = CLAMP(b*a,0.f,1.f);
+ raw_start += scale;
+ raw_end += scale;
+ }
+ }
+}
+
+void BluebananaSlider::update_histogram(float *raw, float *red, float *green, float *blue, int n){
+ int i;
+ int h = troughlines;
+ int w = troughcols;
+ float il2n = 1./log2(n);
+
+ if(!histval)
+ histval = new float[w];
+
+ if(!histred && red){
+ histred = new float[w];
+ histgreen = new float[w];
+ histblue = new float[w];
+ }
+
+ /* resample center */
+ resample_histogram(raw, red, green, blue, histval, histred, histgreen, histblue,
+ HISTSIZE, 0, w, 0, w);
+
+ /* select value normalization */
+ for(i=0;i<w;i++){
+ if(histval[i]<=.0001f){
+ histval[i]=-2;
+ }else{
+ float val = log2(histval[i])*il2n;
+ val = pow(val<0?0:val,.75)*h;
+ if(val<0)val=0;
+ if(val>h)val=h;
+ histval[i]=val;
+ }
+ }
+ render();
+}
+
+// ---------------------------- Single ----------------------------------
+
+BluebananaSliderSingle::BluebananaSliderSingle(BluebananaMain *plugin,
+ BluebananaWindow *gui,
+ int x,
+ int y,
+ int w,
+ int h,
+ float minval,
+ float maxval)
+ : BluebananaSlider(plugin,gui,x,y,w,h,minval,maxval){
+ val = (minval+maxval)/2;
+ increment = 1;
+}
+
+int BluebananaSliderSingle::button_press_event(){
+ if(is_event_win() && cursor_inside()){
+ //int min;
+ //int max;
+ int cx = get_cursor_x();
+
+ gui->deactivate();
+
+ if(get_buttonpress() == 4){
+ set_val(val - increment);
+ return 1;
+ }else if(get_buttonpress() == 5){
+ set_val(val + increment);
+ return 1;
+ }
+
+ switch(light){
+ case 0:
+ xoff = cx-value_to_pixel(val);
+ break;
+ default:
+ return 1;
+ }
+
+ drag = 1;
+ update();
+ return 1;
+ }
+ return 0;
+}
+
+int BluebananaSliderSingle::cursor_motion_event(){
+ int cx = get_cursor_x();
+ //int cy = get_cursor_y();
+
+ if(drag){
+ switch(light){
+ case 0:
+ set_val(pixel_to_value(cx - xoff));
+ break;
+ default:
+ drag = 0;
+ light = -1;
+ update();
+ break;
+ }
+ return 1;
+ }else{
+ if(is_event_win() && cursor_inside()){
+
+ if(in_midslider2(value_to_pixel(val),cx)){
+ if(light!=0){
+ light = 0;
+ update();
+ }
+ }else{
+ if(light!=-1){
+ light = -1;
+ update();
+ }
+ }
+ return 1;
+ }else{
+ if(light!=-1){
+ light = -1;
+ update();
+ }
+ }
+ }
+ return 0;
+}
+
+void BluebananaSliderSingle::set_val(float v){
+ val=v;
+ if(val<minval)val=minval;
+ if(val>maxval)val=maxval;
+ handle_event();
+ update();
+}
+
+void BluebananaSliderSingle::update(){
+ BluebananaSlider::update();
+ draw_bottomslider(value_to_pixel(val),light==0);
+ flash();
+ flush();
+}
+
+// ---------------------------- Bracket ----------------------------------
+
+BluebananaSliderBracket::BluebananaSliderBracket(BluebananaMain *plugin,
+ BluebananaWindow *gui,
+ int x,
+ int y,
+ int w,
+ int h,
+ float minval,
+ float maxval)
+ : BluebananaSlider(plugin,gui,x,y,w,h,minval,maxval){
+ loval = minval;
+ midval = (minval+maxval)/2;
+ hival = maxval;
+ overval = minval;
+ increment = 1;
+}
+
+int BluebananaSliderBracket::button_press_event(){
+ if(is_event_win() && cursor_inside()){
+ //int min;
+ //int max;
+ int cx = get_cursor_x();
+
+ gui->deactivate();
+
+ if(shift_down()){
+ /* narrow/widen range */
+ if(get_buttonpress() == 4){
+ set_delta(increment*2);
+ return 1;
+ }else if(get_buttonpress() == 5){
+ set_delta(-increment*2);
+ return 1;
+ }
+ }else if (ctrl_down()){
+ /* shift all vals up/down */
+ if(get_buttonpress() == 4){
+ set_mid(midval-increment);
+ return 1;
+ }else if(get_buttonpress() == 5){
+ set_mid(midval+increment);
+ return 1;
+ }
+ }else{
+ /* increase/decrease overlap */
+ if(get_buttonpress() == 4){
+ set_over(overval-1);
+ return 1;
+ }else if(get_buttonpress() == 5){
+ set_over(overval+1);
+ return 1;
+ }
+ }
+
+ switch(light){
+ case 0:
+ xoff = cx-value_to_pixel(loval);
+ break;
+ case 1:
+ xoff = cx-value_to_pixel(midval);
+ break;
+ case 2:
+ xoff = cx-value_to_pixel(hival);
+ break;
+ case 3:
+ xoff = cx-value_to_pixel(overval);
+ break;
+ default:
+ return 1;
+ }
+
+ drag = 1;
+ update();
+ return 1;
+ }
+ return 0;
+}
+
+int BluebananaSliderBracket::cursor_motion_event(){
+ int cx = get_cursor_x();
+ int cy = get_cursor_y();
+
+ if(drag){
+ switch(light){
+ case 0:
+ set_lo(pixel_to_value(cx - xoff));
+ break;
+ case 1:
+ set_mid(pixel_to_value(cx - xoff));
+ break;
+ case 2:
+ set_hi(pixel_to_value(cx - xoff));
+ break;
+ case 3:
+ set_over(pixel_to_value(cx - xoff));
+ break;
+ default:
+ drag = 0;
+ light = -1;
+ update();
+ break;
+ }
+ return 1;
+ }else{
+ if(is_event_win() && cursor_inside()){
+ if(in_overslider(value_to_pixel(overval),cx,cy)){
+ if(light!=3){
+ light = 3;
+ update();
+ }
+ }else if(in_midslider(value_to_pixel(midval),cx,cy)){
+ if(light!=1){
+ light = 1;
+ update();
+ }
+ }else if(in_leftslider(value_to_pixel(loval),cx,cy)){
+ if(light!=0){
+ light = 0;
+ update();
+ }
+ }else if(in_rightslider(value_to_pixel(hival),cx,cy)){
+ if(light!=2){
+ light = 2;
+ update();
+ }
+ }else if(in_midslider2(value_to_pixel(midval),cx)){
+ if(light!=1){
+ light = 1;
+ update();
+ }
+ }else if(in_rightslider2(value_to_pixel(hival),cx)){
+ if(light!=2){
+ light = 2;
+ update();
+ }
+ }else if(in_leftslider2(value_to_pixel(loval),cx)){
+ if(light!=0){
+ light = 0;
+ update();
+ }
+ }else if(in_overslider2(value_to_pixel(overval),cx,cy)){
+ if(light!=3){
+ light = 3;
+ update();
+ }
+ }else{
+ if(light!=-1){
+ light = -1;
+ update();
+ }
+ }
+ return 1;
+ }else{
+ if(light!=-1){
+ light = -1;
+ update();
+ }
+ }
+ }
+ return 0;
+}
+
+void BluebananaSliderBracket::set_lo(float val){
+ if(val<minval)val=minval;
+ if(val>maxval)val=maxval;
+ if(val > hival) val=hival;
+ loval=val;
+
+ if(hival<loval)hival+=(maxval-minval);
+ if(midval<loval)midval+=(maxval-minval);
+ midval = (hival+loval)/2.;
+ if(hival>maxval)hival-=(maxval-minval);
+ if(midval>maxval)midval-=(maxval-minval);
+ if(loval>maxval)loval-=(maxval-minval);
+ if(hival<minval)hival+=(maxval-minval);
+ if(midval<minval)midval+=(maxval-minval);
+ if(loval<minval)loval+=(maxval-minval);
+ handle_event();
+ update();
+}
+
+void BluebananaSliderBracket::set_mid(float val){
+ //float oldmid=midval;
+ if(val<minval)val=minval;
+ if(val>maxval)val=maxval;
+ midval=val;
+
+ float delta = (hival+loval)/2.;
+ hival+=midval-delta;
+ loval+=midval-delta;
+ if(hival>maxval){
+ loval += maxval-hival;
+ midval += maxval-hival;
+ hival = maxval;
+ }
+ if(loval<minval){
+ hival-=loval;
+ midval-=loval;
+ loval=minval;
+ }
+ handle_event();
+ update();
+}
+
+void BluebananaSliderBracket::set_hi(float val){
+ if(val<minval)val=minval;
+ if(val>maxval)val=maxval;
+ if(val<loval)val=loval;
+ hival=val;
+
+ if(loval>hival)loval-=(maxval-minval);
+ if(midval>hival)midval-=(maxval-minval);
+ midval=(hival+loval)/2.;
+ if(hival>maxval)hival-=(maxval-minval);
+ if(midval>maxval)midval-=(maxval-minval);
+ if(loval>maxval)loval-=(maxval-minval);
+ if(hival<minval)hival+=(maxval-minval);
+ if(midval<minval)midval+=(maxval-minval);
+ if(loval<minval)loval+=(maxval-minval);
+
+ handle_event();
+ update();
+}
+
+void BluebananaSliderBracket::set_delta(float incr){
+ float delta = (hival-loval)+incr;
+ if(delta<minval)delta=minval;
+ if(delta>maxval)delta=maxval;
+ loval = midval-delta/2;
+ hival = loval+delta;
+
+ if(loval<minval){
+ hival-=loval;
+ midval-=loval;
+ loval=minval;
+ }
+ if(hival>maxval){
+ loval-=(hival-maxval);
+ midval-=(hival-maxval);
+ hival=maxval;
+ }
+ handle_event();
+ update();
+}
+
+void BluebananaSliderBracket::set_over(float val){
+ if(val<minval)val=minval;
+ if(val>maxval)val=maxval;
+ overval=val;
+ handle_event();
+ update();
+}
+
+
+void BluebananaSliderBracket::update(){
+ BluebananaSlider::update();
+ draw_overslider(value_to_pixel(overval),light==3);
+ draw_leftslider(value_to_pixel(loval),light==0);
+ draw_rightslider(value_to_pixel(hival),light==2);
+ draw_midslider(value_to_pixel(midval),light==1);
+ flash();
+ flush();
+}
+
+// ----------------------- Circular Bracket -----------------------------
+
+BluebananaSliderCircular::BluebananaSliderCircular(BluebananaMain *plugin,
+ BluebananaWindow *gui,
+ int x,
+ int y,
+ int w,
+ int h,
+ float minval,
+ float maxval)
+ : BluebananaSliderBracket(plugin,gui,x,y,w,h,minval,maxval){}
+
+void BluebananaSliderCircular::set_lo(float val){
+ if(val<minval)val=minval;
+ if(val>maxval)val=maxval;
+ loval=val;
+
+ if(hival<loval)hival+=(maxval-minval);
+ if(midval<loval)midval+=(maxval-minval);
+ midval = (hival+loval)/2.;
+ if(hival>maxval)hival-=(maxval-minval);
+ if(midval>maxval)midval-=(maxval-minval);
+ if(loval>maxval)loval-=(maxval-minval);
+ if(hival<minval)hival+=(maxval-minval);
+ if(midval<minval)midval+=(maxval-minval);
+ if(loval<minval)loval+=(maxval-minval);
+
+ handle_event();
+ update();
+}
+
+void BluebananaSliderCircular::set_mid(float val){
+ float oldmid=midval;
+ if(val<minval)val=minval;
+ if(val>maxval)val=maxval;
+ midval=val;
+ if(hival<oldmid)hival+=(maxval-minval);
+ if(loval>oldmid)loval-=(maxval-minval);
+ float delta = hival-loval;
+ loval = midval-delta/2;
+ hival = loval+delta;
+ if(hival>maxval)hival-=(maxval-minval);
+ if(loval>maxval)loval-=(maxval-minval);
+ if(hival<minval)hival+=(maxval-minval);
+ if(loval<minval)loval+=(maxval-minval);
+ handle_event();
+ update();
+}
+
+void BluebananaSliderCircular::set_hi(float val){
+ if(val<minval)val=minval;
+ if(val>maxval)val=maxval;
+ hival=val;
+ if(loval>hival)loval-=(maxval-minval);
+ if(midval>hival)midval-=(maxval-minval);
+ midval = (hival+loval)/2.;
+ if(hival>maxval)hival-=(maxval-minval);
+ if(midval>maxval)midval-=(maxval-minval);
+ if(loval>maxval)loval-=(maxval-minval);
+ if(hival<minval)hival+=(maxval-minval);
+ if(midval<minval)midval+=(maxval-minval);
+ if(loval<minval)loval+=(maxval-minval);
+ handle_event();
+ update();
+}
+
+void BluebananaSliderCircular::set_delta(float incr){
+ if(hival<midval)hival+=(maxval-minval);
+ if(loval>midval)loval-=(maxval-minval);
+
+ float delta = (hival-loval)+incr;
+ if(delta<minval)delta=minval;
+ if(delta>maxval)delta=maxval;
+ loval = midval-delta/2;
+ hival = loval+delta;
+
+ if(hival>maxval)hival-=(maxval-minval);
+ if(loval>maxval)loval-=(maxval-minval);
+ if(hival<minval)hival+=(maxval-minval);
+ if(loval<minval)loval+=(maxval-minval);
+ handle_event();
+ update();
+}
+
+void BluebananaSliderCircular::update(){
+ BluebananaSliderBracket::update();
+ flash();
+ flush();
+}
+
+// -------------------------- In + Out + Gamma --------------------------------
+
+#define mG2 (2.f-2.f*MIN_GAMMA)
+#define MG2 (2.f*MAX_GAMMA-2.f)
+
+float BluebananaSliderChannel::pixel_to_gamma(float pixel){
+ float unit = (1.-pixel_to_fraction(pixel)-FRAC0)/(FRAC100-FRAC0);
+ return (unit > .5f ?
+ (1.f-unit) * mG2 + MIN_GAMMA :
+ (.5f-unit) * MG2 + 1.f );
+}
+
+float BluebananaSliderChannel::gamma_to_pixel(float gamma){
+ float fraction =
+ gamma<1 ? 1.f - (gamma-MIN_GAMMA) / mG2 :
+ .5f - (gamma-1.f) / MG2 ;
+ return fraction_to_pixel((1.-fraction) * (FRAC100-FRAC0) + FRAC0);
+}
+
+float BluebananaSliderChannel::pixel_to_value(float pixel){
+ if(pixel<t_x1){
+ return (t_x0-pixel)/t_w01*MIN_HISTBRACKET+MIN_HISTBRACKET;
+ }else if (pixel<t_x2){
+ return (pixel-t_x1)/t_w12*100;
+ }else{
+ return (pixel-t_x2)/t_w23*(MAX_HISTBRACKET-100)+100;
+ }
+}
+
+float BluebananaSliderChannel::value_to_pixel(float val){
+ if(val<0){
+ return rint(MIN_HISTBRACKET-val)/MIN_HISTBRACKET*t_w01+t_x0;
+ }else if(val<100){
+ return rint(val/100.*t_w12+t_x1+.01);
+ }else{
+ return rint((val-100)/(MAX_HISTBRACKET-100.)*t_w23+t_x2);
+ }
+}
+
+BluebananaSliderChannel::BluebananaSliderChannel(BluebananaMain *plugin,
+ BluebananaWindow *gui,
+ int x,
+ int y,
+ int w,
+ int h)
+ : BluebananaSlider(plugin,gui,x,y,w,h,0,100){
+ loval = 0;
+ gamma = 1.;
+ hival = 100.;
+}
+
+BluebananaSliderChannel::~BluebananaSliderChannel(){}
+
+int BluebananaSliderChannel::button_press_event(){
+ if(is_event_win() && cursor_inside()){
+ //int min;
+ //int max;
+ int cx = get_cursor_x();
+ //int cy = get_cursor_y();
+
+ gui->deactivate();
+
+ if(shift_down()){
+ /* narrow/widen range */
+ if(get_buttonpress() == 4){
+ set_range(hival-loval-2);
+ return 1;
+ }else if(get_buttonpress() == 5){
+ if(loval<hival){
+ set_range(hival-loval+2);
+ }
+ return 1;
+ }
+ }else if (ctrl_down()){
+ /* shift all vals up/down */
+ if(get_buttonpress() == 4){
+ set_mid((loval+hival)/2+1);
+ return 1;
+ }else if(get_buttonpress() == 5){
+ set_mid((loval+hival)/2-1);
+ return 1;
+ }
+ }else{
+ /* increase/decrease gamma */
+ if(get_buttonpress() == 4){
+ set_gamma(gamma-.01);
+ return 1;
+ }else if(get_buttonpress() == 5){
+ set_gamma(gamma+.01);
+ return 1;
+ }
+ }
+
+ switch(light){
+ case 0:
+ xoff = cx-value_to_pixel(loval);
+ break;
+ case 1:
+ xoff = cx-value_to_pixel((loval+hival)/2);
+ break;
+ case 2:
+ xoff = cx-value_to_pixel(hival);
+ break;
+ case 3:
+ xoff = cx-gamma_to_pixel(gamma);
+ break;
+ default:
+ return 1;
+ }
+
+ drag = 1;
+ update();
+ return 1;
+ }
+ return 0;
+}
+
+int BluebananaSliderChannel::cursor_motion_event(){
+ int cx = get_cursor_x();
+ int cy = get_cursor_y();
+
+ if(drag){
+ switch(light){
+ case 0:
+ set_lo(pixel_to_value(cx - xoff));
+ break;
+ case 1:
+ set_mid(pixel_to_value(cx - xoff));
+ break;
+ case 2:
+ set_hi(pixel_to_value(cx - xoff));
+ break;
+ case 3:
+ set_gamma(pixel_to_gamma(cx - xoff));
+ break;
+ default:
+ drag = 0;
+ light = -1;
+ update();
+ break;
+ }
+ return 1;
+ }else{
+ if(is_event_win() && cursor_inside()){
+ if(in_topslider(gamma_to_pixel(gamma),cx,cy)){
+ if(light!=3){
+ light = 3;
+ update();
+ }
+ }else if(in_midslider(value_to_pixel((loval+hival)/2),cx,cy)){
+ if(light!=1){
+ light = 1;
+ update();
+ }
+ }else if(in_leftslider(value_to_pixel(loval),cx,cy)){
+ if(light!=0){
+ light = 0;
+ update();
+ }
+ }else if(in_rightslider(value_to_pixel(hival),cx,cy)){
+ if(light!=2){
+ light = 2;
+ update();
+ }
+ }else if(in_bottomslider(value_to_pixel(hival),cx,cy)){
+ if(light!=2){
+ light = 2;
+ update();
+ }
+ }else if(in_bottomslider(value_to_pixel(loval),cx,cy)){
+ if(light!=0){
+ light = 0;
+ update();
+ }
+ }else if(in_midslider2(value_to_pixel((loval+hival)/2),cx)){
+ if(light!=1){
+ light = 1;
+ update();
+ }
+ }else if(in_overslider2(gamma_to_pixel(gamma),cx,cy)){
+ if(light!=3){
+ light = 3;
+ update();
+ }
+ }else{
+ if(light!=-1){
+ light = -1;
+ update();
+ }
+ }
+ return 1;
+ }else{
+ if(light!=-1){
+ light = -1;
+ update();
+ }
+ }
+ }
+ return 0;
+}
+
+void BluebananaSliderChannel::set_lo(float v){
+ if(v>hival)v=hival;
+ if(v<-100)v=-100;
+ if(v>100)v=100;
+ loval=rint(v);
+ handle_event();
+ update();
+}
+
+void BluebananaSliderChannel::set_hi(float v){
+ if(v<loval)v=loval;
+ if(v<0)v=0;
+ if(v>200)v=200;
+ hival=rint(v);
+ handle_event();
+ update();
+}
+
+void BluebananaSliderChannel::set_mid(float v){
+ float mid = (hival+loval)*.5;
+ float range = hival-loval;
+ float del = v-mid;
+
+ if(hival+del>200)del=200-hival;
+ if(hival+del<0)del=0-hival;
+ if(loval+del>100)del=100-loval;
+ if(loval+del<-100)del=-100-loval;
+
+ loval+=rint(del);
+ hival=loval+rint(range);
+ handle_event();
+ update();
+}
+
+void BluebananaSliderChannel::set_range(float v){
+ //float mid = (hival+loval)*.5;
+ float range = hival-loval;
+
+ if(v>200)v=200;
+ if(v<0)v=0;
+
+ float del = (v-range)/2;
+
+ if(hival+del>200)del=200-hival;
+ if(hival+del<0)del=0-hival;
+
+ if(loval-del>100)del=loval-100;
+ if(loval-del<-100)del=loval+100;
+
+ loval-=rint(del);
+ hival=rint(loval+v);
+ handle_event();
+ update();
+}
+
+void BluebananaSliderChannel::set_gamma(float v){
+ if(v>MAX_GAMMA)v=MAX_GAMMA;
+ if(v<MIN_GAMMA)v=MIN_GAMMA;
+ gamma=v;
+ handle_event();
+ update();
+}
+
+void BluebananaSliderChannel::update(){
+ int w = get_w();
+ int h = get_h();
+ int bg_c = get_resources()->get_bg_color();
+ int bg_r = ((bg_c >> 16) & 0xff);
+ int bg_g = ((bg_c >> 8) & 0xff);
+ int bg_b = (bg_c & 0xff);
+ int b_c = highlight ? active_bordercolor : inactive_bordercolor;
+ int b_r = ((b_c >> 16) & 0xff);
+ int b_g = ((b_c >> 8) & 0xff);
+ int b_b = (b_c & 0xff);
+ int tb_c = troughcolor;
+ int tb_r = ((tb_c >> 16) & 0xff);
+ int tb_g = ((tb_c >> 8) & 0xff);
+ int tb_b = (tb_c & 0xff);
+
+ int ZH = Z4-Z1+1;
+ //int ZHC = Z4-ZC+1;
+
+ int i,j;
+
+ t_x0 = fraction_to_pixel(0);
+ t_x1 = fraction_to_pixel(FRAC0);
+ t_x2 = fraction_to_pixel(FRAC100);
+ t_x3 = fraction_to_pixel(1.);
+ t_w01 = t_x1-t_x0;
+ t_w12 = t_x2-t_x1;
+ t_w23 = t_x3-t_x2;
+
+
+ int ntw = troughcols-6;
+ int nth = troughlines;
+ int ntx = t_x0;
+ int nty = Z1+1;
+
+ clear_box(0, 0, w, h);
+
+ /* trough shadow */
+
+ /* w+4 h+4 x-1 y-1 */
+ float del = .9;
+ int shadow_c = ((int)(bg_r*del) << 16) | ((int)(bg_g*del) << 8) | ((int)(bg_b*del));
+ set_color(shadow_c);
+ draw_box (0,Z1,t_x1+3,ZH+2);
+ draw_box (1,Z1-1,t_x1+1,ZH+4);
+ draw_box (t_x1,Z1,t_w12+3,ZH+2);
+ draw_box (t_x1+1,Z1-1,t_w12+1,ZH+4);
+ draw_box (t_x2,Z1,w-t_x2,ZH-2+2);
+ draw_box (t_x2+1,Z1-1,w-t_x2-2,ZH+4);
+
+ /* w+2 h+2 x y */
+ del = .8;
+ shadow_c = ((int)(bg_r*del) << 16) | ((int)(bg_g*del) << 8) | ((int)(bg_b*del));
+ set_color(shadow_c);
+ draw_box (1,Z1+1,t_x1+1,ZH);
+ draw_box (2,Z1,t_x1-1,ZH+2);
+ draw_box (t_x1+1,Z1+1,t_w12+1,ZH);
+ draw_box (t_x1+2,Z1,t_w12-1,ZH+2);
+ draw_box (t_x2+1,Z1+1,w-t_x2-2,ZH);
+ draw_box (t_x2+2,Z1,w-t_x2-4,ZH+2);
+
+ /* w h x+1 y+1 */
+ del = .7;
+ shadow_c = ((int)(bg_r*del) << 16) | ((int)(bg_g*del) << 8) | ((int)(bg_b*del));
+ set_color(shadow_c);
+ draw_box (2,Z1+2,t_x1-1,ZH-2);
+ draw_box (3,Z1+1,t_x1-3,ZH);
+ draw_box (t_x1+2,Z1+2,t_w12-1,ZH-2);
+ draw_box (t_x1+3,Z1+1,t_w12-3,ZH);
+ draw_box (t_x2+2,Z1+2,w-t_x2-4,ZH-2);
+ draw_box (t_x2+3,Z1+1,w-t_x2-6,ZH);
+
+ /* trough border */
+ set_color(b_c);
+ draw_box (1,Z1+1,t_x1-1,ZH-2);
+ draw_box (2,Z1,t_x1-3,ZH);
+ draw_box (t_x1+1,Z1+1,t_w12-1,ZH-2);
+ draw_box (t_x1+2,Z1,t_w12-3,ZH);
+ draw_box (t_x2+1,Z1+1,w-t_x2-4,ZH-2);
+ draw_box (t_x2+2,Z1,w-t_x2-6,ZH);
+
+ /* trough inner */
+ /* the trough in the three-part hist slider is slightly smaller than
+ the full slider range, and cut into three sections */
+ if(!trough){
+ trough = new VFrame(ntw,nth,BC_RGBA8888);
+ }
+
+ if(!trough){
+ fprintf(stderr,_("Bluebanana: Unable to create Frame for slider\n"));
+ }else{
+ unsigned char *data = trough->get_data();
+ float ha = 1.;
+ long bpp = trough->get_bytes_per_pixel();
+ long bpr = trough->get_bytes_per_line();
+ float r,g,b,a,rr,gg,bb;
+
+ if(!highlight){
+ ha*=.25;
+ tb_r = bg_r;
+ tb_g = bg_g;
+ tb_b = bg_b;
+ }
+
+ if(!histval){
+
+ for(i=0;i<ntw;i++){
+ unsigned char *row = data;
+ for(j=0;j<nth;j++){
+ row[0] = tb_r;
+ row[1] = tb_g;
+ row[2] = tb_b;
+ row[3] = 0xff;
+ row+=bpr;
+ }
+ }
+
+ }else{
+
+ trough_color(1.,rr,gg,bb);
+ rr*=255;
+ gg*=255;
+ bb*=255;
+ rr = CLAMP((rr+b_r*3)/4,0,255);
+ gg = CLAMP((gg+b_g*3)/4,0,255);
+ bb = CLAMP((bb+b_b*3)/4,0,255);
+
+ for(i=0;i<ntw;i++){
+ unsigned char *row = data;
+ float y = nth-histval[i];
+ float y0 = i>0?nth-histval[i-1]:y;
+ float y1 = i+1<ntw?nth-histval[i+1]:y;
+ float yp = MIN(y,MIN(y0+1,y1+1));
+ float y3 = (y0+y+y1)*.333f;
+
+ if(histred){
+ r=histred[i];
+ g=histgreen[i];
+ b=histblue[i];
+ }else{
+ float val = (i < t_w01-1 ?
+ ((MIN_HISTBRACKET/100.f) - i/(t_w01-1.f)*(MIN_HISTBRACKET/100.f)) :
+ (i<t_w01+t_w12-4 ?
+ ((i - t_w01 + 1) / (t_w12-4.f)) :
+ ((i - t_w01 - t_w12 + 5) / (t_w23-1.f)*((MAX_HISTBRACKET/100.f)-1.f)+1.f)));
+
+ trough_color(val,r,g,b);
+ r=CLAMP(r,0,255);
+ g=CLAMP(g,0,255);
+ b=CLAMP(b,0,255);
+
+ }
+
+ for(j=0;j<yp-1 && j<nth;j++){
+ row[0] = tb_r;
+ row[1] = tb_g;
+ row[2] = tb_b;
+ row[3] = 0xff;
+ row+=bpr;
+ }
+
+ a=.75*ha;
+ for(;j<y && j<nth;j++){
+ row[0] = rint(rr*a + tb_r*(1-a));
+ row[1] = rint(gg*a + tb_g*(1-a));
+ row[2] = rint(bb*a + tb_b*(1-a));
+ row[3] = 0xff;
+ row+=bpr;
+ }
+
+ a=ha;
+ for(;j<nth;j++){
+ float a = CLAMP(1. - .3*(float)(j-y3)/(nth-y3+1),0.f,1.f)*ha;
+ row[0] = rint(r*a*255.f + tb_r*(1-a));
+ row[1] = rint(g*a*255.f + tb_g*(1-a));
+ row[2] = rint(b*a*255.f + tb_b*(1-a));
+ row[3] = 0xff;
+ row+=bpr;
+ }
+
+ data+=bpp;
+ }
+ }
+
+ draw_vframe(trough, ntx, nty, t_w01-2, 1, 0, 0, t_w01-2, 1);
+ draw_vframe(trough, ntx, nty+1, t_w01-1, nth-2, 0, 1, t_w01-1, nth-2);
+ draw_vframe(trough, ntx, nty+nth-1, t_w01-2, 1, 0, nth-1, t_w01-2, 1);
+
+ draw_vframe(trough, t_x1+3, nty, t_w12-5, 1, t_w01, 0, t_w12-5, 1);
+ draw_vframe(trough, t_x1+2, nty+1, t_w12-3, nth-2, t_w01-1, 1, t_w12-3, nth-2);
+ draw_vframe(trough, t_x1+3, nty+nth-1, t_w12-5, 1, t_w01, nth-1, t_w12-5, 1);
+
+ draw_vframe(trough, t_x2+3, nty, t_w23-2, 1, t_w01+t_w12-3, 0, t_w23-2, 1);
+ draw_vframe(trough, t_x2+2, nty+1, t_w23-1, nth-2, t_w01+t_w12-4, 1, t_w23-1, nth-2);
+ draw_vframe(trough, t_x2+3, nty+nth-1, t_w23-2, 1, t_w01+t_w12-3, nth-1, t_w23-2, 1);
+ }
+
+ draw_topslider(rint(gamma_to_pixel(gamma)),light==3);
+
+ draw_bottomslider(rint(value_to_pixel(loval)),light==0);
+ draw_bottomslider(rint(value_to_pixel(hival)),light==2);
+ draw_midslider(rint(value_to_pixel((loval+hival)/2.)),light==1);
+
+ flash();
+ flush();
+}
+
+void BluebananaSliderChannel::update_histogram(float *raw, float *red, float *green, float *blue, int n){
+ int i;
+ //int h = troughlines;
+ int w = troughcols-6;
+ float il2n = 1./log2(n);
+ int w0 = t_w01-1;
+ int w1 = t_w12-4;
+ int w2 = t_w23-1;
+
+ if(!histval)
+ histval = new float[w];
+
+ if(!histred && red){
+ histred = new float[w];
+ histgreen = new float[w];
+ histblue = new float[w];
+ }
+
+ /* resample left */
+ int span0 = rint((0.f-MIN_HISTBRACKET) / (MAX_HISTBRACKET-MIN_HISTBRACKET) * HISTSIZE);
+ resample_histogram(raw, red, green, blue, histval, histred, histgreen, histblue,
+ span0, 0, w0, 0, w0);
+
+ /* resample center */
+ int span1 = rint(100.f/(MAX_HISTBRACKET-MIN_HISTBRACKET) * HISTSIZE);
+ resample_histogram(raw, red, green, blue, histval+w0, histred+w0, histgreen+w0, histblue+w0,
+ span1, span0, w1, 0, w1+1);
+
+ /* resample right */
+ int span2 = rint((MAX_HISTBRACKET-100.f) / (MAX_HISTBRACKET-MIN_HISTBRACKET) * HISTSIZE);
+ resample_histogram(raw, red, green, blue, histval+w0+w1, histred+w0+w1, histgreen+w0+w1, histblue+w0+w1,
+ span2, span0+span1, w2, 1, w2+1);
+
+ /* select value normalization */
+ for(i=0;i<w;i++){
+ if(histval[i]<=.0001f){
+ histval[i]=-2;
+ }else{
+ float val = log2(histval[i])*il2n;
+ val = pow(val<0?0:val,.75)*troughlines;
+ if(val<0)val=0;
+ if(val>troughlines)val=troughlines;
+ histval[i]=val;
+ }
+ }
+ render();
+}
+
+// ---------------------------- Fill ----------------------------------
+
+int BluebananaSliderFill::over_to_pixel(float input){
+ return fraction_to_pixel(input/maxover);
+}
+
+float BluebananaSliderFill::pixel_to_over(int pixel){
+ return pixel_to_fraction(pixel)*maxover;
+}
+
+BluebananaSliderFill::BluebananaSliderFill(BluebananaMain *plugin,
+ BluebananaWindow *gui,
+ int x,
+ int y,
+ int w,
+ int h,
+ float minval,
+ float maxval,
+ float maxover)
+ : BluebananaSlider(plugin,gui,x,y,w,h,minval,maxval){
+ loval = -2;
+ midval = 0;
+ hival = 2;
+ overval = 0;
+ this->maxover = maxover;
+}
+
+int BluebananaSliderFill::button_press_event(){
+ if(is_event_win() && cursor_inside()){
+ //int min;
+ //int max;
+ int cx = get_cursor_x();
+
+ gui->deactivate();
+
+ if(shift_down()){
+ /* narrow/widen range */
+ if(get_buttonpress() == 4){
+ set_delta(1);
+ return 1;
+ }else if(get_buttonpress() == 5){
+ set_delta(-1);
+ return 1;
+ }
+ }else if (ctrl_down()){
+ /* shift all vals up/down */
+ if(get_buttonpress() == 4){
+ if(loval-increment>minval)
+ set_fill(loval-1,midval-1,hival-1);
+ return 1;
+ }else if(get_buttonpress() == 5){
+ if(hival+increment<maxval)
+ set_fill(loval+1,midval+1,hival+1);
+ return 1;
+ }
+ }else{
+ /* increase/decrease feather */
+ if(get_buttonpress() == 4){
+ set_over(overval-1);
+ return 1;
+ }else if(get_buttonpress() == 5){
+ set_over(overval+1);
+ return 1;
+ }
+ }
+
+ switch(light){
+ case 0:
+ xoff = cx-value_to_pixel(loval);
+ break;
+ case 1:
+ xoff = cx-value_to_pixel(midval);
+ break;
+ case 2:
+ xoff = cx-value_to_pixel(hival);
+ break;
+ case 3:
+ xoff = cx-over_to_pixel(overval);
+ break;
+ default:
+ return 1;
+ }
+
+ drag = 1;
+ update();
+ return 1;
+ }
+ return 0;
+}
+
+int BluebananaSliderFill::cursor_motion_event(){
+ int cx = get_cursor_x();
+ int cy = get_cursor_y();
+
+ if(drag){
+ switch(light){
+ case 0:
+ set_fill(pixel_to_value(cx - xoff),midval,hival);
+ break;
+ case 1:
+ set_fill(loval,pixel_to_value(cx - xoff),hival);
+ break;
+ case 2:
+ set_fill(loval,midval,pixel_to_value(cx - xoff));
+ break;
+ case 3:
+ set_over(pixel_to_over(cx - xoff));
+ break;
+ default:
+ drag = 0;
+ light = -1;
+ update();
+ break;
+ }
+ return 1;
+ }else{
+ if(is_event_win() && cursor_inside()){
+ if(in_overslider(over_to_pixel(overval),cx,cy)){
+ if(light!=3){
+ light = 3;
+ update();
+ }
+ }else if(in_bottomslider(value_to_pixel(midval),cx,cy)){
+ if(light!=1){
+ light = 1;
+ update();
+ }
+ }else if(in_leftslider(value_to_pixel(loval),cx,cy)){
+ if(light!=0){
+ light = 0;
+ update();
+ }
+ }else if(in_rightslider(value_to_pixel(hival),cx,cy)){
+ if(light!=2){
+ light = 2;
+ update();
+ }
+ }else if(in_midslider2(value_to_pixel(midval),cx)){
+ if(light!=1){
+ light = 1;
+ update();
+ }
+ }else if(in_rightslider2(value_to_pixel(hival),cx)){
+ if(light!=2){
+ light = 2;
+ update();
+ }
+ }else if(in_leftslider2(value_to_pixel(loval),cx)){
+ if(light!=0){
+ light = 0;
+ update();
+ }
+ }else if(in_overslider2(over_to_pixel(overval),cx,cy)){
+ if(light!=3){
+ light = 3;
+ update();
+ }
+ }else{
+ if(light!=-1){
+ light = -1;
+ update();
+ }
+ }
+ return 1;
+ }else{
+ if(light!=-1){
+ light = -1;
+ update();
+ }
+ }
+ }
+ return 0;
+}
+
+void BluebananaSliderFill::set_fill(float lo, float mid, float hi){
+ if(lo<minval)lo=minval;
+ if(mid<minval)mid=minval;
+ if(hi<0)hi=0;
+ if(lo>0)lo=0;
+ if(mid>maxval)mid=maxval;
+ if(hi>maxval)hi=maxval;
+
+ if(lo>midval)mid=lo;
+ if(mid<loval)lo=mid;
+ if(mid>hival)hi=mid;
+ if(hi<midval)mid=hi;
+
+ loval=lo;
+ midval=mid;
+ hival=hi;
+
+ handle_event();
+ update();
+}
+
+void BluebananaSliderFill::set_delta(float del){
+ if(loval+del>=minval && hival+del<=maxval){
+ loval-=del;
+ hival+=del;
+ if(loval>hival)
+ loval=hival=rint((loval+hival)/2);
+ if(midval<loval)midval=loval;
+ if(midval>hival)midval=hival;
+ handle_event();
+ update();
+ }
+}
+
+void BluebananaSliderFill::set_over(float over){
+ if(over>=0 && over<=maxover){
+ overval=over;
+ handle_event();
+ update();
+ }
+}
+
+void BluebananaSliderFill::update(){
+ int w = get_w();
+ int h = get_h();
+ int bg_c = get_resources()->get_bg_color();
+ int bg_r = ((bg_c >> 16) & 0xff);
+ int bg_g = ((bg_c >> 8) & 0xff);
+ int bg_b = (bg_c & 0xff);
+ int b_c = highlight ? active_bordercolor : inactive_bordercolor;
+ //int b_r = ((b_c >> 16) & 0xff);
+ //int b_g = ((b_c >> 8) & 0xff);
+ //int b_b = (b_c & 0xff);
+ int tb_c = troughcolor;
+ int tb_r = ((tb_c >> 16) & 0xff);
+ int tb_g = ((tb_c >> 8) & 0xff);
+ int tb_b = (tb_c & 0xff);
+
+ int ZH = Z4-Z1+1;
+ //int ZHC = Z4-ZC+1;
+
+ int i,j;
+
+ int xC = value_to_pixel(0);
+ int ntw = troughcols;
+ int nth = troughlines;
+ int ntx = CW+ZL;
+ int nty = Z1+1;
+
+ clear_box(0, 0, w, h);
+
+ /* trough shadow */
+
+ /* w+4 h+4 x-1 y-1 */
+ float del = .9;
+ int shadow_c = ((int)(bg_r*del) << 16) | ((int)(bg_g*del) << 8) | ((int)(bg_b*del));
+ set_color(shadow_c);
+ draw_box (0,Z1,xC+3,ZH+2);
+ draw_box (1,Z1-1,xC+1,ZH+4);
+ draw_box (xC,Z1,w-xC,ZH+2);
+ draw_box (xC+1,Z1-1,w-xC-2,ZH+4);
+
+ /* w+2 h+2 x y */
+ del = .8;
+ shadow_c = ((int)(bg_r*del) << 16) | ((int)(bg_g*del) << 8) | ((int)(bg_b*del));
+ set_color(shadow_c);
+ draw_box (1,Z1+1,xC+1,ZH);
+ draw_box (2,Z1,xC-1,ZH+2);
+ draw_box (xC+1,Z1+1,w-xC-2,ZH);
+ draw_box (xC+2,Z1,w-xC-4,ZH+2);
+
+ /* w h x+1 y+1 */
+ del = .7;
+ shadow_c = ((int)(bg_r*del) << 16) | ((int)(bg_g*del) << 8) | ((int)(bg_b*del));
+ set_color(shadow_c);
+ draw_box (2,Z1+2,xC-1,ZH-2);
+ draw_box (3,Z1+1,xC-3,ZH);
+ draw_box (xC+2,Z1+2,w-xC-4,ZH-2);
+ draw_box (xC+3,Z1+1,w-xC-6,ZH);
+
+ /* trough border */
+ set_color(b_c);
+ draw_box (1,Z1+1,xC-1,ZH-2);
+ draw_box (2,Z1,xC-3,ZH);
+ draw_box (xC+1,Z1+1,w-xC-4,ZH-2);
+ draw_box (xC+2,Z1,w-xC-6,ZH);
+
+ /* trough inner */
+ /* the trough in the two-part contour slider is slightly smaller than
+ the full slider range, and cut into two sections */
+ if(!trough){
+ trough = new VFrame(ntw,nth,BC_RGBA8888);
+ }
+
+ /* Unlike the hist slider, we just drop the three pixel columns in the center */
+ if(!trough){
+ fprintf(stderr,_("Bluebanana: Unable to create Frame for slider\n"));
+ }else{
+ unsigned char *data = trough->get_data();
+ long bpr = trough->get_bytes_per_line();
+ float ha = 1.;
+ if(!highlight){
+ ha*=.25;
+ tb_r = bg_r;
+ tb_g = bg_g;
+ tb_b = bg_b;
+ }
+
+ for(i=0;i<ntw;i++){
+ unsigned char *row = data + i*trough->get_bytes_per_pixel();
+ for(j=0;j<nth;j++){
+ float r,g,b,a;
+ trough_color((i+.5f)/ntw,(j+.5)/nth,r,g,b,a);
+ r=CLAMP(r,0,255);
+ g=CLAMP(g,0,255);
+ b=CLAMP(b,0,255);
+ a*=ha;
+ row[0] = rint(r*a*255 + tb_r*(1-a));
+ row[1] = rint(g*a*255 + tb_g*(1-a));
+ row[2] = rint(b*a*255 + tb_b*(1-a));
+ row[3] = 0xff;
+ row+=bpr;
+ }
+ }
+
+ draw_vframe(trough, ntx, nty, xC-ntx-2, 1, 0, 0, xC-ntx-2, 1);
+ draw_vframe(trough, ntx, nty+1, xC-ntx-1, nth-2, 0, 1, xC-ntx-1, nth-2);
+ draw_vframe(trough, ntx, nty+nth-1, xC-ntx-2, 1, 0, nth-1, xC-ntx-2, 1);
+
+ draw_vframe(trough, xC+3, nty, ntw-xC+ntx-3, 1, xC-ntx+2, 0, ntw-xC+ntx-3, 1);
+ draw_vframe(trough, xC+2, nty+1, ntw-xC+ntx-2, nth-2, xC-ntx+1, 1, ntx-xC+ntx-2, nth-2);
+ draw_vframe(trough, xC+3, nty+nth-1, ntw-xC+ntx-3, 1, xC-ntx+2, nth-1, ntw-xC+ntx-3, 1);
+ }
+
+ draw_overslider(over_to_pixel(overval),light==3);
+ draw_leftslider(value_to_pixel(loval),light==0);
+ draw_rightslider(value_to_pixel(hival),light==2);
+ draw_bottomslider(value_to_pixel(midval),light==1);
+ flash();
+ flush();
+}