mirror of
https://github.com/kuhyx/utils.git
synced 2026-11-12 16:10:59 +01:00
Some checks are pending
dependency freshness / dependencies on newest stable (push) Waiting to run
file length / file-length (push) Waiting to run
gatelock pre-commit / pre-commit (push) Waiting to run
gatelock tests / test (push) Waiting to run
md-naming / markdown naming convention (push) Waiting to run
palette drift / palette (push) Waiting to run
shared gate tests / gate unit tests (push) Waiting to run
leetcode-guard's study mode has to stop the re-assertion loop and the output-change watcher before it releases the grab, and could only reach them as LockWindow._recovery / _detector -- attributes 0.8.0 folded into the arming bundle, which broke that documented private dependency. They are public read-only properties now, next to `surfaces`. _window no longer re-exports the LockConfig family; it was the one thing keeping it over the 250-line cap, and every importer now takes those names from gatelock._config (or the package) directly. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01HHCbkJWXHjtTUaqvnHRAqA
49 lines
1.9 KiB
Python
49 lines
1.9 KiB
Python
# Copyright (c) 2026 Krzysztof Rudnicki
|
|
"""Colour derivation for the shared widgets: hover blends and variant fills.
|
|
|
|
Split from ``widgets.py`` (250-line cap). The seam is deliberate rather than
|
|
arbitrary: everything here is pure colour arithmetic over ``LockConfig``, with
|
|
no ``tkinter`` import and no widget construction, so it is testable without a
|
|
display. ``widgets.py`` keeps the Tk-facing half and re-exports these names,
|
|
because :mod:`gatelock.widgets` is the public surface the gate apps import.
|
|
"""
|
|
|
|
from __future__ import annotations
|
|
|
|
from typing import TYPE_CHECKING, Literal
|
|
|
|
if TYPE_CHECKING:
|
|
from gatelock._config import LockConfig
|
|
|
|
ButtonVariant = Literal["primary", "secondary", "danger"]
|
|
"""Emphasis role for :func:`gatelock.widgets.make_button`, not a colour."""
|
|
|
|
# Blend fraction toward white for a button's hover/active fill.
|
|
_HOVER_LIGHTEN = 0.12
|
|
_HEX_CHANNEL_OFFSETS = (1, 3, 5)
|
|
_RGB_MAX = 255
|
|
|
|
|
|
def _lighten(hex_color: str, amount: float = _HOVER_LIGHTEN) -> str:
|
|
"""Blend ``hex_color`` toward white by ``amount``, for a hover state."""
|
|
channels = (
|
|
int(hex_color[offset : offset + 2], 16) for offset in _HEX_CHANNEL_OFFSETS
|
|
)
|
|
return "#" + "".join(
|
|
f"{round(channel + (_RGB_MAX - channel) * amount):02x}" for channel in channels
|
|
)
|
|
|
|
|
|
def _button_fills(config: LockConfig) -> dict[ButtonVariant, tuple[str, str]]:
|
|
"""Return the fill/text pair for each variant, read from the palette.
|
|
|
|
All three pairs use ``on_fill`` (never ``fg``) for text drawn on a filled
|
|
surface, per tokens.md -- which is the whole point of keying off a
|
|
variant instead of letting each call site invent its own hex pair.
|
|
"""
|
|
return {
|
|
"primary": (config.palette.accent, config.palette.on_fill),
|
|
"secondary": (config.palette.field_bg, config.palette.fg),
|
|
"danger": (config.palette.danger, config.palette.on_fill),
|
|
}
|