Fix confusing behavior of class Fl_Text_Selection.

Fl_Text_Selection got a new method length() and returns 0 in length()
and in all offsets (start(), end(), position()) if no text is selected
(selected() == false).

The behavior in FLTK 1.3 and earlier versions (returning undefined
values if !selected()) was confusing.


git-svn-id: file:///fltk/svn/fltk/branches/branch-1.4@12356 ea41ed52-d2ee-0310-a9c1-e6b18d33e121
This commit is contained in:
Albrecht Schlosser 2017-07-26 12:32:13 +00:00
parent 4c999258f1
commit 6b24b20966
3 changed files with 141 additions and 60 deletions

View File

@ -18,6 +18,10 @@ Changes in FLTK 1.4.0 Released: ??? ?? 2017
New Features and Extensions New Features and Extensions
- (add new items here) - (add new items here)
- Fl_Text_Selection got a new method length() and returns 0 in length()
and in all offsets (start(), end(), position()) if no text is selected
(selected() == false). The behavior in FLTK 1.3 and earlier versions
(returning undefined values if !selected()) was confusing.
- Added support for MacOS 10.13 "High Sierra". - Added support for MacOS 10.13 "High Sierra".
- New method Fl_Group::bounds() replaces Fl_Group::sizes() which is now - New method Fl_Group::bounds() replaces Fl_Group::sizes() which is now
deprecated. Fl_Group::bounds() uses the new class Fl_Rect that contains deprecated. Fl_Group::bounds() uses the new class Fl_Rect that contains

View File

