Add option background_image_anchor to configure bgimage position
This commit is contained in:
parent
ee852cf5fc
commit
2aa01c58a1
@ -9,6 +9,7 @@
|
||||
#define tex_bottom 1
|
||||
|
||||
uniform float tiled;
|
||||
uniform vec2 translate; // [ left, top ]
|
||||
uniform vec4 sizes; // [ window_width, window_height, image_width, image_height ]
|
||||
|
||||
out vec2 texcoord;
|
||||
@ -37,6 +38,6 @@ float tiling_factor(int i) {
|
||||
|
||||
void main() {
|
||||
vec2 tex_coords = tex_map[gl_VertexID];
|
||||
texcoord = vec2(tex_coords[0] * tiling_factor(0), tex_coords[1] * tiling_factor(1));
|
||||
texcoord = vec2(tex_coords[0] * tiling_factor(0) - translate[0], tex_coords[1] * tiling_factor(1) - translate[1]);
|
||||
gl_Position = vec4(pos_map[gl_VertexID], 0, 1);
|
||||
}
|
||||
|
||||
@ -1975,11 +1975,8 @@ class Boss:
|
||||
|
||||
self.choose_entry('Choose an OS window to move the tab to', items, chosen)
|
||||
|
||||
def set_background_image(self, path: Optional[str], os_windows: Tuple[int, ...], configured: bool, layout: Optional[str]) -> None:
|
||||
if layout:
|
||||
set_background_image(path, os_windows, configured, layout)
|
||||
else:
|
||||
set_background_image(path, os_windows, configured)
|
||||
def set_background_image(self, path: Optional[str], os_windows: Tuple[int, ...], configured: bool, layout: Optional[str], anchor: Optional[str]) -> None:
|
||||
set_background_image(path, os_windows, configured, layout, anchor)
|
||||
for os_window_id in os_windows:
|
||||
self.default_bg_changed_for(os_window_id)
|
||||
|
||||
|
||||
@ -65,6 +65,7 @@ typedef enum MouseTrackingProtocols { NORMAL_PROTOCOL, UTF8_PROTOCOL, SGR_PROTOC
|
||||
typedef enum MouseShapes { BEAM, HAND, ARROW } MouseShape;
|
||||
typedef enum { NONE, MENUBAR, WINDOW, ALL } WindowTitleIn;
|
||||
typedef enum { TILING, SCALED, MIRRORED } BackgroundImageLayout;
|
||||
typedef enum { NORTHWEST, NORTH, NORTHEAST, EAST, SOUTHEAST, SOUTH, SOUTHWEST, WEST, CENTER } BackgroundImageAnchor;
|
||||
|
||||
#define MAX_CHILDREN 512
|
||||
#define BLANK_CHAR 0
|
||||
|
||||
@ -598,7 +598,8 @@ def set_background_image(
|
||||
path: Optional[str],
|
||||
os_window_ids: Tuple[int, ...],
|
||||
configured: bool = True,
|
||||
layout_name: Optional[str] = None
|
||||
layout_name: Optional[str] = None,
|
||||
anchor_name: Optional[str] = None
|
||||
) -> None:
|
||||
pass
|
||||
|
||||
|
||||
@ -66,6 +66,7 @@ typedef struct {
|
||||
unsigned int height, width;
|
||||
uint8_t* bitmap;
|
||||
uint32_t refcnt;
|
||||
BackgroundImageAnchor anchor;
|
||||
} BackgroundImage;
|
||||
|
||||
typedef struct {
|
||||
|
||||
@ -1110,6 +1110,11 @@ opt('background_image_layout', 'tiled',
|
||||
long_text='Whether to tile or scale the background image.'
|
||||
)
|
||||
|
||||
opt('background_image_anchor', 'northwest',
|
||||
choices=('northwest', 'north', 'northeast', 'east', 'southeast', 'south', 'southwest', 'west', 'center'), ctype='bganchor',
|
||||
long_text='Where to position the background image in the window.'
|
||||
)
|
||||
|
||||
opt('background_image_linear', 'no',
|
||||
option_type='to_bool', ctype='bool',
|
||||
long_text='When background image is scaled, whether linear interpolation should be used.'
|
||||
|
||||
8
kitty/options/parse.py
generated
8
kitty/options/parse.py
generated
@ -57,6 +57,14 @@ class Parser:
|
||||
def background_image(self, val: str, ans: typing.Dict[str, typing.Any]) -> None:
|
||||
ans['background_image'] = config_or_absolute_path(val)
|
||||
|
||||
def background_image_anchor(self, val: str, ans: typing.Dict[str, typing.Any]) -> None:
|
||||
val = val.lower()
|
||||
if val not in self.choices_for_background_image_anchor:
|
||||
raise ValueError(f"The value {val} is not a valid choice for background_image_anchor")
|
||||
ans["background_image_anchor"] = val
|
||||
|
||||
choices_for_background_image_anchor = frozenset(('northwest', 'north', 'northeast', 'east', 'southeast', 'south', 'southwest', 'west', 'center'))
|
||||
|
||||
def background_image_layout(self, val: str, ans: typing.Dict[str, typing.Any]) -> None:
|
||||
val = val.lower()
|
||||
if val not in self.choices_for_background_image_layout:
|
||||
|
||||
15
kitty/options/to-c-generated.h
generated
15
kitty/options/to-c-generated.h
generated
@ -694,6 +694,19 @@ convert_from_opts_background_image_layout(PyObject *py_opts, Options *opts) {
|
||||
Py_DECREF(ret);
|
||||
}
|
||||
|
||||
static void
|
||||
convert_from_python_background_image_anchor(PyObject *val, Options *opts) {
|
||||
opts->background_image_anchor = bganchor(val);
|
||||
}
|
||||
|
||||
static void
|
||||
convert_from_opts_background_image_anchor(PyObject *py_opts, Options *opts) {
|
||||
PyObject *ret = PyObject_GetAttrString(py_opts, "background_image_anchor");
|
||||
if (ret == NULL) return;
|
||||
convert_from_python_background_image_anchor(ret, opts);
|
||||
Py_DECREF(ret);
|
||||
}
|
||||
|
||||
static void
|
||||
convert_from_python_background_image_linear(PyObject *val, Options *opts) {
|
||||
opts->background_image_linear = PyObject_IsTrue(val);
|
||||
@ -1049,6 +1062,8 @@ convert_opts_from_python_opts(PyObject *py_opts, Options *opts) {
|
||||
if (PyErr_Occurred()) return false;
|
||||
convert_from_opts_background_image_layout(py_opts, opts);
|
||||
if (PyErr_Occurred()) return false;
|
||||
convert_from_opts_background_image_anchor(py_opts, opts);
|
||||
if (PyErr_Occurred()) return false;
|
||||
convert_from_opts_background_image_linear(py_opts, opts);
|
||||
if (PyErr_Occurred()) return false;
|
||||
convert_from_opts_dynamic_background_opacity(py_opts, opts);
|
||||
|
||||
@ -77,6 +77,36 @@ bglayout(PyObject *layout_name) {
|
||||
return TILING;
|
||||
}
|
||||
|
||||
static BackgroundImageAnchor
|
||||
bganchor(PyObject *anchor_name) {
|
||||
const char *name = PyUnicode_AsUTF8(anchor_name);
|
||||
if (strcmp(name, "north") == 0) {
|
||||
return NORTH;
|
||||
}
|
||||
else if (strcmp(name, "northeast") == 0) {
|
||||
return NORTHEAST;
|
||||
}
|
||||
else if (strcmp(name, "east") == 0) {
|
||||
return EAST;
|
||||
}
|
||||
else if (strcmp(name, "southeast") == 0) {
|
||||
return SOUTHEAST;
|
||||
}
|
||||
else if (strcmp(name, "south") == 0) {
|
||||
return SOUTH;
|
||||
}
|
||||
else if (strcmp(name, "southwest") == 0) {
|
||||
return SOUTHWEST;
|
||||
}
|
||||
else if (strcmp(name, "west") == 0) {
|
||||
return WEST;
|
||||
}
|
||||
else if (strcmp(name, "center") == 0) {
|
||||
return CENTER;
|
||||
}
|
||||
return NORTHWEST;
|
||||
}
|
||||
|
||||
#define STR_SETTER(name) { \
|
||||
free(opts->name); opts->name = NULL; \
|
||||
if (src == Py_None || !PyUnicode_Check(src)) return; \
|
||||
|
||||
4
kitty/options/types.py
generated
4
kitty/options/types.py
generated
@ -14,6 +14,7 @@ from kitty.types import FloatEdges, SingleKey
|
||||
import kitty.types
|
||||
|
||||
if typing.TYPE_CHECKING:
|
||||
choices_for_background_image_anchor = typing.Literal['northwest', 'north', 'northeast', 'east', 'southeast', 'south', 'southwest', 'west', 'center']
|
||||
choices_for_background_image_layout = typing.Literal['mirror-tiled', 'scaled', 'tiled']
|
||||
choices_for_default_pointer_shape = typing.Literal['arrow', 'beam', 'hand']
|
||||
choices_for_linux_display_server = typing.Literal['auto', 'wayland', 'x11']
|
||||
@ -27,6 +28,7 @@ if typing.TYPE_CHECKING:
|
||||
choices_for_tab_powerline_style = typing.Literal['angled', 'round', 'slanted']
|
||||
choices_for_tab_switch_strategy = typing.Literal['last', 'left', 'previous', 'right']
|
||||
else:
|
||||
choices_for_background_image_anchor = str
|
||||
choices_for_background_image_layout = str
|
||||
choices_for_default_pointer_shape = str
|
||||
choices_for_linux_display_server = str
|
||||
@ -53,6 +55,7 @@ option_names = ( # {{{
|
||||
'allow_remote_control',
|
||||
'background',
|
||||
'background_image',
|
||||
'background_image_anchor',
|
||||
'background_image_layout',
|
||||
'background_image_linear',
|
||||
'background_opacity',
|
||||
@ -453,6 +456,7 @@ class Options:
|
||||
allow_remote_control: str = 'n'
|
||||
background: Color = Color(0, 0, 0)
|
||||
background_image: typing.Optional[str] = None
|
||||
background_image_anchor: choices_for_background_image_anchor = 'northwest'
|
||||
background_image_layout: choices_for_background_image_layout = 'tiled'
|
||||
background_image_linear: bool = False
|
||||
background_opacity: float = 1.0
|
||||
|
||||
@ -24,6 +24,7 @@ class SetBackgroundImage(RemoteCommand):
|
||||
img_id+: Unique uuid (as string) used for chunking
|
||||
match: Window to change opacity in
|
||||
layout: The image layout
|
||||
anchor: The image anchor
|
||||
all: Boolean indicating operate on all windows
|
||||
configured: Boolean indicating if the configured value should be changed
|
||||
'''
|
||||
@ -52,6 +53,12 @@ choices=tiled,scaled,mirror-tiled,configured
|
||||
How the image should be displayed. The value of configured will use the configured value.
|
||||
|
||||
|
||||
--anchor
|
||||
type=choices
|
||||
choices=northwest,north,northeast,east,southeast,south,southwest,west,northwest,north,center,configured
|
||||
Where the image should be positioned. The value of configured will use the configured value.
|
||||
|
||||
|
||||
--no-response
|
||||
type=bool-set
|
||||
default=false
|
||||
@ -74,6 +81,7 @@ failed, the command will exit with a success code.
|
||||
'match': opts.match,
|
||||
'configured': opts.configured,
|
||||
'layout': opts.layout,
|
||||
'anchor': opts.anchor,
|
||||
'all': opts.all,
|
||||
'img_id': str(uuid4())
|
||||
}
|
||||
@ -110,6 +118,7 @@ failed, the command will exit with a success code.
|
||||
windows = self.windows_for_payload(boss, window, payload_get)
|
||||
os_windows = tuple({w.os_window_id for w in windows})
|
||||
layout = payload_get('layout')
|
||||
anchor = payload_get('anchor')
|
||||
if data == '-':
|
||||
path = None
|
||||
else:
|
||||
@ -120,7 +129,7 @@ failed, the command will exit with a success code.
|
||||
f.flush()
|
||||
|
||||
try:
|
||||
boss.set_background_image(path, os_windows, payload_get('configured'), layout)
|
||||
boss.set_background_image(path, os_windows, payload_get('configured'), layout, anchor)
|
||||
except ValueError as err:
|
||||
err.hide_traceback = True # type: ignore
|
||||
raise
|
||||
|
||||
@ -166,7 +166,7 @@ typedef struct {
|
||||
static CellProgramLayout cell_program_layouts[NUM_PROGRAMS];
|
||||
static ssize_t blit_vertex_array;
|
||||
typedef struct {
|
||||
GLint image_location, tiled_location, sizes_location, opacity_location, premult_location;
|
||||
GLint image_location, tiled_location, translate_location, sizes_location, opacity_location, premult_location;
|
||||
} BGImageProgramLayout;
|
||||
static BGImageProgramLayout bgimage_program_layout = {0};
|
||||
typedef struct {
|
||||
@ -199,6 +199,7 @@ init_cell_program(void) {
|
||||
bgimage_program_layout.opacity_location = get_uniform_location(BGIMAGE_PROGRAM, "opacity");
|
||||
bgimage_program_layout.sizes_location = get_uniform_location(BGIMAGE_PROGRAM, "sizes");
|
||||
bgimage_program_layout.tiled_location = get_uniform_location(BGIMAGE_PROGRAM, "tiled");
|
||||
bgimage_program_layout.translate_location = get_uniform_location(BGIMAGE_PROGRAM, "translate");
|
||||
bgimage_program_layout.premult_location = get_uniform_location(BGIMAGE_PROGRAM, "premult");
|
||||
tint_program_layout.tint_color_location = get_uniform_location(TINT_PROGRAM, "tint_color");
|
||||
tint_program_layout.edges_location = get_uniform_location(TINT_PROGRAM, "edges");
|
||||
@ -415,6 +416,20 @@ draw_bg(OSWindow *w) {
|
||||
glUniform1f(bgimage_program_layout.tiled_location, tiled);
|
||||
bgimage_constants_set = true;
|
||||
}
|
||||
float translate_left = 0.0f, translate_top = 0.0f;
|
||||
if (OPT(background_image_layout) != SCALED) {
|
||||
if (w->bgimage->anchor == NORTH || w->bgimage->anchor == CENTER || w->bgimage->anchor == SOUTH) {
|
||||
translate_left = ((float)w->window_width / 2.0f - (float)w->bgimage->width / 2.0f) / (float)w->bgimage->width;
|
||||
} else if (w->bgimage->anchor == NORTHEAST || w->bgimage->anchor == EAST || w->bgimage->anchor == SOUTHEAST) {
|
||||
translate_left = ((float)w->window_width - (float)w->bgimage->width) / (float)w->bgimage->width;
|
||||
}
|
||||
if (w->bgimage->anchor == WEST || w->bgimage->anchor == CENTER || w->bgimage->anchor == EAST) {
|
||||
translate_top = ((float)w->window_height / 2.0f - (float)w->bgimage->height / 2.0f) / (float)w->bgimage->height;
|
||||
} else if (w->bgimage->anchor == SOUTHWEST || w->bgimage->anchor == SOUTH || w->bgimage->anchor == SOUTHEAST) {
|
||||
translate_top = ((float)w->window_height - (float)w->bgimage->height) / (float)w->bgimage->height;
|
||||
}
|
||||
}
|
||||
glUniform2f(bgimage_program_layout.translate_location, (GLfloat)translate_left, (GLfloat)translate_top);
|
||||
glUniform4f(bgimage_program_layout.sizes_location,
|
||||
(GLfloat)w->window_width, (GLfloat)w->window_height, (GLfloat)w->bgimage->width, (GLfloat)w->bgimage->height);
|
||||
glUniform1f(bgimage_program_layout.premult_location, w->is_semi_transparent ? 1.f : 0.f);
|
||||
|
||||
@ -180,6 +180,7 @@ add_os_window() {
|
||||
global_state.bgimage = calloc(1, sizeof(BackgroundImage));
|
||||
if (!global_state.bgimage) fatal("Out of memory allocating the global bg image object");
|
||||
global_state.bgimage->refcnt++;
|
||||
global_state.bgimage->anchor = OPT(background_image_anchor);
|
||||
size_t size;
|
||||
if (png_path_to_bitmap(OPT(background_image), &global_state.bgimage->bitmap, &global_state.bgimage->width, &global_state.bgimage->height, &size)) {
|
||||
send_bgimage_to_gpu(OPT(background_image_layout), global_state.bgimage);
|
||||
@ -961,11 +962,13 @@ static PyObject*
|
||||
pyset_background_image(PyObject *self UNUSED, PyObject *args) {
|
||||
const char *path;
|
||||
PyObject *layout_name = NULL;
|
||||
PyObject *anchor_name = NULL;
|
||||
PyObject *os_window_ids;
|
||||
int configured = 0;
|
||||
PA("zO!|pU", &path, &PyTuple_Type, &os_window_ids, &configured, &layout_name);
|
||||
PA("zO!|pOO", &path, &PyTuple_Type, &os_window_ids, &configured, &layout_name, &anchor_name);
|
||||
size_t size;
|
||||
BackgroundImageLayout layout = layout_name ? bglayout(layout_name) : OPT(background_image_layout);
|
||||
BackgroundImageLayout layout = PyUnicode_Check(layout_name) ? bglayout(layout_name) : OPT(background_image_layout);
|
||||
BackgroundImageAnchor anchor = PyUnicode_Check(anchor_name) ? bganchor(anchor_name) : OPT(background_image_anchor);
|
||||
BackgroundImage *bgimage = NULL;
|
||||
if (path) {
|
||||
bgimage = calloc(1, sizeof(BackgroundImage));
|
||||
@ -983,6 +986,7 @@ pyset_background_image(PyObject *self UNUSED, PyObject *args) {
|
||||
global_state.bgimage = bgimage;
|
||||
if (bgimage) bgimage->refcnt++;
|
||||
OPT(background_image_layout) = layout;
|
||||
OPT(background_image_anchor) = anchor;
|
||||
}
|
||||
for (Py_ssize_t i = 0; i < PyTuple_GET_SIZE(os_window_ids); i++) {
|
||||
id_type os_window_id = PyLong_AsUnsignedLongLong(PyTuple_GET_ITEM(os_window_ids, i));
|
||||
@ -990,6 +994,7 @@ pyset_background_image(PyObject *self UNUSED, PyObject *args) {
|
||||
make_os_window_context_current(os_window);
|
||||
free_bgimage(&os_window->bgimage, true);
|
||||
os_window->bgimage = bgimage;
|
||||
os_window->bgimage->anchor = anchor;
|
||||
os_window->render_calls = 0;
|
||||
if (bgimage) bgimage->refcnt++;
|
||||
END_WITH_OS_WINDOW
|
||||
|
||||
@ -47,6 +47,7 @@ typedef struct {
|
||||
|
||||
char* background_image;
|
||||
BackgroundImageLayout background_image_layout;
|
||||
BackgroundImageAnchor background_image_anchor;
|
||||
bool background_image_linear;
|
||||
float background_tint;
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user