Logo Search packages:      
Sourcecode: xcircuit version File versions

sub.c

/*************************************<+>*************************************
 *****************************************************************************
 **
 **   File:        sub.c
 **
 **   Project:     X Widgets
 **
 **   Description: Code for TextEdit widget
 **
 *****************************************************************************
 **   
 **   Copyright (c) 1988 by Hewlett-Packard Company
 **   Copyright (c) 1987, 1988 by Digital Equipment Corporation, Maynard,
 **             Massachusetts, and the Massachusetts Institute of Technology,
 **             Cambridge, Massachusetts
 **   
 **   Permission to use, copy, modify, and distribute this software 
 **   and its documentation for any purpose and without fee is hereby 
 **   granted, provided that the above copyright notice appear in all 
 **   copies and that both that copyright notice and this permission 
 **   notice appear in supporting documentation, and that the names of 
 **   Hewlett-Packard, Digital or  M.I.T.  not be used in advertising or 
 **   publicity pertaining to distribution of the software without 
 **   written prior permission.
 **   
 **   DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
 **   ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
 **   DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
 **   ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
 **   WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
 **   ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
 **   SOFTWARE.
 **   
 *****************************************************************************
 *************************************<+>*************************************/
/*****************************************************************************
*
*  Procedures declared in this file
*
******************************************************************************
*/
static void           InsertCursor () ;
static void           _XtTextNeedsUpdating() ;
static XwTextPosition PositionForXY () ;
static int            LineForPosition () ;
static int            LineAndXYForPosition () ;
static void           BuildLineTable () ;
static XwTextLineRange UpdateLineTable () ;
static void           ForceBuildLineTable() ;
static void           _XtTextScroll() ;
static XwEditResult   ReplaceText () ;
static void           DisplayText() ;
static void           ClearWindow () ;
static void           ClearText () ;     
static void           DisplayAllText () ;
static void           CheckResizeOrOverflow() ;
static void           ProcessExposeRegion() ;
static void           _XtTextPrepareToUpdate() ;
static void           FlushUpdate() ;
static void           _XtTextShowPosition() ;
static void           _XtTextExecuteUpdate() ;

/*
 * Procedure to manage insert cursor visibility for editable text.  It uses
 * the value of ctx->insertPos and an implicit argument. In the event that
 * position is immediately preceded by an eol graphic, then the insert cursor
 * is displayed at the beginning of the next line.
 */
/*--------------------------------------------------------------------------+*/
static void InsertCursor (ctx, state)
/*--------------------------------------------------------------------------+*/
  XwTextEditWidget ctx;
  XwInsertState state;
{
    Position x, y;
    int dy, line, visible;
    XwTextBlock text;

    if (ctx->text.lt.lines < 1) return;
    visible = LineAndXYForPosition(ctx, ctx->text.insertPos, &line, &x, &y);
    if (line < ctx->text.lt.lines)
      dy = (ctx->text.lt.info[line + 1].y - ctx->text.lt.info[line].y) + 1;
    else
      dy = (ctx->text.lt.info[line].y - ctx->text.lt.info[line - 1].y) + 1;

    /** If the insert position is just after eol then put it on next line **/
    if (x > ctx->text.leftmargin &&
      ctx->text.insertPos > 0 &&
      ctx->text.insertPos >= GETLASTPOS(ctx)) {
         /* reading the source is bogus and this code should use scan */
         (*(ctx->text.source->read)) (ctx->text.source,
                              ctx->text.insertPos - 1, &text, 1);
         if (text.ptr[0] == '\n') {
             x = ctx->text.leftmargin;
             y += dy;
         }
    }
    y += dy;
    if (visible)
      (*(ctx->text.sink->insertCursor))(ctx, x, y, state);
}


/*
 * Procedure to register a span of text that is no longer valid on the display
 * It is used to avoid a number of small, and potentially overlapping, screen
 * updates. [note: this is really a private procedure but is used in
 * multiple modules].
 */
