3 * This file is part of LyX, the document processor.
4 * Licence details can be found in the file COPYING.
6 * \author Angus Leeming
8 * Full author contact details are available in file CREDITS
14 #pragma implementation
19 #include "ControlButtons.h"
21 #include "xforms_resize.h"
23 #include "xforms_helpers.h" // formatted
25 #include "gettext.h" // _()
26 #include "BoostFormat.h"
28 #include "support/LAssert.h"
29 #include "support/filetools.h" // LibFileSearch
31 #include FORMS_H_LOCATION
35 // These should be in forms.h but aren't
36 void fl_show_tooltip(const char *, int, int);
38 void fl_hide_tooltip();
40 // Callback function invoked by xforms when the dialog is closed by the
42 static int C_WMHideCB(FL_FORM * form, void *);
44 // Callback function invoked by the xforms pre-handler routine.
45 static int C_PrehandlerCB(FL_OBJECT *, int, FL_Coord, FL_Coord, int, void *);
50 FormBase::FormBase(string const & t, bool allowResize)
52 warning_posted_(false), message_widget_(0),
53 minw_(0), minh_(0), allow_resize_(allowResize),
54 title_(t), icon_pixmap_(0), icon_mask_(0),
55 tooltips_(new Tooltips())
62 XFreePixmap(fl_get_display(), icon_pixmap_);
68 Tooltips & FormBase::tooltips()
74 void FormBase::redraw()
76 if (form() && form()->visible)
77 fl_redraw_form(form());
81 xformsBC & FormBase::bc()
83 return static_cast<xformsBC &>(getController().bc());
84 // return dynamic_cast<GUIbc &>(controller_ptr_->bc());
88 void FormBase::prepare_to_show()
90 double const scale = get_scale_to_fit(form());
92 scale_form_horizontally(form(), scale);
94 // work around dumb xforms sizing bug
98 fl_set_form_atclose(form(), C_WMHideCB, 0);
100 // set the title for the minimized form
101 if (!getController().IconifyWithMain())
102 fl_winicontitle(form()->window, title_.c_str());
104 // assign an icon to the form
105 string const iconname = LibFileSearch("images", "lyx", "xpm");
106 if (!iconname.empty()) {
108 icon_pixmap_ = fl_read_pixmapfile(fl_root,
114 fl_set_form_icon(form(), icon_pixmap_, icon_mask_);
119 void FormBase::show()
121 // build() is/should be called from the controller, so form() should
125 // we use minw_ to flag whether the dialog has ever been shown.
126 // In turn, prepare_to_show() initialises various bits 'n' pieces
127 // (including minw_).
132 // make sure the form is up to date.
133 fl_freeze_form(form());
135 fl_unfreeze_form(form());
137 if (form()->visible) {
138 fl_raise_form(form());
139 /* This XMapWindow() will hopefully ensure that
140 * iconified dialogs are de-iconified. Mad props
141 * out to those crazy Xlib guys for forgetting a
142 * XDeiconifyWindow(). At least WindowMaker, when
143 * being notified of the redirected MapRequest will
144 * specifically de-iconify. From source, fvwm2 seems
147 XMapWindow(fl_get_display(), form()->window);
149 // calls to fl_set_form_minsize/maxsize apply only to the next
150 // fl_show_form(), so this comes first.
151 fl_set_form_minsize(form(), minw_, minh_);
153 fl_set_form_maxsize(form(), minw_, minh_);
155 string const maximize_title = "LyX: " + title_;
156 int const iconify_policy =
157 getController().IconifyWithMain() ? FL_TRANSIENT : 0;
160 FL_PLACE_MOUSE | FL_FREE_SIZE,
162 maximize_title.c_str());
167 void FormBase::hide()
170 // Does no harm if none is visible and ensures that the tooltip form
171 // is hidden should the dialog be closed from the keyboard.
175 // xforms sometimes tries to process a hint-type MotionNotify, and
176 // use XQueryPointer, without verifying if the window still exists.
177 // So we try to clear out motion events in the queue before the
179 XSync(fl_get_display(), false);
181 if (form() && form()->visible)
182 fl_hide_form(form());
186 void FormBase::setPrehandler(FL_OBJECT * ob)
189 fl_set_object_prehandler(ob, C_PrehandlerCB);
193 void FormBase::setMessageWidget(FL_OBJECT * ob)
195 lyx::Assert(ob && ob->objclass == FL_TEXT);
196 message_widget_ = ob;
197 fl_set_object_lsize(message_widget_, FL_NORMAL_SIZE);
201 void FormBase::InputCB(FL_OBJECT * ob, long data)
203 // It is possible to set the choice to 0 when using the
204 // keyboard shortcuts. This work-around deals with the problem.
205 if (ob && ob->objclass == FL_CHOICE && fl_get_choice(ob) < 1) {
206 fl_set_choice(ob, 1);
209 bc().input(input(ob, data));
213 ButtonPolicy::SMInput FormBase::input(FL_OBJECT *, long)
215 return ButtonPolicy::SMI_VALID;
219 // preemptive handler for feedback messages
220 void FormBase::MessageCB(FL_OBJECT * ob, int event)
227 string const feedback = getFeedback(ob);
228 if (feedback.empty() && warning_posted_)
231 warning_posted_ = false;
232 postMessage(getFeedback(ob));
237 if (!warning_posted_)
247 void FormBase::PrehandlerCB(FL_OBJECT * ob, int event, int key)
251 if (ob->objclass == FL_INPUT && event == FL_PUSH && key == 2) {
252 // Trigger an input event when pasting in an xforms input object
253 // using the middle mouse button.
261 if (message_widget_) {
262 // Post feedback as the mouse enters the object,
263 // remove it as the mouse leaves.
264 MessageCB(ob, event);
268 if (ob->objclass == FL_TABFOLDER) {
269 // This prehandler is used to work-around an xforms
270 // bug and ensures that the form->x, form->y coords of
271 // the active tabfolder are up to date.
273 // The tabfolder itself can be very narrow, being just
274 // the visible border to the tabs.
275 // We thus use both FL_ENTER and FL_LEAVE as flags,
276 // in case the FL_ENTER event is not caught.
278 FL_FORM * const folder = fl_get_active_folder(ob);
279 if (folder && folder->window) {
280 fl_get_winorigin(folder->window,
281 &(folder->x), &(folder->y));
288 // Tooltips are not displayed on browser widgets due to an xforms' bug.
289 // I have a fix, but it's not yet in the xforms sources.
290 // This is a work-around:
293 if (ob->objclass == FL_BROWSER &&
294 ob->tooltip && *(ob->tooltip)) {
295 int const x = ob->form->x + ob->x;
296 int const y = ob->form->y + ob->y + ob->h + 1;
297 fl_show_tooltip(ob->tooltip, x, y);
303 if (ob->objclass == FL_BROWSER)
310 void FormBase::postWarning(string const & warning)
312 warning_posted_ = true;
313 postMessage(warning);
317 void FormBase::clearMessage()
319 lyx::Assert(message_widget_);
321 warning_posted_ = false;
323 string const existing = message_widget_->label
324 ? message_widget_->label : string();
325 if (existing.empty())
328 // This trick is needed to get xforms to clear the label...
329 fl_set_object_label(message_widget_, "");
330 fl_hide_object(message_widget_);
334 void FormBase::postMessage(string const & message)
336 lyx::Assert(message_widget_);
338 int const width = message_widget_->w - 10;
340 boost::format fmter = warning_posted_ ?
341 boost::format(_("WARNING! %1$s")) :
342 boost::format("%1$s");
344 string const str = formatted(boost::io::str(fmter % message),
345 width, FL_NORMAL_SIZE);
347 string const tmp = warning_posted_ ?
348 _("WARNING!") + string(" ") + message :
351 string const str = formatted(tmp, width, FL_NORMAL_SIZE);
354 fl_set_object_label(message_widget_, str.c_str());
355 FL_COLOR const label_color = warning_posted_ ? FL_RED : FL_LCOL;
356 fl_set_object_lcol(message_widget_, label_color);
358 if (!message_widget_->visible)
359 fl_show_object(message_widget_);
365 FormBase * GetForm(FL_OBJECT * ob)
367 lyx::Assert(ob && ob->form && ob->form->u_vdata);
368 FormBase * ptr = static_cast<FormBase *>(ob->form->u_vdata);
377 void C_FormBaseApplyCB(FL_OBJECT * ob, long)
379 GetForm(ob)->getController().ApplyButton();
383 void C_FormBaseOKCB(FL_OBJECT * ob, long)
385 GetForm(ob)->getController().OKButton();
389 void C_FormBaseCancelCB(FL_OBJECT * ob, long)
391 FormBase * form = GetForm(ob);
392 form->getController().CancelButton();
396 void C_FormBaseRestoreCB(FL_OBJECT * ob, long)
398 GetForm(ob)->getController().RestoreButton();
402 void C_FormBaseInputCB(FL_OBJECT * ob, long d)
404 GetForm(ob)->InputCB(ob, d);
408 static int C_WMHideCB(FL_FORM * form, void *)
410 // Close the dialog cleanly, even if the WM is used to do so.
411 lyx::Assert(form && form->u_vdata);
412 FormBase * ptr = static_cast<FormBase *>(form->u_vdata);
413 ptr->getController().CancelButton();
417 static int C_PrehandlerCB(FL_OBJECT * ob, int event,
418 FL_Coord, FL_Coord, int key, void *)
420 // Note that the return value is important in the pre-emptive handler.
421 // Don't return anything other than 0.
424 // Don't Assert this one, as it can happen quite naturally when things
425 // are being deleted in the d-tor.
427 if (!ob->form) return 0;
429 FormBase * ptr = static_cast<FormBase *>(ob->form->u_vdata);
432 ptr->PrehandlerCB(ob, event, key);