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