]> git.lyx.org Git - lyx.git/blob - src/frontends/xforms/combox.c
remove defaults stuff, let Qt handle no toolbar
[lyx.git] / src / frontends / xforms / combox.c
1 /**
2  * \file combox.c
3  *
4  * \author Alejandro Aguilar Sierra
5  * \author Angus Leeming
6  *
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.
9  */
10 #include <config.h>
11
12 #include FORMS_H_LOCATION
13 #include "combox.h"
14 #include "freebrowser.h"
15
16
17 extern void fl_add_child(FL_OBJECT *, FL_OBJECT *);
18 extern void fl_addto_freelist(void *);
19
20
21 typedef struct {
22      /** A pointer to the parent widget */
23     FL_OBJECT * combox;
24
25     FL_FREEBROWSER * browser;
26     int browser_height;
27
28     /** The browser will be displayed either below or above the main body. */
29     int browser_position;
30
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.
34      */
35     FL_OBJECT * button_state;
36
37     /**  button_chosen displays the current selection from the browser.
38      *   Click on it to toggle the browser.
39      */
40     FL_OBJECT * button_chosen;
41 } COMBOX_SPEC;
42
43
44 enum { ACTIVATE, DEACTIVATE };
45
46 enum { COMBOX_OPEN, COMBOX_CLOSED };
47
48
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 *);
53
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);
57
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);
62
63
64 FL_OBJECT * fl_create_combox(int type,
65                              FL_Coord x, FL_Coord y, FL_Coord w, FL_Coord h,
66                              char const * label)
67 {
68     FL_OBJECT * ob;
69     FL_OBJECT * button;
70     COMBOX_SPEC * sp;
71
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;
75
76     ob = fl_make_object(FL_COMBOX, type, x, y, w, h, label, combox_handle);
77     ob->align = FL_ALIGN_LEFT;
78
79     sp = ob->spec = fl_calloc(1, sizeof(COMBOX_SPEC));
80     sp->combox = ob;
81     sp->browser_height = 100;
82     sp->browser_position = FL_FREEBROWSER_BELOW;
83
84     sp->browser = fl_create_freebrowser(sp);
85     sp->browser->callback = update_button_chosen;
86
87     sp->button_state = fl_add_button(FL_NORMAL_BUTTON, xs, y, ws, h, "");
88
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);
95
96     set_activation(button, DEACTIVATE);
97     button->parent = ob;
98     button->u_vdata = sp;
99
100     sp->button_chosen = fl_add_button(FL_NORMAL_TEXT, x, y, (w - ws), h, "");
101
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);
109     button->parent = ob;
110     button->u_vdata = sp;
111
112     return ob;
113 }
114
115
116 FL_OBJECT * fl_add_combox(int type,
117                           FL_Coord x, FL_Coord y, FL_Coord w, FL_Coord h,
118                           char const * label)
119 {
120     FL_OBJECT * ob = fl_create_combox(type, x, y, w, h, label);
121     COMBOX_SPEC * sp = ob->spec;
122
123     fl_add_child(ob, sp->button_state);
124     fl_add_child(ob, sp->button_chosen);
125
126     fl_add_object(fl_current_form, ob);
127     return ob;
128 }
129
130
131 void fl_set_combox_browser_height(FL_OBJECT * ob, int bh)
132 {
133     COMBOX_SPEC * sp;
134
135     if (!ob || ob->objclass != FL_COMBOX)
136         return;
137
138     sp = ob->spec;
139     sp->browser_height = bh;
140 }
141
142
143 void fl_set_combox_position(FL_OBJECT * ob, int position)
144 {
145     COMBOX_SPEC * sp;
146
147     if (!ob || ob->objclass != FL_COMBOX)
148         return;
149
150     sp = ob->spec;
151     sp->browser_position = (position == FL_FREEBROWSER_ABOVE) ?
152         FL_FREEBROWSER_ABOVE : FL_FREEBROWSER_BELOW;
153
154     set_state_label(sp, COMBOX_CLOSED);
155 }
156
157
158 void fl_clear_combox(FL_OBJECT * ob)
159 {
160     COMBOX_SPEC * sp;
161     FL_OBJECT * browser;
162
163     if (!ob || ob->objclass != FL_COMBOX)
164         return;
165
166     sp = ob->spec;
167     browser = fl_get_freebrowser_browser(sp->browser);
168
169     fl_clear_browser(browser);
170     fl_set_object_label(sp->button_chosen, "");
171 }
172
173
174 void fl_addto_combox(FL_OBJECT * ob, char const * text)
175 {
176     COMBOX_SPEC * sp;
177     FL_OBJECT * browser;
178     int i;
179     int j;
180     char line[128];
181
182     if (!ob || ob->objclass != FL_COMBOX)
183         return;
184
185     sp = ob->spec;
186     browser = fl_get_freebrowser_browser(sp->browser);
187
188     /* Split the string on '|' boundaries. */
189     i = j = 0;
190     for (; text[i] != '\0'; ++i) {
191         if (text[i] == '|') {
192             line[j] = '\0';
193             fl_add_browser_line(browser, line);
194             j = 0;
195         } else {
196             line[j++] = text[i];
197         }
198     }
199
200     if (j != 0)
201         {
202             line[j] = '\0';
203             fl_add_browser_line(browser, line);
204         }
205
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);
211     }
212 }
213
214
215 void fl_set_combox(FL_OBJECT * ob, int sel)
216 {
217     COMBOX_SPEC * sp;
218     FL_OBJECT * browser;
219
220     if (!ob || ob->objclass != FL_COMBOX)
221         return;
222
223     sp = ob->spec;
224     browser = fl_get_freebrowser_browser(sp->browser);
225
226     if (sel < 1 || sel > fl_get_browser_maxline(browser))
227         return;
228
229     fl_select_browser_line(browser, sel);
230     fl_set_object_label(sp->button_chosen, fl_get_browser_line(browser, sel));
231 }
232
233
234 int fl_get_combox(FL_OBJECT * ob)
235 {
236     COMBOX_SPEC * sp;
237     FL_OBJECT * browser;
238
239     if (!ob || ob->objclass != FL_COMBOX)
240         return 0;
241
242     sp = ob->spec;
243     browser = fl_get_freebrowser_browser(sp->browser);
244     return fl_get_browser(browser);
245 }
246
247
248 char const * fl_get_combox_text(FL_OBJECT * ob)
249 {
250     COMBOX_SPEC * sp;
251
252     if (!ob || ob->objclass != FL_COMBOX)
253         return 0;
254
255     sp = ob->spec;
256     return sp->button_chosen->label;
257 }
258
259
260 char const * fl_get_combox_line(FL_OBJECT * ob, int line)
261 {
262     COMBOX_SPEC * sp;
263     FL_OBJECT * browser;
264     int maxlines;
265
266     if (line < 1 || !ob || ob->objclass != FL_COMBOX)
267         return 0;
268
269     sp = ob->spec;
270     browser = fl_get_freebrowser_browser(sp->browser);
271
272     maxlines = fl_get_browser_maxline(browser);
273     if (line > maxlines)
274         return 0;
275
276     return fl_get_browser_line(browser, line);
277 }
278
279
280 int fl_get_combox_maxitems(FL_OBJECT * ob)
281 {
282     COMBOX_SPEC * sp;
283     FL_OBJECT * browser;
284
285     if (!ob || ob->objclass != FL_COMBOX)
286         return 0;
287
288     sp = ob->spec;
289     browser = fl_get_freebrowser_browser(sp->browser);
290     return fl_get_browser_maxline(browser);
291 }
292
293
294 void fl_show_combox_browser(FL_OBJECT * ob)
295 {
296     if (!ob || ob->objclass != FL_COMBOX)
297         return;
298
299     show_browser(ob->spec);
300 }
301
302
303 void fl_hide_combox_browser(FL_OBJECT * ob)
304 {
305     COMBOX_SPEC * sp;
306
307     if (!ob || ob->objclass != FL_COMBOX)
308         return;
309
310     sp = ob->spec;
311     fl_free_freebrowser(sp->browser);
312 }
313
314
315 static int combox_pre(FL_OBJECT * ob, int ev, FL_Coord mx, FL_Coord my,
316                       int key, void *xev)
317 {
318     COMBOX_SPEC * sp = ob->u_vdata;
319     FL_OBJECT * combox = sp->combox;
320
321     return combox->prehandle ?
322         combox->prehandle(combox, ev, mx, my, key, xev) : 0;
323 }
324
325
326 static int combox_post(FL_OBJECT * ob, int ev, FL_Coord mx, FL_Coord my,
327                        int key, void *xev)
328 {
329     COMBOX_SPEC * sp = ob->u_vdata;
330     FL_OBJECT * combox = sp->combox;
331
332     return combox->posthandle ?
333         combox->posthandle(combox, ev, mx, my, key, xev) : 0;
334 }
335
336
337 static int combox_handle(FL_OBJECT * ob, int event, FL_Coord mx, FL_Coord my,
338                          int key, void * ev)
339 {
340     if (!ob || ob->objclass != FL_COMBOX)
341         return 0;
342
343     switch (event) {
344     case FL_DRAW:
345         attrib_change(ob->spec);
346         /* Fall through */
347     case FL_DRAWLABEL:
348         fl_draw_object_label(ob);
349         break;
350     case FL_SHORTCUT:
351         show_browser(ob->spec);
352         break;
353     case FL_FREEMEM: {
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);
359         break;
360     }
361     }
362     return 0;
363 }
364
365
366 static void set_activation(FL_OBJECT * ob, int activation)
367 {
368     switch (activation) {
369     case ACTIVATE:
370         fl_activate_object(ob);
371         fl_set_object_lcol(ob, FL_LCOL);
372         break;
373     case DEACTIVATE:
374         fl_deactivate_object(ob);
375         fl_set_object_lcol(ob, FL_INACTIVE);
376     }
377 }
378
379
380 static void show_browser(COMBOX_SPEC * sp)
381 {
382     FL_OBJECT * ob = sp->combox;
383
384     /* The browser dimensions. */
385     FL_Coord const bw = ob->w + 20;
386     FL_Coord const bh = sp->browser_height;
387
388     FL_Coord const abs_x = ob->form->x + ob->x;
389
390     FL_Coord abs_y = ob->form->y + ob->y;
391     abs_y += (sp->browser_position == FL_FREEBROWSER_BELOW) ? ob->h : -bh;
392
393     set_state_label(sp, COMBOX_OPEN);
394     fl_show_freebrowser(sp->browser, abs_x, abs_y, bw, bh);
395 }
396
397
398 static void state_cb(FL_OBJECT * ob, long data)
399 {
400     show_browser(ob->u_vdata);
401 }
402
403
404 static void chosen_cb(FL_OBJECT * ob, long data)
405 {
406     show_browser(ob->u_vdata);
407 }
408
409
410 static void update_button_chosen(FL_FREEBROWSER * fb, int action)
411 {
412     COMBOX_SPEC * sp = fb->parent;
413
414     FL_OBJECT * browser = fl_get_freebrowser_browser(sp->browser);
415     FL_OBJECT * combox = sp->combox;
416     if (!browser || !combox) return;
417
418     set_state_label(sp, COMBOX_CLOSED);
419
420     if (action == 1) {
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);
425     }
426 }
427
428
429 static void set_state_label(COMBOX_SPEC * sp, int state)
430 {
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;
436     } else {
437         label = (state == COMBOX_OPEN) ? down : up;
438     }
439     fl_set_object_label(sp->button_state, label);
440     fl_redraw_object(sp->button_state);
441 }
442
443
444 static void attrib_change(COMBOX_SPEC * sp)
445 {
446     FL_OBJECT * parent = sp->combox;
447     FL_OBJECT * button = sp->button_chosen;
448
449     button->boxtype = parent->boxtype;
450     button->col1    = parent->col1;
451     button->col2    = parent->col2;
452     button->bw      = parent->bw;
453
454     button = sp->button_state;
455
456     /* The boxtype is not changed */
457     button->col1    = parent->col1;
458     button->col2    = parent->col2;
459     button->bw      = parent->bw;
460 }