Terminal: implement 24-bit colour.

* Changes `TERM` to `xterm`, as we're now a full colour capable terminal
* Removes now-obsolete GuessPaletteColor from an RGB triple
* Since it's using a struct instead of uint32 for attributes, add a bunch
  of helpers for a cleaner implementation
* Pass the TerminalBuffer's palette to the foreground/background get
  helpers, for when an indexed colour is returned

Change-Id: I33bd3bb1407b87a237a8bc355093fe549e05b43a
Reviewed-on: https://review.haiku-os.org/c/haiku/+/5195
Tested-by: Commit checker robot <no-reply+buildbot@haiku-os.org>
Reviewed-by: Jérôme Duval <jerome.duval@gmail.com>
This commit is contained in:
Jessica Hamilton 2022-04-11 01:04:56 +00:00 committed by Adrien Destugues
parent d45a65c88d
commit c0b591c58f
11 changed files with 232 additions and 167 deletions

View File

@ -113,7 +113,7 @@ BasicTerminalBuffer::BasicTerminalBuffer()
fScreen(NULL),
fScreenOffset(0),
fHistory(NULL),
fAttributes(0),
fAttributes(),
fSoftWrappedCursor(false),
fOverwriteMode(false),
fAlternateScreenActive(false),
@ -287,13 +287,13 @@ BasicTerminalBuffer::IsFullWidthChar(int32 row, int32 column) const
TerminalLine* lineBuffer = ALLOC_LINE_ON_STACK(fWidth);
TerminalLine* line = _HistoryLineAt(row, lineBuffer);
return line != NULL && column > 0 && column < line->length
&& (line->cells[column - 1].attributes & A_WIDTH) != 0;
&& line->cells[column - 1].attributes.IsWidth();
}
int
BasicTerminalBuffer::GetChar(int32 row, int32 column, UTF8Char& character,
uint32& attributes) const
Attributes& attributes) const
{
TerminalLine* lineBuffer = ALLOC_LINE_ON_STACK(fWidth);
TerminalLine* line = _HistoryLineAt(row, lineBuffer);
@ -303,7 +303,7 @@ BasicTerminalBuffer::GetChar(int32 row, int32 column, UTF8Char& character,
if (column < 0 || column >= line->length)
return NO_CHAR;
if (column > 0 && (line->cells[column - 1].attributes & A_WIDTH) != 0)
if (column > 0 && line->cells[column - 1].attributes.IsWidth())
return IN_STRING;
TerminalCell& cell = line->cells[column];
@ -315,7 +315,7 @@ BasicTerminalBuffer::GetChar(int32 row, int32 column, UTF8Char& character,
void
BasicTerminalBuffer::GetCellAttributes(int32 row, int32 column,
uint32& attributes, uint32& count) const
Attributes& attributes, uint32& count) const
{
count = 0;
TerminalLine* lineBuffer = ALLOC_LINE_ON_STACK(fWidth);
@ -336,7 +336,7 @@ BasicTerminalBuffer::GetCellAttributes(int32 row, int32 column,
int32
BasicTerminalBuffer::GetString(int32 row, int32 firstColumn, int32 lastColumn,
char* buffer, uint32& attributes) const
char* buffer, Attributes& attributes) const
{
TerminalLine* lineBuffer = ALLOC_LINE_ON_STACK(fWidth);
TerminalLine* line = _HistoryLineAt(row, lineBuffer);
@ -419,7 +419,7 @@ BasicTerminalBuffer::FindWord(const TermPos& pos,
return true;
}
if (x > 0 && IS_WIDTH(line->cells[x - 1].attributes))
if (x > 0 && line->cells[x - 1].attributes.IsWidth())
x--;
// get the char type at the given position
@ -431,7 +431,7 @@ BasicTerminalBuffer::FindWord(const TermPos& pos,
// find the beginning
TermPos start(x, y);
TermPos end(x + (IS_WIDTH(line->cells[x].attributes)
TermPos end(x + (line->cells[x].attributes.IsWidth()
? FULL_WIDTH : HALF_WIDTH), y);
for (;;) {
TermPos previousPos = start;
@ -455,7 +455,7 @@ BasicTerminalBuffer::FindWord(const TermPos& pos,
if (classifier->Classify(line->cells[nextPos.x].character) != type)
break;
nextPos.x += IS_WIDTH(line->cells[nextPos.x].attributes)
nextPos.x += line->cells[nextPos.x].attributes.IsWidth()
? FULL_WIDTH : HALF_WIDTH;
end = nextPos;
}
@ -489,7 +489,7 @@ BasicTerminalBuffer::NextLinePos(TermPos& pos, bool normalize) const
if (!_NormalizeLinePos(lineBuffer, line, pos))
return false;
pos.x += IS_WIDTH(line->cells[pos.x].attributes) ? FULL_WIDTH : HALF_WIDTH;
pos.x += line->cells[pos.x].attributes.IsWidth() ? FULL_WIDTH : HALF_WIDTH;
return !normalize || _NormalizeLinePos(lineBuffer, line, pos);
}
@ -503,12 +503,15 @@ BasicTerminalBuffer::LineLength(int32 index) const
}
int32
BasicTerminalBuffer::GetLineColor(int32 index) const
void
BasicTerminalBuffer::GetLineColor(int32 index, Attributes& attr) const
{
TerminalLine* lineBuffer = ALLOC_LINE_ON_STACK(fWidth);
TerminalLine* line = _HistoryLineAt(index, lineBuffer);
return line != NULL ? line->attributes : 0;
if (line != NULL)
attr = line->attributes;
else
attr.Reset();
}
@ -641,8 +644,8 @@ BasicTerminalBuffer::InsertChar(UTF8Char c)
TerminalLine* line = _LineAt(fCursor.y);
line->cells[fCursor.x].character = c;
line->cells[fCursor.x].attributes
= fAttributes | (width == FULL_WIDTH ? A_WIDTH : 0);
line->cells[fCursor.x].attributes = fAttributes;
line->cells[fCursor.x].attributes.state |= (width == FULL_WIDTH ? A_WIDTH : 0);
if (line->length < fCursor.x + width)
line->length = fCursor.x + width;
@ -662,7 +665,7 @@ BasicTerminalBuffer::InsertChar(UTF8Char c)
void
BasicTerminalBuffer::FillScreen(UTF8Char c, uint32 attributes)
BasicTerminalBuffer::FillScreen(UTF8Char c, Attributes &attributes)
{
uint32 width = HALF_WIDTH;
if (c.IsFullWidth()) {
@ -838,9 +841,9 @@ BasicTerminalBuffer::EraseCharsFrom(int32 first, int32 numChars)
fSoftWrappedCursor = false;
end = min_c(first + numChars, line->length);
if (first > 0 && IS_WIDTH(line->cells[first - 1].attributes))
if (first > 0 && line->cells[first - 1].attributes.IsWidth())
first--;
if (end > 0 && IS_WIDTH(line->cells[end - 1].attributes))
if (end > 0 && line->cells[end - 1].attributes.IsWidth())
end++;
for (int32 i = first; i < end; i++) {
@ -865,7 +868,7 @@ BasicTerminalBuffer::EraseAbove()
TerminalLine* line = _LineAt(fCursor.y);
if (fCursor.x < line->length) {
int32 to = fCursor.x;
if (IS_WIDTH(line->cells[fCursor.x].attributes))
if (line->cells[fCursor.x].attributes.IsWidth())
to++;
for (int32 i = 0; i <= to; i++) {
line->cells[i].attributes = fAttributes;
@ -1090,7 +1093,7 @@ BasicTerminalBuffer::_AllocateLines(int32 width, int32 count)
_FreeLines(lines, i);
return NULL;
}
lines[i]->Clear(0, width);
lines[i]->Clear(width);
}
return lines;
@ -1337,8 +1340,7 @@ BasicTerminalBuffer::_ResizeRewrap(int32 width, int32 height,
int32 toCopy = min_c(sourceLeft, destLeft);
// If the last cell to copy is the first cell of a
// full-width char, don't copy it yet.
if (toCopy > 0 && IS_WIDTH(
sourceLine->cells[sourceX + toCopy - 1].attributes)) {
if (toCopy > 0 && sourceLine->cells[sourceX + toCopy - 1].attributes.IsWidth()) {
//debug_printf(" -> last char is full-width -- don't copy it\n");
toCopy--;
}
@ -1620,7 +1622,7 @@ BasicTerminalBuffer::_TruncateLine(TerminalLine* line, int32 length)
if (line->length <= length)
return;
if (length > 0 && IS_WIDTH(line->cells[length - 1].attributes))
if (length > 0 && line->cells[length - 1].attributes.IsWidth())
length--;
line->length = length;
@ -1661,7 +1663,7 @@ BasicTerminalBuffer::_GetPartialLineString(BString& string, int32 row,
const TerminalCell& cell = line->cells[x];
string.Append(cell.character.bytes, cell.character.ByteCount());
if (IS_WIDTH(cell.attributes))
if (cell.attributes.IsWidth())
x++;
}
@ -1745,7 +1747,7 @@ BasicTerminalBuffer::_PreviousLinePos(TerminalLine* lineBuffer,
}
pos.x = line->length - 1;
}
if (pos.x > 0 && IS_WIDTH(line->cells[pos.x - 1].attributes))
if (pos.x > 0 && line->cells[pos.x - 1].attributes.IsWidth())
pos.x--;
return true;
@ -1805,7 +1807,7 @@ BasicTerminalBuffer::MakeLinesSnapshots(time_t timeStamp, const char* fileName)
}
fprintf(fileOut, "%02" B_PRId16 ":%02" B_PRId16 ":%08" B_PRIx32 ":\n",
i, line->length, line->attributes);
i, line->length, line->attributes.state);
for (int j = 0; j < line->length; j++)
if (line->cells[j].character.bytes[0] != 0)
fwrite(line->cells[j].character.bytes, 1,
@ -1815,7 +1817,7 @@ BasicTerminalBuffer::MakeLinesSnapshots(time_t timeStamp, const char* fileName)
for (int s = 28; s >= 0; s -= 4) {
for (int j = 0; j < fWidth; j++)
fprintf(fileOut, "%01" B_PRIx32,
(line->cells[j].attributes >> s) & 0x0F);
(line->cells[j].attributes.state >> s) & 0x0F);
fprintf(fileOut, "\n");
}

View File

@ -91,12 +91,12 @@ public:
bool IsFullWidthChar(int32 row, int32 column) const;
int GetChar(int32 row, int32 column,
UTF8Char& character,
uint32& attributes) const;
Attributes& attributes) const;
void GetCellAttributes(int32 row, int32 column,
uint32& attributes, uint32& count) const;
Attributes& attributes, uint32& count) const;
int32 GetString(int32 row, int32 firstColumn,
int32 lastColumn, char* buffer,
uint32& attributes) const;
Attributes& attributes) const;
void GetStringFromRegion(BString& string,
const TermPos& start,
const TermPos& end) const;
@ -105,7 +105,7 @@ public:
bool findNonWords, TermPos& start,
TermPos& end) const;
int32 LineLength(int32 index) const;
int32 GetLineColor(int32 index) const;
void GetLineColor(int32 index, Attributes& attr) const;
bool PreviousLinePos(TermPos& pos) const;
bool NextLinePos(TermPos& pos, bool normalize) const;
@ -120,8 +120,8 @@ public:
bool matchWord, TermPos& matchStart,
TermPos& matchEnd) const;
inline uint32 GetAttributes();
inline void SetAttributes(uint32 attributes);
inline Attributes GetAttributes();
inline void SetAttributes(const Attributes& attributes);
// snapshots and data capture for debugging
void MakeLinesSnapshots(time_t timeStamp,
@ -131,7 +131,7 @@ public:
// insert chars/lines
void InsertChar(UTF8Char c);
void FillScreen(UTF8Char c, uint32 attr);
void FillScreen(UTF8Char c, Attributes &attr);
void InsertCR();
void InsertLF();
@ -235,7 +235,7 @@ protected:
int32 fScreenOffset; // index of screen line 0
HistoryBuffer* fHistory;
uint32 fAttributes;
Attributes fAttributes;
// cursor position (origin: (0, 0))
TermPos fCursor;
@ -272,7 +272,7 @@ BasicTerminalBuffer::HistoryCapacity() const
}
uint32
Attributes
BasicTerminalBuffer::GetAttributes()
{
return fAttributes;
@ -280,7 +280,7 @@ BasicTerminalBuffer::GetAttributes()
void
BasicTerminalBuffer::SetAttributes(uint32 attributes)
BasicTerminalBuffer::SetAttributes(const Attributes& attributes)
{
fAttributes = attributes;
}

View File

@ -84,7 +84,7 @@ HistoryBuffer::GetTerminalLineAt(int32 index, TerminalLine* buffer) const
int32 charCount = 0;
const char* chars = line->Chars();
buffer->length = 0;
uint32 attributes = 0;
Attributes attributes;
AttributesRun* attributesRun = line->AttributesRuns();
int32 attributesRunCount = line->attributesRunCount;
int32 nextAttributesAt = attributesRunCount > 0
@ -95,7 +95,7 @@ HistoryBuffer::GetTerminalLineAt(int32 index, TerminalLine* buffer) const
if (charCount == nextAttributesAt) {
if (charCount < attributesRun->offset) {
// the "hole" in attributes run
attributes = 0;
attributes.Reset();
nextAttributesAt = attributesRun->offset;
} else if (attributesRunCount > 0) {
attributes = attributesRun->attributes;
@ -104,7 +104,7 @@ HistoryBuffer::GetTerminalLineAt(int32 index, TerminalLine* buffer) const
attributesRun++;
attributesRunCount--;
} else {
attributes = 0;
attributes.Reset();
nextAttributesAt = INT_MAX;
}
}
@ -120,10 +120,10 @@ HistoryBuffer::GetTerminalLineAt(int32 index, TerminalLine* buffer) const
// full width char?
if (cell.character.IsFullWidth()) {
cell.attributes |= A_WIDTH;
cell.attributes.state |= A_WIDTH;
// attributes of the second, "invisible" cell must be
// cleared to let full-width chars detection work properly
buffer->cells[charCount++].attributes = 0;
buffer->cells[charCount++].attributes.Reset();
}
}
@ -140,18 +140,18 @@ HistoryBuffer::AddLine(const TerminalLine* line)
{
//debug_printf("HistoryBuffer::AddLine(%p): length: %d\n", line, line->length);
// determine the amount of memory we need for the line
uint32 attributes = 0;
Attributes attributes;
int32 attributesRuns = 0;
int32 byteLength = 0;
for (int32 i = 0; i < line->length; i++) {
const TerminalCell& cell = line->cells[i];
byteLength += cell.character.ByteCount();
if ((cell.attributes & CHAR_ATTRIBUTES) != attributes) {
attributes = cell.attributes & CHAR_ATTRIBUTES;
if (attributes != 0)
if ((cell.attributes.state & CHAR_ATTRIBUTES) != attributes.state) {
attributes.state = cell.attributes.state & CHAR_ATTRIBUTES;
if (attributes.state != 0)
attributesRuns++;
}
if (IS_WIDTH(cell.attributes))
if (cell.attributes.IsWidth())
i++;
}
@ -160,7 +160,7 @@ HistoryBuffer::AddLine(const TerminalLine* line)
// allocate and translate the line
HistoryLine* historyLine = _AllocateLine(attributesRuns, byteLength);
attributes = 0;
attributes.Reset();
AttributesRun* attributesRun = historyLine->AttributesRuns();
char* chars = historyLine->Chars();
@ -173,28 +173,28 @@ HistoryBuffer::AddLine(const TerminalLine* line)
chars += charLength;
// deal with attributes
if ((cell.attributes & CHAR_ATTRIBUTES) != attributes) {
if ((cell.attributes.state & CHAR_ATTRIBUTES) != attributes.state) {
// terminate the previous attributes run
if (attributes != 0) {
if (attributes.state != 0) {
attributesRun->length = i - attributesRun->offset;
attributesRun++;
}
attributes = cell.attributes & CHAR_ATTRIBUTES;
attributes.state = cell.attributes.state & CHAR_ATTRIBUTES;
// init the new one
if (attributes != 0) {
if (attributes.state != 0) {
attributesRun->attributes = attributes;
attributesRun->offset = i;
}
}
if (IS_WIDTH(cell.attributes))
if (cell.attributes.IsWidth())
i++;
}
// set the last attributes run's length
if (attributes != 0)
if (attributes.state != 0)
attributesRun->length = line->length - attributesRun->offset;
historyLine->softBreak = line->softBreak;

View File

@ -74,7 +74,7 @@
// TODO: should extract from /etc/passwd instead???
const char *kDefaultShell = "/bin/sh";
const char *kTerminalType = "xterm-256color";
const char *kTerminalType = "xterm";
/*
* Set environment variable.

View File

@ -206,18 +206,6 @@ enum {
#define BACKCOLOR 0xFF000000
#define CHAR_ATTRIBUTES 0xFFFF7700
#define IS_WIDTH(x) (((x) & A_WIDTH) )
#define IS_BOLD(x) (((x) & BOLD) )
#define IS_UNDER(x) (((x) & UNDERLINE) )
#define IS_INVERSE(x) (((x) & INVERSE) )
#define IS_MOUSE(x) (((x) & MOUSE) )
#define IS_FORESET(x) (((x) & FORESET) )
#define IS_BACKSET(x) (((x) & BACKSET) )
#define IS_FONT(x) (((x) & FONT) )
#define IS_CR(x) (((x) & DUMPCR) )
#define IS_FORECOLOR(x) (((x) & FORECOLOR) >> 16)
#define IS_BACKCOLOR(x) (((x) & BACKCOLOR) >> 24)
#define FORECOLORED(x) ((x) << 16)
#define BACKCOLORED(x) ((x) << 24)

View File

@ -781,12 +781,12 @@ TermParse::EscParse()
case CASE_SGR:
{
/* SGR */
uint32 attributes = fBuffer->GetAttributes();
Attributes attributes = fBuffer->GetAttributes();
for (row = 0; row < nparam; ++row) {
switch (param[row]) {
case DEFAULT:
case 0: /* Reset attribute */
attributes = 0;
attributes.Reset();
break;
case 1: /* Bold */
@ -831,32 +831,22 @@ TermParse::EscParse()
case 35:
case 36:
case 37:
attributes &= ~FORECOLOR;
attributes |= FORECOLORED(param[row] - 30);
attributes |= FORESET;
attributes.SetIndexedForeground(param[row] - 30);
break;
case 38:
{
int color = -1;
if (nparam == 3 && param[1] == 5)
color = param[2];
attributes.SetIndexedForeground(param[2]);
else if (nparam == 5 && param[1] == 2)
color = fBuffer->GuessPaletteColor(
param[2], param[3], param[4]);
if (color >= 0) {
attributes &= ~FORECOLOR;
attributes |= FORECOLORED(color);
attributes |= FORESET;
}
attributes.SetDirectForeground(param[2], param[3], param[4]);
row = nparam; // force exit of the parsing
break;
}
case 39:
attributes &= ~FORESET;
attributes.UnsetForeground();
break;
case 100:
@ -876,32 +866,22 @@ TermParse::EscParse()
case 45:
case 46:
case 47:
attributes &= ~BACKCOLOR;
attributes |= BACKCOLORED(param[row] - 40);
attributes |= BACKSET;
attributes.SetIndexedBackground(param[row] - 40);
break;
case 48:
{
int color = -1;
if (nparam == 3 && param[1] == 5)
color = param[2];
attributes.SetIndexedBackground(param[2]);
else if (nparam == 5 && param[1] == 2)
color = fBuffer->GuessPaletteColor(
param[2], param[3], param[4]);
if (color >= 0) {
attributes &= ~BACKCOLOR;
attributes |= BACKCOLORED(color);
attributes |= BACKSET;
}
attributes.SetDirectBackground(param[2], param[3], param[4]);
row = nparam; // force exit of the parsing
break;
}
case 49:
attributes &= ~BACKSET;
attributes.UnsetBackground();
break;
}
}
@ -996,8 +976,11 @@ TermParse::EscParse()
case CASE_DECALN:
/* DECALN */
fBuffer->FillScreen(UTF8Char('E'), 0);
parsestate = groundtable;
{
Attributes attr;
fBuffer->FillScreen(UTF8Char('E'), attr);
parsestate = groundtable;
}
break;
// case CASE_GSETS:

View File

@ -1028,13 +1028,13 @@ TermView::_Deactivate()
//! Draw part of a line in the given view.
void
TermView::_DrawLinePart(float x1, float y1, uint32 attr, char *buf,
int32 width, Highlight* highlight, bool cursor, BView *inView)
TermView::_DrawLinePart(float x1, float y1, Attributes attr,
char *buf, int32 width, Highlight* highlight, bool cursor, BView *inView)
{
if (highlight != NULL)
attr = highlight->Highlighter()->AdjustTextAttributes(attr);
attr.state = highlight->Highlighter()->AdjustTextAttributes(attr.state);
inView->SetFont(IS_BOLD(attr) && !fEmulateBold && fAllowBold
inView->SetFont(attr.IsBold() && !fEmulateBold && fAllowBold
? &fBoldFont : &fHalfFont);
// Set pen point
@ -1045,13 +1045,10 @@ TermView::_DrawLinePart(float x1, float y1, uint32 attr, char *buf,
rgb_color rgb_back = fTextBackColor;
// color attribute
int forecolor = IS_FORECOLOR(attr);
int backcolor = IS_BACKCOLOR(attr);
if (IS_FORESET(attr))
rgb_fore = fTextBuffer->PaletteColor(forecolor);
if (IS_BACKSET(attr))
rgb_back = fTextBuffer->PaletteColor(backcolor);
if (attr.IsForeSet())
rgb_fore = attr.ForegroundColor(fTextBuffer->Palette());
if (attr.IsBackSet())
rgb_back = attr.BackgroundColor(fTextBuffer->Palette());
// Selection check.
if (cursor) {
@ -1062,7 +1059,7 @@ TermView::_DrawLinePart(float x1, float y1, uint32 attr, char *buf,
rgb_back = highlight->Highlighter()->BackgroundColor();
} else {
// Reverse attribute(If selected area, don't reverse color).
if (IS_INVERSE(attr)) {
if (attr.IsInverse()) {
rgb_color rgb_tmp = rgb_fore;
rgb_fore = rgb_back;
rgb_back = rgb_tmp;
@ -1076,7 +1073,7 @@ TermView::_DrawLinePart(float x1, float y1, uint32 attr, char *buf,
inView->SetHighColor(rgb_fore);
// Draw character.
if (IS_BOLD(attr)) {
if (attr.IsBold()) {
if (fEmulateBold) {
inView->MovePenTo(x1 - 1, y1 + fFontAscent - 1);
inView->DrawString((char *)buf);
@ -1097,7 +1094,7 @@ TermView::_DrawLinePart(float x1, float y1, uint32 attr, char *buf,
inView->SetDrawingMode(B_OP_COPY);
// underline attribute
if (IS_UNDER(attr)) {
if (attr.IsUnder()) {
inView->MovePenTo(x1, y1 + fFontAscent);
inView->StrokeLine(BPoint(x1 , y1 + fFontAscent),
BPoint(x2 , y1 + fFontAscent));
@ -1116,7 +1113,7 @@ TermView::_DrawCursor()
int32 firstVisible = _LineAt(0);
UTF8Char character;
uint32 attr = 0;
Attributes attr;
bool cursorVisible = _IsCursorVisible();
@ -1139,7 +1136,7 @@ TermView::_DrawCursor()
character, attr) == A_CHAR
&& (fCursorStyle == BLOCK_CURSOR || !cursorVisible)) {
int32 width = IS_WIDTH(attr) ? FULL_WIDTH : HALF_WIDTH;
int32 width = attr.IsWidth() ? FULL_WIDTH : HALF_WIDTH;
char buffer[5];
int32 bytes = UTF8Char::ByteCount(character.bytes[0]);
memcpy(buffer, character.bytes, bytes);
@ -1160,15 +1157,15 @@ TermView::_DrawCursor()
fTextBuffer->GetCellAttributes(
fCursor.y, fCursor.x, attr, count);
else
attr = fVisibleTextBuffer->GetLineColor(
fCursor.y - firstVisible);
fVisibleTextBuffer->GetLineColor(fCursor.y - firstVisible, attr);
if (attr.IsBackSet())
rgb_back = attr.BackgroundColor(fTextBuffer->Palette());
if (IS_BACKSET(attr))
rgb_back = fTextBuffer->PaletteColor(IS_BACKCOLOR(attr));
SetHighColor(rgb_back);
}
if (IS_WIDTH(attr) && fCursorStyle != IBEAM_CURSOR)
if (attr.IsWidth() && fCursorStyle != IBEAM_CURSOR)
rect.right += fFontWidth;
FillRect(rect);
@ -1339,7 +1336,7 @@ TermView::Draw(BRect updateRect)
// draw the affected line parts
if (x1 <= x2) {
uint32 attr = 0;
Attributes attr;
for (int32 j = y1; j <= y2; j++) {
int32 k = x1;
@ -1383,12 +1380,10 @@ TermView::Draw(BRect updateRect)
rect.right = rect.left + fFontWidth * count - 1;
nextColumn = i + count;
} else
attr = fVisibleTextBuffer->GetLineColor(j - firstVisible);
fVisibleTextBuffer->GetLineColor(j - firstVisible, attr);
if (IS_BACKSET(attr)) {
int backcolor = IS_BACKCOLOR(attr);
rgb_back = fTextBuffer->PaletteColor(backcolor);
}
if (attr.IsBackSet())
rgb_back = attr.BackgroundColor(fTextBuffer->Palette());
SetHighColor(rgb_back);
rgb_back = HighColor();
@ -1404,7 +1399,7 @@ TermView::Draw(BRect updateRect)
// side - drawing the whole string with one call render the
// characters not aligned to cells grid - that looks much more
// inaccurate for full-width strings than for half-width ones.
if (IS_WIDTH(attr))
if (attr.IsWidth())
count = FULL_WIDTH;
_DrawLinePart(fFontWidth * i, (int32)_LineOffset(j),

View File

@ -23,6 +23,7 @@
#include <String.h>
#include <View.h>
#include "TerminalLine.h"
#include "TermPos.h"
#include "TermViewHighlight.h"
@ -202,7 +203,7 @@ private:
void _Activate();
void _Deactivate();
void _DrawLinePart(float x1, float y1, uint32 attr,
void _DrawLinePart(float x1, float y1, Attributes attr,
char* buffer, int32 width,
Highlight* highlight, bool cursor,
BView* inView);
@ -315,7 +316,7 @@ private:
BScrollBar* fScrollBar;
InlineInput* fInline;
// Color and Attribute.
// Color and Attributes.
rgb_color fTextForeColor;
rgb_color fTextBackColor;
rgb_color fCursorForeColor;

View File

@ -30,7 +30,7 @@ TerminalBuffer::TerminalBuffer()
fAlternateScreen(NULL),
fAlternateHistory(NULL),
fAlternateScreenOffset(0),
fAlternateAttributes(0),
fAlternateAttributes(),
fColorsPalette(NULL),
fListenerValid(false)
{
@ -280,34 +280,6 @@ TerminalBuffer::SetPaletteColor(uint8 index, rgb_color color)
}
rgb_color
TerminalBuffer::PaletteColor(uint8 index)
{
return fColorsPalette[index];
}
int
TerminalBuffer::GuessPaletteColor(int red, int green, int blue)
{
int distance = 255 * 100;
int index = -1;
for (uint32 i = 0; i < kTermColorCount && distance > 0; i++) {
rgb_color color = fColorsPalette[i];
int r = 30 * abs(color.red - red);
int g = 59 * abs(color.green - green);
int b = 11 * abs(color.blue - blue);
int d = r + g + b;
if (distance > d) {
index = i;
distance = d;
}
}
return min_c(index, int(kTermColorCount - 1));
}
void
TerminalBuffer::NotifyQuit(int32 reason)
{

View File

@ -42,8 +42,8 @@ public:
void SetCursorBlinking(bool blinking);
void SetCursorHidden(bool hidden);
void SetPaletteColor(uint8 index, rgb_color color);
rgb_color PaletteColor(uint8 index);
int GuessPaletteColor(int red, int green, int blue);
inline const rgb_color*
Palette() const { return fColorsPalette; }
void NotifyQuit(int32 reason);
@ -75,7 +75,7 @@ private:
TerminalLine** fAlternateScreen;
HistoryBuffer* fAlternateHistory;
int32 fAlternateScreenOffset;
uint32 fAlternateAttributes;
Attributes fAlternateAttributes;
rgb_color* fColorsPalette;
// listener/dirty region management

View File

@ -10,6 +10,7 @@
#ifndef TERMINAL_LINE_H
#define TERMINAL_LINE_H
#include <GraphicsDefs.h>
#include <SupportDefs.h>
#include "TermConst.h"
@ -17,19 +18,142 @@
#include "UTF8Char.h"
struct Attributes {
uint32 state;
uint32 foreground;
uint32 background;
Attributes() : state(0), foreground(0), background(0) {}
inline void Reset() { state = 0; foreground = 0; background = 0; }
inline bool IsWidth() const { return (state & A_WIDTH) == A_WIDTH; }
inline bool IsBold() const { return (state & BOLD) == BOLD; }
inline bool IsUnder() const { return (state & UNDERLINE) == UNDERLINE; }
inline bool IsInverse() const { return (state & INVERSE) == INVERSE; }
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 IsFont() const { return (state & FONT) == FONT; }
inline bool IsCR() const { return (state & DUMPCR) == DUMPCR; }
inline void SetDirectForeground(uint8 red, uint8 green, uint8 blue)
{
foreground = 0x80000000 | (red << 16) | (green << 8) | blue;
state &= ~FORECOLOR;
state |= FORESET;
}
inline void SetDirectBackground(uint8 red, uint8 green, uint8 blue)
{
background = 0x80000000 | (red << 16) | (green << 8) | blue;
state &= ~BACKCOLOR;
state |= BACKSET;
}
inline void SetIndexedForeground(uint32 index)
{
state &= ~FORECOLOR;
state |= FORESET;
state |= FORECOLORED(index);
foreground = 0;
}
inline void SetIndexedBackground(uint32 index)
{
state &= ~BACKCOLOR;
state |= BACKSET;
state |= BACKCOLORED(index);
background = 0;
}
inline void UnsetForeground()
{
state &= ~FORESET;
foreground = 0;
}
inline void UnsetBackground()
{
state &= ~BACKSET;
background = 0;
}
inline rgb_color
ForegroundColor(const rgb_color* indexedColors) const
{
if ((foreground & 0x80000000) != 0)
return make_color((foreground >> 16) & 0xFF,
(foreground >> 8) & 0xFF,
foreground & 0xFF);
else
return indexedColors[(state & FORECOLOR) >> 16];
}
inline rgb_color
BackgroundColor(const rgb_color* indexedColors) const
{
if ((background & 0x80000000) != 0)
return make_color((background >> 16) & 0xFF,
(background >> 8) & 0xFF,
background & 0xFF);
else
return indexedColors[(state & BACKCOLOR) >> 24];
}
inline Attributes&
operator&=(uint32 value) { state &= value; return *this; }
inline Attributes&
operator|=(uint32 value) { state |= value; return *this; }
inline uint32
operator|(uint32 value) { return state | value; }
inline uint32
operator&(uint32 value) { return state & value; }
inline bool
operator==(const Attributes& other) const
{
return state == other.state
&& foreground == other.foreground
&& background == other.background;
}
inline bool
operator!=(const Attributes& other) const
{
return state != other.state
|| foreground != other.foreground
|| background != other.background;
}
};
struct TerminalCell {
UTF8Char character;
uint32 attributes;
UTF8Char character;
Attributes attributes;
};
struct TerminalLine {
uint16 length;
bool softBreak; // soft line break
uint32 attributes;
Attributes attributes;
TerminalCell cells[1];
inline void Clear(uint32 attr = 0, size_t count = 0)
inline void Clear()
{
Clear(Attributes());
}
inline void Clear(size_t count)
{
Clear(Attributes(), count);
}
inline void Clear(Attributes attr, size_t count = 0)
{
length = 0;
attributes = attr;
@ -41,7 +165,7 @@ struct TerminalLine {
struct AttributesRun {
uint32 attributes;
Attributes attributes;
uint16 offset; // character offset
uint16 length; // length of the run in characters
};
@ -52,7 +176,7 @@ struct HistoryLine {
uint16 attributesRunCount; // number of attribute runs
uint16 byteLength : 15; // number of bytes in the line
bool softBreak : 1; // soft line break;
uint32 attributes;
Attributes attributes;
AttributesRun* AttributesRuns() const
{