]> git.lyx.org Git - lyx.git/blob - src/frontends/xforms/combox.C
implement getLabelList
[lyx.git] / src / frontends / xforms / combox.C
1 // -*- C++ -*-
2 /*
3  *  Combox: A combination of two objects (a button and a browser) is
4  *          encapsulated to get a combobox-like object. All XForms 
5  *          functions are hidden.         
6  * 
7  *  GNU Copyleft 1996 Alejandro Aguilar Sierra <asierra@servidor.unam.mx>
8  *                        and the LyX Team.
9  * 
10  *  Dependencies:  Only XForms, but created to be used with LyX.
11  * 
12  */ 
13
14 /* Change log:
15  *  
16  *  2/06/1996,   Alejandro Aguilar Sierra 
17  *    Created and tested.
18  *  
19  *  4/06/1996,   Alejandro Aguilar Sierra 
20  *    Added droplist mode (a button with a black down arrow at right)
21  *    and support for middle and right buttons, as XForms choice object.
22  *
23  *  6/06/1996,   Lars Gullik Bjønnes
24  *    Added a combox with an input object. and a pre and a post handle.
25  * 
26  *  22/07/96,    Alejandro Aguilar Sierra 
27  *    Assigned to the browser its own popup window. No more need of
28  *    external pre and post handlers to simulate the wanted behaviour.
29  * 
30  */ 
31
32 #include <config.h>
33
34 #ifdef __GNUG__
35 #pragma implementation
36 #endif
37
38 #include "combox.h"
39 #include <cstring>
40
41 #include "debug.h"
42
43 using std::endl;
44
45 // These are C wrappers around static members of Combox, used as
46 // callbacks for xforms.
47 extern "C" void C_Combox_input_cb(FL_OBJECT *ob, long);
48 extern "C" void C_Combox_combo_cb(FL_OBJECT *ob, long data) ;
49 extern "C" int C_Combox_peek_event(FL_FORM * form, void *xev);
50
51 Combox::Combox(combox_type t)
52         : type(t), tabfolder1(0), tabfolder2(0)
53 {
54    browser = button = 0;
55    callback = 0;
56    label = 0;
57    cb_arg = 0;
58    _pre = 0;
59    _post = 0;
60    sel = 0;
61    form = 0;
62 }
63
64
65 Combox::~Combox()
66 {
67    remove();
68 }
69
70
71 void Combox::clear()
72 {
73         if (browser) fl_clear_browser(browser);   
74         sel = 0;
75         if (type == FL_COMBOX_INPUT)
76                 fl_set_input(label, "");
77         else
78                 fl_set_object_label(label, "");
79         is_empty = true;
80 }
81
82
83 void Combox::remove()
84 {
85         lyxerr.debug() << "Button: " << button << endl;
86         if (button) {
87                 fl_delete_object(button);
88                 fl_free_object(button); 
89         }
90         
91         lyxerr.debug() << "Label: " << label << endl;
92         if (label && label != button) {
93                 fl_delete_object(label);
94                 fl_free_object(label); 
95         }
96         
97         lyxerr.debug() << "Form: " << form << endl;
98         lyxerr.debug() << "Browser: " << browser << endl;
99         if (form && browser) {
100            fl_delete_object(browser);
101            fl_free_object(browser);
102            fl_free_form(form);
103         }
104         button = 0; 
105         browser = 0; 
106         label = 0;
107         form = 0;
108         sel = 0;
109         is_empty = true;
110 }
111
112
113 void Combox::addline(string const & text)
114 {
115         if (!browser) return;
116         fl_add_browser_line(browser, text.c_str());
117         
118         // By default the first item is selected
119         if (!sel) {
120                 sel = 1;
121                 if (type == FL_COMBOX_INPUT)
122                         fl_set_input(label, text.c_str());
123                 else
124                         fl_set_object_label(label, text.c_str()); 
125         }
126         is_empty = false;
127 }
128
129
130 bool Combox::select_text(string const & t)
131 {
132         if (!browser || t.empty()) return false;
133         int const maxline = fl_get_browser_maxline(browser);
134         
135         for (int i = 1; i <= maxline; ++i) {
136                 if (t == fl_get_browser_line(browser, i)) {
137                         select(i);
138                         return true;
139                 }
140         }
141         return false;  // t does not exist in browser
142 }
143
144
145 void Combox::select(int i)
146 {
147         if (!browser || !button) return;
148         if (i > 0 && i <= fl_get_browser_maxline(browser)) sel = i; 
149         fl_deactivate_object(button);
150         
151         if (type == FL_COMBOX_INPUT)
152                 fl_set_input(label, fl_get_browser_line(browser, sel));
153         else
154                 fl_set_object_label(label, fl_get_browser_line(browser, sel)); 
155         fl_activate_object(button); 
156 }
157
158
159 void Combox::add(int x, int y, int w, int hmin, int hmax,
160                  FL_OBJECT * tabfolder1_, FL_OBJECT * tabfolder2_)
161 {
162         // Store these for later use in working round an xforms bug in Show()
163         tabfolder1 = tabfolder1_;
164         tabfolder2 = tabfolder2_;
165
166         FL_OBJECT * obj;
167         
168         switch (type) {
169         case FL_COMBOX_DROPLIST:
170         {
171                 button = obj = fl_add_button(FL_NORMAL_BUTTON,
172                                              x+w-22, y, 22, hmin, "@2->");
173                 fl_set_object_color(obj, FL_MCOL, FL_MCOL);
174                 fl_set_object_dblbuffer(obj, 1);
175                 fl_set_object_callback(obj, C_Combox_combo_cb, 0);
176                 label = obj = fl_add_button(FL_NORMAL_TEXT, x, y, w-22, hmin, "");
177                 fl_set_object_boxtype(obj, FL_DOWN_BOX);
178                 fl_set_object_color(obj, FL_MCOL, FL_BLACK);
179                 fl_set_object_lalign(obj, FL_ALIGN_CENTER|FL_ALIGN_INSIDE);
180                 fl_set_object_dblbuffer(obj, 1);
181                 fl_set_object_callback(obj, C_Combox_combo_cb, 0);
182                 break;
183         }
184         case FL_COMBOX_NORMAL:
185         {
186                 button = obj = fl_add_button(FL_NORMAL_BUTTON, x, y, w, hmin, "");
187                 fl_set_object_color(obj, FL_MCOL, FL_MCOL);
188                 fl_set_object_boxtype(obj, FL_DOWN_BOX);
189                 fl_set_object_callback(obj, C_Combox_combo_cb, 0);
190                 fl_set_object_color(obj, FL_MCOL, FL_BLACK);
191                 label = button;
192                 break;
193         }
194         case FL_COMBOX_INPUT:
195         {
196                 button = obj = fl_add_button(FL_NORMAL_BUTTON,
197                                              x+w-22, y, 22, hmin, "@2->");
198                 fl_set_object_color(obj, FL_MCOL, FL_MCOL);
199                 fl_set_object_callback(obj, C_Combox_combo_cb, 0);
200                 label = obj = fl_add_input(FL_NORMAL_INPUT, x, y, w-22, hmin, "");
201                 fl_set_object_boxtype(obj, FL_DOWN_BOX);
202                 fl_set_object_return(obj, FL_RETURN_END_CHANGED);
203                 fl_set_object_callback(obj, C_Combox_input_cb, 0);
204                 //fl_set_object_color(obj, FL_MCOL, FL_BLACK);
205                 //fl_set_object_lalign(obj,FL_ALIGN_CENTER|FL_ALIGN_INSIDE);
206                 break;
207         }
208         } // end of switch
209
210         label->u_vdata = this;
211         button->u_vdata = this;
212
213         // Hmm, it seems fl_create_browser is broken in xforms 0.86.
214         // We have to work around that by creating the dropped browser form
215         // at this point already. However, this means that we have
216         // to do a little hacking: (Asger)
217         FL_FORM * current_form = fl_current_form;
218         fl_end_form();
219
220         bw = w + 20; bh = hmax - hmin - 12;
221
222         form = fl_bgn_form(FL_NO_BOX, bw, bh);
223         browser = obj = fl_add_browser(FL_HOLD_BROWSER, 0, 0, bw, bh, "");
224         fl_set_object_boxtype(obj, FL_UP_BOX);
225         fl_set_object_color(obj, FL_MCOL, FL_YELLOW);
226         fl_set_object_gravity(obj, NorthWestGravity, NorthWestGravity);
227         fl_set_object_callback(obj, C_Combox_combo_cb, 2);
228         fl_end_form();
229         browser->u_vdata = this;
230         form->u_vdata = browser;
231         fl_register_raw_callback(form, 
232                                  ButtonPressMask|KeyPressMask,
233                                  C_Combox_peek_event);
234
235         // And revert to adding to the old form (Asger)
236         fl_addto_form(current_form);
237 }
238
239
240 namespace {
241
242 Window save_window;
243
244 } // namespace anon
245
246
247 void Combox::Redraw()
248 {
249         if (browser) fl_redraw_object(browser);
250         if (button) fl_redraw_object(button);
251         if (label) fl_redraw_object(label);
252 }
253  
254 void Combox::Show()
255 {
256         if (_pre) _pre();
257         
258         int tmp;
259         XGetInputFocus(fl_get_display(), &save_window, &tmp); //BUG-Fix Dietmar
260         XFlush(fl_get_display());
261         if (button && type != FL_COMBOX_NORMAL) {
262                 fl_set_object_label(button, "@2<-");          
263                 fl_redraw_object(button);
264         }
265
266         int x = label->x;
267         int y = label->y + label->h;
268         if (tabfolder1) {
269                 // This is a bug work around suggested by Steve Lamont on the
270                 // xforms mailing list. It correctly positions the browser form
271                 // after the main window has been moved.
272                 // The bug only occurs in tabbed folders.
273                 int folder_x, folder_y, folder_w, folder_h;
274                 fl_get_folder_area( tabfolder1,
275                                     &folder_x, &folder_y,
276                                     &folder_w, &folder_h );
277                 x += folder_x;
278                 y += folder_y;
279
280                 if (tabfolder2) {
281                         fl_get_folder_area( tabfolder2,
282                                             &folder_x, &folder_y,
283                                             &folder_w, &folder_h );
284                         x += tabfolder2->form->x + folder_x;
285                         y += tabfolder2->form->y + folder_y;
286                 } else {
287                         x += tabfolder1->form->x;
288                         y += tabfolder1->form->y;
289                 }
290                 
291         } else {
292                 x += label->form->x;
293                 y += label->form->y;
294         }
295
296         fl_set_form_position(form, x, y);
297         fl_show_form(form, FL_PLACE_POSITION, FL_NOBORDER, "");
298         if (sel>0) {
299                 fl_set_browser_topline(browser, sel);
300                 fl_select_browser_line(browser, sel);
301         }
302         XGrabPointer(fl_get_display(), form->window, false,
303                      ButtonPressMask | ButtonReleaseMask | PointerMotionMask,
304                      GrabModeAsync, GrabModeAsync,
305                      0, 0, 0);
306         XFlush(fl_get_display());
307 }
308
309 void Combox::Hide(int who)
310 {  
311         if (!who && browser && label) {
312                 sel = fl_get_browser(browser);
313                 
314                 if (type == FL_COMBOX_INPUT)
315                         fl_set_input(label, fl_get_browser_line(browser, sel));
316                 else
317                         fl_set_object_label(label,
318                                             fl_get_browser_line(browser, sel));         
319 //              if (callback) callback(sel, cb_arg);
320         }
321         XUngrabPointer(fl_get_display(), 0);
322         XFlush(fl_get_display());
323         if (!who && browser && label && callback)
324             callback(sel, cb_arg, this);
325         if (form) {
326                 fl_hide_form(form);
327                 XSetInputFocus(fl_get_display(), save_window,
328                                RevertToParent, CurrentTime); // BUG-FIX-Dietmar
329                 XFlush(fl_get_display());
330         }
331         if (button) {
332                 if (type != FL_COMBOX_NORMAL){
333                         fl_set_object_label(button, "@2->");
334                         fl_redraw_object(button);
335                 }
336         } 
337         if (_post) _post();
338 }
339
340
341 void Combox::activate()
342 {
343         if (browser) fl_activate_object(browser);
344         if (button) fl_activate_object(button);
345         if (label) fl_activate_object(label);
346 }
347
348
349 void Combox::deactivate()
350 {
351         if (browser) fl_deactivate_object(browser);
352         if (button) fl_deactivate_object(button);
353         if (label) fl_deactivate_object(label);
354 }
355
356
357 void Combox::input_cb(FL_OBJECT * ob, long)
358 {
359         Combox * combo = static_cast<Combox*>(ob->u_vdata);
360
361         char const * text = fl_get_input(ob);
362
363         combo->addto(text ? string(text) : string());
364         combo->is_empty = false;
365 }
366
367
368 extern "C" void C_Combox_input_cb(FL_OBJECT * ob, long data)
369 {
370   Combox::input_cb(ob, data);
371 }
372
373
374 void Combox::combo_cb(FL_OBJECT * ob, long data)
375 {
376         Combox * combo = static_cast<Combox*>(ob->u_vdata);
377         switch (data) {
378         case 0:
379         {  
380                 int const i = combo->get();
381                 switch (fl_get_button_numb(ob)) {
382                 case 2: 
383                 {
384                         combo->select(i - 1); 
385                         if (combo->callback)
386                                 combo->callback(combo->sel,
387                                                 combo->cb_arg, combo);
388                         break;
389                 }
390                 case 3: 
391                 {
392                         combo->select(i + 1);  
393                         if (combo->callback)
394                                 combo->callback(combo->sel,
395                                                 combo->cb_arg, combo);
396                         break;
397                 }
398                 default: combo->Show(); break;
399                 }
400                 break;
401         }
402         case 2:
403                 combo->Hide();
404                 break;
405         }
406 }
407
408 extern "C" void C_Combox_combo_cb(FL_OBJECT * ob, long data) 
409 {
410         Combox::combo_cb(ob, data);
411 }
412
413
414 int Combox::peek_event(FL_FORM * form, void * xev)
415 {
416         FL_OBJECT * ob = static_cast<FL_OBJECT *>(form->u_vdata);
417         Combox * combo = static_cast<Combox*>(ob->u_vdata);
418         
419         // I don't know why belowmouse does not work, but it doesn't. (Asger)
420         // Are we sure? Please verify. (Lgb)
421         if (static_cast<XEvent *>(xev)->type == ButtonPress && (
422                 static_cast<XEvent *>(xev)->xbutton.x - ob->x < 0 ||
423                 static_cast<XEvent *>(xev)->xbutton.x - ob->x > ob->w ||
424                 static_cast<XEvent *>(xev)->xbutton.y - ob->y < 0 ||
425                 static_cast<XEvent *>(xev)->xbutton.y - ob->y > ob->h)) {
426                 combo->Hide(1); 
427                 return 1;
428         }
429                 
430         if (static_cast<XEvent*>(xev)->type != KeyPress) return 0;
431         
432         char s_r[10]; s_r[9] = '\0';
433         KeySym keysym_return;
434         XLookupString(&static_cast<XEvent*>(xev)->xkey, s_r, 10, 
435                               &keysym_return, 0);
436         XFlush(fl_get_display());
437         switch (keysym_return) {
438         case XK_Down:
439                 if (fl_get_browser(combo->browser) <
440                     fl_get_browser_maxline(combo->browser))
441                         fl_select_browser_line(combo->browser,
442                                                fl_get_browser(combo->browser)+1);
443                 if (fl_get_browser(combo->browser)>= 
444                     fl_get_browser_topline(combo->browser) +
445                     fl_get_browser_screenlines(combo->browser))
446                         fl_set_browser_topline(combo->browser,
447                                                fl_get_browser(combo->browser)
448                                                - fl_get_browser_screenlines(combo->browser)+1);
449                 if (fl_get_browser(combo->browser)<
450                     fl_get_browser_topline(combo->browser))
451                         fl_set_browser_topline(combo->browser,
452                                                fl_get_browser(combo->browser));
453                 return 1; 
454         case XK_Up:
455                 if (fl_get_browser(combo->browser) > 1)
456                         fl_select_browser_line(combo->browser,
457                                                fl_get_browser(combo->browser)-1);
458                 if (fl_get_browser(combo->browser)>= 
459                     fl_get_browser_topline(combo->browser) +
460                     fl_get_browser_screenlines(combo->browser))
461                         fl_set_browser_topline(combo->browser,
462                                                fl_get_browser(combo->browser)
463                                                - fl_get_browser_screenlines(combo->browser)+1);
464                 if (fl_get_browser(combo->browser) <
465                     fl_get_browser_topline(combo->browser))
466                         fl_set_browser_topline(combo->browser,
467                                                fl_get_browser(combo->browser));
468                 return 1;
469         case XK_Return:
470                 combo->Hide();
471                 return 1;
472         case XK_Escape:
473                 combo->Hide(1);
474                 return 1;
475         }
476         return 0;  
477 }
478         
479 extern "C" int C_Combox_peek_event(FL_FORM * form, void *xev)
480 {
481         return Combox::peek_event(form, xev);
482 }
483
484
485 #ifdef TESTCOMBO
486 typedef struct {
487         FL_FORM *test;
488         FL_OBJECT *bar;
489         void *vdata;
490         long ldata;
491 } FD_test;
492
493 //Combox combo(FL_COMBOX_DROPLIST);
494 Combox combo(FL_COMBOX_INPUT);
495
496 FD_test *fd_test;
497    
498 FD_test *create_form_test(void)
499 {
500    FL_OBJECT *obj;
501    FD_test *fdui = (FD_test *) fl_calloc(1, sizeof(*fdui));
502    
503    fdui->test = fl_bgn_form(FL_NO_BOX, 320, 190);
504    obj = fl_add_box(FL_UP_BOX, 0, 0, 320, 190, "");
505    obj = fl_add_box(FL_DOWN_BOX, 10, 50, 300, 110, "");
506    obj = fl_add_button(FL_NORMAL_BUTTON, 250, 10, 50, 30, _("Done"));
507    combo.add(10, 15, 120, 25, 135); 
508    fl_end_form();
509
510   return fdui;
511 }
512
513 void combo_cb(int i)
514 {
515    fprintf(stderr, "selected %d:%s\n", i, combo.getline());
516 }
517
518 int main(int argc, char *argv[])
519 {
520         //int n1;
521    
522    // Same defaults as in lyx 
523    FL_IOPT cntl;
524    cntl.buttonFontSize = FL_NORMAL_SIZE;
525    cntl.browserFontSize = FL_NORMAL_SIZE;
526    cntl.labelFontSize = FL_NORMAL_SIZE;
527    cntl.choiceFontSize = FL_NORMAL_SIZE;
528    cntl.inputFontSize = FL_NORMAL_SIZE;
529    cntl.borderWidth = -2;
530    fl_set_defaults(FL_PDButtonFontSize, &cntl);  
531    fl_set_defaults(FL_PDBrowserFontSize, &cntl);  
532    fl_set_defaults(FL_PDLabelFontSize, &cntl);  
533    fl_set_defaults(FL_PDChoiceFontSize, &cntl);  
534    fl_set_defaults(FL_PDInputFontSize, &cntl);  
535    fl_set_defaults(FL_PDBorderWidth, &cntl);
536    fl_initialize(&argc, argv, 0, 0, 0);
537    
538    fd_test = create_form_test();
539
540    /* fill-in form initialization code */
541    combo.addline("Title");
542    combo.addline("Author");
543    combo.addline("Date");
544    combo.addline("Abstract");
545    combo.addline("Chapter");
546    combo.addline("Section");
547    combo.addline("Subsection");
548    combo.addline("List");
549    combo.addline("Description");
550    combo.addline("Verse");
551    combo.addline("Verbatim");
552    combo.setcallback(combo_cb);
553 //   combo.select(4);
554    
555    /* show the first form */
556    fl_show_form(fd_test->test, FL_PLACE_CENTER, FL_FULLBORDER, "test");
557    fl_do_forms();
558    return 0;
559 }
560
561 #endif