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

📄 fl_text_display.cxx

📁 SRI international 发布的OAA框架软件
💻 CXX
📖 第 1 页 / 共 5 页
字号:
    wrapped_line_counter(buffer(), startPos, buffer()->length(),
    	    nLines, startPosIsLineStart, 0, &retPos, &retLines, &retLineStart,
    	    &retLineEnd);
    return retPos;
}

/*
** Same as BufEndOfLine, but takes in to account line breaks when wrapping
** is turned on.  If the caller knows that startPos is at a line start, it
** can pass "startPosIsLineStart" as True to make the call more efficient
** by avoiding the additional step of scanning back to the last newline.
**
** Note that the definition of the end of a line is less clear when continuous
** wrap is on.  With continuous wrap off, it's just a pointer to the newline
** that ends the line.  When it's on, it's the character beyond the last
** DISPLAYABLE character on the line, where a whitespace character which has
** been "converted" to a newline for wrapping is not considered displayable.
** Also note that, a line can be wrapped at a non-whitespace character if the
** line had no whitespace.  In this case, this routine returns a pointer to
** the start of the next line.  This is also consistent with the model used by
** visLineLength.
*/
int Fl_Text_Display::line_end(int pos, bool startPosIsLineStart) {
    int retLines, retPos, retLineStart, retLineEnd;
    
    /* If we're not wrapping use more efficien BufEndOfLine */
    if (!mContinuousWrap)
    	return buffer()->line_end(pos);
    
    if (pos == buffer()->length())
    	return pos;
    wrapped_line_counter(buffer(), pos, buffer()->length(), 1,
    	    startPosIsLineStart, 0, &retPos, &retLines, &retLineStart,
	    &retLineEnd);
    return retLineEnd;
}

/*
** Same as BufStartOfLine, but returns the character after last wrap point
** rather than the last newline.
*/
int Fl_Text_Display::line_start(int pos) {
    int retLines, retPos, retLineStart, retLineEnd;
    
    /* If we're not wrapping, use the more efficient BufStartOfLine */
    if (!mContinuousWrap)
    	return buffer()->line_start(pos);

    wrapped_line_counter(buffer(), buffer()->line_start(pos), pos, INT_MAX, true, 0,
			 &retPos, &retLines, &retLineStart, &retLineEnd);
    return retLineStart;
}

/*
** Same as BufCountBackwardNLines, but takes in to account line breaks when
** wrapping is turned on.
*/
int Fl_Text_Display::rewind_lines(int startPos, int nLines) {
    Fl_Text_Buffer *buf = buffer();
    int pos, lineStart, retLines, retPos, retLineStart, retLineEnd;
    
    /* If we're not wrapping, use the more efficient BufCountBackwardNLines */
    if (!mContinuousWrap)
    	return buf->rewind_lines(startPos, nLines);

    pos = startPos;
    while (true) {
	lineStart = buf->line_start(pos);
	wrapped_line_counter(buf, lineStart, pos, INT_MAX,
	    	true, 0, &retPos, &retLines, &retLineStart, &retLineEnd);
	if (retLines > nLines)
    	    return skip_lines(lineStart, retLines-nLines,
    	    	    true);
    	nLines -= retLines;
    	pos = lineStart - 1;
    	if (pos < 0)
    	    return 0;
    	nLines -= 1;
    }
}

void Fl_Text_Display::next_word() {
  int pos = insert_position();
  while ( pos < buffer()->length() && (
            isalnum( buffer()->character( pos ) ) || buffer()->character( pos ) == '_' ) ) {
    pos++;
  }
  while ( pos < buffer()->length() && !( isalnum( buffer()->character( pos ) ) || buffer()->character( pos ) == '_' ) ) {
    pos++;
  }

  insert_position( pos );
}

void Fl_Text_Display::previous_word() {
  int pos = insert_position();
  pos--;
  while ( pos && !( isalnum( buffer()->character( pos ) ) || buffer()->character( pos ) == '_' ) ) {
    pos--;
  }
  while ( pos && ( isalnum( buffer()->character( pos ) ) || buffer()->character( pos ) == '_' ) ) {
    pos--;
  }
  if ( !( isalnum( buffer()->character( pos ) ) || buffer()->character( pos ) == '_' ) ) pos++;

  insert_position( pos );
}

