degesch: color cleanup

This commit is contained in:
Přemysl Eric Janouch 2015-05-12 02:43:53 +02:00
parent b5a7ea63c2
commit 2d040cae73
1 changed files with 79 additions and 63 deletions

142
degesch.c
View File

@ -1563,40 +1563,6 @@ free_terminal (void)
del_curterm (cur_term); del_curterm (cur_term);
} }
// NOTE: commonly terminals have 8 colors (worst), 16 colors (allows brightness
// without the bold/blink attributes), 88 colors (the same plus a 4^3 RGB cube
// and a few shades of gray), or 256 colors (best)
static int
index_to_terminal_palette (int color)
{
hard_assert (color >= 0 && color < 256);
// No conversion
if (max_colors == 256)
return color;
// These colours are the same everywhere
if (color < 16 && max_colors > color)
return color;
// Outside the 16-color range, we only support the 88-color palette,
// which we can interpolate to from the 256-color one on input
if (max_colors != 88)
return -1;
// 24 -> 8 extra shades of gray
if (color >= 232)
return 80 + (color - 232) / 3;
// 6 * 6 * 6 cube -> 4 * 4 * 4 cube
int x[6] = { 0, 1, 1, 2, 2, 3 };
int index = color - 16;
return 16 +
( x[ index / 36 ] << 8
| x[(index / 6) % 6 ] << 4
| x[(index % 6) ] );
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
typedef int (*terminal_printer_fn) (int); typedef int (*terminal_printer_fn) (int);
@ -1726,7 +1692,8 @@ enum
ATTRIBUTE_BOLD = 1 << 0, ATTRIBUTE_BOLD = 1 << 0,
ATTRIBUTE_ITALIC = 1 << 1, ATTRIBUTE_ITALIC = 1 << 1,
ATTRIBUTE_UNDERLINE = 1 << 2, ATTRIBUTE_UNDERLINE = 1 << 2,
ATTRIBUTE_INVERSE = 1 << 3 ATTRIBUTE_INVERSE = 1 << 3,
ATTRIBUTE_BLINK = 1 << 4
}; };
struct attribute_printer struct attribute_printer
@ -1773,50 +1740,94 @@ attribute_printer_apply (struct attribute_printer *self, int attribute)
} }
} }
// TODO: 256-color output // NOTE: commonly terminals have:
// - 8 color -> maybe bold, maybe inverse (should text be bold now?) // 8 colors (worst, bright fg with BOLD, bg sometimes with BLINK)
// - 16 color -> just use the fallback color // 16 colors (okayish, we have the full basic range guaranteed)
// - 88 color -> use the 256color value if available // 88 colors (the same plus a 4^3 RGB cube and a few shades of gray)
// - 256 color -> use the 256color value if available // 256 colors (best, like above but with a larger cube and more gray)
/// Interpolate from the 256-color palette to the 88-color one
static int
attribute_printer_256_to_88 (int color)
{
// These colours are the same everywhere
if (color < 16)
return color;
// 24 -> 8 extra shades of gray
if (color >= 232)
return 80 + (color - 232) / 3;
// 6 * 6 * 6 cube -> 4 * 4 * 4 cube
int x[6] = { 0, 1, 1, 2, 2, 3 };
int index = color - 16;
return 16 +
( x[ index / 36 ] << 8
| x[(index / 6) % 6 ] << 4
| x[(index % 6) ] );
}
static int
attribute_printer_decode_color (int color, bool *is_bright)
{
int16_t c16 = color; hard_assert (c16 < 16);
int16_t c256 = color >> 16; hard_assert (c256 < 256);
*is_bright = false;
switch (max_colors)
{
case 8:
if (c16 >= 8)
{
c16 -= 8;
*is_bright = true;
}
case 16:
return c16;
case 88:
return c256 <= 0 ? c16 : attribute_printer_256_to_88 (c256);
case 256:
return c256 <= 0 ? c16 : c256;
default:
// Unsupported palette
return -1;
}
}
static void static void
attribute_printer_update (struct attribute_printer *self) attribute_printer_update (struct attribute_printer *self)
{ {
int fg = 0; bool fg_is_bright;
if ((int16_t) (self->want_foreground >> 16) > 0) int fg = attribute_printer_decode_color
fg = index_to_terminal_palette ((int16_t) (self->want_foreground >> 16)); (self->want_foreground, &fg_is_bright);
int bg = 0; bool bg_is_bright;
if ((int16_t) (self->want_background >> 16) > 0) int bg = attribute_printer_decode_color
bg = index_to_terminal_palette ((int16_t) (self->want_background >> 16)); (self->want_background, &bg_is_bright);
if (fg <= 0) fg = (int16_t) (self->want_foreground);
if (bg <= 0) bg = (int16_t) (self->want_background);
// TODO: (INVERSE | BOLD) should be used for bright backgrounds
// when possible, i.e. when the foreground shouldn't be bright as well
// and when the BOLD attribute hasn't already been set
int attributes = self->want; int attributes = self->want;
if (max_colors == 8) if (attributes & ATTRIBUTE_INVERSE)
{ {
if (fg >= 8) bool tmp = fg_is_bright;
{ fg_is_bright = bg_is_bright;
attributes |= ATTRIBUTE_BOLD; bg_is_bright = tmp;
fg -= 8;
}
if (bg >= 8)
{
attributes |= ATTRIBUTE_BOLD;
bg -= 8;
}
} }
attribute_printer_reset (self); if (fg_is_bright) attributes |= ATTRIBUTE_BOLD;
if (bg_is_bright) attributes |= ATTRIBUTE_BLINK;
if (fg >= 0) tputs (g_terminal.color_set_fg[fg], 1, self->printer); attribute_printer_reset (self);
if (bg >= 0) tputs (g_terminal.color_set_bg[bg], 1, self->printer);
if (attributes) if (attributes)
tputs (tparm (set_attributes, tputs (tparm (set_attributes,
0, // standout 0, // standout
attributes & ATTRIBUTE_UNDERLINE, attributes & ATTRIBUTE_UNDERLINE,
attributes & ATTRIBUTE_INVERSE, attributes & ATTRIBUTE_INVERSE,
0, // blink attributes & ATTRIBUTE_BLINK,
0, // dim 0, // dim
attributes & ATTRIBUTE_BOLD, attributes & ATTRIBUTE_BOLD,
0, // blank 0, // blank
@ -1824,6 +1835,11 @@ attribute_printer_update (struct attribute_printer *self)
0) // acs 0) // acs
, 1, self->printer); , 1, self->printer);
if (fg >= 0)
tputs (g_terminal.color_set_fg[fg], 1, self->printer);
if (bg >= 0)
tputs (g_terminal.color_set_bg[bg], 1, self->printer);
self->dirty = true; self->dirty = true;
} }