diff --git a/kitty/data-types.c b/kitty/data-types.c index 687dccd87..ac88f2fe3 100644 --- a/kitty/data-types.c +++ b/kitty/data-types.c @@ -864,6 +864,11 @@ PyInit_fast_data_types(void) { PyModule_AddIntMacro(m, COLOR_IS_SPECIAL); PyModule_AddIntMacro(m, COLOR_IS_INDEX); PyModule_AddIntMacro(m, COLOR_IS_RGB); + PyModule_AddIntMacro(m, SCROLLBAR_ALWAYS); + PyModule_AddIntMacro(m, SCROLLBAR_NEVER); + PyModule_AddIntMacro(m, SCROLLBAR_ON_HOVERED); + PyModule_AddIntMacro(m, SCROLLBAR_ON_SCROLLED); + PyModule_AddIntMacro(m, SCROLLBAR_ON_SCROLL_AND_HOVER); #ifdef __APPLE__ // Apple says its SHM_NAME_MAX but SHM_NAME_MAX is not actually declared in typical CrApple style. // This value is based on experimentation and from qsharedmemory.cpp in Qt diff --git a/kitty/data-types.h b/kitty/data-types.h index 274a96d80..3f242ac14 100644 --- a/kitty/data-types.h +++ b/kitty/data-types.h @@ -113,7 +113,8 @@ typedef enum MouseShapes { /* end mouse shapes */ } MouseShape; typedef enum { NONE, MENUBAR, WINDOW, ALL } WindowTitleIn; -typedef enum { SCROLLBAR_TRACK_JUMP=1, SCROLLBAR_TRACK_PAGE=2 } ScrollbarTrackBehavior; +typedef enum { SCROLLBAR_TRACK_JUMP, SCROLLBAR_TRACK_PAGE } ScrollbarTrackBehavior; +typedef enum { SCROLLBAR_NEVER, SCROLLBAR_ON_SCROLLED, SCROLLBAR_ON_HOVERED, SCROLLBAR_ON_SCROLL_AND_HOVER, SCROLLBAR_ALWAYS } ScrollbarVisibilityPolicy; typedef enum { TILING, SCALED, MIRRORED, CLAMPED, CENTER_CLAMPED, CENTER_SCALED } BackgroundImageLayout; typedef struct ImageAnchorPosition { float canvas_x, canvas_y, image_x, image_y; diff --git a/kitty/fast_data_types.pyi b/kitty/fast_data_types.pyi index d0d65bada..1e509d2d6 100644 --- a/kitty/fast_data_types.pyi +++ b/kitty/fast_data_types.pyi @@ -20,6 +20,11 @@ COLOR_IS_SPECIAL: int COLOR_NOT_SET: int COLOR_IS_RGB: int COLOR_IS_INDEX: int +SCROLLBAR_ALWAYS: int +SCROLLBAR_NEVER: int +SCROLLBAR_ON_HOVERED: int +SCROLLBAR_ON_SCROLLED: int +SCROLLBAR_ON_SCROLL_AND_HOVER: int GLFW_LAYER_SHELL_NONE: int GLFW_LAYER_SHELL_PANEL: int GLFW_LAYER_SHELL_TOP: int diff --git a/kitty/options/definition.py b/kitty/options/definition.py index 5f8a37e8b..e172fe6c7 100644 --- a/kitty/options/definition.py +++ b/kitty/options/definition.py @@ -442,71 +442,11 @@ ''' ) -opt('scrollbar_opacity', '0.5', - option_type='unit_float', ctype='float', long_text=''' -The opacity of the scrollbar handle. The default is 0.5 which means 50% opaque. -Set to a value between zero and one.''') - -opt('scrollbar_track_opacity', '0', - option_type='unit_float', ctype='float', long_text=''' -The opacity of the scrollbar track (the background behind the scrollbar handle). -The default is 0 which means completely transparent. Set to a value between zero and one.''') - -opt('scrollbar_color', 'foreground', - option_type='scrollbar_color', long_text=''' -The color of the scrollbar. The default value :code:`foreground` uses the -current text color. You can specify any color as a hexadecimal RGB triplet (e.g. -:code:`#ff0000` for red), or use one of the standard color names (e.g. :code:`red`), -or use a color from the 256 color table (e.g. :code:`color120`). -Additionally, special values like :code:`background`, :code:`foreground`, or any other -configured color variable are supported. The scrollbar appearance is also affected by -:opt:`scrollbar_opacity` and :opt:`scrollbar_track_opacity` which control transparency.''') - -opt('scrollbar_interactive', 'yes', - option_type='to_bool', ctype='bool', long_text=''' -Enable or disable interactive scrollbar functionality. When enabled, you can click -and drag the scrollbar to scroll. When disabled, the scrollbar is only a visual -indicator of the scroll position. Set to :code:`yes` to enable or :code:`no` to disable.''') - -opt('scrollbar_width', '10', - option_type='positive_int', ctype='uint', long_text=''' -The width of the scrollbar in pixels. The default is 10 pixels.''') - -opt('scrollbar_gap', '5', - option_type='positive_int', ctype='uint', long_text=''' -The gap between the scrollbar and the window edge in pixels. The default is 5 pixels.''') -opt('scrollbar_min_thumb_height', '50', - option_type='positive_int', ctype='uint', long_text=''' -The minimum height of the scrollbar thumb in pixels. This prevents the thumb from -becoming too small when there is a lot of content to scroll. The default is 50 pixels.''') -opt('scrollbar_hitbox_expansion', '5', - option_type='positive_int', ctype='uint', long_text=''' -Extra pixels added to the scrollbar thumb hitbox for easier interaction. -This makes it easier to grab the scrollbar even if the visual representation -is thin. The default is 5 pixels on each side.''') - -opt('scrollbar_radius', '5', - option_type='positive_int', ctype='uint', long_text=''' -The radius of the scrollbar thumb corners in pixels. This controls how rounded -the scrollbar thumb appears. Set to 0 for square corners, or a positive value -for rounded corners. The default is 5 pixels.''') - -opt('scrollbar_autohide', 'yes', - option_type='to_bool', ctype='bool', long_text=''' -Hide the scrollbar by default and only show it when scrolling or hovering. -When enabled, the scrollbar will only be visible when you are scrolling -(not at the bottom) or when the mouse is hovering over the scrollbar area. -Set to :code:`yes` to enable or :code:`no` to disable.''') - -opt('scrollbar_track_behavior', 'jump', - option_type='choices', ctype='scrollbar_track_behavior', - choices=('jump', 'page'), +opt( + 'scrollbar', '', + option_type='scrollbar', ctype='!scrollbar', long_text=''' -Control the behavior when clicking on the scrollbar track (the area outside -the thumb). With :code:`jump`, clicking on the track will jump directly to -that position. With :code:`page`, clicking on the track will scroll up or -down by one page, similar to traditional scrollbar behavior.''') - +''') opt('scrollback_pager', 'less --chop-long-lines --RAW-CONTROL-CHARS +INPUT_LINE_NUMBER', option_type='to_cmdline', diff --git a/kitty/options/parse.py b/kitty/options/parse.py index f0ef9ccb1..7d7c5ab40 100644 --- a/kitty/options/parse.py +++ b/kitty/options/parse.py @@ -17,13 +17,13 @@ hide_window_decorations, macos_option_as_alt, macos_titlebar_color, menu_map, modify_font, mouse_hide_wait, narrow_symbols, notify_on_cmd_finish, optional_edge_width, parse_font_spec, parse_map, parse_mouse_map, paste_actions, pointer_shape_when_dragging, remote_control_password, - resize_debounce_time, scrollback_lines, scrollback_pager_history_size, scrollbar_color, - shell_integration, store_multiple, symbol_map, tab_activity_symbol, tab_bar_edge, - tab_bar_margin_height, tab_bar_min_tabs, tab_fade, tab_font_style, tab_separator, - tab_title_template, text_fg_override_threshold, titlebar_color, to_cursor_shape, - to_cursor_unfocused_shape, to_font_size, to_layout_names, to_modifiers, - transparent_background_colors, underline_exclusion, url_prefixes, url_style, visual_bell_duration, - visual_window_select_characters, window_border_width, window_logo_scale, window_size + resize_debounce_time, scrollback_lines, scrollback_pager_history_size, scrollbar, shell_integration, + store_multiple, symbol_map, tab_activity_symbol, tab_bar_edge, tab_bar_margin_height, + tab_bar_min_tabs, tab_fade, tab_font_style, tab_separator, tab_title_template, + text_fg_override_threshold, titlebar_color, to_cursor_shape, to_cursor_unfocused_shape, + to_font_size, to_layout_names, to_modifiers, transparent_background_colors, underline_exclusion, + url_prefixes, url_style, visual_bell_duration, visual_window_select_characters, window_border_width, + window_logo_scale, window_size ) @@ -1206,43 +1206,8 @@ def scrollback_pager(self, val: str, ans: dict[str, typing.Any]) -> None: def scrollback_pager_history_size(self, val: str, ans: dict[str, typing.Any]) -> None: ans['scrollback_pager_history_size'] = scrollback_pager_history_size(val) - def scrollbar_autohide(self, val: str, ans: dict[str, typing.Any]) -> None: - ans['scrollbar_autohide'] = to_bool(val) - - def scrollbar_color(self, val: str, ans: dict[str, typing.Any]) -> None: - ans['scrollbar_color'] = scrollbar_color(val) - - def scrollbar_gap(self, val: str, ans: dict[str, typing.Any]) -> None: - ans['scrollbar_gap'] = positive_int(val) - - def scrollbar_hitbox_expansion(self, val: str, ans: dict[str, typing.Any]) -> None: - ans['scrollbar_hitbox_expansion'] = positive_int(val) - - def scrollbar_interactive(self, val: str, ans: dict[str, typing.Any]) -> None: - ans['scrollbar_interactive'] = to_bool(val) - - def scrollbar_min_thumb_height(self, val: str, ans: dict[str, typing.Any]) -> None: - ans['scrollbar_min_thumb_height'] = positive_int(val) - - def scrollbar_opacity(self, val: str, ans: dict[str, typing.Any]) -> None: - ans['scrollbar_opacity'] = unit_float(val) - - def scrollbar_radius(self, val: str, ans: dict[str, typing.Any]) -> None: - ans['scrollbar_radius'] = positive_int(val) - - def scrollbar_track_behavior(self, val: str, ans: dict[str, typing.Any]) -> None: - val = val.lower() - if val not in self.choices_for_scrollbar_track_behavior: - raise ValueError(f"The value {val} is not a valid choice for scrollbar_track_behavior") - ans["scrollbar_track_behavior"] = val - - choices_for_scrollbar_track_behavior = frozenset(('jump', 'page')) - - def scrollbar_track_opacity(self, val: str, ans: dict[str, typing.Any]) -> None: - ans['scrollbar_track_opacity'] = unit_float(val) - - def scrollbar_width(self, val: str, ans: dict[str, typing.Any]) -> None: - ans['scrollbar_width'] = positive_int(val) + def scrollbar(self, val: str, ans: dict[str, typing.Any]) -> None: + ans['scrollbar'] = scrollbar(val) def select_by_word_characters(self, val: str, ans: dict[str, typing.Any]) -> None: ans['select_by_word_characters'] = str(val) diff --git a/kitty/options/to-c-generated.h b/kitty/options/to-c-generated.h index 52d5d3cc8..3ba61186a 100644 --- a/kitty/options/to-c-generated.h +++ b/kitty/options/to-c-generated.h @@ -253,132 +253,15 @@ convert_from_opts_cursor_trail_color(PyObject *py_opts, Options *opts) { } static void -convert_from_python_scrollbar_opacity(PyObject *val, Options *opts) { - opts->scrollbar_opacity = PyFloat_AsFloat(val); +convert_from_python_scrollbar(PyObject *val, Options *opts) { + scrollbar(val, opts); } static void -convert_from_opts_scrollbar_opacity(PyObject *py_opts, Options *opts) { - PyObject *ret = PyObject_GetAttrString(py_opts, "scrollbar_opacity"); +convert_from_opts_scrollbar(PyObject *py_opts, Options *opts) { + PyObject *ret = PyObject_GetAttrString(py_opts, "scrollbar"); if (ret == NULL) return; - convert_from_python_scrollbar_opacity(ret, opts); - Py_DECREF(ret); -} - -static void -convert_from_python_scrollbar_track_opacity(PyObject *val, Options *opts) { - opts->scrollbar_track_opacity = PyFloat_AsFloat(val); -} - -static void -convert_from_opts_scrollbar_track_opacity(PyObject *py_opts, Options *opts) { - PyObject *ret = PyObject_GetAttrString(py_opts, "scrollbar_track_opacity"); - if (ret == NULL) return; - convert_from_python_scrollbar_track_opacity(ret, opts); - Py_DECREF(ret); -} - -static void -convert_from_python_scrollbar_interactive(PyObject *val, Options *opts) { - opts->scrollbar_interactive = PyObject_IsTrue(val); -} - -static void -convert_from_opts_scrollbar_interactive(PyObject *py_opts, Options *opts) { - PyObject *ret = PyObject_GetAttrString(py_opts, "scrollbar_interactive"); - if (ret == NULL) return; - convert_from_python_scrollbar_interactive(ret, opts); - Py_DECREF(ret); -} - -static void -convert_from_python_scrollbar_width(PyObject *val, Options *opts) { - opts->scrollbar_width = PyLong_AsUnsignedLong(val); -} - -static void -convert_from_opts_scrollbar_width(PyObject *py_opts, Options *opts) { - PyObject *ret = PyObject_GetAttrString(py_opts, "scrollbar_width"); - if (ret == NULL) return; - convert_from_python_scrollbar_width(ret, opts); - Py_DECREF(ret); -} - -static void -convert_from_python_scrollbar_gap(PyObject *val, Options *opts) { - opts->scrollbar_gap = PyLong_AsUnsignedLong(val); -} - -static void -convert_from_opts_scrollbar_gap(PyObject *py_opts, Options *opts) { - PyObject *ret = PyObject_GetAttrString(py_opts, "scrollbar_gap"); - if (ret == NULL) return; - convert_from_python_scrollbar_gap(ret, opts); - Py_DECREF(ret); -} - -static void -convert_from_python_scrollbar_min_thumb_height(PyObject *val, Options *opts) { - opts->scrollbar_min_thumb_height = PyLong_AsUnsignedLong(val); -} - -static void -convert_from_opts_scrollbar_min_thumb_height(PyObject *py_opts, Options *opts) { - PyObject *ret = PyObject_GetAttrString(py_opts, "scrollbar_min_thumb_height"); - if (ret == NULL) return; - convert_from_python_scrollbar_min_thumb_height(ret, opts); - Py_DECREF(ret); -} - -static void -convert_from_python_scrollbar_hitbox_expansion(PyObject *val, Options *opts) { - opts->scrollbar_hitbox_expansion = PyLong_AsUnsignedLong(val); -} - -static void -convert_from_opts_scrollbar_hitbox_expansion(PyObject *py_opts, Options *opts) { - PyObject *ret = PyObject_GetAttrString(py_opts, "scrollbar_hitbox_expansion"); - if (ret == NULL) return; - convert_from_python_scrollbar_hitbox_expansion(ret, opts); - Py_DECREF(ret); -} - -static void -convert_from_python_scrollbar_radius(PyObject *val, Options *opts) { - opts->scrollbar_radius = PyLong_AsUnsignedLong(val); -} - -static void -convert_from_opts_scrollbar_radius(PyObject *py_opts, Options *opts) { - PyObject *ret = PyObject_GetAttrString(py_opts, "scrollbar_radius"); - if (ret == NULL) return; - convert_from_python_scrollbar_radius(ret, opts); - Py_DECREF(ret); -} - -static void -convert_from_python_scrollbar_autohide(PyObject *val, Options *opts) { - opts->scrollbar_autohide = PyObject_IsTrue(val); -} - -static void -convert_from_opts_scrollbar_autohide(PyObject *py_opts, Options *opts) { - PyObject *ret = PyObject_GetAttrString(py_opts, "scrollbar_autohide"); - if (ret == NULL) return; - convert_from_python_scrollbar_autohide(ret, opts); - Py_DECREF(ret); -} - -static void -convert_from_python_scrollbar_track_behavior(PyObject *val, Options *opts) { - opts->scrollbar_track_behavior = scrollbar_track_behavior(val); -} - -static void -convert_from_opts_scrollbar_track_behavior(PyObject *py_opts, Options *opts) { - PyObject *ret = PyObject_GetAttrString(py_opts, "scrollbar_track_behavior"); - if (ret == NULL) return; - convert_from_python_scrollbar_track_behavior(ret, opts); + convert_from_python_scrollbar(ret, opts); Py_DECREF(ret); } @@ -1345,25 +1228,7 @@ convert_opts_from_python_opts(PyObject *py_opts, Options *opts) { if (PyErr_Occurred()) return false; convert_from_opts_cursor_trail_color(py_opts, opts); if (PyErr_Occurred()) return false; - convert_from_opts_scrollbar_opacity(py_opts, opts); - if (PyErr_Occurred()) return false; - convert_from_opts_scrollbar_track_opacity(py_opts, opts); - if (PyErr_Occurred()) return false; - convert_from_opts_scrollbar_interactive(py_opts, opts); - if (PyErr_Occurred()) return false; - convert_from_opts_scrollbar_width(py_opts, opts); - if (PyErr_Occurred()) return false; - convert_from_opts_scrollbar_gap(py_opts, opts); - if (PyErr_Occurred()) return false; - convert_from_opts_scrollbar_min_thumb_height(py_opts, opts); - if (PyErr_Occurred()) return false; - convert_from_opts_scrollbar_hitbox_expansion(py_opts, opts); - if (PyErr_Occurred()) return false; - convert_from_opts_scrollbar_radius(py_opts, opts); - if (PyErr_Occurred()) return false; - convert_from_opts_scrollbar_autohide(py_opts, opts); - if (PyErr_Occurred()) return false; - convert_from_opts_scrollbar_track_behavior(py_opts, opts); + convert_from_opts_scrollbar(py_opts, opts); if (PyErr_Occurred()) return false; convert_from_opts_scrollback_pager_history_size(py_opts, opts); if (PyErr_Occurred()) return false; diff --git a/kitty/options/to-c.h b/kitty/options/to-c.h index 5924c183d..d78d2a8e9 100644 --- a/kitty/options/to-c.h +++ b/kitty/options/to-c.h @@ -58,6 +58,26 @@ window_title_in(PyObject *title_in) { return ALL; } +static inline void +scrollbar(PyObject *src, Options *opts) { +#define G(conv, attr) { RAII_PyObject(x, PyObject_GetAttrString(src, #attr)); if (x) opts->scrollbar.attr = conv(x); } + G(PyFloat_AsFloat, opacity); + G(PyFloat_AsFloat, track_opacity); + G(PyFloat_AsFloat, track_hover_opacity); + G(PyFloat_AsFloat, width); + G(PyFloat_AsFloat, radius); + G(PyFloat_AsFloat, gap); + G(PyFloat_AsFloat, min_handle_height); + G(PyFloat_AsFloat, hitbox_expansion); + G(PyLong_AsUnsignedLong, color); + G(PyLong_AsUnsignedLong, track_color); + G(PyLong_AsLong, visible_when); + G(PyObject_IsTrue, interactive); +#undef G + RAII_PyObject(x, PyObject_GetAttrString(src, "jump_on_track_click")); + opts->scrollbar.track_behavior = (x && PyObject_IsTrue(x)) ? SCROLLBAR_TRACK_JUMP : SCROLLBAR_TRACK_PAGE; +} + static inline ScrollbarTrackBehavior scrollbar_track_behavior(PyObject *val) { const char *v = PyUnicode_AsUTF8(val); diff --git a/kitty/options/types.py b/kitty/options/types.py index c69737645..d80a6066f 100644 --- a/kitty/options/types.py +++ b/kitty/options/types.py @@ -12,7 +12,7 @@ import kitty.fonts from kitty.options.utils import ( AliasMap, KeyDefinition, KeyboardModeMap, MouseHideWait, MouseMap, MouseMapping, NotifyOnCmdFinish, - TabBarMarginHeight + ScrollbarSettings, TabBarMarginHeight ) import kitty.options.utils from kitty.types import FloatEdges @@ -27,7 +27,6 @@ choices_for_macos_show_window_title_in = typing.Literal['all', 'menubar', 'none', 'window'] choices_for_placement_strategy = typing.Literal['top-left', 'top', 'top-right', 'left', 'center', 'right', 'bottom-left', 'bottom', 'bottom-right'] choices_for_pointer_shape_when_grabbed = choices_for_default_pointer_shape -choices_for_scrollbar_track_behavior = typing.Literal['jump', 'page'] choices_for_strip_trailing_spaces = typing.Literal['always', 'never', 'smart'] choices_for_tab_bar_align = typing.Literal['left', 'center', 'right'] choices_for_tab_bar_style = typing.Literal['fade', 'hidden', 'powerline', 'separator', 'slant', 'custom'] @@ -415,17 +414,7 @@ 'scrollback_lines', 'scrollback_pager', 'scrollback_pager_history_size', - 'scrollbar_autohide', - 'scrollbar_color', - 'scrollbar_gap', - 'scrollbar_hitbox_expansion', - 'scrollbar_interactive', - 'scrollbar_min_thumb_height', - 'scrollbar_opacity', - 'scrollbar_radius', - 'scrollbar_track_behavior', - 'scrollbar_track_opacity', - 'scrollbar_width', + 'scrollbar', 'select_by_word_characters', 'select_by_word_characters_forward', 'selection_background', @@ -599,17 +588,7 @@ class Options: scrollback_lines: int = 2000 scrollback_pager: list[str] = ['less', '--chop-long-lines', '--RAW-CONTROL-CHARS', '+INPUT_LINE_NUMBER'] scrollback_pager_history_size: int = 0 - scrollbar_autohide: bool = True - scrollbar_color: int = 0 - scrollbar_gap: int = 5 - scrollbar_hitbox_expansion: int = 5 - scrollbar_interactive: bool = True - scrollbar_min_thumb_height: int = 50 - scrollbar_opacity: float = 0.5 - scrollbar_radius: int = 5 - scrollbar_track_behavior: choices_for_scrollbar_track_behavior = 'jump' - scrollbar_track_opacity: float = 0 - scrollbar_width: int = 10 + scrollbar: ScrollbarSettings = ScrollbarSettings(opacity=0.5, track_opacity=0, track_hover_opacity=0.1, color=0, track_color=0, interactive=True, width=0.5, radius=0.25, gap=0.25, min_handle_height=1.0, hitbox_expansion=0.25, jump_on_track_click=True, visible_when=1) select_by_word_characters: str = '@-./_~?&=%+#' select_by_word_characters_forward: str = '' selection_background: kitty.fast_data_types.Color | None = Color(255, 250, 205) diff --git a/kitty/options/utils.py b/kitty/options/utils.py index 1849d7418..0622520d0 100644 --- a/kitty/options/utils.py +++ b/kitty/options/utils.py @@ -1704,6 +1704,84 @@ def transparent_background_colors(spec: str) -> tuple[tuple[Color, float], ...]: return tuple(ans[:7]) +class ScrollbarSettings(NamedTuple): + opacity: float = 0.5 + track_opacity: float = 0 + track_hover_opacity: float = 0.1 + color: int = 0 + track_color: int = 0 + interactive: bool = True + width: float = 0.5 + radius: float = 0.25 + gap: float = 0.25 + min_handle_height: float = 1.0 + hitbox_expansion: float = 0.25 + jump_on_track_click: bool = True + visible_when: int = 1 + + +default_scrollbar = ScrollbarSettings() + + +def scrollbar(spec: str) -> ScrollbarSettings: + if not spec: + return default_scrollbar + ans = ScrollbarSettings() + def scrollbar_color(x: str) -> int: + return color_with_special_values( + x, {'foreground': 0, 'selection_background': 1}, 'Ignoring invalid scrollbar color: {x}') + for x in shlex_split(spec): + k, sep, v = x.partition('=') + if sep != '=': + log_error(f'Ignoring invalid scrollbar option: {x}') + continue + match k: + case 'opacity': + ans = ans._replace(opacity=unit_float(v)) + case 'track_opacity': + ans = ans._replace(track_opacity=unit_float(v)) + case 'track_hover_opacity': + ans = ans._replace(track_hover_opacity=unit_float(v)) + case 'color': + ans = ans._replace(color=scrollbar_color(v)) + case 'track_color': + ans = ans._replace(track_color=scrollbar_color(v)) + case 'interactive': + ans = ans._replace(interactive=to_bool(v)) + case 'width': + ans = ans._replace(width=positive_float(v)) + case 'radius': + ans = ans._replace(radius=positive_float(v)) + case 'gap': + ans = ans._replace(gap=positive_float(v)) + case 'min_handle_height': + ans = ans._replace(min_handle_height=positive_float(v)) + case 'hitbox_expansion': + ans = ans._replace(hitbox_expansion=positive_float(v)) + case 'track_click': + ans = ans._replace(jump_on_track_click=v == 'jump') + case 'visible_when': + val = -1 + match v: + case 'never': + val = defines.SCROLLBAR_NEVER + case 'scrolled': + val = defines.SCROLLBAR_ON_SCROLLED + case 'hovered': + val = defines.SCROLLBAR_ON_HOVERED + case 'scrolled-and-hovered': + val = defines.SCROLLBAR_ON_SCROLL_AND_HOVER + case 'always': + val = defines.SCROLLBAR_ALWAYS + case _: + log_error(f'Ignoring unknown scrollbar visibility policy: {v}') + if val > -1: + ans = ans._replace(visible_when=val) + case _: + log_error(f'Ignoring unknown scrollbar option: {k}') + return ans + + def deprecated_hide_window_decorations_aliases(key: str, val: str, ans: dict[str, Any]) -> None: if not hasattr(deprecated_hide_window_decorations_aliases, key): setattr(deprecated_hide_window_decorations_aliases, key, True) @@ -1762,14 +1840,5 @@ def deprecated_adjust_line_height(key: str, x: str, opts_dict: dict[str, Any]) - def deprecated_scrollback_indicator_opacity(key: str, val: str, ans: dict[str, Any]) -> None: if not hasattr(deprecated_scrollback_indicator_opacity, key): setattr(deprecated_scrollback_indicator_opacity, key, True) - log_error(f'The option {key} is deprecated. Use scrollbar_opacity instead.') - from kitty.conf.utils import unit_float - ans['scrollbar_opacity'] = unit_float(val) - - -def scrollbar_color(x: str) -> int: - return color_with_special_values( - x, - {'foreground': 0, 'selection_foreground': 1}, - 'Ignoring invalid scrollbar color: {x}' - ) + log_error(f'The option {key} is deprecated. Use scrollbar instead.') + ans['scrollbar'] = ScrollbarSettings(opacity=unit_float(val)) diff --git a/kitty/state.h b/kitty/state.h index fb5998e6c..7253fcabc 100644 --- a/kitty/state.h +++ b/kitty/state.h @@ -70,7 +70,16 @@ typedef struct Options { float macos_thicken_font; WindowTitleIn macos_show_window_title_in; char *bell_path, *bell_theme; - float background_opacity, dim_opacity, scrollback_indicator_opacity; + float background_opacity, dim_opacity; + struct { + float opacity, track_opacity, track_hover_opacity; + color_type color, track_color; + bool interactive; + float width, radius, gap, min_handle_height, hitbox_expansion; + ScrollbarTrackBehavior track_behavior; + ScrollbarVisibilityPolicy visible_when; + } scrollbar; + bool scrollbar_interactive; float scrollbar_opacity; float scrollbar_track_opacity; @@ -82,6 +91,7 @@ typedef struct Options { unsigned int scrollbar_radius; bool scrollbar_autohide; ScrollbarTrackBehavior scrollbar_track_behavior; + float text_contrast, text_gamma_adjustment; bool text_old_gamma;