Move config storage next to the install and auto-create it if missing
versapad_combined.DEFAULT_PATH was hardcoded to this one machine's OneDrive
desktop, which made the tool unusable anywhere else. versapad_data.app_dir()
now resolves to the running .exe's own folder when frozen, or the project
directory when run from source, and DEFAULT_PATH hangs off that instead.
load_or_fetch() previously raised when both the file was missing and the
board unreachable, blocking a fresh install with no config and no board
attached. It now falls back to an empty default_combined() in that case, so
the tool is immediately usable either way. desktop_viewer's
_current_profile_view() picks up the same fallback instead of re-implementing
a narrower version of it.
Also drop the hardcoded PROFILE_NAMES dict, which had drifted out of sync
with the profile_names already stored in the combined JSON -- renaming a
profile in Programmiermodus never showed up in the read-only/browser views.
server.py and desktop_viewer.py now read names from the same JSON everywhere.
versapad_data.CONFIG_PATHS (read-only interop with the official C# VersaGUI's
JSON export) is intentionally left on the OneDrive desktop -- nothing in
this codebase writes there, it's not part of this tool's own config.
(cherry picked from commit 5d14bdd826)
This commit is contained in:
parent
8ba524c07b
commit
b4ad7698ed
7 changed files with 147 additions and 57 deletions
|
|
@ -167,8 +167,8 @@ class VersaPadViewer(tk.Tk):
|
|||
self.tabs = tk.Frame(self, bg=BG)
|
||||
self.tabs.pack(fill="x", padx=20, pady=(12, 10))
|
||||
self.tab_buttons = {}
|
||||
for p in sorted(vp.PROFILE_NAMES):
|
||||
btn = tk.Label(self.tabs, text=vp.PROFILE_NAMES[p], bg=CARD_BG, fg=TEXT,
|
||||
for p in range(vp.NUM_PROFILES):
|
||||
btn = tk.Label(self.tabs, text=f"Profil {p}", bg=CARD_BG, fg=TEXT,
|
||||
font=("Segoe UI", 10, "bold"), padx=14, pady=6, cursor="hand2")
|
||||
btn.pack(side="left", padx=(0, 8))
|
||||
btn.bind("<Button-1>", lambda e, prof=p: self.set_profile(prof, manual=True))
|
||||
|
|
@ -242,11 +242,16 @@ class VersaPadViewer(tk.Tk):
|
|||
self._render()
|
||||
|
||||
def _update_tab_labels(self):
|
||||
"""Profilnamen kommen immer aus der kombinierten JSON (nicht mehr
|
||||
hartkodiert) -- im Programmiermodus aus dem In-Memory-State, sonst
|
||||
per schlankem Datei-Read (kein Board-Zugriff, siehe
|
||||
versapad_combined.profile_names())."""
|
||||
if self.editing.get() and self.combined:
|
||||
names = self.combined["profile_names"]
|
||||
else:
|
||||
names = vcomb.read_profile_names()
|
||||
for p, btn in self.tab_buttons.items():
|
||||
if self.editing.get() and self.combined:
|
||||
btn.configure(text=self.combined["profile_names"][p])
|
||||
else:
|
||||
btn.configure(text=vp.PROFILE_NAMES[p])
|
||||
btn.configure(text=names[p])
|
||||
|
||||
def _rename_tab(self, profile):
|
||||
if not self.editing.get() or self.combined is None:
|
||||
|
|
@ -526,16 +531,19 @@ class VersaPadViewer(tk.Tk):
|
|||
Bevorzugt die kombinierte Datei (versapad_config_all.json), falls
|
||||
vorhanden -- so zeigen im Programmiermodus gespeicherte Aenderungen
|
||||
sich auch hier, statt dass die alten Einzel-JSONs weiter durchscheinen.
|
||||
Fehlt sie (z.B. versehentlich geloescht) und ist Live-Sync gerade aus
|
||||
(COM-Port frei), wird sie automatisch per Serial vom Board neu
|
||||
aufgebaut und als neuer Cache gespeichert -- das Board ist die
|
||||
eigentliche Quelle der Wahrheit, kein Datei-Handling von Hand mehr
|
||||
noetig. Nur wenn das nicht klappt (Board nicht erreichbar, Live-Sync
|
||||
haelt den Port), weicht es zuletzt auf die klassischen
|
||||
versapad_config{1,2,3}.json aus."""
|
||||
if os.path.exists(vcomb.DEFAULT_PATH):
|
||||
Fehlt sie (z.B. versehentlich geloescht, oder frische Installation
|
||||
ganz ohne Config) und ist Live-Sync gerade aus (COM-Port frei), wird
|
||||
sie automatisch angelegt -- per Serial vom Board, oder als leere
|
||||
Default-Config, wenn auch kein Board erreichbar ist (siehe
|
||||
versapad_combined.load_or_fetch()) -- das Tool ist damit auch ganz
|
||||
ohne vorhandene Config sofort benutzbar, kein Datei-Handling von
|
||||
Hand mehr noetig. Nur wenn Live-Sync gerade an ist (haelt den
|
||||
COM-Port) und noch keine Datei existiert, weicht es zuletzt auf die
|
||||
klassischen versapad_config{1,2,3}.json (Export der offiziellen
|
||||
VersaGUI) aus."""
|
||||
if os.path.exists(vcomb.DEFAULT_PATH) or not self.live_sync.get():
|
||||
try:
|
||||
data = vcomb.load_file(vcomb.DEFAULT_PATH)
|
||||
data = vcomb.load_or_fetch(link=self._link)
|
||||
raw = data["profiles"][self.profile]
|
||||
cfg = vp.annotate_profile({
|
||||
"buttons": [dict(b) for b in raw["buttons"]],
|
||||
|
|
@ -544,18 +552,6 @@ class VersaPadViewer(tk.Tk):
|
|||
return cfg, f"Quelle: {vcomb.DEFAULT_PATH}"
|
||||
except (KeyError, IndexError, ValueError):
|
||||
pass # kaputte/unvollstaendige Datei -- weiter unten ausweichen
|
||||
elif not self.live_sync.get():
|
||||
try:
|
||||
data = vcomb.fetch_from_board(link=self._link)
|
||||
vcomb.save_file(data, vcomb.DEFAULT_PATH)
|
||||
raw = data["profiles"][self.profile]
|
||||
cfg = vp.annotate_profile({
|
||||
"buttons": [dict(b) for b in raw["buttons"]],
|
||||
"encoders": [dict(e) for e in raw["encoders"]],
|
||||
})
|
||||
return cfg, "Quelle: Board (neu vom Geraet geladen)"
|
||||
except RuntimeError:
|
||||
pass # Board nicht erreichbar -- weiter unten ausweichen
|
||||
try:
|
||||
return vp.load_profile(self.profile), f"Quelle: {vp.CONFIG_PATHS[self.profile]}"
|
||||
except FileNotFoundError as e:
|
||||
|
|
@ -564,6 +560,7 @@ class VersaPadViewer(tk.Tk):
|
|||
raise FileNotFoundError(f"{e}{hint}") from e
|
||||
|
||||
def _render(self):
|
||||
self._update_tab_labels()
|
||||
for w in self.grid_frame.winfo_children():
|
||||
w.destroy()
|
||||
for w in self.enc_frame.winfo_children():
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue