diff options
| -rw-r--r-- | CHANGES | 2 | ||||
| -rw-r--r-- | FL/Fl_Input_.H | 32 | ||||
| -rw-r--r-- | src/Fl_Input_.cxx | 60 |
3 files changed, 70 insertions, 24 deletions
@@ -1,6 +1,8 @@ CHANGES IN FLTK 1.3.1 + - Fixed Fl_Input_::maximum_size() documentation and replace() method + to honor maximum_size() as number of allowed characters (STR #2747). - Fixed a potential crash if Fl_Double_Window::flush() was called before show() - Fixed regression (in FLTK 1.3.0) that could clear a radio diff --git a/FL/Fl_Input_.H b/FL/Fl_Input_.H index e537342ad..457b98a2e 100644 --- a/FL/Fl_Input_.H +++ b/FL/Fl_Input_.H @@ -3,7 +3,7 @@ // // Input base class header file for the Fast Light Tool Kit (FLTK). // -// Copyright 1998-2010 by Bill Spitzak and others. +// Copyright 1998-2011 by Bill Spitzak and others. // // This library is free software. Distribution and use rights are outlined in // the file "COPYING" which should have been included with this file. If this @@ -69,9 +69,10 @@ \endcode All variables that represent an index into a text buffer are byte-oriented, - not character oriented. Since UTF-8 characters can be up to six bytes long, - simply incrementing such an index will not reliably advance to the next character - in the text buffer. + not character oriented, counting from 0 (at or before the first character) + to size() (at the end of the buffer, after the last byte). Since UTF-8 + characters can be up to six bytes long, simply incrementing such an index + will not reliably advance to the next character in the text buffer. Indices and pointers into the text buffer should always point at a 7 bit ASCII character or the beginning of a UTF-8 character sequence. Behavior for false @@ -123,7 +124,7 @@ class FL_EXPORT Fl_Input_ : public Fl_Widget { of the buffer. */ int mu_p; - /** \internal Maximum size of buffer. \todo Is this really needed? */ + /** \internal Maximum number of characters. */ int maximum_size_; /** \internal Shortcut key that will fetch focus for this widget. */ @@ -260,16 +261,21 @@ public: \see Fl_Widget::size(int, int) */ void size(int W, int H) { Fl_Widget::size(W, H); } - /** Gets the maximum length of the input field. - \todo It is not clear if this function is actually required */ + /** Gets the maximum length of the input field in characters. + \see maximum_size(int). */ int maximum_size() const {return maximum_size_;} - /** Sets the maximum length of the input field. - \todo It is not clear if this function is actually required */ + /** Sets the maximum length of the input field in characters. + This limits the number of <b>characters</b> that can be inserted + in the widget. + \since FLTK 1.3 this is different than the buffer size, since one + character can be more than one byte in UTF-8 encoding. In FLTK 1.1 + this was the same (one byte = one character). + */ void maximum_size(int m) {maximum_size_ = m;} /** Gets the position of the text cursor. - \return the cursor position as an index + \return the cursor position as an index in the range 0..size() \see position(int, int) */ int position() const {return position_;} @@ -281,7 +287,7 @@ public: /* Sets the index for the cursor and mark. */ int position(int p, int m); - /** Set the cursor position and mark. + /** Sets the cursor position and mark. position(n) is the same as <tt>position(n, n)</tt>. \param p new index for cursor and mark \return 0 if no positions changed @@ -296,8 +302,8 @@ public: \see position(), position(int, int) */ int mark(int m) {return position(position(), m);} - /* Deletes text from b to e and inserts the new string text. */ - int replace(int, int, const char*, int=0); + /* Deletes text from \p b to \p e and inserts the new string \p text. */ + int replace(int b, int e, const char *text, int ilen=0); /** Deletes the current selection. diff --git a/src/Fl_Input_.cxx b/src/Fl_Input_.cxx index eea14b838..003d2db4b 100644 --- a/src/Fl_Input_.cxx +++ b/src/Fl_Input_.cxx @@ -3,7 +3,7 @@ // // Common input widget routines for the Fast Light Tool Kit (FLTK). // -// Copyright 1998-2010 by Bill Spitzak and others. +// Copyright 1998-2011 by Bill Spitzak and others. // // This library is free software. Distribution and use rights are outlined in // the file "COPYING" which should have been included with this file. If this @@ -719,9 +719,9 @@ static void undobuffersize(int n) { Deletes text from \p b to \p e and inserts the new string \p text. All changes to the text buffer go through this function. - It deletes the region between \p a and \p b (either one may be less or + It deletes the region between \p b and \p e (either one may be less or equal to the other), and then inserts the string \p text - at that point and moves the mark() and + at that point and moves the mark() and position() to the end of the insertion. Does the callback if <tt>when() & FL_WHEN_CHANGED</tt> and there is a change. @@ -731,11 +731,23 @@ static void undobuffersize(int n) { \p ilen can be zero or <tt>strlen(text)</tt>, which saves a tiny bit of time if you happen to already know the length of the insertion, or can be used to insert a portion of a - string. - - \p b and \p e are clamped to the - <tt>0..size()</tt> range, so it is safe to pass any values. - + string. If \p ilen is zero, <tt>strlen(text)</tt> is used instead. + + \p b and \p e are clamped to the <tt>0..size()</tt> range, so it is + safe to pass any values. \p b, \p e, and \p ilen are used as numbers + of bytes (not characters), where \p b and \p e count from 0 to + size() (end of buffer). + + If \p b and/or \p e don't point to a valid UTF-8 character boundary, + they are adjusted to the previous (\p b) or the next (\p e) valid + UTF-8 character boundary, resp.. + + If the current number of characters in the buffer minus deleted + characters plus inserted characters in \p text would overflow the + number of allowed characters (maximum_size()), then only the first + characters of the string are inserted, so that maximum_size() + is not exceeded. + cut() and insert() are just inline functions that call replace(). \param [in] b beginning index of text to be deleted @@ -743,6 +755,10 @@ static void undobuffersize(int n) { \param [in] text string that will be inserted \param [in] ilen length of \p text or 0 for \c nul terminated strings \return 0 if nothing changed + + \note If \p text does not point to a valid UTF-8 character or includes + invalid UTF-8 sequences, the text is inserted nevertheless (counting + invalid UTF-8 bytes as one character each). */ int Fl_Input_::replace(int b, int e, const char* text, int ilen) { int ul, om, op; @@ -762,10 +778,32 @@ int Fl_Input_::replace(int b, int e, const char* text, int ilen) { } if (text && !ilen) ilen = strlen(text); if (e<=b && !ilen) return 0; // don't clobber undo for a null operation - if (size_+ilen-(e-b) > maximum_size_) { - ilen = maximum_size_-size_+(e-b); - if (ilen < 0) ilen = 0; + + // we must count UTF-8 *characters* to determine whether we can insert + // the full text or only a part of it (and how much this would be) + + int nchars = 0; // characters in value() - deleted + inserted + const char *p = value_; + while (p < (char *)(value_+size_)) { + if (p == (char *)(value_+b)) { // skip removed part + p = (char *)(value_+e); + if (p >= (char *)(value_+size_)) break; + } + int ulen = fl_utf8len(*p); + if (ulen < 1) ulen = 1; // invalid UTF-8 character: count as 1 + nchars++; + p += ulen; + } + int nlen = 0; // length (in bytes) to be inserted + p = text; + while (p < (char *)(text+ilen) && nchars < maximum_size()) { + int ulen = fl_utf8len(*p); + if (ulen < 1) ulen = 1; // invalid UTF-8 character: count as 1 + nchars++; + p += ulen; + nlen += ulen; } + ilen = nlen; put_in_buffer(size_+ilen); |
