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 Angus Leeming
9 * Full author contact details are available in file CREDITS
11 * This is a rewrite of Alejandro's C++ Combox class, originally written
12 * for LyX in 1996. The rewrite turns it into a native xforms widget.
16 #include FORMS_H_LOCATION
18 #include "freebrowser.h"
20 extern void fl_add_child(FL_OBJECT *, FL_OBJECT *);
21 extern void fl_addto_freelist(void *);
25 /** A pointer to the parent widget */
28 FL_FREEBROWSER * browser;
31 /** The browser will be displayed either below or above the main body. */
34 /** button_state displays a down or up arrow depending on whether the
35 * browser is visible or not.
36 * Click on it to toggle the browser.
38 FL_OBJECT * button_state;
40 /** button_chosen displays the current selection from the browser.
41 * Click on it to toggle the browser.
43 FL_OBJECT * button_chosen;
47 enum { ACTIVATE, DEACTIVATE };
49 enum { COMBOX_OPEN, COMBOX_CLOSED };
52 /* function declarations */
53 static int combox_pre(FL_OBJECT *, int, FL_Coord, FL_Coord, int, void *);
54 static int combox_post(FL_OBJECT *, int, FL_Coord, FL_Coord, int, void *);
55 static int combox_handle(FL_OBJECT *, int, FL_Coord, FL_Coord, int, void *);
57 static void update_button_chosen(FL_FREEBROWSER * fb, int action);
58 static void chosen_cb(FL_OBJECT * ob, long data);
59 static void state_cb(FL_OBJECT * ob, long data);
61 static void show_browser(COMBOX_SPEC * sp);
62 static void set_activation(FL_OBJECT * ob, int activation);
63 static void set_state_label(COMBOX_SPEC * sp, int state);
64 static void attrib_change(COMBOX_SPEC * sp);
67 FL_OBJECT * fl_create_combox(FL_COMBOX_TYPE type,
68 FL_Coord x, FL_Coord y, FL_Coord w, FL_Coord h,
75 /* The width and x-position of button_state, respectively. */
76 FL_Coord const ws = 0.7 * h;
77 FL_Coord const xs = x + w - ws;
79 /* The width of button_chosen */
80 FL_Coord const wc = (type == FL_DROPLIST_COMBOX) ? (w - ws) : w;
82 ob = fl_make_object(FL_COMBOX, type, x, y, w, h, label, combox_handle);
83 ob->align = FL_ALIGN_LEFT;
85 sp = ob->spec = fl_calloc(1, sizeof(COMBOX_SPEC));
87 sp->browser_height = 100;
88 sp->browser_position = FL_FREEBROWSER_BELOW;
90 sp->browser = fl_create_freebrowser(sp);
91 sp->browser->callback = update_button_chosen;
94 if (type == FL_DROPLIST_COMBOX) {
95 sp->button_state = fl_add_button(FL_NORMAL_BUTTON, xs, y, ws, h, "");
97 button = sp->button_state;
98 fl_set_object_lalign(button, FL_ALIGN_CENTER|FL_ALIGN_INSIDE);
99 fl_set_object_callback(button, state_cb, 0);
100 fl_set_object_posthandler(button, combox_post);
101 fl_set_object_prehandler(button, combox_pre);
102 set_state_label(sp, COMBOX_CLOSED);
104 set_activation(button, DEACTIVATE);
106 button->u_vdata = sp;
109 sp->button_chosen = fl_add_button(FL_NORMAL_TEXT, x, y, wc, h, "");
111 button = sp->button_chosen;
112 fl_set_object_boxtype(button, FL_FRAME_BOX);
113 fl_set_object_lalign(button, FL_ALIGN_CENTER|FL_ALIGN_INSIDE);
114 fl_set_object_callback(button, chosen_cb, 0);
115 fl_set_object_posthandler(button, combox_post);
116 fl_set_object_prehandler(button, combox_pre);
117 set_activation(button, DEACTIVATE);
119 button->u_vdata = sp;
125 FL_OBJECT * fl_add_combox(FL_COMBOX_TYPE type,
126 FL_Coord x, FL_Coord y, FL_Coord w, FL_Coord h,
129 FL_OBJECT * ob = fl_create_combox(type, x, y, w, h, label);
130 COMBOX_SPEC * sp = ob->spec;
132 if (sp->button_state)
133 fl_add_child(ob, sp->button_state);
134 fl_add_child(ob, sp->button_chosen);
136 fl_add_object(fl_current_form, ob);
141 void fl_set_combox_browser_height(FL_OBJECT * ob, int bh)
145 if (!ob || ob->objclass != FL_COMBOX)
149 sp->browser_height = bh;
153 void fl_set_combox_position(FL_OBJECT * ob, FL_COMBOX_POSITION position)
157 if (!ob || ob->objclass != FL_COMBOX)
161 sp->browser_position = (position == FL_COMBOX_ABOVE) ?
162 FL_FREEBROWSER_ABOVE : FL_FREEBROWSER_BELOW;
164 set_state_label(sp, COMBOX_CLOSED);
168 void fl_clear_combox(FL_OBJECT * ob)
173 if (!ob || ob->objclass != FL_COMBOX)
177 browser = fl_get_freebrowser_browser(sp->browser);
179 fl_clear_browser(browser);
180 fl_set_object_label(sp->button_chosen, "");
184 void fl_addto_combox(FL_OBJECT * ob, char const * text)
192 if (!ob || ob->objclass != FL_COMBOX)
196 browser = fl_get_freebrowser_browser(sp->browser);
198 /* Split the string on '|' boundaries. */
200 for (; text[i] != '\0'; ++i) {
201 if (text[i] == '|') {
203 fl_add_browser_line(browser, line);
213 fl_add_browser_line(browser, line);
216 /* By default the first item is selected */
217 if (!fl_get_browser(browser)) {
218 fl_set_object_label(sp->button_chosen, text);
219 set_activation(sp->button_chosen, ACTIVATE);
220 if (sp->button_state)
221 set_activation(sp->button_state, ACTIVATE);
226 void fl_set_combox(FL_OBJECT * ob, int sel)
231 if (!ob || ob->objclass != FL_COMBOX)
235 browser = fl_get_freebrowser_browser(sp->browser);
237 if (sel < 1 || sel > fl_get_browser_maxline(browser))
240 fl_select_browser_line(browser, sel);
241 fl_set_object_label(sp->button_chosen, fl_get_browser_line(browser, sel));
245 int fl_get_combox(FL_OBJECT * ob)
250 if (!ob || ob->objclass != FL_COMBOX)
254 browser = fl_get_freebrowser_browser(sp->browser);
255 return fl_get_browser(browser);
259 char const * fl_get_combox_text(FL_OBJECT * ob)
263 if (!ob || ob->objclass != FL_COMBOX)
267 return sp->button_chosen->label;
271 char const * fl_get_combox_line(FL_OBJECT * ob, int line)
277 if (line < 1 || !ob || ob->objclass != FL_COMBOX)
281 browser = fl_get_freebrowser_browser(sp->browser);
283 maxlines = fl_get_browser_maxline(browser);
287 return fl_get_browser_line(browser, line);
291 int fl_get_combox_maxitems(FL_OBJECT * ob)
296 if (!ob || ob->objclass != FL_COMBOX)
300 browser = fl_get_freebrowser_browser(sp->browser);
301 return fl_get_browser_maxline(browser);
305 void fl_show_combox_browser(FL_OBJECT * ob)
307 if (!ob || ob->objclass != FL_COMBOX)
310 show_browser(ob->spec);
314 void fl_hide_combox_browser(FL_OBJECT * ob)
318 if (!ob || ob->objclass != FL_COMBOX)
322 fl_free_freebrowser(sp->browser);
326 static int combox_pre(FL_OBJECT * ob, int ev, FL_Coord mx, FL_Coord my,
329 COMBOX_SPEC * sp = ob->u_vdata;
330 FL_OBJECT * combox = sp->combox;
332 return combox->prehandle ?
333 combox->prehandle(combox, ev, mx, my, key, xev) : 0;
337 static int combox_post(FL_OBJECT * ob, int ev, FL_Coord mx, FL_Coord my,
340 COMBOX_SPEC * sp = ob->u_vdata;
341 FL_OBJECT * combox = sp->combox;
343 return combox->posthandle ?
344 combox->posthandle(combox, ev, mx, my, key, xev) : 0;
348 static int combox_handle(FL_OBJECT * ob, int event, FL_Coord mx, FL_Coord my,
351 if (!ob || ob->objclass != FL_COMBOX)
356 attrib_change(ob->spec);
359 fl_draw_object_label(ob);
362 show_browser(ob->spec);
365 COMBOX_SPEC * sp = ob->spec;
366 fl_free_freebrowser(sp->browser);
367 /* children take care of themselves, but we must make sure that
368 sp itself is free-d eventually. */
369 fl_addto_freelist(sp);
377 static void set_activation(FL_OBJECT * ob, int activation)
379 switch (activation) {
381 fl_activate_object(ob);
382 fl_set_object_lcol(ob, FL_LCOL);
385 fl_deactivate_object(ob);
386 fl_set_object_lcol(ob, FL_INACTIVE);
391 static void show_browser(COMBOX_SPEC * sp)
393 FL_OBJECT * ob = sp->combox;
395 /* The browser dimensions. */
396 FL_Coord const bw = ob->w + 20;
397 FL_Coord const bh = sp->browser_height;
399 FL_Coord const abs_x = ob->form->x + ob->x;
401 FL_Coord abs_y = ob->form->y + ob->y;
402 abs_y += (sp->browser_position == FL_FREEBROWSER_BELOW) ? ob->h : -bh;
404 set_state_label(sp, COMBOX_OPEN);
405 fl_show_freebrowser(sp->browser, abs_x, abs_y, bw, bh);
409 static void state_cb(FL_OBJECT * ob, long data)
411 show_browser(ob->u_vdata);
415 static void chosen_cb(FL_OBJECT * ob, long data)
417 show_browser(ob->u_vdata);
421 static void update_button_chosen(FL_FREEBROWSER * fb, int action)
423 COMBOX_SPEC * sp = fb->parent;
425 FL_OBJECT * browser = fl_get_freebrowser_browser(sp->browser);
426 FL_OBJECT * combox = sp->combox;
427 if (!browser || !combox) return;
429 set_state_label(sp, COMBOX_CLOSED);
432 int const sel = fl_get_browser(browser);
433 char const * const text = fl_get_browser_line(browser, sel);
434 fl_set_object_label(sp->button_chosen, text);
435 fl_call_object_callback(combox);
440 static void set_state_label(COMBOX_SPEC * sp, int state)
442 char const * const up = "@2<-";
443 char const * const down = "@2->";
444 char const * label = 0;
446 if (!sp->button_state)
449 if (sp->browser_position == FL_FREEBROWSER_BELOW) {
450 label = (state == COMBOX_OPEN) ? up : down;
452 label = (state == COMBOX_OPEN) ? down : up;
454 fl_set_object_label(sp->button_state, label);
455 fl_redraw_object(sp->button_state);
459 static void attrib_change(COMBOX_SPEC * sp)
461 FL_OBJECT * parent = sp->combox;
462 FL_OBJECT * button = sp->button_chosen;
464 button->boxtype = parent->boxtype;
465 button->col1 = parent->col1;
466 button->col2 = parent->col2;
467 button->bw = parent->bw;
469 if (sp->button_state) {
470 button = sp->button_state;
472 /* The boxtype is not changed */
473 button->col1 = parent->col1;
474 button->col2 = parent->col2;
475 button->bw = parent->bw;