/*--------------------------------------------------------------------------+*/
static void _XtTextNeedsUpdating(ctx, left, right)
/*--------------------------------------------------------------------------+*/
  XwTextEditWidget ctx;
  XwTextPosition left, right;
{
    int     i;
    if (left < right) {
      for (i = 0; i < ctx->text.numranges; i++) {
          if (left <= ctx->text.updateTo[i]
            && right >= ctx->text.updateFrom[i])
            { ctx->text.updateFrom[i] = min(left, ctx->text.updateFrom[i]);
            ctx->text.updateTo[i] = max(right, ctx->text.updateTo[i]);
            return;
          }
      }
      ctx->text.numranges++;
      if (ctx->text.numranges > ctx->text.maxranges) {
          ctx->text.maxranges = ctx->text.numranges;
          i = ctx->text.maxranges * sizeof(XwTextPosition);
          ctx->text.updateFrom = (XwTextPosition *) 
              XtRealloc((char *)ctx->text.updateFrom, (unsigned) i
            * sizeof(XwTextPosition));
          ctx->text.updateTo = (XwTextPosition *) 
            XtRealloc((char *)ctx->text.updateTo, (unsigned) i
            * sizeof(XwTextPosition));
      }
      ctx->text.updateFrom[ctx->text.numranges - 1] = left;
      ctx->text.updateTo[ctx->text.numranges - 1] = right;
    }
}


/* 
 * This routine maps an x and y position in a window that is displaying text
 * into the corresponding position in the source.
 */
/*--------------------------------------------------------------------------+*/
static XwTextPosition PositionForXY (ctx, x, y)
/*--------------------------------------------------------------------------+*/
  XwTextEditWidget ctx;
  Position x,y;
{
 /* it is illegal to call this routine unless there is a valid line table! */
    int     width, fromx, line;
    XwTextPosition position, resultstart, resultend;
    XwTextPosition lastpos = GETLASTPOS(ctx);

    /*** figure out what line it is on ***/
    for (line = 0; line < ctx->text.lt.lines - 1; line++) {
      if (y <= ctx->text.lt.info[line + 1].y)
          break;
    }
    position = ctx->text.lt.info[line].position;
    if (position >= lastpos)
      return lastpos;
    fromx = ctx->text.lt.info[line].x;    /* starting x in line */
    width = x - fromx;              /* num of pix from starting of line */
    (*(ctx->text.sink->resolve)) (ctx, position, fromx, width,
          &resultstart, &resultend);
    if (resultstart >= ctx->text.lt.info[line + 1].position)
      resultstart = (*(ctx->text.source->scan))(ctx->text.source,
            ctx->text.lt.info[line + 1].position, XwstPositions, XwsdLeft,
                                      1, TRUE);
    return resultstart;
}

/*
 * This routine maps a source position in to the corresponding line number
 * of the text that is displayed in the window.
 */
/*--------------------------------------------------------------------------+*/
static int LineForPosition (ctx, position)
/*--------------------------------------------------------------------------+*/
  XwTextEditWidget ctx;
  XwTextPosition position;
  /* it is illegal to call this routine unless there is a valid line table!*/
{
    int     line;

    if (position <= ctx->text.lt.info[0].position)
      return 0;
    for (line = 0; line < ctx->text.lt.lines; line++)
      if (position < ctx->text.lt.info[line + 1].position)
          break;
    return line;
}

/*
 * This routine maps a source position into the corresponding line number
 * and the x, y coordinates of the text that is displayed in the window.
 */
/*--------------------------------------------------------------------------+*/
static int LineAndXYForPosition (ctx, pos, line, x, y)
/*--------------------------------------------------------------------------+*/
  XwTextEditWidget ctx;
  XwTextPosition pos;
  int *line;
  Position *x, *y;
  /* it is illegal to call this routine unless there is a valid line table!*/
{
    XwTextPosition linePos, endPos;
    int     visible, realW, realH;

    *line = 0;
    *x = ctx->text.leftmargin;
    *y = ctx->text.topmargin;
    visible = IsPositionVisible(ctx, pos);
    if (visible) {
      *line = LineForPosition(ctx, pos);
      *y = ctx->text.lt.info[*line].y;
      *x = ctx->text.lt.info[*line].x;
      linePos = ctx->text.lt.info[*line].position;
      (*(ctx->text.sink->findDistance))(ctx, linePos,
                                     *x, pos, &realW, &endPos, &realH);
      *x = *x + realW;
    }
    return visible;
}

/*
 * This routine builds a line table. It does this by starting at the
 * specified position and measuring text to determine the staring position
 * of each line to be displayed. It also determines and saves in the
 * linetable all the required metrics for displaying a given line (e.g.
 * x offset, y offset, line length, etc.).
 */
