1 //
2 // "$Id: Fl_Input.cxx 8726 2011-05-23 18:32:47Z AlbrechtS $"
3 //
4 // Input widget for the Fast Light Tool Kit (FLTK).
5 //
6 // Copyright 1998-2011 by Bill Spitzak and others.
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 // This is the "user interface", it decodes user actions into what to
29 // do to the text. See also Fl_Input_.cxx, where the text is actually
30 // manipulated (and some ui, in particular the mouse, is done...).
31 // In theory you can replace this code with another subclass to change
32 // the keybindings.
33
34 #include <stdio.h>
35 #include <stdlib.h>
36 #include <FL/Fl.H>
37 #include <FL/Fl_Window.H>
38 #include <FL/Fl_Input.H>
39 #include <FL/fl_draw.H>
40 #include <FL/fl_ask.H>
41 #include "flstring.h"
42
43 #if defined(FL_DLL) // really needed for c'tors for MS VC++ only
44 #include <FL/Fl_Float_Input.H>
45 #include <FL/Fl_Int_Input.H>
46 #include <FL/Fl_Multiline_Input.H>
47 #include <FL/Fl_Output.H>
48 #include <FL/Fl_Multiline_Output.H>
49 #include <FL/Fl_Secret_Input.H>
50 #endif
51
52 #ifdef HAVE_LOCALE_H
53 # include <locale.h>
54 #endif
55
56
draw()57 void Fl_Input::draw() {
58 if (input_type() == FL_HIDDEN_INPUT) return;
59 Fl_Boxtype b = box();
60 if (damage() & FL_DAMAGE_ALL) draw_box(b, color());
61 Fl_Input_::drawtext(x()+Fl::box_dx(b), y()+Fl::box_dy(b),
62 w()-Fl::box_dw(b), h()-Fl::box_dh(b));
63 }
64
65 // kludge so shift causes selection to extend:
shift_position(int p)66 int Fl_Input::shift_position(int p) {
67 return position(p, Fl::event_state(FL_SHIFT) ? mark() : p);
68 }
69
shift_up_down_position(int p)70 int Fl_Input::shift_up_down_position(int p) {
71 return up_down_position(p, Fl::event_state(FL_SHIFT));
72 }
73
74 // Old text from FLTK 1.1 for reference:
75 // If you define NORMAL_INPUT_MOVE as zero you will get the peculiar fltk
76 // behavior where moving off the end of an input field will move the
77 // cursor into the next field:
78 // define it as 1 to prevent cursor movement from going to next field:
79 //
80 // Note: this has been replaced by Fl::option(Fl::OPTION_ARROW_FOCUS)
81 // in FLTK 1.3. This option has "inverted" values:
82 // 1 = Arrow keys move focus (previously 0)
83 // 0 = Arrow keys don't move focus (previously 1)
84 // Hence we define ...
85 //
86 #define NORMAL_INPUT_MOVE (Fl::option(Fl::OPTION_ARROW_FOCUS) ? 0 : 1)
87
88 #define ctrl(x) ((x)^0x40)
89
90 // List of characters that are legal in a floating point input field.
91 // This text string is created at run-time to take the current locale
92 // into account (for example, continental Europe uses a comma instead
93 // of a decimal point). For back compatibility reasons, we always
94 // allow the decimal point.
95 #ifdef HAVE_LOCALECONV
96 static const char *standard_fp_chars = ".eE+-";
97 static const char *legal_fp_chars = 0L;
98 #else
99 static const char *legal_fp_chars = ".eE+-";
100 #endif
101
102 // Move cursor up specified #lines
103 // If OPTION_ARROW_FOCUS is disabled, return 1 to prevent focus navigation.
104 //
kf_lines_up(int repeat_num)105 int Fl_Input::kf_lines_up(int repeat_num) {
106 int i = position();
107 if (!line_start(i)) {
108 //UNNEEDED if (input_type()==FL_MULTILINE_INPUT && !Fl::option(Fl::OPTION_ARROW_FOCUS)) return 1;
109 return NORMAL_INPUT_MOVE;
110 }
111 while(repeat_num--) {
112 i = line_start(i);
113 if (!i) break;
114 i--;
115 }
116 shift_up_down_position(line_start(i));
117 return 1;
118 }
119
120 // Move cursor down specified #lines
121 // If OPTION_ARROW_FOCUS is disabled, return 1 to prevent focus navigation.
122 //
kf_lines_down(int repeat_num)123 int Fl_Input::kf_lines_down(int repeat_num) {
124 int i = position();
125 if (line_end(i) >= size()) {
126 //UNNEEDED if (input_type()==FL_MULTILINE_INPUT && !Fl::option(Fl::OPTION_ARROW_FOCUS)) return 1;
127 return NORMAL_INPUT_MOVE;
128 }
129 while (repeat_num--) {
130 i = line_end(i);
131 if (i >= size()) break;
132 i++;
133 }
134 shift_up_down_position(i);
135 return 1;
136 }
137
138 // Move up a page
kf_page_up()139 int Fl_Input::kf_page_up() {
140 return kf_lines_up(linesPerPage());
141 }
142
143 // Move down a page
kf_page_down()144 int Fl_Input::kf_page_down() {
145 return kf_lines_down(linesPerPage());
146 }
147
148 // Toggle insert mode
kf_insert_toggle()149 int Fl_Input::kf_insert_toggle() {
150 if (readonly()) { fl_beep(); return 1; }
151 return 1; // \todo: needs insert mode
152 }
153
154 // Delete word right
kf_delete_word_right()155 int Fl_Input::kf_delete_word_right() {
156 if (readonly()) { fl_beep(); return 1; }
157 if (mark() != position()) return cut();
158 cut(position(), word_end(position()));
159 return 1;
160 }
161
162 // Delete word left
kf_delete_word_left()163 int Fl_Input::kf_delete_word_left() {
164 if (readonly()) { fl_beep(); return 1; }
165 if (mark() != position()) return cut();
166 cut(word_start(position()), position());
167 return 1;
168 }
169
170 // Delete to start of line
kf_delete_sol()171 int Fl_Input::kf_delete_sol() {
172 if (readonly()) { fl_beep(); return 1; }
173 if (mark() != position()) return cut();
174 cut(line_start(position()), position());
175 return 1;
176 }
177
178 // Delete to end of line
kf_delete_eol()179 int Fl_Input::kf_delete_eol() {
180 if (readonly()) { fl_beep(); return 1; }
181 if (mark() != position()) return cut();
182 cut(position(), line_end(position()));
183 return 1;
184 }
185
kf_delete_char_right()186 int Fl_Input::kf_delete_char_right() {
187 if (readonly()) { fl_beep(); return 1; }
188 if (mark() != position()) return cut();
189 else return cut(1);
190 }
191
kf_delete_char_left()192 int Fl_Input::kf_delete_char_left() {
193 if (readonly()) { fl_beep(); return 1; }
194 if (mark() != position()) cut();
195 else cut(-1);
196 return 1;
197 }
198
199 // Move cursor to start of line
kf_move_sol()200 int Fl_Input::kf_move_sol() {
201 return shift_position(line_start(position())) + NORMAL_INPUT_MOVE;
202 }
203
204 // Move cursor to end of line
kf_move_eol()205 int Fl_Input::kf_move_eol() {
206 return shift_position(line_end(position())) + NORMAL_INPUT_MOVE;
207 }
208
209 // Clear to end of line
kf_clear_eol()210 int Fl_Input::kf_clear_eol() {
211 if (readonly()) { fl_beep(); return 1; }
212 if (position()>=size()) return 0;
213 int i = line_end(position());
214 if (i == position() && i < size()) i++;
215 cut(position(), i);
216 return copy_cuts();
217 }
218
219 // Move cursor one character to the left
220 // If OPTION_ARROW_FOCUS is disabled, return 1 to prevent focus navigation.
221 //
kf_move_char_left()222 int Fl_Input::kf_move_char_left() {
223 int i = shift_position(position()-1) + NORMAL_INPUT_MOVE;
224 return Fl::option(Fl::OPTION_ARROW_FOCUS) ? i : 1;
225 }
226
227 // Move cursor one character to the right
228 // If OPTION_ARROW_FOCUS is disabled, return 1 to prevent focus navigation.
229 //
kf_move_char_right()230 int Fl_Input::kf_move_char_right() {
231 int i = shift_position(position()+1) + NORMAL_INPUT_MOVE;
232 return Fl::option(Fl::OPTION_ARROW_FOCUS) ? i : 1;
233 }
234
235 // Move cursor word-left
kf_move_word_left()236 int Fl_Input::kf_move_word_left() {
237 shift_position(word_start(position()));
238 return 1;
239 }
240
241 // Move cursor word-right
kf_move_word_right()242 int Fl_Input::kf_move_word_right() {
243 shift_position(word_end(position()));
244 return 1;
245 }
246
247 // Move cursor up one line and to the start of line (paragraph up)
kf_move_up_and_sol()248 int Fl_Input::kf_move_up_and_sol() {
249 if (line_start(position())==position() && position()>0)
250 return shift_position(line_start(position()-1)) + NORMAL_INPUT_MOVE;
251 else
252 return shift_position(line_start(position())) + NORMAL_INPUT_MOVE;
253 }
254
255 // Move cursor down one line and to the end of line (paragraph down)
kf_move_down_and_eol()256 int Fl_Input::kf_move_down_and_eol() {
257 if (line_end(position())==position() && position()<size())
258 return shift_position(line_end(position()+1)) + NORMAL_INPUT_MOVE;
259 else
260 return shift_position(line_end(position())) + NORMAL_INPUT_MOVE;
261 }
262
263 // Move to top of document
kf_top()264 int Fl_Input::kf_top() {
265 shift_position(0);
266 return 1;
267 }
268
269 // Move to bottom of document
kf_bottom()270 int Fl_Input::kf_bottom() {
271 shift_position(size());
272 return 1;
273 }
274
275 // Select all text in the widget
kf_select_all()276 int Fl_Input::kf_select_all() {
277 position(0,size());
278 return 1;
279 }
280
281 // Undo.
kf_undo()282 int Fl_Input::kf_undo() {
283 if (readonly()) { fl_beep(); return 1; }
284 return undo();
285 }
286
287 // Redo. (currently unimplemented.. toggles undo() instead)
kf_redo()288 int Fl_Input::kf_redo() {
289 if (readonly()) { fl_beep(); return 1; }
290 return kf_undo(); // currently we don't support multilevel undo
291 }
292
293 // Do a copy operation
kf_copy()294 int Fl_Input::kf_copy() {
295 return copy(1);
296 }
297
298 // Do a paste operation
kf_paste()299 int Fl_Input::kf_paste() {
300 if (readonly()) { fl_beep(); return 1; }
301 Fl::paste(*this, 1);
302 return 1;
303 }
304
305 // Do a cut with copy
kf_copy_cut()306 int Fl_Input::kf_copy_cut() {
307 if (readonly()) { fl_beep(); return 1; }
308 copy(1);
309 return cut();
310 }
311
312 // Handle a keystroke.
313 // Returns 1 if handled by us, 0 if not.
314 //
handle_key()315 int Fl_Input::handle_key() {
316
317 char ascii = Fl::event_text()[0];
318
319 int del;
320 if (Fl::compose(del)) {
321
322 // Insert characters into numeric fields after checking for legality:
323 if (input_type() == FL_FLOAT_INPUT || input_type() == FL_INT_INPUT) {
324 Fl::compose_reset(); // ignore any foreign letters...
325
326 // initialize the list of legal characters inside a floating point number
327 #ifdef HAVE_LOCALECONV
328 if (!legal_fp_chars) {
329 int len = strlen(standard_fp_chars);
330 struct lconv *lc = localeconv();
331 if (lc) {
332 if (lc->decimal_point) len += strlen(lc->decimal_point);
333 if (lc->mon_decimal_point) len += strlen(lc->mon_decimal_point);
334 if (lc->positive_sign) len += strlen(lc->positive_sign);
335 if (lc->negative_sign) len += strlen(lc->negative_sign);
336 }
337 // the following line is not a true memory leak because the array is only
338 // allocated once if required, and automatically freed when the program quits
339 char *chars = (char*)malloc(len+1);
340 legal_fp_chars = chars;
341 strcpy(chars, standard_fp_chars);
342 if (lc) {
343 if (lc->decimal_point) strcat(chars, lc->decimal_point);
344 if (lc->mon_decimal_point) strcat(chars, lc->mon_decimal_point);
345 if (lc->positive_sign) strcat(chars, lc->positive_sign);
346 if (lc->negative_sign) strcat(chars, lc->negative_sign);
347 }
348 }
349 #endif // HAVE_LOCALECONV
350
351 // find the insert position
352 int ip = position()<mark() ? position() : mark();
353 // This is complex to allow "0xff12" hex to be typed:
354 if ( (!ip && (ascii == '+' || ascii == '-'))
355 || (ascii >= '0' && ascii <= '9')
356 || (ip==1 && index(0)=='0' && (ascii=='x' || ascii == 'X'))
357 || (ip>1 && index(0)=='0' && (index(1)=='x'||index(1)=='X')
358 && ((ascii>='A'&& ascii<='F') || (ascii>='a'&& ascii<='f')))
359 || (input_type()==FL_FLOAT_INPUT && ascii && strchr(legal_fp_chars, ascii)))
360 {
361 if (readonly()) fl_beep();
362 else replace(position(), mark(), &ascii, 1);
363 }
364 return 1;
365 }
366
367 if (del || Fl::event_length()) {
368 if (readonly()) fl_beep();
369 else replace(position(), del ? position()-del : mark(),
370 Fl::event_text(), Fl::event_length());
371 }
372 return 1;
373 }
374
375 unsigned int mods = Fl::event_state() & (FL_META|FL_CTRL|FL_ALT);
376 unsigned int shift = Fl::event_state() & FL_SHIFT;
377 unsigned int multiline = (input_type() == FL_MULTILINE_INPUT) ? 1 : 0;
378 //
379 // The following lists apps that support these keypresses.
380 // Prefixes: '!' indicates NOT supported, '?' indicates un-verified.
381 //
382 // HIG=Human Interface Guide,
383 // TE=TextEdit.app, SA=Safari.app, WOX=MS Word/OSX -- OSX 10.4.x
384 // NP=Notepad, WP=WordPad, WOW=MS Word/Windows -- WinXP
385 // GE=gedit, KE=kedit -- Ubuntu8.04
386 // OF=old FLTK behavior (<=1.1.10)
387 //
388 // Example: (NP,WP,!WO) means supported in notepad + wordpad, but NOT word.
389 //
390 switch (Fl::event_key()) {
391
392 case FL_Insert:
393 // Note: Mac has no "Insert" key; it's the "Help" key.
394 // This keypress is apparently not possible on macs.
395 //
396 if (mods==0 && shift) return kf_paste(); // Shift-Insert (WP,NP,WOW,GE,KE,OF)
397 if (mods==0) return kf_insert_toggle(); // Insert (Standard)
398 if (mods==FL_CTRL) return kf_copy(); // Ctrl-Insert (WP,NP,WOW,GE,KE,OF)
399 return 0; // ignore other combos, pass to parent
400
401 case FL_Delete: {
402 #ifdef __APPLE__
403 if (mods==0) return kf_delete_char_right(); // Delete (OSX-HIG,TE,SA,WOX)
404 if (mods==FL_CTRL) return kf_delete_char_right(); // Ctrl-Delete (??? TE,!SA,!WOX)
405 if (mods==FL_ALT) return kf_delete_word_right(); // Alt-Delete (OSX-HIG,TE,SA)
406 return 0; // ignore other combos, pass to parent
407 #else
408 int selected = (position() != mark()) ? 1 : 0;
409 if (mods==0 && shift && selected)
410 return kf_copy_cut(); // Shift-Delete with selection (WP,NP,WOW,GE,KE,OF)
411 if (mods==0 && shift && !selected)
412 return kf_delete_char_right(); // Shift-Delete no selection (WP,NP,WOW,GE,KE,!OF)
413 if (mods==0) return kf_delete_char_right(); // Delete (Standard)
414 if (mods==FL_CTRL) return kf_delete_word_right(); // Ctrl-Delete (WP,!NP,WOW,GE,KE,!OF)
415 return 0; // ignore other combos, pass to parent
416 #endif
417 }
418
419 case FL_Left:
420 #ifdef __APPLE__
421 if (mods==0) return kf_move_char_left(); // Left (OSX-HIG)
422 if (mods==FL_ALT) return kf_move_word_left(); // Alt-Left (OSX-HIG)
423 if (mods==FL_META) return kf_move_sol(); // Meta-Left (OSX-HIG)
424 if (mods==FL_CTRL) return kf_move_sol(); // Ctrl-Left (TE/SA)
425 return 0; // ignore other combos, pass to parent
426 #else
427 if (mods==0) return kf_move_char_left(); // Left (WP,NP,WOW,GE,KE,OF)
428 if (mods==FL_CTRL) return kf_move_word_left(); // Ctrl-Left (WP,NP,WOW,GE,KE,!OF)
429 if (mods==FL_META) return kf_move_char_left(); // Meta-Left (WP,NP,?WOW,GE,KE)
430 return 0; // ignore other combos, pass to parent
431 #endif
432
433 case FL_Right:
434 #ifdef __APPLE__
435 if (mods==0) return kf_move_char_right(); // Right (OSX-HIG)
436 if (mods==FL_ALT) return kf_move_word_right(); // Alt-Right (OSX-HIG)
437 if (mods==FL_META) return kf_move_eol(); // Meta-Right (OSX-HIG)
438 if (mods==FL_CTRL) return kf_move_eol(); // Ctrl-Right (TE/SA)
439 return 0; // ignore other combos, pass to parent
440 #else
441 if (mods==0) return kf_move_char_right(); // Right (WP,NP,WOW,GE,KE,OF)
442 if (mods==FL_CTRL) return kf_move_word_right(); // Ctrl-Right (WP,NP,WOW,GE,KE,!OF)
443 if (mods==FL_META) return kf_move_char_right(); // Meta-Right (WP,NP,?WOW,GE,KE,!OF)
444 return 0; // ignore other combos, pass to parent
445 #endif
446
447 case FL_Up:
448 #ifdef __APPLE__
449 if (mods==0) return kf_lines_up(1); // Up (OSX-HIG)
450 if (mods==FL_CTRL) return kf_page_up(); // Ctrl-Up (TE !HIG)
451 if (mods==FL_ALT) return kf_move_up_and_sol(); // Alt-Up (OSX-HIG)
452 if (mods==FL_META) return kf_top(); // Meta-Up (OSX-HIG)
453 return 0; // ignore other combos, pass to parent
454 #else
455 if (mods==0) return kf_lines_up(1); // Up (WP,NP,WOW,GE,KE,OF)
456 if (mods==FL_CTRL) return kf_move_up_and_sol(); // Ctrl-Up (WP,!NP,WOW,GE,!KE,OF)
457 return 0; // ignore other combos, pass to parent
458 #endif
459
460 case FL_Down:
461 #ifdef __APPLE__
462 if (mods==0) return kf_lines_down(1); // Dn (OSX-HIG)
463 if (mods==FL_CTRL) return kf_page_down(); // Ctrl-Dn (TE !HIG)
464 if (mods==FL_ALT) return kf_move_down_and_eol(); // Alt-Dn (OSX-HIG)
465 if (mods==FL_META) return kf_bottom(); // Meta-Dn (OSX-HIG)
466 return 0; // ignore other combos, pass to parent
467 #else
468 if (mods==0) return kf_lines_down(1); // Dn (WP,NP,WOW,GE,KE,OF)
469 if (mods==FL_CTRL) return kf_move_down_and_eol(); // Ctrl-Down (WP,!NP,WOW,GE,!KE,OF)
470 return 0; // ignore other combos, pass to parent
471 #endif
472
473 case FL_Page_Up:
474 // Fl_Input has no scroll control, so instead we move the cursor by one page
475 // OSX-HIG recommends Alt increase one semantic unit, Meta next higher..
476 #ifdef __APPLE__
477 if (mods==0) return kf_page_up(); // PgUp (OSX-HIG)
478 if (mods==FL_ALT) return kf_page_up(); // Alt-PageUp (OSX-HIG)
479 if (mods==FL_META) return kf_top(); // Meta-PageUp (OSX-HIG,!TE)
480 return 0; // ignore other combos, pass to parent
481 #else
482 if (mods==0) return kf_page_up(); // PageUp (WP,NP,WOW,GE,KE)
483 if (mods==FL_CTRL) return kf_page_up(); // Ctrl-PageUp (!WP,!NP,!WOW,!GE,KE,OF)
484 if (mods==FL_ALT) return kf_page_up(); // Alt-PageUp (!WP,!NP,!WOW,!GE,KE,OF)
485 return 0; // ignore other combos, pass to parent
486 #endif
487
488 case FL_Page_Down:
489 #ifdef __APPLE__
490 // Fl_Input has no scroll control, so instead we move the cursor by one page
491 // OSX-HIG recommends Alt increase one semantic unit, Meta next higher..
492 if (mods==0) return kf_page_down(); // PgDn (OSX-HIG)
493 if (mods==FL_ALT) return kf_page_down(); // Alt-PageDn (OSX-HIG)
494 if (mods==FL_META) return kf_bottom(); // Meta-PageDn (OSX-HIG,!TE)
495 return 0; // ignore other combos, pass to parent
496 #else
497 if (mods==0) return kf_page_down(); // PageDn (WP,NP,WOW,GE,KE)
498 if (mods==FL_CTRL) return kf_page_down(); // Ctrl-PageDn (!WP,!NP,!WOW,!GE,KE,OF)
499 if (mods==FL_ALT) return kf_page_down(); // Alt-PageDn (!WP,!NP,!WOW,!GE,KE,OF)
500 return 0; // ignore other combos, pass to parent
501 #endif
502
503 case FL_Home:
504 #ifdef __APPLE__
505 if (mods==0) return kf_top(); // Home (OSX-HIG)
506 if (mods==FL_ALT) return kf_top(); // Alt-Home (???)
507 return 0; // ignore other combos, pass to parent
508 #else
509 if (mods==0) return kf_move_sol(); // Home (WP,NP,WOW,GE,KE,OF)
510 if (mods==FL_CTRL) return kf_top(); // Ctrl-Home (WP,NP,WOW,GE,KE,OF)
511 return 0; // ignore other combos, pass to parent
512 #endif
513
514 case FL_End:
515 #ifdef __APPLE__
516 if (mods==0) return kf_bottom(); // End (OSX-HIG)
517 if (mods==FL_ALT) return kf_bottom(); // Alt-End (???)
518 return 0; // ignore other combos, pass to parent
519 #else
520 if (mods==0) return kf_move_eol(); // End (WP,NP,WOW,GE,KE,OF)
521 if (mods==FL_CTRL) return kf_bottom(); // Ctrl-End (WP,NP,WOW,GE,KE,OF)
522 return 0; // ignore other combos, pass to parent
523 #endif
524
525 case FL_BackSpace:
526 #ifdef __APPLE__
527 if (mods==0) return kf_delete_char_left(); // Backspace (OSX-HIG)
528 if (mods==FL_CTRL) return kf_delete_char_left(); // Ctrl-Backspace (TE/SA)
529 if (mods==FL_ALT) return kf_delete_word_left(); // Alt-Backspace (OSX-HIG)
530 if (mods==FL_META) return kf_delete_sol(); // Meta-Backspace (OSX-HIG,!TE)
531 return 0; // ignore other combos, pass to parent
532 #else
533 if (mods==0) return kf_delete_char_left(); // Backspace (WP,NP,WOW,GE,KE,OF)
534 if (mods==FL_CTRL) return kf_delete_word_left(); // Ctrl-Backspace (WP,!NP,WOW,GE,KE,!OF)
535 return 0; // ignore other combos, pass to parent
536 #endif
537
538 case FL_Enter:
539 case FL_KP_Enter:
540 if (when() & FL_WHEN_ENTER_KEY) {
541 position(size(), 0);
542 maybe_do_callback();
543 return 1;
544 } else if (multiline && !readonly()) {
545 return replace(position(), mark(), "\n", 1);
546 } return 0; // reserved for shortcuts
547
548 case FL_Tab:
549 // Handle special case for multiline input with 'old tab behavior';
550 // tab handled as a normal insertable character.
551 //
552 if (mods==0 && !shift // Tab?
553 && !tab_nav() // old tab behavior enabled?
554 && multiline) { // multiline input?
555 break; // insert tab character
556 }
557 if (mods==0) return 0; // Tab, Shift-Tab? nav focus (Standard/OSX-HIG)
558 return 0; // ignore other combos, pass to parent
559
560 case 'a':
561 if (mods==FL_COMMAND) return kf_select_all(); // Ctrl-A, Mac:Meta-A (Standard/OSX-HIG)
562 break; // handle other combos elsewhere
563 case 'c':
564 if (mods==FL_COMMAND) return kf_copy(); // Ctrl-C, Mac:Meta-C (Standard/OSX-HIG)
565 break; // handle other combos elsewhere
566 case 'v':
567 if (mods==FL_COMMAND) return kf_paste(); // Ctrl-V, Mac:Meta-V (Standard/OSX-HIG)
568 break; // handle other combos elsewhere
569 case 'x':
570 if (mods==FL_COMMAND) return kf_copy_cut(); // Ctrl-X, Mac:Meta-X (Standard/OSX-HIG)
571 break;
572 case 'z':
573 if (mods==FL_COMMAND && !shift) return kf_undo(); // Ctrl-Z, Mac:Meta-Z (Standard/OSX-HIG)
574 if (mods==FL_COMMAND && shift) return kf_redo(); // Shift-Ctrl-Z, Mac:Shift-Meta-Z (Standard/OSX-HIG)
575 break; // handle other combos elsewhere
576 }
577
578 switch (ascii) {
579 case ctrl('H'):
580 return kf_delete_char_left(); // Ctrl-H (!WP,!NP,!WOW,!WOX,TE,SA,GE,KE,OF)
581 case ctrl('I'): // Ctrl-I (literal Tab) (!WP,NP,!WOW,!GE,KE,OF)
582 case ctrl('J'): // Ctrl-J (literal Line Feed/Enter) (Standard)
583 case ctrl('L'): // Ctrl-L (literal Form Feed) (Standard)
584 case ctrl('M'): // Ctrl-M (literal Cr) (Standard)
585 if (readonly()) { fl_beep(); return 1; }
586 // insert a few selected control characters literally:
587 if (input_type() != FL_FLOAT_INPUT && input_type() != FL_INT_INPUT)
588 return replace(position(), mark(), &ascii, 1);
589 break;
590 }
591
592 return 0; // ignored
593 }
594
handle(int event)595 int Fl_Input::handle(int event) {
596 static int dnd_save_position, dnd_save_mark, drag_start = -1, newpos;
597 static Fl_Widget *dnd_save_focus;
598 switch (event) {
599 case FL_FOCUS:
600 switch (Fl::event_key()) {
601 case FL_Right:
602 position(0);
603 break;
604 case FL_Left:
605 position(size());
606 break;
607 case FL_Down:
608 up_down_position(0);
609 break;
610 case FL_Up:
611 up_down_position(line_start(size()));
612 break;
613 case FL_Tab:
614 position(size(),0);
615 break;
616 default:
617 position(position(),mark());// turns off the saved up/down arrow position
618 break;
619 }
620 break;
621
622 case FL_KEYBOARD:
623 // Handle special case for multiline input with 'old tab behavior'
624 // where tab is entered as a character: make sure user attempt to 'tab over'
625 // widget doesn't destroy the field, replacing it with a tab character.
626 //
627 if (Fl::event_key() == FL_Tab // Tab key?
628 && !Fl::event_state(FL_SHIFT) // no shift?
629 && !tab_nav() // with tab navigation disabled?
630 && input_type() == FL_MULTILINE_INPUT // with a multiline input?
631 && (mark()==0 && position()==size())) { // while entire field selected?
632 // Set cursor to the end of the selection...
633 if (mark() > position())
634 position(mark());
635 else
636 position(position());
637 return (1);
638 } else {
639 if (active_r() && window() && this == Fl::belowmouse())
640 window()->cursor(FL_CURSOR_NONE);
641 return handle_key();
642 }
643 //NOTREACHED
644
645 case FL_PUSH:
646 if (Fl::dnd_text_ops()) {
647 int oldpos = position(), oldmark = mark();
648 Fl_Boxtype b = box();
649 Fl_Input_::handle_mouse(x()+Fl::box_dx(b), y()+Fl::box_dy(b),
650 w()-Fl::box_dw(b), h()-Fl::box_dh(b), 0);
651 newpos = position();
652 position( oldpos, oldmark );
653 if (Fl::focus()==this && !Fl::event_state(FL_SHIFT) && input_type()!=FL_SECRET_INPUT &&
654 ( (newpos >= mark() && newpos < position()) ||
655 (newpos >= position() && newpos < mark()) ) ) {
656 // user clicked in the selection, may be trying to drag
657 drag_start = newpos;
658 return 1;
659 }
660 drag_start = -1;
661 }
662
663 if (Fl::focus() != this) {
664 Fl::focus(this);
665 handle(FL_FOCUS);
666 }
667 break;
668
669 case FL_DRAG:
670 if (Fl::dnd_text_ops()) {
671 if (drag_start >= 0) {
672 if (Fl::event_is_click()) return 1; // debounce the mouse
673 // save the position because sometimes we don't get DND_ENTER:
674 dnd_save_position = position();
675 dnd_save_mark = mark();
676 // drag the data:
677 copy(0); Fl::dnd();
678 return 1;
679 }
680 }
681 break;
682
683 case FL_RELEASE:
684 if (Fl::event_button() == 2) {
685 Fl::event_is_click(0); // stop double click from picking a word
686 Fl::paste(*this, 0);
687 } else if (!Fl::event_is_click()) {
688 // copy drag-selected text to the clipboard.
689 copy(0);
690 } else if (Fl::event_is_click() && drag_start >= 0) {
691 // user clicked in the field and wants to reset the cursor position...
692 position(drag_start, drag_start);
693 drag_start = -1;
694 } else if (Fl::event_clicks()) {
695 // user double or triple clicked to select word or whole text
696 copy(0);
697 }
698
699 // For output widgets, do the callback so the app knows the user
700 // did something with the mouse...
701 if (readonly()) do_callback();
702
703 return 1;
704
705 case FL_DND_ENTER:
706 Fl::belowmouse(this); // send the leave events first
707 dnd_save_position = position();
708 dnd_save_mark = mark();
709 dnd_save_focus = Fl::focus();
710 if (dnd_save_focus != this) {
711 Fl::focus(this);
712 handle(FL_FOCUS);
713 }
714 // fall through:
715 case FL_DND_DRAG:
716 //int p = mouse_position(X, Y, W, H);
717 #if DND_OUT_XXXX
718 if (Fl::focus()==this && (p>=dnd_save_position && p<=dnd_save_mark ||
719 p>=dnd_save_mark && p<=dnd_save_position)) {
720 position(dnd_save_position, dnd_save_mark);
721 return 0;
722 }
723 #endif
724 {
725 Fl_Boxtype b = box();
726 Fl_Input_::handle_mouse(x()+Fl::box_dx(b), y()+Fl::box_dy(b),
727 w()-Fl::box_dw(b), h()-Fl::box_dh(b), 0);
728 }
729 return 1;
730
731 case FL_DND_LEAVE:
732 position(dnd_save_position, dnd_save_mark);
733 #if DND_OUT_XXXX
734 if (!focused())
735 #endif
736 if (dnd_save_focus != this) {
737 Fl::focus(dnd_save_focus);
738 handle(FL_UNFOCUS);
739 }
740 #if !(defined(__APPLE__) || defined(WIN32))
741 Fl::first_window()->cursor(FL_CURSOR_MOVE);
742 #endif
743 return 1;
744
745 case FL_DND_RELEASE:
746 take_focus();
747 return 1;
748
749 /* TODO: this will scroll the area, but stop if the cursor would become invisible.
750 That clipping happens in drawtext(). Do we change the clipping or should
751 we move the cursor (ouch)?
752 case FL_MOUSEWHEEL:
753 if (Fl::e_dy > 0) {
754 yscroll( yscroll() - Fl::e_dy*15 );
755 } else if (Fl::e_dy < 0) {
756 yscroll( yscroll() - Fl::e_dy*15 );
757 }
758 return 1;
759 */
760 }
761 Fl_Boxtype b = box();
762 return Fl_Input_::handletext(event,
763 x()+Fl::box_dx(b), y()+Fl::box_dy(b),
764 w()-Fl::box_dw(b), h()-Fl::box_dh(b));
765 }
766
767 /**
768 Creates a new Fl_Input widget using the given position, size,
769 and label string. The default boxtype is FL_DOWN_BOX.
770 */
Fl_Input(int X,int Y,int W,int H,const char * l)771 Fl_Input::Fl_Input(int X, int Y, int W, int H, const char *l)
772 : Fl_Input_(X, Y, W, H, l) {
773 }
774
775 /*
776 The following constructors must not be in the header file(s) if we
777 build a shared object (DLL). Instead they are defined here to force
778 the constructor (and default destructor as well) to be defined in
779 the DLL and exported (STR #2632).
780
781 Note: if you change any of them, do the same changes in the specific
782 header file as well. This redundant definition was chosen to enable
783 inline constructors in the header files (for static linking) as well
784 as those here for dynamic linking (Windows DLL).
785 */
786 #if defined(FL_DLL)
787
Fl_Float_Input(int X,int Y,int W,int H,const char * l)788 Fl_Float_Input::Fl_Float_Input(int X,int Y,int W,int H,const char *l)
789 : Fl_Input(X,Y,W,H,l) {
790 type(FL_FLOAT_INPUT);
791 }
792
Fl_Int_Input(int X,int Y,int W,int H,const char * l)793 Fl_Int_Input::Fl_Int_Input(int X,int Y,int W,int H,const char *l)
794 : Fl_Input(X,Y,W,H,l) {
795 type(FL_INT_INPUT);
796 }
797
Fl_Multiline_Input(int X,int Y,int W,int H,const char * l)798 Fl_Multiline_Input::Fl_Multiline_Input(int X,int Y,int W,int H,const char *l)
799 : Fl_Input(X,Y,W,H,l) {
800 type(FL_MULTILINE_INPUT);
801 }
802
Fl_Output(int X,int Y,int W,int H,const char * l)803 Fl_Output::Fl_Output(int X,int Y,int W,int H, const char *l)
804 : Fl_Input(X, Y, W, H, l) {
805 type(FL_NORMAL_OUTPUT);
806 }
807
Fl_Multiline_Output(int X,int Y,int W,int H,const char * l)808 Fl_Multiline_Output::Fl_Multiline_Output(int X,int Y,int W,int H,const char *l)
809 : Fl_Output(X,Y,W,H,l) {
810 type(FL_MULTILINE_OUTPUT);
811 }
812
Fl_Secret_Input(int X,int Y,int W,int H,const char * l)813 Fl_Secret_Input::Fl_Secret_Input(int X,int Y,int W,int H,const char *l)
814 : Fl_Input(X,Y,W,H,l) {
815 type(FL_SECRET_INPUT);
816 }
817
818 #endif // FL_DLL
819
820 //
821 // End of "$Id: Fl_Input.cxx 8726 2011-05-23 18:32:47Z AlbrechtS $".
822 //
823