Fixes to WORDWRAP modification to Fl_Input based on work done by

Alexander Rabi Beels.  This will not affect things much because WORDWRAP
is normally disabled.  However it fixes a few bugs with word+line selection
and with up/down arrows working when there are tabs or control characters
in the text.  I modified his patches so no changes are needed to the
header files to enable wordwrap and so that very long words scroll
horizontally rather than break between letters.


git-svn-id: file:///fltk/svn/fltk/branches/branch-1.0@1223 ea41ed52-d2ee-0310-a9c1-e6b18d33e121
This commit is contained in:
Bill Spitzak 2000-06-20 07:56:09 +00:00
parent f7e4caec25
commit 823b1f8460
3 changed files with 117 additions and 68 deletions

View File

@ -1,5 +1,5 @@
// //
// "$Id: Fl_Input_.H,v 1.6.2.2 2000/06/05 21:20:24 mike Exp $" // "$Id: Fl_Input_.H,v 1.6.2.3 2000/06/20 07:56:06 bill Exp $"
// //
// Input base class header file for the Fast Light Tool Kit (FLTK). // Input base class header file for the Fast Light Tool Kit (FLTK).
// //
@ -66,8 +66,10 @@ class Fl_Input_ : public Fl_Widget {
protected: protected:
FL_EXPORT int wordboundary(int i) const; FL_EXPORT int word_start(int i) const;
FL_EXPORT int lineboundary(int i) const; FL_EXPORT int word_end(int i) const;
FL_EXPORT int line_start(int i) const;
FL_EXPORT int line_end(int i) const;
FL_EXPORT void drawtext(int, int, int, int); FL_EXPORT void drawtext(int, int, int, int);
FL_EXPORT int up_down_position(int, int keepmark=0); FL_EXPORT int up_down_position(int, int keepmark=0);
FL_EXPORT void handle_mouse(int, int, int, int, int keepmark=0); FL_EXPORT void handle_mouse(int, int, int, int, int keepmark=0);
@ -120,5 +122,5 @@ public:
#endif #endif
// //
// End of "$Id: Fl_Input_.H,v 1.6.2.2 2000/06/05 21:20:24 mike Exp $". // End of "$Id: Fl_Input_.H,v 1.6.2.3 2000/06/20 07:56:06 bill Exp $".
// //

View File

@ -1,5 +1,5 @@
// //
// "$Id: Fl_Input.cxx,v 1.10.2.11 2000/06/10 21:31:00 bill Exp $" // "$Id: Fl_Input.cxx,v 1.10.2.12 2000/06/20 07:56:08 bill Exp $"
// //
// Input widget for the Fast Light Tool Kit (FLTK). // Input widget for the Fast Light Tool Kit (FLTK).
// //
@ -119,11 +119,7 @@ int Fl_Input::handle_key() {
int i; int i;
switch (ascii) { switch (ascii) {
case ctrl('A'): case ctrl('A'):
if (type() == FL_MULTILINE_INPUT) return shift_position(line_start(position())) + NORMAL_INPUT_MOVE;
for (i=position(); i && index(i-1)!='\n'; i--) ;
else
i = 0;
return shift_position(i) + NORMAL_INPUT_MOVE;
case ctrl('B'): case ctrl('B'):
return shift_position(position()-1) + NORMAL_INPUT_MOVE; return shift_position(position()-1) + NORMAL_INPUT_MOVE;
case ctrl('C'): // copy case ctrl('C'): // copy
@ -133,11 +129,7 @@ int Fl_Input::handle_key() {
if (mark() != position()) return cut(); if (mark() != position()) return cut();
else return cut(1); else return cut(1);
case ctrl('E'): case ctrl('E'):
if (type() == FL_MULTILINE_INPUT) return shift_position(line_end(position())) + NORMAL_INPUT_MOVE;
for (i=position(); index(i) && index(i)!='\n'; i++) ;
else
i = size();
return shift_position(i) + NORMAL_INPUT_MOVE;
case ctrl('F'): case ctrl('F'):
return shift_position(position()+1) + NORMAL_INPUT_MOVE; return shift_position(position()+1) + NORMAL_INPUT_MOVE;
case ctrl('H'): case ctrl('H'):
@ -146,26 +138,19 @@ int Fl_Input::handle_key() {
return 1; return 1;
case ctrl('K'): case ctrl('K'):
if (position()>=size()) return 0; if (position()>=size()) return 0;
if (type() == FL_MULTILINE_INPUT) { i = line_end(position());
if (index(position()) == '\n') if (i == position() && i < size()) i++;
i = position() + 1;
else
for (i=position()+1; index(i) && index(i) != '\n'; i++);
} else
i = size();
cut(position(), i); cut(position(), i);
return copy_cuts(); return copy_cuts();
case ctrl('N'): case ctrl('N'):
if (type()!=FL_MULTILINE_INPUT) return 0; i = line_end(position());
for (i=position(); index(i)!='\n'; i++) if (i >= size()) return NORMAL_INPUT_MOVE;
if (!index(i)) return NORMAL_INPUT_MOVE;
shift_up_down_position(i+1); shift_up_down_position(i+1);
return 1; return 1;
case ctrl('P'): case ctrl('P'):
if (type()!=FL_MULTILINE_INPUT) return 0; i = line_start(position());
for (i = position(); i > 0 && index(i-1) != '\n'; i--) ;
if (!i) return NORMAL_INPUT_MOVE; if (!i) return NORMAL_INPUT_MOVE;
shift_up_down_position(i-1); shift_up_down_position(line_start(i-1));
return 1; return 1;
case ctrl('U'): case ctrl('U'):
return cut(0, size()); return cut(0, size());
@ -208,7 +193,7 @@ int Fl_Input::handle(int event) {
up_down_position(0); up_down_position(0);
break; break;
case FL_Up: case FL_Up:
up_down_position(size()); up_down_position(line_start(size()));
break; break;
case FL_Tab: case FL_Tab:
case 0xfe20: // XK_ISO_Left_Tab case 0xfe20: // XK_ISO_Left_Tab
@ -259,5 +244,5 @@ Fl_Input::Fl_Input(int x, int y, int w, int h, const char *l)
} }
// //
// End of "$Id: Fl_Input.cxx,v 1.10.2.11 2000/06/10 21:31:00 bill Exp $". // End of "$Id: Fl_Input.cxx,v 1.10.2.12 2000/06/20 07:56:08 bill Exp $".
// //

View File

@ -1,5 +1,5 @@
// //
// "$Id: Fl_Input_.cxx,v 1.21.2.7 2000/06/08 07:38:29 bill Exp $" // "$Id: Fl_Input_.cxx,v 1.21.2.8 2000/06/20 07:56:09 bill Exp $"
// //
// Common input widget routines for the Fast Light Tool Kit (FLTK). // Common input widget routines for the Fast Light Tool Kit (FLTK).
// //
@ -40,10 +40,8 @@
//////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////
// Wordwrap kludge. It "sort of" works but there are lots of bugs. // Wordwrap kludge. This works ok but is commented out because
// Really the whole multi-line-input should be moved to a seperate // we want to move multi-line functionality to it's own subclass.
// (and much more complex) subclass. Single-line and multi-line
// input are really a *lot* different!
// To try the wordwrap define this: // To try the wordwrap define this:
//#define WORDWRAP //#define WORDWRAP
#ifdef WORDWRAP #ifdef WORDWRAP
@ -60,17 +58,19 @@ const char* Fl_Input_::expand(const char* p, char* buf) const {
const char* lastspace = p; const char* lastspace = p;
char* lastspace_out = o; char* lastspace_out = o;
int width_to_lastspace = 0; int width_to_lastspace = 0;
int word_count = 0;
#endif #endif
if (type()==FL_SECRET_INPUT) { if (type()==FL_SECRET_INPUT) {
while (o<e && p < value_+size_) {*o++ = '*'; p++;} while (o<e && p < value_+size_) {*o++ = '*'; p++;}
} else while (o<e) { } else while (o<e) {
#ifdef WORDWRAP #ifdef WORDWRAP
if (wordwrap && (p >= value_+size_ || *p==' ' || *p=='\n')) { if (wordwrap && (p >= value_+size_ || isspace(*p))) {
width_to_lastspace += fl_width(lastspace, p-lastspace); width_to_lastspace += (int)fl_width(lastspace_out, o-lastspace_out);
if (p > lastspace+1) { if (p > lastspace+1) {
if (width_to_lastspace > wordwrap) { if (word_count && width_to_lastspace > wordwrap) {
p = lastspace; o = lastspace_out; break; p = lastspace; o = lastspace_out; break;
} }
word_count++;
} }
lastspace = p; lastspace = p;
lastspace_out = o; lastspace_out = o;
@ -216,8 +216,7 @@ void Fl_Input_::drawtext(int X, int Y, int W, int H) {
} }
lines++; lines++;
if (e >= value_+size_) break; if (e >= value_+size_) break;
if (*e == '\n' || *e == ' ') e++; p = e+1;
p = e;
} }
// adjust the scrolling: // adjust the scrolling:
@ -296,8 +295,7 @@ void Fl_Input_::drawtext(int X, int Y, int W, int H) {
CONTINUE: CONTINUE:
ypos += height; ypos += height;
if (e >= value_+size_) break; if (e >= value_+size_) break;
if (*e == '\n' || *e == ' ') e++; p = e+1;
p = e;
} }
// for minimal update, erase all lines below last one if necessary: // for minimal update, erase all lines below last one if necessary:
@ -315,15 +313,59 @@ static int isword(char c) {
return (c&128 || isalnum(c) || strchr("#%&-/@\\_~", c)); return (c&128 || isalnum(c) || strchr("#%&-/@\\_~", c));
} }
int Fl_Input_::wordboundary(int i) const { int Fl_Input_::word_end(int i) const {
if (i<=0 || i>=size()) return 1; if (type() == FL_SECRET_INPUT) return size();
return isword(index(i-1)) != isword(index(i)); //while (i < size() && !isword(index(i))) i++;
while (i < size() && isword(index(i))) i++;
return i;
} }
int Fl_Input_::lineboundary(int i) const { int Fl_Input_::word_start(int i) const {
if (i<=0 || i>=size()) return 1; if (type() == FL_SECRET_INPUT) return 0;
// if (i >= size() || !isword(index(i)))
// while (i > 0 && !isword(index(i-1))) i--;
while (i > 0 && isword(index(i-1))) i--;
return i;
}
int Fl_Input_::line_end(int i) const {
if (type() != FL_MULTILINE_INPUT) return size();
#ifdef WORDWRAP
// go to the start of the paragraph:
int j = i;
while (j > 0 && index(j-1) != '\n') j--;
// now measure lines until we get past i, end of that line is real eol:
wordwrap = w()-Fl::box_dw(box())-6;
setfont();
for (const char* p=value()+j; ;) {
char buf[MAXBUF];
p = expand(p, buf);
if (p-value() >= i) return p-value();
p++;
}
#else
while (i < size() && index(i) != '\n') i++;
return i;
#endif
}
int Fl_Input_::line_start(int i) const {
if (type() != FL_MULTILINE_INPUT) return 0; if (type() != FL_MULTILINE_INPUT) return 0;
return index(i-1) == '\n' || index(i) == '\n'; int j = i;
while (j > 0 && index(j-1) != '\n') j--;
#ifdef WORDWRAP
// now measure lines until we get past i, start of that line is real eol:
wordwrap = w()-Fl::box_dw(box())-6;
setfont();
for (const char* p=value()+j; ;) {
char buf[MAXBUF];
const char* e = expand(p, buf);
if (e-value() >= i) return p-value();
p = e+1;
}
#else
return j;
#endif
} }
void Fl_Input_::handle_mouse(int X, int Y, void Fl_Input_::handle_mouse(int X, int Y,
@ -350,9 +392,8 @@ void Fl_Input_::handle_mouse(int X, int Y,
for (p=value();; ) { for (p=value();; ) {
e = expand(p, buf); e = expand(p, buf);
theline--; if (theline < 0) break; theline--; if (theline < 0) break;
if (*e == '\n' || *e == ' ') e++;
p = e;
if (e >= value_+size_) break; if (e >= value_+size_) break;
p = e+1;
} }
const char *l, *r, *t; double f0 = Fl::event_x()-X+xscroll_; const char *l, *r, *t; double f0 = Fl::event_x()-X+xscroll_;
for (l = p, r = e; l<r; ) { for (l = p, r = e; l<r; ) {
@ -375,18 +416,20 @@ void Fl_Input_::handle_mouse(int X, int Y,
if (newpos < size()) newpos++; if (newpos < size()) newpos++;
else newmark--; else newmark--;
} }
if (Fl::event_clicks()>1 || type()==FL_SECRET_INPUT) { if (Fl::event_clicks() > 1) {
while (!lineboundary(newpos)) newpos++; newpos = line_end(newpos);
while (!lineboundary(newmark)) newmark--; newmark = line_start(newmark);
} else { } else {
while (!wordboundary(newpos)) newpos++; newpos = word_end(newpos);
while (!wordboundary(newmark)) newmark--; newmark = word_start(newmark);
} }
} else { } else {
if (Fl::event_clicks()>1 || type()==FL_SECRET_INPUT) { if (Fl::event_clicks() > 1) {
while (!lineboundary(newpos)) newpos--; newpos = line_start(newpos);
newmark = line_end(newmark);
} else { } else {
while (!wordboundary(newpos)) newpos--; newpos = word_start(newpos);
newmark = word_end(newmark);
} }
} }
// if the multiple click does not increase the selection, revert // if the multiple click does not increase the selection, revert
@ -429,16 +472,25 @@ int Fl_Input_::position(int p, int m) {
} }
int Fl_Input_::up_down_position(int i, int keepmark) { int Fl_Input_::up_down_position(int i, int keepmark) {
while (i > 0 && index(i-1) != '\n') i--; // go to start of line // unlike before, i must be at the start of the line already!
double oldwid = 0.0;
setfont(); setfont();
while (index(i) && index(i)!='\n') { #ifdef WORDWRAP
double tt = oldwid + fl_width(index(i)); if (type()==FL_MULTILINE_INPUT)
if ((oldwid+tt)/2 >= up_down_pos) break; wordwrap = w()-Fl::box_dw(box())-6;
oldwid = tt; else wordwrap = 0;
i++; #endif
char buf[MAXBUF];
const char* p = value()+i;
const char* e = expand(p, buf);
const char *l, *r, *t;
for (l = p, r = e; l<r; ) {
t = l+(r-l+1)/2;
int f = (int)expandpos(p, t, buf, 0);
if (f <= up_down_pos) l = t; else r = t-1;
} }
int j = position(i, keepmark ? mark_ : i); int j = l-value();
j = position(j, keepmark ? mark_ : j);
was_up_down = 1; was_up_down = 1;
return j; return j;
} }
@ -536,6 +588,16 @@ int Fl_Input_::replace(int b, int e, const char* text, int ilen) {
undowidget = this; undowidget = this;
mark_ = position_ = undoat = b+ilen; mark_ = position_ = undoat = b+ilen;
#ifdef WORDWRAP
// Insertions into the word at the end of the line will cause it to
// wrap to the next line, so we must indicate that the changes may start
// right after the whitespace before the current word. This will
// result in sub-optimal update when such wrapping does not happen
// but it is too hard to figure out for now...
if (type() == FL_MULTILINE_INPUT)
while (b > 0 && !isspace(index(b))) b--;
#endif
minimal_update(b); minimal_update(b);
if (when()&FL_WHEN_CHANGED) do_callback(); else set_changed(); if (when()&FL_WHEN_CHANGED) do_callback(); else set_changed();
return 1; return 1;
@ -638,7 +700,7 @@ int Fl_Input_::handletext(int event, int X, int Y, int W, int H) {
// strip trailing control characters and spaces before pasting: // strip trailing control characters and spaces before pasting:
const char* t = Fl::event_text(); const char* t = Fl::event_text();
const char* e = t+Fl::event_length(); const char* e = t+Fl::event_length();
if (type()!=FL_MULTILINE_INPUT) while (e > t && *(uchar*)(e-1) <= ' ') e--; if (type() != FL_MULTILINE_INPUT) while (e > t && isspace(*(e-1))) e--;
return replace(position(), mark(), t, e-t);} return replace(position(), mark(), t, e-t);}
default: default:
@ -747,5 +809,5 @@ Fl_Input_::~Fl_Input_() {
} }
// //
// End of "$Id: Fl_Input_.cxx,v 1.21.2.7 2000/06/08 07:38:29 bill Exp $". // End of "$Id: Fl_Input_.cxx,v 1.21.2.8 2000/06/20 07:56:09 bill Exp $".
// //