/*--------------------------------------------------------------------------+*/
static void BuildLineTable (self, position)
/*--------------------------------------------------------------------------+*/
  XwTextEditWidget self;
  XwTextPosition position;
{
    XwTextPosition line, lines;
    Boolean     rebuild;
    XwLineTableEntryPtr lp ;

    rebuild = (Boolean) (position != self->text.lt.top);
    lines= applyDisplay(maxLines)(self) ;

/****************
 *
 *  RBM 
 *
 *  Don't allow a 0-line widget - let clipping occur
 *
 *  NOTE: THE MAXINT CLIPPING IS AN UGLY HACK THAT NEEDS TO BE FIXED 
 *        WITH A CAST!!
 ****************/
    if ((lines < 1) || (lines > 32767)) lines = 1;

    if (self->text.lt.info != NULL && lines != self->text.lt.lines) {
      XtFree((char *) self->text.lt.info);
      self->text.lt.info = NULL;
    }
    if (self->text.lt.info == NULL)
      {     self->text.lt.info = (XwLineTableEntry *)
        XtCalloc(lines + 1, (unsigned)sizeof(XwLineTableEntry));
      self->text.lt.lines = lines ;
      for (line = 0, lp = &(self->text.lt.info[0]) ;
           line < lines; line++, lp++)
        { lp->position = lp->drawPos = 0 ;
          lp->x = lp->y = 0 ;
        }
      rebuild = TRUE;
      }

    self->text.lt.top = position ;
    if (rebuild) UpdateLineTable ( self
                          , position
                          , 0
                          , self->core.width
                            - self->text.leftmargin
                            - self->text.rightmargin
                          , 0
                          , FALSE
                          ) ;
}

/*--------------------------------------------------------------------------+*/
static XwTextLineRange UpdateLineTable
  (self, pos0, posF, width, line0, updateMode)
/*--------------------------------------------------------------------------+*/
     XwTextEditWidget   self ;
     XwTextPosition     pos0, posF ;
     Dimension          width ;
     XwTextPosition     line0 ;
     int          updateMode ;
{
  XwLineTableEntryPtr currLine ;
  XwLineTablePtr      lt ;
  XwTextPosition line, nLines ;
  Dimension x0, y ;
  int       reqW, reqH ;
  TextFit   (*textFitFn)();
  int       wrapEnabled, breakOnWhiteSpace ;
  XwTextPosition fitPos, drawPos, nextPos ;
  
  textFitFn =  self->text.sink->textFitFn ;
  lt = &(self->text.lt) ;
  nLines = lt->lines ;
  x0 = self->text.leftmargin ;
  y = updateMode ? lt->info[line0].y : self->text.topmargin ;
  reqH = 0 ;
  wrapEnabled = (int) self->text.wrap_mode ;
  breakOnWhiteSpace =
    wrapEnabled && (self->text.wrap_break == XwWrapWhiteSpace) ;
  
  for (line = line0; line <= nLines; line++)
    { currLine = &(lt->info[line]) ;
      currLine->x = x0;
      currLine->y = y;
      currLine->position = pos0;
      if (pos0 <= GETLASTPOS(self))
      { currLine->fit = (*textFitFn) ( self
                              , pos0
                              , x0
                              , width
                              , wrapEnabled
                              , breakOnWhiteSpace
                              , &fitPos
                              , &drawPos
                              , &nextPos
                              , &reqW
                              , &reqH
                              ) ;
        currLine->drawPos = drawPos ;

        currLine->endX = x0 + reqW ;
        pos0 = nextPos;
        /* In update mode we must go through the last line which had a
           character replaced in it before terminating on a mere position
           match.  Starting position (of replacement) would be sufficient
           only if we know the font is fixed width. (Good place to
           optimize someday, huh?)
           */
        if (updateMode && (nextPos > posF)
            && (nextPos == lt->info[line+1].position))
          { break ;
           }
      }
      else
      { currLine->endX = x0;
        currLine->fit = tfEndText ;
      }
      y += reqH;
    } ;

  return ( (line < nLines) ? line : nLines - 1 ) ;
}


/*
 * This routine is used to re-display the entire window, independent of
 * its current state.
 */
/*--------------------------------------------------------------------------+*/
static void ForceBuildLineTable(ctx)
/*--------------------------------------------------------------------------+*/
    XwTextEditWidget ctx;
{
    XwTextPosition position;

    position = ctx->text.lt.top;
    ctx->text.lt.top++; /* ugly, but it works */
    BuildLineTable(ctx, position);
}

/*
 * The routine will scroll the displayed text by lines.  If the arg  is
 * positive, move up; otherwise, move down. [note: this is really a private
 * procedure but is used in multiple modules].
 */
