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