Start work on supporting changing of entries in the color table
This commit is contained in:
parent
c983f002c1
commit
3031d41e72
@ -274,6 +274,9 @@ class Boss(Thread):
|
||||
code += 1
|
||||
self.queue_action(self.apply_change_colors)
|
||||
|
||||
def set_color_table_color(self, code, value):
|
||||
print(11111111, code, value)
|
||||
|
||||
def apply_change_colors(self):
|
||||
self.char_grid.change_colors(self.pending_color_changes)
|
||||
self.pending_color_changes = {}
|
||||
|
||||
@ -57,7 +57,8 @@ new(PyTypeObject *type, PyObject UNUSED *args, PyObject UNUSED *kwds) {
|
||||
self = (ColorProfile *)type->tp_alloc(type, 0);
|
||||
if (self != NULL) {
|
||||
if (FG_BG_256[255] == 0) create_256_color_table();
|
||||
memcpy(self->color_table_256, FG_BG_256, sizeof(FG_BG_256));
|
||||
memcpy(self->color_table, FG_BG_256, sizeof(FG_BG_256));
|
||||
memcpy(self->orig_color_table, FG_BG_256, sizeof(FG_BG_256));
|
||||
}
|
||||
return (PyObject*) self;
|
||||
}
|
||||
@ -72,78 +73,32 @@ static PyObject*
|
||||
update_ansi_color_table(ColorProfile *self, PyObject *val) {
|
||||
#define update_ansi_color_table_doc "Update the 16 basic colors"
|
||||
index_type i;
|
||||
PyObject *t;
|
||||
|
||||
if (!PyList_Check(val)) { PyErr_SetString(PyExc_TypeError, "color table must be a list"); return NULL; }
|
||||
|
||||
#define TO_COLOR \
|
||||
t = PyList_GET_ITEM(val, i); \
|
||||
self->ansi_color_table[i] = PyLong_AsUnsignedLong(t);
|
||||
|
||||
for(i = 30; i < 38; i++) {
|
||||
TO_COLOR;
|
||||
}
|
||||
i = 39; TO_COLOR;
|
||||
for(i = 90; i < 98; i++) {
|
||||
TO_COLOR;
|
||||
}
|
||||
i = 99; TO_COLOR;
|
||||
for(i = 40; i < 48; i++) {
|
||||
TO_COLOR;
|
||||
}
|
||||
i = 49; TO_COLOR;
|
||||
for(i = 100; i < 108; i++) {
|
||||
TO_COLOR;
|
||||
if (PyList_GET_SIZE(val) != 16) { PyErr_SetString(PyExc_TypeError, "color table must have 16 items"); return NULL; }
|
||||
for (i = 0; i < 16; i++) {
|
||||
self->color_table[i] = PyLong_AsUnsignedLong(PyList_GET_ITEM(val, i));
|
||||
self->orig_color_table[i] = self->color_table[i];
|
||||
}
|
||||
Py_RETURN_NONE;
|
||||
}
|
||||
|
||||
static PyObject*
|
||||
ansi_color(ColorProfile *self, PyObject *val) {
|
||||
#define ansi_color_doc "Return the color at the specified index"
|
||||
if (!PyLong_Check(val)) { PyErr_SetString(PyExc_TypeError, "index must be an int"); return NULL; }
|
||||
unsigned long idx = PyLong_AsUnsignedLong(val);
|
||||
if (idx >= sizeof(self->ansi_color_table) / sizeof(self->ansi_color_table[0])) {
|
||||
PyErr_SetString(PyExc_IndexError, "Out of bounds"); return NULL;
|
||||
}
|
||||
return PyLong_FromUnsignedLong(self->ansi_color_table[idx]);
|
||||
}
|
||||
|
||||
static PyObject*
|
||||
color_256(ColorProfile *self, PyObject *val) {
|
||||
#define color_256_doc "Return the color at the specified 256-color index"
|
||||
if (!PyLong_Check(val)) { PyErr_SetString(PyExc_TypeError, "index must be an int"); return NULL; }
|
||||
unsigned long idx = PyLong_AsUnsignedLong(val);
|
||||
if (idx >= 256) {
|
||||
PyErr_SetString(PyExc_IndexError, "Out of bounds"); return NULL;
|
||||
}
|
||||
return PyLong_FromUnsignedLong(self->color_table_256[idx]);
|
||||
}
|
||||
|
||||
static PyObject*
|
||||
as_color(ColorProfile *self, PyObject *val) {
|
||||
#define as_color_doc "Convert the specified terminal color into an (r, g, b) tuple based on the current profile values"
|
||||
if (!PyLong_Check(val)) { PyErr_SetString(PyExc_TypeError, "val must be an int"); return NULL; }
|
||||
unsigned long entry = PyLong_AsUnsignedLong(val);
|
||||
unsigned int t = entry & 0xFF;
|
||||
uint8_t r, g, b;
|
||||
uint8_t r;
|
||||
uint32_t col = 0;
|
||||
PyObject *ans = NULL;
|
||||
switch(t) {
|
||||
case 1:
|
||||
r = (entry >> 8) & 0xff;
|
||||
col = self->ansi_color_table[r];
|
||||
col = self->color_table[r];
|
||||
break;
|
||||
case 2:
|
||||
r = (entry >> 8) & 0xff;
|
||||
col = self->color_table_256[r];
|
||||
break;
|
||||
case 3:
|
||||
r = (entry >> 8) & 0xff;
|
||||
g = (entry >> 16) & 0xff;
|
||||
b = (entry >> 24) & 0xff;
|
||||
ans = Py_BuildValue("BBB", r, g, b);
|
||||
break;
|
||||
col = entry >> 8;
|
||||
default:
|
||||
ans = Py_None; Py_INCREF(Py_None);
|
||||
}
|
||||
@ -151,16 +106,14 @@ as_color(ColorProfile *self, PyObject *val) {
|
||||
return ans;
|
||||
}
|
||||
|
||||
uint32_t to_color(ColorProfile *self, uint32_t entry, uint32_t defval) {
|
||||
uint32_t
|
||||
to_color(ColorProfile *self, uint32_t entry, uint32_t defval) {
|
||||
unsigned int t = entry & 0xFF, r;
|
||||
switch(t) {
|
||||
case 1:
|
||||
r = (entry >> 8) & 0xff;
|
||||
return self->ansi_color_table[r];
|
||||
return self->color_table[r];
|
||||
case 2:
|
||||
r = (entry >> 8) & 0xff;
|
||||
return self->color_table_256[r];
|
||||
case 3:
|
||||
return entry >> 8;
|
||||
default:
|
||||
return defval;
|
||||
@ -172,8 +125,6 @@ uint32_t to_color(ColorProfile *self, uint32_t entry, uint32_t defval) {
|
||||
|
||||
static PyMethodDef methods[] = {
|
||||
METHOD(update_ansi_color_table, METH_O)
|
||||
METHOD(ansi_color, METH_O)
|
||||
METHOD(color_256, METH_O)
|
||||
METHOD(as_color, METH_O)
|
||||
{NULL} /* Sentinel */
|
||||
};
|
||||
|
||||
@ -5,7 +5,6 @@
|
||||
import re
|
||||
import sys
|
||||
from collections import namedtuple
|
||||
from itertools import repeat
|
||||
|
||||
import glfw_constants as glfw
|
||||
|
||||
@ -215,7 +214,7 @@ type_map = {
|
||||
'repaint_delay': int,
|
||||
}
|
||||
|
||||
for name in 'foreground foreground_bold background cursor'.split():
|
||||
for name in 'foreground background cursor'.split():
|
||||
type_map[name] = lambda x: to_color(x, validate=True)
|
||||
for i in range(16):
|
||||
type_map['color%d' % i] = lambda x: to_color(x, validate=True)
|
||||
@ -271,9 +270,6 @@ foreground #dddddd
|
||||
# The background color
|
||||
background #000000
|
||||
|
||||
# The high intensity foreground color
|
||||
foreground_bold #ffffff
|
||||
|
||||
# The cursor color
|
||||
cursor #ffffff
|
||||
|
||||
@ -385,16 +381,4 @@ def build_ansi_color_table(opts: Options=defaults):
|
||||
|
||||
def col(i):
|
||||
return as_int(getattr(opts, 'color{}'.format(i)))
|
||||
ans = list(repeat(0, 120))
|
||||
fg = {30 + i: col(i) for i in range(8)}
|
||||
fg[39] = as_int(opts.foreground)
|
||||
fg.update({90 + i: col(i + 8) for i in range(8)})
|
||||
fg[99] = as_int(opts.foreground_bold)
|
||||
bg = {40 + i: col(i) for i in range(8)}
|
||||
bg[49] = as_int(opts.background)
|
||||
bg.update({100 + i: col(i + 8) for i in range(8)})
|
||||
for k, val in fg.items():
|
||||
ans[k] = val
|
||||
for k, val in bg.items():
|
||||
ans[k] = val
|
||||
return ans
|
||||
return list(map(col, range(16)))
|
||||
|
||||
@ -179,8 +179,8 @@ PyTypeObject Cursor_Type;
|
||||
typedef struct {
|
||||
PyObject_HEAD
|
||||
|
||||
uint32_t color_table_256[256];
|
||||
uint32_t ansi_color_table[120];
|
||||
uint32_t color_table[256];
|
||||
uint32_t orig_color_table[256];
|
||||
|
||||
} ColorProfile;
|
||||
PyTypeObject ColorProfile_Type;
|
||||
@ -364,6 +364,7 @@ void screen_set_margins(Screen *self, unsigned int top, unsigned int bottom);
|
||||
void set_title(Screen *self, PyObject*);
|
||||
void set_icon(Screen *self, PyObject*);
|
||||
void set_dynamic_color(Screen *self, unsigned int code, PyObject*);
|
||||
void set_color_table_color(Screen *self, unsigned int code, PyObject*);
|
||||
void screen_request_capabilities(Screen *, PyObject *);
|
||||
void report_device_attributes(Screen *self, unsigned int UNUSED mode, bool UNUSED secondary);
|
||||
void select_graphic_rendition(Screen *self, unsigned int *params, unsigned int count);
|
||||
|
||||
@ -198,6 +198,7 @@ handle_esc_mode_char(Screen *screen, uint32_t ch, PyObject DUMP_UNUSED *dump_cal
|
||||
static inline void
|
||||
dispatch_osc(Screen *screen, PyObject DUMP_UNUSED *dump_callback) {
|
||||
#define DISPATCH_OSC(name) REPORT_OSC(name, string); name(screen, string);
|
||||
#define SET_COLOR(name) REPORT_OSC(name, string); name(screen, code, string);
|
||||
const unsigned int limit = screen->parser_buf_pos;
|
||||
unsigned int code=0, i;
|
||||
for (i = 0; i < MIN(limit, 5); i++) {
|
||||
@ -220,12 +221,15 @@ dispatch_osc(Screen *screen, PyObject DUMP_UNUSED *dump_callback) {
|
||||
case 2:
|
||||
DISPATCH_OSC(set_title);
|
||||
break;
|
||||
case 4:
|
||||
case 104:
|
||||
SET_COLOR(set_color_table_color);
|
||||
break;
|
||||
case 10:
|
||||
case 11:
|
||||
case 110:
|
||||
case 111:
|
||||
REPORT_OSC(set_dynamic_color, string);
|
||||
set_dynamic_color(screen, code, string);
|
||||
SET_COLOR(set_dynamic_color);
|
||||
break;
|
||||
default:
|
||||
REPORT_ERROR("Unknown OSC code: %u", code);
|
||||
@ -234,6 +238,7 @@ dispatch_osc(Screen *screen, PyObject DUMP_UNUSED *dump_callback) {
|
||||
Py_CLEAR(string);
|
||||
}
|
||||
#undef DISPATCH_OSC
|
||||
#undef SET_COLOR
|
||||
}
|
||||
// }}}
|
||||
|
||||
|
||||
@ -199,14 +199,14 @@ void select_graphic_rendition(Screen *self, unsigned int *params, unsigned int c
|
||||
switch(attr) { \
|
||||
case 5: \
|
||||
if (i < count) \
|
||||
self->cursor->which = (params[i++] & 0xFF) << 8 | 2; \
|
||||
self->cursor->which = (params[i++] & 0xFF) << 8 | 1; \
|
||||
break; \
|
||||
case 2: \
|
||||
if (i < count - 2) { \
|
||||
r = params[i++] & 0xFF; \
|
||||
g = params[i++] & 0xFF; \
|
||||
b = params[i++] & 0xFF; \
|
||||
self->cursor->which = r << 24 | g << 16 | b << 8 | 3; \
|
||||
self->cursor->which = r << 24 | g << 16 | b << 8 | 2; \
|
||||
}\
|
||||
break; \
|
||||
} \
|
||||
@ -243,14 +243,18 @@ void select_graphic_rendition(Screen *self, unsigned int *params, unsigned int c
|
||||
self->cursor->strikethrough = false; break;
|
||||
START_ALLOW_CASE_RANGE
|
||||
case 30 ... 37:
|
||||
self->cursor->fg = ((attr - 30) << 8) | 1; break;
|
||||
case 39:
|
||||
case 90 ... 97:
|
||||
self->cursor->fg = (attr << 8) | 1; break;
|
||||
self->cursor->fg = 0; break;
|
||||
case 40 ... 47:
|
||||
self->cursor->bg = ((attr - 40) << 8) | 1; break;
|
||||
case 49:
|
||||
self->cursor->bg = 0; break;
|
||||
case 90 ... 97:
|
||||
self->cursor->fg = ((attr - 90 + 8) << 8) | 1; break;
|
||||
case 100 ... 107:
|
||||
self->cursor->bg = ((attr - 100 + 8) << 8) | 1; break;
|
||||
END_ALLOW_CASE_RANGE
|
||||
self->cursor->bg = (attr << 8) | 1; break;
|
||||
case 38:
|
||||
SET_COLOR(fg);
|
||||
case 48:
|
||||
@ -810,6 +814,11 @@ void set_dynamic_color(Screen *self, unsigned int code, PyObject *color) {
|
||||
if (PyErr_Occurred()) { PyErr_Print(); PyErr_Clear(); }
|
||||
}
|
||||
|
||||
void set_color_table_color(Screen *self, unsigned int code, PyObject *color) {
|
||||
PyObject_CallMethod(self->callbacks, "set_color_table_color", "IO", code, color);
|
||||
if (PyErr_Occurred()) { PyErr_Print(); PyErr_Clear(); }
|
||||
}
|
||||
|
||||
void screen_request_capabilities(Screen *self, PyObject *q) {
|
||||
PyObject_CallMethod(self->callbacks, "request_capabilities", "O", q);
|
||||
if (PyErr_Occurred()) { PyErr_Print(); PyErr_Clear(); }
|
||||
|
||||
@ -130,8 +130,8 @@ string_capabilities = {
|
||||
'ind': r'^J',
|
||||
'indn': r'\E[%p1%dS',
|
||||
# initialize color (set dynamic colors)
|
||||
# 'initc': r'\E]4;%p1%d;rgb\:%p2%{255}%*%{1000}%/%2.2X/%p3%{255}%*%{1000}%/%2.2X/%p4%{255}%*%{1000}%/%2.2X\E\\',
|
||||
# Set all color pairs to original values
|
||||
'initc': r'\E]4;%p1%d;rgb\:%p2%{255}%*%{1000}%/%2.2X/%p3%{255}%*%{1000}%/%2.2X/%p4%{255}%*%{1000}%/%2.2X\E\\',
|
||||
# Set all colors to original values
|
||||
'oc': r'\E]104\007',
|
||||
# turn on blank mode (characters invisible)
|
||||
# 'invis': r'\E[8m',
|
||||
@ -278,7 +278,7 @@ termcap_aliases.update({
|
||||
'al': 'il1',
|
||||
'sf': 'ind',
|
||||
'SF': 'indn',
|
||||
# 'Ic': 'initc',
|
||||
'Ic': 'initc',
|
||||
'oc': 'oc',
|
||||
# 'mk': 'invis',
|
||||
'kb': 'kbs',
|
||||
|
||||
@ -273,8 +273,8 @@ class TestDataTypes(BaseTest):
|
||||
c.update_ansi_color_table(build_ansi_color_table())
|
||||
for i in range(8):
|
||||
col = getattr(defaults, 'color{}'.format(i))
|
||||
self.assertEqual(c.ansi_color(30 + i), col[0] << 16 | col[1] << 8 | col[2])
|
||||
self.ae(c.color_256(255), 0xeeeeee)
|
||||
self.assertEqual(c.as_color(i << 8 | 1), (col[0], col[1], col[2]))
|
||||
self.ae(c.as_color(255 << 8 | 1), (0xee, 0xee, 0xee))
|
||||
|
||||
def test_sprite_map(self):
|
||||
s = SpriteMap(10, 2)
|
||||
|
||||
@ -123,14 +123,14 @@ class TestParser(BaseTest):
|
||||
for attr in 'bold italic reverse strikethrough'.split():
|
||||
self.assertTrue(getattr(s.cursor, attr))
|
||||
self.ae(s.cursor.decoration, 1)
|
||||
self.ae(s.cursor.fg, 34 << 8 | 1)
|
||||
self.ae(s.cursor.bg, 44 << 8 | 1)
|
||||
self.ae(s.cursor.fg, 4 << 8 | 1)
|
||||
self.ae(s.cursor.bg, 4 << 8 | 1)
|
||||
pb('\033[38;5;1;48;5;7m', ('select_graphic_rendition', 6))
|
||||
self.ae(s.cursor.fg, 1 << 8 | 2)
|
||||
self.ae(s.cursor.bg, 7 << 8 | 2)
|
||||
self.ae(s.cursor.fg, 1 << 8 | 1)
|
||||
self.ae(s.cursor.bg, 7 << 8 | 1)
|
||||
pb('\033[38;2;1;2;3;48;2;7;8;9m', ('select_graphic_rendition', 10))
|
||||
self.ae(s.cursor.fg, 1 << 24 | 2 << 16 | 3 << 8 | 3)
|
||||
self.ae(s.cursor.bg, 7 << 24 | 8 << 16 | 9 << 8 | 3)
|
||||
self.ae(s.cursor.fg, 1 << 24 | 2 << 16 | 3 << 8 | 2)
|
||||
self.ae(s.cursor.bg, 7 << 24 | 8 << 16 | 9 << 8 | 2)
|
||||
c = Callbacks()
|
||||
s.callbacks = c
|
||||
pb('\033[5n', ('report_device_status', 5, 0))
|
||||
|
||||
@ -50,6 +50,7 @@ xterm-kitty|KovIdTTY,
|
||||
il1=\E[L,
|
||||
ind=^J,
|
||||
indn=\E[%p1%dS,
|
||||
initc=\E]4;%p1%d;rgb\:%p2%{255}%*%{1000}%/%2.2X/%p3%{255}%*%{1000}%/%2.2X/%p4%{255}%*%{1000}%/%2.2X\E\\,
|
||||
kEND=\E[1;2F,
|
||||
kHOM=\E[1;2H,
|
||||
kLFT=\E[1;2D,
|
||||
|
||||
Binary file not shown.
Loading…
x
Reference in New Issue
Block a user