source: rtems-graphics-toolkit/fltk-1.1.10/src/Fl_Input.cxx @ 513eea1

Last change on this file since 513eea1 was 513eea1, checked in by Joel Sherrill <joel.sherrill@…>, on 01/09/10 at 22:43:24

2010-01-08 Joel Sherrill <joel.sherrill@…>

fltk 1.1.10. imported

  • ORIGIN: Updated.
  • Property mode set to 100644
File size: 13.3 KB
Line 
1//
2// "$Id$"
3//
4// Input widget for the Fast Light Tool Kit (FLTK).
5//
6// Copyright 1998-2006 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#ifdef HAVE_LOCALE_H
44# include <locale.h>
45#endif
46
47
48void Fl_Input::draw() {
49  if (input_type() == FL_HIDDEN_INPUT) return;
50  Fl_Boxtype b = box();
51  if (damage() & FL_DAMAGE_ALL) draw_box(b, color());
52  Fl_Input_::drawtext(x()+Fl::box_dx(b), y()+Fl::box_dy(b),
53                      w()-Fl::box_dw(b), h()-Fl::box_dh(b));
54}
55
56// kludge so shift causes selection to extend:
57int Fl_Input::shift_position(int p) {
58  return position(p, Fl::event_state(FL_SHIFT) ? mark() : p);
59}
60int Fl_Input::shift_up_down_position(int p) {
61  return up_down_position(p, Fl::event_state(FL_SHIFT));
62}
63
64// If you define this symbol as zero you will get the peculiar fltk
65// behavior where moving off the end of an input field will move the
66// cursor into the next field:
67// define it as 1 to prevent cursor movement from going to next field:
68#define NORMAL_INPUT_MOVE 0
69
70#define ctrl(x) ((x)^0x40)
71
72// List of characters that are legal in a floating point input field.
73// This text string is created at run-time to take the current locale
74// into account (for example, continental Europe uses a comma instead
75// of a decimal point). For back compatibility reasons, we always
76// allow the decimal point.
77#ifdef HAVE_LOCALECONV
78static const char *standard_fp_chars = ".eE+-";
79static const char *legal_fp_chars = 0L;
80#else
81static const char *legal_fp_chars = ".eE+-";
82#endif
83
84int Fl_Input::handle_key() {
85
86  char ascii = Fl::event_text()[0];
87
88  int repeat_num=1;
89
90  int del;
91  if (Fl::compose(del)) {
92
93    // Insert characters into numeric fields after checking for legality:
94    if (input_type() == FL_FLOAT_INPUT || input_type() == FL_INT_INPUT) {
95      Fl::compose_reset(); // ignore any foreign letters...
96
97      // initialize the list of legal characters inside a floating point number
98#ifdef HAVE_LOCALECONV
99      if (!legal_fp_chars) {
100        int len = strlen(standard_fp_chars);
101        struct lconv *lc = localeconv();
102        if (lc) {
103          if (lc->decimal_point) len += strlen(lc->decimal_point);
104          if (lc->mon_decimal_point) len += strlen(lc->mon_decimal_point);
105          if (lc->positive_sign) len += strlen(lc->positive_sign);
106          if (lc->negative_sign) len += strlen(lc->negative_sign);
107        }
108        // the following line is not a true memory leak because the array is only
109        // allocated once if required, and automatically freed when the program quits
110        char *chars = (char*)malloc(len+1);
111        legal_fp_chars = chars;
112        strcpy(chars, standard_fp_chars);
113        if (lc) {
114          if (lc->decimal_point) strcat(chars, lc->decimal_point);
115          if (lc->mon_decimal_point) strcat(chars, lc->mon_decimal_point);
116          if (lc->positive_sign) strcat(chars, lc->positive_sign);
117          if (lc->negative_sign) strcat(chars, lc->negative_sign);
118        }
119      }
120#endif // HAVE_LOCALECONV
121
122      // find the insert position
123      int ip = position()<mark() ? position() : mark();
124      // This is complex to allow "0xff12" hex to be typed:
125      if (!ip && (ascii == '+' || ascii == '-')
126          || (ascii >= '0' && ascii <= '9')
127          || (ip==1 && index(0)=='0' && (ascii=='x' || ascii == 'X'))
128          || (ip>1 && index(0)=='0' && (index(1)=='x'||index(1)=='X')
129             && (ascii>='A'&& ascii<='F' || ascii>='a'&& ascii<='f'))
130          || input_type()==FL_FLOAT_INPUT && ascii && strchr(legal_fp_chars, ascii))
131      {
132        if (readonly()) fl_beep();
133        else replace(position(), mark(), &ascii, 1);
134      }
135      return 1;
136    }
137
138    if (del || Fl::event_length()) {
139      if (readonly()) fl_beep();
140      else replace(position(), del ? position()-del : mark(),
141                   Fl::event_text(), Fl::event_length());
142    }
143    return 1;
144  }
145
146  switch (Fl::event_key()) {
147  case FL_Insert:
148    if (Fl::event_state() & FL_CTRL) ascii = ctrl('C');
149    else if (Fl::event_state() & FL_SHIFT) ascii = ctrl('V');
150    break;
151  case FL_Delete:
152    if (Fl::event_state() & FL_SHIFT) ascii = ctrl('X');
153    else ascii = ctrl('D');
154    break;   
155  case FL_Left:
156    ascii = ctrl('B'); break;
157  case FL_Right:
158    ascii = ctrl('F'); break;
159  case FL_Page_Up:
160    fl_font(textfont(),textsize()); //ensure current font is set to ours
161    repeat_num=h()/fl_height(); // number of lines to scroll
162    if (!repeat_num) repeat_num=1;
163  case FL_Up:
164    ascii = ctrl('P'); break;
165  case FL_Page_Down:
166    fl_font(textfont(),textsize());
167    repeat_num=h()/fl_height();
168    if (!repeat_num) repeat_num=1;
169  case FL_Down:
170    ascii = ctrl('N'); break;
171  case FL_Home:
172    if (Fl::event_state() & FL_CTRL) {
173      shift_position(0);
174      return 1;
175    }
176    ascii = ctrl('A');
177    break;
178  case FL_End:
179    if (Fl::event_state() & FL_CTRL) {
180      shift_position(size());
181      return 1;
182    }
183    ascii = ctrl('E'); break;
184   
185  case FL_BackSpace:
186    ascii = ctrl('H'); break;
187  case FL_Enter:
188  case FL_KP_Enter:
189    if (when() & FL_WHEN_ENTER_KEY) {
190      position(size(), 0);
191      maybe_do_callback();
192      return 1;
193    } else if (input_type() == FL_MULTILINE_INPUT && !readonly())
194      return replace(position(), mark(), "\n", 1);
195    else
196      return 0; // reserved for shortcuts
197  case FL_Tab:
198    if (Fl::event_state(FL_CTRL|FL_SHIFT) || input_type()!=FL_MULTILINE_INPUT || readonly()) return 0;
199    return replace(position(), mark(), &ascii, 1);
200#ifdef __APPLE__
201  case 'c' :
202  case 'v' :
203  case 'x' :
204  case 'z' :
205//    printf("'%c' (0x%02x) pressed with%s%s%s%s\n", ascii, ascii,
206//           Fl::event_state(FL_SHIFT) ? " FL_SHIFT" : "",
207//           Fl::event_state(FL_CTRL) ? " FL_CTRL" : "",
208//           Fl::event_state(FL_ALT) ? " FL_ALT" : "",
209//           Fl::event_state(FL_META) ? " FL_META" : "");
210    if (Fl::event_state(FL_META)) ascii -= 0x60;
211//    printf("using '%c' (0x%02x)...\n", ascii, ascii);
212    break;
213#endif // __APPLE__
214  }
215
216  int i;
217  switch (ascii) {
218  case ctrl('A'):
219    return shift_position(line_start(position())) + NORMAL_INPUT_MOVE;
220  case ctrl('B'):
221    return shift_position(position()-1) + NORMAL_INPUT_MOVE;
222  case ctrl('C'): // copy
223    return copy(1);
224  case ctrl('D'):
225  case ctrl('?'):
226    if (readonly()) {
227      fl_beep();
228      return 1;
229    }
230    if (mark() != position()) return cut();
231    else return cut(1);
232  case ctrl('E'):
233    return shift_position(line_end(position())) + NORMAL_INPUT_MOVE;
234  case ctrl('F'):
235    return shift_position(position()+1) + NORMAL_INPUT_MOVE;
236  case ctrl('H'):
237    if (readonly()) {
238      fl_beep();
239      return 1;
240    }
241    if (mark() != position()) cut();
242    else cut(-1);
243    return 1;
244  case ctrl('K'):
245    if (readonly()) {
246      fl_beep();
247      return 1;
248    }
249    if (position()>=size()) return 0;
250    i = line_end(position());
251    if (i == position() && i < size()) i++;
252    cut(position(), i);
253    return copy_cuts();
254  case ctrl('N'):
255    i = position();
256    if (line_end(i) >= size()) return NORMAL_INPUT_MOVE;
257    while (repeat_num--) { 
258      i = line_end(i);
259      if (i >= size()) break;
260      i++;
261    }
262    shift_up_down_position(i);
263    return 1;
264  case ctrl('P'):
265    i = position();
266    if (!line_start(i)) return NORMAL_INPUT_MOVE;
267    while(repeat_num--) {
268      i = line_start(i);
269      if (!i) break;
270      i--;
271    }
272    shift_up_down_position(line_start(i));
273    return 1;
274  case ctrl('U'):
275    if (readonly()) {
276      fl_beep();
277      return 1;
278    }
279    return cut(0, size());
280  case ctrl('V'):
281  case ctrl('Y'):
282    if (readonly()) {
283      fl_beep();
284      return 1;
285    }
286    Fl::paste(*this, 1);
287    return 1;
288  case ctrl('X'):
289  case ctrl('W'):
290    if (readonly()) {
291      fl_beep();
292      return 1;
293    }
294    copy(1);
295    return cut();
296  case ctrl('Z'):
297  case ctrl('_'):
298    if (readonly()) {
299      fl_beep();
300      return 1;
301    }
302    return undo();
303  case ctrl('I'):
304  case ctrl('J'):
305  case ctrl('L'):
306  case ctrl('M'):
307    if (readonly()) {
308      fl_beep();
309      return 1;
310    }
311    // insert a few selected control characters literally:
312    if (input_type() != FL_FLOAT_INPUT && input_type() != FL_INT_INPUT)
313      return replace(position(), mark(), &ascii, 1);
314  }
315
316  return 0;
317}
318
319int Fl_Input::handle(int event) {
320  static int dnd_save_position, dnd_save_mark, drag_start = -1, newpos;
321  static Fl_Widget *dnd_save_focus;
322  switch (event) {
323  case FL_FOCUS:
324    switch (Fl::event_key()) {
325    case FL_Right:
326      position(0);
327      break;
328    case FL_Left:
329      position(size());
330      break;
331    case FL_Down:
332      up_down_position(0);
333      break;
334    case FL_Up:
335      up_down_position(line_start(size()));
336      break;
337    case FL_Tab:
338    case 0xfe20: // XK_ISO_Left_Tab
339      position(size(),0);
340      break;
341    default:
342      position(position(),mark());// turns off the saved up/down arrow position
343      break;
344    }
345    break;
346
347  case FL_KEYBOARD:
348    if (Fl::event_key() == FL_Tab && mark() != position()) {
349      // Set the current cursor position to the end of the selection...
350      if (mark() > position())
351        position(mark());
352      else
353        position(position());
354      return (1);
355    } else {
356      if (active_r() && window() && this == Fl::belowmouse())
357        window()->cursor(FL_CURSOR_NONE);
358      return handle_key();
359    }
360
361  case FL_PUSH:
362    if (Fl::dnd_text_ops()) {
363      int oldpos = position(), oldmark = mark();
364      Fl_Boxtype b = box();
365      Fl_Input_::handle_mouse(
366        x()+Fl::box_dx(b), y()+Fl::box_dy(b),
367        w()-Fl::box_dw(b), h()-Fl::box_dh(b), 0);
368      newpos = position();
369      position( oldpos, oldmark );
370      if (Fl::focus()==this && !Fl::event_state(FL_SHIFT) && input_type()!=FL_SECRET_INPUT &&
371          (newpos >= mark() && newpos < position() ||
372          newpos >= position() && newpos < mark())) {
373        // user clicked in the selection, may be trying to drag
374        drag_start = newpos;
375        return 1;
376      }
377      drag_start = -1;
378    }
379
380    if (Fl::focus() != this) {
381      Fl::focus(this);
382      handle(FL_FOCUS);
383    }
384    break;
385
386  case FL_DRAG:
387    if (Fl::dnd_text_ops()) {
388      if (drag_start >= 0) {
389        if (Fl::event_is_click()) return 1; // debounce the mouse
390        // save the position because sometimes we don't get DND_ENTER:
391        dnd_save_position = position();
392        dnd_save_mark = mark();
393        // drag the data:
394        copy(0); Fl::dnd();
395        return 1;
396      }
397    }
398    break;
399
400  case FL_RELEASE:
401    if (Fl::event_button() == 2) {
402      Fl::event_is_click(0); // stop double click from picking a word
403      Fl::paste(*this, 0);
404    } else if (!Fl::event_is_click()) {
405      // copy drag-selected text to the clipboard.
406      copy(0);
407    } else if (Fl::event_is_click() && drag_start >= 0) {
408      // user clicked in the field and wants to reset the cursor position...
409      position(drag_start, drag_start);
410      drag_start = -1;
411    } else if (Fl::event_clicks()) {
412      // user double or triple clicked to select word or whole text
413      copy(0);
414    }
415
416    // For output widgets, do the callback so the app knows the user
417    // did something with the mouse...
418    if (readonly()) do_callback();
419
420    return 1;
421
422  case FL_DND_ENTER:
423    Fl::belowmouse(this); // send the leave events first
424    dnd_save_position = position();
425    dnd_save_mark = mark();
426    dnd_save_focus = Fl::focus();
427    if (dnd_save_focus != this) {
428      Fl::focus(this);
429      handle(FL_FOCUS);
430    }
431    // fall through:
432  case FL_DND_DRAG:
433    //int p = mouse_position(X, Y, W, H);
434#if DND_OUT_XXXX
435    if (Fl::focus()==this && (p>=dnd_save_position && p<=dnd_save_mark ||
436                      p>=dnd_save_mark && p<=dnd_save_position)) {
437      position(dnd_save_position, dnd_save_mark);
438      return 0;
439    }
440#endif
441    {
442      Fl_Boxtype b = box();
443      Fl_Input_::handle_mouse(
444        x()+Fl::box_dx(b), y()+Fl::box_dy(b),
445        w()-Fl::box_dw(b), h()-Fl::box_dh(b), 0);
446    }
447    return 1;
448
449  case FL_DND_LEAVE:
450    position(dnd_save_position, dnd_save_mark);
451#if DND_OUT_XXXX
452    if (!focused())
453#endif
454    if (dnd_save_focus != this) {
455      Fl::focus(dnd_save_focus);
456      handle(FL_UNFOCUS);
457    }
458    return 1;
459
460  case FL_DND_RELEASE:
461    take_focus();
462    return 1;
463
464  }
465  Fl_Boxtype b = box();
466  return Fl_Input_::handletext(event,
467        x()+Fl::box_dx(b), y()+Fl::box_dy(b),
468        w()-Fl::box_dw(b), h()-Fl::box_dh(b));
469}
470
471Fl_Input::Fl_Input(int X, int Y, int W, int H, const char *l)
472: Fl_Input_(X, Y, W, H, l) {
473}
474
475//
476// End of "$Id$".
477//
Note: See TracBrowser for help on using the repository browser.