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