1 //
2 // "$Id$"
3 //
4 // Color chooser for the Fast Light Tool Kit (FLTK).
5 //
6 // Copyright 1998-2010 by Bill Spitzak and others.
7 //
8 // This library is free software. Distribution and use rights are outlined in
9 // the file "COPYING" which should have been included with this file. If this
10 // file is missing or damaged, see the license at:
11 //
12 // http://www.fltk.org/COPYING.php
13 //
14 // Please report all bugs and problems on the following page:
15 //
16 // http://www.fltk.org/str.php
17 //
18
19 #include <FL/Fl.H>
20 #include <FL/Fl_Color_Chooser.H>
21 #include <FL/fl_draw.H>
22 #include <FL/math.h>
23 #include <stdio.h>
24
25 // Besides being a useful object on it's own, the Fl_Color_Chooser was
26 // an attempt to make a complex composite object that could be easily
27 // imbedded into a user interface. If you wish to make complex objects
28 // of your own, be sure to read this code.
29
30 // The function fl_color_chooser() creates a window containing a color
31 // chooser and a few buttons and current-color indicators. It is an
32 // easier interface for simple programs that just need a color.
33
34 // The "hue box" can be a circle or rectilinear.
35 // You get a circle by defining this:
36 #define CIRCLE 1
37 // And the "hue box" can auto-update when the value changes
38 // you get this by defining this:
39 #define UPDATE_HUE_BOX 1
40
41 /**
42 This \e static method converts HSV colors to RGB colorspace.
43 \param[in] H, S, V color components
44 \param[out] R, G, B color components
45 */
hsv2rgb(double H,double S,double V,double & R,double & G,double & B)46 void Fl_Color_Chooser::hsv2rgb(
47 double H, double S, double V, double& R, double& G, double& B) {
48 if (S < 5.0e-6) {
49 R = G = B = V;
50 } else {
51 int i = (int)H;
52 double f = H - (float)i;
53 double p1 = V*(1.0-S);
54 double p2 = V*(1.0-S*f);
55 double p3 = V*(1.0-S*(1.0-f));
56 switch (i) {
57 case 0: R = V; G = p3; B = p1; break;
58 case 1: R = p2; G = V; B = p1; break;
59 case 2: R = p1; G = V; B = p3; break;
60 case 3: R = p1; G = p2; B = V; break;
61 case 4: R = p3; G = p1; B = V; break;
62 case 5: R = V; G = p1; B = p2; break;
63 }
64 }
65 }
66
67 /**
68 This \e static method converts RGB colors to HSV colorspace.
69 \param[in] R, G, B color components
70 \param[out] H, S, V color components
71 */
rgb2hsv(double R,double G,double B,double & H,double & S,double & V)72 void Fl_Color_Chooser::rgb2hsv(
73 double R, double G, double B, double& H, double& S, double& V) {
74 double maxv = R > G ? R : G; if (B > maxv) maxv = B;
75 V = maxv;
76 if (maxv>0) {
77 double minv = R < G ? R : G; if (B < minv) minv = B;
78 S = 1.0 - double(minv)/maxv;
79 if (maxv > minv) {
80 if (maxv == R) {H = (G-B)/double(maxv-minv); if (H<0) H += 6.0;}
81 else if (maxv == G) H = 2.0+(B-R)/double(maxv-minv);
82 else H = 4.0+(R-G)/double(maxv-minv);
83 }
84 }
85 }
86
87 /** Fl_Color_Chooser modes */
88 enum {
89 M_RGB, /**< mode() of Fl_Color_Chooser showing RGB values */
90 M_BYTE, /**< mode() of Fl_Color_Chooser showing byte values */
91 M_HEX, /**< mode() of Fl_Color_Chooser showing hex values */
92 M_HSV /**< mode() of Fl_Color_Chooser showing HSV values */
93 };
94 static const Fl_Menu_Item mode_menu[] = {
95 {"rgb"},
96 {"byte"},
97 {"hex"},
98 {"hsv"},
99 {0}
100 };
101
102 #ifndef FL_DOXYGEN
format(char * buf)103 int Flcc_Value_Input::format(char* buf) {
104 Fl_Color_Chooser* c = (Fl_Color_Chooser*)parent();
105 if (c->mode() == M_HEX) return sprintf(buf,"0x%02X", int(value()));
106 else return Fl_Valuator::format(buf);
107 }
108 #endif // !FL_DOXYGEN
109
set_valuators()110 void Fl_Color_Chooser::set_valuators() {
111 switch (mode()) {
112 case M_RGB:
113 rvalue.range(0,1); rvalue.step(1,1000); rvalue.value(r_);
114 gvalue.range(0,1); gvalue.step(1,1000); gvalue.value(g_);
115 bvalue.range(0,1); bvalue.step(1,1000); bvalue.value(b_);
116 break;
117 case M_BYTE: /* FALLTHROUGH */
118 case M_HEX:
119 rvalue.range(0,255); rvalue.step(1); rvalue.value(int(255*r_+.5));
120 gvalue.range(0,255); gvalue.step(1); gvalue.value(int(255*g_+.5));
121 bvalue.range(0,255); bvalue.step(1); bvalue.value(int(255*b_+.5));
122 break;
123 case M_HSV:
124 rvalue.range(0,6); rvalue.step(1,1000); rvalue.value(hue_);
125 gvalue.range(0,1); gvalue.step(1,1000); gvalue.value(saturation_);
126 bvalue.range(0,1); bvalue.step(1,1000); bvalue.value(value_);
127 break;
128 }
129 }
130
131 /**
132 Sets the current rgb color values.
133 Does not do the callback. Does not clamp (but out of range values will
134 produce psychedelic effects in the hue selector).
135 \param[in] R, G, B color components.
136 \return 1 if a new rgb value was set, 0 if the rgb value was the previous one.
137 */
rgb(double R,double G,double B)138 int Fl_Color_Chooser::rgb(double R, double G, double B) {
139 if (R == r_ && G == g_ && B == b_) return 0;
140 r_ = R; g_ = G; b_ = B;
141 double ph = hue_;
142 double ps = saturation_;
143 double pv = value_;
144 rgb2hsv(R,G,B,hue_,saturation_,value_);
145 set_valuators();
146 set_changed();
147 if (value_ != pv) {
148 #ifdef UPDATE_HUE_BOX
149 huebox.damage(FL_DAMAGE_SCROLL);
150 #endif
151 valuebox.damage(FL_DAMAGE_EXPOSE);}
152 if (hue_ != ph || saturation_ != ps) {
153 huebox.damage(FL_DAMAGE_EXPOSE);
154 valuebox.damage(FL_DAMAGE_SCROLL);
155 }
156 return 1;
157 }
158
159 /**
160 Set the hsv values.
161 The passed values are clamped (or for hue, modulus 6 is used) to get
162 legal values. Does not do the callback.
163 \param[in] H, S, V color components.
164 \return 1 if a new hsv value was set, 0 if the hsv value was the previous one.
165 */
hsv(double H,double S,double V)166 int Fl_Color_Chooser::hsv(double H, double S, double V) {
167 H = fmod(H,6.0); if (H < 0.0) H += 6.0;
168 if (S < 0.0) S = 0.0; else if (S > 1.0) S = 1.0;
169 if (V < 0.0) V = 0.0; else if (V > 1.0) V = 1.0;
170 if (H == hue_ && S == saturation_ && V == value_) return 0;
171 double ph = hue_;
172 double ps = saturation_;
173 double pv = value_;
174 hue_ = H; saturation_ = S; value_ = V;
175 if (value_ != pv) {
176 #ifdef UPDATE_HUE_BOX
177 huebox.damage(FL_DAMAGE_SCROLL);
178 #endif
179 valuebox.damage(FL_DAMAGE_EXPOSE);}
180 if (hue_ != ph || saturation_ != ps) {
181 huebox.damage(FL_DAMAGE_EXPOSE);
182 valuebox.damage(FL_DAMAGE_SCROLL);
183 }
184 hsv2rgb(H,S,V,r_,g_,b_);
185 set_valuators();
186 set_changed();
187 return 1;
188 }
189
190 ////////////////////////////////////////////////////////////////
191
tohs(double x,double y,double & h,double & s)192 static void tohs(double x, double y, double& h, double& s) {
193 #ifdef CIRCLE
194 x = 2*x-1;
195 y = 1-2*y;
196 s = sqrt(x*x+y*y); if (s > 1.0) s = 1.0;
197 h = (3.0/M_PI)*atan2(y,x);
198 if (h<0) h += 6.0;
199 #else
200 h = fmod(6.0*x,6.0); if (h < 0.0) h += 6.0;
201 s = 1.0-y; if (s < 0.0) s = 0.0; else if (s > 1.0) s = 1.0;
202 #endif
203 }
204
205 #ifndef FL_DOXYGEN
handle(int e)206 int Flcc_HueBox::handle(int e) {
207 static double ih, is;
208 Fl_Color_Chooser* c = (Fl_Color_Chooser*)parent();
209 switch (e) {
210 case FL_PUSH:
211 if (Fl::visible_focus()) {
212 Fl::focus(this);
213 redraw();
214 }
215 ih = c->hue();
216 is = c->saturation();
217 case FL_DRAG: {
218 double Xf, Yf, H, S;
219 Xf = (Fl::event_x()-x()-Fl::box_dx(box()))/double(w()-Fl::box_dw(box()));
220 Yf = (Fl::event_y()-y()-Fl::box_dy(box()))/double(h()-Fl::box_dh(box()));
221 tohs(Xf, Yf, H, S);
222 if (fabs(H-ih) < 3*6.0/w()) H = ih;
223 if (fabs(S-is) < 3*1.0/h()) S = is;
224 if (Fl::event_state(FL_CTRL)) H = ih;
225 if (c->hsv(H, S, c->value())) c->do_callback();
226 } return 1;
227 case FL_FOCUS : /* FALLTHROUGH */
228 case FL_UNFOCUS :
229 if (Fl::visible_focus()) {
230 redraw();
231 return 1;
232 }
233 else return 1;
234 case FL_KEYBOARD :
235 return handle_key(Fl::event_key());
236 default:
237 return 0;
238 }
239 }
240 #endif // !FL_DOXYGEN
241
generate_image(void * vv,int X,int Y,int W,uchar * buf)242 static void generate_image(void* vv, int X, int Y, int W, uchar* buf) {
243 Flcc_HueBox* v = (Flcc_HueBox*)vv;
244 int iw = v->w()-Fl::box_dw(v->box());
245 double Yf = double(Y)/(v->h()-Fl::box_dh(v->box()));
246 #ifdef UPDATE_HUE_BOX
247 const double V = ((Fl_Color_Chooser*)(v->parent()))->value();
248 #else
249 const double V = 1.0;
250 #endif
251 for (int x = X; x < X+W; x++) {
252 double Xf = double(x)/iw;
253 double H,S; tohs(Xf,Yf,H,S);
254 double r=0, g=0, b=0;
255 Fl_Color_Chooser::hsv2rgb(H,S,V,r,g,b);
256 *buf++ = uchar(255*r+.5);
257 *buf++ = uchar(255*g+.5);
258 *buf++ = uchar(255*b+.5);
259 }
260 }
261
262 #ifndef FL_DOXYGEN
handle_key(int key)263 int Flcc_HueBox::handle_key(int key) {
264 int w1 = w()-Fl::box_dw(box())-6;
265 int h1 = h()-Fl::box_dh(box())-6;
266 Fl_Color_Chooser* c = (Fl_Color_Chooser*)parent();
267
268 #ifdef CIRCLE
269 int X = int(.5*(cos(c->hue()*(M_PI/3.0))*c->saturation()+1) * w1);
270 int Y = int(.5*(1-sin(c->hue()*(M_PI/3.0))*c->saturation()) * h1);
271 #else
272 int X = int(c->hue()/6.0*w1);
273 int Y = int((1-c->saturation())*h1);
274 #endif
275
276 switch (key) {
277 case FL_Up :
278 Y -= 3;
279 break;
280 case FL_Down :
281 Y += 3;
282 break;
283 case FL_Left :
284 X -= 3;
285 break;
286 case FL_Right :
287 X += 3;
288 break;
289 default :
290 return 0;
291 }
292
293 double Xf, Yf, H, S;
294 Xf = (double)X/(double)w1;
295 Yf = (double)Y/(double)h1;
296 tohs(Xf, Yf, H, S);
297 if (c->hsv(H, S, c->value())) c->do_callback();
298
299 return 1;
300 }
301 #endif // !FL_DOXYGEN
302
303 #ifndef FL_DOXYGEN
draw()304 void Flcc_HueBox::draw() {
305 if (damage()&FL_DAMAGE_ALL) draw_box();
306 int x1 = x()+Fl::box_dx(box());
307 int yy1 = y()+Fl::box_dy(box());
308 int w1 = w()-Fl::box_dw(box());
309 int h1 = h()-Fl::box_dh(box());
310 if (damage() == FL_DAMAGE_EXPOSE) fl_push_clip(x1+px,yy1+py,6,6);
311 fl_draw_image(generate_image, this, x1, yy1, w1, h1);
312 if (damage() == FL_DAMAGE_EXPOSE) fl_pop_clip();
313 Fl_Color_Chooser* c = (Fl_Color_Chooser*)parent();
314 #ifdef CIRCLE
315 int X = int(.5*(cos(c->hue()*(M_PI/3.0))*c->saturation()+1) * (w1-6));
316 int Y = int(.5*(1-sin(c->hue()*(M_PI/3.0))*c->saturation()) * (h1-6));
317 #else
318 int X = int(c->hue()/6.0*(w1-6));
319 int Y = int((1-c->saturation())*(h1-6));
320 #endif
321 if (X < 0) X = 0; else if (X > w1-6) X = w1-6;
322 if (Y < 0) Y = 0; else if (Y > h1-6) Y = h1-6;
323 // fl_color(c->value()>.75 ? FL_BLACK : FL_WHITE);
324 draw_box(FL_UP_BOX,x1+X,yy1+Y,6,6,Fl::focus() == this ? FL_FOREGROUND_COLOR : FL_GRAY);
325 px = X; py = Y;
326 }
327 #endif // !FL_DOXYGEN
328
329 ////////////////////////////////////////////////////////////////
330
331 #ifndef FL_DOXYGEN
handle(int e)332 int Flcc_ValueBox::handle(int e) {
333 static double iv;
334 Fl_Color_Chooser* c = (Fl_Color_Chooser*)parent();
335 switch (e) {
336 case FL_PUSH:
337 if (Fl::visible_focus()) {
338 Fl::focus(this);
339 redraw();
340 }
341 iv = c->value();
342 case FL_DRAG: {
343 double Yf;
344 Yf = 1-(Fl::event_y()-y()-Fl::box_dy(box()))/double(h()-Fl::box_dh(box()));
345 if (fabs(Yf-iv)<(3*1.0/h())) Yf = iv;
346 if (c->hsv(c->hue(),c->saturation(),Yf)) c->do_callback();
347 } return 1;
348 case FL_FOCUS : /* FALLTHROUGH */
349 case FL_UNFOCUS :
350 if (Fl::visible_focus()) {
351 redraw();
352 return 1;
353 }
354 else return 1;
355 case FL_KEYBOARD :
356 return handle_key(Fl::event_key());
357 default:
358 return 0;
359 }
360 }
361 #endif // !FL_DOXYGEN
362
363 static double tr, tg, tb;
generate_vimage(void * vv,int X,int Y,int W,uchar * buf)364 static void generate_vimage(void* vv, int X, int Y, int W, uchar* buf) {
365 Flcc_ValueBox* v = (Flcc_ValueBox*)vv;
366 double Yf = 255*(1.0-double(Y)/(v->h()-Fl::box_dh(v->box())));
367 uchar r = uchar(tr*Yf+.5);
368 uchar g = uchar(tg*Yf+.5);
369 uchar b = uchar(tb*Yf+.5);
370 for (int x = X; x < X+W; x++) {
371 *buf++ = r; *buf++ = g; *buf++ = b;
372 }
373 }
374
375 #ifndef FL_DOXYGEN
draw()376 void Flcc_ValueBox::draw() {
377 if (damage()&FL_DAMAGE_ALL) draw_box();
378 Fl_Color_Chooser* c = (Fl_Color_Chooser*)parent();
379 c->hsv2rgb(c->hue(),c->saturation(),1.0,tr,tg,tb);
380 int x1 = x()+Fl::box_dx(box());
381 int yy1 = y()+Fl::box_dy(box());
382 int w1 = w()-Fl::box_dw(box());
383 int h1 = h()-Fl::box_dh(box());
384 if (damage() == FL_DAMAGE_EXPOSE) fl_push_clip(x1,yy1+py,w1,6);
385 fl_draw_image(generate_vimage, this, x1, yy1, w1, h1);
386 if (damage() == FL_DAMAGE_EXPOSE) fl_pop_clip();
387 int Y = int((1-c->value()) * (h1-6));
388 if (Y < 0) Y = 0; else if (Y > h1-6) Y = h1-6;
389 draw_box(FL_UP_BOX,x1,yy1+Y,w1,6,Fl::focus() == this ? FL_FOREGROUND_COLOR : FL_GRAY);
390 py = Y;
391 }
392 #endif // !FL_DOXYGEN
393
394 #ifndef FL_DOXYGEN
handle_key(int key)395 int Flcc_ValueBox::handle_key(int key) {
396 int h1 = h()-Fl::box_dh(box())-6;
397 Fl_Color_Chooser* c = (Fl_Color_Chooser*)parent();
398
399 int Y = int((1-c->value()) * h1);
400 if (Y < 0) Y = 0; else if (Y > h1) Y = h1;
401
402 switch (key) {
403 case FL_Up :
404 Y -= 3;
405 break;
406 case FL_Down :
407 Y += 3;
408 break;
409 default :
410 return 0;
411 }
412
413 double Yf;
414 Yf = 1-((double)Y/(double)h1);
415 if (c->hsv(c->hue(),c->saturation(),Yf)) c->do_callback();
416
417 return 1;
418 }
419 #endif // !FL_DOXYGEN
420
421 ////////////////////////////////////////////////////////////////
422
rgb_cb(Fl_Widget * o,void *)423 void Fl_Color_Chooser::rgb_cb(Fl_Widget* o, void*) {
424 Fl_Color_Chooser* c = (Fl_Color_Chooser*)(o->parent());
425 double R = c->rvalue.value();
426 double G = c->gvalue.value();
427 double B = c->bvalue.value();
428 if (c->mode() == M_HSV) {
429 if (c->hsv(R,G,B)) c->do_callback();
430 return;
431 }
432 if (c->mode() != M_RGB) {
433 R = R/255;
434 G = G/255;
435 B = B/255;
436 }
437 if (c->rgb(R,G,B)) c->do_callback();
438 }
439
mode_cb(Fl_Widget * o,void *)440 void Fl_Color_Chooser::mode_cb(Fl_Widget* o, void*) {
441 Fl_Color_Chooser* c = (Fl_Color_Chooser*)(o->parent());
442 // force them to redraw even if value is the same:
443 c->rvalue.value(-1);
444 c->gvalue.value(-1);
445 c->bvalue.value(-1);
446 c->set_valuators();
447 }
448
mode(int newMode)449 void Fl_Color_Chooser::mode(int newMode)
450 {
451 choice.value(newMode);
452 choice.do_callback();
453 }
454
455
456 ////////////////////////////////////////////////////////////////
457
458 /**
459 Creates a new Fl_Color_Chooser widget using the given position, size, and
460 label string.
461 The recommended dimensions are 200x95. The color is initialized to black.
462 \param[in] X, Y, W, H position and size of the widget
463 \param[in] L widget label, default is no label
464 */
Fl_Color_Chooser(int X,int Y,int W,int H,const char * L)465 Fl_Color_Chooser::Fl_Color_Chooser(int X, int Y, int W, int H, const char* L)
466 : Fl_Group(0,0,195,115,L),
467 huebox(0,0,115,115),
468 valuebox(115,0,20,115),
469 choice(140,0,55,25),
470 rvalue(140,30,55,25),
471 gvalue(140,60,55,25),
472 bvalue(140,90,55,25),
473 resize_box(0,0,115,115)
474 {
475 end();
476 resizable(resize_box);
477 resize(X,Y,W,H);
478 r_ = g_ = b_ = 0;
479 hue_ = 0.0;
480 saturation_ = 0.0;
481 value_ = 0.0;
482 huebox.box(FL_DOWN_FRAME);
483 valuebox.box(FL_DOWN_FRAME);
484 choice.menu(mode_menu);
485 set_valuators();
486 rvalue.callback(rgb_cb);
487 gvalue.callback(rgb_cb);
488 bvalue.callback(rgb_cb);
489 choice.callback(mode_cb);
490 choice.box(FL_THIN_UP_BOX);
491 choice.textfont(FL_HELVETICA_BOLD_ITALIC);
492 }
493
494 ////////////////////////////////////////////////////////////////
495 // fl_color_chooser():
496
497 #include <FL/Fl_Window.H>
498 #include <FL/Fl_Box.H>
499 #include <FL/Fl_Return_Button.H>
500
501 class ColorChip : public Fl_Widget {
502 void draw();
503 public:
504 uchar r,g,b;
ColorChip(int X,int Y,int W,int H)505 ColorChip(int X, int Y, int W, int H) : Fl_Widget(X,Y,W,H) {
506 box(FL_ENGRAVED_FRAME);}
507 };
508
draw()509 void ColorChip::draw() {
510 if (damage()&FL_DAMAGE_ALL) draw_box();
511 fl_rectf(x()+Fl::box_dx(box()),
512 y()+Fl::box_dy(box()),
513 w()-Fl::box_dw(box()),
514 h()-Fl::box_dh(box()),r,g,b);
515 }
516
chooser_cb(Fl_Widget * o,void * vv)517 static void chooser_cb(Fl_Widget* o, void* vv) {
518 Fl_Color_Chooser* c = (Fl_Color_Chooser*)o;
519 ColorChip* v = (ColorChip*)vv;
520 v->r = uchar(255*c->r()+.5);
521 v->g = uchar(255*c->g()+.5);
522 v->b = uchar(255*c->b()+.5);
523 v->damage(FL_DAMAGE_EXPOSE);
524 }
525
526 extern const char* fl_ok;
527 extern const char* fl_cancel;
528
529 // fl_color_chooser's callback for ok_button (below)
530 // [in] o is a pointer to okay_button (below)
531 // [in] p is a pointer to an int to receive the return value (1)
532 // closes the fl_color_chooser window
cc_ok_cb(Fl_Widget * o,void * p)533 static void cc_ok_cb (Fl_Widget *o, void *p) {
534 *((int *)p) = 1; // set return value
535 o->window()->hide();
536 }
537
538 // fl_color_chooser's callback for cancel_button and window close
539 // [in] o is a pointer to cancel_button (below) _or_ the dialog window
540 // [in] p is a pointer to an int to receive the return value (0)
541 // closes the fl_color_chooser window
cc_cancel_cb(Fl_Widget * o,void * p)542 static void cc_cancel_cb (Fl_Widget *o, void *p) {
543 *((int *)p) = 0; // set return value
544 if (o->window()) // cancel button
545 o->window()->hide();
546 else // window close
547 o->hide();
548 }
549
550 /** \addtogroup group_comdlg
551 @{ */
552 /**
553 \brief Pops up a window to let the user pick an arbitrary RGB color.
554 \note \#include <FL/Fl_Color_Chooser.H>
555 \image html fl_color_chooser.jpg
556 \image latex fl_color_chooser.jpg "fl_color_chooser" width=8cm
557 \param[in] name Title label for the window
558 \param[in,out] r, g, b Color components in the range 0.0 to 1.0.
559 \param[in] cmode Optional mode for color chooser. See mode(int). Default -1 if none (rgb mode).
560 \retval 1 if user confirms the selection
561 \retval 0 if user cancels the dialog
562 \relates Fl_Color_Chooser
563 */
fl_color_chooser(const char * name,double & r,double & g,double & b,int cmode)564 int fl_color_chooser(const char* name, double& r, double& g, double& b, int cmode) {
565 int ret = 0;
566 Fl_Window window(215,200,name);
567 window.callback(cc_cancel_cb,&ret);
568 Fl_Color_Chooser chooser(10, 10, 195, 115);
569 ColorChip ok_color(10, 130, 95, 25);
570 Fl_Return_Button ok_button(10, 165, 95, 25, fl_ok);
571 ok_button.callback(cc_ok_cb,&ret);
572 ColorChip cancel_color(110, 130, 95, 25);
573 cancel_color.r = uchar(255*r+.5); ok_color.r = cancel_color.r;
574 ok_color.g = cancel_color.g = uchar(255*g+.5);
575 ok_color.b = cancel_color.b = uchar(255*b+.5);
576 Fl_Button cancel_button(110, 165, 95, 25, fl_cancel);
577 cancel_button.callback(cc_cancel_cb,&ret);
578 window.resizable(chooser);
579 chooser.rgb(r,g,b);
580 chooser.callback(chooser_cb, &ok_color);
581 if (cmode!=-1) chooser.mode(cmode);
582 window.end();
583 window.set_modal();
584 window.hotspot(window);
585 window.show();
586 while (window.shown()) Fl::wait();
587 if (ret) { // ok_button or Enter
588 r = chooser.r();
589 g = chooser.g();
590 b = chooser.b();
591 }
592 return ret;
593 }
594
595 /**
596 \brief Pops up a window to let the user pick an arbitrary RGB color.
597 \note \#include <FL/Fl_Color_Chooser.H>
598 \image html fl_color_chooser.jpg
599 \image latex fl_color_chooser.jpg "fl_color_chooser" width=8cm
600 \param[in] name Title label for the window
601 \param[in,out] r, g, b Color components in the range 0 to 255.
602 \param[in] cmode Optional mode for color chooser. See mode(int). Default -1 if none (rgb mode).
603 \retval 1 if user confirms the selection
604 \retval 0 if user cancels the dialog
605 \relates Fl_Color_Chooser
606 */
fl_color_chooser(const char * name,uchar & r,uchar & g,uchar & b,int cmode)607 int fl_color_chooser(const char* name, uchar& r, uchar& g, uchar& b, int cmode) {
608 double dr = r/255.0;
609 double dg = g/255.0;
610 double db = b/255.0;
611 if (fl_color_chooser(name,dr,dg,db,cmode)) {
612 r = uchar(255*dr+.5);
613 g = uchar(255*dg+.5);
614 b = uchar(255*db+.5);
615 return 1;
616 }
617 return 0;
618 }
619
620 /** @} */
621 //
622 // End of "$Id$".
623 //
624