/*--------------------------------------------------------------------------+*/
static void _XtTextScroll(ctx, n)
/*--------------------------------------------------------------------------+*/
  XwTextEditWidget ctx;
  int n;
{
  register XwTextEditPart *text = (XwTextEditPart *) &(ctx->text);
  register XwLineTablePtr lt = &(text->lt);
  XwTextPosition top, target, lastpos = GETLASTPOS(ctx);
  Dimension textwidth =
                      ctx->core.width - (text->leftmargin + text->rightmargin);
  Dimension ypos;
    if (n >= 0) {
      top = min(lt->info[n].position, lastpos);
      BuildLineTable(ctx, top);
      if (top >= lastpos)
          DisplayAllText(ctx);
      else {
          XCopyArea(XtDisplay(ctx), XtWindow(ctx), XtWindow(ctx),
                  text->gc,
                  text->leftmargin,             /* 0, */
                  lt->info[n].y,
                  textwidth,                     /* 9999, */
                  ctx->core.height - lt->info[n].y - text->bottommargin,
                  text->leftmargin,              /* 0, */
                  lt->info[0].y);
          ypos = lt->info[0].y + ctx->core.height - lt->info[n].y;
          (*(text->sink->clearToBackground))
            (ctx,
             text->leftmargin,                    /* 0, */
             ypos,      /* lt->info[0].y + ctx->core.height - lt->info[n].y, */
             textwidth,                           /* 9999, */
             ctx->core.height - (ypos + text->bottommargin)    /* 9999 */
             );
          if (n < lt->lines) n++;
          _XtTextNeedsUpdating(ctx,
                lt->info[lt->lines - n].position, lastpos);
      }
    } else {
      Dimension tempHeight;
      n = -n;
      target = lt->top;
      top = (*(text->source->scan))(text->source, target, XwstEOL,
                             XwsdLeft, n+1, FALSE);
      tempHeight = lt->info[lt->lines-n].y - text->topmargin;
      BuildLineTable(ctx, top);
      if (lt->info[n].position == target) {
          XCopyArea(XtDisplay(ctx), XtWindow(ctx), XtWindow(ctx),
                  text->gc,
                  text->leftmargin,            /* 0, */
                  lt->info[0].y,
                  textwidth,                   /* 9999, */
                  tempHeight,
                  text->leftmargin,            /* 0, */
                  lt->info[n].y);
          _XtTextNeedsUpdating(ctx, 
                lt->info[0].position, lt->info[n].position);
      } else if (lt->top != target) DisplayAllText(ctx);
    }
}


/*
 * This internal routine deletes the text from pos1 to pos2 in a source and
 * then inserts, at pos1, the text that was passed. As a side effect it
 * "invalidates" that portion of the displayed text (if any).
 */
