themes: Workaround for bug where a background color of RGB 0,0,0 in Black color schem...
[ntk.git] / src / Fl_Input.cxx
blobd38d5cfef4b79326ad775eb25545479af3a3e767
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.
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.
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.
23 // Please report all bugs and problems on the following page:
25 // http://www.fltk.org/str.php
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.
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"
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
52 #ifdef HAVE_LOCALE_H
53 # include <locale.h>
54 #endif
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));
65 // kludge so shift causes selection to extend:
66 int Fl_Input::shift_position(int p) {
67 return position(p, Fl::event_state(FL_SHIFT) ? mark() : p);
70 int Fl_Input::shift_up_down_position(int p) {
71 return up_down_position(p, Fl::event_state(FL_SHIFT));
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:
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 ...
86 #define NORMAL_INPUT_MOVE (Fl::option(Fl::OPTION_ARROW_FOCUS) ? 0 : 1)
88 #define ctrl(x) ((x)^0x40)
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
102 // Move cursor up specified #lines
103 // If OPTION_ARROW_FOCUS is disabled, return 1 to prevent focus navigation.
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;
111 while(repeat_num--) {
112 i = line_start(i);
113 if (!i) break;
114 i--;
116 shift_up_down_position(line_start(i));
117 return 1;
120 // Move cursor down specified #lines
121 // If OPTION_ARROW_FOCUS is disabled, return 1 to prevent focus navigation.
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;
129 while (repeat_num--) {
130 i = line_end(i);
131 if (i >= size()) break;
132 i++;
134 shift_up_down_position(i);
135 return 1;
138 // Move up a page
139 int Fl_Input::kf_page_up() {
140 return kf_lines_up(linesPerPage());
143 // Move down a page
144 int Fl_Input::kf_page_down() {
145 return kf_lines_down(linesPerPage());
148 // Toggle insert mode
149 int Fl_Input::kf_insert_toggle() {
150 if (readonly()) { fl_beep(); return 1; }
151 return 1; // \todo: needs insert mode
154 // 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;
162 // 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;
170 // Delete to start of line
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;
178 // Delete to end of line
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;
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);
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;
199 // Move cursor to start of line
200 int Fl_Input::kf_move_sol() {
201 return shift_position(line_start(position())) + NORMAL_INPUT_MOVE;
204 // Move cursor to end of line
205 int Fl_Input::kf_move_eol() {
206 return shift_position(line_end(position())) + NORMAL_INPUT_MOVE;
209 // Clear to end of line
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();
219 // Move cursor one character to the left
220 // If OPTION_ARROW_FOCUS is disabled, return 1 to prevent focus navigation.
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;
227 // Move cursor one character to the right
228 // If OPTION_ARROW_FOCUS is disabled, return 1 to prevent focus navigation.
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;
235 // Move cursor word-left
236 int Fl_Input::kf_move_word_left() {
237 shift_position(word_start(position()));
238 return 1;
241 // Move cursor word-right
242 int Fl_Input::kf_move_word_right() {
243 shift_position(word_end(position()));
244 return 1;
247 // Move cursor up one line and to the start of line (paragraph up)
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;
255 // Move cursor down one line and to the end of line (paragraph down)
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;
263 // Move to top of document
264 int Fl_Input::kf_top() {
265 shift_position(0);
266 return 1;
269 // Move to bottom of document
270 int Fl_Input::kf_bottom() {
271 shift_position(size());
272 return 1;
275 // Select all text in the widget
276 int Fl_Input::kf_select_all() {
277 position(0,size());
278 return 1;
281 // Undo.
282 int Fl_Input::kf_undo() {
283 if (readonly()) { fl_beep(); return 1; }
284 return undo();
287 // Redo. (currently unimplemented.. toggles undo() instead)
288 int Fl_Input::kf_redo() {
289 if (readonly()) { fl_beep(); return 1; }
290 return kf_undo(); // currently we don't support multilevel undo
293 // Do a copy operation
294 int Fl_Input::kf_copy() {
295 return copy(1);
298 // Do a paste operation
299 int Fl_Input::kf_paste() {
300 if (readonly()) { fl_beep(); return 1; }
301 Fl::paste(*this, 1);
302 return 1;
305 // Do a cut with copy
306 int Fl_Input::kf_copy_cut() {
307 if (readonly()) { fl_beep(); return 1; }
308 copy(1);
309 return cut();
312 // Handle a keystroke.
313 // Returns 1 if handled by us, 0 if not.
315 int Fl_Input::handle_key() {
317 char ascii = Fl::event_text()[0];
319 int del;
320 if (Fl::compose(del)) {
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...
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);
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);
349 #endif // HAVE_LOCALECONV
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)))
361 if (readonly()) fl_beep();
362 else replace(position(), mark(), &ascii, 1);
364 return 1;
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());
372 return 1;
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;
379 // The following lists apps that support these keypresses.
380 // Prefixes: '!' indicates NOT supported, '?' indicates un-verified.
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)
388 // Example: (NP,WP,!WO) means supported in notepad + wordpad, but NOT word.
390 switch (Fl::event_key()) {
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.
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
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
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
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
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
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
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
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
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
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
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
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
548 case FL_Tab:
549 // Handle special case for multiline input with 'old tab behavior';
550 // tab handled as a normal insertable character.
552 if (mods==0 && !shift // Tab?
553 && !tab_nav() // old tab behavior enabled?
554 && multiline) { // multiline input?
555 break; // insert tab character
557 if (mods==0) return 0; // Tab, Shift-Tab? nav focus (Standard/OSX-HIG)
558 return 0; // ignore other combos, pass to parent
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
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;
592 return 0; // ignored
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;
620 break;
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.
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();
643 //NOTREACHED
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;
660 drag_start = -1;
663 if (Fl::focus() != this) {
664 Fl::focus(this);
665 handle(FL_FOCUS);
667 break;
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;
681 break;
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);
699 // For output widgets, do the callback so the app knows the user
700 // did something with the mouse...
701 if (readonly()) do_callback();
703 return 1;
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);
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;
723 #endif
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);
729 return 1;
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);
740 #if !(defined(__APPLE__) || defined(WIN32))
741 Fl::first_window()->cursor(FL_CURSOR_MOVE);
742 #endif
743 return 1;
745 case FL_DND_RELEASE:
746 take_focus();
747 return 1;
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 );
758 return 1;
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));
768 Creates a new Fl_Input widget using the given position, size,
769 and label string. The default boxtype is FL_DOWN_BOX.
771 Fl_Input::Fl_Input(int X, int Y, int W, int H, const char *l)
772 : Fl_Input_(X, Y, W, H, l) {
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).
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).
786 #if defined(FL_DLL)
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);
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);
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);
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);
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);
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);
818 #endif // FL_DLL
821 // End of "$Id: Fl_Input.cxx 8726 2011-05-23 18:32:47Z AlbrechtS $".