Terminal: support for underline color and styles

the text is now printed above the underline.

Change-Id: I1a3a7713bf514830106532e1534793e0fe158bc2
Reviewed-on: https://review.haiku-os.org/c/haiku/+/6706
Reviewed-by: waddlesplash <waddlesplash@gmail.com>
This commit is contained in:
Jérôme Duval 2023-07-21 18:47:18 +02:00 committed by waddlesplash
parent c5abd6a796
commit 18d6122240
5 changed files with 184 additions and 14 deletions

View File

@ -167,6 +167,16 @@ enum {
};
// Underline style
enum {
SINGLE_UNDERLINE = 1,
DOUBLE_UNDERLINE,
CURLY_UNDERLINE,
DOTTED_UNDERLINE,
DASHED_UNDERLINE
};
// Preference Folder and setting path
static const int32 DEFAULT = -1;
@ -206,9 +216,10 @@ enum {
#define FONT 0x0100
#define RESERVE 0x0080
#define DUMPCR 0x0040
#define UNDERSET 0x0020
#define FORECOLOR 0xFF0000
#define BACKCOLOR 0xFF000000
#define CHAR_ATTRIBUTES 0xFFFF7700
#define CHAR_ATTRIBUTES 0xFFFF7720
#define FORECOLORED(x) ((x) << 16)
#define BACKCOLORED(x) ((x) << 24)

View File

@ -795,19 +795,49 @@ TermParse::EscParse()
break;
case 4: /* Underline */
attributes |= UNDERLINE;
if ((row + 1) < nparam) {
row++;
switch (param[row]) {
case 0:
attributes.UnsetUnder();
break;
case 1:
attributes.SetUnder(SINGLE_UNDERLINE);
break;
case 2:
attributes.SetUnder(DOUBLE_UNDERLINE);
break;
case 3:
attributes.SetUnder(CURLY_UNDERLINE);
break;
case 4:
attributes.SetUnder(DOTTED_UNDERLINE);
break;
case 5:
attributes.SetUnder(DASHED_UNDERLINE);
break;
default:
row = nparam; // force exit of the parsing
break;
}
} else
attributes.SetUnder(SINGLE_UNDERLINE);
break;
case 7: /* Inverse */
attributes |= INVERSE;
break;
case 21: /* Double Underline */
attributes.SetUnder(DOUBLE_UNDERLINE);
break;
case 22: /* Not Bold */
attributes &= ~BOLD;
break;
case 24: /* Not Underline */
attributes &= ~UNDERLINE;
attributes.UnsetUnder();
break;
case 27: /* Not Inverse */
@ -891,6 +921,25 @@ TermParse::EscParse()
case 49:
attributes.UnsetBackground();
break;
case 58:
{
if (nparam >= 3 && param[row+1] == 5) {
attributes.SetIndexedUnderline(param[row+2]);
row += 2;
} else if (nparam >= 5 && param[row+1] == 2) {
attributes.SetDirectUnderline(param[row+2], param[row+3], param[row+4]);
row += 4;
} else {
row = nparam; // force exit of the parsing
}
break;
}
case 59:
attributes.UnsetUnderline();
break;
}
}
fBuffer->SetAttributes(attributes);

View File