/*--------------------------------------------------------------------------+*/
static XwEditResult ReplaceText (ctx, pos1, pos2, text, verify)
/*--------------------------------------------------------------------------+*/
  XwTextEditWidget ctx;
  XwTextPosition pos1, pos2;
  XwTextBlock *text;
  Boolean     verify;

 /* it is illegal to call this routine unless there is a valid line table!*/
{
    int             i, line1, line2, visible, delta;
    XwEditResult    error;
    Position        x, y;
    XwTextPosition  startPos, endPos, updateFrom, lastpos;
    XwTextVerifyCD  cbdata;
    XwTextBlock       newtxtblk;

    newtxtblk.ptr = (unsigned char*) XtMalloc(text->length);
    newtxtblk.firstPos = text->firstPos;
    newtxtblk.length = text->length;
    strncpy(newtxtblk.ptr, text->ptr, text->length);
    cbdata.operation = modVerify;
    cbdata.doit = TRUE;
    cbdata.currInsert = ctx->text.insertPos;
    cbdata.newInsert = ctx->text.insertPos;
    cbdata.startPos = pos1;
    cbdata.endPos = pos2;
    cbdata.text = &newtxtblk;

    if (verify)
      { XtCallCallbacks((Widget)ctx, XtNmodifyVerification, &cbdata);

      if (!cbdata.doit) {
        text->length = 0;  /* Necessary inorder to return to initial state */
        return XweditReject;
      }
      
      /* Extract any new data changed by the verification callback */
      /* newtxtblk is used in the actual replace call later */
      pos1 = cbdata.startPos;
      pos2 = cbdata.endPos;
      ctx->text.insertPos = cbdata.newInsert;
      }
    
    /* the insertPos may not always be set to the right spot in XwtextAppend */
    if ((pos1 == ctx->text.insertPos) && 
        ((*(ctx->text.source->editType))(ctx->text.source) == XwtextAppend)) {
      ctx->text.insertPos = GETLASTPOS(ctx);
      pos2 = pos2 - pos1 + ctx->text.insertPos;
      pos1 = ctx->text.insertPos;
    }
    updateFrom = (*(ctx->text.source->scan))
      (ctx->text.source, pos1, XwstWhiteSpace, XwsdLeft, 1, TRUE);
    updateFrom = (*(ctx->text.source->scan))
      (ctx->text.source, updateFrom, XwstPositions, XwsdLeft, 1, TRUE);
    startPos = max(updateFrom, ctx->text.lt.top);
    visible = LineAndXYForPosition(ctx, startPos, &line1, &x, &y);
    error = (*(ctx->text.source->replace))
      (ctx->text.source, pos1, pos2, &newtxtblk, &delta);
    XtFree(newtxtblk.ptr);
    if (error) return error;
    lastpos = GETLASTPOS(ctx);
    if (ctx->text.lt.top >= lastpos) {
      BuildLineTable(ctx, lastpos);
      /* ClearWindow(ctx); */
      ClearText(ctx);   
      return error;
    }
    if (delta < lastpos) {
      for (i = 0; i < ctx->text.numranges; i++) {
          if (ctx->text.updateFrom[i] > pos1)
            ctx->text.updateFrom[i] += delta;
          if (ctx->text.updateTo[i] >= pos1)
            ctx->text.updateTo[i] += delta;
      }
    }

    line2 = LineForPosition(ctx, pos1);
    /* 
     * fixup all current line table entries to reflect edit.
     * BUG: it is illegal to do arithmetic on positions. This code should
     * either use scan or the source needs to provide a function for doing
     * position arithmetic.
    */
    for (i = line2 + 1; i <= ctx->text.lt.lines; i++)
      ctx->text.lt.info[i].position += delta;

    endPos = pos1;
    /*
     * Now process the line table and fixup in case edits caused
     * changes in line breaks. If we are breaking on word boundaries,
     * this code checks for moving words to and from lines.
    */
    if (visible) {
      XwTextLineRange lastChangedLine ;
      if (line1) line1-- ;    /* force check for word moving to prev line */
      lastChangedLine =
      UpdateLineTable (ctx
                   , ctx->text.lt.info[line1].position
                   , pos2 + delta
                   , ctx->core.width - ctx->text.leftmargin
                     - ctx->text.rightmargin
                   , line1
                   , TRUE
                   ) ;
      endPos = ctx->text.lt.info[lastChangedLine+1].position ;
    }
    lastpos = GETLASTPOS(ctx);
    if (delta >= lastpos)
      endPos = lastpos;
    if (delta >= lastpos || pos2 >= ctx->text.lt.top)
      _XtTextNeedsUpdating(ctx, updateFrom, endPos);
    return error;
}


/*
 * This routine will display text between two arbitrary source positions.
 * In the event that this span contains highlighted text for the selection, 
 * only that portion will be displayed highlighted.
 */
/*--------------------------------------------------------------------------+*/
static void DisplayText(ctx, pos1, pos2)
/*--------------------------------------------------------------------------+*/
  XwTextEditWidget ctx;
  XwTextPosition pos1, pos2;
  /* it is illegal to call this routine unless there is a valid line table!*/
{
    Position x, y, xlimit, tempx;
    Dimension height;
    int line, i, visible;
    XwTextPosition startPos, endPos, lastpos = GETLASTPOS(ctx);

    if (pos1 < ctx->text.lt.top)
      pos1 = ctx->text.lt.top;
    if (pos2 > lastpos) 
      pos2 = lastpos;
    if (pos1 >= pos2) return;
    visible = LineAndXYForPosition(ctx, pos1, &line, &x, &y);
    if (!visible)
      return;
    startPos = pos1;
    xlimit = ctx->core.width - ctx->text.rightmargin + 1 ;
    height = ctx->text.lt.info[1].y - ctx->text.lt.info[0].y;
    for (i = line; i < ctx->text.lt.lines; i++) {
      endPos = ctx->text.lt.info[i].drawPos + 1;
      if (endPos > pos2)
          endPos = pos2;
      if (endPos > startPos) {
        /*  We know this should not be necessary!!!!
          if (x == ctx->text.leftmargin)
                (*(ctx->text.sink->clearToBackground))(ctx,
                   0, y, ctx->text.leftmargin, height);
          */
          if (startPos >= ctx->text.s.right || endPos <= ctx->text.s.left) {
            (*(ctx->text.sink->display))(ctx, x, y,
                  startPos, endPos, FALSE);
          } else if (startPos >= ctx->text.s.left
                   && endPos <= ctx->text.s.right)
            { (*(ctx->text.sink->display))(ctx, x, y,
                  startPos, endPos, TRUE);
          } else {
            DisplayText(ctx, startPos, ctx->text.s.left);
            DisplayText(ctx, max(startPos, ctx->text.s.left), 
                  min(endPos, ctx->text.s.right));
            DisplayText(ctx, ctx->text.s.right, endPos);
          }
      }
      startPos = ctx->text.lt.info[i + 1].position;
      height = ctx->text.lt.info[i + 1].y - ctx->text.lt.info[i].y;
      tempx = ctx->text.lt.info[i].endX;
        (*(ctx->text.sink->clearToBackground))(ctx,
          tempx, y, xlimit - tempx, height);
      x = ctx->text.leftmargin;
      y = ctx->text.lt.info[i + 1].y;
      if ((endPos == pos2) && (endPos != lastpos))
          break;
    }
}

