]> git.lyx.org Git - lyx.git/blob - src/frontends/xforms/XMiniBuffer.C
Introduce LFUN_PRINT.
[lyx.git] / src / frontends / xforms / XMiniBuffer.C
1 /**
2  * \file XMiniBuffer.C
3  * This file is part of LyX, the document processor.
4  * Licence details can be found in the file COPYING.
5  *
6  * \author Lars
7  * \author Asger and Jürgen
8  *
9  * Full author contact details are available in file CREDITS.
10  */
11
12 #include <config.h>
13
14 #include "XMiniBuffer.h"
15
16 #include "freebrowser.h"
17 #include "xforms_helpers.h"
18
19 #include "controllers/ControlCommandBuffer.h"
20
21 #include "frontends/Timeout.h"
22
23 #include "gettext.h"
24
25 #include <boost/bind.hpp>
26
27
28 using std::vector;
29 using std::string;
30
31
32 namespace {
33
34 /// This creates the input widget for the minibuffer
35 FL_OBJECT * create_input_box(void * parent, int type,
36                              FL_Coord, FL_Coord, FL_Coord, FL_Coord);
37
38 FL_FREEBROWSER * create_freebrowser(void * parent);
39
40 } // namespace anon
41
42
43 XMiniBuffer::XMiniBuffer(ControlCommandBuffer & control,
44                          FL_Coord x, FL_Coord y, FL_Coord h, FL_Coord w)
45         : controller_(control),
46           info_shown_(false)
47 {
48         input_ = create_input_box(this, FL_NORMAL_INPUT, x, y, h, w);
49         freebrowser_.reset(create_freebrowser(this), fl_free_freebrowser);
50
51         info_timer_.reset(new Timeout(1500));
52         idle_timer_.reset(new Timeout(6000));
53         info_con = info_timer_->timeout.connect(boost::bind(&XMiniBuffer::info_timeout, this));
54         idle_con = idle_timer_->timeout.connect(boost::bind(&XMiniBuffer::idle_timeout, this));
55         idle_timer_->start();
56         messageMode();
57 }
58
59
60 // This is here so that scoped ptr will not require a complete type.
61 XMiniBuffer::~XMiniBuffer()
62 {}
63
64
65 void XMiniBuffer::freebrowserCB(int action)
66 {
67         if (action < 0 || action > 1)
68                 // unrecognized action
69                 return;
70
71         if (action == 0)
72                 // The freebrowser has been hidden
73                 return;
74
75         if (freebrowser_->last_printable) {
76                 // Append this char to the current input contents
77                 string input = getString(input_);
78                 input += freebrowser_->last_printable;
79                 fl_set_input(input_, input.c_str());
80
81         } else {
82                 // Fill the input widget with the selected
83                 // browser entry.
84                 FL_OBJECT * browser = freebrowser_->browser;
85                 string const str = getString(browser);
86
87                 if (!str.empty()) {
88                         // add a space so the user can type
89                         // an argument immediately
90                         set_input(str + ' ');
91                 }
92         }
93 }
94
95
96 int XMiniBuffer::peek_event(FL_OBJECT * ob, int event,
97                             int key, XEvent * /*xev*/)
98 {
99         switch (event) {
100         case FL_FOCUS:
101                 messageMode(false);
102                 break;
103         case FL_UNFOCUS:
104                 messageMode();
105                 break;
106         case FL_KEYBOARD:
107         {
108                 string input;
109                 if (info_shown_) {
110                         info_timer_->stop();
111                         info_timeout();
112                 }
113
114                 char const * tmp = fl_get_input(ob);
115                 input = tmp ? tmp : "";
116
117                 switch (key) {
118                 case XK_Down:
119 #ifdef XK_KP_Down
120                 case XK_KP_Down:
121 #endif
122                 {
123                         string const h(controller_.historyDown());
124                         if (h.empty()) {
125                                 show_info(_("[End of history]"), input, false);
126                         } else {
127                                 set_input(h);
128                         }
129                         return 1;
130                 }
131
132                 case XK_Up:
133 #ifdef XK_KP_Up
134                 case XK_KP_Up:
135 #endif
136                 {
137                         string const h(controller_.historyUp());
138                         if (h.empty()) {
139                                 show_info(_("[Beginning of history]"), input, false);
140                         } else {
141                                 set_input(h);
142                         }
143                         return 1;
144                 }
145
146                 case 9:
147                 case XK_Tab:
148                 {
149                         string new_input;
150                         vector<string> comp = controller_.completions(input, new_input);
151
152                         if (comp.empty() && new_input == input) {
153                                 show_info(_("[no match]"), input);
154                                 break;
155                         }
156
157                         if (comp.empty()) {
158                                 set_input(new_input);
159                                 show_info(_("[only completion]"), new_input + ' ');
160                                 break;
161                         }
162
163                         set_input(new_input);
164
165                         // Fill freebrowser_'s browser with the list of
166                         // available completions
167                         FL_OBJECT * browser = freebrowser_->browser;
168                         fl_clear_browser(browser);
169                         vector<string>::const_iterator cit = comp.begin();
170                         vector<string>::const_iterator end = comp.end();
171                         for (; cit != end; ++cit) {
172                                 fl_add_browser_line(browser, cit->c_str());
173                         }
174                         fl_select_browser_line(browser, 1);
175
176                         // Set the position of the freebrowser and display it.
177                         int x,y,w,h;
178                         fl_get_wingeometry(fl_get_real_object_window(input_),
179                                            &x, &y, &w, &h);
180
181                         // asynchronous completion
182                         int const air = input_->x;
183                         x += air;
184                         y += h - (input_->h + air);
185                         w = input_->w;
186                         h = 100;
187
188                         fl_show_freebrowser(freebrowser_.get(), x, y-h, w, h);
189                         return 1;
190                 }
191                 case 27:
192                 case XK_Escape:
193                         messageMode();
194                         return 1;
195                 case 13:
196                 case XK_Return:
197 #ifdef XK_KP_Enter
198                 case XK_KP_Enter:
199 #endif
200                 {
201                         messageMode();
202                         redraw();
203                         controller_.dispatch(input);
204                         return 1;
205                 }
206                 default:
207                         return 0;
208                 }
209         }
210         default:
211                 break;
212         }
213
214         return 0;
215 }
216
217
218 void XMiniBuffer::freeze()
219 {
220         // we must prevent peek_event, or we get an unfocus() when the
221         // containing form gets destroyed
222         fl_set_object_prehandler(input_, 0);
223 }
224
225
226 void XMiniBuffer::show_info(string const & info, string const & input, bool append)
227 {
228         stored_input_ = input;
229         info_shown_ = true;
230         if (append)
231                 set_input(input + ' ' + info);
232         else
233                 set_input(info);
234         info_timer_->start();
235 }
236
237
238 void XMiniBuffer::idle_timeout()
239 {
240         set_input(controller_.getCurrentState());
241 }
242
243
244 void XMiniBuffer::info_timeout()
245 {
246         info_shown_ = false;
247         set_input(stored_input_);
248 }
249
250
251 bool XMiniBuffer::isEditingMode() const
252 {
253         return input_->focus;
254 }
255
256
257 void XMiniBuffer::messageMode(bool on)
258 {
259         set_input("");
260         if (!on) {
261                 fl_activate_object(input_);
262                 fl_set_focus_object(input_->form, input_);
263                 redraw();
264                 idle_timer_->stop();
265         } else {
266                 if (isEditingMode()) {
267                         // focus back to the workarea
268                         fl_set_focus_object(input_->form, 0);
269                         idle_timer_->start();
270                 }
271         }
272 }
273
274
275 void XMiniBuffer::redraw()
276 {
277         fl_redraw_object(input_);
278         XFlush(fl_display);
279 }
280
281
282 void XMiniBuffer::message(string const & str)
283 {
284         if (!isEditingMode())
285                 set_input(str);
286 }
287
288
289 void XMiniBuffer::set_input(string const & str)
290 {
291         fl_set_input(input_, str.c_str());
292 }
293
294
295 namespace {
296
297 extern "C"
298 int C_XMiniBuffer_peek_event(FL_OBJECT * ob, int event,
299                              FL_Coord, FL_Coord,
300                              int key, void * xev)
301 {
302         XMiniBuffer * mini = static_cast<XMiniBuffer*>(ob->u_vdata);
303         return mini->peek_event(ob, event, key, static_cast<XEvent *>(xev));
304 }
305
306
307 extern "C"
308 void C_freebrowserCB(FL_FREEBROWSER * fb, int action)
309 {
310         if (!fb || !fb->parent)
311                 return;
312
313         XMiniBuffer * ptr = static_cast<XMiniBuffer *>(fb->parent);
314         ptr->freebrowserCB(action);
315 }
316
317
318 FL_OBJECT * create_input_box(void * parent, int type,
319                              FL_Coord x, FL_Coord y, FL_Coord w, FL_Coord h)
320 {
321         FL_OBJECT * obj = fl_add_input(type, x, y, w, h, "");
322         fl_set_object_boxtype(obj, FL_DOWN_BOX);
323         fl_set_object_resize(obj, FL_RESIZE_ALL);
324         fl_set_object_gravity(obj, SouthWestGravity, SouthEastGravity);
325         fl_set_object_color(obj, FL_MCOL, FL_MCOL);
326         fl_set_object_lsize(obj, FL_NORMAL_SIZE);
327
328         // To intercept Up, Down, Table for history
329         fl_set_object_prehandler(obj, C_XMiniBuffer_peek_event);
330         obj->u_vdata = parent;
331         obj->wantkey = FL_KEY_TAB;
332
333         return obj;
334 }
335
336
337 FL_FREEBROWSER * create_freebrowser(void * parent)
338 {
339         FL_FREEBROWSER * fb = fl_create_freebrowser(parent);
340         fb->want_printable = 1;
341         fb->callback = C_freebrowserCB;
342         return fb;
343 }
344
345 } // namespace anon