Thank you for your work in this string handling problem . But I am urgen with 
my application. So I did'nt want to wait the final version of UTF8. I had spend 
several days, modified the Fl_Input_.cxx and Fl_Input.cxx  in 1.1.9 to adapt to 
chinese character process. What I do indeed is add a condition in existing 
code, when encounter a char greater than 0x80 try to interpret it as an 2 byte 
chinese character. It involve line sliting, inserting, deleting ,selecting, 
cursor moving etc. Now it seems good to me (I did'nt test exhausit).

the following is code, for your evaluation:
==============Fl_Input_.cxx==================================
//
// "$Id: Fl_Input_.cxx 6104 2008-04-21 20:54:37Z matt $"
//
// Common input widget routines for the Fast Light Tool Kit (FLTK).
//
// Copyright 1998-2006 by Bill Spitzak and others.
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Library General Public
// License as published by the Free Software Foundation; either
// version 2 of the License, or (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
// Library General Public License for more details.
//
// You should have received a copy of the GNU Library General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
// USA.
//
// Please report all bugs and problems on the following page:
//
//     http://www.fltk.org/str.php
//

// This is the base class for Fl_Input.  You can use it directly
// if you are one of those people who like to define their own
// set of editing keys.  It may also be useful for adding scrollbars
// to the input field.

#include <FL/Fl.H>
#include <FL/Fl_Input_.H>
#include <FL/Fl_Window.H>
#include <FL/fl_draw.H>
#include <FL/fl_ask.H>
#include <math.h>
#include "flstring.h"
#include <stdlib.h>
#include <ctype.h>

#define MAXBUF 1024

extern void fl_draw(const char*, int, float, float);

////////////////////////////////////////////////////////////////

// Copy string p..e to the buffer, replacing characters with ^X and \nnn
// as necessary.  Truncate if necessary so the resulting string and
// null terminator fits in a buffer of size n.  Return new end pointer.
const char* Fl_Input_::expand(const char* p, char* buf) const {
  char* o = buf;
  char* e = buf+(MAXBUF-4);
  const char* lastspace = p;
  char* lastspace_out = o;
  int width_to_lastspace = 0;
  int word_count = 0;
  int word_wrap;

  //comment by chenqg: remember start of p;
  const char* start = p;
  for(char *wipe=o;wipe<e;wipe++) *wipe=0;


  /* comment by chenqg
        p for values string,  buf for display string.  if input type is secret 
,i.e. password, display string will be mask by star
  */
  if (input_type()==FL_SECRET_INPUT) {
    while (o<e && p < value_+size_) {*o++ = '*'; p++;}  // comment by chenqg: 
mask buf by star
  }
  else while (o<e) { //expand string from p to buf

    if (wrap() && (p >= value_+size_ || isspace(*p & 255) || (*p & 128))) 
//comment by chenqg: if input set to wrap mode and now a word is exceed width 
,need to be wrap ,  further more , if it is a chinese character ,it also need 
to be wrap treated like 2 bytes width word
        {
                word_wrap = w() - Fl::box_dw(box()) - 2;   //comment by chenqg: 
 input's width sub box frame width and 2
                //width_to_lastspace += (int)fl_width(lastspace_out, 
o-lastspace_out); //comment by chenqg:   calculate  in display string, the word 
width in pixel
                width_to_lastspace = (int)fl_width(buf, o-buf);
                if (p > lastspace+1) {
                        if (word_count && width_to_lastspace > word_wrap) {
                                p = lastspace; o = lastspace_out; break;
                        }
                        word_count++;
                }
                if ((*p & 128) ){//comment by chenqg:  remember the last space 
position    in string p and buf
                        int tmp;
                        tmp = p-start;
                        chineseCharRePositionLeast(start,tmp);
                        if(start+tmp < p){//comment by chenqg:  if current p is 
second byte of a chinese char
                                lastspace = p-2;
                                lastspace_out = o-2;
                        }
                        else{//comment by chenqg:  if current p is fisrt byte 
of a chinese char
                                lastspace = p-1;
                                lastspace_out = o-1;
                        }
                }
                else{
                        lastspace = p;
                        lastspace_out = o;
                }
    }

    if (p >= value_+size_) break;  // comment by chenqg:   provent out of range

    int c = *p++ & 255;
    if (c < ' ' || c == 127) {
            if (c=='\n' && input_type()==FL_MULTILINE_INPUT) {p--; break;}
            if (c == '\t' && input_type()==FL_MULTILINE_INPUT) {
                                for (c = (o-buf)%8; c<8 && o<e; c++) *o++ = ' 
';  // comment by chenqg:  replace \t with space to tab column
            }
                else { // comment by chenqg:   replace control charactor with ^
                        *o++ = '^';
                        *o++ = c ^ 0x40;
                }
#ifdef __APPLE__
    // In MacRoman, all characters are defined, and non-break-space is 0xca
    } else if (c == 0xCA) { // nbsp
      *o++ = ' ';
#else
    // in ISO 8859-1, undefined characters are rendered as octal
    // this is commented out since most X11 seems to use MSWindows Latin-1
    //} else if (c >= 128 && c < 0xA0) {
      // these codes are not defined in ISO code, so we output the octal code 
instead
    //  *o++ = '\\';
    //  *o++ = ((c>>6)&0x03) + '0';
    //  *o++ = ((c>>3)&0x07) + '0';
    //  *o++ = (c&0x07) + '0';
    } else if (c == 0xA0) { // nbsp
      *o++ = ' ';
#endif
    } else {
      *o++ = c;
    }
  }
  //*o=0;   comment by chenqg: the last o maybe a chinese char, cannot replace 
by 0;
  if (o[0] &128)  o[1] = 0;
  else o[0] = 0;

  return p;
}

