Update Screen: Cong cu, settings, them/Chinh sua task

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
2026-08-19 16:58:23 +09:00
co-authored by Claude Sonnet 5
parent e6adfd9350
commit e2d020ef7b
7 changed files with 509 additions and 239 deletions
+64 -1
View File
@@ -38,6 +38,42 @@ from dataclasses import dataclass, asdict
from string import Template
def _chevron_asset(direction: str, color: str) -> str:
"""Render (and cache on disk) a small chevron PNG for QComboBox/QSpinBox
arrow subcontrols. QSS's ``image:`` property only accepts a resource or
file path, never a live QPixmap — and once ``::drop-down``/``::up-button``/
``::down-button`` are styled at all, Qt stops drawing its own built-in
arrow, so without this the controls show no affordance whatsoever."""
import hashlib
import tempfile
from pathlib import Path
key = hashlib.md5(f"{direction}-{color}".encode()).hexdigest()[:10]
path = Path(tempfile.gettempdir()) / "cowork_local_theme" / f"chevron_{key}.png"
if not path.exists():
path.parent.mkdir(parents=True, exist_ok=True)
from PySide6.QtCore import QPointF, Qt
from PySide6.QtGui import QColor, QPainter, QPixmap
size = 12
pm = QPixmap(size, size)
pm.fill(Qt.transparent)
p = QPainter(pm)
p.setRenderHint(QPainter.Antialiasing)
pen = p.pen()
pen.setColor(QColor(color))
pen.setWidthF(1.6)
pen.setCapStyle(Qt.RoundCap)
pen.setJoinStyle(Qt.RoundJoin)
p.setPen(pen)
pts = ([QPointF(2.5, 4.5), QPointF(6, 8), QPointF(9.5, 4.5)] if direction == "down"
else [QPointF(2.5, 7.5), QPointF(6, 4), QPointF(9.5, 7.5)])
p.drawPolyline(pts)
p.end()
pm.save(str(path))
return path.as_posix()
@dataclass(frozen=True)
class Palette:
"""Every colour and shape value the interface is allowed to use."""
@@ -574,6 +610,27 @@ QSpinBox:focus, QDoubleSpinBox:focus { border: 1px solid $focus_ring; }
QLineEdit:disabled, QPlainTextEdit:disabled, QTextEdit:disabled {
background: $surface; color: $text_disabled;
}
/* Explicit up/down button geometry: once ANY spin-box subcontrol is styled,
Qt uses exactly this rect for both painting AND hit-testing, so the
clickable area can no longer drift from what's drawn (the previous
unstyled default arrows misaligned their own click region at 125%/150%
Windows display scaling — this pins both to the same rect instead). */
QSpinBox::up-button, QDoubleSpinBox::up-button {
subcontrol-origin: border; subcontrol-position: top right;
width: 18px; height: 15px; border: none; background: transparent;
}
QSpinBox::down-button, QDoubleSpinBox::down-button {
subcontrol-origin: border; subcontrol-position: bottom right;
width: 18px; height: 15px; border: none; background: transparent;
}
QSpinBox::up-button:hover, QDoubleSpinBox::up-button:hover,
QSpinBox::down-button:hover, QDoubleSpinBox::down-button:hover { background: $hover; }
QSpinBox::up-button:pressed, QDoubleSpinBox::up-button:pressed,
QSpinBox::down-button:pressed, QDoubleSpinBox::down-button:pressed { background: $active; }
QSpinBox::up-arrow, QDoubleSpinBox::up-arrow { image: url($chevron_up); width: 9px; height: 9px; }
QSpinBox::down-arrow, QDoubleSpinBox::down-arrow { image: url($chevron_down); width: 9px; height: 9px; }
QSpinBox::up-arrow:disabled, QSpinBox::down-arrow:disabled,
QDoubleSpinBox::up-arrow:disabled, QDoubleSpinBox::down-arrow:disabled { image: none; }
QTreeView::item, QListView::item, QTableView::item { padding: 4px 3px; border-radius: ${radius_sm}px; }
QTreeView::item:hover, QListView::item:hover { background: $hover; }
@@ -639,6 +696,8 @@ QComboBox:hover { background: $hover; }
QComboBox:focus { border-color: $focus_ring; }
QComboBox:disabled { color: $text_disabled; background: $surface; border-color: $border; }
QComboBox::drop-down { border: none; width: 20px; }
QComboBox::down-arrow { image: url($chevron_down); width: 10px; height: 10px; }
QComboBox::down-arrow:disabled { image: none; }
QComboBox QAbstractItemView {
background: $overlay; color: $text; border: 1px solid $border_strong;
border-radius: ${radius}px; padding: 4px; outline: none;
@@ -825,7 +884,11 @@ def current_palette() -> Palette:
def stylesheet(theme: str) -> str:
"""The application-wide Qt style sheet for ``theme``."""
return _TEMPLATE.substitute(asdict(palette(theme)))
p = palette(theme)
values = asdict(p)
values["chevron_down"] = _chevron_asset("down", p.text_muted)
values["chevron_up"] = _chevron_asset("up", p.text_muted)
return _TEMPLATE.substitute(values)
def role_colors(theme: str) -> dict[str, str]: