4 * \author Alejandro Aguilar Sierra
5 * \author Angus Leeming
7 * This is a rewrite of Alejandro's C++ Combox class, originally written
8 * for LyX in 1996. The rewrite turns it into a native xforms widget.
12 #include FORMS_H_LOCATION
14 #include "freebrowser.h"
17 extern void fl_add_child(FL_OBJECT *, FL_OBJECT *);
18 extern void fl_addto_freelist(void *);
22 /** A pointer to the parent widget */
25 FL_FREEBROWSER * browser;
28 /** The browser will be displayed either below or above the main body. */
31 /** button_state displays a down or up arrow depending on whether the
32 * browser is visible or not.
33 * Click on it to toggle the browser.
35 FL_OBJECT * button_state;
37 /** button_chosen displays the current selection from the browser.
38 * Click on it to toggle the browser.
40 FL_OBJECT * button_chosen;
44 enum { ACTIVATE, DEACTIVATE };
46 enum { COMBOX_OPEN, COMBOX_CLOSED };
49 /* function declarations */
50 static int combox_pre(FL_OBJECT *, int, FL_Coord, FL_Coord, int, void *);
51 static int combox_post(FL_OBJECT *, int, FL_Coord, FL_Coord, int, void *);
52 static int combox_handle(FL_OBJECT *, int, FL_Coord, FL_Coord, int, void *);
54 static void update_button_chosen(FL_FREEBROWSER * fb, int action);
55 static void chosen_cb(FL_OBJECT * ob, long data);
56 static void state_cb(FL_OBJECT * ob, long data);
58 static void show_browser(COMBOX_SPEC * sp);
59 static void set_activation(FL_OBJECT * ob, int activation);
60 static void set_state_label(COMBOX_SPEC * sp, int state);
61 static void attrib_change(COMBOX_SPEC * sp);
64 FL_OBJECT * fl_create_combox(int type,
65 FL_Coord x, FL_Coord y, FL_Coord w, FL_Coord h,
72 /* The width and x-position of button_state, respectively. */
73 FL_Coord const ws = 0.7 * h;
74 FL_Coord const xs = x + w - ws;
76 ob = fl_make_object(FL_COMBOX, type, x, y, w, h, label, combox_handle);
77 ob->align = FL_ALIGN_LEFT;
79 sp = ob->spec = fl_calloc(1, sizeof(COMBOX_SPEC));
81 sp->browser_height = 100;
82 sp->browser_position = FL_FREEBROWSER_BELOW;
84 sp->browser = fl_create_freebrowser(sp);
85 sp->browser->callback = update_button_chosen;
87 sp->button_state = fl_add_button(FL_NORMAL_BUTTON, xs, y, ws, h, "");
89 button = sp->button_state;
90 fl_set_object_lalign(button, FL_ALIGN_CENTER|FL_ALIGN_INSIDE);
91 fl_set_object_callback(button, state_cb, 0);
92 fl_set_object_posthandler(button, combox_post);
93 fl_set_object_prehandler(button, combox_pre);
94 set_state_label(sp, COMBOX_CLOSED);
96 set_activation(button, DEACTIVATE);
100 sp->button_chosen = fl_add_button(FL_NORMAL_TEXT, x, y, (w - ws), h, "");
102 button = sp->button_chosen;
103 fl_set_object_boxtype(button, FL_FRAME_BOX);
104 fl_set_object_lalign(button, FL_ALIGN_CENTER|FL_ALIGN_INSIDE);
105 fl_set_object_callback(button, chosen_cb, 0);
106 fl_set_object_posthandler(button, combox_post);
107 fl_set_object_prehandler(button, combox_pre);
108 set_activation(button, DEACTIVATE);
110 button->u_vdata = sp;
116 FL_OBJECT * fl_add_combox(int type,
117 FL_Coord x, FL_Coord y, FL_Coord w, FL_Coord h,
120 FL_OBJECT * ob = fl_create_combox(type, x, y, w, h, label);
121 COMBOX_SPEC * sp = ob->spec;
123 fl_add_child(ob, sp->button_state);
124 fl_add_child(ob, sp->button_chosen);
126 fl_add_object(fl_current_form, ob);
131 void fl_set_combox_browser_height(FL_OBJECT * ob, int bh)
135 if (!ob || ob->objclass != FL_COMBOX)
139 sp->browser_height = bh;
143 void fl_set_combox_position(FL_OBJECT * ob, int position)
147 if (!ob || ob->objclass != FL_COMBOX)
151 sp->browser_position = (position == FL_FREEBROWSER_ABOVE) ?
152 FL_FREEBROWSER_ABOVE : FL_FREEBROWSER_BELOW;
154 set_state_label(sp, COMBOX_CLOSED);
158 void fl_clear_combox(FL_OBJECT * ob)
163 if (!ob || ob->objclass != FL_COMBOX)
167 browser = fl_get_freebrowser_browser(sp->browser);
169 fl_clear_browser(browser);
170 fl_set_object_label(sp->button_chosen, "");
174 void fl_addto_combox(FL_OBJECT * ob, char const * text)
182 if (!ob || ob->objclass != FL_COMBOX)
186 browser = fl_get_freebrowser_browser(sp->browser);
188 /* Split the string on '|' boundaries. */
190 for (; text[i] != '\0'; ++i) {
191 if (text[i] == '|') {
193 fl_add_browser_line(browser, line);
203 fl_add_browser_line(browser, line);
206 /* By default the first item is selected */
207 if (!fl_get_browser(browser)) {
208 fl_set_object_label(sp->button_chosen, text);
209 set_activation(sp->button_chosen, ACTIVATE);
210 set_activation(sp->button_state, ACTIVATE);
215 void fl_set_combox(FL_OBJECT * ob, int sel)
220 if (!ob || ob->objclass != FL_COMBOX)
224 browser = fl_get_freebrowser_browser(sp->browser);
226 if (sel < 1 || sel > fl_get_browser_maxline(browser))
229 fl_select_browser_line(browser, sel);
230 fl_set_object_label(sp->button_chosen, fl_get_browser_line(browser, sel));
234 int fl_get_combox(FL_OBJECT * ob)
239 if (!ob || ob->objclass != FL_COMBOX)
243 browser = fl_get_freebrowser_browser(sp->browser);
244 return fl_get_browser(browser);
248 char const * fl_get_combox_text(FL_OBJECT * ob)
252 if (!ob || ob->objclass != FL_COMBOX)
256 return sp->button_chosen->label;
260 char const * fl_get_combox_line(FL_OBJECT * ob, int line)
266 if (line < 1 || !ob || ob->objclass != FL_COMBOX)
270 browser = fl_get_freebrowser_browser(sp->browser);
272 maxlines = fl_get_browser_maxline(browser);
276 return fl_get_browser_line(browser, line);
280 int fl_get_combox_maxitems(FL_OBJECT * ob)
285 if (!ob || ob->objclass != FL_COMBOX)
289 browser = fl_get_freebrowser_browser(sp->browser);
290 return fl_get_browser_maxline(browser);
294 void fl_show_combox_browser(FL_OBJECT * ob)
296 if (!ob || ob->objclass != FL_COMBOX)
299 show_browser(ob->spec);
303 void fl_hide_combox_browser(FL_OBJECT * ob)
307 if (!ob || ob->objclass != FL_COMBOX)
311 fl_free_freebrowser(sp->browser);
315 static int combox_pre(FL_OBJECT * ob, int ev, FL_Coord mx, FL_Coord my,
318 COMBOX_SPEC * sp = ob->u_vdata;
319 FL_OBJECT * combox = sp->combox;
321 return combox->prehandle ?
322 combox->prehandle(combox, ev, mx, my, key, xev) : 0;
326 static int combox_post(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->posthandle ?
333 combox->posthandle(combox, ev, mx, my, key, xev) : 0;
337 static int combox_handle(FL_OBJECT * ob, int event, FL_Coord mx, FL_Coord my,
340 if (!ob || ob->objclass != FL_COMBOX)
345 attrib_change(ob->spec);
348 fl_draw_object_label(ob);
351 show_browser(ob->spec);
354 COMBOX_SPEC * sp = ob->spec;
355 fl_free_freebrowser(sp->browser);
356 /* children take care of themselves, but we must make sure that
357 sp itself is free-d eventually. */
358 fl_addto_freelist(sp);
366 static void set_activation(FL_OBJECT * ob, int activation)
368 switch (activation) {
370 fl_activate_object(ob);
371 fl_set_object_lcol(ob, FL_LCOL);
374 fl_deactivate_object(ob);
375 fl_set_object_lcol(ob, FL_INACTIVE);
380 static void show_browser(COMBOX_SPEC * sp)
382 FL_OBJECT * ob = sp->combox;
384 /* The browser dimensions. */
385 FL_Coord const bw = ob->w + 20;
386 FL_Coord const bh = sp->browser_height;
388 FL_Coord const abs_x = ob->form->x + ob->x;
390 FL_Coord abs_y = ob->form->y + ob->y;
391 abs_y += (sp->browser_position == FL_FREEBROWSER_BELOW) ? ob->h : -bh;
393 set_state_label(sp, COMBOX_OPEN);
394 fl_show_freebrowser(sp->browser, abs_x, abs_y, bw, bh);
398 static void state_cb(FL_OBJECT * ob, long data)
400 show_browser(ob->u_vdata);
404 static void chosen_cb(FL_OBJECT * ob, long data)
406 show_browser(ob->u_vdata);
410 static void update_button_chosen(FL_FREEBROWSER * fb, int action)
412 COMBOX_SPEC * sp = fb->parent;
414 FL_OBJECT * browser = fl_get_freebrowser_browser(sp->browser);
415 FL_OBJECT * combox = sp->combox;
416 if (!browser || !combox) return;
418 set_state_label(sp, COMBOX_CLOSED);
421 int const sel = fl_get_browser(browser);
422 char const * const text = fl_get_browser_line(browser, sel);
423 fl_set_object_label(sp->button_chosen, text);
424 fl_call_object_callback(combox);
429 static void set_state_label(COMBOX_SPEC * sp, int state)
431 char const * const up = "@2<-";
432 char const * const down = "@2->";
433 char const * label = 0;
434 if (sp->browser_position == FL_FREEBROWSER_BELOW) {
435 label = (state == COMBOX_OPEN) ? up : down;
437 label = (state == COMBOX_OPEN) ? down : up;
439 fl_set_object_label(sp->button_state, label);
440 fl_redraw_object(sp->button_state);
444 static void attrib_change(COMBOX_SPEC * sp)
446 FL_OBJECT * parent = sp->combox;
447 FL_OBJECT * button = sp->button_chosen;
449 button->boxtype = parent->boxtype;
450 button->col1 = parent->col1;
451 button->col2 = parent->col2;
452 button->bw = parent->bw;
454 button = sp->button_state;
456 /* The boxtype is not changed */
457 button->col1 = parent->col1;
458 button->col2 = parent->col2;
459 button->bw = parent->bw;