@ -1050,12 +1050,15 @@ TermView::_DrawLinePart(float x1, float y1, Attributes attr,
rgb_color rgb_fore = fTextForeColor;
rgb_color rgb_back = fTextBackColor;
rgb_color rgb_under = fTextForeColor;
// color attribute
if (attr.IsForeSet())
rgb_fore = attr.ForegroundColor(fTextBuffer->Palette());
if (attr.IsBackSet())
rgb_back = attr.BackgroundColor(fTextBuffer->Palette());
if (attr.IsUnderSet())
rgb_under = attr.UnderlineColor(fTextBuffer->Palette());
// Selection check.
if (cursor) {
@ -1077,6 +1080,58 @@ TermView::_DrawLinePart(float x1, float y1, Attributes attr,
inView->SetHighColor(rgb_back);
inView->FillRect(BRect(x1, y1, x2 - 1, y2 - 1));
inView->SetLowColor(rgb_back);
// underline attribute
if (attr.IsUnder()) {
inView->SetHighColor(rgb_under);
switch (attr.UnderlineStyle()) {
default:
case SINGLE_UNDERLINE:
inView->MovePenTo(x1, y1 + fFontAscent + 1);
inView->StrokeLine(BPoint(x1 , y1 + fFontAscent + 1),
BPoint(x2 , y1 + fFontAscent + 1));
break;
case DOUBLE_UNDERLINE:
inView->MovePenTo(x1, y1 + fFontAscent);
inView->StrokeLine(BPoint(x1 , y1 + fFontAscent),
BPoint(x2 , y1 + fFontAscent));
inView->MovePenTo(x1, y1 + fFontAscent + 2);
inView->StrokeLine(BPoint(x1 , y1 + fFontAscent + 2),
BPoint(x2 , y1 + fFontAscent + 2));
break;
case CURLY_UNDERLINE:
{
inView->MovePenTo(x1, y1 + fFontAscent + 1);
bool up = true;
for (float x = x1; x < x2; x += 3) {
inView->StrokeLine(BPoint(x, y1 + fFontAscent + (up ? 0 : 2)),
BPoint(std::min(x + 2, x2), y1 + fFontAscent + (up ? 2 : 0)));
up = !up;
}
break;
}
case DOTTED_UNDERLINE:
{
inView->MovePenTo(x1, y1 + fFontAscent + 1);
for (float x = x1; x < x2; x += 4) {
inView->StrokeLine(BPoint(x, y1 + fFontAscent + 1),
BPoint(std::min(x, x2), y1 + fFontAscent + 1));
}
break;
}
case DASHED_UNDERLINE:
{
inView->MovePenTo(x1, y1 + fFontAscent + 1);
for (float x = x1; x < x2; x += 5) {
inView->StrokeLine(BPoint(x, y1 + fFontAscent + 1),
BPoint(std::min(x + 2, x2), y1 + fFontAscent + 1));
}
break;
}
}
}
inView->SetHighColor(rgb_fore);
// Draw character.
@ -1100,12 +1155,6 @@ TermView::_DrawLinePart(float x1, float y1, Attributes attr,
inView->DrawString((char *)buf);
inView->SetDrawingMode(B_OP_COPY);
// underline attribute
if (attr.IsUnder()) {
inView->MovePenTo(x1, y1 + fFontAscent);
inView->StrokeLine(BPoint(x1 , y1 + fFontAscent),
BPoint(x2 , y1 + fFontAscent));
}
}

View File

@ -22,10 +22,19 @@ struct Attributes {
uint32 state;
uint32 foreground;
uint32 background;
uint32 underline;
int underlineStyle;
Attributes() : state(0), foreground(0), background(0) {}
Attributes() : state(0), foreground(0), background(0), underline(0), underlineStyle(0) {}
inline void Reset() { state = 0; foreground = 0; background = 0; }
inline void Reset()
{
state = 0;
foreground = 0;
background = 0;
underline = 0;
underlineStyle = 0;
}
inline bool IsWidth() const { return (state & A_WIDTH) == A_WIDTH; }
inline bool IsBold() const { return (state & BOLD) == BOLD; }
@ -34,6 +43,7 @@ struct Attributes {
inline bool IsMouse() const { return (state & MOUSE) == MOUSE; }
inline bool IsForeSet() const { return (state & FORESET) == FORESET; }
inline bool IsBackSet() const { return (state & BACKSET) == BACKSET; }
inline bool IsUnderSet() const { return (state & UNDERSET) == UNDERSET; }
inline bool IsFont() const { return (state & FONT) == FONT; }
inline bool IsCR() const { return (state & DUMPCR) == DUMPCR; }
@ -51,6 +61,12 @@ struct Attributes {
state |= BACKSET;
}
inline void SetDirectUnderline(uint8 red, uint8 green, uint8 blue)
{
underline = 0x80000000 | (red << 16) | (green << 8) | blue;
state |= UNDERSET;
}
inline void SetIndexedForeground(uint32 index)
{
state &= ~FORECOLOR;
@ -67,6 +83,18 @@ struct Attributes {
background = 0;
}
inline void SetIndexedUnderline(uint32 index)
{
state |= UNDERSET;
underline = index;
}
inline void SetUnder(int style)
{
underlineStyle = style;
state |= UNDERLINE;
}
inline void UnsetForeground()
{
state &= ~FORESET;
@ -79,6 +107,18 @@ struct Attributes {
background = 0;
}
inline void UnsetUnderline()
{
state &= ~UNDERSET;
underline = 0;
}
inline void UnsetUnder()
{
underlineStyle = 0;
state &= ~UNDERLINE;
}
inline rgb_color
ForegroundColor(const rgb_color* indexedColors) const
{
@ -101,6 +141,23 @@ struct Attributes {
return indexedColors[(state & BACKCOLOR) >> 24];
}
inline rgb_color
UnderlineColor(const rgb_color* indexedColors) const
{
if ((underline & 0x80000000) != 0)
return make_color((underline >> 16) & 0xFF,
(underline >> 8) & 0xFF,
underline & 0xFF);
else
return indexedColors[underline];
}
inline int
UnderlineStyle() const
{
return underlineStyle;
}
inline Attributes&
operator&=(uint32 value) { state &= value; return *this; }
@ -118,7 +175,9 @@ struct Attributes {
{
return state == other.state
&& foreground == other.foreground
&& background == other.background;
&& background == other.background
&& underline == other.underline
&& underlineStyle == other.underlineStyle;
}
inline bool
@ -126,7 +185,9 @@ struct Attributes {
{
return state != other.state
|| foreground != other.foreground
|| background != other.background;
|| background != other.background
|| underline != other.underline
|| underlineStyle != other.underlineStyle;
}
};

View File

@ -1069,7 +1069,7 @@ CASE_ESC_DIGIT,
/* 8 9 : ; */
CASE_ESC_DIGIT,
CASE_ESC_DIGIT,
CASE_IGNORE,
CASE_ESC_SEMI,
CASE_ESC_SEMI,
/* < = > ? */
CASE_IGNORE,