2 * Combox: A combination of two objects (a button and a browser) is
3 * encapsulated to get a combobox-like object. All XForms
4 * functions are hidden.
6 * GNU Copyleft 1996 Alejandro Aguilar Sierra <asierra@servidor.unam.mx>
9 * Dependencies: Only XForms, but created to be used with LyX.
15 * 2/06/1996, Alejandro Aguilar Sierra
18 * 4/06/1996, Alejandro Aguilar Sierra
19 * Added droplist mode (a button with a black down arrow at right)
20 * and support for middle and right buttons, as XForms choice object.
22 * 6/06/1996, Lars Gullik Bjønnes
23 * Added a combox with an input object. and a pre and a post handle.
25 * 22/07/96, Alejandro Aguilar Sierra
26 * Assigned to the browser its own popup window. No more need of
27 * external pre and post handlers to simulate the wanted behaviour.
34 #pragma implementation
44 // These are C wrappers around static members of Combox, used as
45 // callbacks for xforms.
49 void C_Combox_input_cb(FL_OBJECT * ob, long data)
51 Combox::input_cb(ob, data);
55 void C_Combox_combo_cb(FL_OBJECT * ob, long data)
57 Combox::combo_cb(ob, data);
61 int C_Combox_peek_event(FL_FORM * form, void *xev)
63 return Combox::peek_event(form, xev);
69 Combox::Combox(combox_type t)
70 : type(t), tabfolder1(0), tabfolder2(0)
91 if (browser) fl_clear_browser(browser);
93 if (type == FL_COMBOX_INPUT)
94 fl_set_input(label, "");
96 fl_set_object_label(label, "");
101 void Combox::remove()
103 lyxerr[Debug::GUI] << "Button: " << button << endl;
105 fl_delete_object(button);
106 fl_free_object(button);
109 lyxerr[Debug::GUI] << "Label: " << label << endl;
110 if (label && label != button) {
111 fl_delete_object(label);
112 fl_free_object(label);
115 lyxerr[Debug::GUI] << "Form: " << form << endl;
116 lyxerr[Debug::GUI] << "Browser: " << browser << endl;
117 if (form && browser) {
118 fl_delete_object(browser);
119 fl_free_object(browser);
131 void Combox::addline(string const & text)
133 if (!browser) return;
134 fl_add_browser_line(browser, text.c_str());
136 // By default the first item is selected
139 if (type == FL_COMBOX_INPUT)
140 fl_set_input(label, text.c_str());
142 fl_set_object_label(label, text.c_str());
148 bool Combox::select(string const & t)
150 if (!browser || t.empty()) return false;
151 int const maxline = fl_get_browser_maxline(browser);
153 for (int i = 1; i <= maxline; ++i) {
154 if (t == fl_get_browser_line(browser, i)) {
159 return false; // t does not exist in browser
163 void Combox::select(int i)
165 if (!browser || !button) return;
166 if (i > 0 && i <= fl_get_browser_maxline(browser)) sel = i;
167 fl_deactivate_object(button);
169 if (type == FL_COMBOX_INPUT)
170 fl_set_input(label, fl_get_browser_line(browser, sel));
172 fl_set_object_label(label, fl_get_browser_line(browser, sel));
173 fl_activate_object(button);
177 void Combox::add(int x, int y, int w, int hmin, int hmax,
178 FL_OBJECT * tabfolder1_, FL_OBJECT * tabfolder2_)
180 // Store these for later use in working round an xforms bug in show()
181 tabfolder1 = tabfolder1_;
182 tabfolder2 = tabfolder2_;
187 case FL_COMBOX_DROPLIST:
189 button = obj = fl_add_button(FL_NORMAL_BUTTON,
190 x+w-22, y, 22, hmin, "@2->");
191 fl_set_object_color(obj, FL_MCOL, FL_MCOL);
192 fl_set_object_dblbuffer(obj, 1);
193 fl_set_object_callback(obj, C_Combox_combo_cb, 0);
194 label = obj = fl_add_button(FL_NORMAL_TEXT, x, y, w-22, hmin, "");
195 fl_set_object_boxtype(obj, FL_DOWN_BOX);
196 fl_set_object_color(obj, FL_MCOL, FL_BLACK);
197 fl_set_object_lalign(obj, FL_ALIGN_CENTER|FL_ALIGN_INSIDE);
198 fl_set_object_dblbuffer(obj, 1);
199 fl_set_object_callback(obj, C_Combox_combo_cb, 0);
202 case FL_COMBOX_NORMAL:
204 button = obj = fl_add_button(FL_NORMAL_BUTTON, x, y, w, hmin, "");
205 fl_set_object_color(obj, FL_MCOL, FL_MCOL);
206 fl_set_object_boxtype(obj, FL_DOWN_BOX);
207 fl_set_object_callback(obj, C_Combox_combo_cb, 0);
208 fl_set_object_color(obj, FL_MCOL, FL_BLACK);
212 case FL_COMBOX_INPUT:
214 button = obj = fl_add_button(FL_NORMAL_BUTTON,
215 x+w-22, y, 22, hmin, "@2->");
216 fl_set_object_color(obj, FL_MCOL, FL_MCOL);
217 fl_set_object_callback(obj, C_Combox_combo_cb, 0);
218 label = obj = fl_add_input(FL_NORMAL_INPUT, x, y, w-22, hmin, "");
219 fl_set_object_boxtype(obj, FL_DOWN_BOX);
220 fl_set_object_return(obj, FL_RETURN_END_CHANGED);
221 fl_set_object_callback(obj, C_Combox_input_cb, 0);
222 //fl_set_object_color(obj, FL_MCOL, FL_BLACK);
223 //fl_set_object_lalign(obj,FL_ALIGN_CENTER|FL_ALIGN_INSIDE);
228 label->u_vdata = this;
229 button->u_vdata = this;
231 // Hmm, it seems fl_create_browser is broken in xforms 0.86.
232 // We have to work around that by creating the dropped browser form
233 // at this point already. However, this means that we have
234 // to do a little hacking: (Asger)
235 FL_FORM * current_form = fl_current_form;
238 bw = w + 20; bh = hmax - hmin - 12;
240 form = fl_bgn_form(FL_NO_BOX, bw, bh);
241 browser = obj = fl_add_browser(FL_HOLD_BROWSER, 0, 0, bw, bh, "");
242 fl_set_object_boxtype(obj, FL_UP_BOX);
243 fl_set_object_color(obj, FL_MCOL, FL_YELLOW);
244 fl_set_object_gravity(obj, NorthWestGravity, NorthWestGravity);
245 fl_set_object_callback(obj, C_Combox_combo_cb, 2);
247 browser->u_vdata = this;
248 form->u_vdata = browser;
249 fl_register_raw_callback(form,
250 ButtonPressMask|KeyPressMask,
251 C_Combox_peek_event);
253 // And revert to adding to the old form (Asger)
254 fl_addto_form(current_form);
265 void Combox::redraw()
267 if (browser) fl_redraw_object(browser);
268 if (button) fl_redraw_object(button);
269 if (label) fl_redraw_object(label);
277 XGetInputFocus(fl_get_display(), &save_window, &tmp); //BUG-Fix Dietmar
278 XFlush(fl_get_display());
279 if (button && type != FL_COMBOX_NORMAL) {
280 fl_set_object_label(button, "@2<-");
281 fl_redraw_object(button);
285 int y = label->y + label->h;
287 // This is a bug work around suggested by Steve Lamont on the
288 // xforms mailing list. It correctly positions the browser form
289 // after the main window has been moved.
290 // The bug only occurs in tabbed folders.
291 int folder_x, folder_y, folder_w, folder_h;
292 fl_get_folder_area( tabfolder1,
293 &folder_x, &folder_y,
294 &folder_w, &folder_h );
299 fl_get_folder_area( tabfolder2,
300 &folder_x, &folder_y,
301 &folder_w, &folder_h );
302 x += tabfolder2->form->x + folder_x;
303 y += tabfolder2->form->y + folder_y;
305 x += tabfolder1->form->x;
306 y += tabfolder1->form->y;
314 fl_set_form_position(form, x, y);
315 fl_show_form(form, FL_PLACE_POSITION, FL_NOBORDER, "");
317 fl_set_browser_topline(browser, sel);
318 fl_select_browser_line(browser, sel);
320 XGrabPointer(fl_get_display(), form->window, false,
321 ButtonPressMask | ButtonReleaseMask | PointerMotionMask,
322 GrabModeAsync, GrabModeAsync,
324 XFlush(fl_get_display());
327 void Combox::hide(int who)
329 if (!who && browser && label) {
330 sel = fl_get_browser(browser);
332 if (type == FL_COMBOX_INPUT)
333 fl_set_input(label, fl_get_browser_line(browser, sel));
335 fl_set_object_label(label,
336 fl_get_browser_line(browser, sel));
337 // if (callback) callback(sel, cb_arg);
339 XUngrabPointer(fl_get_display(), 0);
340 XFlush(fl_get_display());
343 XSetInputFocus(fl_get_display(), save_window,
344 RevertToParent, CurrentTime); // BUG-FIX-Dietmar
345 XFlush(fl_get_display());
348 if (type != FL_COMBOX_NORMAL){
349 fl_set_object_label(button, "@2->");
350 fl_redraw_object(button);
353 if (!who && browser && label && callback)
354 callback(sel, cb_arg, this);
359 void Combox::activate()
361 if (browser) fl_activate_object(browser);
362 if (button) fl_activate_object(button);
363 if (label) fl_activate_object(label);
367 void Combox::deactivate()
369 if (browser) fl_deactivate_object(browser);
370 if (button) fl_deactivate_object(button);
371 if (label) fl_deactivate_object(label);
375 void Combox::input_cb(FL_OBJECT * ob, long)
377 Combox * combo = static_cast<Combox*>(ob->u_vdata);
379 char const * text = fl_get_input(ob);
381 combo->addto(text ? string(text) : string());
382 combo->is_empty = false;
386 void Combox::combo_cb(FL_OBJECT * ob, long data)
388 Combox * combo = static_cast<Combox*>(ob->u_vdata);
392 int const i = combo->get();
393 switch (fl_get_button_numb(ob)) {
396 combo->select(i - 1);
398 combo->callback(combo->sel,
399 combo->cb_arg, combo);
404 combo->select(i + 1);
406 combo->callback(combo->sel,
407 combo->cb_arg, combo);
410 default: combo->show(); break;
421 int Combox::peek_event(FL_FORM * form, void * xev)
423 FL_OBJECT * ob = static_cast<FL_OBJECT *>(form->u_vdata);
424 Combox * combo = static_cast<Combox*>(ob->u_vdata);
426 // I don't know why belowmouse does not work, but it doesn't. (Asger)
427 // Are we sure? Please verify. (Lgb)
428 if (static_cast<XEvent *>(xev)->type == ButtonPress && (
429 static_cast<XEvent *>(xev)->xbutton.x - ob->x < 0 ||
430 static_cast<XEvent *>(xev)->xbutton.x - ob->x > ob->w ||
431 static_cast<XEvent *>(xev)->xbutton.y - ob->y < 0 ||
432 static_cast<XEvent *>(xev)->xbutton.y - ob->y > ob->h)) {
437 if (static_cast<XEvent*>(xev)->type != KeyPress) return 0;
439 char s_r[10]; s_r[9] = '\0';
440 KeySym keysym_return;
441 XLookupString(&static_cast<XEvent*>(xev)->xkey, s_r, 10,
443 XFlush(fl_get_display());
444 switch (keysym_return) {
446 if (fl_get_browser(combo->browser) <
447 fl_get_browser_maxline(combo->browser))
448 fl_select_browser_line(combo->browser,
449 fl_get_browser(combo->browser)+1);
450 if (fl_get_browser(combo->browser)>=
451 fl_get_browser_topline(combo->browser) +
452 fl_get_browser_screenlines(combo->browser))
453 fl_set_browser_topline(combo->browser,
454 fl_get_browser(combo->browser)
455 - fl_get_browser_screenlines(combo->browser)+1);
456 if (fl_get_browser(combo->browser)<
457 fl_get_browser_topline(combo->browser))
458 fl_set_browser_topline(combo->browser,
459 fl_get_browser(combo->browser));
462 if (fl_get_browser(combo->browser) > 1)
463 fl_select_browser_line(combo->browser,
464 fl_get_browser(combo->browser)-1);
465 if (fl_get_browser(combo->browser)>=
466 fl_get_browser_topline(combo->browser) +
467 fl_get_browser_screenlines(combo->browser))
468 fl_set_browser_topline(combo->browser,
469 fl_get_browser(combo->browser)
470 - fl_get_browser_screenlines(combo->browser)+1);
471 if (fl_get_browser(combo->browser) <
472 fl_get_browser_topline(combo->browser))
473 fl_set_browser_topline(combo->browser,
474 fl_get_browser(combo->browser));
495 //Combox combo(FL_COMBOX_DROPLIST);
496 Combox combo(FL_COMBOX_INPUT);
500 FD_test *create_form_test(void)
503 FD_test *fdui = (FD_test *) fl_calloc(1, sizeof(*fdui));
505 fdui->test = fl_bgn_form(FL_NO_BOX, 320, 190);
506 obj = fl_add_box(FL_UP_BOX, 0, 0, 320, 190, "");
507 obj = fl_add_box(FL_DOWN_BOX, 10, 50, 300, 110, "");
508 obj = fl_add_button(FL_NORMAL_BUTTON, 250, 10, 50, 30, _("Done"));
509 combo.add(10, 15, 120, 25, 135);
517 fprintf(stderr, "selected %d:%s\n", i, combo.getline());
520 int main(int argc, char *argv[])
524 // Same defaults as in lyx
526 cntl.buttonFontSize = FL_NORMAL_SIZE;
527 cntl.browserFontSize = FL_NORMAL_SIZE;
528 cntl.labelFontSize = FL_NORMAL_SIZE;
529 cntl.choiceFontSize = FL_NORMAL_SIZE;
530 cntl.inputFontSize = FL_NORMAL_SIZE;
531 cntl.borderWidth = -2;
532 fl_set_defaults(FL_PDButtonFontSize, &cntl);
533 fl_set_defaults(FL_PDBrowserFontSize, &cntl);
534 fl_set_defaults(FL_PDLabelFontSize, &cntl);
535 fl_set_defaults(FL_PDChoiceFontSize, &cntl);
536 fl_set_defaults(FL_PDInputFontSize, &cntl);
537 fl_set_defaults(FL_PDBorderWidth, &cntl);
538 fl_initialize(&argc, argv, 0, 0, 0);
540 fd_test = create_form_test();
542 /* fill-in form initialization code */
543 combo.addline("Title");
544 combo.addline("Author");
545 combo.addline("Date");
546 combo.addline("Abstract");
547 combo.addline("Chapter");
548 combo.addline("Section");
549 combo.addline("Subsection");
550 combo.addline("List");
551 combo.addline("Description");
552 combo.addline("Verse");
553 combo.addline("Verbatim");
554 combo.setcallback(combo_cb);
557 /* show the first form */
558 fl_show_form(fd_test->test, FL_PLACE_CENTER, FL_FULLBORDER, "test");