]> git.lyx.org Git - lyx.git/blob - src/combox.C
2dcffc9743eeb4d11f74c73ff828ea6dcd0499c2
[lyx.git] / src / 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 (C) 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 Combox::Combox(combox_type t): type(t)
44 {
45    browser = button = 0;
46    callback = 0;
47    label = 0;
48    cb_arg = 0;
49    _pre = 0;
50    _post = 0;
51    sel = 0;
52    form = 0;
53 }
54
55
56 Combox::~Combox()
57 {
58    remove();
59 }
60
61
62 void Combox::clear()
63 {
64         if (browser) fl_clear_browser(browser);   
65         sel = 0;
66         if (type == FL_COMBOX_INPUT)
67                 fl_set_input(label, "");
68         else
69                 fl_set_object_label(label, "");
70         is_empty = true;
71 }
72
73
74 void Combox::remove()
75 {
76         lyxerr.debug() << "Button: " << button << endl;
77         if (button) {
78                 fl_delete_object(button);
79                 fl_free_object(button); 
80         }
81         
82         lyxerr.debug() << "Label: " << label << endl;
83         if (label && label!=button) {
84                 fl_delete_object(label);
85                 fl_free_object(label); 
86         }
87         
88         lyxerr.debug() << "Form: " << form << endl;
89         lyxerr.debug() << "Browser: " << browser << endl;
90         if (form && browser) {
91            fl_delete_object(browser);
92            fl_free_object(browser);
93            fl_free_form(form);
94         }
95         button = 0; 
96         browser = 0; 
97         label = 0;
98         form = 0;
99         sel = 0;
100         is_empty = true;
101 }
102
103
104 void Combox::addline(char const* text)
105 {
106         if (!browser) return;
107         fl_add_browser_line(browser, text);
108         
109         // By default the first item is selected
110         if (!sel) {
111                 sel = 1;
112                 if (type == FL_COMBOX_INPUT)
113                         fl_set_input(label, text);
114                 else
115                         fl_set_object_label(label, text); 
116         }
117         is_empty = false;
118 }
119
120
121 bool Combox::select_text(char const* t)
122 {
123         if (!browser || !t) return false;
124         for (int i=1; i<=fl_get_browser_maxline(browser); i++) {
125                 if (!strcmp(t, fl_get_browser_line(browser, i))) {
126                         select(i);
127                         return true;
128                 }
129         }
130         return false;  // t does not exist in browser
131 }
132
133
134 void Combox::select(int i)
135 {
136         if (!browser || !button) return;
137         if (i>0 && i<=fl_get_browser_maxline(browser)) sel = i; 
138         fl_deactivate_object(button);
139         
140         if (type == FL_COMBOX_INPUT)
141                 fl_set_input(label, fl_get_browser_line(browser, sel));
142         else
143                 fl_set_object_label(label, fl_get_browser_line(browser, sel)); 
144         fl_activate_object(button); 
145 }
146
147
148 void Combox::add(int x, int y, int w, int hmin, int hmax)
149 {  
150         FL_OBJECT *obj;
151         
152         switch(type) {
153         case FL_COMBOX_DROPLIST:
154         {
155                 button = obj = fl_add_button(FL_NORMAL_BUTTON,
156                                              x+w-22,y,22,hmin,"@2->");
157                 fl_set_object_color(obj,FL_MCOL, FL_MCOL);
158                 fl_set_object_dblbuffer(obj, 1);
159                 fl_set_object_callback(obj,combo_cb,0);
160                 label = obj = fl_add_button(FL_NORMAL_TEXT,x,y,w-22,hmin,"");
161                 fl_set_object_boxtype(obj,FL_DOWN_BOX);
162                 fl_set_object_color(obj,FL_MCOL,FL_BLACK);
163                 fl_set_object_lalign(obj,FL_ALIGN_CENTER|FL_ALIGN_INSIDE);
164                 fl_set_object_dblbuffer(obj, 1);
165                 fl_set_object_callback(obj,combo_cb,0);
166                 break;
167         }
168         case FL_COMBOX_NORMAL:
169         {
170                 button = obj = fl_add_button(FL_NORMAL_BUTTON,x,y,w,hmin,"");
171                 fl_set_object_color(obj,FL_MCOL, FL_MCOL);
172                 fl_set_object_boxtype(obj,FL_DOWN_BOX);
173                 fl_set_object_callback(obj,combo_cb,0);
174                 fl_set_object_color(obj,FL_MCOL,FL_BLACK);
175                 label = button;
176                 break;
177         }
178         case FL_COMBOX_INPUT:
179         {
180                 button = obj = fl_add_button(FL_NORMAL_BUTTON,
181                                              x+w-22,y,22,hmin,"@2->");
182                 fl_set_object_color(obj,FL_MCOL, FL_MCOL);
183                 fl_set_object_callback(obj,combo_cb,0);
184                 label = obj = fl_add_input(FL_NORMAL_INPUT,x,y,w-22,hmin,"");
185                 fl_set_object_boxtype(obj,FL_DOWN_BOX);
186                 fl_set_object_return(obj, FL_RETURN_END_CHANGED);
187                 fl_set_object_callback(obj,input_cb,0);
188                 //fl_set_object_color(obj,FL_MCOL,FL_BLACK);
189                 //fl_set_object_lalign(obj,FL_ALIGN_CENTER|FL_ALIGN_INSIDE);
190                 break;
191         }
192         } // end of switch
193
194         label->u_vdata = (void*)this;
195         button->u_vdata = (void*)this;
196
197         // Hmm, it seems fl_create_browser is broken in xforms 0.86.
198         // We have to work around that by creating the dropped browser form
199         // at this point already. However, this means that we have
200         // to do a little hacking: (Asger)
201         FL_FORM * current_form = fl_current_form;
202         fl_end_form();
203
204         bw = w+20; bh = hmax-hmin-12;
205
206         form = fl_bgn_form(FL_NO_BOX, bw, bh);
207         browser = obj = fl_add_browser(FL_HOLD_BROWSER, 0, 0, bw,bh,"");
208         fl_set_object_boxtype(obj,FL_UP_BOX);
209         fl_set_object_color(obj,FL_MCOL, FL_YELLOW);
210         fl_set_object_gravity(obj, NorthWestGravity, NorthWestGravity);
211         fl_set_object_callback(obj,combo_cb,2);
212         fl_end_form();
213         browser->u_vdata = (void*)this;
214         form->u_vdata = browser;
215         fl_register_raw_callback(form, ButtonPressMask|KeyPressMask,peek_event);
216
217         // And revert to adding to the old form (Asger)
218         fl_addto_form(current_form);
219 }
220
221
222 static Window save_window;
223
224
225 void Combox::Redraw()
226 {
227         if (browser) fl_redraw_object(browser);
228         if (button) fl_redraw_object(button);
229         if (label) fl_redraw_object(label);
230 }
231  
232 void Combox::Show()
233 {
234         if (_pre) _pre();
235         
236         int tmp;
237         XGetInputFocus(fl_display, &save_window, &tmp); //BUG-Fix Dietmar
238         XFlush(fl_display);
239         if (button && type != FL_COMBOX_NORMAL) {
240                 fl_set_object_label(button, "@2<-");          
241                 fl_redraw_object(button);
242         }
243         int x = label->form->x + label->x, y = label->form->y + label->y;
244         fl_set_form_position(form, x, y + label->h);
245         fl_show_form(form, FL_PLACE_POSITION, FL_NOBORDER, "");
246         if (sel>0) {
247                 fl_set_browser_topline(browser, sel);
248                 fl_select_browser_line(browser, sel);
249         }
250         XGrabPointer(fl_display, form->window, false,
251                      ButtonPressMask | ButtonReleaseMask | PointerMotionMask,
252                      GrabModeAsync, GrabModeAsync,
253                      0, 0,0);
254         XFlush(fl_display);
255 }
256
257 void Combox::Hide(int who)
258 {  
259         if (!who && browser && label) {
260                 sel = fl_get_browser(browser);
261                 
262                 if (type == FL_COMBOX_INPUT)
263                         fl_set_input(label, fl_get_browser_line(browser, sel));
264                 else
265                         fl_set_object_label(label,
266                                             fl_get_browser_line(browser, sel));         
267                 if (callback) callback(sel,cb_arg);
268         }
269         XUngrabPointer(fl_display, 0);
270         XFlush(fl_display);
271         if (form) {
272                 fl_hide_form(form);
273                 XSetInputFocus(fl_display, save_window,
274                                RevertToParent, CurrentTime); // BUG-FIX-Dietmar
275                 XFlush(fl_display);
276         }
277         if (button) {
278                 if (type != FL_COMBOX_NORMAL){
279                         fl_set_object_label(button, "@2->");
280                         fl_redraw_object(button);
281                 }
282         } 
283         if (_post) _post();
284 }
285
286
287 void Combox::activate()
288 {
289         if (browser) fl_activate_object(browser);
290         if (button) fl_activate_object(button);
291         if (label) fl_activate_object(label);
292 }
293
294
295 void Combox::deactivate()
296 {
297         if (browser) fl_deactivate_object(browser);
298         if (button) fl_deactivate_object(button);
299         if (label) fl_deactivate_object(label);
300 }
301
302 void Combox::input_cb(FL_OBJECT *ob, long)
303 {
304         Combox *combo = (Combox*)ob->u_vdata;
305
306         char const *text = fl_get_input(ob);
307
308         combo->addto(text);
309         combo->is_empty = false;
310 }
311
312
313 void Combox::combo_cb(FL_OBJECT *ob, long data)
314 {
315         Combox *combo = (Combox*)ob->u_vdata;
316         switch (data) {
317         case 0:
318         {  
319                 int i = combo->get();
320                 switch (fl_get_button_numb(ob)) {
321                 case 2: 
322                 {
323                         combo->select(--i); 
324                         if (combo->callback)
325                                 combo->callback(combo->sel,
326                                                 combo->cb_arg);
327                         break;
328                 }
329                 case 3: 
330                 {
331                         combo->select(++i);  
332                         if (combo->callback)
333                                 combo->callback(combo->sel,
334                                                 combo->cb_arg);
335                         break;
336                 }
337                 default: combo->Show(); break;
338                 }
339                 break;
340         }
341         case 2:
342                 combo->Hide();
343                 break;
344         }
345 }
346
347
348 int Combox::peek_event(FL_FORM * form, void *xev)
349 {
350         FL_OBJECT *ob = (FL_OBJECT *)form->u_vdata;
351         Combox *combo = (Combox*)ob->u_vdata;
352         
353 #if FL_REVISION < 86
354         if(((XEvent *)xev)->type==ButtonPress && !ob->belowmouse)
355 #endif
356 #if FL_REVISION > 85
357 // I don't know why belowmouse does not work, but it doesn't. (Asger)
358                 if (((XEvent *) xev)->type == ButtonPress && (
359                         ((XEvent *)xev)->xbutton.x - ob->x < 0 ||
360                         ((XEvent *)xev)->xbutton.x - ob->x > ob->w ||
361                         ((XEvent *)xev)->xbutton.y - ob->y < 0 ||
362                         ((XEvent *)xev)->xbutton.y - ob->y > ob->h))
363 #endif
364         {
365                 combo->Hide(1); 
366                 return 1;
367         }
368                 
369         if (((XEvent*)xev)->type != KeyPress) return 0;
370         
371         char s_r[10];
372         static int num_bytes;
373         KeySym keysym_return;
374         num_bytes = XLookupString(&((XEvent*)xev)->xkey, s_r, 10, 
375                                   &keysym_return, 0);
376         XFlush(fl_display);
377         switch (keysym_return) {
378         case XK_Down:
379                 if (fl_get_browser(combo->browser) <
380                     fl_get_browser_maxline(combo->browser))
381                         fl_select_browser_line(combo->browser,
382                                                fl_get_browser(combo->browser)+1);
383                 if (fl_get_browser(combo->browser)>=
384                     fl_get_browser_topline(combo->browser) +
385                     fl_get_browser_screenlines(combo->browser))
386                         fl_set_browser_topline(combo->browser,
387                                                fl_get_browser(combo->browser)
388                                                - fl_get_browser_screenlines(combo->browser)+1);
389                 if (fl_get_browser(combo->browser)<
390                     fl_get_browser_topline(combo->browser))
391                         fl_set_browser_topline(combo->browser,
392                                                fl_get_browser(combo->browser));
393                 return 1; 
394         case XK_Up:
395                 if (fl_get_browser(combo->browser) > 1)
396                         fl_select_browser_line(combo->browser,
397                                                fl_get_browser(combo->browser)-1);
398                 if (fl_get_browser(combo->browser)>=
399                     fl_get_browser_topline(combo->browser) +
400                     fl_get_browser_screenlines(combo->browser))
401                         fl_set_browser_topline(combo->browser,
402                                                fl_get_browser(combo->browser)
403                                                - fl_get_browser_screenlines(combo->browser)+1);
404                 if (fl_get_browser(combo->browser) <
405                     fl_get_browser_topline(combo->browser))
406                         fl_set_browser_topline(combo->browser,
407                                                fl_get_browser(combo->browser));
408                 return 1;
409         case XK_Return:
410                 combo->Hide();
411                 return 1;
412         case XK_Escape:
413                 combo->Hide(1);
414                 return 1;
415         }
416         return 0;  
417 }
418         
419
420 #ifdef TESTCOMBO
421 typedef struct {
422         FL_FORM *test;
423         FL_OBJECT *bar;
424         void *vdata;
425         long ldata;
426 } FD_test;
427
428 //Combox combo(FL_COMBOX_DROPLIST);
429 Combox combo(FL_COMBOX_INPUT);
430
431 FD_test *fd_test;
432    
433 FD_test *create_form_test(void)
434 {
435    FL_OBJECT *obj;
436    FD_test *fdui = (FD_test *) fl_calloc(1, sizeof(*fdui));
437    
438    fdui->test = fl_bgn_form(FL_NO_BOX, 320, 190);
439    obj = fl_add_box(FL_UP_BOX,0,0,320,190,"");
440    obj = fl_add_box(FL_DOWN_BOX,10,50,300,110,"");
441    obj = fl_add_button(FL_NORMAL_BUTTON,250,10,50,30,_("Done"));
442    combo.add(10,15,120,25,135); 
443    fl_end_form();
444
445   return fdui;
446 }
447
448 void combo_cb(int i)
449 {
450    fprintf(stderr, "selected %d:%s\n", i, combo.getline());
451 }
452
453 int main(int argc, char *argv[])
454 {
455         //int n1;
456    
457    // Same defaults as in lyx 
458    FL_IOPT cntl;
459    cntl.buttonFontSize = FL_NORMAL_SIZE;
460    cntl.browserFontSize = FL_NORMAL_SIZE;
461    cntl.labelFontSize = FL_NORMAL_SIZE;
462    cntl.choiceFontSize = FL_NORMAL_SIZE;
463    cntl.inputFontSize = FL_NORMAL_SIZE;
464    cntl.borderWidth = -2;
465    fl_set_defaults(FL_PDButtonFontSize, &cntl);  
466    fl_set_defaults(FL_PDBrowserFontSize, &cntl);  
467    fl_set_defaults(FL_PDLabelFontSize, &cntl);  
468    fl_set_defaults(FL_PDChoiceFontSize, &cntl);  
469    fl_set_defaults(FL_PDInputFontSize, &cntl);  
470    fl_set_defaults(FL_PDBorderWidth, &cntl);
471    fl_initialize(&argc, argv, 0, 0, 0);
472    
473    fd_test = create_form_test();
474
475    /* fill-in form initialization code */
476    combo.addline("Title");
477    combo.addline("Author");
478    combo.addline("Date");
479    combo.addline("Abstract");
480    combo.addline("Chapter");
481    combo.addline("Section");
482    combo.addline("Subsection");
483    combo.addline("List");
484    combo.addline("Description");
485    combo.addline("Verse");
486    combo.addline("Verbatim");
487    combo.setcallback(combo_cb);
488 //   combo.select(4);
489    
490    /* show the first form */
491    fl_show_form(fd_test->test,FL_PLACE_CENTER,FL_FULLBORDER,"test");
492    fl_do_forms();
493    return 0;
494 }
495
496 #endif