/*
 * Clear the window to background color.
 */
/*--------------------------------------------------------------------------+*/
static void ClearWindow (ctx)
/*--------------------------------------------------------------------------+*/
  XwTextEditWidget ctx;
{
    (*(ctx->text.sink->clearToBackground))(ctx, 0, 0, ctx->core.width,
                                 ctx->core.height);
}

/*
 * Clear the portion of the window that the text in drawn in, or that is
 * don't clear the margins  
 */
/*--------------------------------------------------------------------------+*/
static void ClearText (ctx)
/*--------------------------------------------------------------------------+*/
  XwTextEditWidget ctx;
{
  register XwTextEditPart *text = (XwTextEditPart *) &(ctx->text);
  (*(text->sink->clearToBackground))
             (ctx, 0, 0, ctx->core.width, ctx->core.height);
}

/*
 * Internal redisplay entire window.
 */
/*--------------------------------------------------------------------------+*/
static void DisplayAllText (w)
/*--------------------------------------------------------------------------+*/
  Widget w;
{
    XwTextEditWidget ctx = (XwTextEditWidget) w;

    if (!XtIsRealized((Widget)ctx)) return;

    ClearText(ctx);
    /* ClearWindow(ctx); */
    /* BuildLineTable(ctx, ctx->text.lt.top); */
    _XtTextNeedsUpdating(ctx, zeroPosition, GETLASTPOS(ctx));
 
}

/*
 * This routine checks to see if the window should be resized (grown or
 * shrunk) or scrolled then text to be painted overflows to the right or
 * the bottom of the window. It is used by the keyboard input routine.
 */
/*--------------------------------------------------------------------------+*/
static void CheckResizeOrOverflow(ctx)
/*--------------------------------------------------------------------------+*/
  XwTextEditWidget ctx;
{
  XwTextLineRange i, nLines ;
  Dimension width;
  XtWidgetGeometry rbox;
  XtGeometryResult reply;
  XwLineTableEntryPtr lp ;
  XwLineTablePtr      lt ;
  XwTextEditPart   *tp ;

  tp = &(ctx->text) ;
  lt = &(tp->lt) ;
  nLines = lt->lines ;
  
  if (tp->grow_state & XwGrowHorizontal)
    { UpdateLineTable ( ctx, lt->top, 0, INFINITE_WIDTH, 0, FALSE) ;
      width = 0 ;
      for (i=0, lp = &(lt->info[0]) ; i < nLines ; i++, lp++)
      { if (width < lp->endX) width = lp->endX ;
      } ;
      width += ctx->text.rightmargin;
      if (width > ctx->core.width)
      { rbox.request_mode = CWWidth;
        rbox.width = width;
        reply = XtMakeGeometryRequest((Widget)ctx, &rbox, &rbox);
        if (reply == XtGeometryAlmost)
          reply = XtMakeGeometryRequest((Widget)ctx, &rbox, NULL);
        /* NOTE: following test is expected to be a fall-through from
           previous.  Should not be an else if. */
        if (reply == XtGeometryYes)
          ctx->core.width = rbox.width;
        else      /* if request not satisfied, disallow future attempts */
          { tp->grow_state &= ~XwGrowHorizontal ;
            UpdateLineTable ( ctx, lt->top, 0, ctx->core.width
                  - ctx->text.leftmargin - ctx->text.rightmargin,
                  0, FALSE);
          }
      }
    } ;
  
  if ((tp->grow_state & XwGrowVertical)
      && ( ! (lt->info[nLines].fit & tfEndText)
        || (lt->info[nLines].drawPos > lt->info[nLines].position))
      )
    { rbox.request_mode = CWHeight;
      rbox.height = (*(ctx->text.sink->maxHeight))
      (ctx, nLines + 1) + tp->topmargin + tp->bottommargin ;
      reply = XtMakeGeometryRequest((Widget)ctx, &rbox, &rbox);
      if (reply == XtGeometryAlmost)
      reply = XtMakeGeometryRequest((Widget)ctx, &rbox, NULL);
      if (reply == XtGeometryYes)
      ctx->core.height = rbox.height;
      else  /* if request not satisfied, disallow future attempts */
      { tp->grow_state &= ~XwGrowVertical ;
      }
    } ;
}

