]> git.lyx.org Git - lyx.git/blob - src/frontends/xforms/FormBase.C
You want real tooltips too? You got 'em. See the ChangeLog for how to use.
[lyx.git] / src / frontends / xforms / FormBase.C
1 /* This file is part of
2  * ====================================================== 
3  *
4  *           LyX, The Document Processor
5  *
6  *           Copyright 2000-2001 The LyX Team.
7  *
8  * ======================================================
9  *
10  * \author Angus Leeming <a.leeming@ic.ac.uk>
11  */
12
13 #include <config.h>
14
15 #ifdef __GNUG__
16 #pragma implementation
17 #endif
18
19 #include "Dialogs.h"
20 #include "FormBase.h"
21 #include "xformsBC.h"
22 #include "support/LAssert.h"
23
24 #if FL_REVISION < 89
25
26 namespace {
27
28 int TooltipHandler(FL_OBJECT *ob, int event);
29
30 void TooltipTimerCB(FL_OBJECT * timer, long data);
31  
32 }
33
34 extern "C" {
35
36 static int C_FormBaseTooltipHandler(FL_OBJECT * ob, int event,
37                                     FL_Coord, FL_Coord, int, void *)
38 {
39         return TooltipHandler(ob, event);
40 }
41
42 static void C_FormBaseTooltipTimerCB(FL_OBJECT * ob, long data)
43 {
44         TooltipTimerCB(ob, data);
45 }
46
47 }
48  
49 #endif // FL_REVISION < 89
50
51
52 extern "C" {
53
54 // Callback function invoked by xforms when the dialog is closed by the
55 // window manager
56 static int C_FormBaseWMHideCB(FL_FORM * form, void *);
57
58 // Use this to diaplay feedback messages or to trigger an input event on paste
59 // with the middle mouse button
60 static int C_FormBasePrehandler(FL_OBJECT * ob, int event,
61                                 FL_Coord, FL_Coord, int key, void *);
62
63 } // extern "C"
64
65
66 FormBase::FormBase(ControlButtons & c, string const & t, bool allowResize)
67         : ViewBC<xformsBC>(c), minw_(0), minh_(0), allow_resize_(allowResize),
68           title_(t), warning_posted_(false)
69
70 {
71 #if FL_REVISION < 89
72         tooltip_timer_ = 0;
73 #endif
74 }
75
76
77 void FormBase::redraw()
78 {
79         if (form() && form()->visible)
80                 fl_redraw_form(form());
81 }
82
83
84 void FormBase::show()
85 {
86         if (!form()) {
87                 build();
88         }
89
90         // use minw_ to flag whether the dialog has ever been shown
91         // (Needed now that build() is/should be called from the controller)
92         if (minw_ == 0) {
93                 bc().refresh();
94
95                 // work around dumb xforms sizing bug
96                 minw_ = form()->w;
97                 minh_ = form()->h;
98
99                 fl_set_form_atclose(form(), C_FormBaseWMHideCB, 0);
100         }
101
102         fl_freeze_form(form());
103         update();  // make sure its up-to-date
104         fl_unfreeze_form(form());
105
106         if (form()->visible) {
107                 fl_raise_form(form());
108                 /* This XMapWindow() will hopefully ensure that
109                  * iconified dialogs are de-iconified. Mad props
110                  * out to those crazy Xlib guys for forgetting a
111                  * XDeiconifyWindow(). At least WindowMaker, when
112                  * being notified of the redirected MapRequest will
113                  * specifically de-iconify. From source, fvwm2 seems
114                  * to do the same.
115                  */
116                 XMapWindow(fl_get_display(), form()->window);
117         } else {
118                 // calls to fl_set_form_minsize/maxsize apply only to the next
119                 // fl_show_form(), so this comes first.
120                 fl_set_form_minsize(form(), minw_, minh_);
121                 if (!allow_resize_)
122                         fl_set_form_maxsize(form(), minw_, minh_);
123
124                 fl_show_form(form(),
125                         FL_PLACE_MOUSE | FL_FREE_SIZE,
126                         (controller_.IconifyWithMain() ? FL_TRANSIENT : 0),
127                         title_.c_str());
128         }
129 }
130
131
132 void FormBase::hide()
133 {
134         if (form() && form()->visible)
135                 fl_hide_form(form());
136 }
137
138
139 void FormBase::InputCB(FL_OBJECT * ob, long data)
140 {
141         // It is possible to set the choice to 0 when using the
142         // keyboard shortcuts. This work-around deals with the problem.
143         if (ob && ob->objclass == FL_CHOICE && fl_get_choice(ob) < 1) {
144                 fl_set_choice(ob, 1);
145         }
146
147         bc().input(input(ob, data));
148 }
149
150
151 ButtonPolicy::SMInput FormBase::input(FL_OBJECT *, long)
152 {
153         return ButtonPolicy::SMI_VALID;
154 }
155
156
157 // preemptive handler for feedback messages
158 void FormBase::FeedbackCB(FL_OBJECT * ob, int event)
159 {
160         lyx::Assert(ob);
161
162         switch (event) {
163         case FL_ENTER:
164                 warning_posted_ = false;
165                 feedback(ob);
166                 break;
167
168         case FL_LEAVE:
169                 if (!warning_posted_)
170                         clear_feedback();
171                 break;
172
173         default:
174                 break;
175         }
176 }
177
178
179 void FormBase::setTooltipHandler(FL_OBJECT * ob)
180 {
181         lyx::Assert(ob);
182
183 #if FL_REVISION < 89
184         if (!tooltip_timer_) {
185                 fl_addto_form(form());
186                 tooltip_timer_ = fl_add_timer(FL_HIDDEN_TIMER, 0, 0, 0, 0, "");
187                 fl_end_form();
188         }
189
190         fl_set_object_posthandler(ob, C_FormBaseTooltipHandler);
191         ob->u_cdata = reinterpret_cast<char *>(tooltip_timer_);
192
193 #else
194         string const help(getTooltip(ob));
195         if (!help.empty())
196                 fl_set_object_helper(ob, help.c_str()); 
197 #endif // FL_REVISION < 89
198 }
199
200
201 void FormBase::setPrehandler(FL_OBJECT * ob)
202 {
203         lyx::Assert(ob);
204         fl_set_object_prehandler(ob, C_FormBasePrehandler);
205 }
206
207
208 void FormBase::setWarningPosted(bool warning)
209 {
210         warning_posted_ = warning;
211 }
212
213
214 #if FL_REVISION < 89
215
216 string const FormBase::getTooltipCB(FL_OBJECT * ob)
217 {
218         return getTooltip(ob);
219 }
220
221 #endif // FL_REVISION < 89
222
223
224 namespace {
225
226 FormBase * GetForm(FL_OBJECT * ob)
227 {
228         lyx::Assert(ob && ob->form && ob->form->u_vdata);
229         FormBase * pre = static_cast<FormBase *>(ob->form->u_vdata);
230         return pre;
231 }
232
233 } // namespace anon
234
235
236 extern "C" {
237
238 void C_FormBaseApplyCB(FL_OBJECT * ob, long)
239 {
240         GetForm(ob)->ApplyButton();
241 }
242
243
244 void C_FormBaseOKCB(FL_OBJECT * ob, long)
245 {
246         GetForm(ob)->OKButton();
247 }
248
249
250 void C_FormBaseCancelCB(FL_OBJECT * ob, long)
251 {
252         FormBase * form = GetForm(ob);
253         form->CancelButton();
254 }
255
256
257 void C_FormBaseRestoreCB(FL_OBJECT * ob, long)
258 {
259         GetForm(ob)->RestoreButton();
260 }
261
262
263 void C_FormBaseInputCB(FL_OBJECT * ob, long d)
264 {
265         GetForm(ob)->InputCB(ob, d);
266 }
267
268
269 static int C_FormBaseWMHideCB(FL_FORM * form, void *)
270 {
271         // Close the dialog cleanly, even if the WM is used to do so.
272         lyx::Assert(form && form->u_vdata);
273         FormBase * pre = static_cast<FormBase *>(form->u_vdata);
274         pre->CancelButton();
275         return FL_CANCEL;
276 }
277
278
279 static int C_FormBasePrehandler(FL_OBJECT * ob, int event,
280                                 FL_Coord, FL_Coord, int key, void *)
281 {
282         // Note that the return value is important in the pre-emptive handler.
283         // Don't return anything other than 0.
284         lyx::Assert(ob);
285
286         // Don't Assert this one, as it can happen quite naturally when things
287         // are being deleted in the d-tor.
288         //Assert(ob->form);
289         if (!ob->form) return 0;
290
291         FormBase * pre = static_cast<FormBase *>(ob->form->u_vdata);
292         if (!pre) return 0;
293
294         if (event == FL_PUSH && key == 2 && ob->objclass == FL_INPUT) {
295                 // Trigger an input event when pasting in an xforms input object
296                 // using the middle mouse button.
297                 pre->InputCB(ob, 0);
298
299         } else if (event == FL_ENTER || event == FL_LEAVE){
300                 // Post feedback as the mouse enters the object,
301                 // remove it as the mouse leaves.
302                 pre->FeedbackCB(ob, event);
303         }
304
305         return 0;
306 }
307  
308 } // extern "C"
309
310
311 #if FL_REVISION < 89
312
313 namespace {
314
315 void TooltipTimerCB(FL_OBJECT * timer, long data)
316 {
317         FL_OBJECT * ob = reinterpret_cast<FL_OBJECT*>(data);
318         lyx::Assert(ob && ob->form);
319
320         string const help = GetForm(timer)->getTooltipCB(ob);
321         if (help.empty())
322                 return;
323
324         fl_show_oneliner(help.c_str(),
325                          ob->form->x + ob->x,
326                          ob->form->y + ob->y + ob->h);
327 }
328
329
330 // post_handler for bubble-help (Matthias)
331 int TooltipHandler(FL_OBJECT *ob, int event)
332 {
333         lyx::Assert(ob);
334         FL_OBJECT * timer = reinterpret_cast<FL_OBJECT *>(ob->u_cdata);
335         lyx::Assert(timer);
336
337         // We do not test for empty help here, since this can never happen
338         if (event == FL_ENTER){
339                 fl_set_object_callback(timer,
340                                        C_FormBaseTooltipTimerCB,
341                                        reinterpret_cast<long>(ob));
342                 fl_set_timer(timer, 1);
343         }
344         else if (event != FL_MOTION){
345                 fl_set_timer(timer, 0);
346                 fl_hide_oneliner();
347         }
348         return 0;
349 }
350
351 } // namespace anon
352
353 #endif // FL_REVISION < 89