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