- Refactored TimerPage component to improve layout and user experience. - Updated theme configuration to utilize design tokens for better maintainability. - Introduced new tokens for colors and typography to align with design principles. - Simplified state management and improved timer functionality. - Enhanced accessibility and responsiveness of UI elements.
79 lines
2.2 KiB
Python
79 lines
2.2 KiB
Python
"""Where the mini timer appears.
|
|
|
|
Two mechanisms, because one is not enough:
|
|
|
|
* **X11** — the application may place its own window, so the computed point is
|
|
applied directly.
|
|
* **Wayland** — it may not: a client cannot position an xdg-toplevel, and
|
|
setting `x`/`y` is quietly ignored. KWin *can* place it, through the same
|
|
window rule that already forces "keep above", so the point is written there.
|
|
|
|
The geometry maths is a pure function so it can be checked without a screen.
|
|
"""
|
|
|
|
from __future__ import annotations
|
|
|
|
from dataclasses import dataclass
|
|
|
|
CORNERS = (
|
|
"top-left",
|
|
"top-centre",
|
|
"top-right",
|
|
"bottom-left",
|
|
"bottom-centre",
|
|
"bottom-right",
|
|
"centre",
|
|
"remember",
|
|
)
|
|
|
|
# What the settings page shows, in the order it shows them.
|
|
CORNER_LABELS = {
|
|
"top-left": "Top left",
|
|
"top-centre": "Top centre",
|
|
"top-right": "Top right",
|
|
"bottom-left": "Bottom left",
|
|
"bottom-centre": "Bottom centre",
|
|
"bottom-right": "Bottom right",
|
|
"centre": "Centre of the screen",
|
|
"remember": "Where I last dragged it",
|
|
}
|
|
|
|
|
|
@dataclass(frozen=True, slots=True)
|
|
class Rect:
|
|
"""A screen's usable area — panels and docks already taken off."""
|
|
|
|
x: int
|
|
y: int
|
|
width: int
|
|
height: int
|
|
|
|
|
|
def point_for(corner: str, screen: Rect, size: tuple[int, int], margin: int = 24) -> tuple[int, int]:
|
|
"""Top-left point that puts a `size` window in `corner` of `screen`."""
|
|
width, height = size
|
|
margin = max(0, margin)
|
|
|
|
vertical, _, horizontal = corner.partition("-")
|
|
if corner == "centre":
|
|
vertical, horizontal = "centre", "centre"
|
|
|
|
if horizontal == "left":
|
|
x = screen.x + margin
|
|
elif horizontal == "right":
|
|
x = screen.x + screen.width - width - margin
|
|
else: # centre
|
|
x = screen.x + (screen.width - width) // 2
|
|
|
|
if vertical == "top":
|
|
y = screen.y + margin
|
|
elif vertical == "bottom":
|
|
y = screen.y + screen.height - height - margin
|
|
else: # centre
|
|
y = screen.y + (screen.height - height) // 2
|
|
|
|
# Never place it off-screen, however small the screen or large the margin.
|
|
x = max(screen.x, min(x, screen.x + max(screen.width - width, 0)))
|
|
y = max(screen.y, min(y, screen.y + max(screen.height - height, 0)))
|
|
return int(x), int(y)
|