1 //
2 // "$Id: Fl_Text_Editor.cxx 8034 2010-12-15 12:21:55Z AlbrechtS $"
3 //
4 // Copyright 2001-2010 by Bill Spitzak and others.
5 // Original code Copyright Mark Edel.  Permission to distribute under
6 // the LGPL for the FLTK library granted by Mark Edel.
7 //
8 // This library is free software; you can redistribute it and/or
9 // modify it under the terms of the GNU Library General Public
10 // License as published by the Free Software Foundation; either
11 // version 2 of the License, or (at your option) any later version.
12 //
13 // This library is distributed in the hope that it will be useful,
14 // but WITHOUT ANY WARRANTY; without even the implied warranty of
15 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16 // Library General Public License for more details.
17 //
18 // You should have received a copy of the GNU Library General Public
19 // License along with this library; if not, write to the Free Software
20 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
21 // USA.
22 //
23 // Please report all bugs and problems on the following page:
24 //
25 //     http://www.fltk.org/str.php
26 //
27 
28 #include <stdio.h>
29 #include <stdlib.h>
30 #include "flstring.h"
31 #include <ctype.h>
32 #include <FL/Fl.H>
33 #include <FL/Fl_Window.H>
34 #include <FL/Fl_Text_Editor.H>
35 #include <FL/fl_ask.H>
36 
37 
38 /* Keyboard Control Matrix
39 
40 key\modifier   plain  Ctrl   Alt  Meta
41   left          1/1  13/9   0/13  0/9
42   right         2/2  14/10  0/14  0/10
43   up            3/19 21/7   0/15  0/17
44   down          4/20 22/8   0/16  0/18
45   home          9/5  17/0   0/0   0/0
46   end          10/6  18/0   0/0   0/0
47   page up      11/7  23/0   0/11  0/0
48   page down    12/8  24/0   0/12  0/0
49     (FLTK action / OS X action)
50     (adding the shift key extends the selection, all other combinations are no-op)
51 
52   0: no-op
53   1: move cursor to the left, at line beginning wrap to end of prev line, at doc start no-op
54   2: move cursor to the right, at line end move to beginning of the next line, at doc end no-op
55   3: move cursor up, at doc top no-op
56   4: move cursor down, at doc bottom no-op
57   5: scroll display to top of text (cursor unchanged)
58   6: scroll display to end of text (cursor unchanged)
59   7: scroll text down one page (cursor unchanged)
60   8: scroll text up one page (cursor unchanged)
61   9: move cursor to beginning of line
62  10: move cursor to end of line
63  11: move cursor up one page and scroll down
64  12: move cursor down one page and scroll up
65  13: move to the beginning of the word or the previous word
66  14: move to the end of the word or the next word
67  15: if start of line: start of prev line, else start of this line
68  16: if end of line: end of next line, else end of this line
69  17: move cursor to the beginning of the document
70  18: move cursor to the end of the document
71  19: move cursor up, at doc top: home, at doc start: no-op)
72  20: move cursor down, at doc bot: end, at doc end: no-op)
73  21: scroll text down one line (cursor unchanged)
74  22: scroll text up one line (cursor unchanged)
75  23: move cursor to the beginning of the top of the screen
76  24: move cursor to the beginning of the bottom of the window
77 */
78 
79 /**  The constructor creates a new text editor widget.*/
Fl_Text_Editor(int X,int Y,int W,int H,const char * l)80 Fl_Text_Editor::Fl_Text_Editor(int X, int Y, int W, int H,  const char* l)
81     : Fl_Text_Display(X, Y, W, H, l) {
82   mCursorOn = 1;
83   insert_mode_ = 1;
84   key_bindings = 0;
85 
86   // handle the default key bindings
87   add_default_key_bindings(&key_bindings);
88 
89   // handle everything else
90   default_key_function(kf_default);
91 }
92 
93 #ifndef FL_DOXYGEN
94 Fl_Text_Editor::Key_Binding* Fl_Text_Editor::global_key_bindings = 0;
95 #endif
96 
97 // These are the default key bindings every widget should start with
98 static struct {
99   int key;
100   int state;
101   Fl_Text_Editor::Key_Func func;
102 } default_key_bindings[] = {
103   { FL_Escape,    FL_TEXT_EDITOR_ANY_STATE, Fl_Text_Editor::kf_ignore     },
104   { FL_Enter,     FL_TEXT_EDITOR_ANY_STATE, Fl_Text_Editor::kf_enter      },
105   { FL_KP_Enter,  FL_TEXT_EDITOR_ANY_STATE, Fl_Text_Editor::kf_enter      },
106   { FL_BackSpace, FL_TEXT_EDITOR_ANY_STATE, Fl_Text_Editor::kf_backspace  },
107   { FL_Insert,    FL_TEXT_EDITOR_ANY_STATE, Fl_Text_Editor::kf_insert     },
108   { FL_Delete,    FL_TEXT_EDITOR_ANY_STATE, Fl_Text_Editor::kf_delete     },
109   { FL_Home,      0,                        Fl_Text_Editor::kf_move       },
110   { FL_End,       0,                        Fl_Text_Editor::kf_move       },
111   { FL_Left,      0,                        Fl_Text_Editor::kf_move       },
112   { FL_Up,        0,                        Fl_Text_Editor::kf_move       },
113   { FL_Right,     0,                        Fl_Text_Editor::kf_move       },
114   { FL_Down,      0,                        Fl_Text_Editor::kf_move       },
115   { FL_Page_Up,   0,                        Fl_Text_Editor::kf_move       },
116   { FL_Page_Down, 0,                        Fl_Text_Editor::kf_move       },
117   { FL_Home,      FL_SHIFT,                 Fl_Text_Editor::kf_shift_move },
118   { FL_End,       FL_SHIFT,                 Fl_Text_Editor::kf_shift_move },
119   { FL_Left,      FL_SHIFT,                 Fl_Text_Editor::kf_shift_move },
120   { FL_Up,        FL_SHIFT,                 Fl_Text_Editor::kf_shift_move },
121   { FL_Right,     FL_SHIFT,                 Fl_Text_Editor::kf_shift_move },
122   { FL_Down,      FL_SHIFT,                 Fl_Text_Editor::kf_shift_move },
123   { FL_Page_Up,   FL_SHIFT,                 Fl_Text_Editor::kf_shift_move },
124   { FL_Page_Down, FL_SHIFT,                 Fl_Text_Editor::kf_shift_move },
125   { FL_Home,      FL_CTRL,                  Fl_Text_Editor::kf_ctrl_move  },
126   { FL_End,       FL_CTRL,                  Fl_Text_Editor::kf_ctrl_move  },
127   { FL_Left,      FL_CTRL,                  Fl_Text_Editor::kf_ctrl_move  },
128   { FL_Up,        FL_CTRL,                  Fl_Text_Editor::kf_ctrl_move  },
129   { FL_Right,     FL_CTRL,                  Fl_Text_Editor::kf_ctrl_move  },
130   { FL_Down,      FL_CTRL,                  Fl_Text_Editor::kf_ctrl_move  },
131   { FL_Page_Up,   FL_CTRL,                  Fl_Text_Editor::kf_ctrl_move  },
132   { FL_Page_Down, FL_CTRL,                  Fl_Text_Editor::kf_ctrl_move  },
133   { FL_Home,      FL_CTRL|FL_SHIFT,         Fl_Text_Editor::kf_c_s_move   },
134   { FL_End,       FL_CTRL|FL_SHIFT,         Fl_Text_Editor::kf_c_s_move   },
135   { FL_Left,      FL_CTRL|FL_SHIFT,         Fl_Text_Editor::kf_c_s_move   },
136   { FL_Up,        FL_CTRL|FL_SHIFT,         Fl_Text_Editor::kf_c_s_move   },
137   { FL_Right,     FL_CTRL|FL_SHIFT,         Fl_Text_Editor::kf_c_s_move   },
138   { FL_Down,      FL_CTRL|FL_SHIFT,         Fl_Text_Editor::kf_c_s_move   },
139   { FL_Page_Up,   FL_CTRL|FL_SHIFT,         Fl_Text_Editor::kf_c_s_move   },
140   { FL_Page_Down, FL_CTRL|FL_SHIFT,         Fl_Text_Editor::kf_c_s_move   },
141 //{ FL_Clear,	  0,                        Fl_Text_Editor::delete_to_eol },
142   { 'z',          FL_CTRL,                  Fl_Text_Editor::kf_undo	  },
143   { '/',          FL_CTRL,                  Fl_Text_Editor::kf_undo	  },
144   { 'x',          FL_CTRL,                  Fl_Text_Editor::kf_cut        },
145   { FL_Delete,    FL_SHIFT,                 Fl_Text_Editor::kf_cut        },
146   { 'c',          FL_CTRL,                  Fl_Text_Editor::kf_copy       },
147   { FL_Insert,    FL_CTRL,                  Fl_Text_Editor::kf_copy       },
148   { 'v',          FL_CTRL,                  Fl_Text_Editor::kf_paste      },
149   { FL_Insert,    FL_SHIFT,                 Fl_Text_Editor::kf_paste      },
150   { 'a',          FL_CTRL,                  Fl_Text_Editor::kf_select_all },
151 
152 #ifdef __APPLE__
153   // Define CMD+key accelerators...
154   { 'z',          FL_COMMAND,               Fl_Text_Editor::kf_undo       },
155   { 'x',          FL_COMMAND,               Fl_Text_Editor::kf_cut        },
156   { 'c',          FL_COMMAND,               Fl_Text_Editor::kf_copy       },
157   { 'v',          FL_COMMAND,               Fl_Text_Editor::kf_paste      },
158   { 'a',          FL_COMMAND,               Fl_Text_Editor::kf_select_all },
159   { FL_Left,      FL_COMMAND,               Fl_Text_Editor::kf_meta_move  },
160   { FL_Right,     FL_COMMAND,               Fl_Text_Editor::kf_meta_move  },
161   { FL_Up,        FL_COMMAND,               Fl_Text_Editor::kf_meta_move  },
162   { FL_Down,      FL_COMMAND,               Fl_Text_Editor::kf_meta_move  },
163   { FL_Left,      FL_COMMAND|FL_SHIFT,      Fl_Text_Editor::kf_m_s_move   },
164   { FL_Right,     FL_COMMAND|FL_SHIFT,      Fl_Text_Editor::kf_m_s_move   },
165   { FL_Up,        FL_COMMAND|FL_SHIFT,      Fl_Text_Editor::kf_m_s_move   },
166   { FL_Down,      FL_COMMAND|FL_SHIFT,      Fl_Text_Editor::kf_m_s_move   },
167 #endif // __APPLE__
168 
169   { 0,            0,                        0                             }
170 };
171 
172 /**  Adds all of the default editor key bindings to the specified key binding list.*/
add_default_key_bindings(Key_Binding ** list)173 void Fl_Text_Editor::add_default_key_bindings(Key_Binding** list) {
174   for (int i = 0; default_key_bindings[i].key; i++) {
175     add_key_binding(default_key_bindings[i].key,
176                     default_key_bindings[i].state,
177                     default_key_bindings[i].func,
178                     list);
179   }
180 }
181 
182 /**  Returns the function associated with a key binding.*/
bound_key_function(int key,int state,Key_Binding * list)183 Fl_Text_Editor::Key_Func Fl_Text_Editor::bound_key_function(int key, int state, Key_Binding* list) {
184   Key_Binding* cur;
185   for (cur = list; cur; cur = cur->next)
186     if (cur->key == key)
187       if (cur->state == FL_TEXT_EDITOR_ANY_STATE || cur->state == state)
188         break;
189   if (!cur) return 0;
190   return cur->function;
191 }
192 
193 /**  Removes all of the key bindings associated with the text editor or list.*/
remove_all_key_bindings(Key_Binding ** list)194 void Fl_Text_Editor::remove_all_key_bindings(Key_Binding** list) {
195   Key_Binding *cur, *next;
196   for (cur = *list; cur; cur = next) {
197     next = cur->next;
198     delete cur;
199   }
200   *list = 0;
201 }
202 
203 /** Removes the key binding associated with the key "key" of state "state" */
remove_key_binding(int key,int state,Key_Binding ** list)204 void Fl_Text_Editor::remove_key_binding(int key, int state, Key_Binding** list) {
205   Key_Binding *cur, *last = 0;
206   for (cur = *list; cur; last = cur, cur = cur->next)
207     if (cur->key == key && cur->state == state) break;
208   if (!cur) return;
209   if (last) last->next = cur->next;
210   else *list = cur->next;
211   delete cur;
212 }
213 /** Adds a key of state "state" with the function "function" */
add_key_binding(int key,int state,Key_Func function,Key_Binding ** list)214 void Fl_Text_Editor::add_key_binding(int key, int state, Key_Func function,
215                                 Key_Binding** list) {
216   Key_Binding* kb = new Key_Binding;
217   kb->key = key;
218   kb->state = state;
219   kb->function = function;
220   kb->next = *list;
221   *list = kb;
222 }
223 
224 ////////////////////////////////////////////////////////////////
225 
kill_selection(Fl_Text_Editor * e)226 static void kill_selection(Fl_Text_Editor* e) {
227   if (e->buffer()->selected()) {
228     e->insert_position(e->buffer()->primary_selection()->start());
229     e->buffer()->remove_selection();
230   }
231 }
232 
233 /** Inserts the text associated with the key */
kf_default(int c,Fl_Text_Editor * e)234 int Fl_Text_Editor::kf_default(int c, Fl_Text_Editor* e) {
235   // FIXME: this function is a mess! Fix this!
236   if (!c || (!isprint(c) && c != '\t')) return 0;
237   char s[2] = "\0";
238   s[0] = (char)c;
239   kill_selection(e);
240   if (e->insert_mode()) e->insert(s);
241   else e->overstrike(s);
242   e->show_insert_position();
243   e->set_changed();
244   if (e->when()&FL_WHEN_CHANGED) e->do_callback();
245   return 1;
246 }
247 
248 /** Ignores the keypress */
kf_ignore(int,Fl_Text_Editor *)249 int Fl_Text_Editor::kf_ignore(int, Fl_Text_Editor*) {
250   return 0; // don't handle
251 }
252 /**  Does a backspace in the current buffer.*/
kf_backspace(int,Fl_Text_Editor * e)253 int Fl_Text_Editor::kf_backspace(int, Fl_Text_Editor* e) {
254   if (!e->buffer()->selected() && e->move_left()) {
255     int p1 = e->insert_position();
256     int p2 = e->buffer()->next_char(p1);
257     e->buffer()->select(p1, p2);
258   }
259   kill_selection(e);
260   e->show_insert_position();
261   e->set_changed();
262   if (e->when()&FL_WHEN_CHANGED) e->do_callback();
263   return 1;
264 }
265 
266 /** Inserts a newline at the current cursor position */
kf_enter(int,Fl_Text_Editor * e)267 int Fl_Text_Editor::kf_enter(int, Fl_Text_Editor* e) {
268   kill_selection(e);
269   e->insert("\n");
270   e->show_insert_position();
271   e->set_changed();
272   if (e->when()&FL_WHEN_CHANGED) e->do_callback();
273   return 1;
274 }
275 
276 extern void fl_text_drag_me(int pos, Fl_Text_Display* d);
277 /**  Moves the text cursor in the direction indicated by key c.*/
kf_move(int c,Fl_Text_Editor * e)278 int Fl_Text_Editor::kf_move(int c, Fl_Text_Editor* e) {
279   int i;
280   int selected = e->buffer()->selected();
281   if (!selected)
282     e->dragPos = e->insert_position();
283   e->buffer()->unselect();
284   Fl::copy("", 0, 0);
285   switch (c) {
286   case FL_Home:
287       e->insert_position(e->buffer()->line_start(e->insert_position()));
288       break;
289     case FL_End:
290       e->insert_position(e->buffer()->line_end(e->insert_position()));
291       break;
292     case FL_Left:
293       e->move_left();
294       break;
295     case FL_Right:
296       e->move_right();
297       break;
298     case FL_Up:
299       e->move_up();
300       break;
301     case FL_Down:
302       e->move_down();
303       break;
304     case FL_Page_Up:
305       for (i = 0; i < e->mNVisibleLines - 1; i++) e->move_up();
306       break;
307     case FL_Page_Down:
308       for (i = 0; i < e->mNVisibleLines - 1; i++) e->move_down();
309       break;
310   }
311   e->show_insert_position();
312   return 1;
313 }
314 
315 /**  Extends the current selection in the direction of key c.*/
kf_shift_move(int c,Fl_Text_Editor * e)316 int Fl_Text_Editor::kf_shift_move(int c, Fl_Text_Editor* e) {
317   kf_move(c, e);
318   fl_text_drag_me(e->insert_position(), e);
319   char *copy = e->buffer()->selection_text();
320   if (copy) {
321     Fl::copy(copy, strlen(copy), 0);
322     free(copy);
323     }
324   return 1;
325 }
326 /** Moves the current text cursor in the direction indicated by control key */
kf_ctrl_move(int c,Fl_Text_Editor * e)327 int Fl_Text_Editor::kf_ctrl_move(int c, Fl_Text_Editor* e) {
328   if (!e->buffer()->selected())
329     e->dragPos = e->insert_position();
330   if (c != FL_Up && c != FL_Down) {
331     e->buffer()->unselect();
332     Fl::copy("", 0, 0);
333     e->show_insert_position();
334   }
335   switch (c) {
336     case FL_Home:
337       e->insert_position(0);
338       e->scroll(0, 0);
339       break;
340     case FL_End:
341       e->insert_position(e->buffer()->length());
342       e->scroll(e->count_lines(0, e->buffer()->length(), 1), 0);
343       break;
344     case FL_Left:
345       e->previous_word();
346       break;
347     case FL_Right:
348       e->next_word();
349       break;
350     case FL_Up:
351       e->scroll(e->mTopLineNum-1, e->mHorizOffset);
352       break;
353     case FL_Down:
354       e->scroll(e->mTopLineNum+1, e->mHorizOffset);
355       break;
356     case FL_Page_Up:
357       e->insert_position(e->mLineStarts[0]);
358       break;
359     case FL_Page_Down:
360       e->insert_position(e->mLineStarts[e->mNVisibleLines-2]);
361       break;
362   }
363   return 1;
364 }
365 
366 /** Moves the current text cursor in the direction indicated by meta key */
kf_meta_move(int c,Fl_Text_Editor * e)367 int Fl_Text_Editor::kf_meta_move(int c, Fl_Text_Editor* e) {
368   if (!e->buffer()->selected())
369     e->dragPos = e->insert_position();
370   if (c != FL_Up && c != FL_Down) {
371     e->buffer()->unselect();
372     Fl::copy("", 0, 0);
373     e->show_insert_position();
374   }
375   switch (c) {
376     case FL_Up:				// top of buffer
377       e->insert_position(0);
378       e->scroll(0, 0);
379       break;
380     case FL_Down:			// end of buffer
381       e->insert_position(e->buffer()->length());
382       e->scroll(e->count_lines(0, e->buffer()->length(), 1), 0);
383       break;
384     case FL_Left:			// beginning of line
385       kf_move(FL_Home, e);
386       break;
387     case FL_Right:			// end of line
388       kf_move(FL_End, e);
389       break;
390   }
391   return 1;
392 }
393 
394 /** Extends the current selection in the direction indicated by meta key c. */
kf_m_s_move(int c,Fl_Text_Editor * e)395 int Fl_Text_Editor::kf_m_s_move(int c, Fl_Text_Editor* e) {
396   kf_meta_move(c, e);
397   fl_text_drag_me(e->insert_position(), e);
398   return 1;
399 }
400 
401 /** Extends the current selection in the direction indicated by control key c. */
kf_c_s_move(int c,Fl_Text_Editor * e)402 int Fl_Text_Editor::kf_c_s_move(int c, Fl_Text_Editor* e) {
403   kf_ctrl_move(c, e);
404   fl_text_drag_me(e->insert_position(), e);
405   return 1;
406 }
407 
408 /**  Moves the text cursor to the beginning of the current line.*/
kf_home(int,Fl_Text_Editor * e)409 int Fl_Text_Editor::kf_home(int, Fl_Text_Editor* e) {
410     return kf_move(FL_Home, e);
411 }
412 
413 /**  Moves the text cursor to the end of the current line.*/
kf_end(int,Fl_Text_Editor * e)414 int Fl_Text_Editor::kf_end(int, Fl_Text_Editor* e) {
415   return kf_move(FL_End, e);
416 }
417 
418 /**  Moves the text cursor one character to the left.*/
kf_left(int,Fl_Text_Editor * e)419 int Fl_Text_Editor::kf_left(int, Fl_Text_Editor* e) {
420   return kf_move(FL_Left, e);
421 }
422 
423 /**  Moves the text cursor one line up.*/
kf_up(int,Fl_Text_Editor * e)424 int Fl_Text_Editor::kf_up(int, Fl_Text_Editor* e) {
425   return kf_move(FL_Up, e);
426 }
427 
428 /**  Moves the text cursor one character to the right.*/
kf_right(int,Fl_Text_Editor * e)429 int Fl_Text_Editor::kf_right(int, Fl_Text_Editor* e) {
430   return kf_move(FL_Right, e);
431 }
432 /**  Moves the text cursor one line down.*/
kf_down(int,Fl_Text_Editor * e)433 int Fl_Text_Editor::kf_down(int, Fl_Text_Editor* e) {
434   return kf_move(FL_Down, e);
435 }
436 
437 /**  Moves the text cursor up one page.*/
kf_page_up(int,Fl_Text_Editor * e)438 int Fl_Text_Editor::kf_page_up(int, Fl_Text_Editor* e) {
439   return kf_move(FL_Page_Up, e);
440 }
441 
442 /**  Moves the text cursor down one page.*/
kf_page_down(int,Fl_Text_Editor * e)443 int Fl_Text_Editor::kf_page_down(int, Fl_Text_Editor* e) {
444   return kf_move(FL_Page_Down, e);
445 }
446 /**  Toggles the insert mode in the text editor.*/
kf_insert(int,Fl_Text_Editor * e)447 int Fl_Text_Editor::kf_insert(int, Fl_Text_Editor* e) {
448   e->insert_mode(e->insert_mode() ? 0 : 1);
449   return 1;
450 }
451 
452 /**  Does a delete of selected text or the current character in the current buffer.*/
kf_delete(int,Fl_Text_Editor * e)453 int Fl_Text_Editor::kf_delete(int, Fl_Text_Editor* e) {
454   if (!e->buffer()->selected()) {
455     int p1 = e->insert_position();
456     int p2 = e->buffer()->next_char(p1);
457     e->buffer()->select(p1, p2);
458   }
459 
460   kill_selection(e);
461   e->show_insert_position();
462   e->set_changed();
463   if (e->when()&FL_WHEN_CHANGED) e->do_callback();
464   return 1;
465 }
466 
467 /**  Does a copy of selected text or the current character in the current buffer.*/
kf_copy(int,Fl_Text_Editor * e)468 int Fl_Text_Editor::kf_copy(int, Fl_Text_Editor* e) {
469   if (!e->buffer()->selected()) return 1;
470   const char *copy = e->buffer()->selection_text();
471   if (*copy) Fl::copy(copy, strlen(copy), 1);
472   free((void*)copy);
473   e->show_insert_position();
474   return 1;
475 }
476 
477 /**  Does a cut of selected text in the current buffer.*/
kf_cut(int c,Fl_Text_Editor * e)478 int Fl_Text_Editor::kf_cut(int c, Fl_Text_Editor* e) {
479   kf_copy(c, e);
480   kill_selection(e);
481   e->set_changed();
482   if (e->when()&FL_WHEN_CHANGED) e->do_callback();
483   return 1;
484 }
485 
486 /**  Does a paste of selected text in the current buffer.*/
kf_paste(int,Fl_Text_Editor * e)487 int Fl_Text_Editor::kf_paste(int, Fl_Text_Editor* e) {
488   kill_selection(e);
489   Fl::paste(*e, 1);
490   e->show_insert_position();
491   e->set_changed();
492   if (e->when()&FL_WHEN_CHANGED) e->do_callback();
493   return 1;
494 }
495 
496 /**  Selects all text in the current buffer.*/
kf_select_all(int,Fl_Text_Editor * e)497 int Fl_Text_Editor::kf_select_all(int, Fl_Text_Editor* e) {
498   e->buffer()->select(0, e->buffer()->length());
499   const char *copy = e->buffer()->selection_text();
500   if (*copy) Fl::copy(copy, strlen(copy), 0);
501   free((void*)copy);
502   return 1;
503 }
504 /**  Undo last edit in the current buffer. Also deselect previous selection. */
kf_undo(int,Fl_Text_Editor * e)505 int Fl_Text_Editor::kf_undo(int , Fl_Text_Editor* e) {
506   e->buffer()->unselect();
507   Fl::copy("", 0, 0);
508   int crsr;
509   int ret = e->buffer()->undo(&crsr);
510   e->insert_position(crsr);
511   e->show_insert_position();
512   e->set_changed();
513   if (e->when()&FL_WHEN_CHANGED) e->do_callback();
514   return ret;
515 }
516 
517 /** Handles a key press in the editor */
handle_key()518 int Fl_Text_Editor::handle_key() {
519   // Call FLTK's rules to try to turn this into a printing character.
520   // This uses the right-hand ctrl key as a "compose prefix" and returns
521   // the changes that should be made to the text, as a number of
522   // bytes to delete and a string to insert:
523   int del = 0;
524   if (Fl::compose(del)) {
525     if (del) {
526       int dp = insert_position(), di = del;
527       while (di--) dp = buffer()->prev_char_clipped(dp);
528       buffer()->select(dp, insert_position());
529     }
530     kill_selection(this);
531     if (Fl::event_length()) {
532       if (insert_mode()) insert(Fl::event_text());
533       else overstrike(Fl::event_text());
534     }
535     show_insert_position();
536     set_changed();
537     if (when()&FL_WHEN_CHANGED) do_callback();
538     return 1;
539   }
540 
541   int key = Fl::event_key(), state = Fl::event_state(), c = Fl::event_text()[0];
542   state &= FL_SHIFT|FL_CTRL|FL_ALT|FL_META; // only care about these states
543   Key_Func f;
544   f = bound_key_function(key, state, global_key_bindings);
545   if (!f) f = bound_key_function(key, state, key_bindings);
546   if (f) return f(key, this);
547   if (default_key_function_ && !state) return default_key_function_(c, this);
548   return 0;
549 }
550 
551 /** does or does not a callback according to changed() and when() settings */
maybe_do_callback()552 void Fl_Text_Editor::maybe_do_callback() {
553 //  printf("Fl_Text_Editor::maybe_do_callback()\n");
554 //  printf("changed()=%d, when()=%x\n", changed(), when());
555   if (changed() || (when()&FL_WHEN_NOT_CHANGED)) do_callback();
556 }
557 
handle(int event)558 int Fl_Text_Editor::handle(int event) {
559   static int dndCursorPos;
560 
561   if (!buffer()) return 0;
562 
563   switch (event) {
564     case FL_FOCUS:
565       show_cursor(mCursorOn); // redraws the cursor
566       if (buffer()->selected()) redraw(); // Redraw selections...
567       Fl::focus(this);
568       return 1;
569 
570     case FL_UNFOCUS:
571       show_cursor(mCursorOn); // redraws the cursor
572       if (buffer()->selected()) redraw(); // Redraw selections...
573     case FL_HIDE:
574       if (when() & FL_WHEN_RELEASE) maybe_do_callback();
575       return 1;
576 
577     case FL_KEYBOARD:
578       if (active_r() && window() && this == Fl::belowmouse())
579         window()->cursor(FL_CURSOR_NONE);
580       return handle_key();
581 
582     case FL_PASTE:
583       if (!Fl::event_text()) {
584         fl_beep();
585 	return 1;
586       }
587       buffer()->remove_selection();
588       if (insert_mode()) insert(Fl::event_text());
589       else overstrike(Fl::event_text());
590       show_insert_position();
591       set_changed();
592       if (when()&FL_WHEN_CHANGED) do_callback();
593       return 1;
594 
595     case FL_ENTER:
596 // MRS: WIN32 only?  Need to test!
597 //    case FL_MOVE:
598       show_cursor(mCursorOn);
599       return 1;
600 
601     case FL_PUSH:
602       if (Fl::event_button() == 2) {
603         // don't let the text_display see this event
604         if (Fl_Group::handle(event)) return 1;
605         dragType = DRAG_NONE;
606 	if(buffer()->selected()) {
607 	  buffer()->unselect();
608 	  }
609 	int pos = xy_to_position(Fl::event_x(), Fl::event_y(), CURSOR_POS);
610         insert_position(pos);
611         Fl::paste(*this, 0);
612         Fl::focus(this);
613         set_changed();
614         if (when()&FL_WHEN_CHANGED) do_callback();
615         return 1;
616       }
617       break;
618 
619     case FL_SHORTCUT:
620       if (!(shortcut() ? Fl::test_shortcut(shortcut()) : test_shortcut()))
621         return 0;
622       if (Fl::visible_focus() && handle(FL_FOCUS)) {
623         Fl::focus(this);
624         return 1;
625       }
626       break;
627 
628       // Handle drag'n'drop attempt by the user. This is a simplified
629       // implementation which allows dnd operations onto the scroll bars.
630     case FL_DND_ENTER: // save the current cursor position
631       if (Fl::visible_focus() && handle(FL_FOCUS))
632         Fl::focus(this);
633       show_cursor(mCursorOn);
634       dndCursorPos = insert_position();
635       /* fall through */
636     case FL_DND_DRAG: // show a temporary insertion cursor
637       insert_position(xy_to_position(Fl::event_x(), Fl::event_y(), CURSOR_POS));
638       return 1;
639     case FL_DND_LEAVE: // restore original cursor
640       insert_position(dndCursorPos);
641       return 1;
642     case FL_DND_RELEASE: // keep insertion cursor and wait for the FL_PASTE event
643       buffer()->unselect(); // FL_PASTE must not destroy current selection!
644       return 1;
645   }
646 
647   return Fl_Text_Display::handle(event);
648 }
649 
650 //
651 // End of "$Id: Fl_Text_Editor.cxx 8034 2010-12-15 12:21:55Z AlbrechtS $".
652 //
653