]> git.lyx.org Git - lyx.git/blob - src/frontends/xforms/DropDown.C
better support for keypad keys
[lyx.git] / src / frontends / xforms / DropDown.C
1 /**
2  * \file DropDown.C
3  * Copyright 2001 the LyX Team
4  * Read the file COPYING
5  *
6  * \author John Levon, moz@compsoc.man.ac.uk
7  */
8
9 #include <config.h>
10
11 #ifdef __GNUG__
12 #pragma implementation
13 #endif
14
15 #include "DropDown.h"
16 #include "xforms_helpers.h"
17
18 #include FORMS_H_LOCATION
19
20 #include <iostream>
21 #include <cctype>
22
23
24 #ifndef CXX_GLOBAL_CSTD
25 using std::isprint;
26 #endif
27
28 using std::vector;
29
30
31 namespace {
32
33 extern "C" void C_CompletedCB(FL_OBJECT * ob, long)
34 {
35         DropDown * d = static_cast<DropDown*>(ob->u_vdata);
36         d->completed();
37 }
38
39
40 extern "C" int C_PeekCB(FL_FORM * form, void *xev)
41 {
42         DropDown * d = static_cast<DropDown*>(form->u_vdata);
43         return d->peek(static_cast<XEvent*>(xev));
44 }
45
46 } // namespace anon
47
48
49 DropDown::DropDown(LyXView * lv, FL_OBJECT * ob)
50         : lv_(lv)
51 {
52         form_ = fl_bgn_form(FL_NO_BOX, ob->w, 100);
53         fl_add_box(FL_UP_BOX, 0, 0, ob->w, 100, "");
54         browser_ = fl_add_browser(FL_SELECT_BROWSER, 0, 0, ob->w, 100, "");
55         form_->u_vdata = this;
56         browser_->u_vdata = this;
57         fl_set_object_callback(browser_, C_CompletedCB, 0);
58         fl_register_raw_callback(form_, KeyPressMask|ButtonPressMask, C_PeekCB);
59         fl_end_form();
60 }
61
62
63 DropDown::~DropDown()
64 {
65         if (form_->visible)
66                 fl_hide_form(form_);
67         fl_free_form(form_);
68 }
69
70
71 void DropDown::select(vector<string> const & choices, int x, int y, int w)
72 {
73         if (choices.empty())
74                 return;
75
76         fl_set_form_geometry(form_, x, y-100, w, 100);
77         fl_clear_browser(browser_);
78
79         vector<string>::const_iterator cit = choices.begin();
80         vector<string>::const_iterator end = choices.end();
81         for (; cit != end; ++cit) {
82                 fl_add_browser_line(browser_, cit->c_str());
83         }
84         fl_select_browser_line(browser_, 1);
85         fl_show_form(form_, FL_PLACE_POSITION, FL_NOBORDER, "");
86         XGrabPointer(fl_get_display(), form_->window, false,
87                      ButtonPressMask | ButtonReleaseMask | PointerMotionMask,
88                      GrabModeAsync, GrabModeAsync, 0, 0, 0);
89         XFlush(fl_get_display());
90 }
91
92
93 void DropDown::line_up()
94 {
95         if (fl_get_browser(browser_) > 1)
96                 fl_select_browser_line(browser_, fl_get_browser(browser_) - 1);
97         if (fl_get_browser(browser_) >= fl_get_browser_topline(browser_) +
98             fl_get_browser_screenlines(browser_))
99                 fl_set_browser_topline(browser_, fl_get_browser(browser_)
100                                        - fl_get_browser_screenlines(browser_) + 1);
101         if (fl_get_browser(browser_) < fl_get_browser_topline(browser_))
102                 fl_set_browser_topline(browser_, fl_get_browser(browser_));
103 }
104
105
106 void DropDown::line_down()
107 {
108         if (fl_get_browser(browser_) < fl_get_browser_maxline(browser_))
109                 fl_select_browser_line(browser_, fl_get_browser(browser_) + 1);
110         if (fl_get_browser(browser_) >= fl_get_browser_topline(browser_) +
111             fl_get_browser_screenlines(browser_))
112                 fl_set_browser_topline(browser_, fl_get_browser(browser_)
113                                        - fl_get_browser_screenlines(browser_) + 1);
114         if (fl_get_browser(browser_) < fl_get_browser_topline(browser_))
115                 fl_set_browser_topline(browser_, fl_get_browser(browser_));
116 }
117
118
119 int DropDown::peek(XEvent * xev)
120 {
121         int x,y;
122         unsigned int keymask;
123
124         fl_get_mouse(&x, &y, &keymask);
125
126         if (xev->type == ButtonPress) {
127                 if (!(x >= form_->x && x <= (form_->x + form_->w) &&
128                       y >= form_->y && y << (form_->y + form_->h))) {
129                         fl_hide_form(form_);
130                         return 1;
131                 }
132                 XUngrabPointer(fl_get_display(), CurrentTime);
133         } else if (xev->type == KeyPress) {
134                 char s_r[10]; s_r[9] = '\0';
135                 KeySym keysym_return;
136                 XLookupString(&xev->xkey, s_r, 10, &keysym_return, 0);
137                 switch (keysym_return) {
138                 case XK_Down:
139 #ifdef XK_KP_Down
140                 case XK_KP_Down:
141 #endif
142                         line_down();
143                         return 1;
144                 case XK_Up:
145 #ifdef XK_KP_Up
146                 case XK_KP_Up:
147 #endif
148                         line_up();
149                         return 1;
150                 case XK_Return:
151 #ifdef XK_KP_Enter
152                 case XK_KP_Enter:
153 #endif
154                         completed();
155                         return 1;
156                 case XK_Escape:
157                         fl_deselect_browser(browser_);
158                         completed();
159                         return 1;
160                 default:
161                         // FIXME: if someone has a got a way to
162                         // convince the event to fall back to the
163                         // minibuffer, I'm glad to hear it.
164                         // fl_XPutBackEvent() doesn't work.
165
166                         // This is a bit less elegant perhaps, but works
167                         // well enough. Angus 11 Jan 2002
168                         if (s_r[0] && isprint(s_r[0])) {
169                                 key_pressed(s_r[0]);
170                                 return 1;
171                         }
172                 }
173         }
174         return 0;
175 }
176
177
178 void DropDown::completed()
179 {
180         XUngrabPointer(fl_get_display(), CurrentTime);
181         fl_hide_form(form_);
182         result(getSelectedStringFromBrowser(browser_));
183 }
184
185
186 void DropDown::key_pressed(char c)
187 {
188         XUngrabPointer(fl_get_display(), CurrentTime);
189         fl_hide_form(form_);
190         keypress(c);
191 }