feat: initialize CCMA member administration
@@ -0,0 +1,16 @@
|
|||||||
|
__pycache__/
|
||||||
|
*.py[cod]
|
||||||
|
*.egg-info/
|
||||||
|
.pytest_cache/
|
||||||
|
.ruff_cache/
|
||||||
|
.venv/
|
||||||
|
build/
|
||||||
|
dist/
|
||||||
|
.coverage
|
||||||
|
htmlcov/
|
||||||
|
.idea/
|
||||||
|
.vscode/
|
||||||
|
|
||||||
|
# Local member stores must never be committed.
|
||||||
|
member-store/
|
||||||
|
*.ccma-lock
|
||||||
@@ -0,0 +1,21 @@
|
|||||||
|
MIT License
|
||||||
|
|
||||||
|
Copyright (c) 2026 Chaos Computer Club Mannheim e.V.
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all
|
||||||
|
copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
SOFTWARE.
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
include VERSION
|
||||||
@@ -0,0 +1,47 @@
|
|||||||
|
[build-system]
|
||||||
|
requires = ["setuptools>=69"]
|
||||||
|
build-backend = "setuptools.build_meta"
|
||||||
|
|
||||||
|
[project]
|
||||||
|
name = "ccma"
|
||||||
|
dynamic = ["version"]
|
||||||
|
description = "Chaotic Creature Member Administration for Chaos Computer Club Mannheim e.V."
|
||||||
|
readme = "README.md"
|
||||||
|
requires-python = ">=3.11"
|
||||||
|
license = "MIT"
|
||||||
|
authors = [{name = "Chaos Computer Club Mannheim e.V."}]
|
||||||
|
dependencies = [
|
||||||
|
"screeninfo>=0.8.1,<1",
|
||||||
|
"ttkbootstrap-icons",
|
||||||
|
"ttkbootstrap-icons-mat",
|
||||||
|
]
|
||||||
|
|
||||||
|
[project.optional-dependencies]
|
||||||
|
dev = [
|
||||||
|
"pytest>=8",
|
||||||
|
"ruff>=0.6",
|
||||||
|
]
|
||||||
|
|
||||||
|
[project.scripts]
|
||||||
|
ccma = "ccma.app:main"
|
||||||
|
|
||||||
|
[tool.setuptools]
|
||||||
|
package-dir = {"" = "src"}
|
||||||
|
include-package-data = true
|
||||||
|
|
||||||
|
[tool.setuptools.packages.find]
|
||||||
|
where = ["src"]
|
||||||
|
|
||||||
|
[tool.setuptools.package-data]
|
||||||
|
ccma = ["VERSION", "assets/CHANGELOG.json", "assets/themes/forest/**/*", "assets/themes/forest/*"]
|
||||||
|
|
||||||
|
[tool.pytest.ini_options]
|
||||||
|
testpaths = ["tests"]
|
||||||
|
pythonpath = ["src"]
|
||||||
|
|
||||||
|
[tool.ruff]
|
||||||
|
line-length = 110
|
||||||
|
target-version = "py311"
|
||||||
|
|
||||||
|
[tool.ruff.lint]
|
||||||
|
select = ["E", "F", "I", "UP", "B"]
|
||||||
@@ -0,0 +1,2 @@
|
|||||||
|
# Install CCMA and its runtime dependencies from pyproject.toml.
|
||||||
|
-e .
|
||||||
@@ -0,0 +1,21 @@
|
|||||||
|
from pathlib import Path
|
||||||
|
from shutil import copyfile
|
||||||
|
|
||||||
|
from setuptools import setup
|
||||||
|
from setuptools.command.build_py import build_py
|
||||||
|
|
||||||
|
ROOT = Path(__file__).resolve().parent
|
||||||
|
|
||||||
|
|
||||||
|
class BuildPyWithVersion(build_py):
|
||||||
|
def run(self) -> None:
|
||||||
|
super().run()
|
||||||
|
target = Path(self.build_lib) / "ccma" / "VERSION"
|
||||||
|
target.parent.mkdir(parents=True, exist_ok=True)
|
||||||
|
copyfile(ROOT / "VERSION", target)
|
||||||
|
|
||||||
|
|
||||||
|
setup(
|
||||||
|
version=(ROOT / "VERSION").read_text(encoding="utf-8").strip(),
|
||||||
|
cmdclass={"build_py": BuildPyWithVersion},
|
||||||
|
)
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
from ccma.version import get_version
|
||||||
|
|
||||||
|
__version__ = get_version()
|
||||||
|
|
||||||
|
__all__ = ["__version__"]
|
||||||
@@ -0,0 +1,4 @@
|
|||||||
|
from ccma.app import main
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
||||||
@@ -0,0 +1,134 @@
|
|||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
import tkinter as tk
|
||||||
|
from pathlib import Path
|
||||||
|
from tkinter import filedialog, messagebox
|
||||||
|
|
||||||
|
from ccma import __version__
|
||||||
|
from ccma.config import load_config
|
||||||
|
from ccma.domain.dates import setup_system_locale
|
||||||
|
from ccma.storage.repository import MemberRepository
|
||||||
|
from ccma.ui.main_window import MainWindow
|
||||||
|
from ccma.ui.monitors import (
|
||||||
|
centered_geometry,
|
||||||
|
ensure_visible_geometry,
|
||||||
|
monitor_for_geometry,
|
||||||
|
preferred_monitor,
|
||||||
|
)
|
||||||
|
from ccma.ui.splash import SplashScreen, StartupResult
|
||||||
|
from ccma.ui.theme import load_theme
|
||||||
|
from ccma.ui.window_state import is_maximized, maximize
|
||||||
|
|
||||||
|
|
||||||
|
class CCMAApp(tk.Tk):
|
||||||
|
def __init__(self):
|
||||||
|
super().__init__()
|
||||||
|
setup_system_locale()
|
||||||
|
self.config_obj = load_config()
|
||||||
|
self.title(f"CCMA · v{__version__}")
|
||||||
|
self.minsize(1050, 650)
|
||||||
|
load_theme(self, self.config_obj.theme_mode)
|
||||||
|
self.startup_monitor = preferred_monitor(self, self.config_obj.monitor_bounds)
|
||||||
|
initial_geometry = self.config_obj.window_geometry or centered_geometry(
|
||||||
|
1500, 860, self.startup_monitor
|
||||||
|
)
|
||||||
|
self.geometry(ensure_visible_geometry(initial_geometry, self.startup_monitor))
|
||||||
|
self._last_normal_geometry = self.geometry()
|
||||||
|
self._geometry_capture_job: str | None = None
|
||||||
|
self.bind("<Configure>", self._remember_window_geometry)
|
||||||
|
self.protocol("WM_DELETE_WINDOW", self.close)
|
||||||
|
self.withdraw()
|
||||||
|
self.after_idle(self._start)
|
||||||
|
|
||||||
|
def _start(self) -> None:
|
||||||
|
store_path = self._resolve_store()
|
||||||
|
if not store_path:
|
||||||
|
self.destroy()
|
||||||
|
return
|
||||||
|
repository = MemberRepository(store_path)
|
||||||
|
try:
|
||||||
|
SplashScreen(
|
||||||
|
self,
|
||||||
|
repository,
|
||||||
|
self._startup_complete,
|
||||||
|
self._startup_failed,
|
||||||
|
run_housekeeper=self.config_obj.run_housekeeper_on_startup,
|
||||||
|
monitor=self.startup_monitor,
|
||||||
|
housekeeper_settings=self.config_obj.housekeeper_settings(),
|
||||||
|
)
|
||||||
|
except Exception as exc:
|
||||||
|
self._startup_failed(exc)
|
||||||
|
|
||||||
|
def _resolve_store(self) -> Path | None:
|
||||||
|
configured = self.config_obj.store_path.strip()
|
||||||
|
if configured:
|
||||||
|
return Path(configured).expanduser()
|
||||||
|
selected = filedialog.askdirectory(
|
||||||
|
parent=self,
|
||||||
|
title="Zentrales CCMA-Mitgliederverzeichnis auswählen oder anlegen",
|
||||||
|
initialdir=str(Path.home()),
|
||||||
|
mustexist=False,
|
||||||
|
)
|
||||||
|
if not selected:
|
||||||
|
return None
|
||||||
|
self.config_obj.store_path = selected
|
||||||
|
self.config_obj.save()
|
||||||
|
return Path(selected)
|
||||||
|
|
||||||
|
def _startup_complete(self, result: StartupResult) -> None:
|
||||||
|
self.deiconify()
|
||||||
|
main = MainWindow(
|
||||||
|
self,
|
||||||
|
result.repository,
|
||||||
|
self.config_obj,
|
||||||
|
result.findings,
|
||||||
|
result.validation_errors,
|
||||||
|
)
|
||||||
|
main.pack(fill="both", expand=True)
|
||||||
|
if self.config_obj.window_state in {"maximized", "zoomed"}:
|
||||||
|
self.after_idle(lambda: maximize(self))
|
||||||
|
|
||||||
|
def _startup_failed(self, error: Exception) -> None:
|
||||||
|
self.deiconify()
|
||||||
|
messagebox.showerror("CCMA konnte nicht gestartet werden", str(error), parent=self)
|
||||||
|
self.destroy()
|
||||||
|
|
||||||
|
def _remember_window_geometry(self, _event: tk.Event | None = None) -> None:
|
||||||
|
if self._geometry_capture_job:
|
||||||
|
try:
|
||||||
|
self.after_cancel(self._geometry_capture_job)
|
||||||
|
except tk.TclError:
|
||||||
|
pass
|
||||||
|
self._geometry_capture_job = self.after(150, self._capture_normal_geometry)
|
||||||
|
|
||||||
|
def _capture_normal_geometry(self) -> None:
|
||||||
|
self._geometry_capture_job = None
|
||||||
|
try:
|
||||||
|
if self.state() == "normal" and not is_maximized(self) and self.winfo_viewable():
|
||||||
|
self._last_normal_geometry = self.winfo_geometry()
|
||||||
|
except tk.TclError:
|
||||||
|
return
|
||||||
|
|
||||||
|
def close(self) -> None:
|
||||||
|
try:
|
||||||
|
maximized = is_maximized(self)
|
||||||
|
current_geometry = self.winfo_geometry()
|
||||||
|
if not maximized:
|
||||||
|
self._last_normal_geometry = current_geometry
|
||||||
|
self.config_obj.window_geometry = self._last_normal_geometry
|
||||||
|
self.config_obj.window_state = "maximized" if maximized else "normal"
|
||||||
|
monitor = monitor_for_geometry(self, current_geometry)
|
||||||
|
self.config_obj.monitor_bounds = monitor.as_tuple()
|
||||||
|
self.config_obj.save()
|
||||||
|
except (OSError, tk.TclError):
|
||||||
|
pass
|
||||||
|
self.destroy()
|
||||||
|
|
||||||
|
|
||||||
|
def main() -> None:
|
||||||
|
app = CCMAApp()
|
||||||
|
app.mainloop()
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
||||||
@@ -0,0 +1,25 @@
|
|||||||
|
[
|
||||||
|
{
|
||||||
|
"version": "0.0.1-dev0",
|
||||||
|
"date": "2026-06-21",
|
||||||
|
"changes": [
|
||||||
|
"Projektgrundlage für CCMA – Chaotic Creature Member Administration geschaffen.",
|
||||||
|
"Dateibasierten Mitglieder-Store mit transparenten JSON-Dateien, atomarem Speichern und separaten Dokumentordnern eingeführt.",
|
||||||
|
"Append-only Eventlog pro Mitglied für Systemereignisse, Zahlungen, Mahnungen und Vorstandskommentare ergänzt.",
|
||||||
|
"Universelle Mitgliedersuche, parallele Mitglied-Tabs, Dashboard und ersten prüfenden Hausmeisterlauf umgesetzt.",
|
||||||
|
"Forest Light/Dark, Material-Design-Icons und einen eigenen Splash-Screen integriert.",
|
||||||
|
"Optionen für Mitglieder-Store, zukünftige GnuCash-Datei, Darstellung und Startautomatisierung ergänzt.",
|
||||||
|
"Integrierten Changelog im Optionen-Dialog mit scrollbaren Release-Karten ergänzt.",
|
||||||
|
"Ribbon-Suche und Aktionsbuttons für ein klar getrenntes, responsives Layout überarbeitet.",
|
||||||
|
"Konfigurierbare automatische oder manuelle Mitgliedsnummern mit Pattern, Vorschau und Kollisionsschutz eingeführt.",
|
||||||
|
"Strikte Datumsvalidierung und Live-Altersanzeige für Mitgliedsdaten ergänzt.",
|
||||||
|
"Datumseingabe und -anzeige an das Systemformat angepasst; gespeichert wird weiterhin portabel im ISO-Format.",
|
||||||
|
"Eine ribbonweite Mitgliederliste mit direktem Zugriff auf alle Akten ergänzt.",
|
||||||
|
"Texthintergründe der Dashboard-Karten an die Kartenflächen angeglichen.",
|
||||||
|
"Hausmeister um konfigurierbare Geburtstags- und Mitgliedsjubiläumsmeldungen erweitert.",
|
||||||
|
"Statusänderungen werden mit altem und neuem Klartextwert in der Mitgliederchronik protokolliert.",
|
||||||
|
"Fensterposition, normaler Fensterzustand und Maximierung werden gespeichert; der Splash startet auf dem zuletzt verwendeten Monitor.",
|
||||||
|
"Anwendungsname und technische Paketbezeichnung auf CCMA vereinheitlicht."
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
@@ -0,0 +1,21 @@
|
|||||||
|
MIT License
|
||||||
|
|
||||||
|
Copyright (c) 2021 rdbende
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all
|
||||||
|
copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
SOFTWARE.
|
||||||
@@ -0,0 +1,534 @@
|
|||||||
|
# Copyright (c) 2021 rdbende <rdbende@gmail.com>
|
||||||
|
|
||||||
|
# The Forest theme is a beautiful and modern ttk theme inspired by Excel.
|
||||||
|
|
||||||
|
package require Tk 8.6
|
||||||
|
|
||||||
|
namespace eval ttk::theme::forest-dark {
|
||||||
|
|
||||||
|
variable version 1.0
|
||||||
|
package provide ttk::theme::forest-dark $version
|
||||||
|
variable colors
|
||||||
|
array set colors {
|
||||||
|
-fg "#eeeeee"
|
||||||
|
-bg "#313131"
|
||||||
|
-disabledfg "#595959"
|
||||||
|
-disabledbg "#ffffff"
|
||||||
|
-selectfg "#ffffff"
|
||||||
|
-selectbg "#217346"
|
||||||
|
}
|
||||||
|
|
||||||
|
proc LoadImages {imgdir} {
|
||||||
|
variable I
|
||||||
|
foreach file [glob -directory $imgdir *.png] {
|
||||||
|
set img [file tail [file rootname $file]]
|
||||||
|
set I($img) [image create photo -file $file -format png]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
LoadImages [file join [file dirname [info script]] forest-dark]
|
||||||
|
|
||||||
|
# Settings
|
||||||
|
ttk::style theme create forest-dark -parent default -settings {
|
||||||
|
ttk::style configure . \
|
||||||
|
-background $colors(-bg) \
|
||||||
|
-foreground $colors(-fg) \
|
||||||
|
-troughcolor $colors(-bg) \
|
||||||
|
-focuscolor $colors(-selectbg) \
|
||||||
|
-selectbackground $colors(-selectbg) \
|
||||||
|
-selectforeground $colors(-selectfg) \
|
||||||
|
-insertwidth 1 \
|
||||||
|
-insertcolor $colors(-fg) \
|
||||||
|
-fieldbackground $colors(-selectbg) \
|
||||||
|
-font {TkDefaultFont 10} \
|
||||||
|
-borderwidth 1 \
|
||||||
|
-relief flat
|
||||||
|
|
||||||
|
ttk::style map . -foreground [list disabled $colors(-disabledfg)]
|
||||||
|
|
||||||
|
tk_setPalette background [ttk::style lookup . -background] \
|
||||||
|
foreground [ttk::style lookup . -foreground] \
|
||||||
|
highlightColor [ttk::style lookup . -focuscolor] \
|
||||||
|
selectBackground [ttk::style lookup . -selectbackground] \
|
||||||
|
selectForeground [ttk::style lookup . -selectforeground] \
|
||||||
|
activeBackground [ttk::style lookup . -selectbackground] \
|
||||||
|
activeForeground [ttk::style lookup . -selectforeground]
|
||||||
|
|
||||||
|
option add *font [ttk::style lookup . -font]
|
||||||
|
|
||||||
|
|
||||||
|
# Layouts
|
||||||
|
ttk::style layout TButton {
|
||||||
|
Button.button -children {
|
||||||
|
Button.padding -children {
|
||||||
|
Button.label -side left -expand true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ttk::style layout Toolbutton {
|
||||||
|
Toolbutton.button -children {
|
||||||
|
Toolbutton.padding -children {
|
||||||
|
Toolbutton.label -side left -expand true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ttk::style layout TMenubutton {
|
||||||
|
Menubutton.button -children {
|
||||||
|
Menubutton.padding -children {
|
||||||
|
Menubutton.indicator -side right
|
||||||
|
Menubutton.label -side right -expand true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ttk::style layout TOptionMenu {
|
||||||
|
OptionMenu.button -children {
|
||||||
|
OptionMenu.padding -children {
|
||||||
|
OptionMenu.indicator -side right
|
||||||
|
OptionMenu.label -side right -expand true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ttk::style layout Accent.TButton {
|
||||||
|
AccentButton.button -children {
|
||||||
|
AccentButton.padding -children {
|
||||||
|
AccentButton.label -side left -expand true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ttk::style layout TCheckbutton {
|
||||||
|
Checkbutton.button -children {
|
||||||
|
Checkbutton.padding -children {
|
||||||
|
Checkbutton.indicator -side left
|
||||||
|
Checkbutton.label -side right -expand true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ttk::style layout Switch {
|
||||||
|
Switch.button -children {
|
||||||
|
Switch.padding -children {
|
||||||
|
Switch.indicator -side left
|
||||||
|
Switch.label -side right -expand true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ttk::style layout ToggleButton {
|
||||||
|
ToggleButton.button -children {
|
||||||
|
ToggleButton.padding -children {
|
||||||
|
ToggleButton.label -side left -expand true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ttk::style layout TRadiobutton {
|
||||||
|
Radiobutton.button -children {
|
||||||
|
Radiobutton.padding -children {
|
||||||
|
Radiobutton.indicator -side left
|
||||||
|
Radiobutton.label -side right -expand true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ttk::style layout Vertical.TScrollbar {
|
||||||
|
Vertical.Scrollbar.trough -sticky ns -children {
|
||||||
|
Vertical.Scrollbar.thumb -expand true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ttk::style layout Horizontal.TScrollbar {
|
||||||
|
Horizontal.Scrollbar.trough -sticky ew -children {
|
||||||
|
Horizontal.Scrollbar.thumb -expand true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ttk::style layout TCombobox {
|
||||||
|
Combobox.field -sticky nswe -children {
|
||||||
|
Combobox.padding -expand true -sticky nswe -children {
|
||||||
|
Combobox.textarea -sticky nswe
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Combobox.button -side right -sticky ns -children {
|
||||||
|
Combobox.arrow -sticky nsew
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ttk::style layout TSpinbox {
|
||||||
|
Spinbox.field -sticky nsew -children {
|
||||||
|
Spinbox.padding -expand true -sticky nswe -children {
|
||||||
|
Spinbox.textarea -sticky nsew
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
null -side right -sticky nsew -children {
|
||||||
|
Spinbox.uparrow -side right -sticky nsew -children {
|
||||||
|
Spinbox.symuparrow
|
||||||
|
}
|
||||||
|
Spinbox.downarrow -side left -sticky nsew -children {
|
||||||
|
Spinbox.symdownarrow
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ttk::style layout Horizontal.TSeparator {
|
||||||
|
Horizontal.separator -sticky nswe
|
||||||
|
}
|
||||||
|
|
||||||
|
ttk::style layout Vertical.TSeparator {
|
||||||
|
Vertical.separator -sticky nswe
|
||||||
|
}
|
||||||
|
|
||||||
|
ttk::style layout Card {
|
||||||
|
Card.field {
|
||||||
|
Card.padding -expand 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ttk::style layout TLabelframe {
|
||||||
|
Labelframe.border {
|
||||||
|
Labelframe.padding -expand 1 -children {
|
||||||
|
Labelframe.label -side left
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ttk::style layout TNotebook {
|
||||||
|
Notebook.border -children {
|
||||||
|
TNotebook.Tab -expand 1 -side top
|
||||||
|
Notebook.client -sticky nsew
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ttk::style layout TNotebook.Tab {
|
||||||
|
Notebook.tab -children {
|
||||||
|
Notebook.padding -side top -children {
|
||||||
|
Notebook.label
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ttk::style layout Treeview.Item {
|
||||||
|
Treeitem.padding -sticky nswe -children {
|
||||||
|
Treeitem.indicator -side left -sticky {}
|
||||||
|
Treeitem.image -side left -sticky {}
|
||||||
|
Treeitem.text -side left -sticky {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
# Elements
|
||||||
|
|
||||||
|
# Button
|
||||||
|
ttk::style configure TButton -padding {8 4 8 4} -width -10 -anchor center
|
||||||
|
|
||||||
|
ttk::style element create Button.button image \
|
||||||
|
[list $I(rect-basic) \
|
||||||
|
{selected disabled} $I(rect-basic) \
|
||||||
|
disabled $I(rect-basic) \
|
||||||
|
selected $I(rect-basic) \
|
||||||
|
pressed $I(rect-basic) \
|
||||||
|
active $I(rect-hover) \
|
||||||
|
] -border 4 -sticky nsew
|
||||||
|
|
||||||
|
# Toolbutton
|
||||||
|
ttk::style configure Toolbutton -padding {8 4 8 4} -width -10 -anchor center
|
||||||
|
|
||||||
|
ttk::style element create Toolbutton.button image \
|
||||||
|
[list $I(empty) \
|
||||||
|
{selected disabled} $I(empty) \
|
||||||
|
disabled $I(empty) \
|
||||||
|
selected $I(rect-basic) \
|
||||||
|
pressed $I(rect-basic) \
|
||||||
|
active $I(rect-basic) \
|
||||||
|
] -border 4 -sticky nsew
|
||||||
|
|
||||||
|
# Menubutton
|
||||||
|
ttk::style configure TMenubutton -padding {8 4 4 4}
|
||||||
|
|
||||||
|
ttk::style element create Menubutton.button image \
|
||||||
|
[list $I(rect-basic) \
|
||||||
|
disabled $I(rect-basic) \
|
||||||
|
pressed $I(rect-basic) \
|
||||||
|
active $I(rect-hover) \
|
||||||
|
] -border 4 -sticky nsew
|
||||||
|
|
||||||
|
ttk::style element create Menubutton.indicator image \
|
||||||
|
[list $I(down) \
|
||||||
|
active $I(down) \
|
||||||
|
pressed $I(down) \
|
||||||
|
disabled $I(down) \
|
||||||
|
] -width 15 -sticky e
|
||||||
|
|
||||||
|
# OptionMenu
|
||||||
|
ttk::style configure TOptionMenu -padding {8 4 4 4}
|
||||||
|
|
||||||
|
ttk::style element create OptionMenu.button image \
|
||||||
|
[list $I(rect-basic) \
|
||||||
|
disabled $I(rect-basic) \
|
||||||
|
pressed $I(rect-basic) \
|
||||||
|
active $I(rect-hover) \
|
||||||
|
] -border 4 -sticky nsew
|
||||||
|
|
||||||
|
ttk::style element create OptionMenu.indicator image \
|
||||||
|
[list $I(down) \
|
||||||
|
active $I(down) \
|
||||||
|
pressed $I(down) \
|
||||||
|
disabled $I(down) \
|
||||||
|
] -width 15 -sticky e
|
||||||
|
|
||||||
|
# AccentButton
|
||||||
|
ttk::style configure Accent.TButton -padding {8 4 8 4} -width -10 -anchor center -foreground #eeeeee
|
||||||
|
|
||||||
|
ttk::style element create AccentButton.button image \
|
||||||
|
[list $I(rect-accent) \
|
||||||
|
{selected disabled} $I(rect-accent-hover) \
|
||||||
|
disabled $I(rect-accent-hover) \
|
||||||
|
selected $I(rect-accent) \
|
||||||
|
pressed $I(rect-accent) \
|
||||||
|
active $I(rect-accent-hover) \
|
||||||
|
] -border 4 -sticky nsew
|
||||||
|
|
||||||
|
# Checkbutton
|
||||||
|
ttk::style configure TCheckbutton -padding 4
|
||||||
|
|
||||||
|
ttk::style element create Checkbutton.indicator image \
|
||||||
|
[list $I(check-unsel-accent) \
|
||||||
|
{alternate disabled} $I(check-tri-basic) \
|
||||||
|
{selected disabled} $I(check-basic) \
|
||||||
|
disabled $I(check-unsel-basic) \
|
||||||
|
{pressed alternate} $I(check-tri-hover) \
|
||||||
|
{active alternate} $I(check-tri-hover) \
|
||||||
|
alternate $I(check-tri-accent) \
|
||||||
|
{pressed selected} $I(check-hover) \
|
||||||
|
{active selected} $I(check-hover) \
|
||||||
|
selected $I(check-accent) \
|
||||||
|
{pressed !selected} $I(check-unsel-pressed) \
|
||||||
|
active $I(check-unsel-hover) \
|
||||||
|
] -width 26 -sticky w
|
||||||
|
|
||||||
|
# Switch
|
||||||
|
ttk::style element create Switch.indicator image \
|
||||||
|
[list $I(off-accent) \
|
||||||
|
{selected disabled} $I(on-basic) \
|
||||||
|
disabled $I(off-basic) \
|
||||||
|
{pressed selected} $I(on-accent) \
|
||||||
|
{active selected} $I(on-hover) \
|
||||||
|
selected $I(on-accent) \
|
||||||
|
{pressed !selected} $I(off-accent) \
|
||||||
|
active $I(off-hover) \
|
||||||
|
] -width 46 -sticky w
|
||||||
|
|
||||||
|
# ToggleButton
|
||||||
|
ttk::style configure ToggleButton -padding {8 4 8 4} -width -10 -anchor center
|
||||||
|
|
||||||
|
ttk::style element create ToggleButton.button image \
|
||||||
|
[list $I(rect-basic) \
|
||||||
|
{selected disabled} $I(rect-accent-hover) \
|
||||||
|
disabled $I(rect-basic) \
|
||||||
|
{pressed selected} $I(rect-basic) \
|
||||||
|
{active selected} $I(rect-accent-hover) \
|
||||||
|
selected $I(rect-accent) \
|
||||||
|
{pressed !selected} $I(rect-accent) \
|
||||||
|
active $I(rect-hover) \
|
||||||
|
] -border 4 -sticky nsew
|
||||||
|
|
||||||
|
# Radiobutton
|
||||||
|
ttk::style configure TRadiobutton -padding 4
|
||||||
|
|
||||||
|
ttk::style element create Radiobutton.indicator image \
|
||||||
|
[list $I(radio-unsel-accent) \
|
||||||
|
{alternate disabled} $I(radio-tri-basic) \
|
||||||
|
{selected disabled} $I(radio-basic) \
|
||||||
|
disabled $I(radio-unsel-basic) \
|
||||||
|
{pressed alternate} $I(radio-tri-hover) \
|
||||||
|
{active alternate} $I(radio-tri-hover) \
|
||||||
|
alternate $I(radio-tri-accent) \
|
||||||
|
{pressed selected} $I(radio-hover) \
|
||||||
|
{active selected} $I(radio-hover) \
|
||||||
|
selected $I(radio-accent) \
|
||||||
|
{pressed !selected} $I(radio-unsel-pressed) \
|
||||||
|
active $I(radio-unsel-hover) \
|
||||||
|
] -width 26 -sticky w
|
||||||
|
|
||||||
|
# Scrollbar
|
||||||
|
ttk::style element create Horizontal.Scrollbar.trough image $I(hor-basic) \
|
||||||
|
-sticky ew
|
||||||
|
|
||||||
|
ttk::style element create Horizontal.Scrollbar.thumb image \
|
||||||
|
[list $I(hor-accent) \
|
||||||
|
disabled $I(hor-basic) \
|
||||||
|
pressed $I(hor-hover) \
|
||||||
|
active $I(hor-hover) \
|
||||||
|
] -sticky ew
|
||||||
|
|
||||||
|
ttk::style element create Vertical.Scrollbar.trough image $I(vert-basic) \
|
||||||
|
-sticky ns
|
||||||
|
|
||||||
|
ttk::style element create Vertical.Scrollbar.thumb image \
|
||||||
|
[list $I(vert-accent) \
|
||||||
|
disabled $I(vert-basic) \
|
||||||
|
pressed $I(vert-hover) \
|
||||||
|
active $I(vert-hover) \
|
||||||
|
] -sticky ns
|
||||||
|
|
||||||
|
# Scale
|
||||||
|
ttk::style element create Horizontal.Scale.trough image $I(scale-hor) \
|
||||||
|
-border 5 -padding 0
|
||||||
|
|
||||||
|
ttk::style element create Horizontal.Scale.slider image \
|
||||||
|
[list $I(thumb-hor-accent) \
|
||||||
|
disabled $I(thumb-hor-basic) \
|
||||||
|
pressed $I(thumb-hor-hover) \
|
||||||
|
active $I(thumb-hor-hover) \
|
||||||
|
] -sticky {}
|
||||||
|
|
||||||
|
ttk::style element create Vertical.Scale.trough image $I(scale-vert) \
|
||||||
|
-border 5 -padding 0
|
||||||
|
|
||||||
|
ttk::style element create Vertical.Scale.slider image \
|
||||||
|
[list $I(thumb-vert-accent) \
|
||||||
|
disabled $I(thumb-vert-basic) \
|
||||||
|
pressed $I(thumb-vert-hover) \
|
||||||
|
active $I(thumb-vert-hover) \
|
||||||
|
] -sticky {}
|
||||||
|
|
||||||
|
# Progressbar
|
||||||
|
ttk::style element create Horizontal.Progressbar.trough image $I(hor-basic) \
|
||||||
|
-sticky ew
|
||||||
|
|
||||||
|
ttk::style element create Horizontal.Progressbar.pbar image $I(hor-accent) \
|
||||||
|
-sticky ew
|
||||||
|
|
||||||
|
ttk::style element create Vertical.Progressbar.trough image $I(vert-basic) \
|
||||||
|
-sticky ns
|
||||||
|
|
||||||
|
ttk::style element create Vertical.Progressbar.pbar image $I(vert-accent) \
|
||||||
|
-sticky ns
|
||||||
|
|
||||||
|
# Entry
|
||||||
|
ttk::style element create Entry.field image \
|
||||||
|
[list $I(border-basic) \
|
||||||
|
{focus hover} $I(border-accent) \
|
||||||
|
invalid $I(border-invalid) \
|
||||||
|
disabled $I(border-basic) \
|
||||||
|
focus $I(border-accent) \
|
||||||
|
hover $I(border-hover) \
|
||||||
|
] -border 5 -padding {8} -sticky nsew
|
||||||
|
|
||||||
|
# Combobox
|
||||||
|
ttk::style map TCombobox -selectbackground [list \
|
||||||
|
{!focus} $colors(-selectbg) \
|
||||||
|
{readonly hover} $colors(-selectbg) \
|
||||||
|
{readonly focus} $colors(-selectbg) \
|
||||||
|
]
|
||||||
|
|
||||||
|
ttk::style map TCombobox -selectforeground [list \
|
||||||
|
{!focus} $colors(-selectfg) \
|
||||||
|
{readonly hover} $colors(-selectfg) \
|
||||||
|
{readonly focus} $colors(-selectfg) \
|
||||||
|
]
|
||||||
|
|
||||||
|
ttk::style element create Combobox.field image \
|
||||||
|
[list $I(border-basic) \
|
||||||
|
{readonly disabled} $I(rect-basic) \
|
||||||
|
{readonly pressed} $I(rect-basic) \
|
||||||
|
{readonly focus hover} $I(rect-hover) \
|
||||||
|
{readonly focus} $I(rect-hover) \
|
||||||
|
{readonly hover} $I(rect-hover) \
|
||||||
|
{focus hover} $I(border-accent) \
|
||||||
|
readonly $I(rect-basic) \
|
||||||
|
invalid $I(border-invalid) \
|
||||||
|
disabled $I(border-basic) \
|
||||||
|
focus $I(border-accent) \
|
||||||
|
hover $I(border-hover) \
|
||||||
|
] -border 5 -padding {8 8 28 8}
|
||||||
|
|
||||||
|
ttk::style element create Combobox.button image \
|
||||||
|
[list $I(combo-button-basic) \
|
||||||
|
{!readonly focus} $I(combo-button-focus) \
|
||||||
|
{readonly focus} $I(combo-button-hover) \
|
||||||
|
{readonly hover} $I(combo-button-hover)
|
||||||
|
] -border 5 -padding {2 6 6 6}
|
||||||
|
|
||||||
|
ttk::style element create Combobox.arrow image $I(down) -width 15 -sticky e
|
||||||
|
|
||||||
|
# Spinbox
|
||||||
|
ttk::style element create Spinbox.field image \
|
||||||
|
[list $I(border-basic) \
|
||||||
|
invalid $I(border-invalid) \
|
||||||
|
disabled $I(border-basic) \
|
||||||
|
focus $I(border-accent) \
|
||||||
|
hover $I(border-hover) \
|
||||||
|
] -border 5 -padding {8 8 54 8} -sticky nsew
|
||||||
|
|
||||||
|
ttk::style element create Spinbox.uparrow image $I(spin-button-up) -border 4 -sticky nsew
|
||||||
|
|
||||||
|
ttk::style element create Spinbox.downarrow image \
|
||||||
|
[list $I(spin-button-down-basic) \
|
||||||
|
focus $I(spin-button-down-focus) \
|
||||||
|
] -border 4 -sticky nsew
|
||||||
|
|
||||||
|
ttk::style element create Spinbox.symuparrow image $I(up) -width 15 -sticky {}
|
||||||
|
ttk::style element create Spinbox.symdownarrow image $I(down) -width 17 -sticky {}
|
||||||
|
|
||||||
|
# Sizegrip
|
||||||
|
ttk::style element create Sizegrip.sizegrip image $I(sizegrip) \
|
||||||
|
-sticky nsew
|
||||||
|
|
||||||
|
# Separator
|
||||||
|
ttk::style element create Horizontal.separator image $I(separator)
|
||||||
|
|
||||||
|
ttk::style element create Vertical.separator image $I(separator)
|
||||||
|
|
||||||
|
# Card
|
||||||
|
ttk::style element create Card.field image $I(card) \
|
||||||
|
-border 10 -padding 4 -sticky nsew
|
||||||
|
|
||||||
|
# Labelframe
|
||||||
|
ttk::style element create Labelframe.border image $I(card) \
|
||||||
|
-border 5 -padding 4 -sticky nsew
|
||||||
|
|
||||||
|
# Notebook
|
||||||
|
ttk::style configure TNotebook -padding 2
|
||||||
|
|
||||||
|
ttk::style element create Notebook.border image $I(card) -border 5
|
||||||
|
|
||||||
|
ttk::style element create Notebook.client image $I(notebook) -border 5
|
||||||
|
|
||||||
|
ttk::style element create Notebook.tab image \
|
||||||
|
[list $I(tab-basic) \
|
||||||
|
selected $I(tab-accent) \
|
||||||
|
active $I(tab-hover) \
|
||||||
|
] -border 5 -padding {14 4}
|
||||||
|
|
||||||
|
# Treeview
|
||||||
|
ttk::style element create Treeview.field image $I(card) \
|
||||||
|
-border 5
|
||||||
|
|
||||||
|
ttk::style element create Treeheading.cell image \
|
||||||
|
[list $I(tree-basic) \
|
||||||
|
pressed $I(tree-pressed)
|
||||||
|
] -border 5 -padding 6 -sticky nsew
|
||||||
|
|
||||||
|
ttk::style element create Treeitem.indicator image \
|
||||||
|
[list $I(right) \
|
||||||
|
user2 $I(empty) \
|
||||||
|
user1 $I(down) \
|
||||||
|
] -width 17 -sticky {}
|
||||||
|
|
||||||
|
ttk::style configure Treeview -background $colors(-bg)
|
||||||
|
ttk::style configure Treeview.Item -padding {2 0 0 0}
|
||||||
|
|
||||||
|
ttk::style map Treeview \
|
||||||
|
-background [list selected $colors(-selectbg)] \
|
||||||
|
-foreground [list selected $colors(-selectfg)]
|
||||||
|
|
||||||
|
# Sashes
|
||||||
|
#ttk::style map TPanedwindow -background [list hover $colors(-bg)]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
After Width: | Height: | Size: 385 B |
|
After Width: | Height: | Size: 389 B |
|
After Width: | Height: | Size: 333 B |
|
After Width: | Height: | Size: 337 B |
|
After Width: | Height: | Size: 408 B |
|
After Width: | Height: | Size: 374 B |
|
After Width: | Height: | Size: 434 B |
|
After Width: | Height: | Size: 406 B |
|
After Width: | Height: | Size: 434 B |
|
After Width: | Height: | Size: 317 B |
|
After Width: | Height: | Size: 300 B |
|
After Width: | Height: | Size: 320 B |
|
After Width: | Height: | Size: 346 B |
|
After Width: | Height: | Size: 333 B |
|
After Width: | Height: | Size: 341 B |
|
After Width: | Height: | Size: 290 B |
|
After Width: | Height: | Size: 235 B |
|
After Width: | Height: | Size: 245 B |
|
After Width: | Height: | Size: 239 B |
|
After Width: | Height: | Size: 251 B |
|
After Width: | Height: | Size: 130 B |
|
After Width: | Height: | Size: 162 B |
|
After Width: | Height: | Size: 162 B |
|
After Width: | Height: | Size: 162 B |
|
After Width: | Height: | Size: 193 B |
|
After Width: | Height: | Size: 679 B |
|
After Width: | Height: | Size: 640 B |
|
After Width: | Height: | Size: 692 B |
|
After Width: | Height: | Size: 676 B |
|
After Width: | Height: | Size: 633 B |
|
After Width: | Height: | Size: 685 B |
|
After Width: | Height: | Size: 565 B |
|
After Width: | Height: | Size: 543 B |
|
After Width: | Height: | Size: 579 B |
|
After Width: | Height: | Size: 465 B |
|
After Width: | Height: | Size: 450 B |
|
After Width: | Height: | Size: 489 B |
|
After Width: | Height: | Size: 605 B |
|
After Width: | Height: | Size: 559 B |
|
After Width: | Height: | Size: 615 B |
|
After Width: | Height: | Size: 468 B |
|
After Width: | Height: | Size: 290 B |
|
After Width: | Height: | Size: 290 B |
|
After Width: | Height: | Size: 272 B |
|
After Width: | Height: | Size: 273 B |
|
After Width: | Height: | Size: 217 B |
|
After Width: | Height: | Size: 166 B |
|
After Width: | Height: | Size: 161 B |
|
After Width: | Height: | Size: 128 B |
|
After Width: | Height: | Size: 459 B |
|
After Width: | Height: | Size: 153 B |
|
After Width: | Height: | Size: 160 B |
|
After Width: | Height: | Size: 222 B |
|
After Width: | Height: | Size: 188 B |
|
After Width: | Height: | Size: 188 B |
|
After Width: | Height: | Size: 188 B |
|
After Width: | Height: | Size: 270 B |
|
After Width: | Height: | Size: 258 B |
|
After Width: | Height: | Size: 273 B |
|
After Width: | Height: | Size: 269 B |
|
After Width: | Height: | Size: 253 B |
|
After Width: | Height: | Size: 269 B |
|
After Width: | Height: | Size: 149 B |
|
After Width: | Height: | Size: 171 B |
|
After Width: | Height: | Size: 250 B |
|
After Width: | Height: | Size: 158 B |
|
After Width: | Height: | Size: 158 B |
|
After Width: | Height: | Size: 158 B |
@@ -0,0 +1,541 @@
|
|||||||
|
# Copyright (c) 2021 rdbende <rdbende@gmail.com>
|
||||||
|
|
||||||
|
# The Forest theme is a beautiful and modern ttk theme inspired by Excel.
|
||||||
|
|
||||||
|
package require Tk 8.6
|
||||||
|
|
||||||
|
namespace eval ttk::theme::forest-light {
|
||||||
|
|
||||||
|
variable version 1.0
|
||||||
|
package provide ttk::theme::forest-light $version
|
||||||
|
variable colors
|
||||||
|
array set colors {
|
||||||
|
-fg "#313131"
|
||||||
|
-bg "#ffffff"
|
||||||
|
-disabledfg "#595959"
|
||||||
|
-disabledbg "#ffffff"
|
||||||
|
-selectfg "#ffffff"
|
||||||
|
-selectbg "#217346"
|
||||||
|
}
|
||||||
|
|
||||||
|
proc LoadImages {imgdir} {
|
||||||
|
variable I
|
||||||
|
foreach file [glob -directory $imgdir *.png] {
|
||||||
|
set img [file tail [file rootname $file]]
|
||||||
|
set I($img) [image create photo -file $file -format png]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
LoadImages [file join [file dirname [info script]] forest-light]
|
||||||
|
|
||||||
|
# Settings
|
||||||
|
ttk::style theme create forest-light -parent default -settings {
|
||||||
|
ttk::style configure . \
|
||||||
|
-background $colors(-bg) \
|
||||||
|
-foreground $colors(-fg) \
|
||||||
|
-troughcolor $colors(-bg) \
|
||||||
|
-focuscolor $colors(-selectbg) \
|
||||||
|
-selectbackground $colors(-selectbg) \
|
||||||
|
-selectforeground $colors(-selectfg) \
|
||||||
|
-insertwidth 1 \
|
||||||
|
-insertcolor $colors(-fg) \
|
||||||
|
-fieldbackground $colors(-selectbg) \
|
||||||
|
-font {TkDefaultFont 10} \
|
||||||
|
-borderwidth 1 \
|
||||||
|
-relief flat
|
||||||
|
|
||||||
|
ttk::style map . -foreground [list disabled $colors(-disabledfg)]
|
||||||
|
|
||||||
|
tk_setPalette background [ttk::style lookup . -background] \
|
||||||
|
foreground [ttk::style lookup . -foreground] \
|
||||||
|
highlightColor [ttk::style lookup . -focuscolor] \
|
||||||
|
selectBackground [ttk::style lookup . -selectbackground] \
|
||||||
|
selectForeground [ttk::style lookup . -selectforeground] \
|
||||||
|
activeBackground [ttk::style lookup . -selectbackground] \
|
||||||
|
activeForeground [ttk::style lookup . -selectforeground]
|
||||||
|
|
||||||
|
option add *font [ttk::style lookup . -font]
|
||||||
|
|
||||||
|
|
||||||
|
# Layouts
|
||||||
|
ttk::style layout TButton {
|
||||||
|
Button.button -children {
|
||||||
|
Button.padding -children {
|
||||||
|
Button.label -side left -expand true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ttk::style layout Toolbutton {
|
||||||
|
Toolbutton.button -children {
|
||||||
|
Toolbutton.padding -children {
|
||||||
|
Toolbutton.label -side left -expand true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ttk::style layout TMenubutton {
|
||||||
|
Menubutton.button -children {
|
||||||
|
Menubutton.padding -children {
|
||||||
|
Menubutton.indicator -side right
|
||||||
|
Menubutton.label -side right -expand true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ttk::style layout TOptionMenu {
|
||||||
|
OptionMenu.button -children {
|
||||||
|
OptionMenu.padding -children {
|
||||||
|
OptionMenu.indicator -side right
|
||||||
|
OptionMenu.label -side right -expand true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ttk::style layout Accent.TButton {
|
||||||
|
AccentButton.button -children {
|
||||||
|
AccentButton.padding -children {
|
||||||
|
AccentButton.label -side left -expand true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ttk::style layout TCheckbutton {
|
||||||
|
Checkbutton.button -children {
|
||||||
|
Checkbutton.padding -children {
|
||||||
|
Checkbutton.indicator -side left
|
||||||
|
Checkbutton.label -side right -expand true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ttk::style layout Switch {
|
||||||
|
Switch.button -children {
|
||||||
|
Switch.padding -children {
|
||||||
|
Switch.indicator -side left
|
||||||
|
Switch.label -side right -expand true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ttk::style layout ToggleButton {
|
||||||
|
ToggleButton.button -children {
|
||||||
|
ToggleButton.padding -children {
|
||||||
|
ToggleButton.label -side left -expand true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ttk::style layout TRadiobutton {
|
||||||
|
Radiobutton.button -children {
|
||||||
|
Radiobutton.padding -children {
|
||||||
|
Radiobutton.indicator -side left
|
||||||
|
Radiobutton.label -side right -expand true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ttk::style layout Vertical.TScrollbar {
|
||||||
|
Vertical.Scrollbar.trough -sticky ns -children {
|
||||||
|
Vertical.Scrollbar.thumb -expand true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ttk::style layout Horizontal.TScrollbar {
|
||||||
|
Horizontal.Scrollbar.trough -sticky ew -children {
|
||||||
|
Horizontal.Scrollbar.thumb -expand true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ttk::style layout TCombobox {
|
||||||
|
Combobox.field -sticky nswe -children {
|
||||||
|
Combobox.padding -expand true -sticky nswe -children {
|
||||||
|
Combobox.textarea -sticky nswe
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Combobox.button -side right -sticky ns -children {
|
||||||
|
Combobox.arrow -sticky nsew
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ttk::style layout TSpinbox {
|
||||||
|
Spinbox.field -sticky nsew -children {
|
||||||
|
Spinbox.padding -expand true -sticky nswe -children {
|
||||||
|
Spinbox.textarea -sticky nsew
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
null -side right -sticky nsew -children {
|
||||||
|
Spinbox.uparrow -side right -sticky nsew -children {
|
||||||
|
Spinbox.symuparrow
|
||||||
|
}
|
||||||
|
Spinbox.downarrow -side left -sticky nsew -children {
|
||||||
|
Spinbox.symdownarrow
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ttk::style layout Horizontal.TSeparator {
|
||||||
|
Horizontal.separator -sticky nswe
|
||||||
|
}
|
||||||
|
|
||||||
|
ttk::style layout Vertical.TSeparator {
|
||||||
|
Vertical.separator -sticky nswe
|
||||||
|
}
|
||||||
|
|
||||||
|
ttk::style layout Card {
|
||||||
|
Card.field {
|
||||||
|
Card.padding -expand 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ttk::style layout TLabelframe {
|
||||||
|
Labelframe.border {
|
||||||
|
Labelframe.padding -expand 1 -children {
|
||||||
|
Labelframe.label -side left
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ttk::style layout TNotebook {
|
||||||
|
Notebook.border -children {
|
||||||
|
TNotebook.Tab -expand 1 -side top
|
||||||
|
Notebook.client -sticky nsew
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ttk::style layout TNotebook.Tab {
|
||||||
|
Notebook.tab -children {
|
||||||
|
Notebook.padding -side top -children {
|
||||||
|
Notebook.label
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ttk::style layout Treeview.Item {
|
||||||
|
Treeitem.padding -sticky nswe -children {
|
||||||
|
Treeitem.indicator -side left -sticky {}
|
||||||
|
Treeitem.image -side left -sticky {}
|
||||||
|
Treeitem.text -side left -sticky {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
# Elements
|
||||||
|
|
||||||
|
# Button
|
||||||
|
ttk::style configure TButton -padding {8 4 8 4} -width -10 -anchor center
|
||||||
|
|
||||||
|
ttk::style element create Button.button image \
|
||||||
|
[list $I(rect-basic) \
|
||||||
|
{selected disabled} $I(rect-basic) \
|
||||||
|
disabled $I(rect-basic) \
|
||||||
|
selected $I(rect-basic) \
|
||||||
|
pressed $I(rect-basic) \
|
||||||
|
active $I(rect-hover) \
|
||||||
|
] -border 4 -sticky nsew
|
||||||
|
|
||||||
|
# Toolbutton
|
||||||
|
ttk::style configure Toolbutton -padding {8 4 8 4} -width -10 -anchor center
|
||||||
|
|
||||||
|
ttk::style element create Toolbutton.button image \
|
||||||
|
[list $I(empty) \
|
||||||
|
{selected disabled} $I(empty) \
|
||||||
|
disabled $I(empty) \
|
||||||
|
selected $I(rect-basic) \
|
||||||
|
pressed $I(rect-basic) \
|
||||||
|
active $I(rect-basic) \
|
||||||
|
] -border 4 -sticky nsew
|
||||||
|
|
||||||
|
# Menubutton
|
||||||
|
ttk::style configure TMenubutton -padding {8 4 4 4}
|
||||||
|
|
||||||
|
ttk::style element create Menubutton.button image \
|
||||||
|
[list $I(rect-basic) \
|
||||||
|
disabled $I(rect-basic) \
|
||||||
|
pressed $I(rect-basic) \
|
||||||
|
active $I(rect-hover) \
|
||||||
|
] -border 4 -sticky nsew
|
||||||
|
|
||||||
|
ttk::style element create Menubutton.indicator image \
|
||||||
|
[list $I(down) \
|
||||||
|
active $I(down) \
|
||||||
|
pressed $I(down) \
|
||||||
|
disabled $I(down) \
|
||||||
|
] -width 15 -sticky e
|
||||||
|
|
||||||
|
# OptionMenu
|
||||||
|
ttk::style configure TOptionMenu -padding {8 4 4 4}
|
||||||
|
|
||||||
|
ttk::style element create OptionMenu.button image \
|
||||||
|
[list $I(rect-basic) \
|
||||||
|
disabled $I(rect-basic) \
|
||||||
|
pressed $I(rect-basic) \
|
||||||
|
active $I(rect-hover) \
|
||||||
|
] -border 4 -sticky nsew
|
||||||
|
|
||||||
|
ttk::style element create OptionMenu.indicator image \
|
||||||
|
[list $I(down) \
|
||||||
|
active $I(down) \
|
||||||
|
pressed $I(down) \
|
||||||
|
disabled $I(down) \
|
||||||
|
] -width 15 -sticky e
|
||||||
|
|
||||||
|
# AccentButton
|
||||||
|
ttk::style configure Accent.TButton -padding {8 4 8 4} -width -10 -anchor center -foreground #eeeeee
|
||||||
|
|
||||||
|
ttk::style element create AccentButton.button image \
|
||||||
|
[list $I(rect-accent) \
|
||||||
|
{selected disabled} $I(rect-accent-hover) \
|
||||||
|
disabled $I(rect-accent-hover) \
|
||||||
|
selected $I(rect-accent) \
|
||||||
|
pressed $I(rect-accent) \
|
||||||
|
active $I(rect-accent-hover) \
|
||||||
|
] -border 4 -sticky nsew
|
||||||
|
|
||||||
|
# Checkbutton
|
||||||
|
ttk::style configure TCheckbutton -padding 4
|
||||||
|
|
||||||
|
ttk::style element create Checkbutton.indicator image \
|
||||||
|
[list $I(check-unsel-accent) \
|
||||||
|
{alternate disabled} $I(check-tri-basic) \
|
||||||
|
{selected disabled} $I(check-basic) \
|
||||||
|
disabled $I(check-unsel-basic) \
|
||||||
|
{pressed alternate} $I(check-tri-hover) \
|
||||||
|
{active alternate} $I(check-tri-hover) \
|
||||||
|
alternate $I(check-tri-accent) \
|
||||||
|
{pressed selected} $I(check-hover) \
|
||||||
|
{active selected} $I(check-hover) \
|
||||||
|
selected $I(check-accent) \
|
||||||
|
{pressed !selected} $I(check-unsel-pressed) \
|
||||||
|
active $I(check-unsel-hover) \
|
||||||
|
] -width 26 -sticky w
|
||||||
|
|
||||||
|
# Switch
|
||||||
|
ttk::style element create Switch.indicator image \
|
||||||
|
[list $I(off-accent) \
|
||||||
|
{selected disabled} $I(on-basic) \
|
||||||
|
disabled $I(off-basic) \
|
||||||
|
{pressed selected} $I(on-accent) \
|
||||||
|
{active selected} $I(on-hover) \
|
||||||
|
selected $I(on-accent) \
|
||||||
|
{pressed !selected} $I(off-accent) \
|
||||||
|
active $I(off-hover) \
|
||||||
|
] -width 46 -sticky w
|
||||||
|
|
||||||
|
# ToggleButton
|
||||||
|
ttk::style configure ToggleButton -padding {8 4 8 4} -width -10 -anchor center -foregound $colors(-fg)
|
||||||
|
|
||||||
|
ttk::style map ToggleButton -foreground \
|
||||||
|
[list {pressed selected} $colors(-fg) \
|
||||||
|
{pressed !selected} #ffffff \
|
||||||
|
selected #ffffff]
|
||||||
|
|
||||||
|
ttk::style element create ToggleButton.button image \
|
||||||
|
[list $I(rect-basic) \
|
||||||
|
{selected disabled} $I(rect-accent-hover) \
|
||||||
|
disabled $I(rect-basic) \
|
||||||
|
{pressed selected} $I(rect-basic) \
|
||||||
|
{active selected} $I(rect-accent-hover) \
|
||||||
|
selected $I(rect-accent) \
|
||||||
|
{pressed !selected} $I(rect-accent) \
|
||||||
|
active $I(rect-hover) \
|
||||||
|
] -border 4 -sticky nsew
|
||||||
|
|
||||||
|
# Radiobutton
|
||||||
|
ttk::style configure TRadiobutton -padding 4
|
||||||
|
|
||||||
|
ttk::style element create Radiobutton.indicator image \
|
||||||
|
[list $I(radio-unsel-accent) \
|
||||||
|
{alternate disabled} $I(radio-tri-basic) \
|
||||||
|
{selected disabled} $I(radio-basic) \
|
||||||
|
disabled $I(radio-unsel-basic) \
|
||||||
|
{pressed alternate} $I(radio-tri-hover) \
|
||||||
|
{active alternate} $I(radio-tri-hover) \
|
||||||
|
alternate $I(radio-tri-accent) \
|
||||||
|
{pressed selected} $I(radio-hover) \
|
||||||
|
{active selected} $I(radio-hover) \
|
||||||
|
selected $I(radio-accent) \
|
||||||
|
{pressed !selected} $I(radio-unsel-pressed) \
|
||||||
|
active $I(radio-unsel-hover) \
|
||||||
|
] -width 26 -sticky w
|
||||||
|
|
||||||
|
# Scrollbar
|
||||||
|
ttk::style element create Horizontal.Scrollbar.trough image $I(hor-basic) \
|
||||||
|
-sticky ew
|
||||||
|
|
||||||
|
ttk::style element create Horizontal.Scrollbar.thumb image \
|
||||||
|
[list $I(hor-accent) \
|
||||||
|
disabled $I(hor-basic) \
|
||||||
|
pressed $I(hor-hover) \
|
||||||
|
active $I(hor-hover) \
|
||||||
|
] -sticky ew
|
||||||
|
|
||||||
|
ttk::style element create Vertical.Scrollbar.trough image $I(vert-basic) \
|
||||||
|
-sticky ns
|
||||||
|
|
||||||
|
ttk::style element create Vertical.Scrollbar.thumb image \
|
||||||
|
[list $I(vert-accent) \
|
||||||
|
disabled $I(vert-basic) \
|
||||||
|
pressed $I(vert-hover) \
|
||||||
|
active $I(vert-hover) \
|
||||||
|
] -sticky ns
|
||||||
|
|
||||||
|
# Scale
|
||||||
|
ttk::style element create Horizontal.Scale.trough image $I(scale-hor) \
|
||||||
|
-border 5 -padding 0
|
||||||
|
|
||||||
|
ttk::style element create Horizontal.Scale.slider image \
|
||||||
|
[list $I(thumb-hor-accent) \
|
||||||
|
disabled $I(thumb-hor-basic) \
|
||||||
|
pressed $I(thumb-hor-hover) \
|
||||||
|
active $I(thumb-hor-hover) \
|
||||||
|
] -sticky {}
|
||||||
|
|
||||||
|
ttk::style element create Vertical.Scale.trough image $I(scale-vert) \
|
||||||
|
-border 5 -padding 0
|
||||||
|
|
||||||
|
ttk::style element create Vertical.Scale.slider image \
|
||||||
|
[list $I(thumb-vert-accent) \
|
||||||
|
disabled $I(thumb-vert-basic) \
|
||||||
|
pressed $I(thumb-vert-hover) \
|
||||||
|
active $I(thumb-vert-hover) \
|
||||||
|
] -sticky {}
|
||||||
|
|
||||||
|
# Progressbar
|
||||||
|
ttk::style element create Horizontal.Progressbar.trough image $I(hor-basic) \
|
||||||
|
-sticky ew
|
||||||
|
|
||||||
|
ttk::style element create Horizontal.Progressbar.pbar image $I(hor-accent) \
|
||||||
|
-sticky ew
|
||||||
|
|
||||||
|
ttk::style element create Vertical.Progressbar.trough image $I(vert-basic) \
|
||||||
|
-sticky ns
|
||||||
|
|
||||||
|
ttk::style element create Vertical.Progressbar.pbar image $I(vert-accent) \
|
||||||
|
-sticky ns
|
||||||
|
|
||||||
|
# Entry
|
||||||
|
ttk::style element create Entry.field image \
|
||||||
|
[list $I(border-basic) \
|
||||||
|
{focus hover} $I(border-accent) \
|
||||||
|
invalid $I(border-invalid) \
|
||||||
|
disabled $I(border-basic) \
|
||||||
|
focus $I(border-accent) \
|
||||||
|
hover $I(border-hover) \
|
||||||
|
] -border 5 -padding {8} -sticky nsew
|
||||||
|
|
||||||
|
# Combobox
|
||||||
|
ttk::style map TCombobox -selectbackground [list \
|
||||||
|
{!focus} $colors(-selectbg) \
|
||||||
|
{readonly hover} $colors(-selectbg) \
|
||||||
|
{readonly focus} $colors(-selectbg) \
|
||||||
|
]
|
||||||
|
|
||||||
|
ttk::style map TCombobox -selectforeground [list \
|
||||||
|
{!focus} $colors(-selectfg) \
|
||||||
|
{readonly hover} $colors(-selectfg) \
|
||||||
|
{readonly focus} $colors(-selectfg) \
|
||||||
|
]
|
||||||
|
|
||||||
|
ttk::style element create Combobox.field image \
|
||||||
|
[list $I(border-basic) \
|
||||||
|
{readonly disabled} $I(rect-basic) \
|
||||||
|
{readonly pressed} $I(rect-basic) \
|
||||||
|
{readonly focus hover} $I(rect-hover) \
|
||||||
|
{readonly focus} $I(rect-hover) \
|
||||||
|
{readonly hover} $I(rect-hover) \
|
||||||
|
{focus hover} $I(border-accent) \
|
||||||
|
readonly $I(rect-basic) \
|
||||||
|
invalid $I(border-invalid) \
|
||||||
|
disabled $I(border-basic) \
|
||||||
|
focus $I(border-accent) \
|
||||||
|
hover $I(border-hover) \
|
||||||
|
] -border 5 -padding {8 8 28 8}
|
||||||
|
|
||||||
|
ttk::style element create Combobox.button image \
|
||||||
|
[list $I(combo-button-basic) \
|
||||||
|
{!readonly focus} $I(combo-button-focus) \
|
||||||
|
{readonly focus} $I(combo-button-hover) \
|
||||||
|
{readonly hover} $I(combo-button-hover)
|
||||||
|
] -border 5 -padding {2 6 6 6}
|
||||||
|
|
||||||
|
ttk::style element create Combobox.arrow image $I(down) -width 15 -sticky e
|
||||||
|
|
||||||
|
# Spinbox
|
||||||
|
ttk::style element create Spinbox.field image \
|
||||||
|
[list $I(border-basic) \
|
||||||
|
invalid $I(border-invalid) \
|
||||||
|
disabled $I(border-basic) \
|
||||||
|
focus $I(border-accent) \
|
||||||
|
hover $I(border-hover) \
|
||||||
|
] -border 5 -padding {8 8 54 8} -sticky nsew
|
||||||
|
|
||||||
|
ttk::style element create Spinbox.uparrow image $I(spin-button-up) -border 4 -sticky nsew
|
||||||
|
|
||||||
|
ttk::style element create Spinbox.downarrow image \
|
||||||
|
[list $I(spin-button-down-basic) \
|
||||||
|
focus $I(spin-button-down-focus) \
|
||||||
|
] -border 4 -sticky nsew
|
||||||
|
|
||||||
|
ttk::style element create Spinbox.symuparrow image $I(up) -width 15 -sticky {}
|
||||||
|
ttk::style element create Spinbox.symdownarrow image $I(down) -width 17 -sticky {}
|
||||||
|
|
||||||
|
# Sizegrip
|
||||||
|
ttk::style element create Sizegrip.sizegrip image $I(sizegrip) \
|
||||||
|
-sticky nsew
|
||||||
|
|
||||||
|
# Separator
|
||||||
|
ttk::style element create Horizontal.separator image $I(separator)
|
||||||
|
|
||||||
|
ttk::style element create Vertical.separator image $I(separator)
|
||||||
|
|
||||||
|
# Card
|
||||||
|
ttk::style element create Card.field image $I(card) \
|
||||||
|
-border 10 -padding 4 -sticky nsew
|
||||||
|
|
||||||
|
# Labelframe
|
||||||
|
ttk::style element create Labelframe.border image $I(card) \
|
||||||
|
-border 5 -padding 4 -sticky nsew
|
||||||
|
|
||||||
|
# Notebook
|
||||||
|
ttk::style configure TNotebook -padding 2
|
||||||
|
|
||||||
|
ttk::style element create Notebook.border image $I(card) -border 5
|
||||||
|
|
||||||
|
ttk::style element create Notebook.client image $I(notebook) -border 5
|
||||||
|
|
||||||
|
ttk::style element create Notebook.tab image \
|
||||||
|
[list $I(tab-basic) \
|
||||||
|
selected $I(tab-accent) \
|
||||||
|
active $I(tab-hover) \
|
||||||
|
] -border 5 -padding {14 4}
|
||||||
|
|
||||||
|
# Treeview
|
||||||
|
ttk::style element create Treeview.field image $I(card) \
|
||||||
|
-border 5
|
||||||
|
|
||||||
|
ttk::style element create Treeheading.cell image \
|
||||||
|
[list $I(tree-basic) \
|
||||||
|
pressed $I(tree-pressed)
|
||||||
|
] -border 5 -padding 6 -sticky nsew
|
||||||
|
|
||||||
|
ttk::style element create Treeitem.indicator image \
|
||||||
|
[list $I(right) \
|
||||||
|
user2 $I(empty) \
|
||||||
|
{user1 focus} $I(down-focus) \
|
||||||
|
focus $I(right-focus) \
|
||||||
|
user1 $I(down) \
|
||||||
|
] -width 17 -sticky {}
|
||||||
|
|
||||||
|
ttk::style configure Treeview -background $colors(-bg)
|
||||||
|
ttk::style configure Treeview.Item -padding {2 0 0 0}
|
||||||
|
|
||||||
|
ttk::style map Treeview \
|
||||||
|
-background [list selected $colors(-selectbg)] \
|
||||||
|
-foreground [list selected $colors(-selectfg)]
|
||||||
|
|
||||||
|
# Sashes
|
||||||
|
#ttk::style map TPanedwindow -background [list hover $colors(-bg)]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
After Width: | Height: | Size: 445 B |
|
After Width: | Height: | Size: 463 B |
|
After Width: | Height: | Size: 311 B |
|
After Width: | Height: | Size: 324 B |
|
After Width: | Height: | Size: 444 B |
|
After Width: | Height: | Size: 353 B |
|
After Width: | Height: | Size: 526 B |
|
After Width: | Height: | Size: 390 B |
|
After Width: | Height: | Size: 531 B |
|
After Width: | Height: | Size: 358 B |
|
After Width: | Height: | Size: 281 B |
|
After Width: | Height: | Size: 358 B |
|
After Width: | Height: | Size: 403 B |
|
After Width: | Height: | Size: 311 B |
|
After Width: | Height: | Size: 398 B |
|
After Width: | Height: | Size: 335 B |
|
After Width: | Height: | Size: 247 B |
|
After Width: | Height: | Size: 260 B |