fltk 1.3.0rc3
About: FLTK (Fast Light Tool Kit) is a cross-platform C++ GUI toolkit for UNIX/Linux (X11), Microsoft Windows, and MacOS X. Release candidate.
  SfR Fresh Dox: fltk-1.3.0rc3-source.tar.gz ("inofficial" and yet experimental doxygen-generated source code documentation)  

Fl_Input.cxx

Go to the documentation of this file.
00001 //
00002 // "$Id: Fl_Input.cxx 8115 2010-12-27 00:16:57Z greg.ercolano $"
00003 //
00004 // Input widget for the Fast Light Tool Kit (FLTK).
00005 //
00006 // Copyright 1998-2010 by Bill Spitzak and others.
00007 //
00008 // This library is free software; you can redistribute it and/or
00009 // modify it under the terms of the GNU Library General Public
00010 // License as published by the Free Software Foundation; either
00011 // version 2 of the License, or (at your option) any later version.
00012 //
00013 // This library is distributed in the hope that it will be useful,
00014 // but WITHOUT ANY WARRANTY; without even the implied warranty of
00015 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00016 // Library General Public License for more details.
00017 //
00018 // You should have received a copy of the GNU Library General Public
00019 // License along with this library; if not, write to the Free Software
00020 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
00021 // USA.
00022 //
00023 // Please report all bugs and problems on the following page:
00024 //
00025 //     http://www.fltk.org/str.php
00026 //
00027 
00028 // This is the "user interface", it decodes user actions into what to
00029 // do to the text.  See also Fl_Input_.cxx, where the text is actually
00030 // manipulated (and some ui, in particular the mouse, is done...).
00031 // In theory you can replace this code with another subclass to change
00032 // the keybindings.
00033 
00034 #include <stdio.h>
00035 #include <stdlib.h>
00036 #include <FL/Fl.H>
00037 #include <FL/Fl_Window.H>
00038 #include <FL/Fl_Input.H>
00039 #include <FL/fl_draw.H>
00040 #include <FL/fl_ask.H>
00041 #include "flstring.h"
00042 
00043 #ifdef HAVE_LOCALE_H
00044 # include <locale.h>
00045 #endif
00046 
00047 
00048 void Fl_Input::draw() {
00049   if (input_type() == FL_HIDDEN_INPUT) return;
00050   Fl_Boxtype b = box();
00051   if (damage() & FL_DAMAGE_ALL) draw_box(b, color());
00052   Fl_Input_::drawtext(x()+Fl::box_dx(b), y()+Fl::box_dy(b),
00053                       w()-Fl::box_dw(b), h()-Fl::box_dh(b));
00054 }
00055 
00056 // kludge so shift causes selection to extend:
00057 int Fl_Input::shift_position(int p) {
00058   return position(p, Fl::event_state(FL_SHIFT) ? mark() : p);
00059 }
00060 
00061 int Fl_Input::shift_up_down_position(int p) {
00062   return up_down_position(p, Fl::event_state(FL_SHIFT));
00063 }
00064 
00065 // Old text from FLTK 1.1 for reference:
00066 // If you define NORMAL_INPUT_MOVE as zero you will get the peculiar fltk
00067 // behavior where moving off the end of an input field will move the
00068 // cursor into the next field:
00069 // define it as 1 to prevent cursor movement from going to next field:
00070 //
00071 // Note: this has been replaced by Fl::option(Fl::OPTION_ARROW_FOCUS)
00072 // in FLTK 1.3.  This option has "inverted" values:
00073 //   1 = Arrow keys move focus (previously 0)
00074 //   0 = Arrow keys don't move focus (previously 1)
00075 // Hence we define ...
00076 //
00077 #define NORMAL_INPUT_MOVE (Fl::option(Fl::OPTION_ARROW_FOCUS) ? 0 : 1)
00078 
00079 #define ctrl(x) ((x)^0x40)
00080 
00081 // List of characters that are legal in a floating point input field.
00082 // This text string is created at run-time to take the current locale
00083 // into account (for example, continental Europe uses a comma instead
00084 // of a decimal point). For back compatibility reasons, we always 
00085 // allow the decimal point.
00086 #ifdef HAVE_LOCALECONV
00087 static const char *standard_fp_chars = ".eE+-"; 
00088 static const char *legal_fp_chars = 0L;
00089 #else
00090 static const char *legal_fp_chars = ".eE+-"; 
00091 #endif
00092 
00093 // Move cursor up specified #lines
00094 //    If OPTION_ARROW_FOCUS is disabled, return 1 to prevent focus navigation.
00095 //
00096 int Fl_Input::kf_lines_up(int repeat_num) {
00097   int i = position();
00098   if (!line_start(i)) {
00099     //UNNEEDED if (input_type()==FL_MULTILINE_INPUT && !Fl::option(Fl::OPTION_ARROW_FOCUS)) return 1;
00100     return NORMAL_INPUT_MOVE;
00101   }
00102   while(repeat_num--) {
00103     i = line_start(i);
00104     if (!i) break;
00105     i--;
00106   }
00107   shift_up_down_position(line_start(i));
00108   return 1;
00109 }
00110 
00111 // Move cursor down specified #lines
00112 //    If OPTION_ARROW_FOCUS is disabled, return 1 to prevent focus navigation.
00113 //
00114 int Fl_Input::kf_lines_down(int repeat_num) {
00115   int i = position();
00116   if (line_end(i) >= size()) {
00117     //UNNEEDED if (input_type()==FL_MULTILINE_INPUT && !Fl::option(Fl::OPTION_ARROW_FOCUS)) return 1;
00118     return NORMAL_INPUT_MOVE;
00119   }
00120   while (repeat_num--) {  
00121     i = line_end(i);
00122     if (i >= size()) break;
00123     i++;
00124   }
00125   shift_up_down_position(i);
00126   return 1;
00127 }
00128 
00129 // Move up a page
00130 int Fl_Input::kf_page_up() {
00131   return kf_lines_up(linesPerPage());
00132 }
00133 
00134 // Move down a page
00135 int Fl_Input::kf_page_down() {
00136   return kf_lines_down(linesPerPage());
00137 }
00138 
00139 // Toggle insert mode
00140 int Fl_Input::kf_insert_toggle() {
00141   if (readonly()) { fl_beep(); return 1; }
00142   return 1;                             // \todo: needs insert mode
00143 }
00144 
00145 // Delete word right
00146 int Fl_Input::kf_delete_word_right() {
00147   if (readonly()) { fl_beep(); return 1; }
00148   if (mark() != position()) return cut();
00149   cut(position(), word_end(position()));
00150   return 1;
00151 }
00152 
00153 // Delete word left
00154 int Fl_Input::kf_delete_word_left() {
00155   if (readonly()) { fl_beep(); return 1; }
00156   if (mark() != position()) return cut();
00157   cut(word_start(position()), position());
00158   return 1;
00159 }
00160 
00161 // Delete to start of line
00162 int Fl_Input::kf_delete_sol() {
00163   if (readonly()) { fl_beep(); return 1; }
00164   if (mark() != position()) return cut();
00165   cut(line_start(position()), position());
00166   return 1;
00167 }
00168 
00169 // Delete to end of line
00170 int Fl_Input::kf_delete_eol() {
00171   if (readonly()) { fl_beep(); return 1; }
00172   if (mark() != position()) return cut();
00173   cut(position(), line_end(position()));
00174   return 1;
00175 }
00176 
00177 int Fl_Input::kf_delete_char_right() {
00178   if (readonly()) { fl_beep(); return 1; }
00179   if (mark() != position()) return cut();
00180   else return cut(1);
00181 }
00182 
00183 int Fl_Input::kf_delete_char_left() {
00184   if (readonly()) { fl_beep(); return 1; }
00185   if (mark() != position()) cut();
00186   else cut(-1);
00187   return 1;
00188 }
00189 
00190 // Move cursor to start of line
00191 int Fl_Input::kf_move_sol() {
00192   return shift_position(line_start(position())) + NORMAL_INPUT_MOVE;
00193 }
00194 
00195 // Move cursor to end of line
00196 int Fl_Input::kf_move_eol() {
00197   return shift_position(line_end(position())) + NORMAL_INPUT_MOVE;
00198 }
00199 
00200 // Clear to end of line
00201 int Fl_Input::kf_clear_eol() {
00202   if (readonly()) { fl_beep(); return 1; }
00203   if (position()>=size()) return 0;
00204   int i = line_end(position());
00205   if (i == position() && i < size()) i++;
00206   cut(position(), i);
00207   return copy_cuts();
00208 }
00209 
00210 // Move cursor one character to the left
00211 //    If OPTION_ARROW_FOCUS is disabled, return 1 to prevent focus navigation.
00212 //
00213 int Fl_Input::kf_move_char_left() {
00214   int i = shift_position(position()-1) + NORMAL_INPUT_MOVE;
00215   return Fl::option(Fl::OPTION_ARROW_FOCUS) ? i : 1;
00216 }
00217 
00218 // Move cursor one character to the right
00219 //    If OPTION_ARROW_FOCUS is disabled, return 1 to prevent focus navigation.
00220 //
00221 int Fl_Input::kf_move_char_right() {
00222   int i = shift_position(position()+1) + NORMAL_INPUT_MOVE;
00223   return Fl::option(Fl::OPTION_ARROW_FOCUS) ? i : 1;
00224 }
00225 
00226 // Move cursor word-left
00227 int Fl_Input::kf_move_word_left() {
00228   shift_position(word_start(position()));
00229   return 1; 
00230 }
00231 
00232 // Move cursor word-right
00233 int Fl_Input::kf_move_word_right() {
00234   shift_position(word_end(position()));
00235   return 1;
00236 }
00237 
00238 // Move cursor up one line and to the start of line (paragraph up)
00239 int Fl_Input::kf_move_up_and_sol() {
00240   if (line_start(position())==position() && position()>0)
00241     return shift_position(line_start(position()-1)) + NORMAL_INPUT_MOVE;
00242   else
00243     return shift_position(line_start(position())) + NORMAL_INPUT_MOVE;
00244 }
00245 
00246 // Move cursor down one line and to the end of line (paragraph down)
00247 int Fl_Input::kf_move_down_and_eol() {
00248   if (line_end(position())==position() && position()<size())
00249     return shift_position(line_end(position()+1)) + NORMAL_INPUT_MOVE;
00250   else
00251     return shift_position(line_end(position())) + NORMAL_INPUT_MOVE;
00252 }
00253 
00254 // Move to top of document
00255 int Fl_Input::kf_top() {
00256   shift_position(0);
00257   return 1;
00258 }
00259 
00260 // Move to bottom of document
00261 int Fl_Input::kf_bottom() {
00262   shift_position(size());
00263   return 1; 
00264 }
00265 
00266 // Select all text in the widget
00267 int Fl_Input::kf_select_all() {
00268   position(0,size());
00269   return 1;
00270 }
00271 
00272 // Undo.
00273 int Fl_Input::kf_undo() {
00274   if (readonly()) { fl_beep(); return 1; }
00275   return undo();
00276 }
00277 
00278 // Redo. (currently unimplemented.. toggles undo() instead)
00279 int Fl_Input::kf_redo() {
00280   if (readonly()) { fl_beep(); return 1; }
00281   return kf_undo();                     // currently we don't support multilevel undo
00282 }
00283 
00284 // Do a copy operation
00285 int Fl_Input::kf_copy() {
00286   return copy(1);
00287 }
00288 
00289 // Do a paste operation
00290 int Fl_Input::kf_paste() {
00291   if (readonly()) { fl_beep(); return 1; }
00292   Fl::paste(*this, 1);
00293   return 1;
00294 }
00295 
00296 // Do a cut with copy
00297 int Fl_Input::kf_copy_cut() {
00298   if (readonly()) { fl_beep(); return 1; }
00299   copy(1);
00300   return cut();
00301 }
00302 
00303 // Handle a keystroke.
00304 //     Returns 1 if handled by us, 0 if not.
00305 //
00306 int Fl_Input::handle_key() {
00307   
00308   char ascii = Fl::event_text()[0];
00309   
00310   int del;
00311   if (Fl::compose(del)) {
00312     
00313     // Insert characters into numeric fields after checking for legality:
00314     if (input_type() == FL_FLOAT_INPUT || input_type() == FL_INT_INPUT) {
00315       Fl::compose_reset(); // ignore any foreign letters...
00316       
00317       // initialize the list of legal characters inside a floating point number
00318 #ifdef HAVE_LOCALECONV
00319       if (!legal_fp_chars) {
00320         int len = strlen(standard_fp_chars);
00321         struct lconv *lc = localeconv();
00322         if (lc) {
00323           if (lc->decimal_point) len += strlen(lc->decimal_point);
00324           if (lc->mon_decimal_point) len += strlen(lc->mon_decimal_point);
00325           if (lc->positive_sign) len += strlen(lc->positive_sign);
00326           if (lc->negative_sign) len += strlen(lc->negative_sign);
00327         }
00328         // the following line is not a true memory leak because the array is only
00329         // allocated once if required, and automatically freed when the program quits
00330         char *chars = (char*)malloc(len+1);
00331         legal_fp_chars = chars;
00332         strcpy(chars, standard_fp_chars);
00333         if (lc) {
00334           if (lc->decimal_point) strcat(chars, lc->decimal_point);
00335           if (lc->mon_decimal_point) strcat(chars, lc->mon_decimal_point);
00336           if (lc->positive_sign) strcat(chars, lc->positive_sign);
00337           if (lc->negative_sign) strcat(chars, lc->negative_sign);
00338         }
00339       }
00340 #endif // HAVE_LOCALECONV
00341       
00342       // find the insert position
00343       int ip = position()<mark() ? position() : mark();
00344       // This is complex to allow "0xff12" hex to be typed:
00345       if (   (!ip && (ascii == '+' || ascii == '-')) 
00346           || (ascii >= '0' && ascii <= '9') 
00347           || (ip==1 && index(0)=='0' && (ascii=='x' || ascii == 'X')) 
00348           || (ip>1 && index(0)=='0' && (index(1)=='x'||index(1)=='X') 
00349               && ((ascii>='A'&& ascii<='F') || (ascii>='a'&& ascii<='f'))) 
00350           || (input_type()==FL_FLOAT_INPUT && ascii && strchr(legal_fp_chars, ascii))) 
00351       {
00352         if (readonly()) fl_beep();
00353         else replace(position(), mark(), &ascii, 1);
00354       }
00355       return 1;
00356     }
00357     
00358     if (del || Fl::event_length()) {
00359       if (readonly()) fl_beep();
00360       else replace(position(), del ? position()-del : mark(),
00361                    Fl::event_text(), Fl::event_length());
00362     }
00363     return 1;
00364   }
00365   
00366   unsigned int mods = Fl::event_state() & (FL_META|FL_CTRL|FL_ALT);
00367   unsigned int shift = Fl::event_state() & FL_SHIFT;
00368   unsigned int multiline = (input_type() == FL_MULTILINE_INPUT) ? 1 : 0;
00369   //
00370   // The following lists apps that support these keypresses.
00371   // Prefixes: '!' indicates NOT supported, '?' indicates un-verified.
00372   //
00373   //    HIG=Human Interface Guide, 
00374   //    TE=TextEdit.app, SA=Safari.app, WOX=MS Word/OSX -- OSX 10.4.x
00375   //    NP=Notepad, WP=WordPad, WOW=MS Word/Windows     -- WinXP
00376   //    GE=gedit, KE=kedit                              -- Ubuntu8.04
00377   //    OF=old FLTK behavior (<=1.1.10)
00378   //
00379   // Example: (NP,WP,!WO) means supported in notepad + wordpad, but NOT word.
00380   //
00381   switch (Fl::event_key()) {
00382 
00383     case FL_Insert:
00384       // Note: Mac has no "Insert" key; it's the "Help" key.
00385       //       This keypress is apparently not possible on macs.
00386       //
00387       if (mods==0 && shift) return kf_paste();                  // Shift-Insert   (WP,NP,WOW,GE,KE,OF)
00388       if (mods==0)          return kf_insert_toggle();          // Insert         (Standard)
00389       if (mods==FL_CTRL)    return kf_copy();                   // Ctrl-Insert    (WP,NP,WOW,GE,KE,OF)
00390       return 0;                                                 // ignore other combos, pass to parent
00391 
00392     case FL_Delete: {
00393 #ifdef __APPLE__
00394       if (mods==0)          return kf_delete_char_right();      // Delete         (OSX-HIG,TE,SA,WOX)
00395       if (mods==FL_CTRL)    return kf_delete_char_right();      // Ctrl-Delete    (??? TE,!SA,!WOX)
00396       if (mods==FL_ALT)     return kf_delete_word_right();      // Alt-Delete     (OSX-HIG,TE,SA)
00397       return 0;                                                 // ignore other combos, pass to parent
00398 #else
00399       int selected = (position() != mark()) ? 1 : 0;
00400       if (mods==0 && shift && selected)
00401                             return kf_copy_cut();               // Shift-Delete with selection (WP,NP,WOW,GE,KE,OF)
00402       if (mods==0 && shift && !selected)
00403                             return kf_delete_char_right();      // Shift-Delete no selection (WP,NP,WOW,GE,KE,!OF)
00404       if (mods==0)          return kf_delete_char_right();      // Delete         (Standard)
00405       if (mods==FL_CTRL)    return kf_delete_word_right();      // Ctrl-Delete    (WP,!NP,WOW,GE,KE,!OF)
00406       return 0;                                                 // ignore other combos, pass to parent
00407 #endif
00408     }
00409 
00410     case FL_Left:
00411 #ifdef __APPLE__
00412       if (mods==0)          return kf_move_char_left();         // Left           (OSX-HIG)
00413       if (mods==FL_ALT)     return kf_move_word_left();         // Alt-Left       (OSX-HIG)
00414       if (mods==FL_META)    return kf_move_sol();               // Meta-Left      (OSX-HIG)
00415       if (mods==FL_CTRL)    return kf_move_sol();               // Ctrl-Left      (TE/SA)
00416       return 0;                                                 // ignore other combos, pass to parent
00417 #else
00418       if (mods==0)          return kf_move_char_left();         // Left           (WP,NP,WOW,GE,KE,OF)
00419       if (mods==FL_CTRL)    return kf_move_word_left();         // Ctrl-Left      (WP,NP,WOW,GE,KE,!OF)
00420       if (mods==FL_META)    return kf_move_char_left();         // Meta-Left      (WP,NP,?WOW,GE,KE)
00421       return 0;                                                 // ignore other combos, pass to parent
00422 #endif
00423 
00424     case FL_Right:
00425 #ifdef __APPLE__
00426       if (mods==0)          return kf_move_char_right();        // Right          (OSX-HIG)
00427       if (mods==FL_ALT)     return kf_move_word_right();        // Alt-Right      (OSX-HIG)
00428       if (mods==FL_META)    return kf_move_eol();               // Meta-Right     (OSX-HIG)
00429       if (mods==FL_CTRL)    return kf_move_eol();               // Ctrl-Right     (TE/SA)
00430       return 0;                                                 // ignore other combos, pass to parent
00431 #else
00432       if (mods==0)          return kf_move_char_right();        // Right          (WP,NP,WOW,GE,KE,OF)
00433       if (mods==FL_CTRL)    return kf_move_word_right();        // Ctrl-Right     (WP,NP,WOW,GE,KE,!OF)
00434       if (mods==FL_META)    return kf_move_char_right();        // Meta-Right     (WP,NP,?WOW,GE,KE,!OF)
00435       return 0;                                                 // ignore other combos, pass to parent
00436 #endif
00437 
00438     case FL_Up:
00439 #ifdef __APPLE__
00440       if (mods==0)          return kf_lines_up(1);              // Up             (OSX-HIG)
00441       if (mods==FL_CTRL)    return kf_page_up();                // Ctrl-Up        (TE !HIG)
00442       if (mods==FL_ALT)     return kf_move_up_and_sol();        // Alt-Up         (OSX-HIG)
00443       if (mods==FL_META)    return kf_top();                    // Meta-Up        (OSX-HIG)
00444       return 0;                                                 // ignore other combos, pass to parent
00445 #else
00446       if (mods==0)          return kf_lines_up(1);              // Up             (WP,NP,WOW,GE,KE,OF)
00447       if (mods==FL_CTRL)    return kf_move_up_and_sol();        // Ctrl-Up        (WP,!NP,WOW,GE,!KE,OF)
00448       return 0;                                                 // ignore other combos, pass to parent
00449 #endif
00450 
00451     case FL_Down:
00452 #ifdef __APPLE__
00453       if (mods==0)          return kf_lines_down(1);            // Dn             (OSX-HIG)
00454       if (mods==FL_CTRL)    return kf_page_down();              // Ctrl-Dn        (TE !HIG)
00455       if (mods==FL_ALT)     return kf_move_down_and_eol();      // Alt-Dn         (OSX-HIG)
00456       if (mods==FL_META)    return kf_bottom();                 // Meta-Dn        (OSX-HIG)
00457       return 0;                                                 // ignore other combos, pass to parent
00458 #else
00459       if (mods==0)          return kf_lines_down(1);            // Dn             (WP,NP,WOW,GE,KE,OF)
00460       if (mods==FL_CTRL)    return kf_move_down_and_eol();      // Ctrl-Down      (WP,!NP,WOW,GE,!KE,OF)
00461       return 0;                                                 // ignore other combos, pass to parent
00462 #endif
00463 
00464     case FL_Page_Up:
00465       // Fl_Input has no scroll control, so instead we move the cursor by one page
00466       // OSX-HIG recommends Alt increase one semantic unit, Meta next higher..
00467 #ifdef __APPLE__
00468       if (mods==0)          return kf_page_up();                // PgUp           (OSX-HIG)
00469       if (mods==FL_ALT)     return kf_page_up();                // Alt-PageUp     (OSX-HIG)
00470       if (mods==FL_META)    return kf_top();                    // Meta-PageUp    (OSX-HIG,!TE)
00471       return 0;                                                 // ignore other combos, pass to parent
00472 #else
00473       if (mods==0)          return kf_page_up();                // PageUp         (WP,NP,WOW,GE,KE)
00474       if (mods==FL_CTRL)    return kf_page_up();                // Ctrl-PageUp    (!WP,!NP,!WOW,!GE,KE,OF)
00475       if (mods==FL_ALT)     return kf_page_up();                // Alt-PageUp     (!WP,!NP,!WOW,!GE,KE,OF)
00476       return 0;                                                 // ignore other combos, pass to parent
00477 #endif
00478 
00479     case FL_Page_Down:
00480 #ifdef __APPLE__
00481       // Fl_Input has no scroll control, so instead we move the cursor by one page
00482       // OSX-HIG recommends Alt increase one semantic unit, Meta next higher..
00483       if (mods==0)          return kf_page_down();              // PgDn           (OSX-HIG)
00484       if (mods==FL_ALT)     return kf_page_down();              // Alt-PageDn     (OSX-HIG)
00485       if (mods==FL_META)    return kf_bottom();                 // Meta-PageDn    (OSX-HIG,!TE)
00486       return 0;                                                 // ignore other combos, pass to parent
00487 #else
00488       if (mods==0)          return kf_page_down();              // PageDn         (WP,NP,WOW,GE,KE)
00489       if (mods==FL_CTRL)    return kf_page_down();              // Ctrl-PageDn    (!WP,!NP,!WOW,!GE,KE,OF)
00490       if (mods==FL_ALT)     return kf_page_down();              // Alt-PageDn     (!WP,!NP,!WOW,!GE,KE,OF)
00491       return 0;                                                 // ignore other combos, pass to parent
00492 #endif
00493 
00494     case FL_Home:
00495 #ifdef __APPLE__
00496       if (mods==0)          return kf_top();                    // Home           (OSX-HIG)
00497       if (mods==FL_ALT)     return kf_top();                    // Alt-Home       (???)
00498       return 0;                                                 // ignore other combos, pass to parent
00499 #else
00500       if (mods==0)          return kf_move_sol();               // Home           (WP,NP,WOW,GE,KE,OF)
00501       if (mods==FL_CTRL)    return kf_top();                    // Ctrl-Home      (WP,NP,WOW,GE,KE,OF)
00502       return 0;                                                 // ignore other combos, pass to parent
00503 #endif
00504 
00505     case FL_End:
00506 #ifdef __APPLE__
00507       if (mods==0)          return kf_bottom();                 // End            (OSX-HIG)
00508       if (mods==FL_ALT)     return kf_bottom();                 // Alt-End        (???)
00509       return 0;                                                 // ignore other combos, pass to parent
00510 #else
00511       if (mods==0)          return kf_move_eol();               // End            (WP,NP,WOW,GE,KE,OF)
00512       if (mods==FL_CTRL)    return kf_bottom();                 // Ctrl-End       (WP,NP,WOW,GE,KE,OF)
00513       return 0;                                                 // ignore other combos, pass to parent
00514 #endif
00515 
00516     case FL_BackSpace:
00517 #ifdef __APPLE__
00518       if (mods==0)          return kf_delete_char_left();       // Backspace      (OSX-HIG)
00519       if (mods==FL_CTRL)    return kf_delete_char_left();       // Ctrl-Backspace (TE/SA)
00520       if (mods==FL_ALT)     return kf_delete_word_left();       // Alt-Backspace  (OSX-HIG)
00521       if (mods==FL_META)    return kf_delete_sol();             // Meta-Backspace (OSX-HIG,!TE)
00522       return 0;                                                 // ignore other combos, pass to parent
00523 #else
00524       if (mods==0)          return kf_delete_char_left();       // Backspace      (WP,NP,WOW,GE,KE,OF)
00525       if (mods==FL_CTRL)    return kf_delete_word_left();       // Ctrl-Backspace (WP,!NP,WOW,GE,KE,!OF)
00526       return 0;                                                 // ignore other combos, pass to parent
00527 #endif
00528 
00529     case FL_Enter:
00530     case FL_KP_Enter:
00531       if (when() & FL_WHEN_ENTER_KEY) {
00532         position(size(), 0);
00533         maybe_do_callback();
00534         return 1;
00535       } else if (multiline && !readonly()) {
00536         return replace(position(), mark(), "\n", 1);
00537       } return 0;                       // reserved for shortcuts
00538 
00539     case FL_Tab:
00540       // Handle special case for multiline input with 'old tab behavior';
00541       // tab handled as a normal insertable character.
00542       //
00543       if (mods==0 && !shift             // Tab?
00544            && !tab_nav()                // old tab behavior enabled?
00545            && multiline) {              // multiline input?
00546         break;                          // insert tab character
00547       }
00548       if (mods==0) return 0;                                    // Tab, Shift-Tab? nav focus      (Standard/OSX-HIG)
00549       return 0;                                                 // ignore other combos, pass to parent
00550 
00551     case 'a':
00552       if (mods==FL_COMMAND) return kf_select_all();             // Ctrl-A, Mac:Meta-A             (Standard/OSX-HIG)
00553       break;                                                    // handle other combos elsewhere
00554     case 'c':
00555       if (mods==FL_COMMAND) return kf_copy();                   // Ctrl-C, Mac:Meta-C             (Standard/OSX-HIG)
00556       break;                                                    // handle other combos elsewhere
00557     case 'v':
00558       if (mods==FL_COMMAND) return kf_paste();                  // Ctrl-V, Mac:Meta-V             (Standard/OSX-HIG)
00559       break;                                                    // handle other combos elsewhere
00560     case 'x':
00561       if (mods==FL_COMMAND) return kf_copy_cut();               // Ctrl-X, Mac:Meta-X             (Standard/OSX-HIG)
00562       break;
00563     case 'z':
00564       if (mods==FL_COMMAND && !shift) return kf_undo();         // Ctrl-Z, Mac:Meta-Z             (Standard/OSX-HIG)
00565       if (mods==FL_COMMAND && shift)  return kf_redo();         // Shift-Ctrl-Z, Mac:Shift-Meta-Z (Standard/OSX-HIG)
00566       break;                                                    // handle other combos elsewhere
00567   }
00568   
00569   switch (ascii) {
00570     case ctrl('H'):
00571       return kf_delete_char_left();                             // Ctrl-H                           (!WP,!NP,!WOW,!WOX,TE,SA,GE,KE,OF)
00572     case ctrl('I'):                                             // Ctrl-I (literal Tab)             (!WP,NP,!WOW,!GE,KE,OF)
00573     case ctrl('J'):                                             // Ctrl-J (literal Line Feed/Enter) (Standard)
00574     case ctrl('L'):                                             // Ctrl-L (literal Form Feed)       (Standard)
00575     case ctrl('M'):                                             // Ctrl-M (literal Cr)              (Standard)
00576       if (readonly()) { fl_beep(); return 1; }
00577       // insert a few selected control characters literally:
00578       if (input_type() != FL_FLOAT_INPUT && input_type() != FL_INT_INPUT)
00579         return replace(position(), mark(), &ascii, 1);
00580       break;
00581   }
00582   
00583   return 0;             // ignored
00584 }
00585 
00586 int Fl_Input::handle(int event) {
00587   static int dnd_save_position, dnd_save_mark, drag_start = -1, newpos;
00588   static Fl_Widget *dnd_save_focus;
00589   switch (event) {
00590     case FL_FOCUS:
00591       switch (Fl::event_key()) {
00592         case FL_Right:
00593           position(0);
00594           break;
00595         case FL_Left:
00596           position(size());
00597           break;
00598         case FL_Down:
00599           up_down_position(0);
00600           break;
00601         case FL_Up:
00602           up_down_position(line_start(size()));
00603           break;
00604         case FL_Tab:
00605           position(size(),0);
00606           break;
00607         default:
00608           position(position(),mark());// turns off the saved up/down arrow position
00609           break;
00610       }
00611       break;
00612       
00613     case FL_KEYBOARD:
00614       // Handle special case for multiline input with 'old tab behavior'
00615       // where tab is entered as a character: make sure user attempt to 'tab over'
00616       // widget doesn't destroy the field, replacing it with a tab character.
00617       //
00618       if (Fl::event_key() == FL_Tab                     // Tab key?
00619           && !Fl::event_state(FL_SHIFT)                 // no shift?
00620           && !tab_nav()                                 // with tab navigation disabled?
00621           && input_type() == FL_MULTILINE_INPUT         // with a multiline input?
00622           && (mark()==0 && position()==size())) {       // while entire field selected?
00623         // Set cursor to the end of the selection...
00624         if (mark() > position())
00625           position(mark());
00626         else
00627           position(position());
00628         return (1);
00629       } else {
00630         if (active_r() && window() && this == Fl::belowmouse()) 
00631           window()->cursor(FL_CURSOR_NONE);
00632         return handle_key();
00633       }
00634       //NOTREACHED
00635       
00636     case FL_PUSH:
00637       if (Fl::dnd_text_ops()) {
00638         int oldpos = position(), oldmark = mark();
00639         Fl_Boxtype b = box();
00640         Fl_Input_::handle_mouse(x()+Fl::box_dx(b), y()+Fl::box_dy(b),
00641                                 w()-Fl::box_dw(b), h()-Fl::box_dh(b), 0);
00642         newpos = position(); 
00643         position( oldpos, oldmark );
00644         if (Fl::focus()==this && !Fl::event_state(FL_SHIFT) && input_type()!=FL_SECRET_INPUT &&
00645            ( (newpos >= mark() && newpos < position()) || 
00646              (newpos >= position() && newpos < mark()) ) ) {
00647           // user clicked in the selection, may be trying to drag
00648           drag_start = newpos;
00649           return 1;
00650         }
00651         drag_start = -1;
00652       }
00653       
00654       if (Fl::focus() != this) {
00655         Fl::focus(this);
00656         handle(FL_FOCUS);
00657       }
00658       break;
00659       
00660     case FL_DRAG:
00661       if (Fl::dnd_text_ops()) {
00662         if (drag_start >= 0) {
00663           if (Fl::event_is_click()) return 1; // debounce the mouse
00664                                               // save the position because sometimes we don't get DND_ENTER:
00665           dnd_save_position = position();
00666           dnd_save_mark = mark();
00667           // drag the data:
00668           copy(0); Fl::dnd();
00669           return 1;
00670         }
00671       }
00672       break;
00673       
00674     case FL_RELEASE:
00675       if (Fl::event_button() == 2) {
00676         Fl::event_is_click(0); // stop double click from picking a word
00677         Fl::paste(*this, 0);
00678       } else if (!Fl::event_is_click()) {
00679         // copy drag-selected text to the clipboard.
00680         copy(0);
00681       } else if (Fl::event_is_click() && drag_start >= 0) {
00682         // user clicked in the field and wants to reset the cursor position...
00683         position(drag_start, drag_start);
00684         drag_start = -1;
00685       } else if (Fl::event_clicks()) {
00686         // user double or triple clicked to select word or whole text
00687         copy(0);
00688       }
00689       
00690       // For output widgets, do the callback so the app knows the user
00691       // did something with the mouse...
00692       if (readonly()) do_callback();
00693       
00694       return 1;
00695       
00696     case FL_DND_ENTER:
00697       Fl::belowmouse(this); // send the leave events first
00698       dnd_save_position = position();
00699       dnd_save_mark = mark();
00700       dnd_save_focus = Fl::focus();
00701       if (dnd_save_focus != this) {
00702         Fl::focus(this);
00703         handle(FL_FOCUS);
00704       }
00705       // fall through:
00706     case FL_DND_DRAG: 
00707       //int p = mouse_position(X, Y, W, H);
00708 #if DND_OUT_XXXX
00709       if (Fl::focus()==this && (p>=dnd_save_position && p<=dnd_save_mark ||
00710                                 p>=dnd_save_mark && p<=dnd_save_position)) {
00711         position(dnd_save_position, dnd_save_mark);
00712         return 0;
00713       }
00714 #endif
00715       {
00716         Fl_Boxtype b = box();
00717         Fl_Input_::handle_mouse(x()+Fl::box_dx(b), y()+Fl::box_dy(b),
00718                                 w()-Fl::box_dw(b), h()-Fl::box_dh(b), 0);
00719       }
00720       return 1;
00721       
00722     case FL_DND_LEAVE:
00723       position(dnd_save_position, dnd_save_mark);
00724 #if DND_OUT_XXXX
00725       if (!focused())
00726 #endif
00727         if (dnd_save_focus != this) {
00728           Fl::focus(dnd_save_focus);
00729           handle(FL_UNFOCUS);
00730         }
00731 #if !(defined(__APPLE__) || defined(WIN32))
00732       Fl::first_window()->cursor(FL_CURSOR_MOVE);
00733 #endif
00734       return 1;
00735       
00736     case FL_DND_RELEASE:
00737       take_focus();
00738       return 1;
00739       
00740       /* TODO: this will scroll the area, but stop if the cursor would become invisible.
00741        That clipping happens in drawtext(). Do we change the clipping or should 
00742        we move the cursor (ouch)?
00743        case FL_MOUSEWHEEL:
00744        if (Fl::e_dy > 0) {
00745        yscroll( yscroll() - Fl::e_dy*15 );
00746        } else if (Fl::e_dy < 0) {
00747        yscroll( yscroll() - Fl::e_dy*15 );
00748        }
00749        return 1;
00750        */
00751   }
00752   Fl_Boxtype b = box();
00753   return Fl_Input_::handletext(event,
00754                                x()+Fl::box_dx(b), y()+Fl::box_dy(b),
00755                                w()-Fl::box_dw(b), h()-Fl::box_dh(b));
00756 }
00757 
00762 Fl_Input::Fl_Input(int X, int Y, int W, int H, const char *l)
00763 : Fl_Input_(X, Y, W, H, l) {
00764 }
00765 
00766 //
00767 // End of "$Id: Fl_Input.cxx 8115 2010-12-27 00:16:57Z greg.ercolano $".
00768 //