// After filling in such a buffer, find the width to e
double Fl_Input_::expandpos(
  const char* p,        // real string
  const char* e,        // pointer into real string
  const char* buf,      // conversion of real string by expand()
  int* returnn          // return offset into buf here
) const {
  int n = 0;
  if (input_type()==FL_SECRET_INPUT) n = e-p;
  else while (p<e) {
    int c = *p++ & 255;
    if (c < ' ' || c == 127) {
      if (c == '\t' && input_type()==FL_MULTILINE_INPUT) n += 8-(n%8);
      else n += 2;
#ifdef __APPLE__
    // in MacRoman, all characters are defined
#else
    // in Windows Latin-1 all characters are defined
    //} else if (c >= 128 && c < 0xA0) {
      // these codes are not defined in ISO code, so we output the octal code 
instead
    //  n += 4;
#endif
    } else {
      n++;
    }
  }
  if (returnn) *returnn = n;
  return fl_width(buf, n);
}

////////////////////////////////////////////////////////////////

// minimal update:
// Characters from mu_p to end of widget are redrawn.
// If erase_cursor_only, small part at mu_p is redrawn.
// Right now minimal update just keeps unchanged characters from
// being erased, so they don't blink.

void Fl_Input_::minimal_update(int p) {
  if (damage() & FL_DAMAGE_ALL) return; // don't waste time if it won't be done
  if (damage() & FL_DAMAGE_EXPOSE) {
    if (p < mu_p) mu_p = p;
  } else {
    mu_p = p;
  }

  damage(FL_DAMAGE_EXPOSE);
  erase_cursor_only = 0;
}

void Fl_Input_::minimal_update(int p, int q) {
  if (q < p) p = q;
  minimal_update(p);
}

////////////////////////////////////////////////////////////////

static double up_down_pos;
static int was_up_down;

void Fl_Input_::setfont() const {
 fl_font(textfont(), textsize());
}

void Fl_Input_::drawtext(int X, int Y, int W, int H) {
  int do_mu = !(damage()&FL_DAMAGE_ALL);

  if (Fl::focus()!=this && !size()) {
    if (do_mu) { // we have to erase it if cursor was there
      draw_box(box(), X-Fl::box_dx(box()), Y-Fl::box_dy(box()),
               W+Fl::box_dw(box()), H+Fl::box_dh(box()), color());
    }
    return;
  }

  int selstart, selend;
  if (Fl::focus()!=this && /*Fl::selection_owner()!=this &&*/ 
Fl::pushed()!=this)
    selstart = selend = 0;
  else if (position() <= mark()) {
    selstart = position(); selend = mark();
  } else {
    selend = position(); selstart = mark();
  }

  setfont();
  const char *p, *e;
  char buf[MAXBUF];

  // count how many lines and put the last one into the buffer:
  // And figure out where the cursor is:
  int height = fl_height();
  int lines;
  int curx, cury;
  for (p=value(), curx=cury=lines=0; ;) {
    e = expand(p, buf);
        if (position() >= p-value() && position() <= e-value()) {
      curx = int(expandpos(p, value()+position(), buf, 0)+.5);
      if (Fl::focus()==this && !was_up_down) up_down_pos = curx;
      cury = lines*height;
      int newscroll = xscroll_;
      if (curx > newscroll+W-20) {
        // figure out scrolling so there is space after the cursor:
        newscroll = curx+20-W;
        // figure out the furthest left we ever want to scroll:
        int ex = int(expandpos(p, e, buf, 0))+2-W;
        // use minimum of both amounts:
        if (ex < newscroll) newscroll = ex;
      } else if (curx < newscroll+20) {
        newscroll = curx-20;
      }
      if (newscroll < 0) newscroll = 0;
      if (newscroll != xscroll_) {
        xscroll_ = newscroll;
        mu_p = 0; erase_cursor_only = 0;
      }
    }
    lines++;
    if (e >= value_+size_) break;
    p = e+1;
  }

  // adjust the scrolling:
  if (input_type()==FL_MULTILINE_INPUT) {
    int newy = yscroll_;
    if (cury < newy) newy = cury;
    if (cury > newy+H-height) newy = cury-H+height;
    if (newy < -1) newy = -1;
    if (newy != yscroll_) {yscroll_ = newy; mu_p = 0; erase_cursor_only = 0;}
  } else {
    yscroll_ = -(H-height)/2;
  }

  fl_clip(X, Y, W, H);
  Fl_Color tc = active_r() ? textcolor() : fl_inactive(textcolor());

  p = value();
  // visit each line and draw it:
  int desc = height-fl_descent();
  float xpos = (float)(X - xscroll_ + 1);
  int ypos = -yscroll_;
  for (; ypos < H;) {

    // re-expand line unless it is the last one calculated above:
    if (lines>1) e = expand(p, buf);

    if (ypos <= -height) goto CONTINUE; // clipped off top

    if (do_mu) {        // for minimal update:
      const char* pp = value()+mu_p; // pointer to where minimal update starts
      if (e < pp) goto CONTINUE2; // this line is before the changes
      if (readonly()) erase_cursor_only = 0; // this isn't the most efficient 
way
      if (erase_cursor_only && p > pp) goto CONTINUE2; // this line is after
      // calculate area to erase:
      float r = (float)(X+W);
      float xx;
      if (p >= pp) {
        xx = (float)X;
        if (erase_cursor_only) r = xpos+2;
        else if (readonly()) xx -= 3;
      } else {
        xx = xpos + (float)expandpos(p, pp, buf, 0);
        if (erase_cursor_only) r = xx+2;
        else if (readonly()) xx -= 3;
      }
      // clip to and erase it:
      fl_push_clip((int)xx-1-height/8, Y+ypos, (int)(r-xx+2+height/4), height);
      draw_box(box(), X-Fl::box_dx(box()), Y-Fl::box_dy(box()),
               W+Fl::box_dw(box()), H+Fl::box_dh(box()), color());
      // it now draws entire line over it
      // this should not draw letters to left of erased area, but
      // that is nyi.
    }

    // Draw selection area if required:
    if (selstart < selend && selstart <= e-value() && selend > p-value()) {
      const char* pp = value()+selstart;
      float x1 = xpos;
      int offset1 = 0;
      if (pp > p) {
        fl_color(tc);
        x1 += (float)expandpos(p, pp, buf, &offset1);
        fl_draw(buf, offset1, xpos, (float)(Y+ypos+desc));
      }
      pp = value()+selend;
      float x2 = (float)(X+W);
      int offset2;
      if (pp <= e) x2 = xpos + (float)expandpos(p, pp, buf, &offset2);
      else offset2 = strlen(buf);
      fl_color(selection_color());
      fl_rectf((int)(x1+0.5), Y+ypos, (int)(x2-x1+0.5), height);
      fl_color(fl_contrast(textcolor(), selection_color()));
      fl_draw(buf+offset1, offset2-offset1, x1, (float)(Y+ypos+desc));
      if (pp < e) {
        fl_color(tc);
        fl_draw(buf+offset2, strlen(buf+offset2), x2, (float)(Y+ypos+desc));
      }
    } else {
      // draw unselected text
      fl_color(tc);
      fl_draw(buf, strlen(buf), xpos, (float)(Y+ypos+desc));
    }

    if (do_mu) fl_pop_clip();

  CONTINUE2:
    // draw the cursor:
    if (Fl::focus() == this && selstart == selend &&
        position() >= p-value() && position() <= e-value()) {
      fl_color(cursor_color());
      if (readonly()) {
        fl_line((int)(xpos+curx-2.5f), Y+ypos+height-1,
                (int)(xpos+curx+0.5f), Y+ypos+height-4,
                (int)(xpos+curx+3.5f), Y+ypos+height-1);
      } else {
        fl_rectf((int)(xpos+curx+0.5), Y+ypos, 2, height);
      }
    }

  CONTINUE:
    ypos += height;
    if (e >= value_+size_) break;
//    if (*e == '\n' || *e == ' ') e++;
//    p = e;
        p =e+1;
  }

  // for minimal update, erase all lines below last one if necessary:
  if (input_type()==FL_MULTILINE_INPUT && do_mu && ypos<H
      && (!erase_cursor_only || p <= value()+mu_p)) {
    if (ypos < 0) ypos = 0;
    fl_push_clip(X, Y+ypos, W, H-ypos);
    draw_box(box(), X-Fl::box_dx(box()), Y-Fl::box_dy(box()),
             W+Fl::box_dw(box()), H+Fl::box_dh(box()), color());
    fl_pop_clip();
  }

  fl_pop_clip();
}

static int isword(char c) {
  return (c&128 || isalnum(c) || strchr("#%&-/@\\_~", c));
}

int Fl_Input_::word_end(int i) const {
  if (input_type() == FL_SECRET_INPUT) return size();
  //while (i < size() && !isword(index(i))) i++;
  while (i < size() && isword(index(i))) i++;
  return i;
}

int Fl_Input_::word_start(int i) const {
  if (input_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 (input_type() != FL_MULTILINE_INPUT) return size();

  if (wrap()) {
    // 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:
    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;
  }
}

int Fl_Input_::line_start(int i) const {
  if (input_type() != FL_MULTILINE_INPUT) return 0;
  int j = i;
  while (j > 0 && index(j-1) != '\n') j--;
  if (wrap()) {
    // now measure lines until we get past i, start of that line is real eol:
    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;
}

void Fl_Input_::handle_mouse(int X, int Y, int /*W*/, int /*H*/, int drag) {
  was_up_down = 0;
  if (!size()) return;
  setfont();

  const char *p, *e;
  char buf[MAXBUF];

  int theline = (input_type()==FL_MULTILINE_INPUT) ?
    (Fl::event_y()-Y+yscroll_)/fl_height() : 0;

  int newpos = 0;
  for (p=value();; ) {
    e = expand(p, buf);
    theline--; if (theline < 0) break;
    if (e >= value_+size_) break;
    p = e+1;
  }
  const char *l, *r, *t; double f0 = Fl::event_x()-X+xscroll_;
  for (l = p, r = e; l<r; ) {
    double f;
    t = l+(r-l+1)/2;
    f = X-xscroll_+expandpos(p, t, buf, 0);
    if (f <= Fl::event_x()) {l = t; f0 = Fl::event_x()-f;}
    else r = t-1;
  }
  if (l < e) { // see if closer to character on right:
    double f1 = X-xscroll_+expandpos(p, l+1, buf, 0)-Fl::event_x();
    if (f1 < f0) l = l+1;
  }
  newpos = l-value();

  int newmark = drag ? mark() : newpos;
  if (Fl::event_clicks()) {
    if (newpos >= newmark) {
      if (newpos == newmark) {
        if (newpos < size()) newpos++;
        else newmark--;
      }
      if (Fl::event_clicks() > 1) {
        newpos = line_end(newpos);
        newmark = line_start(newmark);
      } else {
        newpos = word_end(newpos);
        newmark = word_start(newmark);
      }
    } else {
      if (Fl::event_clicks() > 1) {
        newpos = line_start(newpos);
        newmark = line_end(newmark);
      } else {
        newpos = word_start(newpos);
        newmark = word_end(newmark);
      }
    }
    // if the multiple click does not increase the selection, revert
    // to single-click behavior:
    if (!drag && (mark() > position() ?
                  (newmark >= position() && newpos <= mark()) :
                  (newmark >= mark() && newpos <= position()))) {
      Fl::event_clicks(0);
      newmark = newpos = l-value();
    }
  }
  chineseCharRePositionLeast(p-1,newpos);
  position(newpos, newmark);
}


//comment by chenqg:  if p position is a chinese character, need to reposistion 
to that start of end of the chinese character, but not in the middle
// in reposition least , p will reposition to start of chinese character, while 
reposition great will reposition to the end.
void chineseCharRePositionLeast(const char *start,int &p)
{

        if (start[p] &128){
                int i,curs;

                //comment by chenqg: search from back to front , to find the 
tart of chinese character
                for(i=p;i >= 0;i --){
                        if ( !(start[i] &128) ) break;
                }
                curs = p-i;

                if ((curs/2)*2==curs ) p--;  //if odd(curs)  , p must sub 1

        }
}
void chineseCharRePositionGreat(const char *start,int &p)
{
        if (start[p] &128){
                int p1=p;

                chineseCharRePositionLeast(start,p1);
                if (p1 < p ) p++;
        }
}

int Fl_Input_::position(int p, int m) {
  was_up_down = 0;
  if (p<0) p = 0;
  if (p>size()) p = size();
  if (m<0) m = 0;
  if (m>size()) m = size();
  chineseCharRePositionLeast(value(),p);  //comment by chenqg: to check if it 
is chinese character ,need to reposition
   chineseCharRePositionLeast(value(),m);//comment by chenqg:  to check  if it 
is chinese character ,need to reposition
  if (p == position_ && m == mark_) return 0;
  //if (Fl::selection_owner() == this) Fl::selection_owner(0);
  if (p != m) {
    if (p != position_) minimal_update(position_, p);
    if (m != mark_) minimal_update(mark_, m);
  } else {
    // new position is a cursor
    if (position_ == mark_) {
      // old position was just a cursor
      if (Fl::focus() == this && !(damage()&FL_DAMAGE_EXPOSE)) {
        minimal_update(position_); erase_cursor_only = 1;
      }
    } else { // old position was a selection
      minimal_update(position_, mark_);
    }
  }
  position_ = p;
  mark_ = m;
  return 1;
}

int Fl_Input_::up_down_position(int i, int keepmark) {
  // unlike before, i must be at the start of the line already!

  setfont();
  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 = l-value();
  j = position(j, keepmark ? mark_ : j);
  was_up_down = 1;
  return j;
}

int Fl_Input_::copy(int clipboard) {
  int b = position();
  int e = mark();
  if (b != e) {
    if (b > e) {b = mark(); e = position();}
    if (input_type() == FL_SECRET_INPUT) e = b;
    Fl::copy(value()+b, e-b, clipboard);
    return 1;
  }
  return 0;
}

#define MAXFLOATSIZE 40

static char* undobuffer;
static int undobufferlength;
static Fl_Input_* undowidget;
static int undoat;      // points after insertion
static int undocut;     // number of characters deleted there
static int undoinsert;  // number of characters inserted
static int yankcut;     // length of valid contents of buffer, even if undocut=0

static void undobuffersize(int n) {
  if (n > undobufferlength) {
    if (undobuffer) {
      do {undobufferlength *= 2;} while (undobufferlength < n);
      undobuffer = (char*)realloc(undobuffer, undobufferlength);
    } else {
      undobufferlength = n+9;
      undobuffer = (char*)malloc(undobufferlength);
    }
  }
}

// all changes go through here, delete characters b-e and insert text:
int Fl_Input_::replace(int b, int e, const char* text, int ilen) {

  was_up_down = 0;

  if (b<0) b = 0;
  if (e<0) e = 0;
  if (b>size_) b = size_;
  if (e>size_) e = size_;
  chineseCharRePositionLeast(value(),b);//comment by chenqg: reposition for 
chinese characters
  chineseCharRePositionLeast(value(),e);
  if (e<b) {int t=b; b=e; e=t;}
  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;
  }

  put_in_buffer(size_+ilen);

  if (e>b) {
    if (undowidget == this && b == undoat) {
      undobuffersize(undocut+(e-b));
      memcpy(undobuffer+undocut, value_+b, e-b);
      undocut += e-b;
    } else if (undowidget == this && e == undoat && !undoinsert) {
      undobuffersize(undocut+(e-b));
      memmove(undobuffer+(e-b), undobuffer, undocut);
      memcpy(undobuffer, value_+b, e-b);
      undocut += e-b;
    } else if (undowidget == this && e == undoat && (e-b)<undoinsert) {
      undoinsert -= e-b;
    } else {
      undobuffersize(e-b);
      memcpy(undobuffer, value_+b, e-b);
      undocut = e-b;
      undoinsert = 0;
    }
    memmove(buffer+b, buffer+e, size_-e+1);
    size_ -= e-b;
    undowidget = this;
    undoat = b;
    if (input_type() == FL_SECRET_INPUT) yankcut = 0; else yankcut = undocut;
  }

  if (ilen) {
    if (undowidget == this && b == undoat)
      undoinsert += ilen;
    else {
      undocut = 0;
      undoinsert = ilen;
    }
    memmove(buffer+b+ilen, buffer+b, size_-b+1);
    memcpy(buffer+b, text, ilen);
    size_ += ilen;
  }
  undowidget = this;
  undoat = b+ilen;

  // 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 (wrap()) {
    // if there is a space in the pasted text, the whole line may have rewrapped
    int i;
    for (i=0; i<ilen; i++)
      if (text[i]==' ') break;
    if (i==ilen)
      while (b > 0 && !isspace(index(b) & 255) && index(b)!='\n') b--;
    else
      while (b > 0 && index(b)!='\n') b--;
  }

  // make sure we redraw the old selection or cursor:
  if (mark_ < b) b = mark_;
  if (position_ < b) b = position_;

  minimal_update(b);

  mark_ = position_ = undoat;

  set_changed();
  if (when()&FL_WHEN_CHANGED) do_callback();
  return 1;
}