/*
** Callback attached to the text buffer to receive delete information before
** the modifications are actually made.
*/
void Fl_Text_Display::buffer_predelete_cb(int pos, int nDeleted, void *cbArg) {
    Fl_Text_Display *textD = (Fl_Text_Display *)cbArg;
    if (textD->mContinuousWrap && 
        (textD->mFixedFontWidth == -1 || textD->mModifyingTabDistance))
	/* Note: we must perform this measurement, even if there is not a
	   single character deleted; the number of "deleted" lines is the
	   number of visual lines spanned by the real line in which the 
	   modification takes place. 
	   Also, a modification of the tab distance requires the same
	   kind of calculations in advance, even if the font width is "fixed",
	   because when the width of the tab characters changes, the layout 
	   of the text may be completely different. */
	textD->measure_deleted_lines(pos, nDeleted);
    else
	textD->mSuppressResync = 0; /* Probably not needed, but just in case */
}

/*
** Callback attached to the text buffer to receive modification information
*/
void Fl_Text_Display::buffer_modified_cb( int pos, int nInserted, int nDeleted,
    int nRestyled, const char *deletedText, void *cbArg ) {
  int linesInserted, linesDeleted, startDispPos, endDispPos;
  Fl_Text_Display *textD = ( Fl_Text_Display * ) cbArg;
  Fl_Text_Buffer *buf = textD->mBuffer;
  int oldFirstChar = textD->mFirstChar;
  int scrolled, origCursorPos = textD->mCursorPos;
  int wrapModStart, wrapModEnd;

  /* buffer modification cancels vertical cursor motion column */
  if ( nInserted != 0 || nDeleted != 0 )
    textD->mCursorPreferredCol = -1;

    /* Count the number of lines inserted and deleted, and in the case
       of continuous wrap mode, how much has changed */
    if (textD->mContinuousWrap) {
    	textD->find_wrap_range(deletedText, pos, nInserted, nDeleted,
    	    	&wrapModStart, &wrapModEnd, &linesInserted, &linesDeleted);
    } else {
   linesInserted = nInserted == 0 ? 0 :
                  buf->count_lines( pos, pos + nInserted );
   linesDeleted = nDeleted == 0 ? 0 : countlines( deletedText );
    }

  /* Update the line starts and mTopLineNum */
  if ( nInserted != 0 || nDeleted != 0 ) {
   if (textD->mContinuousWrap) {
     textD->update_line_starts( wrapModStart, wrapModEnd-wrapModStart,
                     nDeleted + pos-wrapModStart + (wrapModEnd-(pos+nInserted)),
                     linesInserted, linesDeleted, &scrolled );
   } else {
     textD->update_line_starts( pos, nInserted, nDeleted, linesInserted,
                               linesDeleted, &scrolled );
   }
  } else
    scrolled = 0;

    /* If we're counting non-wrapped lines as well, maintain the absolute
       (non-wrapped) line number of the text displayed */
    if (textD->maintaining_absolute_top_line_number() &&
        (nInserted != 0 || nDeleted != 0)) {
	if (pos + nDeleted < oldFirstChar)
	    textD->mAbsTopLineNum += buf->count_lines(pos, pos + nInserted) -
		    countlines(deletedText);
	else if (pos < oldFirstChar)
	    textD->reset_absolute_top_line_number();
    }    	    

  /* Update the line count for the whole buffer */
  textD->mNBufferLines += linesInserted - linesDeleted;

  /* Update the cursor position */
  if ( textD->mCursorToHint != NO_HINT ) {
    textD->mCursorPos = textD->mCursorToHint;
    textD->mCursorToHint = NO_HINT;
  } else if ( textD->mCursorPos > pos ) {
    if ( textD->mCursorPos < pos + nDeleted )
      textD->mCursorPos = pos;
    else
      textD->mCursorPos += nInserted - nDeleted;
  }

  // refigure scrollbars & stuff
  textD->resize(textD->x(), textD->y(), textD->w(), textD->h());

  // don't need to do anything else if not visible?
  if (!textD->visible_r()) return;

  /* If the changes caused scrolling, re-paint everything and we're done. */
  if ( scrolled ) {
    textD->damage(FL_DAMAGE_EXPOSE);
    if ( textD->mStyleBuffer )   /* See comments in extendRangeForStyleMods */
      textD->mStyleBuffer->primary_selection()->selected(0);
    return;
  }

  /* If the changes didn't cause scrolling, decide the range of characters
     that need to be re-painted.  Also if the cursor position moved, be
     sure that the redisplay range covers the old cursor position so the
     old cursor gets erased, and erase the bits of the cursor which extend
     beyond the left and right edges of the text. */
  startDispPos = textD->mContinuousWrap ? wrapModStart : pos;
  if ( origCursorPos == startDispPos && textD->mCursorPos != startDispPos )
    startDispPos = min( startDispPos, origCursorPos - 1 );
  if ( linesInserted == linesDeleted ) {
    if ( nInserted == 0 && nDeleted == 0 )
      endDispPos = pos + nRestyled;
    else {
      endDispPos = textD->mContinuousWrap ? wrapModEnd :
            buf->line_end( pos + nInserted ) + 1;
      // CET - FIXME      if ( origCursorPos >= startDispPos &&
      //                ( origCursorPos <= endDispPos || endDispPos == buf->length() ) )
    }

	if (linesInserted > 1) textD->draw_line_numbers(false);
  } else {
    endDispPos = textD->mLastChar + 1;
    // CET - FIXME   if ( origCursorPos >= pos )
        /* If more than one line is inserted/deleted, a line break may have
           been inserted or removed in between, and the line numbers may
           have changed. If only one line is altered, line numbers cannot
           be affected (the insertion or removal of a line break always 
           results in at least two lines being redrawn). */
	textD->draw_line_numbers(false);
  }

  /* If there is a style buffer, check if the modification caused additional
     changes that need to be redisplayed.  (Redisplaying separately would
     cause double-redraw on almost every modification involving styled
     text).  Extend the redraw range to incorporate style changes */
  if ( textD->mStyleBuffer )
    textD->extend_range_for_styles( &startDispPos, &endDispPos );

  /* Redisplay computed range */
  textD->redisplay_range( startDispPos, endDispPos );
}

