diff --git a/README.md b/README.md index 8063497b..e60e7b48 100644 --- a/README.md +++ b/README.md @@ -163,6 +163,8 @@ systemctl enable leads_vec python -m leads_vec -t path/to/the/theme.json run ``` +To learn about themes, read [Color and Themes](https://customtkinter.tomschimansky.com/documentation/color). + ##### Magnify Font Sizes ```shell @@ -265,6 +267,7 @@ Note that a purely empty file could cause an error. | `height` | `int` | Window height | Main | `480` | | `fullscreen` | `bool` | `True`: auto maximize; `False`: window mode | Main | `False` | | `no_title_bar` | `bool` | `True`: no title bar; `False`: default title bar | Main | `False` | +| `theme_mode` | `bool` | `"system"`, `"light"`, `"dark`" | Main | `False` | | `manual_mode` | `bool` | `True`: hide control system; `False`: show control system | Main | `False` | | `refresh_rate` | `int` | GUI frame per second | Main | `30` | | `m_ratio` | `float` | Meter widget size ratio | Main | `0.7` | diff --git a/leads/config/template.py b/leads/config/template.py index 039dd8f9..3cb68ff6 100644 --- a/leads/config/template.py +++ b/leads/config/template.py @@ -1,5 +1,5 @@ from json import dumps as _dumps -from typing import Any as _Any, override as _override +from typing import Any as _Any, override as _override, Literal as _Literal from leads.data import Serializable @@ -9,11 +9,11 @@ def __init__(self, base: dict[str, _Any]) -> None: """ All custom attributes should be public (not named after "_"). Writable attributes should start with "w_" such as "w_debug_level". - :param base: base dictionary + :param base: the base dictionary """ self._d: dict[str, _Any] = base self._frozen: bool = False - self.w_debug_level: str = "DEBUG" + self.w_debug_level: _Literal["DEBUG", "INFO", "WARN", "ERROR"] = "DEBUG" self.data_seq_size: int = 100 self.num_laps_timed: int = 3 self.data_dir: str = "data" @@ -60,8 +60,8 @@ def _writable(self, name: str) -> bool: def set(self, name: str, value: _Any) -> None: """ Set the value with a given name in the dictionary. - :param name: dictionary key - :param value: value to set + :param name: the dictionary key + :param value: the value to set """ if self._writable(name): self._d[name] = value @@ -70,8 +70,8 @@ def set(self, name: str, value: _Any) -> None: def get(self, name: str, default: _Any | None = None) -> _Any | None: """ Get the value of a given name from the dictionary. - :param name: dictionary key - :param default: default value if the value does not exist + :param name: the dictionary key + :param default: the default value if the value does not exist :return: the value if it exists or else the default value """ return self._d.get(name, default) diff --git a/leads_gui/config.py b/leads_gui/config.py index 99dafbc5..683a675e 100644 --- a/leads_gui/config.py +++ b/leads_gui/config.py @@ -1,4 +1,4 @@ -from typing import Any as _Any +from typing import Any as _Any, Literal as _Literal from leads import ConfigTemplate as _ConfigTemplate @@ -9,6 +9,7 @@ def __init__(self, base: dict[str, _Any]) -> None: self.height: int = 480 self.fullscreen: bool = False self.no_title_bar: bool = False + self.theme_mode: _Literal["system", "light", "dark"] = "system" self.manual_mode: bool = False self.refresh_rate: int = 30 self.m_ratio: float = .7 diff --git a/leads_gui/prototype.py b/leads_gui/prototype.py index cc875703..437c067a 100644 --- a/leads_gui/prototype.py +++ b/leads_gui/prototype.py @@ -1,9 +1,11 @@ from tkinter import Misc as _Misc, Event as _Event -from typing import Callable as _Callable, Self as _Self, TypeVar as _TypeVar, Generic as _Generic, Any as _Any +from typing import Callable as _Callable, Self as _Self, TypeVar as _TypeVar, Generic as _Generic, Any as _Any, \ + Literal as _Literal from PIL import ImageTk as _ImageTk from customtkinter import CTk as _CTk, CTkCanvas as _CTkCanvas, get_appearance_mode as _get_appearance_mode, \ - ThemeManager as _ThemeManager, Variable as _Variable, ScalingTracker as _ScalingTracker + ThemeManager as _ThemeManager, Variable as _Variable, ScalingTracker as _ScalingTracker, \ + set_appearance_mode as _set_appearance_mode from numpy import lcm as _lcm from leads import require_config as _require_config @@ -190,12 +192,14 @@ def __init__(self, on_refresh: _Callable[[_Self], None] = lambda _: None, title: str = "LEADS", fullscreen: bool = True, - no_title_bar: bool = True) -> None: + no_title_bar: bool = True, + theme_mode: _Literal["system", "light", "dark"] = "system") -> None: self._root: _CTk = _CTk() self._root.title(title) self._root.wm_iconbitmap() self._root.iconphoto(True, _ImageTk.PhotoImage(file=f"{_ASSETS_PATH}/logo.png")) self._root.overrideredirect(no_title_bar) + _set_appearance_mode(theme_mode) sw, sh = self._root.winfo_screenwidth(), self._root.winfo_screenheight() self._width: int = sw if fullscreen else width self._height: int = sh if fullscreen else height