int Fl_Input_::undo() {
  was_up_down = 0;
  if (undowidget != this || !undocut && !undoinsert) return 0;

  int ilen = undocut;
  int xlen = undoinsert;
  int b = undoat-xlen;
  int b1 = b;

  put_in_buffer(size_+ilen);

  if (ilen) {
    memmove(buffer+b+ilen, buffer+b, size_-b+1);
    memcpy(buffer+b, undobuffer, ilen);
    size_ += ilen;
    b += ilen;
  }

  if (xlen) {
    undobuffersize(xlen);
    memcpy(undobuffer, buffer+b, xlen);
    memmove(buffer+b, buffer+b+xlen, size_-xlen-b+1);
    size_ -= xlen;
  }

  undocut = xlen;
  if (xlen) yankcut = xlen;
  undoinsert = ilen;
  undoat = b;
  mark_ = b /* -ilen */;
  position_ = b;

  if (wrap())
    while (b1 > 0 && index(b1)!='\n') b1--;
  minimal_update(b1);
  set_changed();
  if (when()&FL_WHEN_CHANGED) do_callback();
  return 1;
}

int Fl_Input_::copy_cuts() {
  // put the yank buffer into the X clipboard
  if (!yankcut || input_type()==FL_SECRET_INPUT) return 0;
  Fl::copy(undobuffer, yankcut, 1);
  return 1;
}

