summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorMatthias Melcher <github@matthiasm.com>2022-01-27 23:50:06 +0100
committerGitHub <noreply@github.com>2022-01-27 23:50:06 +0100
commitcdb51045dda7076be33147cc8e9138035ad9b97e (patch)
treebdb05911b0514aa39ab442d0caac761c529f8c53 /src
parent84c0b7495b0859cce8b79fc6e4ceee19bc4f2f35 (diff)
Background color attribute for Fl_Text_Display. (#378)
* Background color attribute for Fl_Text_Display. * Adding attributes. * Avoid clipping horizontal * Fl_Text_Display underlining. * Better line positions * Typos, testing. * Documentation.
Diffstat (limited to 'src')
-rw-r--r--src/Fl_Text_Display.cxx351
1 files changed, 213 insertions, 138 deletions
diff --git a/src/Fl_Text_Display.cxx b/src/Fl_Text_Display.cxx
index 6612595bd..b26311767 100644
--- a/src/Fl_Text_Display.cxx
+++ b/src/Fl_Text_Display.cxx
@@ -2022,141 +2022,148 @@ int Fl_Text_Display::handle_vline(
X = text_area.x - mHorizOffset;
}
- startX = X;
- startIndex = 0;
- if (!lineStr) {
- // just clear the background
- if (mode==DRAW_LINE) {
- style = position_style(lineStartPos, lineLen, -1);
- draw_string( style|BG_ONLY_MASK, text_area.x, Y, text_area.x+text_area.w, lineStr, lineLen );
- }
- if (mode==FIND_INDEX) {
- IS_UTF8_ALIGNED2(buffer(), lineStartPos)
- return lineStartPos;
+ // In DRAW_LINE mode, the first iteration of the loop will draw all
+ // backgrounds. The second iteration will draw the text, so that text
+ // overlapping background color changes will not be clipped.
+ for (int loop=1; loop<=2; loop++) {
+ int mask = (loop==1) ? BG_ONLY_MASK : TEXT_ONLY_MASK;
+ startX = X;
+ startIndex = 0;
+ if (!lineStr) {
+ // just clear the background
+ if (mode==DRAW_LINE) {
+ style = position_style(lineStartPos, lineLen, -1);
+ if (loop==1)
+ draw_string( style|BG_ONLY_MASK, text_area.x, Y, text_area.x+text_area.w, lineStr, lineLen );
+ }
+ if (mode==FIND_INDEX) {
+ IS_UTF8_ALIGNED2(buffer(), lineStartPos)
+ return lineStartPos;
+ }
+ return 0;
}
- return 0;
- }
- char currChar = 0, prevChar = 0;
- styleX = startX; startStyle = startIndex;
- // draw the line
- style = position_style(lineStartPos, lineLen, 0);
- for (i=0; i<lineLen; ) {
- currChar = lineStr[i]; // one byte is enough to handele tabs and other cases
- int len = fl_utf8len1(currChar);
- if (len<=0) len = 1; // OUCH!
- charStyle = position_style(lineStartPos, lineLen, i);
- if (charStyle!=style || currChar=='\t' || prevChar=='\t') {
- // draw a segment whenever the style changes or a Tab is found
- double w = 0;
- if (prevChar=='\t') {
- // draw a single Tab space
- double tab = col_to_x(mBuffer->tab_distance());
- double xAbs = (mode==GET_WIDTH) ? startX : startX+mHorizOffset-text_area.x;
- w = ((int(xAbs/tab)+1)*tab) - xAbs;
- styleX = startX+w; startStyle = i;
- if (mode==DRAW_LINE)
- draw_string( style|BG_ONLY_MASK, int(startX), Y, int(startX+w), 0, 0 );
- if (mode==FIND_INDEX && startX+w>rightClip) {
- // find x pos inside block
- free(lineStr);
- if (cursor_pos && (startX+w/2<rightClip)) // STR #2788
- return lineStartPos + startIndex + len; // STR #2788
- return lineStartPos + startIndex;
- }
- } else {
- // draw the text segment from the previous style change up to this point
- if ( (style&0xff)==(charStyle&0xff)) {
- w = string_width( lineStr+startStyle, i-startStyle, style ) - startX + styleX;
+ char currChar = 0, prevChar = 0;
+ styleX = startX; startStyle = startIndex;
+ // draw the line
+ style = position_style(lineStartPos, lineLen, 0);
+ for (i=0; i<lineLen; ) {
+ currChar = lineStr[i]; // one byte is enough to handele tabs and other cases
+ int len = fl_utf8len1(currChar);
+ if (len<=0) len = 1; // OUCH!
+ charStyle = position_style(lineStartPos, lineLen, i);
+ if (charStyle!=style || currChar=='\t' || prevChar=='\t') {
+ // draw a segment whenever the style changes or a Tab is found
+ double w = 0;
+ if (prevChar=='\t') {
+ // draw a single Tab space
+ double tab = col_to_x(mBuffer->tab_distance());
+ double xAbs = (mode==GET_WIDTH) ? startX : startX+mHorizOffset-text_area.x;
+ w = ((int(xAbs/tab)+1)*tab) - xAbs;
+ styleX = startX+w; startStyle = i;
+ if (mode==DRAW_LINE && loop==1)
+ draw_string( style|BG_ONLY_MASK, int(startX), Y, int(startX+w), 0, 0 );
+ if (mode==FIND_INDEX && startX+w>rightClip) {
+ // find x pos inside block
+ free(lineStr);
+ if (cursor_pos && (startX+w/2<rightClip)) // STR #2788
+ return lineStartPos + startIndex + len; // STR #2788
+ return lineStartPos + startIndex;
+ }
} else {
- w = string_width( lineStr+startIndex, i-startIndex, style );
- }
- if (mode==DRAW_LINE) {
- if (startIndex!=startStyle) {
- fl_push_clip(int(startX), Y, int(w)+1, mMaxsize);
- draw_string( style, int(styleX), Y, int(startX+w), lineStr+startStyle, i-startStyle );
- fl_pop_clip();
+ // draw the text segment from the previous style change up to this point
+ if ( (style&0xff)==(charStyle&0xff)) {
+ w = string_width( lineStr+startStyle, i-startStyle, style ) - startX + styleX;
} else {
- draw_string( style, int(startX), Y, int(startX+w), lineStr+startIndex, i-startIndex );
+ w = string_width( lineStr+startIndex, i-startIndex, style );
}
- }
- if (mode==FIND_INDEX && startX+w>rightClip) {
- // find x pos inside block
- int di;
- if (startIndex!=startStyle) {
- di = find_x(lineStr+startStyle, i-startStyle, style, -int(rightClip-styleX)); // STR #2788
- di = lineStartPos + startStyle + di;
- } else {
- di = find_x(lineStr+startIndex, i-startIndex, style, -int(rightClip-startX)); // STR #2788
- di = lineStartPos + startIndex + di;
+ if (mode==DRAW_LINE) {
+ if (startIndex!=startStyle) {
+ fl_push_clip(int(startX), Y, int(w)+1, mMaxsize);
+ draw_string( style|mask, int(styleX), Y, int(startX+w), lineStr+startStyle, i-startStyle );
+ fl_pop_clip();
+ } else {
+ draw_string( style|mask, int(startX), Y, int(startX+w), lineStr+startIndex, i-startIndex );
+ }
+ }
+ if (mode==FIND_INDEX && startX+w>rightClip) {
+ // find x pos inside block
+ int di;
+ if (startIndex!=startStyle) {
+ di = find_x(lineStr+startStyle, i-startStyle, style, -int(rightClip-styleX)); // STR #2788
+ di = lineStartPos + startStyle + di;
+ } else {
+ di = find_x(lineStr+startIndex, i-startIndex, style, -int(rightClip-startX)); // STR #2788
+ di = lineStartPos + startIndex + di;
+ }
+ free(lineStr);
+ IS_UTF8_ALIGNED2(buffer(), (lineStartPos+startIndex+di))
+ return di;
+ }
+ if ( (style&0xff)!=(charStyle&0xff)) {
+ startStyle = i;
+ styleX = startX+w;
}
- free(lineStr);
- IS_UTF8_ALIGNED2(buffer(), (lineStartPos+startIndex+di))
- return di;
- }
- if ( (style&0xff)!=(charStyle&0xff)) {
- startStyle = i;
- styleX = startX+w;
}
+ style = charStyle;
+ startX += w;
+ startIndex = i;
}
- style = charStyle;
- startX += w;
- startIndex = i;
+ i += len;
+ prevChar = currChar;
}
- i += len;
- prevChar = currChar;
- }
- double w = 0;
- if (currChar=='\t') {
- // draw a single Tab space
- double tab = col_to_x(mBuffer->tab_distance());
- double xAbs = (mode==GET_WIDTH) ? startX : startX+mHorizOffset-text_area.x;
- w = ((int(xAbs/tab)+1)*tab) - xAbs;
- if (mode==DRAW_LINE)
- draw_string( style|BG_ONLY_MASK, int(startX), Y, int(startX+w), 0, 0 );
- if (mode==FIND_INDEX) {
- // find x pos inside block
- free(lineStr);
- if (cursor_pos) // STR #2788
- return lineStartPos + startIndex + ( rightClip-startX>w/2 ? 1 : 0 ); // STR #2788
- return lineStartPos + startIndex + ( rightClip-startX>w ? 1 : 0 );
- }
- } else {
- w = string_width( lineStr+startIndex, i-startIndex, style );
- if (mode==DRAW_LINE) {
- // STR 2531
- if (startIndex!=startStyle) {
- fl_push_clip(int(startX), Y, int(w)+1, mMaxsize);
- draw_string( style, int(styleX), Y, int(startX+w), lineStr+startStyle, i-startStyle );
- fl_pop_clip();
- } else {
- draw_string( style, int(startX), Y, int(startX+w), lineStr+startIndex, i-startIndex );
+ double w = 0;
+ if (currChar=='\t') {
+ // draw a single Tab space
+ double tab = col_to_x(mBuffer->tab_distance());
+ double xAbs = (mode==GET_WIDTH) ? startX : startX+mHorizOffset-text_area.x;
+ w = ((int(xAbs/tab)+1)*tab) - xAbs;
+ if (mode==DRAW_LINE && loop==1)
+ draw_string( style|BG_ONLY_MASK, int(startX), Y, int(startX+w), 0, 0 );
+ if (mode==FIND_INDEX) {
+ // find x pos inside block
+ free(lineStr);
+ if (cursor_pos) // STR #2788
+ return lineStartPos + startIndex + ( rightClip-startX>w/2 ? 1 : 0 ); // STR #2788
+ return lineStartPos + startIndex + ( rightClip-startX>w ? 1 : 0 );
}
- }
- if (mode==FIND_INDEX) {
- // find x pos inside block
- int di;
- if (startIndex!=startStyle) {
- di = find_x(lineStr+startStyle, i-startStyle, style, -int(rightClip-styleX)); // STR #2788
- di = lineStartPos + startStyle + di;
- } else {
- di = find_x(lineStr+startIndex, i-startIndex, style, -int(rightClip-startX)); // STR #2788
- di = lineStartPos + startIndex + di;
+ } else {
+ w = string_width( lineStr+startIndex, i-startIndex, style );
+ if (mode==DRAW_LINE) {
+ // STR 2531
+ if (startIndex!=startStyle) {
+ fl_push_clip(int(startX), Y, int(w)+1, mMaxsize);
+ draw_string( style|mask, int(styleX), Y, int(startX+w), lineStr+startStyle, i-startStyle );
+ fl_pop_clip();
+ } else {
+ draw_string( style|mask, int(startX), Y, int(startX+w), lineStr+startIndex, i-startIndex );
+ }
}
+ if (mode==FIND_INDEX) {
+ // find x pos inside block
+ int di;
+ if (startIndex!=startStyle) {
+ di = find_x(lineStr+startStyle, i-startStyle, style, -int(rightClip-styleX)); // STR #2788
+ di = lineStartPos + startStyle + di;
+ } else {
+ di = find_x(lineStr+startIndex, i-startIndex, style, -int(rightClip-startX)); // STR #2788
+ di = lineStartPos + startIndex + di;
+ }
+ free(lineStr);
+ IS_UTF8_ALIGNED2(buffer(), (lineStartPos+startIndex+di))
+ return di;
+ }
+ }
+ if (mode==GET_WIDTH) {
free(lineStr);
- IS_UTF8_ALIGNED2(buffer(), (lineStartPos+startIndex+di))
- return di;
+ return int(startX+w);
}
- }
- if (mode==GET_WIDTH) {
- free(lineStr);
- return int(startX+w);
- }
- // clear the rest of the line
- startX += w;
- style = position_style(lineStartPos, lineLen, i);
- if (mode==DRAW_LINE)
- draw_string( style|BG_ONLY_MASK, int(startX), Y, text_area.x+text_area.w, lineStr, lineLen );
+ // clear the rest of the line
+ startX += w;
+ style = position_style(lineStartPos, lineLen, i);
+ if (mode==DRAW_LINE && loop==1)
+ draw_string( style|BG_ONLY_MASK, int(startX), Y, text_area.x+text_area.w, lineStr, lineLen );
+ }
free(lineStr);
IS_UTF8_ALIGNED2(buffer(), (lineStartPos+lineLen))
@@ -2267,7 +2274,7 @@ void Fl_Text_Display::draw_string(int style,
const char *string, int nChars) const {
IS_UTF8_ALIGNED(string)
- const Style_Table_Entry * styleRec;
+ const Style_Table_Entry *styleRec = NULL;
/* Draw blank area rather than text, if that was the request */
if ( style & FILL_MASK ) {
@@ -2284,6 +2291,7 @@ void Fl_Text_Display::draw_string(int style,
int fsize = textsize();
Fl_Color foreground;
Fl_Color background;
+ Fl_Color bgbasecolor;
if ( style & STYLE_LOOKUP_MASK ) {
int si = (style & STYLE_LOOKUP_MASK) - 'A';
@@ -2293,19 +2301,27 @@ void Fl_Text_Display::draw_string(int style,
styleRec = mStyleTable + si;
font = styleRec->font;
fsize = styleRec->size;
+ bgbasecolor = (styleRec->attr&ATTR_BGCOLOR) ? styleRec->bgcolor : color();
if (style & PRIMARY_MASK) {
if (Fl::focus() == (Fl_Widget*)this) {
- if (Fl::screen_driver()->has_marked_text() && Fl::compose_state)
- background = color();// Mac OS: underline marked text
- else
+ if (Fl::screen_driver()->has_marked_text() && Fl::compose_state) {
+ background = bgbasecolor; // Mac OS: underline marked text
+ } else {
background = selection_color();
}
- else background = fl_color_average(color(), selection_color(), 0.4f);
+ } else {
+ background = fl_color_average(bgbasecolor, selection_color(), 0.4f);
+ }
} else if (style & HIGHLIGHT_MASK) {
- if (Fl::focus() == (Fl_Widget*)this) background = fl_color_average(color(), selection_color(), 0.5f);
- else background = fl_color_average(color(), selection_color(), 0.6f);
- } else background = color();
+ if (Fl::focus() == (Fl_Widget*)this) {
+ background = fl_color_average(bgbasecolor, selection_color(), 0.5f);
+ } else {
+ background = fl_color_average(bgbasecolor, selection_color(), 0.6f);
+ }
+ } else {
+ background = bgbasecolor;
+ }
foreground = (style & PRIMARY_MASK) ? fl_contrast(styleRec->color, background) : styleRec->color;
} else if (style & PRIMARY_MASK) {
if (Fl::focus() == (Fl_Widget*)this) background = selection_color();
@@ -2332,11 +2348,44 @@ void Fl_Text_Display::draw_string(int style,
if (!(style & BG_ONLY_MASK)) {
fl_color( foreground );
fl_font( font, fsize );
+ int baseline = Y + mMaxsize - fl_descent();
// Make sure antialiased ÄÖÜ do not leak on line above:
// on X11+Xft the antialiased part of characters such as ÄÖÜ leak on the bottom pixel of the line above
static int can_leak = Fl::screen_driver()->text_display_can_leak();
- if (can_leak) fl_push_clip(X, Y, toX - X, mMaxsize);
- fl_draw( string, nChars, X, Y + mMaxsize - fl_descent());
+ // Clip top and bottom only. Add margin to avoid clipping horizontally
+ if (can_leak) fl_push_clip(x(), Y, w(), mMaxsize);
+ fl_draw( string, nChars, X, baseline);
+ if (styleRec) {
+ if (styleRec->attr & ATTR_LINES_MASK) {
+ int pitch = fsize/7;
+ int prevAA = fl_antialias();
+ fl_antialias(1);
+ switch (styleRec->attr & ATTR_LINES_MASK) {
+ case ATTR_UNDERLINE:
+ fl_color(foreground);
+ fl_line_style(FL_SOLID, pitch);
+ goto DRAW_UNDERLINE;
+ break;
+ case ATTR_GRAMMAR:
+ fl_color(FL_BLUE);
+ goto DRAW_DOTTED_UNDERLINE;
+ case ATTR_SPELLING:
+ fl_color(FL_RED);
+ DRAW_DOTTED_UNDERLINE:
+ fl_line_style(FL_DOT, pitch);
+ DRAW_UNDERLINE:
+ fl_xyline(X, baseline + fl_descent()/2, toX);
+ break;
+ case ATTR_STRIKE_THROUGH:
+ fl_color(foreground);
+ fl_line_style(FL_SOLID, pitch);
+ fl_xyline(X, baseline - (fl_height()-fl_descent())/3, toX);
+ break;
+ }
+ fl_line_style(FL_SOLID, 1);
+ fl_antialias(prevAA);
+ }
+ }
if (Fl::screen_driver()->has_marked_text() && Fl::compose_state && (style & PRIMARY_MASK)) {
fl_color( fl_color_average(foreground, background, 0.6f) );
fl_line(X, Y + mMaxsize - 1, X + (int)fl_width(string, nChars), Y + mMaxsize - 1);
@@ -2379,21 +2428,31 @@ void Fl_Text_Display::clear_rect(int style,
if ( width == 0 )
return;
+ Fl_Color bgbasecolor = color();
+ if ( style & STYLE_LOOKUP_MASK ) {
+ int si = (style & STYLE_LOOKUP_MASK) - 'A';
+ if (si < 0) si = 0;
+ else if (si >= mNStyles) si = mNStyles - 1;
+ const Style_Table_Entry *styleRec = mStyleTable + si;
+ if (styleRec->attr&ATTR_BGCOLOR_EXT_)
+ bgbasecolor = styleRec->bgcolor;
+ }
+
Fl_Color c;
if (style & PRIMARY_MASK) {
if (Fl::focus()==(Fl_Widget*)this) {
c = selection_color();
} else {
- c = fl_color_average(color(), selection_color(), 0.4f);
+ c = fl_color_average(bgbasecolor, selection_color(), 0.4f);
}
} else if (style & HIGHLIGHT_MASK) {
if (Fl::focus()==(Fl_Widget*)this) {
- c = fl_color_average(color(), selection_color(), 0.5f);
+ c = fl_color_average(bgbasecolor, selection_color(), 0.5f);
} else {
- c = fl_color_average(color(), selection_color(), 0.6f);
+ c = fl_color_average(bgbasecolor, selection_color(), 0.6f);
}
} else {
- c = color();
+ c = bgbasecolor;
}
fl_color(active_r() ? c : fl_inactive(c));
fl_rectf( X, Y, width, height );
@@ -2502,6 +2561,10 @@ void Fl_Text_Display::draw_cursor( int X, int Y ) {
Note that style is a somewhat incorrect name, drawing method would
be more appropriate.
+ If lineIndex is pointing to the last character in a line, and the second
+ to last character has the ATTR_BGCOLOR_EXT set, the background color will
+ extend into the remaining line.
+
\param lineStartPos beginning of this line
\param lineLen number of bytes in line
\param lineIndex position of character within line
@@ -2520,9 +2583,21 @@ int Fl_Text_Display::position_style( int lineStartPos, int lineLen, int lineInde
pos = lineStartPos + min( lineIndex, lineLen );
- if ( lineIndex >= lineLen )
+ if ( styleBuf && lineIndex==lineLen && lineLen>0) {
+ style = ( unsigned char ) styleBuf->byte_at( pos-1 );
+ if (style == mUnfinishedStyle && mUnfinishedHighlightCB) {
+ (mUnfinishedHighlightCB)( pos, mHighlightCBArg);
+ style = (unsigned char) styleBuf->byte_at( pos);
+ }
+ int si = (style & STYLE_LOOKUP_MASK) - 'A';
+ if (si < 0) si = 0;
+ else if (si >= mNStyles) si = mNStyles - 1;
+ const Style_Table_Entry *styleRec = mStyleTable + si;
+ if ((styleRec->attr&ATTR_BGCOLOR_EXT_)==0)
+ style = FILL_MASK;
+ } else if ( lineIndex >= lineLen ) {
style = FILL_MASK;
- else if ( styleBuf != NULL ) {
+ } else if ( styleBuf != NULL ) {
style = ( unsigned char ) styleBuf->byte_at( pos );
if (style == mUnfinishedStyle && mUnfinishedHighlightCB) {
/* encountered "unfinished" style, trigger parsing */