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