void Fl_Input_::maybe_do_callback() {
  if (changed() || (when()&FL_WHEN_NOT_CHANGED)) {
    do_callback();
  }
}

int Fl_Input_::handletext(int event, int X, int Y, int W, int H) {
  switch (event) {

  case FL_ENTER:
  case FL_MOVE:
    if (active_r() && window()) window()->cursor(FL_CURSOR_INSERT);
    return 1;

  case FL_LEAVE:
    if (active_r() && window()) window()->cursor(FL_CURSOR_DEFAULT);
    return 1;

  case FL_FOCUS:
    if (mark_ == position_) {
      minimal_update(size()+1);
    } else //if (Fl::selection_owner() != this)
      minimal_update(mark_, position_);
    return 1;

  case FL_UNFOCUS:
    if (active_r() && window()) window()->cursor(FL_CURSOR_DEFAULT);
    if (mark_ == position_) {
      if (!(damage()&FL_DAMAGE_EXPOSE)) {minimal_update(position_); 
erase_cursor_only = 1;}
    } else //if (Fl::selection_owner() != this)
      minimal_update(mark_, position_);
  case FL_HIDE:
    if (!readonly() && (when() & FL_WHEN_RELEASE))
      maybe_do_callback();
    return 1;

  case FL_PUSH:
    if (active_r() && window()) window()->cursor(FL_CURSOR_INSERT);

    handle_mouse(X, Y, W, H, Fl::event_state(FL_SHIFT));

    if (Fl::focus() != this) {
      Fl::focus(this);
      handle(FL_FOCUS);
    }
    return 1;

  case FL_DRAG:
    handle_mouse(X, Y, W, H, 1);
    return 1;

  case FL_RELEASE:
    copy(0);
    return 1;

  case FL_PASTE: {
    // Don't allow pastes into readonly widgets...
    if (readonly()) {
      fl_beep(FL_BEEP_ERROR);
      return 1;
    }

    // See if we have anything to paste...
    if (!Fl::event_text() || !Fl::event_length()) return 1;

    // strip trailing control characters and spaces before pasting:
    const char* t = Fl::event_text();
    const char* e = t+Fl::event_length();
    if (input_type() != FL_MULTILINE_INPUT) while (e > t && isspace(*(e-1) & 
255)) e--;
    if (!t || e <= t) return 1; // Int/float stuff will crash without this test
    if (input_type() == FL_INT_INPUT) {
      while (isspace(*t & 255) && t < e) t ++;
      const char *p = t;
      if (*p == '+' || *p == '-') p ++;
      if (strncmp(p, "0x", 2) == 0) {
        p += 2;
        while (isxdigit(*p & 255) && p < e) p ++;
      } else {
        while (isdigit(*p & 255) && p < e) p ++;
      }
      if (p < e) {
        fl_beep(FL_BEEP_ERROR);
        return 1;
      } else return replace(0, size(), t, e - t);
    } else if (input_type() == FL_FLOAT_INPUT) {
      while (isspace(*t & 255) && t < e) t ++;
      const char *p = t;
      if (*p == '+' || *p == '-') p ++;
      while (isdigit(*p & 255) && p < e) p ++;
      if (*p == '.') {
        p ++;
        while (isdigit(*p & 255) && p < e) p ++;
        if (*p == 'e' || *p == 'E') {
          p ++;
          if (*p == '+' || *p == '-') p ++;
          while (isdigit(*p & 255) && p < e) p ++;
        }
      }
      if (p < e) {
        fl_beep(FL_BEEP_ERROR);
        return 1;
      } else return replace(0, size(), t, e - t);
    }
    return replace(position(), mark(), t, e-t);}

  default:
    return 0;
  }
}

/*------------------------------*/

Fl_Input_::Fl_Input_(int X, int Y, int W, int H, const char* l)
: Fl_Widget(X, Y, W, H, l) {
  box(FL_DOWN_BOX);
  color(FL_BACKGROUND2_COLOR, FL_SELECTION_COLOR);
  align(FL_ALIGN_LEFT);
  textsize_ = (uchar)FL_NORMAL_SIZE;
  textfont_ = FL_HELVETICA;
  textcolor_ = FL_FOREGROUND_COLOR;
  cursor_color_ = FL_FOREGROUND_COLOR; // was FL_BLUE
  mark_ = position_ = size_ = 0;
  bufsize = 0;
  buffer  = 0;
  value_ = "";
  xscroll_ = yscroll_ = 0;
  maximum_size_ = 32767;
}

void Fl_Input_::put_in_buffer(int len) {
  if (value_ == buffer && bufsize > len) {
    buffer[size_] = 0;
    return;
  }
  if (!bufsize) {
    if (len > size_) len += 9; // let a few characters insert before realloc
    bufsize = len+1;
    buffer = (char*)malloc(bufsize);
  } else if (bufsize <= len) {
    // we may need to move old value in case it points into buffer:
    int moveit = (value_ >= buffer && value_ < buffer+bufsize);
    // enlarge current buffer
    if (len > size_) {
      do {bufsize *= 2;} while (bufsize <= len);
    } else {
      bufsize = len+1;
    }
    // Note: the following code is equivalent to:
    //
    //   if (moveit) value_ = value_ - buffer;
    //   char* nbuffer = (char*)realloc(buffer, bufsize);
    //   if (moveit) value_ = value_ + nbuffer;
    //   buffer = nbuffer;
    //
    // We just optimized the pointer arithmetic for value_...
    //
    char* nbuffer = (char*)realloc(buffer, bufsize);
    if (moveit) value_ += (nbuffer-buffer);
    buffer = nbuffer;
  }
  memmove(buffer, value_, size_); buffer[size_] = 0;
  value_ = buffer;
}

