📄 fl_text_display.cxx
字号:
*/
void Fl_Text_Display::draw_vline(int visLineNum, int leftClip, int rightClip,
int leftCharIndex, int rightCharIndex) {
Fl_Text_Buffer * buf = mBuffer;
int i, X, Y, startX, charIndex, lineStartPos, lineLen, fontHeight;
int stdCharWidth, charWidth, startIndex, charStyle, style;
int charLen, outStartIndex, outIndex;
int dispIndexOffset;
char expandedChar[ FL_TEXT_MAX_EXP_CHAR_LEN ], outStr[ MAX_DISP_LINE_LEN ];
char *outPtr;
const char *lineStr;
// printf("draw_vline(visLineNum=%d, leftClip=%d, rightClip=%d, leftCharIndex=%d, rightCharIndex=%d)\n",
// visLineNum, leftClip, rightClip, leftCharIndex, rightCharIndex);
// printf("nNVisibleLines=%d\n", mNVisibleLines);
/* If line is not displayed, skip it */
if ( visLineNum < 0 || visLineNum >= mNVisibleLines )
return;
/* Calculate Y coordinate of the string to draw */
fontHeight = mMaxsize;
Y = text_area.y + visLineNum * fontHeight;
/* Get the text, length, and buffer position of the line to display */
lineStartPos = mLineStarts[ visLineNum ];
// printf("lineStartPos=%d\n", lineStartPos);
if ( lineStartPos == -1 ) {
lineLen = 0;
lineStr = NULL;
} else {
lineLen = vline_length( visLineNum );
lineStr = buf->text_range( lineStartPos, lineStartPos + lineLen );
}
/* Space beyond the end of the line is still counted in units of characters
of a standardized character width (this is done mostly because style
changes based on character position can still occur in this region due
to rectangular Fl_Text_Selections). stdCharWidth must be non-zero to
prevent a potential infinite loop if X does not advance */
stdCharWidth = TMPFONTWIDTH; //mFontStruct->max_bounds.width;
if ( stdCharWidth <= 0 ) {
Fl::error("Fl_Text_Display::draw_vline(): bad font measurement");
free((void *)lineStr);
return;
}
/* Shrink the clipping range to the active display area */
leftClip = max( text_area.x, leftClip );
rightClip = min( rightClip, text_area.x + text_area.w );
/* Rectangular Fl_Text_Selections are based on "real" line starts (after
a newline or start of buffer). Calculate the difference between the
last newline position and the line start we're using. Since scanning
back to find a newline is expensive, only do so if there's actually a
rectangular Fl_Text_Selection which needs it */
if (mContinuousWrap && (range_touches_selection(buf->primary_selection(),
lineStartPos, lineStartPos + lineLen) || range_touches_selection(
buf->secondary_selection(), lineStartPos, lineStartPos + lineLen) ||
range_touches_selection(buf->highlight_selection(), lineStartPos,
lineStartPos + lineLen))) {
dispIndexOffset = buf->count_displayed_characters(
buf->line_start(lineStartPos), lineStartPos);
} else
dispIndexOffset = 0;
/* Step through character positions from the beginning of the line (even if
that's off the left edge of the displayed area) to find the first
character position that's not clipped, and the X coordinate for drawing
that character */
X = text_area.x - mHorizOffset;
outIndex = 0;
for ( charIndex = 0; ; charIndex++ ) {
charLen = charIndex >= lineLen ? 1 :
Fl_Text_Buffer::expand_character( lineStr[ charIndex ], outIndex,
expandedChar, buf->tab_distance(), buf->null_substitution_character() );
style = position_style( lineStartPos, lineLen, charIndex,
outIndex + dispIndexOffset );
charWidth = charIndex >= lineLen ? stdCharWidth :
string_width( expandedChar, charLen, style );
if ( X + charWidth >= leftClip && charIndex >= leftCharIndex ) {
startIndex = charIndex;
outStartIndex = outIndex;
startX = X;
break;
}
X += charWidth;
outIndex += charLen;
}
/* Scan character positions from the beginning of the clipping range, and
draw parts whenever the style changes (also note if the cursor is on
this line, and where it should be drawn to take advantage of the x
position which we've gone to so much trouble to calculate) */
outPtr = outStr;
outIndex = outStartIndex;
X = startX;
for ( charIndex = startIndex; charIndex < rightCharIndex; charIndex++ ) {
charLen = charIndex >= lineLen ? 1 :
Fl_Text_Buffer::expand_character( lineStr[ charIndex ], outIndex, expandedChar,
buf->tab_distance(), buf->null_substitution_character() );
charStyle = position_style( lineStartPos, lineLen, charIndex,
outIndex + dispIndexOffset );
for ( i = 0; i < charLen; i++ ) {
if ( i != 0 && charIndex < lineLen && lineStr[ charIndex ] == '\t' )
charStyle = position_style( lineStartPos, lineLen,
charIndex, outIndex + dispIndexOffset );
if ( charStyle != style ) {
draw_string( style, startX, Y, X, outStr, outPtr - outStr );
outPtr = outStr;
startX = X;
style = charStyle;
}
if ( charIndex < lineLen ) {
*outPtr = expandedChar[ i ];
charWidth = string_width( &expandedChar[ i ], 1, charStyle );
} else
charWidth = stdCharWidth;
outPtr++;
X += charWidth;
outIndex++;
}
if ( outPtr - outStr + FL_TEXT_MAX_EXP_CHAR_LEN >= MAX_DISP_LINE_LEN || X >= rightClip )
break;
}
/* Draw the remaining style segment */
draw_string( style, startX, Y, X, outStr, outPtr - outStr );
/* Draw the cursor if part of it appeared on the redisplayed part of
this line. Also check for the cases which are not caught as the
line is scanned above: when the cursor appears at the very end
of the redisplayed section. */
/* CET - FIXME
if ( mCursorOn )
{
if ( hasCursor )
draw_cursor( cursorX, Y );
else if ( charIndex < lineLen && ( lineStartPos + charIndex + 1 == cursorPos )
&& X == rightClip )
{
if ( cursorPos >= buf->length() )
draw_cursor( X - 1, Y );
else
{
draw_cursor( X - 1, Y );
}
}
}
*/
if ( lineStr != NULL )
free((void *)lineStr);
}
/*
** Draw a string or blank area according to parameter "style", using the
** appropriate colors and drawing method for that style, with top left
** corner at X, y. If style says to draw text, use "string" as source of
** characters, and draw "nChars", if style is FILL, erase
** rectangle where text would have drawn from X to toX and from Y to
** the maximum Y extent of the current font(s).
*/
void Fl_Text_Display::draw_string( int style, int X, int Y, int toX,
const char *string, int nChars ) {
const Style_Table_Entry * styleRec;
/* Draw blank area rather than text, if that was the request */
if ( style & FILL_MASK ) {
clear_rect( style, X, Y, toX - X, mMaxsize );
return;
}
/* Set font, color, and gc depending on style. For normal text, GCs
for normal drawing, or drawing within a Fl_Text_Selection or highlight are
pre-allocated and pre-configured. For syntax highlighting, GCs are
configured here, on the fly. */
Fl_Font font = textfont();
int fsize = textsize();
Fl_Color foreground;
Fl_Color background;
if ( style & STYLE_LOOKUP_MASK ) {
int si = (style & STYLE_LOOKUP_MASK) - 'A';
if (si < 0) si = 0;
else if (si >= mNStyles) si = mNStyles - 1;
styleRec = mStyleTable + si;
font = styleRec->font;
fsize = styleRec->size;
if ( style & (HIGHLIGHT_MASK | PRIMARY_MASK) ) {
background = selection_color();
} else background = color();
foreground = fl_contrast(styleRec->color, background);
} else if ( style & (HIGHLIGHT_MASK | PRIMARY_MASK) ) {
background = selection_color();
foreground = fl_contrast(textcolor(), background);
} else {
foreground = textcolor();
background = color();
}
fl_color( background );
fl_rectf( X, Y, toX - X, mMaxsize );
fl_color( foreground );
fl_font( font, fsize );
fl_draw( string, nChars, X, Y + mMaxsize - fl_descent());
// CET - FIXME
/* If any space around the character remains unfilled (due to use of
different sized fonts for highlighting), fill in above or below
to erase previously drawn characters */
/*
if (fs->ascent < mAscent)
clear_rect( style, X, Y, toX - X, mAscent - fs->ascent);
if (fs->descent < mDescent)
clear_rect( style, X, Y + mAscent + fs->descent, toX - x,
mDescent - fs->descent);
*/
/* Underline if style is secondary Fl_Text_Selection */
/*
if (style & SECONDARY_MASK)
XDrawLine(XtDisplay(mW), XtWindow(mW), gc, x,
y + mAscent, toX - 1, Y + fs->ascent);
*/
}
/*
** Clear a rectangle with the appropriate background color for "style"
*/
void Fl_Text_Display::clear_rect( int style, int X, int Y,
int width, int height ) {
/* A width of zero means "clear to end of window" to XClearArea */
if ( width == 0 )
return;
if ( style & HIGHLIGHT_MASK ) {
fl_color( fl_contrast(textcolor(), color()) );
fl_rectf( X, Y, width, height );
} else if ( style & PRIMARY_MASK ) {
fl_color( FL_SELECTION_COLOR );
fl_rectf( X, Y, width, height );
} else {
fl_color( color() );
fl_rectf( X, Y, width, height );
}
}
/*
** Draw a cursor with top center at X, y.
*/
void Fl_Text_Display::draw_cursor( int X, int Y ) {
typedef struct {
int x1, y1, x2, y2;
}
Segment;
Segment segs[ 5 ];
int left, right, cursorWidth, midY;
// int fontWidth = mFontStruct->min_bounds.width, nSegs = 0;
int fontWidth = TMPFONTWIDTH; // CET - FIXME
int nSegs = 0;
int fontHeight = mMaxsize;
int bot = Y + fontHeight - 1;
if ( X < text_area.x - 1 || X > text_area.x + text_area.w )
return;
/* For cursors other than the block, make them around 2/3 of a character
width, rounded to an even number of pixels so that X will draw an
odd number centered on the stem at x. */
cursorWidth = 4; //(fontWidth/3) * 2;
left = X - cursorWidth / 2;
right = left + cursorWidth;
/* Create segments and draw cursor */
if ( mCursorStyle == CARET_CURSOR ) {
midY = bot - fontHeight / 5;
segs[ 0 ].x1 = left; segs[ 0 ].y1 = bot; segs[ 0 ].x2 = X; segs[ 0 ].y2 = midY;
segs[ 1 ].x1 = X; segs[ 1 ].y1 = midY; segs[ 1 ].x2 = right; segs[ 1 ].y2 = bot;
segs[ 2 ].x1 = left; segs[ 2 ].y1 = bot; segs[ 2 ].x2 = X; segs[ 2 ].y2 = midY - 1;
segs[ 3 ].x1 = X; segs[ 3 ].y1 = midY - 1; segs[ 3 ].x2 = right; segs[ 3 ].y2 = bot;
nSegs = 4;
} else if ( mCursorStyle == NORMAL_CURSOR ) {
segs[ 0 ].x1 = left; segs[ 0 ].y1 = Y; segs[ 0 ].x2 = right; segs[ 0 ].y2 = Y;
segs[ 1 ].x1 = X; segs[ 1 ].y1 = Y; segs[ 1 ].x2 = X; segs[ 1 ].y2 = bot;
segs[ 2 ].x1 = left; segs[ 2 ].y1 = bot; segs[ 2 ].x2 = right; segs[ 2 ].y2 = bot;
nSegs = 3;
} else if ( mCursorStyle == HEAVY_CURSOR ) {
segs[ 0 ].x1 = X - 1; segs[ 0 ].y1 = Y; segs[ 0 ].x2 = X - 1; segs[ 0 ].y2 = bot;
segs[ 1 ].x1 = X; segs[ 1 ].y1 = Y; segs[ 1 ].x2 = X; segs[ 1 ].y2 = bot;
segs[ 2 ].x1 = X + 1; segs[ 2 ].y1 = Y; segs[ 2 ].x2 = X + 1; segs[ 2 ].y2 = bot;
segs[ 3 ].x1 = left; segs[ 3 ].y1 = Y; segs[ 3 ].x2 = right; segs[ 3 ].y2 = Y;
segs[ 4 ].x1 = left; segs[ 4 ].y1 = bot; segs[ 4 ].x2 = right; segs[ 4 ].y2 = bot;
nSegs = 5;
} else if ( mCursorStyle == DIM_CURSOR ) {
midY = Y + fontHeight / 2;
segs[ 0 ].x1 = X; segs[ 0 ].y1 = Y; segs[ 0 ].x2 = X; segs[ 0 ].y2 = Y;
segs[ 1 ].x1 = X; segs[ 1 ].y1 = midY; segs[ 1 ].x2 = X; segs[ 1 ].y2 = midY;
segs[ 2 ].x1 = X; segs[ 2 ].y1 = bot; segs[ 2 ].x2 = X; segs[ 2 ].y2 = bot;
nSegs = 3;
} else if ( mCursorStyle == BLOCK_CURSOR ) {
right = X + fontWidth;
segs[ 0 ].x1 = X; segs[ 0 ].y1 = Y; segs[ 0 ].x2 = right; segs[ 0 ].y2 = Y;
segs[ 1 ].x1 = right; segs[ 1 ].y1 = Y; segs[ 1 ].x2 = right; segs[ 1 ].y2 = bot;
segs[ 2 ].x1 = right; segs[ 2 ].y1 = bot; segs[ 2 ].x2 = X; segs[ 2 ].y2 = bot;
segs[ 3 ].x1 = X; segs[ 3 ].y1 = bot; segs[ 3 ].x2 = X; segs[ 3 ].y2 = Y;
nSegs = 4;
}
fl_color( mCursor_color );
for ( int k = 0; k < nSegs; k++ ) {
fl_line( segs[ k ].x1, segs[ k ].y1, segs[ k ].x2, segs[ k ].y2 );
}
}
/*
** Determine the drawing method to use to draw a specific character from "buf".
** "lineStartPos" gives the character index where the line begins, "lineIndex",
** the number of characters past the beginning of the line, and "dispIndex",
** the number of displayed characters past the beginning of the line. Passing
** lineStartPos of -1 returns the drawing style for "no text".
**
** Why not just: position_style(pos)? Because style applies to blank areas
** of the window beyond the text boundaries, and because this routine must also
** decide whether a position is inside of a rectangular Fl_Text_Selection, and do
** so efficiently, without re-counting character positions from the start of the
** line.
**
** Note that style is a somewhat incorrect name, drawing method would
** be more appropriate.
*/
int Fl_Text_Display::position_style( int lineStartPos,
int lineLen, int lineIndex, int dispIndex ) {
Fl_Text_Buffer * buf = mBuffer;
Fl_Text_Buffer *styleBuf = mStyleBuffer;
int pos, style = 0;
if ( lineS
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -