Implement dynamic control of transparent background colors via escape code
Still have to implement it via remote control
This commit is contained in:
parent
dbfeb8d6a4
commit
c3130419a7
7 changed files with 98 additions and 6 deletions
|
|
@ -77,6 +77,8 @@ Detailed list of changes
|
|||
0.36.3 [future]
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
- The option ``second_transparent_bg`` has been removed and replaced by :opt:`transparent_background_colors` which allows setting up to seven additional colors that will be transparent, with individual opacities per color (:iss:`7646`)
|
||||
|
||||
- Fix a regression in the previous release that broke use of the ``cd`` command in session files (:iss:`7829`)
|
||||
|
||||
- macOS: Fix shortcuts that become entries in the global menubar being reported as removed shortcuts in the debug output
|
||||
|
|
|
|||
|
|
@ -69,8 +69,11 @@ selection_foreground The foreground color of selections
|
|||
cursor The color of the text cursor Foreground color
|
||||
cursor_text The color of text under the cursor Background color
|
||||
visual_bell The color of a visual bell Automatic color selection based on current screen colors
|
||||
second_transparent_background A color that might be rendered semi-transparent No second color is made transparent
|
||||
in addition to the default background color
|
||||
transparent_background_color1..8 A background color that is rendered Unset
|
||||
with the specified opacity in cells that have
|
||||
the specified background color. An opacity
|
||||
value less than zero means, use the
|
||||
:opt:`background_opacity` value.
|
||||
================================= =============================================== ===============================
|
||||
|
||||
In this table the third column shows what effect setting the color to *dynamic*
|
||||
|
|
@ -160,8 +163,19 @@ RGB colors are encoded in one of three forms:
|
|||
|
||||
``rgbi:<red>/<green>/<blue>``
|
||||
red, green, and blue are floating-point values between 0.0 and 1.0, inclusive. The input format for these values is an optional
|
||||
sign, a string of numbers possibly containing a decimal point, and an optional exponent field containing an E or e followed by a possibly
|
||||
signed integer string.
|
||||
sign, a string of numbers possibly containing a decimal point, and an optional exponent field containing an E or e followed by a possibly
|
||||
signed integer string. Values outside the ``0 - 1`` range must be clipped to be within the range.
|
||||
|
||||
If a color should have an alpha component, it must be suffixed to the color
|
||||
specification in the form :code:`@number between zero and one`. For example::
|
||||
|
||||
red@0.5 rgb:ff0000@0.1 #ff0000@0.3
|
||||
|
||||
The syntax for the floating point alpha component is the same as used for the
|
||||
components of ``rgbi`` defined above. When not specified, the default alpha
|
||||
value is ``1.0``. Values outside the range ``0 - 1`` must be clipped
|
||||
to be within the range, negative values may have special context dependent
|
||||
meaning.
|
||||
|
||||
In addition, the following color names are accepted (case-insensitively) corresponding to the
|
||||
specified RGB values.
|
||||
|
|
|
|||
|
|
@ -249,10 +249,12 @@ colorprofile_to_transparent_color(const ColorProfile *self, unsigned index, colo
|
|||
if (index < arraysz(self->configured_transparent_colors)) {
|
||||
if (self->overriden_transparent_colors[index].is_set) {
|
||||
*color = self->overriden_transparent_colors[index].color; *opacity = self->overriden_transparent_colors[index].opacity;
|
||||
if (*opacity < 0) *opacity = OPT(background_opacity);
|
||||
return true;
|
||||
}
|
||||
if (self->configured_transparent_colors[index].is_set) {
|
||||
*color = self->configured_transparent_colors[index].color; *opacity = self->configured_transparent_colors[index].opacity;
|
||||
if (*opacity < 0) *opacity = OPT(background_opacity);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
|
@ -537,6 +539,36 @@ reload_from_opts(ColorProfile *self, PyObject *args UNUSED) {
|
|||
Py_RETURN_NONE;
|
||||
}
|
||||
|
||||
static PyObject*
|
||||
get_transparent_background_color(ColorProfile *self, PyObject *index) {
|
||||
if (!PyLong_Check(index)) { PyErr_SetString(PyExc_TypeError, "index must be an int"); return NULL; }
|
||||
unsigned long idx = PyLong_AsUnsignedLong(index);
|
||||
if (PyErr_Occurred()) return NULL;
|
||||
if (idx >= arraysz(self->configured_transparent_colors)) Py_RETURN_NONE;
|
||||
TransparentDynamicColor *c = self->overriden_transparent_colors[idx].is_set ? self->overriden_transparent_colors + idx : self->configured_transparent_colors + idx;
|
||||
if (!c->is_set) Py_RETURN_NONE;
|
||||
float opacity = c->opacity >= 0 ? c->opacity : OPT(background_opacity);
|
||||
return (PyObject*)alloc_color((c->color >> 16) & 0xff, (c->color >> 8) & 0xff, c->color & 0xff, (unsigned)(255.f * opacity));
|
||||
}
|
||||
|
||||
static PyObject*
|
||||
set_transparent_background_color(ColorProfile *self, PyObject *const *args, Py_ssize_t nargs) {
|
||||
if (nargs < 1) { PyErr_SetString(PyExc_TypeError, "must specify index"); return NULL; }
|
||||
if (!PyLong_Check(args[0])) { PyErr_SetString(PyExc_TypeError, "index must be an int"); return NULL; }
|
||||
unsigned long idx = PyLong_AsUnsignedLong(args[0]);
|
||||
if (PyErr_Occurred()) return NULL;
|
||||
if (idx >= arraysz(self->configured_transparent_colors)) Py_RETURN_NONE;
|
||||
if (nargs < 2) { self->overriden_transparent_colors[idx].is_set = false; Py_RETURN_NONE; }
|
||||
if (!PyObject_TypeCheck(args[1], &Color_Type)) { PyErr_SetString(PyExc_TypeError, "color must be Color object"); return NULL; }
|
||||
Color *c = (Color*)args[1];
|
||||
float opacity = (float)(c->color.alpha) / 255.f;
|
||||
if (nargs > 2 && PyFloat_Check(args[2])) opacity = (float)PyFloat_AsDouble(args[2]);
|
||||
self->overriden_transparent_colors[idx].is_set = true;
|
||||
self->overriden_transparent_colors[idx].color = c->color.rgb;
|
||||
self->overriden_transparent_colors[idx].opacity = MAX(-1.f, MIN(opacity, 1.f));
|
||||
Py_RETURN_NONE;
|
||||
}
|
||||
|
||||
static PyMethodDef cp_methods[] = {
|
||||
METHOD(reset_color_table, METH_NOARGS)
|
||||
METHOD(as_dict, METH_NOARGS)
|
||||
|
|
@ -544,7 +576,9 @@ static PyMethodDef cp_methods[] = {
|
|||
METHOD(as_color, METH_O)
|
||||
METHOD(reset_color, METH_O)
|
||||
METHOD(set_color, METH_VARARGS)
|
||||
METHODB(get_transparent_background_color, METH_O),
|
||||
METHODB(reload_from_opts, METH_VARARGS),
|
||||
{"set_transparent_background_color", (PyCFunction)(void(*)(void))set_transparent_background_color, METH_FASTCALL, ""},
|
||||
{NULL} /* Sentinel */
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -828,6 +828,9 @@ class ColorProfile:
|
|||
|
||||
def reload_from_opts(self, opts: Optional[Options] = None) -> None: ...
|
||||
|
||||
def get_transparent_background_color(self, index: int) -> Color | None: ...
|
||||
def set_transparent_background_color(self, index: int, color: Color | None = None, opacity: float | None = None) -> None: ...
|
||||
|
||||
|
||||
def patch_color_profiles(
|
||||
spec: Dict[str, Optional[int]], profiles: Tuple[ColorProfile, ...], change_configured: bool
|
||||
|
|
|
|||
|
|
@ -447,13 +447,41 @@ def process_remote_print(msg: memoryview) -> str:
|
|||
return replace_c0_codes_except_nl_space_tab(base64_decode(msg)).decode('utf-8', 'replace')
|
||||
|
||||
|
||||
def transparent_background_color_control(cp: ColorProfile, responses: dict[str, str], index: int, key: str, sep: str, val: str) -> None:
|
||||
if sep == '=':
|
||||
if val == '?':
|
||||
if index > 8:
|
||||
responses[key] = '?'
|
||||
else:
|
||||
c = cp.get_transparent_background_color(index - 1)
|
||||
if c is None:
|
||||
responses[key] = ''
|
||||
else:
|
||||
opacity = max(0, min(c.alpha / 255.0, 1))
|
||||
responses[key] = f'rgb:{c.red:02x}/{c.green:02x}/{c.blue:02x}@{opacity:.4f}'
|
||||
elif index <= 8:
|
||||
col, _, o = val.partition('@')
|
||||
try:
|
||||
opacity = float(o)
|
||||
except Exception:
|
||||
opacity = -1.0
|
||||
c = to_color(col)
|
||||
if c is not None:
|
||||
cp.set_transparent_background_color(index - 1, c, opacity)
|
||||
elif index <= 8:
|
||||
cp.set_transparent_background_color(index - 1)
|
||||
|
||||
|
||||
def color_control(cp: ColorProfile, code: int, value: Union[str, bytes, memoryview] = '') -> str:
|
||||
if isinstance(value, (bytes, memoryview)):
|
||||
value = str(value, 'utf-8', 'replace')
|
||||
responses = {}
|
||||
responses: dict[str, str] = {}
|
||||
for rec in value.split(';'):
|
||||
key, sep, val = rec.partition('=')
|
||||
# TODO: Add transparent_colors
|
||||
if key.startswith('transparent_background_color'):
|
||||
index = int(key[len('transparent_background_color'):])
|
||||
transparent_background_color_control(cp, responses, index, key, sep, val)
|
||||
continue
|
||||
attr = {
|
||||
'foreground': 'default_fg', 'background': 'default_bg',
|
||||
'selection_background': 'highlight_bg', 'selection_foreground': 'highlight_fg',
|
||||
|
|
@ -481,6 +509,7 @@ def serialize_color(c: Optional[Color]) -> str:
|
|||
else:
|
||||
if attr:
|
||||
if val:
|
||||
val = val.partition('@')[0]
|
||||
col = to_color(val)
|
||||
if col is not None:
|
||||
setattr(cp, attr, col)
|
||||
|
|
@ -489,6 +518,7 @@ def serialize_color(c: Optional[Color]) -> str:
|
|||
setattr(cp, attr, None)
|
||||
else:
|
||||
if 0 <= colnum <= 255:
|
||||
val = val.partition('@')[0]
|
||||
col = to_color(val)
|
||||
if col is not None:
|
||||
cp.set_color(colnum, color_as_int(col))
|
||||
|
|
|
|||
|
|
@ -59,6 +59,8 @@ def color_control(self, code, data) -> None:
|
|||
response = color_control(self.color_profile, code, data)
|
||||
if response:
|
||||
def p(x):
|
||||
if '@' in x:
|
||||
return (to_color(x.partition('@')[0]), int(255 * float(x.partition('@')[2])))
|
||||
ans = to_color(x)
|
||||
if ans is None:
|
||||
ans = x
|
||||
|
|
|
|||
|
|
@ -1280,3 +1280,10 @@ def q(send, expected=None):
|
|||
q({'selection_background': ''})
|
||||
self.assertIsNone(s.color_profile.highlight_bg)
|
||||
q({'selection_background': '?'}, {'selection_background': ''})
|
||||
s.color_profile.reload_from_opts(defaults)
|
||||
q({'transparent_background_color9': '?'}, {'transparent_background_color9': '?'})
|
||||
q({'transparent_background_color2': '?'}, {'transparent_background_color2': ''})
|
||||
q({'transparent_background_color2': 'red@0.5'})
|
||||
q({'transparent_background_color2': '?'}, {'transparent_background_color2': (Color(255, 0, 0), 126)})
|
||||
q({'transparent_background_color2': '#ffffff@-1'})
|
||||
q({'transparent_background_color2': '?'}, {'transparent_background_color2': (Color(255, 255, 255), 255)})
|
||||
|
|
|
|||
Loading…
Reference in a new issue