int Fl_Input_::static_value(const char* str, int len) {
  clear_changed();
  if (undowidget == this) undowidget = 0;
  if (str == value_ && len == size_) return 0;
  if (len) { // non-empty new value:
    if (xscroll_ || yscroll_) {
      xscroll_ = yscroll_ = 0;
      minimal_update(0);
    } else {
      int i = 0;
      // find first different character:
      if (value_) {
        for (; i<size_ && i<len && str[i]==value_[i]; i++);
        if (i==size_ && i==len) return 0;
      }
      minimal_update(i);
    }
    value_ = str;
    size_ = len;
  } else { // empty new value:
    if (!size_) return 0; // both old and new are empty.
    size_ = 0;
    value_ = "";
    xscroll_ = yscroll_ = 0;
    minimal_update(0);
  }
  position(readonly() ? 0 : size());
  return 1;
}

int Fl_Input_::static_value(const char* str) {
  return static_value(str, str ? strlen(str) : 0);
}

int Fl_Input_::value(const char* str, int len) {
  int r = static_value(str, len);
  if (len) put_in_buffer(len);
  return r;
}

int Fl_Input_::value(const char* str) {
  return value(str, str ? strlen(str) : 0);
}

void Fl_Input_::resize(int X, int Y, int W, int H) {
  if (W != w()) xscroll_ = 0;
  if (H != h()) yscroll_ = 0;
  Fl_Widget::resize(X, Y, W, H);
}

Fl_Input_::~Fl_Input_() {
  if (undowidget == this) undowidget = 0;
  if (bufsize) free((void*)buffer);
}

//
// End of "$Id: Fl_Input_.cxx 6104 2008-04-21 20:54:37Z matt $".
//
==================Fl_Input.cxx===========================
//
// "$Id: Fl_Input.cxx 6103 2008-04-21 20:42:51Z matt $"
//
// Input widget for the Fast Light Tool Kit (FLTK).
//
// Copyright 1998-2006 by Bill Spitzak and others.
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Library General Public
// License as published by the Free Software Foundation; either
// version 2 of the License, or (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
// Library General Public License for more details.
//
// You should have received a copy of the GNU Library General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
// USA.
//
// Please report all bugs and problems on the following page:
//
//     http://www.fltk.org/str.php
//

// This is the "user interface", it decodes user actions into what to
// do to the text.  See also Fl_Input_.cxx, where the text is actually
// manipulated (and some ui, in particular the mouse, is done...).
// In theory you can replace this code with another subclass to change
// the keybindings.

#include <stdio.h>
#include <stdlib.h>
#include <FL/Fl.H>
#include <FL/Fl_Window.H>
#include <FL/Fl_Input.H>
#include <FL/fl_draw.H>
#include <FL/fl_ask.H>
#include "flstring.h"

#ifdef HAVE_LOCALE_H
# include <locale.h>
#endif


void Fl_Input::draw() {
  if (input_type() == FL_HIDDEN_INPUT) return;
  Fl_Boxtype b = box();
  if (damage() & FL_DAMAGE_ALL) draw_box(b, color());
  Fl_Input_::drawtext(x()+Fl::box_dx(b), y()+Fl::box_dy(b),
                      w()-Fl::box_dw(b), h()-Fl::box_dh(b));
}

// kludge so shift causes selection to extend:
int Fl_Input::shift_position(int p) {
  return position(p, Fl::event_state(FL_SHIFT) ? mark() : p);
}
int Fl_Input::shift_up_down_position(int p) {
  return up_down_position(p, Fl::event_state(FL_SHIFT));
}

// If you define this symbol as zero you will get the peculiar fltk
// behavior where moving off the end of an input field will move the
// cursor into the next field:
// define it as 1 to prevent cursor movement from going to next field:
#define NORMAL_INPUT_MOVE 0

#define ctrl(x) ((x)^0x40)

// List of characters that are legal in a floating point input field.
// This text string is created at run-time to take the current locale
// into account (for example, continental Europe uses a comma instead
// of a decimal point). For back compatibility reasons, we always
// allow the decimal point.
#ifdef HAVE_LOCALECONV
static const char *standard_fp_chars = ".eE+-";
static const char *legal_fp_chars = 0L;
#else
static const char *legal_fp_chars = ".eE+-";
#endif

