]> git.lyx.org Git - features.git/blob - src/minibuffer.C
write \mathrm{x}\mathrm{y} as \mathrm{xy} again
[features.git] / src / minibuffer.C
1 /* ###########################################################################
2  *
3  *                 The MiniBuffer Class
4  *                 read minibuffer.h for more
5  *                 information.
6  * 
7  *           Copyright 1995 Matthias Ettrich
8  *           Copyright 1995-2001 The LyX Team.  
9  * 
10  * ###########################################################################
11  */
12
13 #include <config.h>
14
15 #include <iostream>
16
17 #ifdef __GNUG__
18 #pragma implementation
19 #endif
20
21 // FIXME: temporary 
22 #include "frontends/xforms/DropDown.h"
23  
24 #include "minibuffer.h"
25
26 #include "support/lyxalgo.h"
27 #include "support/filetools.h"
28 #include "support/lstrings.h"
29 #include "LyXView.h"
30 #include "XFormsView.h"
31 #include "gettext.h"
32 #include "LyXAction.h"
33 #include "BufferView.h"
34
35
36 using SigC::slot;
37 using std::vector;
38
39 extern LyXAction lyxaction;
40
41
42 namespace {
43
44 struct prefix {
45         string p;
46         prefix(string const & s) 
47                 : p(s) {}
48         bool operator()(string const & s) const {
49                 return prefixIs(s, p);
50         }
51 };
52
53 } // end of anon namespace
54
55
56 MiniBuffer::MiniBuffer(LyXView * o, FL_Coord x, FL_Coord y,
57                        FL_Coord h, FL_Coord w)
58         : stored_(false), owner_(o), state_(spaces)
59 {
60         add(FL_NORMAL_INPUT, x, y, h, w);
61         timer.setTimeout(6000);
62         timer.timeout.connect(slot(this, &MiniBuffer::init));
63         stored_timer.setTimeout(1500);
64         stored_timer.timeout.connect(slot(this, &MiniBuffer::stored_slot));
65         deactivate();
66 }
67
68  
69 // thanks for nothing, xforms (recursive creation not allowed) 
70 void MiniBuffer::dd_init()
71 {
72         dropdown_ = new DropDown(owner_, the_buffer);
73         dropdown_->result.connect(slot(this, &MiniBuffer::set_input));
74 }
75
76
77 MiniBuffer::~MiniBuffer()
78 {
79         delete dropdown_;
80 }
81
82  
83 void MiniBuffer::stored_slot() 
84 {
85         if (stored_) {
86                 stored_ = false;
87                 set_input(stored_input);
88         }
89 }
90
91
92 void MiniBuffer::stored_set(string const & str) 
93 {
94         stored_input = str;
95         stored_ = true;
96         stored_timer.start();
97 }
98
99
100 int MiniBuffer::peek_event(FL_OBJECT * ob, int event, int key)
101 {
102         switch (event) {
103         case FL_KEYBOARD:
104         {
105                 char const * tmp = fl_get_input(ob);
106                 string input = tmp ? tmp : "";
107                 if (stored_) {
108                         stored_timer.stop();
109                         input = stored_input;
110                         set_input(input);
111                         stored_ = false;
112                 }
113                 
114                 switch (key) {
115                 case XK_Down:
116                         if (hist_iter != history_->end()) {
117                                 ++hist_iter;
118                         }
119                         if (hist_iter == history_->end()) {
120                                 // no further history
121                                 stored_set(input);
122                                 set_input(_("[End of history]"));
123                         } else {
124                                 set_input((*hist_iter));
125                         }
126                         return 1; 
127                 case XK_Up:
128                         if (hist_iter == history_->begin()) {
129                                 // no further history
130                                 stored_set(input);
131                                 set_input(_("[Beginning of history]"));
132                         } else {
133                                 --hist_iter;
134                                 set_input((*hist_iter));
135                         }
136                         return 1; 
137                 case 9:
138                 case XK_Tab:
139                 {
140                         // Completion handling.
141                         
142                         vector<string> comp;
143                         lyx::copy_if(completion_.begin(),
144                                      completion_.end(),
145                                      std::back_inserter(comp), prefix(input));
146
147                         if (comp.empty()) {
148                                 // No matches
149                                 string const tmp = input + _(" [no match]");
150                                 stored_set(input);
151                                 set_input(tmp);
152                         } else if (comp.size() == 1) {
153                                 // Perfect match
154                                 string const tmp =
155                                         comp[0] + _(" [sole completion]");
156                                 stored_set(comp[0]);
157                                 set_input(tmp);
158                         } else {
159                                 // More that one match
160                                 // Find maximal avaliable prefix
161                                 string const tmp = comp[0];
162                                 string test(input);
163                                 test += tmp[test.length()];
164                                 while (test.length() < tmp.length()) {
165                                         vector<string> vtmp;
166                                         lyx::copy_if(comp.begin(),
167                                                      comp.end(),
168                                                      std::back_inserter(vtmp),
169                                                      prefix(test));
170                                         if (vtmp.size() != comp.size()) {
171                                                 test.erase(test.length() - 1);
172                                                 break;
173                                         }
174                                         test += tmp[test.length()];
175                                 }
176                                 set_input(test);
177                                 
178                                 int x,y,w,h;
179                                 fl_get_wingeometry(fl_get_real_object_window(the_buffer),
180                                         &x, &y, &w, &h);
181  
182                                 // asynchronous completion 
183                                 dropdown_->select(comp, x, y + h, w);
184                         }
185                         return 1; 
186                 }
187                 case 27:
188                 case XK_Escape:
189                         // Abort
190                         owner_->view()->focus(true);
191                         init();
192                         deactivate();
193                         //escape.emit();
194                         return 1; 
195                 case 13:
196                 case XK_Return:
197                 {
198 #if 0
199                         // This will go in again in a little while
200                         // we need to be able to declare what types
201                         // of argumetns LFUN's should have first. (Lgb)
202                         // First check for match
203                         vector<string>::const_iterator cit =
204                                 std::find(completion_.begin(),
205                                           completion_.end(),
206                                           input);
207                         if (cit == completion_.end()) {
208                                 // no such func/item
209                                 stored_set(input);
210                                 string const tmp = input + _(" [no match]");
211                                 set_input(tmp);
212                         } else {
213 #endif
214                                 // Return the inputted string
215                                 deactivate();
216                                 owner_->view()->focus(true);
217                                 history_->push_back(input);
218                                 stringReady.emit(input);
219 # if 0
220                         }
221 #endif
222                         return 1;
223                 }
224                 case XK_space:
225                 {
226                         // Depending on the input state spaces might not
227                         // be allowed.
228                         switch (state_) {
229                         case spaces:
230                                 return 0;
231                         case nospaces:
232                         {
233                                 stored_set(input);
234                                 string const tmp = input + _(" [no match]");
235                                 set_input(tmp);
236                                 return 1;
237                         }
238                         }
239                         
240                 }
241                 
242                 default:
243                         return 0;
244                 }
245         }
246         default:
247                 //lyxerr << "Unhandled minibuffer event!" << endl;
248                 break;
249         }
250         
251         return 0;
252 }
253
254
255 extern "C" {
256         
257         static
258         int C_MiniBuffer_peek_event(FL_OBJECT * ob, int event, 
259                                     FL_Coord, FL_Coord,
260                                     int key, void * /*xev*/)
261         {
262                 MiniBuffer * mini = static_cast<MiniBuffer*>(ob->u_vdata);
263                 return mini->peek_event(ob, event, key);
264         }
265         
266 }
267
268
269 void MiniBuffer::prepare()
270 {
271         text.erase();
272         set_input("");
273         activate();
274         fl_set_focus_object(static_cast<XFormsView *>(owner_)->getForm(),
275                             the_buffer);
276 }
277
278
279 FL_OBJECT * MiniBuffer::add(int type, FL_Coord x, FL_Coord y,
280                            FL_Coord w, FL_Coord h)
281 {
282         FL_OBJECT * obj;
283         
284         the_buffer = obj = fl_add_input(type, x, y, w, h, text.c_str());
285         fl_set_object_boxtype(obj, FL_DOWN_BOX);
286         fl_set_object_resize(obj, FL_RESIZE_ALL);
287         fl_set_object_gravity(obj, SouthWestGravity, SouthEastGravity);
288         fl_set_object_color(obj, FL_MCOL, FL_MCOL);
289         fl_set_object_lsize(obj, FL_NORMAL_SIZE);
290         
291         // To intercept Up, Down, Table for history
292         fl_set_object_prehandler(obj, C_MiniBuffer_peek_event);
293         obj->u_vdata = this;
294         obj->wantkey = FL_KEY_TAB;
295
296         set_input(text);
297         
298         return obj;
299 }
300
301
302 void MiniBuffer::message(string const & str) 
303 {
304         timer.restart();
305         string const ntext = strip(str);
306         if (!the_buffer->focus) {
307                 set_input(ntext);
308                 text = ntext;
309         }
310 }
311
312
313 void MiniBuffer::messagePush(string const & str) 
314 {
315         text_stored = text;
316         message(str);
317 }
318
319
320 void MiniBuffer::messagePop()
321 {
322         if (!text_stored.empty()) {
323                 message(text_stored);
324                 text_stored.erase();
325         }
326 }
327
328
329 void MiniBuffer::addSet(string const & s1, string const & s2)
330 {
331         string const str = text + ' ' +  s1 + ' ' + s2;
332         message(str);
333 }
334
335
336 void MiniBuffer::getString(State spaces,
337                            vector<string> const & completion,
338                            vector<string> & history)
339 {
340         state_ = spaces;
341         completion_ = completion;
342         history_ = &history;
343         hist_iter = history_->end();
344         prepare();
345 }
346
347
348 void MiniBuffer::init()
349 {
350         // If we have focus, we don't want to change anything.
351         if (the_buffer->focus)
352                 return;
353
354         timeout.emit();
355         timer.stop();
356 }
357
358
359 void MiniBuffer::activate()
360 {
361         fl_activate_object(the_buffer);
362         redraw();
363 }
364
365
366 void MiniBuffer::deactivate()
367 {
368         redraw();
369         fl_deactivate_object(the_buffer);
370         XFlush(fl_display);
371 }
372
373
374 void MiniBuffer::redraw() 
375 {
376         fl_redraw_object(the_buffer);
377         XFlush(fl_display);
378 }
379
380
381 void MiniBuffer::set_input(string const & str)
382 {
383         fl_set_input(the_buffer, str.c_str());
384         XFlush(fl_display);
385 }