diff options
| author | Michael R Sweet <michael.r.sweet@gmail.com> | 1998-10-06 18:21:25 +0000 |
|---|---|---|
| committer | Michael R Sweet <michael.r.sweet@gmail.com> | 1998-10-06 18:21:25 +0000 |
| commit | f9039b2ae21988783feae9b362818e7923e82d14 (patch) | |
| tree | 6d6fe3679d73448758f9794e7d4d4f6b22a4adad /src/Fl_Color_Chooser.cxx | |
| parent | 67e89232f9ba067825a158734a09e0fa21aacbe3 (diff) | |
Initial revision
git-svn-id: file:///fltk/svn/fltk/trunk@2 ea41ed52-d2ee-0310-a9c1-e6b18d33e121
Diffstat (limited to 'src/Fl_Color_Chooser.cxx')
| -rw-r--r-- | src/Fl_Color_Chooser.cxx | 397 |
1 files changed, 397 insertions, 0 deletions
diff --git a/src/Fl_Color_Chooser.cxx b/src/Fl_Color_Chooser.cxx new file mode 100644 index 000000000..e0e2d926a --- /dev/null +++ b/src/Fl_Color_Chooser.cxx @@ -0,0 +1,397 @@ +// Fl_Color_Chooser.C + +// Besides being a useful object on it's own, the Fl_Color_Chooser was +// an attempt to make a complex composite object that could be easily +// imbedded into a user interface. If you wish to make complex objects +// of your own, be sure to read this code. + +// The function fl_color_chooser() creates a window containing a color +// chooser and a few buttons and current-color indicators. It is an +// easier interface for simple programs that just need a color. + +#include <FL/Fl.H> +#include <FL/Fl_Color_Chooser.H> +#include <FL/fl_draw.H> +#include <FL/math.h> +#include <stdio.h> + +// The "hue box" can be a circle or rectilinear. +// You get a circle by defining this: +// #define CIRCLE 1 +// And the "hue box" can auto-update when the value changes +// you get this by defining this: +#define UPDATE_HUE_BOX 1 + +void Fl_Color_Chooser::hsv2rgb( + double H, double S, double V, double& r, double& g, double& b) { + if (S < 5.0e-6) { + r = g = b = V; + } else { + int i = (int)H; + double f = H - (float)i; + double p1 = V*(1.0-S); + double p2 = V*(1.0-S*f); + double p3 = V*(1.0-S*(1.0-f)); + switch (i) { + case 0: r = V; g = p3; b = p1; break; + case 1: r = p2; g = V; b = p1; break; + case 2: r = p1; g = V; b = p3; break; + case 3: r = p1; g = p2; b = V; break; + case 4: r = p3; g = p1; b = V; break; + case 5: r = V; g = p1; b = p2; break; + } + } +} + +void Fl_Color_Chooser::rgb2hsv( + double r, double g, double b, double& H, double& S, double& V) { + double maxv = r > g ? r : g; if (b > maxv) maxv = b; + V = maxv; + if (maxv>0) { + double minv = r < g ? r : g; if (b < minv) minv = b; + S = 1.0 - double(minv)/maxv; + if (maxv > minv) { + if (maxv == r) {H = (g-b)/double(maxv-minv); if (H<0) H += 6.0;} + else if (maxv == g) H = 2.0+(b-r)/double(maxv-minv); + else H = 4.0+(r-g)/double(maxv-minv); + } + } +} + +enum {M_RGB, M_BYTE, M_HEX, M_HSV}; // modes +static Fl_Menu_Item mode_menu[] = { + {"rgb"}, + {"byte"}, + {"hex"}, + {"hsv"}, + {0} +}; + +int Flcc_Value_Input::format(char* buf) { + Fl_Color_Chooser* c = (Fl_Color_Chooser*)parent(); + if (c->mode() == M_HEX) return sprintf(buf,"0x%02X", int(value())); + else return Fl_Valuator::format(buf); +} + +void Fl_Color_Chooser::set_valuators() { + switch (mode()) { + case M_RGB: + rvalue.range(0,1); rvalue.step(1,1000); rvalue.value(r_); + gvalue.range(0,1); gvalue.step(1,1000); gvalue.value(g_); + bvalue.range(0,1); bvalue.step(1,1000); bvalue.value(b_); + break; + case M_BYTE: + case M_HEX: + rvalue.range(0,255); rvalue.step(1); rvalue.value(int(255*r_+.5)); + gvalue.range(0,255); gvalue.step(1); gvalue.value(int(255*g_+.5)); + bvalue.range(0,255); bvalue.step(1); bvalue.value(int(255*b_+.5)); + break; + case M_HSV: + rvalue.range(0,6); rvalue.step(1,1000); rvalue.value(hue_); + gvalue.range(0,1); gvalue.step(1,1000); gvalue.value(saturation_); + bvalue.range(0,1); bvalue.step(1,1000); bvalue.value(value_); + break; + } +} + +int Fl_Color_Chooser::rgb(double r, double g, double b) { + if (r == r_ && g == g_ && b == b_) return 0; + r_ = r; g_ = g; b_ = b; + double ph = hue_; + double ps = saturation_; + double pv = value_; + rgb2hsv(r,g,b,hue_,saturation_,value_); + set_valuators(); + if (value_ != pv) { +#ifdef UPDATE_HUE_BOX + huebox.damage(6); +#endif + valuebox.damage(2);} + if (hue_ != ph || saturation_ != ps) {huebox.damage(2); valuebox.damage(6);} + return 1; +} + +int Fl_Color_Chooser::hsv(double h, double s, double v) { + h = fmod(h,6.0); if (h < 0.0) h += 6.0; + if (s < 0.0) s = 0.0; else if (s > 1.0) s = 1.0; + if (v < 0.0) v = 0.0; else if (v > 1.0) v = 1.0; + if (h == hue_ && s == saturation_ && v == value_) return 0; + double ph = hue_; + double ps = saturation_; + double pv = value_; + hue_ = h; saturation_ = s; value_ = v; + if (value_ != pv) { +#ifdef UPDATE_HUE_BOX + huebox.damage(6); +#endif + valuebox.damage(2);} + if (hue_ != ph || saturation_ != ps) {huebox.damage(2); valuebox.damage(6);} + hsv2rgb(h,s,v,r_,g_,b_); + set_valuators(); + return 1; +} + +//////////////////////////////////////////////////////////////// + +static void tohs(double x, double y, double& h, double& s) { +#ifdef CIRCLE + x = 2*x-1; + y = 1-2*y; + s = sqrt(x*x+y*y); if (s > 1.0) s = 1.0; + h = (3.0/M_PI)*atan2(y,x); + if (h<0) h += 6.0; +#else + h = fmod(6.0*x,6.0); if (h < 0.0) h += 6.0; + s = 1.0-y; if (s < 0.0) s = 0.0; else if (s > 1.0) s = 1.0; +#endif +} + +int Flcc_HueBox::handle(int e) { + static double ih, is; + Fl_Color_Chooser* c = (Fl_Color_Chooser*)parent(); + switch (e) { + case FL_PUSH: + ih = c->hue(); + is = c->saturation(); + case FL_DRAG: { + double Xf, Yf, H, S; + Xf = (Fl::event_x()-x()-Fl::box_dx(box()))/double(w()-Fl::box_dw(box())); + Yf = (Fl::event_y()-y()-Fl::box_dy(box()))/double(h()-Fl::box_dh(box())); + tohs(Xf, Yf, H, S); + if (fabs(H-ih) < 3*6.0/w()) H = ih; + if (fabs(S-is) < 3*1.0/h()) S = is; + if (Fl::event_state(FL_CTRL)) H = ih; + if (c->hsv(H, S, c->value())) c->do_callback(); + } return 1; + default: + return 0; + } +} + +static void generate_image(void* vv, int X, int Y, int W, uchar* buf) { + Flcc_HueBox* v = (Flcc_HueBox*)vv; + int iw = v->w()-Fl::box_dw(v->box()); + double Yf = double(Y)/(v->h()-Fl::box_dh(v->box())); +#ifdef UPDATE_HUE_BOX + const double V = ((Fl_Color_Chooser*)(v->parent()))->value(); +#else + const double V = 1.0; +#endif + for (int x = X; x < X+W; x++) { + double Xf = double(x)/iw; + double H,S; tohs(Xf,Yf,H,S); + double r,g,b; + Fl_Color_Chooser::hsv2rgb(H,S,V,r,g,b); + *buf++ = uchar(255*r+.5); + *buf++ = uchar(255*g+.5); + *buf++ = uchar(255*b+.5); + } +} + +void Flcc_HueBox::draw() { + if (damage()&128) draw_box(); + int x1 = x()+Fl::box_dx(box()); + int y1 = y()+Fl::box_dy(box()); + int w1 = w()-Fl::box_dw(box()); + int h1 = h()-Fl::box_dh(box()); + if (damage() == 2) fl_clip(x1+px,y1+py,6,6); + fl_draw_image(generate_image, this, x1, y1, w1, h1); + if (damage() == 2) fl_pop_clip(); + Fl_Color_Chooser* c = (Fl_Color_Chooser*)parent(); +#ifdef CIRCLE + int X = int(.5*(cos(c->hue()*(M_PI/3.0))*c->saturation()+1) * (w1-6)); + int Y = int(.5*(1-sin(c->hue()*(M_PI/3.0))*c->saturation()) * (h1-6)); +#else + int X = int(c->hue()/6.0*(w1-6)); + int Y = int((1-c->saturation())*(h1-6)); +#endif + if (X < 0) X = 0; else if (X > w1-6) X = w1-6; + if (Y < 0) Y = 0; else if (Y > h1-6) Y = h1-6; + // fl_color(c->value()>.75 ? FL_BLACK : FL_WHITE); + draw_box(FL_UP_BOX,x1+X,y1+Y,6,6,FL_GRAY); + px = X; py = Y; +} + +//////////////////////////////////////////////////////////////// + +int Flcc_ValueBox::handle(int e) { + static double iv; + Fl_Color_Chooser* c = (Fl_Color_Chooser*)parent(); + switch (e) { + case FL_PUSH: + iv = c->value(); + case FL_DRAG: { + double Yf; + Yf = 1-(Fl::event_y()-y()-Fl::box_dy(box()))/double(h()-Fl::box_dh(box())); + if (fabs(Yf-iv)<3*1.0/h()) Yf = iv; + if (c->hsv(c->hue(),c->saturation(),Yf)) c->do_callback(); + } return 1; + default: + return 0; + } +} + +static double tr, tg, tb; +static void generate_vimage(void* vv, int X, int Y, int W, uchar* buf) { + Flcc_ValueBox* v = (Flcc_ValueBox*)vv; + double Yf = 255*(1.0-double(Y)/(v->h()-Fl::box_dh(v->box()))); + uchar r = uchar(tr*Yf+.5); + uchar g = uchar(tg*Yf+.5); + uchar b = uchar(tb*Yf+.5); + for (int x = X; x < X+W; x++) { + *buf++ = r; *buf++ = g; *buf++ = b; + } +} + +void Flcc_ValueBox::draw() { + if (damage()&128) draw_box(); + Fl_Color_Chooser* c = (Fl_Color_Chooser*)parent(); + c->hsv2rgb(c->hue(),c->saturation(),1.0,tr,tg,tb); + int x1 = x()+Fl::box_dx(box()); + int y1 = y()+Fl::box_dy(box()); + int w1 = w()-Fl::box_dw(box()); + int h1 = h()-Fl::box_dh(box()); + if (damage() == 2) fl_clip(x1,y1+py,w1,6); + fl_draw_image(generate_vimage, this, x1, y1, w1, h1); + if (damage() == 2) fl_pop_clip(); + int Y = int((1-c->value()) * (h1-6)); + if (Y < 0) Y = 0; else if (Y > h1-6) Y = h1-6; + draw_box(FL_UP_BOX,x1,y1+Y,w1,6,FL_GRAY); + py = Y; +} + +//////////////////////////////////////////////////////////////// + +void Fl_Color_Chooser::rgb_cb(Fl_Widget* o, void*) { + Fl_Color_Chooser* c = (Fl_Color_Chooser*)(o->parent()); + double r = c->rvalue.value(); + double g = c->gvalue.value(); + double b = c->bvalue.value(); + if (c->mode() == M_HSV) { + if (c->hsv(r,g,b)) c->do_callback(); + return; + } + if (c->mode() != M_RGB) { + r = r/255; + g = g/255; + b = b/255; + } + if (c->rgb(r,g,b)) c->do_callback(); +} + +void Fl_Color_Chooser::mode_cb(Fl_Widget* o, void*) { + Fl_Color_Chooser* c = (Fl_Color_Chooser*)(o->parent()); + c->set_valuators(); +} + +//////////////////////////////////////////////////////////////// + +Fl_Color_Chooser::Fl_Color_Chooser(int X, int Y, int W, int H, const char* L) + : Fl_Group(0,0,180,100,L), + huebox(0,0,100,100), + valuebox(100,0,20,100), + choice(120,0,60,20), + rvalue(120,20,60,25), + gvalue(120,45,60,25), + bvalue(120,70,60,25), + resize_box(0,95,100,5) +{ + end(); + resizable(resize_box); + resize(X,Y,W,H); + r_ = g_ = b_ = 0; + hue_ = 0.0; + saturation_ = 0.0; + value_ = 0.0; + huebox.box(FL_DOWN_FRAME); + valuebox.box(FL_DOWN_FRAME); + choice.menu(mode_menu); + set_valuators(); + rvalue.callback(rgb_cb); + gvalue.callback(rgb_cb); + bvalue.callback(rgb_cb); + choice.callback(mode_cb); + choice.box(FL_THIN_UP_BOX); + choice.textfont(FL_HELVETICA_BOLD_ITALIC); +} + +//////////////////////////////////////////////////////////////// +// fl_color_chooser(): + +#include <FL/Fl_Window.H> +#include <FL/Fl_Box.H> +#include <FL/Fl_Return_Button.H> + +class ColorChip : public Fl_Widget { + void draw(); +public: + uchar r,g,b; + ColorChip(int X, int Y, int W, int H) : Fl_Widget(X,Y,W,H) { + box(FL_ENGRAVED_FRAME);} +}; + +void ColorChip::draw() { + if (damage()&128) draw_box(); + fl_rectf(x()+Fl::box_dx(box()), + y()+Fl::box_dy(box()), + w()-Fl::box_dw(box()), + h()-Fl::box_dh(box()),r,g,b); +} + +static void chooser_cb(Fl_Object* o, void* vv) { + Fl_Color_Chooser* c = (Fl_Color_Chooser*)o; + ColorChip* v = (ColorChip*)vv; + v->r = uchar(255*c->r()+.5); + v->g = uchar(255*c->g()+.5); + v->b = uchar(255*c->b()+.5); + v->damage(2); +} + +extern const char* fl_ok; +extern const char* fl_cancel; + +int fl_color_chooser(const char* name, double& r, double& g, double& b) { + Fl_Window window(210,165,name); + Fl_Color_Chooser chooser(5, 5, 200, 95); + ColorChip ok_color(5, 105, 95, 30); + Fl_Return_Button ok_button(5, 135, 95, 25, fl_ok); + ColorChip cancel_color(110, 105, 95, 30); + cancel_color.r = uchar(255*r+.5); ok_color.r = cancel_color.r; + ok_color.g = cancel_color.g = uchar(255*g+.5); + ok_color.b = cancel_color.b = uchar(255*b+.5); + Fl_Button cancel_button(110, 135, 95, 25, fl_cancel); + window.resizable(chooser); + chooser.rgb(r,g,b); + chooser.callback(chooser_cb, &ok_color); + window.end(); + window.set_modal(); + window.hotspot(window); + window.show(); + while (window.shown()) { + Fl::wait(); + Fl_Widget* o; + while ((o = Fl::readqueue())) { + if (o == &ok_button) { + r = chooser.r(); + g = chooser.g(); + b = chooser.b(); + return 1; + } + if (o == &window || o == &cancel_button) return 0; + } + } + return 0; +} + +int fl_color_chooser(const char* name, uchar& r, uchar& g, uchar& b) { + double dr = r/255.0; + double dg = g/255.0; + double db = b/255.0; + if (fl_color_chooser(name,dr,dg,db)) { + r = uchar(255*dr+.5); + g = uchar(255*dg+.5); + b = uchar(255*db+.5); + return 1; + } + return 0; +} |
