3 * Copyright 1996-2002 The LyX Team.
4 * Copyright 1996Alejandro Aguilar Sierra
5 * See the file COPYING.
7 * \author Alejandro Aguilar Sierra
10 /* A combination of two objects (a button and a browser) is encapsulated to
11 * get a combobox-like object. All XForms functions are hidden.
17 * 2/06/1996, Alejandro Aguilar Sierra
20 * 4/06/1996, Alejandro Aguilar Sierra
21 * Added droplist mode (a button with a black down arrow at right)
22 * and support for middle and right buttons, as XForms choice object.
24 * 6/06/1996, Lars Gullik Bjønnes
25 * Added a combox with an input object. and a pre and a post handle.
27 * 22/07/96, Alejandro Aguilar Sierra
28 * Assigned to the browser its own popup window. No more need of
29 * external pre and post handlers to simulate the wanted behaviour.
36 #pragma implementation
46 // These are C wrappers around static members of Combox, used as
47 // callbacks for xforms.
51 void C_Combox_input_cb(FL_OBJECT * ob, long data)
53 Combox::input_cb(ob, data);
57 void C_Combox_combo_cb(FL_OBJECT * ob, long data)
59 Combox::combo_cb(ob, data);
63 int C_Combox_peek_event(FL_FORM * form, void *xev)
65 return Combox::peek_event(form, xev);
71 Combox::Combox(combox_type t)
72 : type(t), tabfolder1(0), tabfolder2(0)
87 // This is now handled by the XFormsView destructor (Lgb)
94 if (browser) fl_clear_browser(browser);
96 if (type == FL_COMBOX_INPUT)
97 fl_set_input(label, "");
99 fl_set_object_label(label, "");
104 void Combox::remove()
106 lyxerr[Debug::GUI] << "Button: " << button << endl;
108 fl_delete_object(button);
109 fl_free_object(button);
112 lyxerr[Debug::GUI] << "Label: " << label << endl;
113 if (label && label != button) {
114 fl_delete_object(label);
115 fl_free_object(label);
118 lyxerr[Debug::GUI] << "Form: " << form << endl;
119 lyxerr[Debug::GUI] << "Browser: " << browser << endl;
120 if (form && browser) {
121 fl_delete_object(browser);
122 fl_free_object(browser);
134 void Combox::addline(string const & text)
136 if (!browser) return;
137 fl_add_browser_line(browser, text.c_str());
139 // By default the first item is selected
142 if (type == FL_COMBOX_INPUT)
143 fl_set_input(label, text.c_str());
145 fl_set_object_label(label, text.c_str());
151 bool Combox::select(string const & t)
153 if (!browser || t.empty()) return false;
154 int const maxline = fl_get_browser_maxline(browser);
156 for (int i = 1; i <= maxline; ++i) {
157 if (t == fl_get_browser_line(browser, i)) {
162 return false; // t does not exist in browser
166 void Combox::select(int i)
168 if (!browser || !button) return;
169 if (i > 0 && i <= fl_get_browser_maxline(browser)) sel = i;
170 fl_deactivate_object(button);
172 if (type == FL_COMBOX_INPUT)
173 fl_set_input(label, fl_get_browser_line(browser, sel));
175 fl_set_object_label(label, fl_get_browser_line(browser, sel));
176 fl_activate_object(button);
180 void Combox::add(int x, int y, int w, int hmin, int hmax,
181 FL_OBJECT * tabfolder1_, FL_OBJECT * tabfolder2_)
183 // Store these for later use in working round an xforms bug in show()
184 tabfolder1 = tabfolder1_;
185 tabfolder2 = tabfolder2_;
190 case FL_COMBOX_DROPLIST:
192 button = obj = fl_add_button(FL_NORMAL_BUTTON,
193 x+w-22, y, 22, hmin, "@2->");
194 fl_set_object_color(obj, FL_MCOL, FL_MCOL);
195 fl_set_object_dblbuffer(obj, 1);
196 fl_set_object_callback(obj, C_Combox_combo_cb, 0);
197 label = obj = fl_add_button(FL_NORMAL_TEXT, x, y, w-22, hmin, "");
198 fl_set_object_boxtype(obj, FL_DOWN_BOX);
199 fl_set_object_color(obj, FL_MCOL, FL_BLACK);
200 fl_set_object_lalign(obj, FL_ALIGN_CENTER|FL_ALIGN_INSIDE);
201 fl_set_object_dblbuffer(obj, 1);
202 fl_set_object_callback(obj, C_Combox_combo_cb, 0);
205 case FL_COMBOX_NORMAL:
207 button = obj = fl_add_button(FL_NORMAL_BUTTON, x, y, w, hmin, "");
208 fl_set_object_color(obj, FL_MCOL, FL_MCOL);
209 fl_set_object_boxtype(obj, FL_DOWN_BOX);
210 fl_set_object_callback(obj, C_Combox_combo_cb, 0);
211 fl_set_object_color(obj, FL_MCOL, FL_BLACK);
215 case FL_COMBOX_INPUT:
217 button = obj = fl_add_button(FL_NORMAL_BUTTON,
218 x+w-22, y, 22, hmin, "@2->");
219 fl_set_object_color(obj, FL_MCOL, FL_MCOL);
220 fl_set_object_callback(obj, C_Combox_combo_cb, 0);
221 label = obj = fl_add_input(FL_NORMAL_INPUT, x, y, w-22, hmin, "");
222 fl_set_object_boxtype(obj, FL_DOWN_BOX);
223 fl_set_object_return(obj, FL_RETURN_END_CHANGED);
224 fl_set_object_callback(obj, C_Combox_input_cb, 0);
225 //fl_set_object_color(obj, FL_MCOL, FL_BLACK);
226 //fl_set_object_lalign(obj,FL_ALIGN_CENTER|FL_ALIGN_INSIDE);
231 label->u_vdata = this;
232 button->u_vdata = this;
234 // Hmm, it seems fl_create_browser is broken in xforms 0.86.
235 // We have to work around that by creating the dropped browser form
236 // at this point already. However, this means that we have
237 // to do a little hacking: (Asger)
238 FL_FORM * current_form = fl_current_form;
242 bh = hmax - hmin - 12;
244 form = fl_bgn_form(FL_NO_BOX, bw, bh);
245 browser = obj = fl_add_browser(FL_HOLD_BROWSER, 0, 0, bw, bh, "");
246 fl_set_object_boxtype(obj, FL_UP_BOX);
247 fl_set_object_color(obj, FL_MCOL, FL_YELLOW);
248 fl_set_object_gravity(obj, NorthWestGravity, NorthWestGravity);
249 fl_set_object_callback(obj, C_Combox_combo_cb, 2);
251 browser->u_vdata = this;
252 form->u_vdata = browser;
253 fl_register_raw_callback(form,
254 ButtonPressMask|KeyPressMask,
255 C_Combox_peek_event);
257 // And revert to adding to the old form (Asger)
258 fl_addto_form(current_form);
269 void Combox::redraw()
271 if (browser) fl_redraw_object(browser);
272 if (button) fl_redraw_object(button);
273 if (label) fl_redraw_object(label);
281 XGetInputFocus(fl_get_display(), &save_window, &tmp); //BUG-Fix Dietmar
282 XFlush(fl_get_display());
283 if (button && type != FL_COMBOX_NORMAL) {
284 fl_set_object_label(button, "@2<-");
285 fl_redraw_object(button);
289 int y = label->y + label->h;
291 // This is a bug work around suggested by Steve Lamont on the
292 // xforms mailing list. It correctly positions the browser form
293 // after the main window has been moved.
294 // The bug only occurs in tabbed folders.
295 int folder_x, folder_y, folder_w, folder_h;
296 fl_get_folder_area( tabfolder1,
297 &folder_x, &folder_y,
298 &folder_w, &folder_h);
303 fl_get_folder_area( tabfolder2,
304 &folder_x, &folder_y,
305 &folder_w, &folder_h);
306 x += tabfolder2->form->x + folder_x;
307 y += tabfolder2->form->y + folder_y;
309 x += tabfolder1->form->x;
310 y += tabfolder1->form->y;
318 fl_set_form_position(form, x, y);
319 fl_show_form(form, FL_PLACE_POSITION, FL_NOBORDER, "");
321 fl_set_browser_topline(browser, sel);
322 fl_select_browser_line(browser, sel);
324 XGrabPointer(fl_get_display(), form->window, false,
325 ButtonPressMask | ButtonReleaseMask | PointerMotionMask,
326 GrabModeAsync, GrabModeAsync,
328 XFlush(fl_get_display());
331 void Combox::hide(int who)
333 if (!who && browser && label) {
334 sel = fl_get_browser(browser);
336 if (type == FL_COMBOX_INPUT)
337 fl_set_input(label, fl_get_browser_line(browser, sel));
339 fl_set_object_label(label,
340 fl_get_browser_line(browser, sel));
341 // if (callback) callback(sel, cb_arg);
343 XUngrabPointer(fl_get_display(), 0);
344 XFlush(fl_get_display());
347 XSetInputFocus(fl_get_display(), save_window,
348 RevertToParent, CurrentTime); // BUG-FIX-Dietmar
349 XFlush(fl_get_display());
352 if (type != FL_COMBOX_NORMAL) {
353 fl_set_object_label(button, "@2->");
354 fl_redraw_object(button);
357 if (!who && browser && label && callback)
358 callback(sel, cb_arg, this);
363 void Combox::activate()
366 fl_activate_object(browser);
368 fl_activate_object(button);
369 fl_set_object_lcol(button, FL_BLACK);
372 fl_activate_object(label);
373 fl_set_object_lcol(label, FL_BLACK);
378 void Combox::deactivate()
381 fl_deactivate_object(browser);
383 fl_deactivate_object(button);
384 fl_set_object_lcol(button, FL_INACTIVE);
387 fl_deactivate_object(label);
388 fl_set_object_lcol(label, FL_INACTIVE);
393 void Combox::input_cb(FL_OBJECT * ob, long)
395 Combox * combo = static_cast<Combox*>(ob->u_vdata);
397 char const * text = fl_get_input(ob);
399 combo->addto(text ? string(text) : string());
400 combo->is_empty = false;
404 void Combox::combo_cb(FL_OBJECT * ob, long data)
406 Combox * combo = static_cast<Combox*>(ob->u_vdata);
410 int const i = combo->get();
411 switch (fl_get_button_numb(ob)) {
414 combo->select(i - 1);
416 combo->callback(combo->sel,
417 combo->cb_arg, combo);
422 combo->select(i + 1);
424 combo->callback(combo->sel,
425 combo->cb_arg, combo);
428 default: combo->show(); break;
439 int Combox::peek_event(FL_FORM * form, void * xev)
441 FL_OBJECT * ob = static_cast<FL_OBJECT *>(form->u_vdata);
442 Combox * combo = static_cast<Combox*>(ob->u_vdata);
444 // below mouse does not work like we need it
445 if (static_cast<XEvent *>(xev)->type == ButtonPress && (
446 static_cast<XEvent *>(xev)->xbutton.x - ob->x < 0 ||
447 static_cast<XEvent *>(xev)->xbutton.x - ob->x > ob->w ||
448 static_cast<XEvent *>(xev)->xbutton.y - ob->y < 0 ||
449 static_cast<XEvent *>(xev)->xbutton.y - ob->y > ob->h)) {
454 if (static_cast<XEvent*>(xev)->type != KeyPress) return 0;
456 char s_r[10]; s_r[9] = '\0';
457 KeySym keysym_return;
458 XLookupString(&static_cast<XEvent*>(xev)->xkey, s_r, 10,
460 XFlush(fl_get_display());
461 switch (keysym_return) {
466 if (fl_get_browser(combo->browser) <
467 fl_get_browser_maxline(combo->browser))
468 fl_select_browser_line(combo->browser,
469 fl_get_browser(combo->browser)+1);
470 if (fl_get_browser(combo->browser)>=
471 fl_get_browser_topline(combo->browser) +
472 fl_get_browser_screenlines(combo->browser))
473 fl_set_browser_topline(combo->browser,
474 fl_get_browser(combo->browser)
475 - fl_get_browser_screenlines(combo->browser)+1);
476 if (fl_get_browser(combo->browser)<
477 fl_get_browser_topline(combo->browser))
478 fl_set_browser_topline(combo->browser,
479 fl_get_browser(combo->browser));
485 if (fl_get_browser(combo->browser) > 1)
486 fl_select_browser_line(combo->browser,
487 fl_get_browser(combo->browser)-1);
488 if (fl_get_browser(combo->browser)>=
489 fl_get_browser_topline(combo->browser) +
490 fl_get_browser_screenlines(combo->browser))
491 fl_set_browser_topline(combo->browser,
492 fl_get_browser(combo->browser)
493 - fl_get_browser_screenlines(combo->browser)+1);
494 if (fl_get_browser(combo->browser) <
495 fl_get_browser_topline(combo->browser))
496 fl_set_browser_topline(combo->browser,
497 fl_get_browser(combo->browser));
521 //Combox combo(FL_COMBOX_DROPLIST);
522 Combox combo(FL_COMBOX_INPUT);
526 FD_test *create_form_test(void)
529 FD_test *fdui = (FD_test *) fl_calloc(1, sizeof(*fdui));
531 fdui->test = fl_bgn_form(FL_NO_BOX, 320, 190);
532 obj = fl_add_box(FL_UP_BOX, 0, 0, 320, 190, "");
533 obj = fl_add_box(FL_DOWN_BOX, 10, 50, 300, 110, "");
534 obj = fl_add_button(FL_NORMAL_BUTTON, 250, 10, 50, 30, _("Done"));
535 combo.add(10, 15, 120, 25, 135);
543 fprintf(stderr, "selected %d:%s\n", i, combo.getline());
546 int main(int argc, char *argv[])
550 // Same defaults as in lyx
552 cntl.buttonFontSize = FL_NORMAL_SIZE;
553 cntl.browserFontSize = FL_NORMAL_SIZE;
554 cntl.labelFontSize = FL_NORMAL_SIZE;
555 cntl.choiceFontSize = FL_NORMAL_SIZE;
556 cntl.inputFontSize = FL_NORMAL_SIZE;
557 cntl.borderWidth = -2;
558 fl_set_defaults(FL_PDButtonFontSize, &cntl);
559 fl_set_defaults(FL_PDBrowserFontSize, &cntl);
560 fl_set_defaults(FL_PDLabelFontSize, &cntl);
561 fl_set_defaults(FL_PDChoiceFontSize, &cntl);
562 fl_set_defaults(FL_PDInputFontSize, &cntl);
563 fl_set_defaults(FL_PDBorderWidth, &cntl);
564 fl_initialize(&argc, argv, 0, 0, 0);
566 fd_test = create_form_test();
568 /* fill-in form initialization code */
569 combo.addline("Title");
570 combo.addline("Author");
571 combo.addline("Date");
572 combo.addline("Abstract");
573 combo.addline("Chapter");
574 combo.addline("Section");
575 combo.addline("Subsection");
576 combo.addline("List");
577 combo.addline("Description");
578 combo.addline("Verse");
579 combo.addline("Verbatim");
580 combo.setcallback(combo_cb);
583 /* show the first form */
584 fl_show_form(fd_test->test, FL_PLACE_CENTER, FL_FULLBORDER, "test");