@ -3,7 +3,7 @@
// //
// Header file for Fl_Text_Buffer class. // Header file for Fl_Text_Buffer class.
// //
// Copyright 2001-2016 by Bill Spitzak and others. // Copyright 2001-2017 by Bill Spitzak and others.
// Original code Copyright Mark Edel. Permission to distribute under // Original code Copyright Mark Edel. Permission to distribute under
// the LGPL for the FLTK library granted by Mark Edel. // the LGPL for the FLTK library granted by Mark Edel.
// //
@ -61,71 +61,108 @@
/** /**
\class Fl_Text_Selection \class Fl_Text_Selection
\brief This is an internal class for Fl_Text_Buffer to manage text selections. \brief This is an internal class for Fl_Text_Buffer to manage text selections.
This class works correctly with UTF-8 strings assuming that the parameters
for all calls are on character boundaries. All methods use byte (not UTF-8 character) offsets and start at 0. This
*/ class works correctly with UTF-8 strings assuming that the parameters
for all calls are on character boundaries.
If the selection is inactive (not currently used), then selected()
returns \p false and start() and end() return 0 (zero).
The stored offsets are in ascending order, hence the following conditions
are true (pseudo code):
\code
if ( !selected() ) : (start() == 0) && (end() == 0) && (start() == end())
if ( selected() ) : start() < end()
always : 0 <= start() <= end()
always : length() == end() - start()
\endcode
The selection size in bytes can always (unconditionally) be computed by
\code
int size = sel->end() - sel->start();
\endcode
\see length()
\note
The \b protected member variables \p mStart and \p mEnd are not
necessarily 0 (zero) if mSelected == \p false because they are
not cleared when \p selected(false) is called (as of Jul 2017).
This may be changed in the future.
*/
class FL_EXPORT Fl_Text_Selection { class FL_EXPORT Fl_Text_Selection {
friend class Fl_Text_Buffer; friend class Fl_Text_Buffer;
public: public:
/** // Sets the selection range and selected().
\brief Set the selection range. void set(int startpos, int endpos);
\param start byte offset to first selected character
\param end byte offset pointing after last selected character
*/
void set(int start, int end);
/** // Updates a selection after text was modified.
\brief Updates a selection after text was modified.
Updates an individual selection for changes in the corresponding text
\param pos byte offset into text buffer at which the change occurred
\param nDeleted number of bytes deleted from the buffer
\param nInserted number of bytes inserted into the buffer
*/
void update(int pos, int nDeleted, int nInserted); void update(int pos, int nDeleted, int nInserted);
/** /**
\brief Return the byte offset to the first selected character. \brief Returns the byte offset to the first selected character.
\return byte offset
*/ The returned offset is only valid if selected() returns true.
int start() const { return mStart; } If the selection is not valid the returned offset is 0 since FLTK 1.4.0.
\note In FLTK 1.3.x the returned offset could be non-zero even if
selected() would have returned 0.
\return byte offset or 0 if not selected.
*/
int start() const { return mSelected ? mStart : 0; }
/** /**
\brief Return the byte offset to the character after the last selected character. \brief Returns the byte offset to the character after the last selected character.
\return byte offset
*/ The returned offset is only valid if selected() returns true (non-zero).
int end() const { return mEnd; } The offset is 0 if no text is selected (since FLTK 1.4.0).
\note In FLTK 1.3.x the returned offset could be non-zero even if
selected() would have returned 0.
\return byte offset or 0 if not selected.
*/
int end() const { return mSelected ? mEnd : 0; }
/** /**
\brief Returns true if any text is selected. \brief Returns true if any text is selected.
\return a non-zero number if any text has been selected, or 0 \return \p true if any text has been selected, or \p false
if no text is selected. if no text is selected.
*/ */
bool selected() const { return mSelected; } bool selected() const { return mSelected; }
/** /**
\brief Modify the 'selected' flag. \brief Modifies the 'selected' flag.
\param b new flag \param b new flag
*/ */
void selected(bool b) { mSelected = b; } void selected(bool b) { mSelected = b; }
/** /**
Return true if position \p pos with indentation \p dispIndex is in \brief Returns the size in bytes of the selection.
the Fl_Text_Selection.
*/ This is a convenience method. It always returns the same as
\code
end() - start()
\endcode
and it returns 0 if selected() == false.
\return size in bytes or 0 if not selected.
\since FLTK 1.4.0
*/
int length() const { return mSelected ? mEnd - mStart : 0; }
// Returns true if position \p pos is in this Fl_Text_Selection.
int includes(int pos) const; int includes(int pos) const;
/** // Returns true if selected() and the positions of this selection.
\brief Return the positions of this selection. int position(int *startpos, int *endpos) const;
\param start return byte offset to first selected character
\param end return byte offset pointing after last selected character
\return true if selected
*/
int position(int* start, int* end) const;
protected: protected:

View File

@ -1,7 +1,7 @@
// //
// "$Id$" // "$Id$"
// //
// Copyright 2001-2016 by Bill Spitzak and others. // Copyright 2001-2017 by Bill Spitzak and others.
// Original code Copyright Mark Edel. Permission to distribute under // Original code Copyright Mark Edel. Permission to distribute under
// the LGPL for the FLTK library granted by Mark Edel. // the LGPL for the FLTK library granted by Mark Edel.
// //
@ -1214,36 +1214,66 @@ void Fl_Text_Buffer::remove_(int start, int end)
} }
/* /**
simple setter. \brief Sets the selection range.
Unicode safe. Start and end must be at a character boundary.
*/ \p startpos and \p endpos must be at a character boundary.
If \p startpos != \p endpos selected() is set to true, else to false.
If \p startpos is greater than \p endpos they are swapped so that
\p startpos \<= \p endpos.
\param[in] startpos byte offset to first selected character
\param[in] endpos byte offset pointing after last selected character
*/
void Fl_Text_Selection::set(int startpos, int endpos) void Fl_Text_Selection::set(int startpos, int endpos)
{ {
mSelected = startpos != endpos; mSelected = (startpos != endpos);
mStart = min(startpos, endpos); mStart = min(startpos, endpos);
mEnd = max(startpos, endpos); mEnd = max(startpos, endpos);
} }
/* /**
simple getter. \brief Returns the status and the positions of this selection.
Unicode safe. Start and end will be at a character boundary.
*/ This method returns the same as \p selected() as an \p int (0 or 1)
in its return value and the offsets to the start of the selection
in \p startpos and to the byte after the last selected character
in \p endpos, if selected() is \p true.
If selected() is \p false, both offsets are set to 0.
\note In FLTK 1.3.x \p startpos and \p endpos were \b not \b modified
if selected() was false.
\param startpos return byte offset to first selected character
\param endpos return byte offset pointing after last selected character
\return whether the selection is active (selected()) or not
\retval 0 if not selected
\retval 1 if selected
\see selected(), start(), end()
*/
int Fl_Text_Selection::position(int *startpos, int *endpos) const { int Fl_Text_Selection::position(int *startpos, int *endpos) const {
if (!mSelected) if (!mSelected) {
*startpos = 0;
*endpos = 0;
return 0; return 0;
}
*startpos = mStart; *startpos = mStart;
*endpos = mEnd; *endpos = mEnd;
return 1; return 1;
} }
/* /**
Return if a position is inside the selected area. Returns true if position \p pos is in the Fl_Text_Selection.
Unicode safe. Pos must be at a character boundary.
*/ \p pos must be at a character boundary.
*/
int Fl_Text_Selection::includes(int pos) const { int Fl_Text_Selection::includes(int pos) const {
return (selected() && pos >= start() && pos < end() ); return (selected() && pos >= start() && pos < end() );
} }
@ -1447,7 +1477,17 @@ void Fl_Text_Buffer::update_selections(int pos, int nDeleted,
} }
/**
\brief Updates a selection after text was modified.
Updates an individual selection for changes in the corresponding text.
\param pos byte offset into text buffer at which the change occurred
\param nDeleted number of bytes deleted from the buffer
\param nInserted number of bytes inserted into the buffer
*/
// unicode safe, assuming the arguments are on character boundaries // unicode safe, assuming the arguments are on character boundaries
void Fl_Text_Selection::update(int pos, int nDeleted, int nInserted) void Fl_Text_Selection::update(int pos, int nDeleted, int nInserted)
{ {
if (!mSelected || pos > mEnd) if (!mSelected || pos > mEnd)