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