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