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 fl_draw_object_label(ob);
381 show_browser(ob->spec);
384 COMBOX_SPEC * sp = ob->spec;
385 fl_free_freebrowser(sp->freebrowser);
386 /* children take care of themselves, but we must make sure that
387 sp itself is free-d eventually. */
388 fl_addto_freelist(sp);
397 set_activation(FL_OBJECT * ob, int activation)
399 switch (activation) {
401 fl_activate_object(ob);
402 fl_set_object_lcol(ob, FL_LCOL);
405 fl_deactivate_object(ob);
406 fl_set_object_lcol(ob, FL_INACTIVE);
412 show_browser(COMBOX_SPEC * sp)
414 FL_OBJECT * ob = sp->combox;
416 /* The browser dimensions. */
417 FL_Coord const bw = ob->w + 20;
418 FL_Coord const bh = sp->browser_height;
420 FL_Coord const abs_x = ob->form->x + ob->x;
422 FL_Coord abs_y = ob->form->y + ob->y;
423 abs_y += (sp->browser_position == FL_FREEBROWSER_BELOW) ? ob->h : -bh;
425 set_state_label(sp, COMBOX_OPEN);
426 fl_show_freebrowser(sp->freebrowser, abs_x, abs_y, bw, bh);
431 state_cb(FL_OBJECT * ob, long data)
433 show_browser(ob->u_vdata);
438 chosen_cb(FL_OBJECT * ob, long data)
440 show_browser(ob->u_vdata);
445 update_button_chosen(FL_FREEBROWSER * fb, int action)
447 COMBOX_SPEC * sp = fb->parent;
449 FL_OBJECT * browser = sp->freebrowser->browser;
450 FL_OBJECT * combox = sp->combox;
451 if (!browser || !combox) return;
453 set_state_label(sp, COMBOX_CLOSED);
456 int const sel = fl_get_browser(browser);
457 char const * const text = fl_get_browser_line(browser, sel);
458 fl_set_object_label(sp->button_chosen, text);
459 fl_call_object_callback(combox);
465 set_state_label(COMBOX_SPEC * sp, int state)
467 char const * const up = "@2<-";
468 char const * const down = "@2->";
469 char const * label = 0;
471 if (!sp->button_state)
474 if (sp->browser_position == FL_FREEBROWSER_BELOW) {
475 label = (state == COMBOX_OPEN) ? up : down;
477 label = (state == COMBOX_OPEN) ? down : up;
479 fl_set_object_label(sp->button_state, label);
480 fl_redraw_object(sp->button_state);
485 attrib_change(COMBOX_SPEC * sp)
487 FL_OBJECT * parent = sp->combox;
488 FL_OBJECT * button = sp->button_chosen;
490 button->boxtype = parent->boxtype;
491 button->col1 = parent->col1;
492 button->col2 = parent->col2;
493 button->bw = parent->bw;
495 if (sp->button_state) {
496 button = sp->button_state;
498 /* The boxtype is not changed */
499 button->col1 = parent->col1;
500 button->col2 = parent->col2;
501 button->bw = parent->bw;