scopedvr-map-editor/src/ui/ui_scale.gd

136 lines
4.4 KiB
GDScript

class_name UIScale
extends RefCounted
## Zentrale UI-Skalierung (Karte t_297221b5): EIN Faktor für den ganzen Editor.
##
## Stufen: Klein (1.0) / Mittel (1.25) / Groß (1.5). Der Faktor multipliziert
## alle Layout-Werte beim UI-Bau (Schrift, Zeilen-/Knopfhöhen, Panelbreiten,
## Thumbnail-Größe, Abstände) — bewusst als Faktor-Multiplikation und NICHT als
## stretch/canvas_items, damit (a) die 3D-Map-Ansicht pixelgenau unberührt bleibt,
## (b) nichts doppelt skaliert und (c) die Stufe vom Nutzer gewählt wird statt
## von der Fenstergröße abzuhängen.
##
## Die gewählte Stufe liegt in user://scopedvr_editor.cfg, Abschnitt [ui]
## (Key "groesse"). ConfigFile lädt+speichert die GANZE Datei — der Abschnitt
## [library] (Klapp-Zustand, Karte t_59fc0f21) bleibt dabei erhalten.
##
## Für Tests/Probes kann per Umgebungsvariable SCOPEDVR_UI_CFG eine andere
## Config-Datei erzwungen werden (hermetische Läufe ohne Nutzer-Config).
## Typografie-Ebenen (Karte t_2336c58e/U7 — verbindlich): genau ZWEI Schrift-
## Größen (Body + Klein) plus eine Überschriften-Stufe. KEINE weiteren Größen
## im Code — alles über die drei Helfer unten, skaliert mit der UI-Stufe.
const HEADING_FONT_SIZE := 20 # Überschriften (Panel-/Gruppen-Header, Titel)
const SMALL_FONT_SIZE := 13 # Nebentext (Zähler, Badges, Tile-IDs)
const CFG_PATH := "user://scopedvr_editor.cfg"
const CFG_SECTION := "ui"
const CFG_KEY := "groesse" # "klein" | "mittel" | "gross"
const WIN_SECTION := "fenster" # Fenster-Zustand (maximiert/Größe/Position)
## [key, Anzeige-Name, Faktor]
const STEPS: Array = [
["klein", "Klein", 1.0],
["mittel", "Mittel", 1.25],
["gross", "Groß", 1.5],
]
const BASE_FONT_SIZE := 16 # bisherige feste Schriftgröße (main.gd, Vorher)
static var _factor: float = -1.0 # Cache; < 0 = noch nicht aus der Config gelesen
static func cfg_path() -> String:
var env := OS.get_environment("SCOPEDVR_UI_CFG")
if not env.is_empty():
return env
return CFG_PATH
static func step_count() -> int:
return STEPS.size()
static func step_label(i: int) -> String:
return str(STEPS[clampi(i, 0, STEPS.size() - 1)][1])
static func step_key(i: int) -> String:
return str(STEPS[clampi(i, 0, STEPS.size() - 1)][0])
static func step_index_from_key(key: String) -> int:
for i in STEPS.size():
if str(STEPS[i][0]) == key:
return i
return 0 # unbekannt/leer → Klein (Vorher-Verhalten)
## Aktuelle Stufe aus der Config (ohne Cache).
static func step_index() -> int:
var cfg := ConfigFile.new()
if cfg.load(cfg_path()) != OK:
return 0 # keine Config = Klein (altes Verhalten)
return step_index_from_key(str(cfg.get_value(CFG_SECTION, CFG_KEY, "")))
## Faktor der aktuellen Stufe (cached — UI-Bau ruft das sehr oft).
static func factor() -> float:
if _factor < 0.0:
_factor = float(STEPS[step_index()][2])
return _factor
## Stufe setzen UND sofort in die Config schreiben (Abschnitte wie [library]
## bleiben erhalten — ConfigFile liest/schreibt die ganze Datei).
static func set_step_index(i: int) -> void:
i = clampi(i, 0, STEPS.size() - 1)
var cfg := ConfigFile.new()
cfg.load(cfg_path()) # fehlt die Datei: leer anfangen, Abschnitte bleiben
cfg.set_value(CFG_SECTION, CFG_KEY, str(STEPS[i][0]))
var err := cfg.save(cfg_path())
if err != OK:
push_warning("UIScale: Config nicht schreibbar (%s), Stufe nur für diese Sitzung." % err)
_factor = float(STEPS[i][2])
## Cache verwerfen und neu lesen — simuliert den Neustart (für Tests/Probes).
static func reload() -> void:
_factor = -1.0
factor()
# ------------------------------------------------------- Rechenhelfer (Bau) --
## Ganzzahliges Pixel-Maß (Höhen, Breiten, Abstände, Schriftgrößen).
static func px(v: float) -> int:
return int(round(v * factor()))
## Fließkommamaß (z. B. split_offset).
static func f(v: float) -> float:
return v * factor()
## custom_minimum_size = UIScale.v2(b, h) statt Vector2(b, h).
static func v2(x: float, y: float) -> Vector2:
return Vector2(px(x), px(y))
## Dialog-/Fenstergrößen.
static func v2i(x: float, y: float) -> Vector2i:
return Vector2i(px(x), px(y))
## Standardschriftgröße (Body-Text, bisher fest 16).
static func font_size() -> int:
return px(BASE_FONT_SIZE)
## Überschriften-Größe (Panel-/Gruppen-Header, Titel) — U7-Raster.
static func heading_font_size() -> int:
return px(HEADING_FONT_SIZE)
## Nebentext-Größe (Zähler, Badges, Tile-IDs) — U7-Raster.
static func small_font_size() -> int:
return px(SMALL_FONT_SIZE)