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