]> git.lyx.org Git - lyx.git/blob - src/frontends/xforms/FormColorpicker.C
Change Assert to BOOST_ASSERT.
[lyx.git] / src / frontends / xforms / FormColorpicker.C
1 /**
2  * \file FormColorpicker.C
3  * This file is part of LyX, the document processor.
4  * Licence details can be found in the file COPYING.
5  *
6  * \author Angus Leeming
7  *
8  * Full author contact details are available in file CREDITS.
9  */
10
11 #include <config.h>
12
13 #include "FormColorpicker.h"
14 #include "forms/form_colorpicker.h"
15
16 #include "Tooltips.h"
17 #include "xforms_resize.h"
18
19 #include "gettext.h"
20 #include "lyxrc.h"
21
22 #include "support/filetools.h" //  LibFileSearch
23 #include "support/tostr.h"
24
25 #include "lyx_forms.h"
26
27
28 namespace {
29
30 enum GuiColors {
31         GUI_COLOR_CHOICE   = FL_FREE_COL13,
32         GUI_COLOR_HUE_DIAL = FL_FREE_COL14,
33 };
34
35
36 string const fillLabel(RGBColor const & rgb)
37 {
38         return tostr(rgb.r) + ", " + tostr(rgb.g) + ", " + tostr(rgb.b);
39 }
40
41
42 string const fillLabel(HSVColor const & hsv)
43 {
44         int const h = int(hsv.h);
45         int const s = int(100.0 * hsv.s);
46         int const v = int(100.0 * hsv.v);
47
48         return tostr(h) + ", " + tostr(s) + ", " + tostr(v);
49 }
50
51 } // namespace anon
52
53
54 extern "C" {
55
56 // Callback function invoked by xforms when the dialog is closed by the
57 // window manager.
58 static int C_WMHideCB(FL_FORM * form, void *);
59
60 } // extern "C"
61
62
63 FormColorpicker::FormColorpicker()
64         : minw_(0), minh_(0),
65           title_(_("Select Color")),
66           finished_(true),
67           icon_pixmap_(0), icon_mask_(0),
68           tooltips_(new Tooltips)
69 {}
70
71
72 FormColorpicker::~FormColorpicker()
73 {
74         if (icon_pixmap_)
75                 XFreePixmap(fl_get_display(), icon_pixmap_);
76 }
77
78
79 RGBColor const & FormColorpicker::requestColor(RGBColor const & color)
80 {
81         input_color_ = color;
82         color_ = color;
83
84         show();
85
86         fl_deactivate_all_forms();
87         fl_activate_form(form());
88
89         finished_ = false;
90         while (!finished_)
91                 fl_check_forms();
92
93         fl_activate_all_forms();
94         return color_;
95 }
96
97
98 void FormColorpicker::show()
99 {
100         if (!form()) {
101                 build();
102                 prepare_to_show();
103         }
104
105         // make sure the form is up to date.
106         fl_freeze_form(form());
107         update();
108         fl_unfreeze_form(form());
109
110         if (form()->visible) {
111                 fl_raise_form(form());
112                 /* This XMapWindow() will hopefully ensure that
113                  * iconified dialogs are de-iconified. Mad props
114                  * out to those crazy Xlib guys for forgetting a
115                  * XDeiconifyWindow(). At least WindowMaker, when
116                  * being notified of the redirected MapRequest will
117                  * specifically de-iconify. From source, fvwm2 seems
118                  * to do the same.
119                  */
120                 XMapWindow(fl_get_display(), form()->window);
121         } else {
122                 // calls to fl_set_form_minsize/maxsize apply only to the next
123                 // fl_show_form(), so this comes first.
124                 fl_set_form_minsize(form(), minw_, minh_);
125
126                 string const maximize_title = "LyX: " + title_;
127                 int const iconify_policy =
128                         lyxrc.dialogs_iconify_with_main ? FL_TRANSIENT : 0;
129
130                 fl_show_form(form(),
131                              FL_PLACE_MOUSE | FL_FREE_SIZE,
132                              iconify_policy,
133                              maximize_title.c_str());
134         }
135 }
136
137
138 void FormColorpicker::hide() const
139 {
140         // xforms sometimes tries to process a hint-type MotionNotify, and
141         // use XQueryPointer, without verifying if the window still exists.
142         // So we try to clear out motion events in the queue before the
143         // DestroyNotify
144         XSync(fl_get_display(), false);
145
146         if (form() && form()->visible)
147                 fl_hide_form(form());
148 }
149
150
151 void FormColorpicker::build()
152 {
153         dialog_.reset(build_colorpicker(this));
154         rgb_.reset(build_colorpicker_rgb(this));
155         hsv_.reset(build_colorpicker_hsv(this));
156
157         fl_set_object_color(dialog_->button_color,
158                             GUI_COLOR_CHOICE, GUI_COLOR_CHOICE);
159
160         fl_set_object_color(hsv_->dial_hue, GUI_COLOR_HUE_DIAL, FL_BLACK);
161         fl_set_dial_bounds(hsv_->dial_hue, 0.0, 360.0);
162         fl_set_dial_step(hsv_->dial_hue, 1.0);
163         fl_set_dial_return(hsv_->dial_hue, FL_RETURN_CHANGED);
164
165         fl_set_slider_bounds(hsv_->slider_saturation, 0.0, 1.0);
166         fl_set_slider_step(hsv_->slider_saturation, 0.01);
167         fl_set_slider_return(hsv_->slider_saturation, FL_RETURN_CHANGED);
168
169         fl_set_slider_bounds(hsv_->slider_value, 0.0, 1.0);
170         fl_set_slider_step(hsv_->slider_value, 0.01);
171         fl_set_slider_return(hsv_->slider_value, FL_RETURN_CHANGED);
172
173         fl_set_slider_bounds(rgb_->slider_red, 0.0, 255.0);
174         fl_set_slider_step(rgb_->slider_red, 1.0);
175         fl_set_slider_return(rgb_->slider_red, FL_RETURN_CHANGED);
176
177         fl_set_slider_bounds(rgb_->slider_green, 0.0, 255.0);
178         fl_set_slider_step(rgb_->slider_green, 1.0);
179         fl_set_slider_return(rgb_->slider_green, FL_RETURN_CHANGED);
180
181         fl_set_slider_bounds(rgb_->slider_blue, 0.0, 255.0);
182         fl_set_slider_step(rgb_->slider_blue, 1.0);
183         fl_set_slider_return(rgb_->slider_blue, FL_RETURN_CHANGED);
184
185         // Stack tabs
186         fl_addto_tabfolder(dialog_->tabfolder,_("RGB").c_str(), rgb_->form);
187         fl_addto_tabfolder(dialog_->tabfolder,_("HSV").c_str(), hsv_->form);
188 }
189
190
191 void FormColorpicker::update() const
192 {
193         fl_mapcolor(GUI_COLOR_CHOICE, color_.r, color_.g, color_.b);
194
195         FL_FORM * folder = fl_get_active_folder(dialog_->tabfolder);
196
197         if (!folder)
198                 folder = rgb_->form;
199
200         if (folder == rgb_->form) {
201                 fl_set_slider_value(rgb_->slider_red,   color_.r);
202                 fl_set_slider_value(rgb_->slider_green, color_.g);
203                 fl_set_slider_value(rgb_->slider_blue,  color_.b);
204
205                 fl_set_object_label(dialog_->text_color_values,
206                                     fillLabel(color_).c_str());
207
208         } else if (folder == hsv_->form) {
209                 HSVColor hsv = HSVColor(color_);
210                 hsv.h = std::max(hsv.h, 0.0);
211
212                 fl_set_dial_value(hsv_->dial_hue, hsv.h);
213                 fl_set_slider_value(hsv_->slider_saturation, hsv.s);
214                 fl_set_slider_value(hsv_->slider_value, hsv.v);
215
216                 fl_set_object_label(dialog_->text_color_values,
217                                     fillLabel(hsv).c_str());
218
219                 RGBColor col = HSVColor(hsv.h, 1.0, 1.0);
220                 col.r = std::max(col.r, 0u);
221                 fl_mapcolor(GUI_COLOR_HUE_DIAL, col.r, col.g, col.b);
222                 fl_redraw_object(hsv_->dial_hue);
223         }
224 }
225
226
227 void FormColorpicker::input(FL_OBJECT * ob, long)
228 {
229         if (ob == dialog_->tabfolder) {
230                 update();
231
232         } else if (ob == hsv_->dial_hue ||
233                    ob == hsv_->slider_saturation ||
234                    ob == hsv_->slider_value) {
235                 InputHSV();
236
237         } else if (ob == rgb_->slider_red ||
238                    ob == rgb_->slider_green ||
239                    ob == rgb_->slider_blue) {
240                 InputRGB();
241
242         } else if (ob == dialog_->button_ok) {
243                 hide();
244                 finished_ = true;
245
246         } else if (ob == dialog_->button_close || ob == 0) {
247                 color_ = input_color_;
248                 hide();
249                 finished_ = true;
250         }
251 }
252
253
254 FL_FORM * FormColorpicker::form() const
255 {
256         return dialog_.get() ? dialog_->form : 0;
257 }
258
259
260 Tooltips & FormColorpicker::tooltips() const
261 {
262         return *tooltips_;
263 }
264
265
266 void FormColorpicker::prepare_to_show()
267 {
268         double const scale = get_scale_to_fit(form());
269         if (scale > 1.001)
270                 scale_form_horizontally(form(), scale);
271
272         // work around dumb xforms sizing bug
273         minw_ = form()->w;
274         minh_ = form()->h;
275
276         fl_set_form_atclose(form(), C_WMHideCB, 0);
277
278         // set the title for the minimized form
279         if (!lyxrc.dialogs_iconify_with_main)
280                 fl_winicontitle(form()->window, title_.c_str());
281
282         //  assign an icon to the form
283         string const iconname =
284                 lyx::support::LibFileSearch("images", "lyx", "xpm");
285
286         if (!iconname.empty()) {
287                 unsigned int w, h;
288                 icon_pixmap_ = fl_read_pixmapfile(fl_root,
289                                                   iconname.c_str(),
290                                                   &w,
291                                                   &h,
292                                                   &icon_mask_,
293                                                   0, 0, 0);
294                 fl_set_form_icon(form(), icon_pixmap_, icon_mask_);
295         }
296 }
297
298
299 void FormColorpicker::InputRGB()
300 {
301         int const red   = int(fl_get_slider_value(rgb_->slider_red));
302         int const green = int(fl_get_slider_value(rgb_->slider_green));
303         int const blue  = int(fl_get_slider_value(rgb_->slider_blue));
304
305         color_ = RGBColor(red, green, blue);
306
307         fl_freeze_form(dialog_->form);
308
309         fl_set_object_label(dialog_->text_color_values,
310                             fillLabel(color_).c_str());
311
312         fl_mapcolor(GUI_COLOR_CHOICE, color_.r, color_.g, color_.b);
313         fl_redraw_object(dialog_->button_color);
314
315         fl_unfreeze_form(dialog_->form);
316 }
317
318
319 void FormColorpicker::InputHSV()
320 {
321         double const hue = fl_get_dial_value(hsv_->dial_hue);
322         double const sat = fl_get_slider_value(hsv_->slider_saturation);
323         double const val = fl_get_slider_value(hsv_->slider_value);
324
325         HSVColor hsv = HSVColor(hue, sat, val);
326         color_ = hsv;
327
328         fl_freeze_form(dialog_->form);
329
330         fl_set_object_label(dialog_->text_color_values, fillLabel(hsv).c_str());
331
332         fl_mapcolor(GUI_COLOR_CHOICE, color_.r, color_.g, color_.b);
333         fl_redraw_object(dialog_->button_color);
334
335         RGBColor col = HSVColor(hue, 1.0, 1.0);
336         col.r = std::max(col.r, 0u);
337         fl_mapcolor(GUI_COLOR_HUE_DIAL, col.r, col.g, col.b);
338         fl_redraw_object(hsv_->dial_hue);
339
340         fl_unfreeze_form(dialog_->form);
341 }
342
343
344 extern "C" {
345
346 void C_FormColorpickerInputCB(FL_OBJECT * ob, long d)
347 {
348         BOOST_ASSERT(ob && ob->form && ob->form->u_vdata);
349         FormColorpicker * ptr =
350                 static_cast<FormColorpicker *>(ob->form->u_vdata);
351         ptr->input(ob, d);
352 }
353
354
355 static int C_WMHideCB(FL_FORM * form, void *)
356 {
357         // Close the dialog cleanly, even if the WM is used to do so.
358         BOOST_ASSERT(form && form->u_vdata);
359         FormColorpicker * ptr = static_cast<FormColorpicker *>(form->u_vdata);
360         ptr->input(0, 0);
361         return FL_CANCEL;
362 }
363
364 } // extern "C"