int Fl_Input::handle_key() {

  char ascii = Fl::event_text()[0];

  int repeat_num=1;

  int del;
  if (Fl::compose(del)) {

    // Insert characters into numeric fields after checking for legality:
    if (input_type() == FL_FLOAT_INPUT || input_type() == FL_INT_INPUT) {
      Fl::compose_reset(); // ignore any foreign letters...

      // initialize the list of legal characters inside a floating point number
#ifdef HAVE_LOCALECONV
      if (!legal_fp_chars) {
        int len = strlen(standard_fp_chars);
        struct lconv *lc = localeconv();
        if (lc) {
          if (lc->decimal_point) len += strlen(lc->decimal_point);
          if (lc->mon_decimal_point) len += strlen(lc->mon_decimal_point);
          if (lc->positive_sign) len += strlen(lc->positive_sign);
          if (lc->negative_sign) len += strlen(lc->negative_sign);
        }
        // the following line is not a true memory leak because the array is 
only
        // allocated once if required, and automatically freed when the program 
quits
        char *chars = (char*)malloc(len+1);
        legal_fp_chars = chars;
        strcpy(chars, standard_fp_chars);
        if (lc) {
          if (lc->decimal_point) strcat(chars, lc->decimal_point);
          if (lc->mon_decimal_point) strcat(chars, lc->mon_decimal_point);
          if (lc->positive_sign) strcat(chars, lc->positive_sign);
          if (lc->negative_sign) strcat(chars, lc->negative_sign);
        }
      }
#endif // HAVE_LOCALECONV

      // This is complex to allow "0xff12" hex to be typed:
      if (!position() && (ascii == '+' || ascii == '-') ||
          (ascii >= '0' && ascii <= '9') ||
          (position()==1 && index(0)=='0' && (ascii=='x' || ascii == 'X')) ||
          (position()>1 && index(0)=='0' && (index(1)=='x'||index(1)=='X')
           && (ascii>='A'&& ascii<='F' || ascii>='a'&& ascii<='f')) ||
          input_type()==FL_FLOAT_INPUT && ascii && strchr(legal_fp_chars, 
ascii)) {
        if (readonly()) fl_beep();
        else replace(position(), mark(), &ascii, 1);
      }
      return 1;
    }

    if (del || Fl::event_length()) {
      if (readonly()) fl_beep();
      else replace(position(), del ? position()-del : mark(),
                   Fl::event_text(), Fl::event_length());
    }
    return 1;
  }

  switch (Fl::event_key()) {
  case FL_Insert:
    if (Fl::event_state() & FL_CTRL) ascii = ctrl('C');
    else if (Fl::event_state() & FL_SHIFT) ascii = ctrl('V');
    break;
  case FL_Delete:
    if (Fl::event_state() & FL_SHIFT) ascii = ctrl('X');
    else ascii = ctrl('D');
    break;
  case FL_Left:
    ascii = ctrl('B'); break;
  case FL_Right:
    ascii = ctrl('F'); break;
  case FL_Page_Up:
    fl_font(textfont(),textsize()); //ensure current font is set to ours
    repeat_num=h()/fl_height(); // number of lines to scroll
    if (!repeat_num) repeat_num=1;
  case FL_Up:
    ascii = ctrl('P'); break;
  case FL_Page_Down:
    fl_font(textfont(),textsize());
    repeat_num=h()/fl_height();
    if (!repeat_num) repeat_num=1;
  case FL_Down:
    ascii = ctrl('N'); break;
  case FL_Home:
    if (Fl::event_state() & FL_CTRL) {
      shift_position(0);
      return 1;
    }
    ascii = ctrl('A');
    break;
  case FL_End:
    if (Fl::event_state() & FL_CTRL) {
      shift_position(size());
      return 1;
    }
    ascii = ctrl('E'); break;

  case FL_BackSpace:
    ascii = ctrl('H'); break;
  case FL_Enter:
  case FL_KP_Enter:
    if (when() & FL_WHEN_ENTER_KEY) {
      position(size(), 0);
      maybe_do_callback();
      return 1;
    } else if (input_type() == FL_MULTILINE_INPUT && !readonly())
      return replace(position(), mark(), "\n", 1);
    else
      return 0; // reserved for shortcuts
  case FL_Tab:
    if (Fl::event_state(FL_CTRL|FL_SHIFT) || input_type()!=FL_MULTILINE_INPUT 
|| readonly()) return 0;
    return replace(position(), mark(), &ascii, 1);
#ifdef __APPLE__
  case 'c' :
  case 'v' :
  case 'x' :
  case 'z' :
//    printf("'%c' (0x%02x) pressed with%s%s%s%s\n", ascii, ascii,
//           Fl::event_state(FL_SHIFT) ? " FL_SHIFT" : "",
//           Fl::event_state(FL_CTRL) ? " FL_CTRL" : "",
//           Fl::event_state(FL_ALT) ? " FL_ALT" : "",
//           Fl::event_state(FL_META) ? " FL_META" : "");
    if (Fl::event_state(FL_META)) ascii -= 0x60;
//    printf("using '%c' (0x%02x)...\n", ascii, ascii);
    break;
#endif // __APPLE__
  }

  int i,pp;
  switch (ascii) {
  case ctrl('A'):
    return shift_position(line_start(position())) + NORMAL_INPUT_MOVE;
  case ctrl('B'):
        //commet by chenqg: if is chinese charactor , move in 2 byte step
        pp=position()-1;
        chineseCharRePositionLeast(value(),pp);
    return shift_position(pp) + NORMAL_INPUT_MOVE;
  case ctrl('C'): // copy
    return copy(1);
  case ctrl('D'):
  case ctrl('?'):
    if (readonly()) {
      fl_beep();
      return 1;
    }
        //commet by chenqg: if is chinese charactor , delete in 2 byte step
        pp = position()+1;
        chineseCharRePositionGreat(value(),pp);
        if (pp == position()+2) pp=2;
        else pp=1;
    if (mark() != position()) return cut();
    else return cut(pp);
  case ctrl('E'):
    return shift_position(line_end(position())) + NORMAL_INPUT_MOVE;
  case ctrl('F'):
        //commet by chenqg: if is chinese charactor , move in 2 byte step
        pp=position()+1;
        chineseCharRePositionGreat(value(),pp);
    return shift_position(pp) + NORMAL_INPUT_MOVE;
  case ctrl('H'):
    if (readonly()) {
      fl_beep();
      return 1;
    }
    if (mark() != position()) cut();
    else cut(-1);
    return 1;
  case ctrl('K'):
    if (readonly()) {
      fl_beep();
      return 1;
    }
    if (position()>=size()) return 0;
    i = line_end(position());
    if (i == position() && i < size()) i++;
    cut(position(), i);
    return copy_cuts();
  case ctrl('N'):
    i = position();
    if (line_end(i) >= size()) return NORMAL_INPUT_MOVE;
    while (repeat_num--) {
      i = line_end(i);
      if (i >= size()) break;
      i++;
    }
    shift_up_down_position(i);
    return 1;
  case ctrl('P'):
    i = position();
    if (!line_start(i)) return NORMAL_INPUT_MOVE;
    while(repeat_num--) {
      i = line_start(i);
      if (!i) break;
      i--;
    }
    shift_up_down_position(line_start(i));
    return 1;
  case ctrl('U'):
    if (readonly()) {
      fl_beep();
      return 1;
    }
    return cut(0, size());
  case ctrl('V'):
  case ctrl('Y'):
    if (readonly()) {
      fl_beep();
      return 1;
    }
    Fl::paste(*this, 1);
    return 1;
  case ctrl('X'):
  case ctrl('W'):
    if (readonly()) {
      fl_beep();
      return 1;
    }
    copy(1);
    return cut();
  case ctrl('Z'):
  case ctrl('_'):
    if (readonly()) {
      fl_beep();
      return 1;
    }
    return undo();
  case ctrl('I'):
  case ctrl('J'):
  case ctrl('L'):
  case ctrl('M'):
    if (readonly()) {
      fl_beep();
      return 1;
    }
    // insert a few selected control characters literally:
    if (input_type() != FL_FLOAT_INPUT && input_type() != FL_INT_INPUT)
      return replace(position(), mark(), &ascii, 1);
  }

  return 0;
}

