3 * This file is part of LyX, the document processor.
4 * Licence details can be found in the file COPYING.
6 * \author Alejandro Aguilar Sierra
7 * \author Lars Gullik Bjønnes
8 * \author Jean-Marc Lasgouttes
9 * \author Angus Leeming
11 * Full author contact details are available in file CREDITS
13 * This is a rewrite of Alejandro's C++ Combox class, originally written
14 * for LyX in 1996. The rewrite turns it into a native xforms widget.
18 #include "lyx_forms.h"
20 #include "freebrowser.h"
22 extern void fl_add_child(FL_OBJECT *, FL_OBJECT *);
23 extern void fl_addto_freelist(void *);
27 /** A pointer to the parent widget */
30 FL_FREEBROWSER * freebrowser;
33 /** The browser will be displayed either below or above the main body. */
36 /** button_state displays a down or up arrow depending on whether the
37 * browser is visible or not.
38 * Click on it to toggle the browser.
40 FL_OBJECT * button_state;
42 /** button_chosen displays the current selection from the browser.
43 * Click on it to toggle the browser.
45 FL_OBJECT * button_chosen;
49 enum { ACTIVATE, DEACTIVATE };
51 enum { COMBOX_OPEN, COMBOX_CLOSED };
54 /* function declarations */
55 static int combox_pre(FL_OBJECT *, int, FL_Coord, FL_Coord, int, void *);
56 static int combox_post(FL_OBJECT *, int, FL_Coord, FL_Coord, int, void *);
57 static int combox_handle(FL_OBJECT *, int, FL_Coord, FL_Coord, int, void *);
59 static void update_button_chosen(FL_FREEBROWSER * fb, int action);
60 static void chosen_cb(FL_OBJECT * ob, long data);
61 static void state_cb(FL_OBJECT * ob, long data);
63 static void show_browser(COMBOX_SPEC * sp);
64 static void set_activation(FL_OBJECT * ob, int activation);
65 static void set_state_label(COMBOX_SPEC * sp, int state);
66 static void attrib_change(COMBOX_SPEC * sp);
70 fl_create_combox(FL_COMBOX_TYPE type,
71 FL_Coord x, FL_Coord y, FL_Coord w, FL_Coord h,
78 /* The width and x-position of button_state, respectively. */
79 FL_Coord const ws = 0.7 * h;
80 FL_Coord const xs = x + w - ws;
82 /* The width of button_chosen */
83 FL_Coord const wc = (type == FL_DROPLIST_COMBOX) ? (w - ws) : w;
85 ob = fl_make_object(FL_COMBOX, type, x, y, w, h, label, combox_handle);
86 ob->align = FL_ALIGN_LEFT;
88 sp = ob->spec = fl_calloc(1, sizeof(COMBOX_SPEC));
90 sp->browser_height = 100;
91 sp->browser_position = FL_FREEBROWSER_BELOW;
93 sp->freebrowser = fl_create_freebrowser(sp);
94 sp->freebrowser->callback = update_button_chosen;
97 if (type == FL_DROPLIST_COMBOX) {
98 sp->button_state = fl_add_button(FL_NORMAL_BUTTON, xs, y, ws, h, "");
100 button = sp->button_state;
101 fl_set_object_lalign(button, FL_ALIGN_CENTER|FL_ALIGN_INSIDE);
102 fl_set_object_callback(button, state_cb, 0);
103 fl_set_object_posthandler(button, combox_post);
104 fl_set_object_prehandler(button, combox_pre);
105 set_state_label(sp, COMBOX_CLOSED);
107 set_activation(button, DEACTIVATE);
109 button->u_vdata = sp;
112 sp->button_chosen = fl_add_button(FL_NORMAL_TEXT, x, y, wc, h, "");
114 button = sp->button_chosen;
115 fl_set_object_boxtype(button, FL_FRAME_BOX);
116 fl_set_object_lalign(button, FL_ALIGN_CENTER|FL_ALIGN_INSIDE);
117 fl_set_object_callback(button, chosen_cb, 0);
118 fl_set_object_posthandler(button, combox_post);
119 fl_set_object_prehandler(button, combox_pre);
120 set_activation(button, DEACTIVATE);
122 button->u_vdata = sp;
129 fl_add_combox(FL_COMBOX_TYPE type,
130 FL_Coord x, FL_Coord y, FL_Coord w, FL_Coord h,
133 FL_OBJECT * ob = fl_create_combox(type, x, y, w, h, label);
134 COMBOX_SPEC * sp = ob->spec;
136 if (sp->button_state)
137 fl_add_child(ob, sp->button_state);
138 fl_add_child(ob, sp->button_chosen);
140 fl_add_object(fl_current_form, ob);
146 fl_set_combox_browser_height(FL_OBJECT * ob, int bh)
150 if (!ob || ob->objclass != FL_COMBOX)
154 sp->browser_height = bh;
159 fl_set_combox_position(FL_OBJECT * ob, FL_COMBOX_POSITION position)
163 if (!ob || ob->objclass != FL_COMBOX)
167 sp->browser_position = (position == FL_COMBOX_ABOVE) ?
168 FL_FREEBROWSER_ABOVE : FL_FREEBROWSER_BELOW;
170 set_state_label(sp, COMBOX_CLOSED);
175 fl_clear_combox(FL_OBJECT * ob)
180 if (!ob || ob->objclass != FL_COMBOX)
184 browser = sp->freebrowser->browser;
186 fl_clear_browser(browser);
187 fl_set_object_label(sp->button_chosen, "");
192 fl_addto_combox(FL_OBJECT * ob, char const * text)
200 if (!ob || ob->objclass != FL_COMBOX)
204 browser = sp->freebrowser->browser;
206 /* Split the string on '|' boundaries. */
208 for (; text[i] != '\0'; ++i) {
209 if (text[i] == '|') {
211 fl_add_browser_line(browser, line);
220 fl_add_browser_line(browser, line);
223 /* By default the first item is selected */
224 if (fl_get_browser_maxline(browser)) {
225 char const * const label = fl_get_browser_line(browser, 1);
226 fl_set_object_label(sp->button_chosen, label);
227 fl_select_browser_line(browser, 1);
228 set_activation(sp->button_chosen, ACTIVATE);
229 if (sp->button_state)
230 set_activation(sp->button_state, ACTIVATE);
236 fl_set_combox(FL_OBJECT * ob, int sel)
241 if (!ob || ob->objclass != FL_COMBOX)
245 browser = sp->freebrowser->browser;
247 if (sel < 1 || sel > fl_get_browser_maxline(browser))
250 fl_select_browser_line(browser, sel);
251 fl_set_object_label(sp->button_chosen, fl_get_browser_line(browser, sel));
256 fl_get_combox(FL_OBJECT * ob)
261 if (!ob || ob->objclass != FL_COMBOX)
265 browser = sp->freebrowser->browser;
266 return fl_get_browser(browser);
271 fl_get_combox_text(FL_OBJECT * ob)
275 if (!ob || ob->objclass != FL_COMBOX)
279 return sp->button_chosen->label;
284 fl_get_combox_line(FL_OBJECT * ob, int line)
290 if (line < 1 || !ob || ob->objclass != FL_COMBOX)
294 browser = sp->freebrowser->browser;
296 maxlines = fl_get_browser_maxline(browser);
300 return fl_get_browser_line(browser, line);
305 fl_get_combox_maxitems(FL_OBJECT * ob)
310 if (!ob || ob->objclass != FL_COMBOX)
314 browser = sp->freebrowser->browser;
315 return fl_get_browser_maxline(browser);
320 fl_show_combox_browser(FL_OBJECT * ob)
322 if (!ob || ob->objclass != FL_COMBOX)
325 show_browser(ob->spec);
330 fl_hide_combox_browser(FL_OBJECT * ob)
334 if (!ob || ob->objclass != FL_COMBOX)
338 fl_free_freebrowser(sp->freebrowser);
343 combox_pre(FL_OBJECT * ob, int ev, FL_Coord mx, FL_Coord my, int key,
346 COMBOX_SPEC * sp = ob->u_vdata;
347 FL_OBJECT * combox = sp->combox;
349 return combox->prehandle ?
350 combox->prehandle(combox, ev, mx, my, key, xev) : 0;
355 combox_post(FL_OBJECT * ob, int ev, FL_Coord mx, FL_Coord my, int key,
358 COMBOX_SPEC * sp = ob->u_vdata;
359 FL_OBJECT * combox = sp->combox;
361 return combox->posthandle ?
362 combox->posthandle(combox, ev, mx, my, key, xev) : 0;
367 combox_handle(FL_OBJECT * ob, int event, FL_Coord mx, FL_Coord my, int key,
370 if (!ob || ob->objclass != FL_COMBOX)
375 attrib_change(ob->spec);
378 COMBOX_SPEC * sp = ob->spec;
381 ob->x != sp->button_chosen->x ||
382 ob->y != sp->button_chosen->y;
385 if (sp->button_state) {
386 xbs = ob->x + (sp->button_state->x - sp->button_chosen->x);
388 xbs != sp->button_state->x ||
389 ob->y != sp->button_state->y;
393 fl_freeze_form(ob->form);
394 fl_set_object_position(sp->button_chosen, ob->x, ob->y);
395 if (sp->button_state)
396 fl_set_object_position(sp->button_state, xbs, ob->y);
397 fl_unfreeze_form(ob->form);
400 fl_draw_object_label(ob);
403 show_browser(ob->spec);
406 COMBOX_SPEC * sp = ob->spec;
407 fl_free_freebrowser(sp->freebrowser);
408 /* children take care of themselves, but we must make sure that
409 sp itself is free-d eventually. */
410 fl_addto_freelist(sp);
419 set_activation(FL_OBJECT * ob, int activation)
421 switch (activation) {
423 fl_activate_object(ob);
424 fl_set_object_lcol(ob, FL_LCOL);
427 fl_deactivate_object(ob);
428 fl_set_object_lcol(ob, FL_INACTIVE);
434 show_browser(COMBOX_SPEC * sp)
436 FL_OBJECT * ob = sp->combox;
438 /* The browser dimensions. */
439 FL_Coord const bw = ob->w + 20;
440 FL_Coord const bh = sp->browser_height;
442 FL_Coord const abs_x = ob->form->x + ob->x;
444 FL_Coord abs_y = ob->form->y + ob->y;
445 abs_y += (sp->browser_position == FL_FREEBROWSER_BELOW) ? ob->h : -bh;
447 set_state_label(sp, COMBOX_OPEN);
448 fl_show_freebrowser(sp->freebrowser, abs_x, abs_y, bw, bh);
453 state_cb(FL_OBJECT * ob, long data)
455 show_browser(ob->u_vdata);
460 chosen_cb(FL_OBJECT * ob, long data)
462 show_browser(ob->u_vdata);
467 update_button_chosen(FL_FREEBROWSER * fb, int action)
469 COMBOX_SPEC * sp = fb->parent;
471 FL_OBJECT * browser = sp->freebrowser->browser;
472 FL_OBJECT * combox = sp->combox;
473 if (!browser || !combox) return;
475 set_state_label(sp, COMBOX_CLOSED);
478 int const sel = fl_get_browser(browser);
479 char const * const text = fl_get_browser_line(browser, sel);
480 fl_set_object_label(sp->button_chosen, text);
481 fl_call_object_callback(combox);
487 set_state_label(COMBOX_SPEC * sp, int state)
489 char const * const up = "@2<-";
490 char const * const down = "@2->";
491 char const * label = 0;
493 if (!sp->button_state)
496 if (sp->browser_position == FL_FREEBROWSER_BELOW) {
497 label = (state == COMBOX_OPEN) ? up : down;
499 label = (state == COMBOX_OPEN) ? down : up;
501 fl_set_object_label(sp->button_state, label);
502 fl_redraw_object(sp->button_state);
507 attrib_change(COMBOX_SPEC * sp)
509 FL_OBJECT * parent = sp->combox;
510 FL_OBJECT * button = sp->button_chosen;
512 button->boxtype = parent->boxtype;
513 button->col1 = parent->col1;
514 button->col2 = parent->col2;
515 button->bw = parent->bw;
517 if (sp->button_state) {
518 button = sp->button_state;
520 /* The boxtype is not changed */
521 button->col1 = parent->col1;
522 button->col2 = parent->col2;
523 button->bw = parent->bw;