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