3 * Copyright 1996Alejandro Aguilar Sierra
4 * This file is part of LyX, the document processor.
5 * Licence details can be found in the file COPYING.
7 * \author Alejandro Aguilar Sierra
9 * Full author contact details are available in file CREDITS
12 /* A combination of two objects (a button and a browser) is encapsulated to
13 * get a combobox-like object. All XForms functions are hidden.
19 * 2/06/1996, Alejandro Aguilar Sierra
22 * 4/06/1996, Alejandro Aguilar Sierra
23 * Added droplist mode (a button with a black down arrow at right)
24 * and support for middle and right buttons, as XForms choice object.
26 * 6/06/1996, Lars Gullik Bjønnes
27 * Added a combox with an input object. and a pre and a post handle.
29 * 22/07/96, Alejandro Aguilar Sierra
30 * Assigned to the browser its own popup window. No more need of
31 * external pre and post handlers to simulate the wanted behaviour.
38 #pragma implementation
48 // These are C wrappers around static members of Combox, used as
49 // callbacks for xforms.
53 void C_Combox_input_cb(FL_OBJECT * ob, long data)
55 Combox::input_cb(ob, data);
59 void C_Combox_combo_cb(FL_OBJECT * ob, long data)
61 Combox::combo_cb(ob, data);
65 int C_Combox_peek_event(FL_FORM * form, void *xev)
67 return Combox::peek_event(form, xev);
73 Combox::Combox(combox_type t)
89 // This is now handled by the XFormsView destructor (Lgb)
96 if (browser) fl_clear_browser(browser);
98 if (type == FL_COMBOX_INPUT)
99 fl_set_input(label, "");
101 fl_set_object_label(label, "");
106 void Combox::remove()
108 lyxerr[Debug::GUI] << "Button: " << button << endl;
110 fl_delete_object(button);
111 fl_free_object(button);
114 lyxerr[Debug::GUI] << "Label: " << label << endl;
115 if (label && label != button) {
116 fl_delete_object(label);
117 fl_free_object(label);
120 lyxerr[Debug::GUI] << "Form: " << form << endl;
121 lyxerr[Debug::GUI] << "Browser: " << browser << endl;
122 if (form && browser) {
123 fl_delete_object(browser);
124 fl_free_object(browser);
136 void Combox::addline(string const & text)
138 if (!browser) return;
139 fl_add_browser_line(browser, text.c_str());
141 // By default the first item is selected
144 if (type == FL_COMBOX_INPUT)
145 fl_set_input(label, text.c_str());
147 fl_set_object_label(label, text.c_str());
153 bool Combox::select(string const & t)
155 if (!browser || t.empty()) return false;
156 int const maxline = fl_get_browser_maxline(browser);
158 for (int i = 1; i <= maxline; ++i) {
159 if (t == fl_get_browser_line(browser, i)) {
164 return false; // t does not exist in browser
168 void Combox::select(int i)
170 if (!browser || !button) return;
171 if (i > 0 && i <= fl_get_browser_maxline(browser)) sel = i;
172 fl_deactivate_object(button);
174 if (type == FL_COMBOX_INPUT)
175 fl_set_input(label, fl_get_browser_line(browser, sel));
177 fl_set_object_label(label, fl_get_browser_line(browser, sel));
178 fl_activate_object(button);
182 void Combox::add(int x, int y, int w, int hmin, int hmax)
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;
239 bh = hmax - hmin - 12;
241 form = fl_bgn_form(FL_NO_BOX, bw, bh);
242 browser = obj = fl_add_browser(FL_HOLD_BROWSER, 0, 0, bw, bh, "");
243 fl_set_object_boxtype(obj, FL_UP_BOX);
244 fl_set_object_color(obj, FL_MCOL, FL_YELLOW);
245 fl_set_object_gravity(obj, NorthWestGravity, NorthWestGravity);
246 fl_set_object_callback(obj, C_Combox_combo_cb, 2);
248 browser->u_vdata = this;
249 form->u_vdata = browser;
250 fl_register_raw_callback(form,
251 ButtonPressMask|KeyPressMask,
252 C_Combox_peek_event);
254 // And revert to adding to the old form (Asger)
255 fl_addto_form(current_form);
266 void Combox::redraw()
268 if (browser) fl_redraw_object(browser);
269 if (button) fl_redraw_object(button);
270 if (label) fl_redraw_object(label);
278 XGetInputFocus(fl_get_display(), &save_window, &tmp); //BUG-Fix Dietmar
279 XFlush(fl_get_display());
280 if (button && type != FL_COMBOX_NORMAL) {
281 fl_set_object_label(button, "@2<-");
282 fl_redraw_object(button);
285 // This fix ensures that, even if label lies on a tabfolder,
286 // the x,y coords of the underlying form are up to date.
287 // It should be rendered redundant by a similar fix in the
288 // tabfolder prehandler, but apparently "enter" events are not always
290 // Angus 4 Oct, 2002.
291 if (label->form->window) {
292 FL_FORM * lf = label->form;
293 fl_get_winorigin(lf->window, &(lf->x), &(lf->y));
296 int const x = label->form->x + label->x;
297 int const y = label->form->y + label->y + label->h;
299 fl_set_form_position(form, x, y);
300 fl_show_form(form, FL_PLACE_POSITION, FL_NOBORDER, "");
302 fl_set_browser_topline(browser, sel);
303 fl_select_browser_line(browser, sel);
305 XGrabPointer(fl_get_display(), form->window, false,
306 ButtonPressMask | ButtonReleaseMask | PointerMotionMask,
307 GrabModeAsync, GrabModeAsync,
309 XFlush(fl_get_display());
312 void Combox::hide(int who)
314 if (!who && browser && label) {
315 sel = fl_get_browser(browser);
317 if (type == FL_COMBOX_INPUT)
318 fl_set_input(label, fl_get_browser_line(browser, sel));
320 fl_set_object_label(label,
321 fl_get_browser_line(browser, sel));
322 // if (callback) callback(sel, cb_arg);
324 XUngrabPointer(fl_get_display(), 0);
325 XFlush(fl_get_display());
328 XSetInputFocus(fl_get_display(), save_window,
329 RevertToParent, CurrentTime); // BUG-FIX-Dietmar
330 XFlush(fl_get_display());
333 if (type != FL_COMBOX_NORMAL) {
334 fl_set_object_label(button, "@2->");
335 fl_redraw_object(button);
338 if (!who && browser && label && callback)
339 callback(sel, cb_arg, this);
344 void Combox::activate()
347 fl_activate_object(browser);
349 fl_activate_object(button);
350 fl_set_object_lcol(button, FL_BLACK);
353 fl_activate_object(label);
354 fl_set_object_lcol(label, FL_BLACK);
359 void Combox::deactivate()
362 fl_deactivate_object(browser);
364 fl_deactivate_object(button);
365 fl_set_object_lcol(button, FL_INACTIVE);
368 fl_deactivate_object(label);
369 fl_set_object_lcol(label, FL_INACTIVE);
374 void Combox::input_cb(FL_OBJECT * ob, long)
376 Combox * combo = static_cast<Combox*>(ob->u_vdata);
378 char const * text = fl_get_input(ob);
380 combo->addto(text ? string(text) : string());
381 combo->is_empty = false;
385 void Combox::combo_cb(FL_OBJECT * ob, long data)
387 Combox * combo = static_cast<Combox*>(ob->u_vdata);
391 int const i = combo->get();
392 switch (fl_get_button_numb(ob)) {
395 combo->select(i - 1);
397 combo->callback(combo->sel,
398 combo->cb_arg, combo);
403 combo->select(i + 1);
405 combo->callback(combo->sel,
406 combo->cb_arg, combo);
409 default: combo->show(); break;
420 int Combox::peek_event(FL_FORM * form, void * xev)
422 FL_OBJECT * ob = static_cast<FL_OBJECT *>(form->u_vdata);
423 Combox * combo = static_cast<Combox*>(ob->u_vdata);
425 // below mouse does not work like we need it
426 if (static_cast<XEvent *>(xev)->type == ButtonPress && (
427 static_cast<XEvent *>(xev)->xbutton.x - ob->x < 0 ||
428 static_cast<XEvent *>(xev)->xbutton.x - ob->x > ob->w ||
429 static_cast<XEvent *>(xev)->xbutton.y - ob->y < 0 ||
430 static_cast<XEvent *>(xev)->xbutton.y - ob->y > ob->h)) {
435 if (static_cast<XEvent*>(xev)->type != KeyPress) return 0;
437 char s_r[10]; s_r[9] = '\0';
438 KeySym keysym_return;
439 XLookupString(&static_cast<XEvent*>(xev)->xkey, s_r, 10,
441 XFlush(fl_get_display());
442 switch (keysym_return) {
447 if (fl_get_browser(combo->browser) <
448 fl_get_browser_maxline(combo->browser))
449 fl_select_browser_line(combo->browser,
450 fl_get_browser(combo->browser)+1);
451 if (fl_get_browser(combo->browser)>=
452 fl_get_browser_topline(combo->browser) +
453 fl_get_browser_screenlines(combo->browser))
454 fl_set_browser_topline(combo->browser,
455 fl_get_browser(combo->browser)
456 - fl_get_browser_screenlines(combo->browser)+1);
457 if (fl_get_browser(combo->browser)<
458 fl_get_browser_topline(combo->browser))
459 fl_set_browser_topline(combo->browser,
460 fl_get_browser(combo->browser));
466 if (fl_get_browser(combo->browser) > 1)
467 fl_select_browser_line(combo->browser,
468 fl_get_browser(combo->browser)-1);
469 if (fl_get_browser(combo->browser)>=
470 fl_get_browser_topline(combo->browser) +
471 fl_get_browser_screenlines(combo->browser))
472 fl_set_browser_topline(combo->browser,
473 fl_get_browser(combo->browser)
474 - fl_get_browser_screenlines(combo->browser)+1);
475 if (fl_get_browser(combo->browser) <
476 fl_get_browser_topline(combo->browser))
477 fl_set_browser_topline(combo->browser,
478 fl_get_browser(combo->browser));
502 //Combox combo(FL_COMBOX_DROPLIST);
503 Combox combo(FL_COMBOX_INPUT);
507 FD_test *create_form_test(void)
510 FD_test *fdui = (FD_test *) fl_calloc(1, sizeof(*fdui));
512 fdui->test = fl_bgn_form(FL_NO_BOX, 320, 190);
513 obj = fl_add_box(FL_UP_BOX, 0, 0, 320, 190, "");
514 obj = fl_add_box(FL_DOWN_BOX, 10, 50, 300, 110, "");
515 obj = fl_add_button(FL_NORMAL_BUTTON, 250, 10, 50, 30, _("Done"));
516 combo.add(10, 15, 120, 25, 135);
524 fprintf(stderr, "selected %d:%s\n", i, combo.getline());
527 int main(int argc, char *argv[])
531 // Same defaults as in lyx
533 cntl.buttonFontSize = FL_NORMAL_SIZE;
534 cntl.browserFontSize = FL_NORMAL_SIZE;
535 cntl.labelFontSize = FL_NORMAL_SIZE;
536 cntl.choiceFontSize = FL_NORMAL_SIZE;
537 cntl.inputFontSize = FL_NORMAL_SIZE;
538 cntl.borderWidth = -2;
539 fl_set_defaults(FL_PDButtonFontSize, &cntl);
540 fl_set_defaults(FL_PDBrowserFontSize, &cntl);
541 fl_set_defaults(FL_PDLabelFontSize, &cntl);
542 fl_set_defaults(FL_PDChoiceFontSize, &cntl);
543 fl_set_defaults(FL_PDInputFontSize, &cntl);
544 fl_set_defaults(FL_PDBorderWidth, &cntl);
545 fl_initialize(&argc, argv, 0, 0, 0);
547 fd_test = create_form_test();
549 /* fill-in form initialization code */
550 combo.addline("Title");
551 combo.addline("Author");
552 combo.addline("Date");
553 combo.addline("Abstract");
554 combo.addline("Chapter");
555 combo.addline("Section");
556 combo.addline("Subsection");
557 combo.addline("List");
558 combo.addline("Description");
559 combo.addline("Verse");
560 combo.addline("Verbatim");
561 combo.setcallback(combo_cb);
564 /* show the first form */
565 fl_show_form(fd_test->test, FL_PLACE_CENTER, FL_FULLBORDER, "test");