]> git.lyx.org Git - lyx.git/blob - src/frontends/xforms/freebrowser.c
ditch FileInfo -> use boost.filesystem
[lyx.git] / src / frontends / xforms / freebrowser.c
1 /**
2  * \file freebrowser.c
3  * This file is part of LyX, the document processor.
4  * Licence details can be found in the file COPYING.
5  *
6  * \author Alejandro Aguilar Sierra
7  * \author Lars Gullik Bjønnes
8  * \author Jean-Marc Lasgouttes
9  * \author Angus Leeming
10  *
11  * Full author contact details are available in file CREDITS
12  *
13  * This is a rewrite of Alejandro's C++ Combox class, originally written
14  * for LyX in 1996. The rewrite turns it into a native xforms widget.
15  */
16 #include <config.h>
17
18 #include "lyx_forms.h"
19 #include "freebrowser.h"
20 #include <ctype.h> /* isprint */
21
22 extern void fl_hide_tooltip(void);
23
24 static void browser_cb(FL_OBJECT * ob, long data);
25 static int peek_event(FL_FORM * form, void * xev);
26
27
28 FL_FREEBROWSER *
29 fl_create_freebrowser(void * parent)
30 {
31     FL_FORM * current_form = fl_current_form;
32     FL_FREEBROWSER * fb = fl_calloc(1, sizeof(FL_FREEBROWSER));
33     FL_OBJECT * ob;
34
35     /* Default size */
36     FL_Coord const w = 100;
37     FL_Coord const h = 100;
38
39     fb->parent = parent;
40     fb->callback = 0;
41     fb->want_printable = 0;
42     fb->last_printable = 0;
43
44     if (current_form) fl_end_form();
45     fb->form = fl_bgn_form(FL_NO_BOX, w, h);
46
47     fb->form->u_vdata = fb;
48     fl_register_raw_callback(fb->form, ButtonPressMask|KeyPressMask,
49                              peek_event);
50
51     ob = fb->browser = fl_add_browser(FL_HOLD_BROWSER, 0, 0, w, h, "");
52     ob->u_vdata = fb;
53     fl_set_object_boxtype(ob, FL_UP_BOX);
54     fl_set_object_color(ob, FL_MCOL, FL_YELLOW);
55     fl_set_object_gravity(ob, NorthWestGravity, SouthEastGravity);
56     fl_set_object_callback(ob, browser_cb, 0);
57     fl_end_form();
58
59     if (current_form)
60         fl_addto_form(current_form);
61
62     return fb;
63 }
64
65
66 void
67 fl_free_freebrowser(FL_FREEBROWSER * fb)
68 {
69     if (!fb)
70         return;
71
72     if (fb->form)
73         fl_free_form(fb->form);
74
75     fl_free(fb);
76     fb = 0;
77 }
78
79
80 void
81 fl_show_freebrowser(FL_FREEBROWSER * fb,
82                     FL_Coord x, FL_Coord y, FL_Coord w, FL_Coord h)
83 {
84     int tmp;
85     int const pos = fl_get_browser(fb->browser);
86
87     fl_set_form_geometry(fb->form, x, y, w, h);
88
89     XGetInputFocus(fl_get_display(), &fb->save_window, &tmp);
90     XFlush(fl_get_display());
91
92     fl_show_form(fb->form, FL_PLACE_POSITION, FL_NOBORDER, "");
93
94     fl_select_browser_line(fb->browser, pos);
95     fl_set_browser_topline(fb->browser, pos);
96
97     XGrabPointer(fl_get_display(), fb->form->window, 0,
98                  ButtonPressMask | ButtonReleaseMask | PointerMotionMask,
99                  GrabModeAsync, GrabModeAsync,
100                  0, 0, 0);
101     XFlush(fl_get_display());
102
103     fl_hide_tooltip();
104 }
105
106
107 void
108 fl_hide_freebrowser(FL_FREEBROWSER * fb)
109 {
110     XUngrabPointer(fl_get_display(), 0);
111     XFlush(fl_get_display());
112
113     if (fb->form->visible)
114         fl_hide_form(fb->form);
115
116     XSetInputFocus(fl_get_display(), fb->save_window,
117                    RevertToParent, CurrentTime);
118     XFlush(fl_get_display());
119
120     if (fb->callback)
121         fb->callback(fb, 0);
122 }
123
124
125 static void
126 browser_cb(FL_OBJECT * ob, long data)
127 {
128     /* Silence warning about unused parameter */
129     (void) data;
130
131     FL_FREEBROWSER * fb = ob->u_vdata;
132     fl_hide_freebrowser(fb);
133     if (fb->callback)
134         fb->callback(fb, 1);
135 }
136
137
138 static int
139 eventWithinObj(XEvent * xev, FL_OBJECT * ob)
140 {
141     int result = 0;
142     if (xev && ob) {
143         int const xev_x = (int)(xev->xbutton.x);
144         int const xev_y = (int)(xev->xbutton.y);
145         int const ob_x  = (int)(ob->x);
146         int const ob_y  = (int)(ob->y);
147         int const ob_w  = (int)(ob->w);
148         int const ob_h  = (int)(ob->h);
149
150         int const dx = xev_x - ob_x;
151         int const dy = xev_y - ob_y;
152
153         /* result is true if the event occurred within the ob */
154         result = !(dx < 0 || dx > ob_w || dy < 0 || dy > ob_h);
155     }
156     return result;
157 }
158
159
160 static int
161 peek_event(FL_FORM * form, void * ev)
162 {
163     XEvent * xev = ev;
164     FL_FREEBROWSER * fb = form->u_vdata;
165     FL_OBJECT * browser = fb->browser;
166
167     fb->last_printable = 0;
168     fl_hide_tooltip();
169
170     if (xev->type == ButtonPress && !eventWithinObj(xev, browser)) {
171         fl_hide_freebrowser(fb);
172         return 1;
173     }
174
175     if (xev->type == KeyPress) {
176         KeySym keysym_return;
177         char s_r[10];
178         s_r[9] = '\0';
179         XLookupString(&xev->xkey, s_r, 10, &keysym_return, 0);
180
181         XFlush(fl_get_display());
182
183         switch (keysym_return) {
184         case XK_Down:
185 #ifdef XK_KP_Down
186         case XK_KP_Down:
187 #endif
188         {
189             int sel = fl_get_browser(browser);
190             int const top = fl_get_browser_topline(browser);
191             int const screenlines = fl_get_browser_screenlines(browser);
192
193             if (sel < 1 || sel >= fl_get_browser_maxline(browser))
194                 return 0;
195
196             ++sel;
197             fl_select_browser_line(browser, sel);
198
199             if (sel >= top + screenlines)
200                 fl_set_browser_topline(browser, sel - screenlines + 1);
201
202             if (sel < top)
203                 fl_set_browser_topline(browser, sel);
204
205             return 1;
206         }
207
208         case XK_Up:
209 #ifdef XK_KP_Up
210         case XK_KP_Up:
211 #endif
212         {
213             int sel = fl_get_browser(browser);
214             int const top = fl_get_browser_topline(browser);
215             int const screenlines = fl_get_browser_screenlines(browser);
216
217             if (sel <= 1 || sel > fl_get_browser_maxline(browser))
218                 return 0;
219
220             --sel;
221             fl_select_browser_line(browser, sel);
222
223             if (sel >= top + screenlines)
224                 fl_set_browser_topline(browser, sel - screenlines + 1);
225
226             if (sel < top)
227                 fl_set_browser_topline(browser, sel);
228
229             return 1;
230         }
231
232         case XK_Return:
233 #ifdef XK_KP_Enter
234         case XK_KP_Enter:
235 #endif
236             fl_hide_freebrowser(fb);
237             if (fb->callback)
238                 fb->callback(fb, 1);
239             return 1;
240
241         case XK_Escape:
242             fl_hide_freebrowser(fb);
243             return 1;
244         default:
245             if (fb->want_printable && s_r[0] && isprint(s_r[0])) {
246                 fb->last_printable = s_r[0];
247                 fl_hide_freebrowser(fb);
248                 if (fb->callback)
249                     fb->callback(fb, 1);
250                 return 1;
251             }
252         }
253     }
254     return 0;
255 }