int Fl_Input::handle(int event) {
  static int dnd_save_position, dnd_save_mark, drag_start = -1, newpos;
  static Fl_Widget *dnd_save_focus;
  switch (event) {
  case FL_FOCUS:
    switch (Fl::event_key()) {
    case FL_Right:
      position(0);
      break;
    case FL_Left:
      position(size());
      break;
    case FL_Down:
      up_down_position(0);
      break;
    case FL_Up:
      up_down_position(line_start(size()));
      break;
    case FL_Tab:
    case 0xfe20: // XK_ISO_Left_Tab
      position(size(),0);
      break;
    default:
      position(position(),mark());// turns off the saved up/down arrow position
      break;
    }
    break;

  case FL_KEYBOARD:
    if (Fl::event_key() == FL_Tab && mark() != position()) {
      // Set the current cursor position to the end of the selection...
      if (mark() > position())
        position(mark());
      else
        position(position());
      return (1);
    } else {
      if (active_r() && window() && this == Fl::belowmouse())
        window()->cursor(FL_CURSOR_NONE);
      return handle_key();
    }

  case FL_PUSH:
    if (Fl::dnd_text_ops()) {
      int oldpos = position(), oldmark = mark();
      Fl_Boxtype b = box();
      Fl_Input_::handle_mouse(
        x()+Fl::box_dx(b), y()+Fl::box_dy(b),
        w()-Fl::box_dw(b), h()-Fl::box_dh(b), 0);
      newpos = position();
      position( oldpos, oldmark );
      if (Fl::focus()==this && !Fl::event_state(FL_SHIFT) && 
input_type()!=FL_SECRET_INPUT &&
          (newpos >= mark() && newpos < position() ||
          newpos >= position() && newpos < mark())) {
        // user clicked in the selection, may be trying to drag
        drag_start = newpos;
        return 1;
      }
      drag_start = -1;
    }

    if (Fl::focus() != this) {
      Fl::focus(this);
      handle(FL_FOCUS);
    }
    break;

  case FL_DRAG:
    if (Fl::dnd_text_ops()) {
      if (drag_start >= 0) {
        if (Fl::event_is_click()) return 1; // debounce the mouse
        // save the position because sometimes we don't get DND_ENTER:
        dnd_save_position = position();
        dnd_save_mark = mark();
        // drag the data:
        copy(0); Fl::dnd();
        return 1;
      }
    }
    break;

  case FL_RELEASE:
    if (Fl::event_button() == 2) {
      Fl::event_is_click(0); // stop double click from picking a word
      Fl::paste(*this, 0);
    } else if (!Fl::event_is_click()) {
      // copy drag-selected text to the clipboard.
      copy(0);
    } else if (Fl::event_is_click() && drag_start >= 0) {
      // user clicked in the field and wants to reset the cursor position...
      position(drag_start, drag_start);
      drag_start = -1;
    } else if (Fl::event_clicks()) {
      // user double or triple clicked to select word or whole text
      copy(0);
    }

    // For output widgets, do the callback so the app knows the user
    // did something with the mouse...
    if (readonly()) do_callback();

    return 1;

  case FL_DND_ENTER:
    Fl::belowmouse(this); // send the leave events first
    dnd_save_position = position();
    dnd_save_mark = mark();
    dnd_save_focus = Fl::focus();
    if (dnd_save_focus != this) {
      Fl::focus(this);
      handle(FL_FOCUS);
    }
    // fall through:
  case FL_DND_DRAG:
    //int p = mouse_position(X, Y, W, H);
#if DND_OUT_XXXX
    if (Fl::focus()==this && (p>=dnd_save_position && p<=dnd_save_mark ||
                      p>=dnd_save_mark && p<=dnd_save_position)) {
      position(dnd_save_position, dnd_save_mark);
      return 0;
    }
#endif
    {
      Fl_Boxtype b = box();
      Fl_Input_::handle_mouse(
        x()+Fl::box_dx(b), y()+Fl::box_dy(b),
        w()-Fl::box_dw(b), h()-Fl::box_dh(b), 0);
    }
    return 1;

  case FL_DND_LEAVE:
    position(dnd_save_position, dnd_save_mark);
#if DND_OUT_XXXX
    if (!focused())
#endif
    if (dnd_save_focus != this) {
      Fl::focus(dnd_save_focus);
      handle(FL_UNFOCUS);
    }
    return 1;

  case FL_DND_RELEASE:
    take_focus();
    return 1;

  }
  Fl_Boxtype b = box();
  return Fl_Input_::handletext(event,
        x()+Fl::box_dx(b), y()+Fl::box_dy(b),
        w()-Fl::box_dw(b), h()-Fl::box_dh(b));
}

Fl_Input::Fl_Input(int X, int Y, int W, int H, const char *l)
: Fl_Input_(X, Y, W, H, l) {
}

//
// End of "$Id: Fl_Input.cxx 6103 2008-04-21 20:42:51Z matt $".
//


_______________________________________________
fltk mailing list
[email protected]
http://lists.easysw.com/mailman/listinfo/fltk

Reply via email to