3 * Combox: A combination of two objects (a button and a browser) is
4 * encapsulated to get a combobox-like object. All XForms
5 * functions are hidden.
7 * GNU Copyleft 1996 Alejandro Aguilar Sierra <asierra@servidor.unam.mx>
10 * Dependencies: Only XForms, but created to be used with LyX.
16 * 2/06/1996, Alejandro Aguilar Sierra
19 * 4/06/1996, Alejandro Aguilar Sierra
20 * Added droplist mode (a button with a black down arrow at right)
21 * and support for middle and right buttons, as XForms choice object.
23 * 6/06/1996, Lars Gullik Bjønnes
24 * Added a combox with an input object. and a pre and a post handle.
26 * 22/07/96, Alejandro Aguilar Sierra
27 * Assigned to the browser its own popup window. No more need of
28 * external pre and post handlers to simulate the wanted behaviour.
35 #pragma implementation
45 // These are C wrappers around static members of Combox, used as
46 // callbacks for xforms.
47 extern "C" void C_Combox_input_cb(FL_OBJECT *ob, long);
48 extern "C" void C_Combox_combo_cb(FL_OBJECT *ob, long data) ;
49 extern "C" int C_Combox_peek_event(FL_FORM * form, void *xev);
51 Combox::Combox(combox_type t)
52 : type(t), tabfolder1(0), tabfolder2(0)
73 if (browser) fl_clear_browser(browser);
75 if (type == FL_COMBOX_INPUT)
76 fl_set_input(label, "");
78 fl_set_object_label(label, "");
85 lyxerr.debug() << "Button: " << button << endl;
87 fl_delete_object(button);
88 fl_free_object(button);
91 lyxerr.debug() << "Label: " << label << endl;
92 if (label && label != button) {
93 fl_delete_object(label);
94 fl_free_object(label);
97 lyxerr.debug() << "Form: " << form << endl;
98 lyxerr.debug() << "Browser: " << browser << endl;
99 if (form && browser) {
100 fl_delete_object(browser);
101 fl_free_object(browser);
113 void Combox::addline(string const & text)
115 if (!browser) return;
116 fl_add_browser_line(browser, text.c_str());
118 // By default the first item is selected
121 if (type == FL_COMBOX_INPUT)
122 fl_set_input(label, text.c_str());
124 fl_set_object_label(label, text.c_str());
130 bool Combox::select_text(string const & t)
132 if (!browser || t.empty()) return false;
133 int const maxline = fl_get_browser_maxline(browser);
135 for (int i = 1; i <= maxline; ++i) {
136 if (t == fl_get_browser_line(browser, i)) {
141 return false; // t does not exist in browser
145 void Combox::select(int i)
147 if (!browser || !button) return;
148 if (i > 0 && i <= fl_get_browser_maxline(browser)) sel = i;
149 fl_deactivate_object(button);
151 if (type == FL_COMBOX_INPUT)
152 fl_set_input(label, fl_get_browser_line(browser, sel));
154 fl_set_object_label(label, fl_get_browser_line(browser, sel));
155 fl_activate_object(button);
159 void Combox::add(int x, int y, int w, int hmin, int hmax,
160 FL_OBJECT * tabfolder1_, FL_OBJECT * tabfolder2_)
162 // Store these for later use in working round an xforms bug in Show()
163 tabfolder1 = tabfolder1_;
164 tabfolder2 = tabfolder2_;
169 case FL_COMBOX_DROPLIST:
171 button = obj = fl_add_button(FL_NORMAL_BUTTON,
172 x+w-22, y, 22, hmin, "@2->");
173 fl_set_object_color(obj, FL_MCOL, FL_MCOL);
174 fl_set_object_dblbuffer(obj, 1);
175 fl_set_object_callback(obj, C_Combox_combo_cb, 0);
176 label = obj = fl_add_button(FL_NORMAL_TEXT, x, y, w-22, hmin, "");
177 fl_set_object_boxtype(obj, FL_DOWN_BOX);
178 fl_set_object_color(obj, FL_MCOL, FL_BLACK);
179 fl_set_object_lalign(obj, FL_ALIGN_CENTER|FL_ALIGN_INSIDE);
180 fl_set_object_dblbuffer(obj, 1);
181 fl_set_object_callback(obj, C_Combox_combo_cb, 0);
184 case FL_COMBOX_NORMAL:
186 button = obj = fl_add_button(FL_NORMAL_BUTTON, x, y, w, hmin, "");
187 fl_set_object_color(obj, FL_MCOL, FL_MCOL);
188 fl_set_object_boxtype(obj, FL_DOWN_BOX);
189 fl_set_object_callback(obj, C_Combox_combo_cb, 0);
190 fl_set_object_color(obj, FL_MCOL, FL_BLACK);
194 case FL_COMBOX_INPUT:
196 button = obj = fl_add_button(FL_NORMAL_BUTTON,
197 x+w-22, y, 22, hmin, "@2->");
198 fl_set_object_color(obj, FL_MCOL, FL_MCOL);
199 fl_set_object_callback(obj, C_Combox_combo_cb, 0);
200 label = obj = fl_add_input(FL_NORMAL_INPUT, x, y, w-22, hmin, "");
201 fl_set_object_boxtype(obj, FL_DOWN_BOX);
202 fl_set_object_return(obj, FL_RETURN_END_CHANGED);
203 fl_set_object_callback(obj, C_Combox_input_cb, 0);
204 //fl_set_object_color(obj, FL_MCOL, FL_BLACK);
205 //fl_set_object_lalign(obj,FL_ALIGN_CENTER|FL_ALIGN_INSIDE);
210 label->u_vdata = this;
211 button->u_vdata = this;
213 // Hmm, it seems fl_create_browser is broken in xforms 0.86.
214 // We have to work around that by creating the dropped browser form
215 // at this point already. However, this means that we have
216 // to do a little hacking: (Asger)
217 FL_FORM * current_form = fl_current_form;
220 bw = w + 20; bh = hmax - hmin - 12;
222 form = fl_bgn_form(FL_NO_BOX, bw, bh);
223 browser = obj = fl_add_browser(FL_HOLD_BROWSER, 0, 0, bw, bh, "");
224 fl_set_object_boxtype(obj, FL_UP_BOX);
225 fl_set_object_color(obj, FL_MCOL, FL_YELLOW);
226 fl_set_object_gravity(obj, NorthWestGravity, NorthWestGravity);
227 fl_set_object_callback(obj, C_Combox_combo_cb, 2);
229 browser->u_vdata = this;
230 form->u_vdata = browser;
231 fl_register_raw_callback(form,
232 ButtonPressMask|KeyPressMask,
233 C_Combox_peek_event);
235 // And revert to adding to the old form (Asger)
236 fl_addto_form(current_form);
240 static Window save_window;
243 void Combox::Redraw()
245 if (browser) fl_redraw_object(browser);
246 if (button) fl_redraw_object(button);
247 if (label) fl_redraw_object(label);
255 XGetInputFocus(fl_get_display(), &save_window, &tmp); //BUG-Fix Dietmar
256 XFlush(fl_get_display());
257 if (button && type != FL_COMBOX_NORMAL) {
258 fl_set_object_label(button, "@2<-");
259 fl_redraw_object(button);
263 int y = label->y + label->h;
265 // This is a bug work around suggested by Steve Lamont on the
266 // xforms mailing list. It correctly positions the browser form
267 // after the main window has been moved.
268 // The bug only occurs in tabbed folders.
269 int folder_x, folder_y, folder_w, folder_h;
270 fl_get_folder_area( tabfolder1,
271 &folder_x, &folder_y,
272 &folder_w, &folder_h );
277 fl_get_folder_area( tabfolder2,
278 &folder_x, &folder_y,
279 &folder_w, &folder_h );
280 x += tabfolder2->form->x + folder_x;
281 y += tabfolder2->form->y + folder_y;
283 x += tabfolder1->form->x;
284 y += tabfolder1->form->y;
292 fl_set_form_position(form, x, y);
293 fl_show_form(form, FL_PLACE_POSITION, FL_NOBORDER, "");
295 fl_set_browser_topline(browser, sel);
296 fl_select_browser_line(browser, sel);
298 XGrabPointer(fl_get_display(), form->window, false,
299 ButtonPressMask | ButtonReleaseMask | PointerMotionMask,
300 GrabModeAsync, GrabModeAsync,
302 XFlush(fl_get_display());
305 void Combox::Hide(int who)
307 if (!who && browser && label) {
308 sel = fl_get_browser(browser);
310 if (type == FL_COMBOX_INPUT)
311 fl_set_input(label, fl_get_browser_line(browser, sel));
313 fl_set_object_label(label,
314 fl_get_browser_line(browser, sel));
315 // if (callback) callback(sel, cb_arg);
317 XUngrabPointer(fl_get_display(), 0);
318 XFlush(fl_get_display());
319 if (!who && browser && label && callback)
320 callback(sel, cb_arg, this);
323 XSetInputFocus(fl_get_display(), save_window,
324 RevertToParent, CurrentTime); // BUG-FIX-Dietmar
325 XFlush(fl_get_display());
328 if (type != FL_COMBOX_NORMAL){
329 fl_set_object_label(button, "@2->");
330 fl_redraw_object(button);
337 void Combox::activate()
339 if (browser) fl_activate_object(browser);
340 if (button) fl_activate_object(button);
341 if (label) fl_activate_object(label);
345 void Combox::deactivate()
347 if (browser) fl_deactivate_object(browser);
348 if (button) fl_deactivate_object(button);
349 if (label) fl_deactivate_object(label);
353 void Combox::input_cb(FL_OBJECT * ob, long)
355 Combox * combo = static_cast<Combox*>(ob->u_vdata);
357 char const * text = fl_get_input(ob);
359 combo->addto(text ? string(text) : string());
360 combo->is_empty = false;
364 extern "C" void C_Combox_input_cb(FL_OBJECT * ob, long data)
366 Combox::input_cb(ob, data);
370 void Combox::combo_cb(FL_OBJECT * ob, long data)
372 Combox * combo = static_cast<Combox*>(ob->u_vdata);
376 int const i = combo->get();
377 switch (fl_get_button_numb(ob)) {
380 combo->select(i - 1);
382 combo->callback(combo->sel,
383 combo->cb_arg, combo);
388 combo->select(i + 1);
390 combo->callback(combo->sel,
391 combo->cb_arg, combo);
394 default: combo->Show(); break;
404 extern "C" void C_Combox_combo_cb(FL_OBJECT * ob, long data)
406 Combox::combo_cb(ob, data);
410 int Combox::peek_event(FL_FORM * form, void * xev)
412 FL_OBJECT * ob = static_cast<FL_OBJECT *>(form->u_vdata);
413 Combox * combo = static_cast<Combox*>(ob->u_vdata);
415 // I don't know why belowmouse does not work, but it doesn't. (Asger)
416 // Are we sure? Please verify. (Lgb)
417 if (static_cast<XEvent *>(xev)->type == ButtonPress && (
418 static_cast<XEvent *>(xev)->xbutton.x - ob->x < 0 ||
419 static_cast<XEvent *>(xev)->xbutton.x - ob->x > ob->w ||
420 static_cast<XEvent *>(xev)->xbutton.y - ob->y < 0 ||
421 static_cast<XEvent *>(xev)->xbutton.y - ob->y > ob->h)) {
426 if (static_cast<XEvent*>(xev)->type != KeyPress) return 0;
428 char s_r[10]; s_r[9] = '\0';
429 KeySym keysym_return;
430 XLookupString(&static_cast<XEvent*>(xev)->xkey, s_r, 10,
432 XFlush(fl_get_display());
433 switch (keysym_return) {
435 if (fl_get_browser(combo->browser) <
436 fl_get_browser_maxline(combo->browser))
437 fl_select_browser_line(combo->browser,
438 fl_get_browser(combo->browser)+1);
439 if (fl_get_browser(combo->browser)>=
440 fl_get_browser_topline(combo->browser) +
441 fl_get_browser_screenlines(combo->browser))
442 fl_set_browser_topline(combo->browser,
443 fl_get_browser(combo->browser)
444 - fl_get_browser_screenlines(combo->browser)+1);
445 if (fl_get_browser(combo->browser)<
446 fl_get_browser_topline(combo->browser))
447 fl_set_browser_topline(combo->browser,
448 fl_get_browser(combo->browser));
451 if (fl_get_browser(combo->browser) > 1)
452 fl_select_browser_line(combo->browser,
453 fl_get_browser(combo->browser)-1);
454 if (fl_get_browser(combo->browser)>=
455 fl_get_browser_topline(combo->browser) +
456 fl_get_browser_screenlines(combo->browser))
457 fl_set_browser_topline(combo->browser,
458 fl_get_browser(combo->browser)
459 - fl_get_browser_screenlines(combo->browser)+1);
460 if (fl_get_browser(combo->browser) <
461 fl_get_browser_topline(combo->browser))
462 fl_set_browser_topline(combo->browser,
463 fl_get_browser(combo->browser));
475 extern "C" int C_Combox_peek_event(FL_FORM * form, void *xev)
477 return Combox::peek_event(form, xev);
489 //Combox combo(FL_COMBOX_DROPLIST);
490 Combox combo(FL_COMBOX_INPUT);
494 FD_test *create_form_test(void)
497 FD_test *fdui = (FD_test *) fl_calloc(1, sizeof(*fdui));
499 fdui->test = fl_bgn_form(FL_NO_BOX, 320, 190);
500 obj = fl_add_box(FL_UP_BOX, 0, 0, 320, 190, "");
501 obj = fl_add_box(FL_DOWN_BOX, 10, 50, 300, 110, "");
502 obj = fl_add_button(FL_NORMAL_BUTTON, 250, 10, 50, 30, _("Done"));
503 combo.add(10, 15, 120, 25, 135);
511 fprintf(stderr, "selected %d:%s\n", i, combo.getline());
514 int main(int argc, char *argv[])
518 // Same defaults as in lyx
520 cntl.buttonFontSize = FL_NORMAL_SIZE;
521 cntl.browserFontSize = FL_NORMAL_SIZE;
522 cntl.labelFontSize = FL_NORMAL_SIZE;
523 cntl.choiceFontSize = FL_NORMAL_SIZE;
524 cntl.inputFontSize = FL_NORMAL_SIZE;
525 cntl.borderWidth = -2;
526 fl_set_defaults(FL_PDButtonFontSize, &cntl);
527 fl_set_defaults(FL_PDBrowserFontSize, &cntl);
528 fl_set_defaults(FL_PDLabelFontSize, &cntl);
529 fl_set_defaults(FL_PDChoiceFontSize, &cntl);
530 fl_set_defaults(FL_PDInputFontSize, &cntl);
531 fl_set_defaults(FL_PDBorderWidth, &cntl);
532 fl_initialize(&argc, argv, 0, 0, 0);
534 fd_test = create_form_test();
536 /* fill-in form initialization code */
537 combo.addline("Title");
538 combo.addline("Author");
539 combo.addline("Date");
540 combo.addline("Abstract");
541 combo.addline("Chapter");
542 combo.addline("Section");
543 combo.addline("Subsection");
544 combo.addline("List");
545 combo.addline("Description");
546 combo.addline("Verse");
547 combo.addline("Verbatim");
548 combo.setcallback(combo_cb);
551 /* show the first form */
552 fl_show_form(fd_test->test, FL_PLACE_CENTER, FL_FULLBORDER, "test");