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