/*
 * This routine processes all "expose region" XEvents. In general, its job
 * is to the best job at minimal re-paint of the text, displayed in the
 * window, that it can.
 */
/*--------------------------------------------------------------------------+*/
static void ProcessExposeRegion(w, event)
/*--------------------------------------------------------------------------+*/
  Widget w;
  XEvent *event;
{
    XwTextEditWidget ctx = (XwTextEditWidget) w;
    XwTextPosition pos1, pos2, resultend;
    int line;
    int x = event->xexpose.x;
    int y = event->xexpose.y;
    int width = event->xexpose.width;
    int height = event->xexpose.height;
    XwLineTableEntryPtr info;

   _XtTextPrepareToUpdate(ctx);
    if (x < ctx->text.leftmargin) /* stomp on caret tracks */
        (*(ctx->text.sink->clearToBackground))(ctx, x, y, width, height);
   /* figure out starting line that was exposed */
    line = LineForPosition(ctx, PositionForXY(ctx, x, y));
    while (line < ctx->text.lt.lines && ctx->text.lt.info[line + 1].y < y)
      line++;
    while (line < ctx->text.lt.lines) {
      info = &(ctx->text.lt.info[line]);
      if (info->y >= y + height)
          break;
      (*(ctx->text.sink->resolve))(ctx, 
                                info->position, info->x,
                          x - info->x, &pos1, &resultend);
      (*(ctx->text.sink->resolve))(ctx, 
                                info->position, info->x,
                          x + width - info->x, &pos2, 
                                &resultend);
      pos2 = (*(ctx->text.source->scan))(ctx->text.source, pos2,
                                 XwstPositions, XwsdRight, 1, TRUE);
      _XtTextNeedsUpdating(ctx, pos1, pos2);
      line++;
    }
    _XtTextExecuteUpdate(ctx);

}

/*
 * This routine does all setup required to syncronize batched screen updates
 */
/*--------------------------------------------------------------------------+*/
static void _XtTextPrepareToUpdate(ctx)
/*--------------------------------------------------------------------------+*/
  XwTextEditWidget ctx;
{

   if ((ctx->text.oldinsert < 0) && ctx->text.update_flag) {
      InsertCursor(ctx, XwisOff);
      ctx->text.numranges = 0;
      ctx->text.showposition = FALSE;
      ctx->text.oldinsert = ctx->text.insertPos;
    }
}


/*
 * This is a private utility routine used by _XtTextExecuteUpdate. It
 * processes all the outstanding update requests and merges update
 * ranges where possible.
 */
/*--------------------------------------------------------------------------+*/
static void FlushUpdate(ctx)
/*--------------------------------------------------------------------------+*/
  XwTextEditWidget ctx;
{
    int     i, w;
    XwTextPosition updateFrom, updateTo;
    while (ctx->text.numranges > 0) {
      updateFrom = ctx->text.updateFrom[0];
      w = 0;
      for (i=1 ; i<ctx->text.numranges ; i++) {
          if (ctx->text.updateFrom[i] < updateFrom) {
            updateFrom = ctx->text.updateFrom[i];
            w = i;
          }
      }
      updateTo = ctx->text.updateTo[w];
      ctx->text.numranges--;
      ctx->text.updateFrom[w] = ctx->text.updateFrom[ctx->text.numranges];
      ctx->text.updateTo[w] = ctx->text.updateTo[ctx->text.numranges];
      for (i=ctx->text.numranges-1 ; i>=0 ; i--) {
          while (ctx->text.updateFrom[i] <= updateTo
               && i < ctx->text.numranges)
            {
            updateTo = ctx->text.updateTo[i];
            ctx->text.numranges--;
            ctx->text.updateFrom[i] =
              ctx->text.updateFrom[ctx->text.numranges];
            ctx->text.updateTo[i] =
              ctx->text.updateTo[ctx->text.numranges];
          }
      }
      DisplayText(ctx, updateFrom, updateTo);
    }
}


