⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 fl_input_.cxx

📁 SRI international 发布的OAA框架软件
💻 CXX
📖 第 1 页 / 共 2 页
字号:
//
// "$Id: Fl_Input_.cxx,v 1.1.1.1 2003/06/03 22:25:42 agno Exp $"
//
// Common input widget routines for the Fast Light Tool Kit (FLTK).
//
// Copyright 1998-2003 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 to "fltk-bugs@fltk.org".
//

// 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

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

// 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;

  if (input_type()==FL_SECRET_INPUT) {
    while (o<e && p < value_+size_) {*o++ = '*'; p++;}
  } else while (o<e) {
    if (wrap() && (p >= value_+size_ || isspace(*p))) {
      word_wrap = w() - Fl::box_dw(box()) - 2;
      width_to_lastspace += (int)fl_width(lastspace_out, o-lastspace_out);
      if (p > lastspace+1) {
	if (word_count && width_to_lastspace > word_wrap) {
	  p = lastspace; o = lastspace_out; break;
	}
	word_count++;
      }
      lastspace = p;
      lastspace_out = o;
    }

    if (p >= value_+size_) break;
    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++ = ' ';
      } else {
	*o++ = '^';
	*o++ = c ^ 0x40;
      }
    } else if (c == 0xA0) { // nbsp
      *o++ = ' ';
    } else {
      *o++ = c;
    }
  }
  *o = 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;
    } else if (c >= 128 && c < 0xA0) {
      n += 4;
    } 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();
  int xpos = 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:
      int r = X+W;
      int xx;
      if (p >= pp) {
	xx = X;
	if (erase_cursor_only) r = xpos+2;
	else if (readonly()) xx -= 3;
      } else {
	xx = xpos+(int)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(xx, Y+ypos, r-xx, 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;
      int x1 = xpos;
      int offset1 = 0;
      if (pp > p) {
	fl_color(tc);
	x1 += int(expandpos(p, pp, buf, &offset1));
	fl_draw(buf, offset1, xpos, Y+ypos+desc);
      }
      pp = value()+selend;
      int x2 = X+W;
      int offset2;
      if (pp <= e) x2 = xpos+int(expandpos(p, pp, buf, &offset2));
      else offset2 = strlen(buf);
      fl_color(selection_color());
      fl_rectf(x1, Y+ypos, x2-x1, height);
      fl_color(fl_contrast(textcolor(), selection_color()));
      fl_draw(buf+offset1, offset2-offset1, x1, Y+ypos+desc);
      if (pp < e) {
	fl_color(tc);
	fl_draw(buf+offset2, x2, Y+ypos+desc);
      }
    } else {
      // draw unselected text
      fl_color(tc);
      fl_draw(buf, xpos, 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(xpos+curx-3, Y+ypos+height-1,
	        xpos+curx, Y+ypos+height-4,
	        xpos+curx+3, Y+ypos+height-1);
      } else {
        fl_rectf(xpos+curx, Y+ypos, 2, height);
      }
    }

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

  // 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);

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -