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

📄 fl_text_display.cxx

📁 SRI international 发布的OAA框架软件
💻 CXX
📖 第 1 页 / 共 5 页
字号:
     padding to make up for removed control characters at the end */
  indent = startIndent;
  for ( p = startPos; ; p++ ) {
    if ( p == buf->length() )
      break;
    ch = buf->character( p );
    if ( ch == '\n' )
      break;
    indent += Fl_Text_Buffer::character_width( ch, indent, buf->tab_distance(), buf->null_substitution_character() );
    if ( indent == endIndent ) {
      p++;
      break;
    } else if ( indent > endIndent ) {
      if ( ch != '\t' ) {
        p++;
        paddedText = new char [ textLen + FL_TEXT_MAX_EXP_CHAR_LEN + 1 ];
        strcpy( paddedText, text );
        for ( i = 0; i < indent - endIndent; i++ )
          paddedText[ textLen + i ] = ' ';
        paddedText[ textLen + i ] = '\0';
      }
      break;
    }
  }
  endPos = p;

  mCursorToHint = startPos + textLen;
  buf->replace( startPos, endPos, paddedText == NULL ? text : paddedText );
  mCursorToHint = NO_HINT;
  if ( paddedText != NULL )
    delete [] paddedText;
}

/*
** Translate a buffer text position to the XY location where the top left
** of the cursor would be positioned to point to that character.  Returns
** 0 if the position is not displayed because it is VERTICALLY out
** of view.  If the position is horizontally out of view, returns the
** X coordinate where the position would be if it were visible.
*/

int Fl_Text_Display::position_to_xy( int pos, int* X, int* Y ) {
  int charIndex, lineStartPos, fontHeight, lineLen;
  int visLineNum, charLen, outIndex, xStep, charStyle;
  char expandedChar[ FL_TEXT_MAX_EXP_CHAR_LEN ];
  const char *lineStr;

//  printf("position_to_xy(pos=%d, X=%p, Y=%p)\n", pos, X, Y);

  /* If position is not displayed, return false */
  if (pos < mFirstChar || (pos > mLastChar && !empty_vlines())) {
//    printf("    returning 0\n"
//           "    mFirstChar=%d, mLastChar=%d, empty_vlines()=0\n",
//	   mFirstChar, mLastChar);
    return 0;
  }

  /* Calculate Y coordinate */
  if (!position_to_line(pos, &visLineNum)) {
//    puts("    returning 0\n"
//         "    position_to_line()=0");
    return 0;
  }

  if (visLineNum < 0 || visLineNum > mNBufferLines) {
//    printf("    returning 0\n"
//           "    visLineNum=%d, mNBufferLines=%d\n",
//	   visLineNum, mNBufferLines);
    return 0;
  }

  fontHeight = mMaxsize;
  *Y = text_area.y + visLineNum * fontHeight;

  /* Get the text, length, and  buffer position of the line. If the position
     is beyond the end of the buffer and should be at the first position on
     the first empty line, don't try to get or scan the text  */
  lineStartPos = mLineStarts[visLineNum];
  if ( lineStartPos == -1 ) {
    *X = text_area.x - mHorizOffset;
    return 1;
  }
  lineLen = vline_length( visLineNum );
  lineStr = mBuffer->text_range( lineStartPos, lineStartPos + lineLen );

  /* Step through character positions from the beginning of the line
     to "pos" to calculate the X coordinate */
  xStep = text_area.x - mHorizOffset;
  outIndex = 0;
  for ( charIndex = 0; charIndex < lineLen && charIndex < pos - lineStartPos; charIndex++ ) {
    charLen = Fl_Text_Buffer::expand_character( lineStr[ charIndex ], outIndex, expandedChar,
              mBuffer->tab_distance(), mBuffer->null_substitution_character() );
    charStyle = position_style( lineStartPos, lineLen, charIndex,
                                outIndex );
    xStep += string_width( expandedChar, charLen, charStyle );
    outIndex += charLen;
  }
  *X = xStep;
  delete [] (char *)lineStr;
  return 1;
}

/*
** Find the line number of position "pos".  Note: this only works for
** displayed lines.  If the line is not displayed, the function returns
** 0 (without the mLineStarts array it could turn in to very long
** calculation involving scanning large amounts of text in the buffer).
** If continuous wrap mode is on, returns the absolute line number (as opposed
** to the wrapped line number which is used for scrolling).
*/
int Fl_Text_Display::position_to_linecol( int pos, int* lineNum, int* column ) {
  int retVal;
    
    /* In continuous wrap mode, the absolute (non-wrapped) line count is
       maintained separately, as needed.  Only return it if we're actually
       keeping track of it and pos is in the displayed text */
    if (mContinuousWrap) {
	if (!maintaining_absolute_top_line_number() ||
       pos < mFirstChar || pos > mLastChar)
	    return 0;
	*lineNum = mAbsTopLineNum + buffer()->count_lines(mFirstChar, pos);
	*column
     = buffer()->count_displayed_characters(buffer()->line_start(pos), pos);
	return 1;
    }

  retVal = position_to_line( pos, lineNum );
  if ( retVal ) {
    *column = mBuffer->count_displayed_characters(
                mLineStarts[ *lineNum ], pos );
    *lineNum += mTopLineNum;
  }
  return retVal;
}

/*
** Return 1 if position (X, Y) is inside of the primary Fl_Text_Selection
*/
int Fl_Text_Display::in_selection( int X, int Y ) {
  int row, column, pos = xy_to_position( X, Y, CHARACTER_POS );
  Fl_Text_Buffer *buf = mBuffer;

  xy_to_rowcol( X, Y, &row, &column, CHARACTER_POS );
  if (range_touches_selection(buf->primary_selection(), mFirstChar, mLastChar))
    column = wrapped_column(row, column);
  return buf->primary_selection()->includes(pos, buf->line_start( pos ), column);
}

/*
** Correct a column number based on an unconstrained position (as returned by
** TextDXYToUnconstrainedPosition) to be relative to the last actual newline
** in the buffer before the row and column position given, rather than the
** last line start created by line wrapping.  This is an adapter
** for rectangular selections and code written before continuous wrap mode,
** which thinks that the unconstrained column is the number of characters
** from the last newline.  Obviously this is time consuming, because it
** invloves character re-counting.
*/
int Fl_Text_Display::wrapped_column(int row, int column) {
    int lineStart, dispLineStart;
    
    if (!mContinuousWrap || row < 0 || row > mNVisibleLines)
    	return column;
    dispLineStart = mLineStarts[row];
    if (dispLineStart == -1)
    	return column;
    lineStart = buffer()->line_start(dispLineStart);
    return column
		 + buffer()->count_displayed_characters(lineStart, dispLineStart);
}

/*
** Correct a row number from an unconstrained position (as returned by
** TextDXYToUnconstrainedPosition) to a straight number of newlines from the
** top line of the display.  Because rectangular selections are based on
** newlines, rather than display wrapping, and anywhere a rectangular selection
** needs a row, it needs it in terms of un-wrapped lines.
*/
int Fl_Text_Display::wrapped_row(int row) {
    if (!mContinuousWrap || row < 0 || row > mNVisibleLines)
    	return row;
    return buffer()->count_lines(mFirstChar, mLineStarts[row]);
}

/*
** Scroll the display to bring insertion cursor into view.
**
** Note: it would be nice to be able to do this without counting lines twice
** (scroll_() counts them too) and/or to count from the most efficient
** starting point, but the efficiency of this routine is not as important to
** the overall performance of the text display.
*/
void Fl_Text_Display::display_insert() {
  int hOffset, topLine, X, Y;
  hOffset = mHorizOffset;
  topLine = mTopLineNum;

//	FIXME: I don't understand this well enough to know if it is correct
//	       it is different than nedit 5.3
  if (insert_position() < mFirstChar) {
    topLine -= count_lines(insert_position(), mFirstChar, false);
  } else if (mLineStarts[mNVisibleLines-2] != -1) {
    int lastChar = buffer()->line_end(mLineStarts[mNVisibleLines-2]);
    if (insert_position() >= lastChar)
      topLine
        += count_lines(lastChar - (wrap_uses_character(mLastChar) ? 0 : 1),
                        insert_position(), false);
  }

  /* Find the new setting for horizontal offset (this is a bit ungraceful).
     If the line is visible, just use PositionToXY to get the position
     to scroll to, otherwise, do the vertical scrolling first, then the
     horizontal */
  if (!position_to_xy( mCursorPos, &X, &Y )) {
    scroll_(topLine, hOffset);
    if (!position_to_xy( mCursorPos, &X, &Y ))
      return;   /* Give up, it's not worth it (but why does it fail?) */
  }
  if (X > text_area.x + text_area.w)
    hOffset += X-(text_area.x + text_area.w);
  else if (X < text_area.x)
    hOffset += X-text_area.x;

  /* Do the scroll */
  if (topLine != mTopLineNum || hOffset != mHorizOffset)
    scroll_(topLine, hOffset);
}

void Fl_Text_Display::show_insert_position() {
  display_insert_position_hint = 1;
  resize(x(), y(), w(), h());
}

/*
** Cursor movement functions
*/
int Fl_Text_Display::move_right() {
  if ( mCursorPos >= mBuffer->length() )
    return 0;
  insert_position( mCursorPos + 1 );
  return 1;
}

int Fl_Text_Display::move_left() {
  if ( mCursorPos <= 0 )
    return 0;
  insert_position( mCursorPos - 1 );
  return 1;
}

int Fl_Text_Display::move_up() {
  int lineStartPos, column, prevLineStartPos, newPos, visLineNum;

  /* Find the position of the start of the line.  Use the line starts array
     if possible */
  if ( position_to_line( mCursorPos, &visLineNum ) )
    lineStartPos = mLineStarts[ visLineNum ];
  else {
    lineStartPos = buffer()->line_start( mCursorPos );
    visLineNum = -1;
  }
  if ( lineStartPos == 0 )
    return 0;

  /* Decide what column to move to, if there's a preferred column use that */
  column = mCursorPreferredCol >= 0 ? mCursorPreferredCol :
           mBuffer->count_displayed_characters( lineStartPos, mCursorPos );

  /* count forward from the start of the previous line to reach the column */
  if ( visLineNum != -1 && visLineNum != 0 )
    prevLineStartPos = mLineStarts[ visLineNum - 1 ];
  else
    prevLineStartPos = buffer()->rewind_lines( lineStartPos, 1 );
  newPos = mBuffer->skip_displayed_characters( prevLineStartPos, column );
    if (mContinuousWrap)
    	newPos = min(newPos, line_end(prevLineStartPos, true));

  /* move the cursor */
  insert_position( newPos );

  /* if a preferred column wasn't aleady established, establish it */
  mCursorPreferredCol = column;
  return 1;
}

int Fl_Text_Display::move_down() {
  int lineStartPos, column, nextLineStartPos, newPos, visLineNum;

  if ( mCursorPos == mBuffer->length() )
    return 0;
  if ( position_to_line( mCursorPos, &visLineNum ) )
    lineStartPos = mLineStarts[ visLineNum ];
  else {
    lineStartPos = buffer()->line_start( mCursorPos );
    visLineNum = -1;
  }
  column = mCursorPreferredCol >= 0 ? mCursorPreferredCol :
           mBuffer->count_displayed_characters( lineStartPos, mCursorPos );
  nextLineStartPos = skip_lines( lineStartPos, 1, true );
  newPos = mBuffer->skip_displayed_characters( nextLineStartPos, column );
    if (mContinuousWrap)
    	newPos = min(newPos, line_end(nextLineStartPos, true));

  insert_position( newPos );
  mCursorPreferredCol = column;
  return 1;
}

/*
** Same as BufCountLines, but takes in to account wrapping if 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.
*/
int Fl_Text_Display::count_lines(int startPos, int endPos,
    	bool startPosIsLineStart) {
    int retLines, retPos, retLineStart, retLineEnd;
    
    /* If we're not wrapping use simple (and more efficient) BufCountLines */
    if (!mContinuousWrap)
    	return buffer()->count_lines(startPos, endPos);
    
    wrapped_line_counter(buffer(), startPos, endPos, INT_MAX,
	    startPosIsLineStart, 0, &retPos, &retLines, &retLineStart,
	    &retLineEnd);
    return retLines;
}

/*
** Same as BufCountForwardNLines, 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.
*/
int Fl_Text_Display::skip_lines(int startPos, int nLines,
    bool startPosIsLineStart) {
    int retLines, retPos, retLineStart, retLineEnd;
    
    /* if we're not wrapping use more efficient BufCountForwardNLines */
    if (!mContinuousWrap)
    	return buffer()->skip_lines(startPos, nLines);
    
    /* wrappedLineCounter can't handle the 0 lines case */
    if (nLines == 0)
    	return startPos;
    
    /* use the common line counting routine to count forward */

⌨️ 快捷键说明

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