2 Commits
Author SHA1 Message Date
Kerim AtilganandClaude Opus 5.5 7b9a2acec0 Testdaten: erfundene statt echter Kundennummer
Build / linux (push) Successful in 1m58s
Build / windows-exe (push) Successful in 7m19s
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-02 21:15:08 +01:00
Kerim AtilganandClaude Opus 5.5 8c86571034 Modernes Design: neue Symbole und Programm-Icon, ohne „95“ im Namen, Tipp des Tages ohne Büroklammer
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-02 21:12:05 +01:00
36 changed files with 150 additions and 43 deletions

No files matched your search

+1
View File
@@ -16,3 +16,4 @@ build/version_info.txt
selbsttest.txt selbsttest.txt
/*.jpg /*.jpg
/*.png /*.png
.claude/
BIN
View File
Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.3 KiB

After

Width:  |  Height:  |  Size: 43 KiB

BIN
View File
Binary file not shown.

Before

Width:  |  Height:  |  Size: 980 B

After

Width:  |  Height:  |  Size: 24 KiB

-20
View File
@@ -1,20 +0,0 @@
"""Erzeugt assets/app.ico aus der Pixel-Grafik in provtool/gui/win95.py (benötigt Pillow, nur zum Entwickeln)."""
import sys
from pathlib import Path
from PIL import Image
ROOT = Path(__file__).resolve().parents[1]
sys.path.insert(0, str(ROOT))
from provtool.gui.win95 import PALETTE, _icon_rows # noqa: E402
img = Image.new("RGBA", (16, 16), (0, 0, 0, 0))
for y, row in enumerate(_icon_rows("app")):
for x, ch in enumerate(row):
if ch != ".":
img.putpixel((x, y), tuple(int(PALETTE[ch][i:i + 2], 16) for i in (1, 3, 5)) + (255,))
groessen = [16, 32, 48, 64, 128, 256]
big = img.resize((256, 256), Image.NEAREST)
big.save(ROOT / "assets" / "app.ico", sizes=[(s, s) for s in groessen])
big.save(ROOT / "assets" / "app.png")
print("assets/app.ico geschrieben")
+117
View File
@@ -0,0 +1,117 @@
"""Zeichnet die modernen Symbole (flach, wie Windows 11) und das Programm-Icon.
Ausgabe: provtool/gui/bilder/modern/<name>.png (20 px) und <name>_gross.png (40 px),
assets/app.ico und assets/app.png. Benötigt Pillow – nur zum Entwickeln, nicht zur Laufzeit.
"""
from pathlib import Path
from PIL import Image, ImageDraw, ImageFont
ROOT = Path(__file__).resolve().parents[1]
ZIEL = ROOT / "provtool" / "gui" / "bilder" / "modern"
N = 160 # Zeichenfläche (8-fach), danach weich verkleinert
LINIE, AKZENT, HELL = (66, 66, 66, 255), (0, 95, 184, 255), (255, 255, 255, 255)
GELB, ROT, ORANGE = (240, 190, 70, 255), (196, 43, 28, 255), (247, 168, 0, 255)
S = 9 # Strichstärke auf der Zeichenfläche
SCHRIFT = "/usr/share/fonts/truetype/dejavu/DejaVuSans-Bold.ttf"
def leinwand():
img = Image.new("RGBA", (N, N), (0, 0, 0, 0))
return img, ImageDraw.Draw(img)
def zeichen(d, text, farbe, groesse=104):
f = ImageFont.truetype(SCHRIFT, groesse)
d.text((N / 2, N / 2 + 4), text, font=f, fill=farbe, anchor="mm")
def prozent(d, farbe, s=S):
d.ellipse((28, 28, 68, 68), outline=farbe, width=s)
d.ellipse((92, 92, 132, 132), outline=farbe, width=s)
d.line((120, 30, 40, 130), fill=farbe, width=s + 2)
def neu(d):
d.polygon([(34, 14), (96, 14), (126, 44), (126, 146), (34, 146)], outline=LINIE, width=S, fill=HELL)
d.line([(96, 14), (96, 44), (126, 44)], fill=LINIE, width=S)
d.ellipse((86, 86, 150, 150), fill=AKZENT)
d.line((118, 100, 118, 136), fill=HELL, width=S)
d.line((100, 118, 136, 118), fill=HELL, width=S)
def oeffnen(d):
d.polygon([(14, 34), (62, 34), (76, 50), (146, 50), (146, 132), (14, 132)], fill=GELB, outline=(193, 140, 30, 255),
width=S - 2)
d.rectangle((14, 66, 146, 132), fill=(250, 210, 100, 255), outline=(193, 140, 30, 255), width=S - 2)
def ablage(d, hoch: bool):
d.line([(18, 96), (18, 140), (142, 140), (142, 96)], fill=LINIE, width=S, joint="curve")
oben, unten = (14, 104) if hoch else (14, 104)
d.line((80, oben, 80, unten), fill=AKZENT, width=S + 2)
if hoch:
d.polygon([(80, 8), (52, 42), (108, 42)], fill=AKZENT)
else:
d.polygon([(80, 118), (52, 82), (108, 82)], fill=AKZENT)
def haendler(d):
d.ellipse((24, 26, 74, 76), outline=LINIE, width=S)
d.arc((8, 82, 90, 170), 180, 360, fill=LINIE, width=S)
d.ellipse((88, 34, 132, 78), fill=AKZENT)
d.pieslice((74, 86, 152, 166), 180, 360, fill=AKZENT)
def rechner(d): # Stift: Betrag ändern
d.polygon([(110, 18), (142, 50), (58, 134), (26, 102)], fill=HELL, outline=LINIE, width=S)
d.polygon([(26, 102), (58, 134), (16, 144)], fill=AKZENT)
d.line((98, 30, 130, 62), fill=LINIE, width=S)
def birne(d):
d.ellipse((34, 10, 126, 102), fill=GELB, outline=(193, 140, 30, 255), width=S - 2)
d.rectangle((56, 96, 104, 122), fill=GELB)
d.rectangle((56, 122, 104, 150), fill=(120, 120, 120, 255))
d.line((60, 134, 100, 134), fill=HELL, width=4)
def kreis(d, farbe, text):
d.ellipse((6, 6, 154, 154), fill=farbe)
zeichen(d, text, HELL)
def warnung(d):
d.polygon([(80, 8), (156, 148), (4, 148)], fill=ORANGE)
zeichen(d, "!", (30, 30, 30, 255), 92)
def app(d):
d.rounded_rectangle((4, 4, 156, 156), radius=34, fill=AKZENT)
prozent(d, HELL, 13)
ICONS = {
"neu": neu, "oeffnen": oeffnen, "import": lambda d: ablage(d, False), "export": lambda d: ablage(d, True),
"haendler": haendler, "prozent": lambda d: prozent(d, AKZENT), "rechner": rechner, "birne": birne,
"info": lambda d: kreis(d, AKZENT, "i"), "frage": lambda d: kreis(d, AKZENT, "?"),
"fehler": lambda d: kreis(d, ROT, "×"), "warnung": warnung, "app": app,
}
def main():
ZIEL.mkdir(parents=True, exist_ok=True)
for name, zeichne in ICONS.items():
img, d = leinwand()
zeichne(d)
img.resize((20, 20), Image.LANCZOS).save(ZIEL / f"{name}.png")
img.resize((40, 40), Image.LANCZOS).save(ZIEL / f"{name}_gross.png")
if name == "app":
gross = img.resize((256, 256), Image.LANCZOS)
gross.save(ROOT / "assets" / "app.png")
gross.save(ROOT / "assets" / "app.ico", sizes=[(s, s) for s in (16, 24, 32, 48, 64, 128, 256)])
print(f"{len(ICONS)} Symbole nach {ZIEL} geschrieben, assets/app.ico + app.png erneuert")
if __name__ == "__main__":
main()
+1 -1
View File
@@ -1,5 +1,5 @@
"""Provisions-Manager 95 – Provisionsabrechnung für Unterhändler der Handy-Insel Miesbach.""" """Provisions-Manager 95 – Provisionsabrechnung für Unterhändler der Handy-Insel Miesbach."""
__version__ = "1.4.0" __version__ = "1.4.1"
APP_NAME = "Provisions-Manager 95" APP_NAME = "Provisions-Manager 95"
APP_ORG = "Handy-Insel Miesbach" APP_ORG = "Handy-Insel Miesbach"
+8 -8
View File
@@ -12,7 +12,7 @@ from datetime import date
from pathlib import Path from pathlib import Path
from tkinter import filedialog from tkinter import filedialog
from provtool import APP_NAME, config from provtool import config
from provtool import export as exp from provtool import export as exp
from provtool import regeln from provtool import regeln
from provtool.db import EIGEN, UNZUGEORDNET, AbrechnungErledigt, Datenbank from provtool.db import EIGEN, UNZUGEORDNET, AbrechnungErledigt, Datenbank
@@ -79,8 +79,8 @@ class App:
root.report_callback_exception = self._fehler_handler root.report_callback_exception = self._fehler_handler
klassisch = w.DESIGN == "win95" # Win95: eigene Titelleiste; modern: normaler Windows-Rahmen klassisch = w.DESIGN == "win95" # Win95: eigene Titelleiste; modern: normaler Windows-Rahmen
w.KLASSISCH = klassisch w.KLASSISCH = klassisch
self.rahmen = rh.Hauptrahmen(root, APP_NAME, self.icons("app"), self.beenden, klassisch=klassisch) self.rahmen = rh.Hauptrahmen(root, w.APP_NAME, self.icons("app"), self.beenden, klassisch=klassisch)
self.rahmen.set_titel(APP_NAME) self.rahmen.set_titel(w.APP_NAME)
self.inhalt = self.rahmen.inhalt self.inhalt = self.rahmen.inhalt
self._menue() self._menue()
@@ -151,7 +151,7 @@ class App:
hi.add_separator() hi.add_separator()
hi.add_command(label="Einrichtungs-Assistent...", command=self.assistent) hi.add_command(label="Einrichtungs-Assistent...", command=self.assistent)
hi.add_separator() hi.add_separator()
hi.add_command(label=f"Info über {APP_NAME}...", command=lambda: dlg.InfoDialog(self.root).zeigen()) hi.add_command(label=f"Info über {w.APP_NAME}...", command=lambda: dlg.InfoDialog(self.root).zeigen())
def _toolbar(self): def _toolbar(self):
tb = tk.Frame(self.inhalt, bg=w.FACE, bd=0 if w.MODERN else 1, relief="raised") tb = tk.Frame(self.inhalt, bg=w.FACE, bd=0 if w.MODERN else 1, relief="raised")
@@ -277,12 +277,12 @@ class App:
if self.aid and self.db.abrechnung(self.aid): if self.aid and self.db.abrechnung(self.aid):
self.positionen = self.db.positionen(self.aid) self.positionen = self.db.positionen(self.aid)
titel = self.db.abrechnung(self.aid)["titel"] + (" – erledigt" if self.db.erledigt(self.aid) else "") titel = self.db.abrechnung(self.aid)["titel"] + (" – erledigt" if self.db.erledigt(self.aid) else "")
self.rahmen.set_titel(f"{APP_NAME} - [{titel}]") self.rahmen.set_titel(f"{w.APP_NAME} - [{titel}]")
self.status.set("info", f" Abrechnung: {titel}") self.status.set("info", f" Abrechnung: {titel}")
else: else:
self.aid = None self.aid = None
self.positionen = [] self.positionen = []
self.rahmen.set_titel(APP_NAME) self.rahmen.set_titel(w.APP_NAME)
self.status.set("info", " Keine Abrechnung geöffnet – Datei > Neue Abrechnung oder Import") self.status.set("info", " Keine Abrechnung geöffnet – Datei > Neue Abrechnung oder Import")
self._haendlerliste(behalte_auswahl) self._haendlerliste(behalte_auswahl)
self._tabelle() self._tabelle()
@@ -1061,7 +1061,7 @@ class App:
"Rufnummer, Name oder Tarif eingeben – die Liste filtert sofort. Tastenkürzel: Strg+F."), "Rufnummer, Name oder Tarif eingeben – die Liste filtert sofort. Tastenkürzel: Strg+F."),
(self.menueleiste.knoepfe["?"], "Das war's!", (self.menueleiste.knoepfe["?"], "Das war's!",
"Diesen Rundgang, den Einrichtungs-Assistenten und die Tipps finden Sie jederzeit hier im Menü „?“.\n\n" "Diesen Rundgang, den Einrichtungs-Assistenten und die Tipps finden Sie jederzeit hier im Menü „?“.\n\n"
"Viel Erfolg mit dem Provisions-Manager 95!"), f"Viel Erfolg mit dem {w.APP_NAME}!"),
] ]
self._rundgang = ass.Rundgang(self, schritte) self._rundgang = ass.Rundgang(self, schritte)
@@ -1073,7 +1073,7 @@ class App:
text = "".join(traceback.format_exception(exc, val, tb)) text = "".join(traceback.format_exception(exc, val, tb))
try: try:
with (config.app_dir() / "fehler.log").open("a", encoding="utf-8") as f: with (config.app_dir() / "fehler.log").open("a", encoding="utf-8") as f:
f.write(f"--- {date.today().isoformat()} {APP_NAME}\n{text}\n") f.write(f"--- {date.today().isoformat()} {w.APP_NAME}\n{text}\n")
except OSError: except OSError:
pass pass
# Beim/nach dem Beenden keine Meldung mehr zeigen – das Fenster gibt es dann nicht mehr # Beim/nach dem Beenden keine Meldung mehr zeigen – das Fenster gibt es dann nicht mehr
+10 -10
View File
@@ -7,7 +7,6 @@ from collections import Counter, defaultdict
from pathlib import Path from pathlib import Path
from tkinter import filedialog, ttk from tkinter import filedialog, ttk
from provtool import APP_NAME
from provtool.db import CAPS_ANBIETER, CAPS_WERT, Haendler, ist_grossgeschrieben from provtool.db import CAPS_ANBIETER, CAPS_WERT, Haendler, ist_grossgeschrieben
from provtool.gui import win32 from provtool.gui import win32
from provtool.gui import win95 as w from provtool.gui import win95 as w
@@ -33,7 +32,7 @@ class Einrichtungsassistent(w.Dialog):
BREITE, HOEHE = 470, 340 BREITE, HOEHE = 470, 340
def __init__(self, app): def __init__(self, app):
super().__init__(app.root, "Provisions-Manager 95 – Einrichtung") super().__init__(app.root, f"{w.APP_NAME} – Einrichtung")
self.app = app self.app = app
self.dateien: list[str] = [] self.dateien: list[str] = []
self.vorschlaege: dict[str, list[str]] = {"freenet": [], "vodafone": []} self.vorschlaege: dict[str, list[str]] = {"freenet": [], "vodafone": []}
@@ -77,7 +76,7 @@ class Einrichtungsassistent(w.Dialog):
for i, (x, y) in enumerate(((20, 30), (120, 55), (35, 120), (128, 150), (60, 20))): for i, (x, y) in enumerate(((20, 30), (120, 55), (35, 120), (128, 150), (60, 20))):
c.create_rectangle(x, y, x + 2 + i % 2, y + 2 + i % 2, fill=w.WHITE, outline="") c.create_rectangle(x, y, x + 2 + i % 2, y + 2 + i % 2, fill=w.WHITE, outline="")
c.create_image(77, self.HOEHE // 2 - 10, image=self._img) c.create_image(77, self.HOEHE // 2 - 10, image=self._img)
c.create_text(77, self.HOEHE - 38, text="Provisions-\nManager 95", fill=w.WHITE, font=w.FONT_BOLD, c.create_text(77, self.HOEHE - 38, text=w.APP_NAME.replace("-", "-\n", 1), fill=w.WHITE, font=w.FONT_BOLD,
justify="center") justify="center")
def _leeren(self): def _leeren(self):
@@ -100,7 +99,7 @@ class Einrichtungsassistent(w.Dialog):
self.b_zurueck.configure(state="normal" if nr > 0 else "disabled") self.b_zurueck.configure(state="normal" if nr > 0 else "disabled")
self.b_weiter.configure(text="Fertig stellen" if nr == len(self.seiten) - 1 else "Weiter >") self.b_weiter.configure(text="Fertig stellen" if nr == len(self.seiten) - 1 else "Weiter >")
if self.titelleiste: if self.titelleiste:
self.titelleiste.set_titel(f"Provisions-Manager 95 – Einrichtung (Schritt {nr + 1} von {len(self.seiten)})") self.titelleiste.set_titel(f"{w.APP_NAME} – Einrichtung (Schritt {nr + 1} von {len(self.seiten)})")
def _weiter(self): def _weiter(self):
pruefer = getattr(self, f"_pruefe_{self.nr}", None) pruefer = getattr(self, f"_pruefe_{self.nr}", None)
@@ -128,7 +127,7 @@ class Einrichtungsassistent(w.Dialog):
# ---------------------------------------------------------------- Seite 1 # ---------------------------------------------------------------- Seite 1
def _s_willkommen(self): def _s_willkommen(self):
self._ueberschrift(f"Willkommen beim {APP_NAME}!") self._ueberschrift(f"Willkommen beim {w.APP_NAME}!")
self._text("Dieser Assistent richtet das Programm in wenigen Schritten ein:") self._text("Dieser Assistent richtet das Programm in wenigen Schritten ein:")
for punkt in ("Speicherort der Daten festlegen", for punkt in ("Speicherort der Daten festlegen",
"Unterhändler mit ihren Kennungen anlegen", "Unterhändler mit ihren Kennungen anlegen",
@@ -384,7 +383,7 @@ class Einrichtungsassistent(w.Dialog):
def _s_fertig(self): def _s_fertig(self):
self._ueberschrift("Fertig!") self._ueberschrift("Fertig!")
n = len(self.app.db.haendler_liste()) n = len(self.app.db.haendler_liste())
self._text(f"Der {APP_NAME} ist eingerichtet.") self._text(f"Der {w.APP_NAME} ist eingerichtet.")
self._text(f" - {n} Händler angelegt") self._text(f" - {n} Händler angelegt")
if self.v_abrechnung.get(): if self.v_abrechnung.get():
self._text(f" - Abrechnung „{self.v_titel.get().strip()}“" self._text(f" - Abrechnung „{self.v_titel.get().strip()}“"
@@ -582,13 +581,14 @@ class TippDesTages(w.Dialog):
haupt.pack(padx=12, pady=12) haupt.pack(padx=12, pady=12)
box = tk.Frame(haupt, bg=w.WHITE, bd=2, relief="sunken") box = tk.Frame(haupt, bg=w.WHITE, bd=2, relief="sunken")
box.pack(side="left", fill="both") box.pack(side="left", fill="both")
self._bild = tipp_bild(self) # Büroklammer nur im Win95-Design; modern eine schlichte Glühbirne
self.bild_ok = self._bild is not None self._bild = None if w.MODERN else tipp_bild(self)
if self._bild is None: # Ersatz, falls das Bild fehlt self.bild_ok = self._bild is not None or w.MODERN
if self._bild is None:
self._bild = w.make_icon(self, "birne", 3) self._bild = w.make_icon(self, "birne", 3)
tk.Label(box, image=self._bild, bg=w.WHITE).pack(side="left", anchor="n", padx=(12, 4), pady=10) tk.Label(box, image=self._bild, bg=w.WHITE).pack(side="left", anchor="n", padx=(12, 4), pady=10)
# fester Textbereich: der Tipp bricht darin um und kann nicht mehr abgeschnitten werden # fester Textbereich: der Tipp bricht darin um und kann nicht mehr abgeschnitten werden
rechts = tk.Frame(box, bg=w.WHITE, padx=12, pady=10, width=380, height=self._bild.height() + 20) rechts = tk.Frame(box, bg=w.WHITE, padx=12, pady=10, width=380, height=max(self._bild.height(), 170) + 20)
rechts.pack(side="left", fill="both") rechts.pack(side="left", fill="both")
rechts.pack_propagate(False) rechts.pack_propagate(False)
tk.Label(rechts, text="Wussten Sie schon...", bg=w.WHITE, font=(w.FONT_FAMILY, w.FONT_SIZE + 6, "bold"), tk.Label(rechts, text="Wussten Sie schon...", bg=w.WHITE, font=(w.FONT_FAMILY, w.FONT_SIZE + 6, "bold"),
Binary file not shown.

After

Width:  |  Height:  |  Size: 990 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 787 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 550 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 951 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 964 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 876 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 594 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1007 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 827 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 789 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 539 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 811 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 686 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 583 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 742 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

+3 -3
View File
@@ -4,7 +4,7 @@ from __future__ import annotations
import tkinter as tk import tkinter as tk
from tkinter import filedialog, ttk from tkinter import filedialog, ttk
from provtool import APP_NAME, APP_ORG, __version__ from provtool import APP_ORG, __version__
from provtool import regeln from provtool import regeln
from provtool import zeitraum as zr from provtool import zeitraum as zr
from provtool.db import CAPS_ANBIETER, CAPS_WERT, AbrechnungErledigt, Datenbank, Haendler from provtool.db import CAPS_ANBIETER, CAPS_WERT, AbrechnungErledigt, Datenbank, Haendler
@@ -1022,7 +1022,7 @@ class EinstellungenDialog(w.Dialog):
class InfoDialog(w.Dialog): class InfoDialog(w.Dialog):
def __init__(self, master): def __init__(self, master):
super().__init__(master, f"Info über {APP_NAME}") super().__init__(master, f"Info über {w.APP_NAME}")
top = tk.Frame(self, bg=w.FACE) top = tk.Frame(self, bg=w.FACE)
top.pack(padx=14, pady=14) top.pack(padx=14, pady=14)
c = tk.Canvas(top, width=110, height=110, bg=w.TEAL, bd=2, relief="sunken", highlightthickness=0) c = tk.Canvas(top, width=110, height=110, bg=w.TEAL, bd=2, relief="sunken", highlightthickness=0)
@@ -1031,7 +1031,7 @@ class InfoDialog(w.Dialog):
c.create_image(57, 57, image=self._img) c.create_image(57, 57, image=self._img)
rechts = tk.Frame(top, bg=w.FACE) rechts = tk.Frame(top, bg=w.FACE)
rechts.pack(side="left", padx=(14, 0), anchor="n") rechts.pack(side="left", padx=(14, 0), anchor="n")
tk.Label(rechts, text=APP_NAME, font=w.FONT_BIG).pack(anchor="w") tk.Label(rechts, text=w.APP_NAME, font=w.FONT_BIG).pack(anchor="w")
tk.Label(rechts, text=f"Version {__version__}", anchor="w").pack(anchor="w") tk.Label(rechts, text=f"Version {__version__}", anchor="w").pack(anchor="w")
w.trenner(rechts, vertikal=False).pack(fill="x", pady=8) w.trenner(rechts, vertikal=False).pack(fill="x", pady=8)
tk.Label(rechts, text=f"Lizenziert für:\n{APP_ORG}\n\nProvisionsabrechnung für Unterhändler\n" tk.Label(rechts, text=f"Lizenziert für:\n{APP_ORG}\n\nProvisionsabrechnung für Unterhändler\n"
+10 -1
View File
@@ -7,6 +7,7 @@ from __future__ import annotations
import sys import sys
import tkinter as tk import tkinter as tk
from pathlib import Path
from tkinter import ttk from tkinter import ttk
FACE = "#c0c0c0" FACE = "#c0c0c0"
@@ -22,6 +23,7 @@ SEL_BG, SEL_FG = NAVY, WHITE # Auswahl/Markierung
RAND = SHADOW # dünne Rahmenlinien (nur modern) RAND = SHADOW # dünne Rahmenlinien (nur modern)
DESIGN = "win95" DESIGN = "win95"
MODERN = False MODERN = False
APP_NAME = "Provisions-Manager 95" # modern: ohne „95“
_PALETTEN = { _PALETTEN = {
"win95": dict(FACE="#c0c0c0", HILITE="#ffffff", LIGHT="#dfdfdf", SHADOW="#808080", DARK="#000000", "win95": dict(FACE="#c0c0c0", HILITE="#ffffff", LIGHT="#dfdfdf", SHADOW="#808080", DARK="#000000",
@@ -43,9 +45,10 @@ FONT_MONO = ("Courier New" if IS_WIN else "DejaVu Sans Mono", FONT_SIZE + 1)
def design_setzen(name: str) -> None: def design_setzen(name: str) -> None:
"""„modern“ oder „win95“ – setzt Farben und Schriften (Feinschliff der Schrift in apply()).""" """„modern“ oder „win95“ – setzt Farben und Schriften (Feinschliff der Schrift in apply())."""
global DESIGN, MODERN, FONT_FAMILY, FONT_SIZE global DESIGN, MODERN, FONT_FAMILY, FONT_SIZE, APP_NAME
DESIGN = name if name in _PALETTEN else "modern" DESIGN = name if name in _PALETTEN else "modern"
MODERN = DESIGN == "modern" MODERN = DESIGN == "modern"
APP_NAME = "Provisions-Manager" if MODERN else "Provisions-Manager 95"
globals().update(_PALETTEN[DESIGN]) globals().update(_PALETTEN[DESIGN])
FONT_FAMILY = ("Segoe UI" if MODERN else "MS Sans Serif") if IS_WIN else "DejaVu Sans" FONT_FAMILY = ("Segoe UI" if MODERN else "MS Sans Serif") if IS_WIN else "DejaVu Sans"
FONT_SIZE = 9 if (MODERN or not IS_WIN) else 8 FONT_SIZE = 9 if (MODERN or not IS_WIN) else 8
@@ -295,7 +298,13 @@ def _icon_rows(name: str) -> list[str]:
return [r.ljust(16, ".")[:16] for r in rows[:16]] + ["." * 16] * (16 - len(rows)) return [r.ljust(16, ".")[:16] for r in rows[:16]] + ["." * 16] * (16 - len(rows))
MODERNE_ICONS = Path(__file__).resolve().parent / "bilder" / "modern"
def make_icon(master, name: str, scale: int = 1) -> tk.PhotoImage: def make_icon(master, name: str, scale: int = 1) -> tk.PhotoImage:
datei = MODERNE_ICONS / f"{name}{'_gross' if scale > 1 else ''}.png"
if MODERN and datei.exists(): # glatte Symbole aus build/make_moderne_icons.py
return tk.PhotoImage(master=master, file=str(datei))
img = tk.PhotoImage(master=master, width=16 * scale, height=16 * scale) img = tk.PhotoImage(master=master, width=16 * scale, height=16 * scale)
for y, row in enumerate(_icon_rows(name)): for y, row in enumerate(_icon_rows(name)):
for x, ch in enumerate(row): for x, ch in enumerate(row):