From 18d6122240d1fc5cb29561ad710c5b29d1fdb36e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=B4me=20Duval?= Date: Fri, 21 Jul 2023 18:47:18 +0200 Subject: [PATCH] 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 --- src/apps/terminal/TermConst.h | 13 +++++- src/apps/terminal/TermParse.cpp | 53 +++++++++++++++++++++++- src/apps/terminal/TermView.cpp | 61 +++++++++++++++++++++++++--- src/apps/terminal/TerminalLine.h | 69 ++++++++++++++++++++++++++++++-- src/apps/terminal/VTPrsTbl.c | 2 +- 5 files changed, 184 insertions(+), 14 deletions(-) diff --git a/src/apps/terminal/TermConst.h b/src/apps/terminal/TermConst.h index f704a156a5..bd5fe48658 100644 --- a/src/apps/terminal/TermConst.h +++ b/src/apps/terminal/TermConst.h @@ -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) diff --git a/src/apps/terminal/TermParse.cpp b/src/apps/terminal/TermParse.cpp index e1e9511d26..6faa8c40e6 100644 --- a/src/apps/terminal/TermParse.cpp +++ b/src/apps/terminal/TermParse.cpp @@ -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); diff --git a/src/apps/terminal/TermView.cpp b/src/apps/terminal/TermView.cpp index 5fae17eddb..c275fc71ba 100644 --- a/src/apps/terminal/TermView.cpp +++ b/src/apps/terminal/TermView.cpp @@ -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)); - } } diff --git a/src/apps/terminal/TerminalLine.h b/src/apps/terminal/TerminalLine.h index 0f5e5cfa49..95e1a83fa0 100644 --- a/src/apps/terminal/TerminalLine.h +++ b/src/apps/terminal/TerminalLine.h @@ -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; } }; diff --git a/src/apps/terminal/VTPrsTbl.c b/src/apps/terminal/VTPrsTbl.c index ac43bb9396..8bf3b5ccfb 100644 --- a/src/apps/terminal/VTPrsTbl.c +++ b/src/apps/terminal/VTPrsTbl.c @@ -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,