/*
** In continuous wrap mode, internal line numbers are calculated after
** wrapping.  A separate non-wrapped line count is maintained when line
** numbering is turned on.  There is some performance cost to maintaining this
** line count, so normally absolute line numbers are not tracked if line
** numbering is off.  This routine allows callers to specify that they still
** want this line count maintained (for use via TextDPosToLineAndCol).
** More specifically, this allows the line number reported in the statistics
** line to be calibrated in absolute lines, rather than post-wrapped lines.
*/
void Fl_Text_Display::maintain_absolute_top_line_number(int state) {
    mNeedAbsTopLineNum = state;
    reset_absolute_top_line_number();
}

/*
** Returns the absolute (non-wrapped) line number of the first line displayed.
** Returns 0 if the absolute top line number is not being maintained.
*/
int Fl_Text_Display::get_absolute_top_line_number() {
    if (!mContinuousWrap)
	return mTopLineNum;
    if (maintaining_absolute_top_line_number())
	return mAbsTopLineNum;
    return 0;
}

/*
** Re-calculate absolute top line number for a change in scroll position.
*/
void Fl_Text_Display::absolute_top_line_number(int oldFirstChar) {
    if (maintaining_absolute_top_line_number()) {
	if (mFirstChar < oldFirstChar)
	    mAbsTopLineNum -= buffer()->count_lines(mFirstChar, oldFirstChar);
	else
	    mAbsTopLineNum += buffer()->count_lines(oldFirstChar, mFirstChar);
    }
}

/*
** Return true if a separate absolute top line number is being maintained
** (for displaying line numbers or showing in the statistics line).
*/
int Fl_Text_Display::maintaining_absolute_top_line_number() {
    return mContinuousWrap &&
	    (mLineNumWidth != 0 || mNeedAbsTopLineNum);
}

/*
** Count lines from the beginning of the buffer to reestablish the
** absolute (non-wrapped) top line number.  If mode is not continuous wrap,
** or the number is not being maintained, does nothing.
*/
void Fl_Text_Display::reset_absolute_top_line_number() {
    mAbsTopLineNum = 1;
    absolute_top_line_number(0);
}

/*
** Find the line number of position "pos" relative to the first line of
** displayed text. Returns 0 if the line is not displayed.
*/
int Fl_Text_Display::position_to_line( int pos, int *lineNum ) {
  int i;

  *lineNum = 0;
  if ( pos < mFirstChar ) return 0;
  if ( pos > mLastChar ) {
    if ( empty_vlines() ) {
      if ( mLastChar < mBuffer->length() ) {
        if ( !position_to_line( mLastChar, lineNum ) ) {
          Fl::error("Fl_Text_Display::position_to_line(): Consistency check ptvl failed");
          return 0;
        }
        return ++( *lineNum ) <= mNVisibleLines - 1;
      } else {
        position_to_line( mLastChar - 1, lineNum );
        return 1;
      }
    }
    return 0;
  }

  for ( i = mNVisibleLines - 1; i >= 0; i-- ) {
    if ( mLineStarts[ i ] != -1 && pos >= mLineStarts[ i ] ) {
      *lineNum = i;
      return 1;
    }
  }
  return 0;   /* probably never be reached */
}

/*
** Draw the text on a single line represented by "visLineNum" (the
** number of lines down from the top of the display), limited by
** "leftClip" and "rightClip" window coordinates and "leftCharIndex" and
** "rightCharIndex" character positions (not including the character at
** position "rightCharIndex").

⌨️ 快捷键说明

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