/*
 * This is a private utility routine used by _XtTextExecuteUpdate. This routine
 * worries about edits causing new data or the insertion point becoming
 * invisible (off the screen). Currently it always makes it visible by
 * scrolling. It probably needs generalization to allow more options.
 */
/*--------------------------------------------------------------------------+*/
static void _XtTextShowPosition(ctx)
/*--------------------------------------------------------------------------+*/
  XwTextEditWidget ctx;
{
    XwTextPosition top, first, second, insertPos ;
    XwTextPosition lastpos = GETLASTPOS(ctx);
    XwTextEditPart *text = &(ctx->text) ;
    XwLineTablePtr lt = &(text->lt) ;
    short hScroll ;

    /* NOTE: Following code relies on current assumption that
       horizontal scrolling will be enabled only when there is
       only one display line.
       */

    insertPos = text->insertPos ;
    if (   insertPos < lt->top
      || insertPos >= lt->info[lt->lines].position
      || (hScroll = ((text->scroll_state & XwAutoScrollHorizontal)
                   && (insertPos > lt->info[0].drawPos)
                   && ( lt->info[0].drawPos + 1 < lastpos))
          ? 1 : 0 )
      
      )
      {
      if (   lt->lines > 0
          && (insertPos < lt->top 
            || lt->info[lt->lines].position <=  lastpos
            || hScroll)
          ) {
          first = lt->top;
          second = lt->info[1].position;
/*
          if (insertPos < first)
            top = (*(text->source->scan))(
                  text->source, insertPos, XwstEOL,
                  XwsdLeft, 1, FALSE);
          else
            top = (*(text->source->scan))(
                  text->source, insertPos, XwstEOL,
                  XwsdLeft, lt->lines, FALSE);
          BuildLineTable(ctx, top);
          while (insertPos >= lt->info[lt->lines].position) {
            if (lt->info[lt->lines].position > lastpos)
                break;
            BuildLineTable(ctx, lt->info[1].position);
          }
*/
          if (text->scroll_state & XwAutoScrollHorizontal) {
            if ((insertPos > lt->info[0].drawPos) &&
                (lt->info[0].drawPos + 1 < lastpos)) {
                 /* smooth scroll:  scroll by one character at a time */

               XwTextPosition delta = 0 ;
               top = insertPos - (lt->info[0].drawPos
                               - lt->info[0].position) - 1;
               while (insertPos > lt->info[0].drawPos+1) {
                  BuildLineTable (ctx, top += delta) ;
                  delta = (insertPos - top) >> 2 ;
               }
               first = -1 ; /* prevent scroll down by one line */
              }

            else if (insertPos < first) {
                 /* Do the same as above, for traveling to the left */

               XwTextPosition delta = 0 ;
               if (insertPos < 0) insertPos = 0;
               top = insertPos;
               if (top < 0) top = 0;
               BuildLineTable (ctx, top);
               while (insertPos < lt->top) {
                  top -= delta;
                  if (top < 0) top = 0;
                  BuildLineTable (ctx, top);
                  delta = (insertPos - top) >> 2;
               }
               first = -1 ; /* prevent scroll down by one line */
              }
          }

          if (lt->top == second && lt->lines > 1) {
              BuildLineTable(ctx, first);
            _XtTextScroll(ctx, 1);
          } else if (lt->info[1].position == first && lt->lines > 1) {
            BuildLineTable(ctx, first);
            _XtTextScroll(ctx, -1);
          } else {
            text->numranges = 0;
            if (lt->top != first)
                DisplayAllText(ctx);
          }
      }
    }
}



/*
 * This routine causes all batched screen updates to be performed
 */
/*--------------------------------------------------------------------------+*/
static void _XtTextExecuteUpdate(ctx)
/*--------------------------------------------------------------------------+*/
  XwTextEditWidget ctx;
{
    if ((ctx->text.oldinsert >= 0) && ctx->text.update_flag) {
      if (ctx->text.oldinsert != ctx->text.insertPos
        || ctx->text.showposition)
      _XtTextShowPosition(ctx);
      FlushUpdate(ctx);
      InsertCursor(ctx, XwisOn);
      ctx->text.oldinsert = -1;
    }
}

Generated by  Doxygen 1.6.0   Back to index