U7 (t_2336c58e): Feinschliff — Theme konsequent (Disabled/Fokus/Hover, LineEdit, Tab-Hover, Splitter-Anfassen, Scrollbars, Farb-Token warning/badge_outline), Abstands-Raster 4/8 über UIScale, Typografie-Raster (heading/body/small via ui_scale.gd), Tooltips für alle Knöpfe inkl. Dialoge, Leerzustand in der Bibliothek, Fenstertitel mit „(ungespeichert)“. Neue Suite tests/test_theme.gd (35 Checks). Keine Funktionsänderung.

This commit is contained in:
Hermes (scopedvr-dev) 2026-10-20 12:08:10 +00:00
parent 0e1406a63e
commit f6c754115a
18 changed files with 574 additions and 68 deletions

View file

@ -287,7 +287,7 @@ func _swatch(c: Color, name: String) -> Button:
sb.set_corner_radius_all(6)
btn.add_theme_stylebox_override("normal", sb)
var sb_hover: StyleBoxFlat = sb.duplicate()
sb_hover.bg_color = Color(minf(c.r + 0.08, 1.0), minf(c.g + 0.08, 1.0), minf(c.b + 0.08, 1.0))
sb_hover.bg_color = c.lightened(0.08) # U7: Aufhellung statt Manuell-Mathe
btn.add_theme_stylebox_override("hover", sb_hover)
btn.add_theme_stylebox_override("pressed", sb_hover)
btn.add_theme_stylebox_override("focus", StyleBoxEmpty.new())

View file

@ -485,8 +485,9 @@ func _build_dialogs_and_overlays() -> void:
# Dialog — der Editor bleibt bedienbar, das Panel liegt nur obenauf.
help_overlay = PanelContainer.new()
var overlay_style := StyleBoxFlat.new()
overlay_style.bg_color = Color(0.09, 0.11, 0.13, 0.97) # Slate, wie Statuszeile
overlay_style.border_color = Color(0.35, 0.55, 0.7)
# U7: Farben über das Theme (Editor/colors/help_bg, help_border).
overlay_style.bg_color = get_theme_color("help_bg", "Editor")
overlay_style.border_color = get_theme_color("help_border", "Editor")
overlay_style.set_border_width_all(2)
overlay_style.set_corner_radius_all(8)
overlay_style.set_content_margin_all(UIScale.px(14))
@ -505,8 +506,8 @@ func _build_dialogs_and_overlays() -> void:
help_overlay.add_child(overlay_box)
help_overlay_title = Label.new()
help_overlay_title.text = "Kurzhilfe — alle Tasten auf einen Blick (H oder Esc schließt)"
help_overlay_title.add_theme_font_size_override("font_size", UIScale.f(20))
help_overlay_title.add_theme_color_override("font_color", Color(0.55, 0.8, 1.0))
help_overlay_title.add_theme_font_size_override("font_size", UIScale.heading_font_size())
help_overlay_title.add_theme_color_override("font_color", get_theme_color("accent", "Editor"))
overlay_box.add_child(help_overlay_title)
help_overlay_text = RichTextLabel.new()
help_overlay_text.bbcode_enabled = true
@ -591,7 +592,8 @@ func _build_center_viewport() -> SubViewportContainer:
help_label.offset_left = UIScale.px(12)
help_label.offset_bottom = UIScale.px(-8)
help_label.offset_top = UIScale.px(-46)
help_label.modulate = Color(1, 1, 1, 0.65)
# U7: Hinweis-Farbe über Theme (Editor/colors/muted) statt modulate.
help_label.add_theme_color_override("font_color", get_theme_color("muted", "Editor"))
# Karte t_297221b5: OHNE Umbruch würde die Mindestbreite des langen Texts
# bei Stufe „Groß“ die 3D-Ansicht breiter zwingen als das Fenster ist —
# die rechte Spalte rutschte aus dem Bildschirm. Mit Umbruch bleibt die
@ -632,8 +634,9 @@ func _rubberband_clear() -> void:
func _draw_rubberband() -> void:
if rubber_rect.size.x <= 0.0 or rubber_rect.size.y <= 0.0:
return
rubber_overlay.draw_rect(rubber_rect, Color(0.45, 0.8, 1.0, 0.16), true)
rubber_overlay.draw_rect(rubber_rect, Color(0.45, 0.8, 1.0, 0.9), false, 2.0)
# U7: Rubberband-Farben über das Theme (Editor/colors/rubber_fill/_line).
rubber_overlay.draw_rect(rubber_rect, get_theme_color("rubber_fill", "Editor"), true)
rubber_overlay.draw_rect(rubber_rect, get_theme_color("rubber_line", "Editor"), false, 2.0)
# ------------------------------------------------------------ Map-Aktionen --
func _start_with_new_map() -> void:
@ -854,8 +857,9 @@ func _replace_doc_in_place(result: Dictionary) -> void:
func _update_banner_build(parent: Container) -> void:
update_banner = PanelContainer.new()
var style := StyleBoxFlat.new()
style.bg_color = Color(0.36, 0.25, 0.06, 0.97) # gedämpftes Bernstein
style.border_color = Color(0.95, 0.72, 0.15)
# U7: Banner-Farben über das Theme (Editor/colors/update_bg/_border).
style.bg_color = get_theme_color("update_bg", "Editor")
style.border_color = get_theme_color("update_border", "Editor")
style.set_border_width_all(2)
style.set_content_margin_all(UIScale.px(8))
style.set_corner_radius_all(6)
@ -864,7 +868,7 @@ func _update_banner_build(parent: Container) -> void:
h.add_theme_constant_override("separation", UIScale.px(14))
update_banner.add_child(h)
update_label = Label.new()
update_label.add_theme_font_size_override("font_size", UIScale.f(17))
update_label.add_theme_font_size_override("font_size", UIScale.font_size())
h.add_child(update_label)
var spacer := Control.new()
spacer.size_flags_horizontal = Control.SIZE_EXPAND_FILL
@ -2079,15 +2083,19 @@ func _refresh_file_label() -> void:
# Karte t_297221b5: bei egalisiertem Label (große Stufe, schmales Fenster)
# steht der volle Name im Tooltip.
file_label.tooltip_text = file_label.text
get_window().title = "%s — %s" % [APP_TITLE, map_name]
# U7 (Karte t_2336c58e): ungespeicherte Änderungen auch im FENSTERTITEL —
# so sieht man sie selbst dann, wenn die Datei-Leiste egalisiert ist.
get_window().title = "%s — %s%s" % [APP_TITLE, map_name,
" (ungespeichert)" if dirty else ""]
func _set_status(text: String, is_error := false) -> void:
if status_label == null or not is_instance_valid(status_label):
return # UI wurde gerade neu aufgebaut (UI-Größe) — nichts anfassen
status_label.text = text
# U7: Statusfarben über das Theme (Editor/colors/status_error/_ok).
status_label.add_theme_color_override("font_color",
Color(1.0, 0.6, 0.5) if is_error else Color(0.75, 0.95, 0.75))
get_theme_color("status_error" if is_error else "status_ok", "Editor"))
func _fmt_int(value: int) -> String:

View file

@ -39,6 +39,8 @@ func _init() -> void:
size_option.add_item(label)
size_option.select(1) # Mittel als Default
size_option.custom_minimum_size = UIScale.v2(0, 40)
# U7: Klartext-Tooltips (Karte t_2336c58e).
size_option.tooltip_text = "Kantenlänge des Geländes — größer = mehr Platz zum Bauen"
vbox.add_child(size_option)
vbox.add_child(_make_label("Welches Wetter soll die Map haben?"))
@ -46,6 +48,7 @@ func _init() -> void:
for label in _weather_labels:
weather_option.add_item(label)
weather_option.custom_minimum_size = UIScale.v2(0, 40)
weather_option.tooltip_text = "Licht und Stimmung der Karte (Tag/Abend/Regen/Nacht)"
vbox.add_child(weather_option)
var hint := _make_label("Die Map startet leer mit 4 Spawn-Punkten pro Team\n(Blau im Westen, Rot im Osten) — beides lässt sich später ändern.")

View file

@ -44,6 +44,7 @@ var _recent_tiles: Dictionary = {} # id → Button (Zuletzt-Ansicht, frisch g
var _recent_ids: Array = [] # Reihenfolge: neueste zuerst
var selected_oid: String = "" # per Klick gewähltes Objekt
var _id_font_normal: int = 0 # ID-Schriftgröße (skaliert), Normalzustand
var _empty_hint: Label # Leerzustand (U7): kein Treffer / leerer Bereich
static func spec() -> Dictionary:
@ -75,7 +76,7 @@ func build() -> void:
# „Alle auf" / „Alle zu" (t_59fc0f21): Klapp-Zustand aller Gruppen auf einmal.
var group_btns := HBoxContainer.new()
group_btns.add_theme_constant_override("separation", UIScale.px(6))
group_btns.add_theme_constant_override("separation", UIScale.px(8)) # U7-Raster
library_open_all_btn = Button.new()
library_open_all_btn.text = "Alle auf"
library_open_all_btn.size_flags_horizontal = Control.SIZE_EXPAND_FILL
@ -93,8 +94,9 @@ func build() -> void:
# Zähler „N von M sichtbar" (U4): M = Objekte im aktiven Bereich, N = davon
# durch Suche/Kategorie sichtbar.
library_counter = Label.new()
library_counter.add_theme_font_size_override("font_size", UIScale.f(11))
library_counter.modulate = Color(1, 1, 1, 0.7)
# U7: Nebentext-Größe + Theme-Farbe (Editor/colors/field).
library_counter.add_theme_font_size_override("font_size", UIScale.small_font_size())
library_counter.add_theme_color_override("font_color", theme_color("field"))
library_counter.tooltip_text = "Sichtbare Kacheln im aktiven Bereich"
add_child(library_counter)
@ -107,6 +109,14 @@ func build() -> void:
library_box.size_flags_horizontal = Control.SIZE_EXPAND_FILL
library_box.add_theme_constant_override("separation", UIScale.px(4))
scroll.add_child(library_box)
# Leerzustand (U7, „fertig aussehen"): freundlicher Klartext statt
# stummer leerer Fläche — Suchbegriff ohne Treffer oder leerer Bereich.
_empty_hint = Label.new()
_empty_hint.text = "Nichts gefunden — anderen Suchbegriff oder „Alle“ versuchen."
_empty_hint.autowrap_mode = TextServer.AUTOWRAP_WORD_SMART
_empty_hint.add_theme_color_override("font_color", theme_color("muted"))
_empty_hint.visible = false
scroll.add_child(_empty_hint)
_recent_box = VBoxContainer.new()
_recent_box.visible = false
_recent_box.add_theme_constant_override("separation", UIScale.px(4))
@ -230,7 +240,7 @@ func _fill_library() -> void:
header.alignment = HORIZONTAL_ALIGNMENT_LEFT
header.custom_minimum_size = UIScale.v2(0, 34)
header.tooltip_text = "Gruppe „%s“ auf-/zuklappen" % g_label
header.add_theme_font_size_override("font_size", UIScale.f(18))
header.add_theme_font_size_override("font_size", UIScale.heading_font_size())
header.add_theme_font_override("font", _library_header_font())
library_box.add_child(header)
var group_box := VBoxContainer.new()
@ -239,8 +249,8 @@ func _fill_library() -> void:
var grid := GridContainer.new()
grid.columns = 2
grid.size_flags_horizontal = Control.SIZE_EXPAND_FILL
grid.add_theme_constant_override("h_separation", UIScale.px(6))
grid.add_theme_constant_override("v_separation", UIScale.px(6))
grid.add_theme_constant_override("h_separation", UIScale.px(8)) # U7-Raster
grid.add_theme_constant_override("v_separation", UIScale.px(8)) # U7-Raster
group_box.add_child(grid)
library_box.add_child(group_box)
header.toggled.connect(_on_library_group_toggled.bind(g_key, g_label, g_ids.size(), header, group_box))
@ -424,6 +434,9 @@ func _apply_library_filter(query: String) -> void:
visible_count += 1
if library_counter != null:
library_counter.text = "%d von %d sichtbar" % [visible_count, scope]
# Leerzustand (U7): 0 Treffer → Klartext-Hinweis zeigen statt stummer Fläche.
if _empty_hint != null:
_empty_hint.visible = visible_count == 0
func _library_oid_matches(oid: String, q: String) -> bool:
@ -480,7 +493,7 @@ func _build_tile(oid: String) -> Button:
var tile := VBoxContainer.new()
tile.mouse_filter = Control.MOUSE_FILTER_IGNORE
tile.set_anchors_preset(Control.PRESET_FULL_RECT)
tile.add_theme_constant_override("separation", UIScale.px(2))
tile.add_theme_constant_override("separation", UIScale.px(4)) # U7-Raster
btn.add_child(tile)
# Vorschaubild: bleibt DIREKTES Kind der Kachel-VBox (test_library_
# browser_ui sucht es dort) mit gepinnter Min-Größe (test_ui_scale
@ -498,9 +511,10 @@ func _build_tile(oid: String) -> Button:
tile.add_child(tr)
var id_lbl := Label.new()
id_lbl.text = oid
_id_font_normal = UIScale.f(9)
# U7: Tile-ID als Nebentext-Größe, Farbe über Theme (Editor/colors/title).
_id_font_normal = UIScale.small_font_size()
id_lbl.add_theme_font_size_override("font_size", _id_font_normal)
id_lbl.modulate = Color(1, 1, 1, 0.6)
id_lbl.add_theme_color_override("font_color", theme_color("title"))
id_lbl.horizontal_alignment = HORIZONTAL_ALIGNMENT_CENTER
id_lbl.clip_text = true
id_lbl.text_overrun_behavior = TextServer.OVERRUN_TRIM_ELLIPSIS
@ -509,7 +523,7 @@ func _build_tile(oid: String) -> Button:
tile.add_child(id_lbl)
var lbl := Label.new()
lbl.text = name_txt
lbl.add_theme_font_size_override("font_size", UIScale.f(11))
lbl.add_theme_font_size_override("font_size", UIScale.small_font_size())
lbl.horizontal_alignment = HORIZONTAL_ALIGNMENT_CENTER
lbl.clip_text = true
lbl.text_overrun_behavior = TextServer.OVERRUN_TRIM_ELLIPSIS
@ -518,16 +532,19 @@ func _build_tile(oid: String) -> Button:
if missing:
# Klar sichtbar markieren (U4): Bild abgedunkelt + Warn-Badge
# als Overlay am unteren Bildrand (immer innerhalb der Kachel).
tr.modulate = Color(1, 1, 1, 0.45)
# U7: Abdunkeln nur über Alpha (Farbe bleibt weiß), Badge-Farbe
# über Theme (Editor/colors/warning + badge_outline), Nebentext-
# Größe statt Mikroschrift (U7-Raster: zwei Größen + Überschrift).
tr.modulate.a = 0.45
tr.clip_contents = true
var warn := Label.new()
warn.text = "Modell fehlt"
warn.set_anchors_preset(Control.PRESET_BOTTOM_WIDE)
warn.offset_top = -UIScale.px(13)
warn.offset_top = -UIScale.px(18)
warn.offset_bottom = -UIScale.px(1)
warn.add_theme_font_size_override("font_size", UIScale.f(9))
warn.add_theme_color_override("font_color", Color(1, 0.62, 0.3))
warn.add_theme_color_override("font_outline_color", Color(0, 0, 0))
warn.add_theme_font_size_override("font_size", UIScale.small_font_size())
warn.add_theme_color_override("font_color", theme_color("warning"))
warn.add_theme_color_override("font_outline_color", theme_color("badge_outline"))
warn.add_theme_constant_override("outline_size", UIScale.px(3))
warn.horizontal_alignment = HORIZONTAL_ALIGNMENT_CENTER
warn.mouse_filter = Control.MOUSE_FILTER_IGNORE
@ -555,7 +572,9 @@ func _set_tile_hover(oid: String, on: bool) -> void:
var id_lbl := _find_id_label(btn)
if id_lbl == null:
return
id_lbl.add_theme_font_size_override("font_size", UIScale.f(14) if on else _id_font_normal)
# U7-Raster: Hover-Stufe ist die Body-Schrift (klein → body), kein Wert ins Freie.
id_lbl.add_theme_font_size_override("font_size",
UIScale.font_size() if on else _id_font_normal)
func _tile_button(oid: String) -> Button:
@ -622,11 +641,12 @@ func _apply_tile_selection() -> void:
for other_oid in library_buttons:
var btn := library_buttons[other_oid] as Button
btn.button_pressed = str(other_oid) == selected_oid
btn.modulate = Color(1, 1, 1) if str(other_oid) == selected_oid else Color(1, 1, 1, 0.85)
# U7: Auswahl-Markierung nur über Alpha (Farbe bleibt weiß).
btn.modulate.a = 1.0 if str(other_oid) == selected_oid else 0.85
for recent_oid in _recent_tiles:
var rbtn := _recent_tiles[recent_oid] as Button
rbtn.button_pressed = str(recent_oid) == selected_oid
rbtn.modulate = Color(1, 1, 1) if str(recent_oid) == selected_oid else Color(1, 1, 1, 0.85)
rbtn.modulate.a = 1.0 if str(recent_oid) == selected_oid else 0.85
## Der Bibliotheks-Button des aktiven Platzier-Objekts leuchtet auf
@ -682,14 +702,14 @@ func _fill_recent_box() -> void:
_recent_tiles.clear()
var head := Label.new()
head.text = "Zuletzt benutzt"
head.add_theme_font_size_override("font_size", UIScale.f(18))
head.add_theme_font_size_override("font_size", UIScale.heading_font_size())
head.add_theme_font_override("font", _library_header_font())
_recent_box.add_child(head)
_recent_grid = GridContainer.new()
_recent_grid.columns = 2
_recent_grid.size_flags_horizontal = Control.SIZE_EXPAND_FILL
_recent_grid.add_theme_constant_override("h_separation", UIScale.px(6))
_recent_grid.add_theme_constant_override("v_separation", UIScale.px(6))
_recent_grid.add_theme_constant_override("h_separation", UIScale.px(8)) # U7-Raster
_recent_grid.add_theme_constant_override("v_separation", UIScale.px(8)) # U7-Raster
_recent_box.add_child(_recent_grid)
var lib: Dictionary = main.manifest.get("objects", {})
for oid in _recent_ids:
@ -700,4 +720,4 @@ func _fill_recent_box() -> void:
_recent_tiles[str(oid)] = btn
if str(oid) == selected_oid:
btn.button_pressed = true
btn.modulate = Color(1, 1, 1)
btn.modulate.a = 1.0

View file

@ -45,13 +45,13 @@ func build() -> void:
add_child(spawn_edit_btn)
spawn_panel = VBoxContainer.new()
spawn_panel.add_theme_constant_override("separation", UIScale.px(6))
spawn_panel.add_theme_constant_override("separation", UIScale.px(8)) # U7-Raster
spawn_panel.visible = false
add_child(spawn_panel)
spawn_panel.add_child(_field_label("Team:"))
var team_row := HBoxContainer.new()
team_row.add_theme_constant_override("separation", UIScale.px(6))
team_row.add_theme_constant_override("separation", UIScale.px(8)) # U7-Raster
spawn_panel.add_child(team_row)
var team_group := ButtonGroup.new()
spawn_team_blue = _spawn_team_button("🔵 Team Blau", team_group, 0)
@ -93,6 +93,8 @@ func _spawn_team_button(text: String, group: ButtonGroup, team: int) -> Button:
btn.toggle_mode = true
btn.button_group = group
btn.custom_minimum_size = UIScale.v2(0, 40)
# U7: Werkzeugname im Tooltip (Team, in das neue Zonen gemalt werden).
btn.tooltip_text = "Zonen für %s malen" % ("Team Blau" if team == 0 else "Team Rot")
btn.pressed.connect(_on_spawn_team_changed.bind(team))
return btn

View file

@ -16,7 +16,8 @@ var main # src/ui/main.gd (script-erweitert → untypisiert)
func setup(p_main) -> void:
main = p_main
add_theme_constant_override("separation", 8)
# U7-Abstands-Raster (4/8 px, über ui_scale skaliert): Panel-Grundabstand.
add_theme_constant_override("separation", UIScale.px(8))
## Titel der Sektions-Überschrift (Registry-Titel als Default).
@ -24,20 +25,29 @@ func panel_title() -> String:
return "Panel"
# --- Farb-Zugriff NUR über das Theme (Karte t_2336c58e/U7) ------------------
## Farben kommen ausschließlich aus theme/editor_theme.tres (Abschnitt
## Editor/colors/…) — keine Farbwerte mehr im Panel-Code. Der Wert liest
## sich vom angeschlossenen Theme-Baum (main hängt theme auf das Fenster).
func theme_color(cname: String) -> Color:
return get_theme_color(cname, "Editor")
# --- Gemeinsame Bau-Helfer (aus main.gd übernommen, Logik identisch) --------
func _header_label(text: String) -> Label:
var label := Label.new()
label.text = text
label.add_theme_font_size_override("font_size", UIScale.f(19))
label.add_theme_color_override("font_color", Color(0.55, 0.8, 1.0))
label.add_theme_font_size_override("font_size", UIScale.heading_font_size())
label.add_theme_color_override("font_color", theme_color("accent"))
return label
func _field_label(text: String) -> Label:
var label := Label.new()
label.text = text
label.modulate = Color(1, 1, 1, 0.7)
label.add_theme_color_override("font_color", theme_color("field"))
return label
@ -45,7 +55,7 @@ func _muted_label(text: String) -> Label:
var label := Label.new()
label.text = text
label.autowrap_mode = TextServer.AUTOWRAP_WORD_SMART
label.modulate = Color(1, 1, 1, 0.55)
label.add_theme_color_override("font_color", theme_color("muted"))
return label

View file

@ -49,6 +49,8 @@ func build() -> void:
add_child(_field_label("Wetter"))
prop_weather = OptionButton.new()
# U7: Klartext-Tooltip am Wetter-Auswahlfeld.
prop_weather.tooltip_text = "Licht und Stimmung der Karte (Tag/Abend/Regen/Nacht)"
prop_weather.add_item("Mittag (sonnig, klar)")
prop_weather.add_item("Abend (warmes Licht)")
prop_weather.add_item("Regen (grau, kühl)")

View file

@ -24,7 +24,9 @@ func build() -> void:
# Karte 3/3 (t_11b5c25b): PERMANENTE Werkzeug-Anzeige — Sly sieht immer,
# in welchem Werkzeug er ist, plus Hint für den Flugmodus (Umschalt+F).
tool_label = Label.new()
tool_label.modulate = Color(0.55, 0.8, 1.0)
# U7: Werkzeug-Farbe über Theme (Editor/colors/accent).
tool_label.add_theme_color_override("font_color",
get_theme_color("accent", "Editor"))
# Karte t_297221b5: Statuszeilen-Labels egalisiert (min-size-Druck bei 1.5×)
tool_label.clip_text = true
tool_label.text_overrun_behavior = TextServer.OVERRUN_TRIM_ELLIPSIS
@ -33,20 +35,26 @@ func build() -> void:
# Symmetrie-Anzeige (Karte t_f5935023, M1): Sly sieht in der Statuszeile
# immer, ob/wie gespiegelt wird (Standard: Punkt).
sym_label = Label.new()
sym_label.modulate = Color(0.55, 0.8, 1.0)
# U7: Symmetrie-Farbe über Theme (Editor/colors/accent).
sym_label.add_theme_color_override("font_color",
get_theme_color("accent", "Editor"))
sym_label.clip_text = true
sym_label.text_overrun_behavior = TextServer.OVERRUN_TRIM_ELLIPSIS
add_child(sym_label)
stats_objects = Label.new()
stats_objects.modulate = Color(1, 1, 1, 0.75)
# U7: Nebentext-Farbe über Theme (Editor/colors/field).
stats_objects.add_theme_color_override("font_color",
get_theme_color("field", "Editor"))
stats_objects.clip_text = true
stats_objects.text_overrun_behavior = TextServer.OVERRUN_TRIM_ELLIPSIS
add_child(stats_objects)
# Terrain-Anteil + Editor-FPS (Perf-Zähler, Karte t_9aba04f1)
stats_terrain = Label.new()
stats_terrain.modulate = Color(1, 1, 1, 0.75)
# U7: Nebentext-Farbe über Theme (Editor/colors/field).
stats_terrain.add_theme_color_override("font_color",
get_theme_color("field", "Editor"))
stats_terrain.clip_text = true
stats_terrain.text_overrun_behavior = TextServer.OVERRUN_TRIM_ELLIPSIS
add_child(stats_terrain)

View file

@ -51,6 +51,8 @@ func build() -> void:
add_child(half_label)
half_option = OptionButton.new()
half_option.custom_minimum_size = UIScale.v2(0, 36)
# U7: Klartext-Tooltip — welche Seite als Vorlage dient.
half_option.tooltip_text = "Welche Hälfte die Vorlage ist (die andere wird angepasst)"
half_option.item_selected.connect(_on_half_selected)
add_child(half_option)
_refresh_half_option()
@ -208,7 +210,8 @@ func _apply(quelle_hoch: bool) -> void:
main.call("_after_structure_change")
var report := str(res["report"])
report_label.text = report
report_label.modulate = Color(0.55, 0.9, 0.55)
# U7: Bericht-Farbe über Theme (Editor/colors/status_ok).
report_label.add_theme_color_override("font_color", theme_color("status_ok"))
main.call("_set_status", report.split(".")[0] + ".")
@ -223,11 +226,15 @@ func _on_check_pressed() -> void:
var rep := SymmetryOps.check(main.doc, mode)
var text := str(rep["text"])
report_label.text = text
report_label.modulate = Color(0.55, 0.9, 0.55) if bool(rep["ok"]) else Color(1.0, 0.75, 0.35)
# U7: Bericht-Farben über Theme (Editor/colors/status_ok / warning).
report_label.add_theme_color_override("font_color",
theme_color("status_ok") if bool(rep["ok"]) else theme_color("warning"))
main.call("_set_status", text)
func _say(text: String, is_error := false) -> void:
report_label.text = text
report_label.modulate = Color(1.0, 0.75, 0.35) if is_error else Color(0.55, 0.9, 0.55)
# U7: Bericht-Farben über Theme (Editor/colors/warning / status_ok).
report_label.add_theme_color_override("font_color",
theme_color("warning") if is_error else theme_color("status_ok"))
main.call("_set_status", text, is_error)

View file

@ -41,19 +41,23 @@ func build() -> void:
add_child(terrain_edit_btn)
terrain_panel = VBoxContainer.new()
terrain_panel.add_theme_constant_override("separation", UIScale.px(6))
terrain_panel.add_theme_constant_override("separation", UIScale.px(8)) # U7-Raster
terrain_panel.visible = false
add_child(terrain_panel)
terrain_panel.add_child(_field_label("Pinsel-Werkzeug:"))
var mode_row := HBoxContainer.new()
mode_row.add_theme_constant_override("separation", UIScale.px(6))
mode_row.add_theme_constant_override("separation", UIScale.px(8)) # U7-Raster
terrain_panel.add_child(mode_row)
var mode_group := ButtonGroup.new()
terrain_mode_raise = _terrain_mode_button("Heben ⬆", mode_group)
terrain_mode_lower = _terrain_mode_button("Senken ⬇", mode_group)
terrain_mode_smooth = _terrain_mode_button("Glätten ≈", mode_group)
terrain_mode_paint = _terrain_mode_button("Malen 🖌", mode_group)
terrain_mode_raise = _terrain_mode_button("Heben ⬆", mode_group,
"Pinsel-Modus Heben: Boden unter dem Pinsel anheben (Taste 1)")
terrain_mode_lower = _terrain_mode_button("Senken ⬇", mode_group,
"Pinsel-Modus Senken: Boden unter dem Pinsel absenken (Taste 2)")
terrain_mode_smooth = _terrain_mode_button("Glätten ≈", mode_group,
"Pinsel-Modus Glätten: Höhenunterschiede verrutschen (Taste 3)")
terrain_mode_paint = _terrain_mode_button("Malen 🖌", mode_group,
"Pinsel-Modus Malen: Material auf den Boden malen (Taste 4)")
terrain_mode_raise.button_pressed = true
terrain_mode_raise.toggled.connect(_on_terrain_mode_changed)
terrain_mode_lower.toggled.connect(_on_terrain_mode_changed)
@ -71,7 +75,7 @@ func build() -> void:
terrain_panel.add_child(terrain_palette)
terrain_palette.add_child(_field_label("Material:"))
var mat_row := HBoxContainer.new()
mat_row.add_theme_constant_override("separation", UIScale.px(6))
mat_row.add_theme_constant_override("separation", UIScale.px(8)) # U7-Raster
terrain_palette.add_child(mat_row)
var mat_group := ButtonGroup.new()
var mat_labels := ["🌿 Gras", "🏖 Sand", "🪨 Fels"]
@ -91,7 +95,7 @@ func build() -> void:
# Pinselgrößen-Presets (Karte t_603ec1a8): drei große Buttons + freier Slider.
terrain_panel.add_child(_field_label("Pinselgröße:"))
var size_row := HBoxContainer.new()
size_row.add_theme_constant_override("separation", UIScale.px(6))
size_row.add_theme_constant_override("separation", UIScale.px(8)) # U7-Raster
terrain_panel.add_child(size_row)
var size_group := ButtonGroup.new()
terrain_size_btn_small = _terrain_size_button("Klein\n(4 m)", size_group, 4.0)
@ -142,15 +146,15 @@ func build() -> void:
add_child(build_edit_btn)
build_panel = VBoxContainer.new()
build_panel.add_theme_constant_override("separation", UIScale.px(6))
build_panel.add_theme_constant_override("separation", UIScale.px(8)) # U7-Raster
build_panel.visible = false
add_child(build_panel)
build_panel.add_child(_field_label("Bauteil:"))
var build_grid := GridContainer.new()
build_grid.columns = 2
build_grid.add_theme_constant_override("h_separation", UIScale.px(6))
build_grid.add_theme_constant_override("v_separation", UIScale.px(6))
build_grid.add_theme_constant_override("h_separation", UIScale.px(8)) # U7-Raster
build_grid.add_theme_constant_override("v_separation", UIScale.px(8)) # U7-Raster
build_panel.add_child(build_grid)
var build_group := ButtonGroup.new()
for kind_id in BuildOps.KINDS.keys():
@ -190,12 +194,13 @@ func _on_terrain_btn_pressed() -> void:
main.call("_set_tool_mode", "objects")
func _terrain_mode_button(text: String, group: ButtonGroup) -> Button:
func _terrain_mode_button(text: String, group: ButtonGroup, hinweis: String) -> Button:
var btn := Button.new()
btn.text = text
btn.toggle_mode = true
btn.button_group = group
btn.custom_minimum_size = UIScale.v2(0, 40)
btn.tooltip_text = hinweis # U7: Werkzeugname + Taste im Tooltip
return btn

View file

@ -41,12 +41,14 @@ static func spec() -> Dictionary:
func build() -> void:
add_theme_constant_override("separation", UIScale.px(10))
add_theme_constant_override("separation", UIScale.px(8)) # U7-Raster (4/8)
var file_menu := MenuButton.new()
file_menu.text = "Datei"
file_menu.flat = false
file_menu.custom_minimum_size = UIScale.v2(90, 40)
# U7: Klartext-Tooltip am Datei-Menü (alle Map-Aktionen an einem Ort).
file_menu.tooltip_text = "Map-Aktionen: neu, öffnen, speichern, testen, Updates"
var popup := file_menu.get_popup()
popup.add_item("Neue Map…", 0)
popup.add_item("Öffnen…", 1)
@ -156,7 +158,7 @@ func build() -> void:
title_label = Label.new()
title_label.text = " %s" % main.APP_TITLE
title_label.add_theme_font_size_override("font_size", UIScale.f(20))
title_label.add_theme_font_size_override("font_size", UIScale.heading_font_size())
# Karte t_297221b5: bei großer Stufe darf der Titel EGALISIEREN statt die
# Top-Bar aus dem Fenster zu drücken (Mindestbreite der Schrift skaliert mit).
# Mindestbreite, damit er nicht KOMPLETT verschwindet (Ellipsis macht "Scop…").
@ -174,7 +176,9 @@ func build() -> void:
file_label = Label.new()
file_label.text = ""
file_label.modulate = Color(1, 1, 1, 0.6)
# U7: Farbe über Theme (Editor/colors/title) statt modulate-Wert im Code.
file_label.add_theme_color_override("font_color",
get_theme_color("title", "Editor"))
# Karte t_297221b5: Map-Pfad darf bei großer Stufe egalisiert werden
# (Voller Name im Tooltip, sonst drückt die Zeile die Top-Bar aus dem Fenster).
# Expand: bekommt zusammen mit dem Spacer seinen Anteil, egalisiert mit "…".

View file

@ -43,6 +43,8 @@ func _init() -> void:
var btn := Button.new()
btn.text = "%d m" % size
btn.custom_minimum_size = UIScale.v2(0, 40)
# U7: Klartext-Tooltips (Karte t_2336c58e).
btn.tooltip_text = "Preset: Karte quadratisch %d × %d m" % [size, size]
btn.pressed.connect(_on_preset.bind(float(size)))
preset_h.add_child(btn)
vbox.add_child(preset_h)
@ -69,6 +71,8 @@ func _init() -> void:
drop_check = CheckBox.new()
drop_check.text = "Draußen liegende Objekte/Bauteile/Spawn-Punkte beim Verkleinern entfernen"
drop_check.button_pressed = true
# U7: Klartext-Tooltip (Karte t_2336c58e).
drop_check.tooltip_text = "An = Dinge außerhalb der neuen Grenze fliegen raus (Strg+Z holt sie zurück).\nAus = sie bleiben, aber die Map ist dann NICHT speicherbar."
drop_check.toggled.connect(func(_p: bool) -> void: _update_preview())
vbox.add_child(drop_check)

View file

@ -17,6 +17,12 @@ extends RefCounted
## 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"
@ -115,6 +121,16 @@ static func v2i(x: float, y: float) -> Vector2i:
return Vector2i(px(x), px(y))
## Standardschriftgröße (bisher fest 16).
## 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)

View file

@ -0,0 +1,61 @@
extends SceneTree
## Beweis-Probe (Karte t_2336c58e, WEGWERF — nicht Teil der Suite):
## U7 Feinschliff — Screenshot der GANZEN Oberfläche (vorher/nachher je
## Baumzustand). Bibliothek „Alle auf" + erste Gruppe offen, damit die
## Kacheln im Bild sind.
## Aufruf: xvfb-run -a godot4 --path . --rendering-driver opengl3 \
## -s res://tests/probe_u7_theme_render.gd (mit ../scopedvr-client)
func _initialize() -> void:
_run.call_deferred()
func _shot(pfad: String) -> void:
await process_frame
await RenderingServer.frame_post_draw
var img := root.get_viewport().get_texture().get_image()
img.save_png(pfad)
print("Bild: %s (%dx%d)" % [pfad, img.get_width(), img.get_height()])
## „Modelle fehlen"-AcceptDialog schließen (kommt erst nach 2 Frames von
## utils/modelle_status.gd — mehrfach probieren, mit Wartezeit dazwischen).
func _dismiss_dialogs() -> void:
for i in 6:
await process_frame
var stack: Array = [root]
while not stack.is_empty():
var n: Node = stack.pop_back()
if n is AcceptDialog:
(n as AcceptDialog).hide()
n.queue_free()
stack.append_array(n.get_children())
func _run() -> void:
var dir := OS.get_environment("U7_DIR")
if dir.is_empty():
dir = "/tmp/u7_beweise"
DirAccess.make_dir_recursive_absolute(dir)
var name := "u7_ui_%s.png" % str(OS.get_environment("U7_MODUS"))
var scene: PackedScene = load("res://scenes/main.tscn")
var main = scene.instantiate()
root.add_child(main)
await process_frame
await process_frame
await _dismiss_dialogs()
DisplayServer.window_set_mode(DisplayServer.WINDOW_MODE_WINDOWED)
DisplayServer.window_set_size(Vector2i(2328, 1310))
await process_frame
await process_frame
# Bibliothek sichtbar füllen: „Alle auf" (der Klick feuert toggled an den
# Gruppen-Headern → Körper sichtbar; der cfg-Schrieb läuft in eine
# hermetische HOME-Umgebung, siehe Startkommando).
var open_btn: Button = main.library_open_all_btn
if open_btn != null:
open_btn.pressed.emit()
await process_frame
await process_frame
await _shot(dir.path_join(name))
print("PROBE_U7_OK dir=%s" % dir)
quit(0)

View file

@ -0,0 +1 @@
uid://d178qhns0kc2s

203
tests/test_theme.gd Normal file
View file

@ -0,0 +1,203 @@
extends SceneTree
## Editor-Test (headless): Theme-Konsistenz — Karte t_2336c58e (U7 Feinschliff).
## Ausführen: godot --headless --path . -s res://tests/test_theme.gd
## Exit 0 = alles grün.
##
## Was hier geprüft wird:
## 1. Theme-Ressource: main nutzt theme/editor_theme.tres (EINE Farbquelle),
## Theme-Schrift = UIScale.font_size().
## 2. Theme-Inhalt: Hover/Fokus/Disabled (Button), Tab-Hover, LineEdit,
## Splitter-Anfassen (grabber_area), Scrollbars, Tooltip + die Farb-Token
## (accent, status_ok/error, muted, field, title, warning).
## 3. KEINE hartkodierten Farben im Code: Suche nach "Color(" in
## src/ui/panels/*.gd, src/ui/main.gd, src/ui/inspector_panel.gd.
## 4. Alle Knöpfe (Button/MenuButton/CheckBox) haben einen Tooltip.
## 5. Typografie-Raster: Überschrift > Body > Nebentext, alles über UIScale.
## 6. Fenstertitel zeigt ungespeicherte Änderungen an (U7 Kleinigkeit).
const UIScale := preload("res://src/ui/ui_scale.gd")
var failures := 0
var checks := 0
var main: Control
func _initialize() -> void:
_run_all.call_deferred()
func _check(cond: bool, label: String) -> void:
checks += 1
if cond:
print(" ok: %s" % label)
else:
failures += 1
print(" FAIL: %s" % label)
func _finish() -> void:
if failures == 0:
print("ALL OK: %d checks" % checks)
quit(0)
else:
print("FAILED: %d/%d checks" % [failures, checks])
quit(1)
func _run_all() -> void:
var scene: PackedScene = load("res://scenes/main.tscn")
_check(scene != null, "scenes/main.tscn laedt")
if scene == null:
_finish()
return
main = scene.instantiate()
root.add_child(main)
# Zwei Frames: _ready + Layout laufen lassen (auch deferred UI-Arbeit).
await process_frame
await process_frame
_test_theme_set()
_test_theme_content()
_test_no_hardcoded_colors()
_test_tooltips()
_test_typography()
_test_window_title_dirty()
_finish()
## 1) main hängt genau die Theme-Datei aus dem Projekt an (eine Quelle).
func _test_theme_set() -> void:
print("Testgruppe: Theme-Ressource gesetzt")
_check(main.theme != null, "main.theme gesetzt")
if main.theme == null:
return
var theme_file: Theme = load("res://theme/editor_theme.tres")
_check(main.theme == theme_file,
"main nutzt theme/editor_theme.tres (eine Farbquelle)")
_check(int(main.theme.default_font_size) == UIScale.font_size(),
"Theme-Schrift = UIScale.font_size() (%d)" % UIScale.font_size())
## 2) Die U7-Theme-Bausteine sind alle da (Hover/Fokus/Disabled, Splitter,
## Scrollbars, Tooltip, Farb-Token).
func _test_theme_content() -> void:
print("Testgruppe: Theme-Inhalt (Hover/Fokus/Disabled/Splitter/Farben)")
var th: Theme = main.theme
_check(th.has_stylebox("disabled", "Button"), "Button: Disabled-Style (ausgegraut)")
_check(th.has_stylebox("hover", "Button"), "Button: Hover-Style")
_check(th.has_stylebox("pressed", "Button"), "Button: Aktiv-Style")
_check(th.has_stylebox("focus", "Button"), "Button: Fokus-Rahmen")
_check(th.has_color("font_disabled_color", "Button"),
"Button: Disabled-Schriftfarbe (sichtbar ausgegraut)")
_check(th.has_color("font_placeholder_color", "LineEdit"),
"LineEdit: Platzhalter-Farbe")
_check(th.has_stylebox("focus", "LineEdit"), "LineEdit: Fokus-Rahmen")
_check(th.has_stylebox("tab_hovered", "TabContainer"), "Tabs: Hover-Zustand")
_check(th.has_stylebox("grabber_area", "HSplitContainer"),
"Splitter: Anfassen-Fläche (HSplit)")
_check(th.has_stylebox("grabber_area", "VSplitContainer"),
"Splitter: Anfassen-Fläche (VSplit)")
_check(th.has_stylebox("grabber_area_highlight", "HSplitContainer"),
"Splitter: Anfassen-Hervorhebung (HSplit)")
_check(th.has_stylebox("grabber", "VScrollBar"), "ScrollBar: Griff (V)")
_check(th.has_stylebox("grabber", "HScrollBar"), "ScrollBar: Griff (H)")
_check(th.has_stylebox("panel", "TooltipPanel"), "Tooltip: Panel-Style")
_check(th.has_color("accent", "Editor"), "Farb-Token: accent")
_check(th.has_color("status_ok", "Editor"), "Farb-Token: status_ok")
_check(th.has_color("status_error", "Editor"), "Farb-Token: status_error")
_check(th.has_color("muted", "Editor"), "Farb-Token: muted")
_check(th.has_color("field", "Editor"), "Farb-Token: field")
_check(th.has_color("title", "Editor"), "Farb-Token: title")
_check(th.has_color("warning", "Editor"), "Farb-Token: warning")
## 3) Keine Farbwerte mehr im Code — alles kommt aus dem Theme.
## Scan: src/ui/panels/*.gd (verbindlich) + main.gd + inspector_panel.gd.
## Achtung: nur "Color(" (Konstruktor) zählt — theme_color()/-> Color: sind
## Schlüsselwörter, keine Farbwerte.
func _test_no_hardcoded_colors() -> void:
print("Testgruppe: keine hartkodierten Farben im Code")
var dateien: Array = []
var dir := DirAccess.open("res://src/ui/panels")
if dir != null:
dir.list_dir_begin()
var fname := dir.get_next()
while not fname.is_empty():
if fname.ends_with(".gd"):
dateien.append("res://src/ui/panels/" + fname)
fname = dir.get_next()
dateien.append("res://src/ui/main.gd")
dateien.append("res://src/ui/inspector_panel.gd")
_check(dateien.size() > 5, "Farb-Scan: %d Skripte gefunden" % dateien.size())
var farb_dateien := 0
for pfad in dateien:
var text := FileAccess.get_file_as_string(pfad)
if text.contains("Color("):
farb_dateien += 1
print(" hartkodierte Farbe in: %s" % pfad)
_check(farb_dateien == 0,
"kein 'Color(' in den Panel-Skripten/main.gd/Inspektor")
## 4) Jeder klickbare Knopf (Button/MenuButton/CheckBox/CheckButton) im
## gebauten UI trägt einen Tooltip — Werkzeugname/Tastenkürzel inklusive.
func _test_tooltips() -> void:
print("Testgruppe: alle Knöpfe haben Tooltips")
var ohne := 0
var mit := 0
var stack: Array = [main]
while not stack.is_empty():
var n: Node = stack.pop_back()
if n is Button or n is MenuButton:
var str_text := str((n as Control).tooltip_text)
if str_text.strip_edges().is_empty():
ohne += 1
var ort := str(n.get_parent().name)
var elter := n.get_parent()
while elter != null and elter != main:
elter = elter.get_parent()
if elter != null:
ort = str(elter.name) + "/" + ort
print(" ohne Tooltip: %s (%s) text='%s' pfad=%s" % [
n.name, n.get_class(),
str((n as Control).get("text")), ort])
else:
mit += 1
for c in n.get_children():
stack.append(c)
_check(mit > 20, "Knöpfe mit Tooltip gefunden (%d)" % mit)
_check(ohne == 0, "kein Knopf ohne Tooltip (%d ohne)" % ohne)
## 5) Genau drei Typografie-Ebenen über UIScale: Überschrift > Body > Nebentext.
func _test_typography() -> void:
print("Testgruppe: Typografie-Raster über UIScale")
_check(UIScale.heading_font_size() > UIScale.font_size(),
"Überschrift (%d) größer als Body (%d)" % [
UIScale.heading_font_size(), UIScale.font_size()])
_check(UIScale.font_size() > UIScale.small_font_size(),
"Body (%d) größer als Nebentext (%d)" % [
UIScale.font_size(), UIScale.small_font_size()])
# Stufen-Skalierung wandert mit (Groß-Stufe, ohne UI-Rebuild zu brauchen):
UIScale.set_step_index(2)
_check(UIScale.heading_font_size() == UIScale.px(UIScale.HEADING_FONT_SIZE),
"Überschrift skaliert mit der UI-Stufe (Groß)")
_check(UIScale.small_font_size() == UIScale.px(UIScale.SMALL_FONT_SIZE),
"Nebentext skaliert mit der UI-Stufe (Groß)")
UIScale.set_step_index(0) # zurück auf Klein (wie der Test-Start)
## 6) Fenstertitel nennt ungespeicherte Änderungen (U7-Kleinigkeit).
func _test_window_title_dirty() -> void:
print("Testgruppe: Fenstertitel bei ungespeicherten Änderungen")
main.dirty = true
main.call("_refresh_file_label")
var titel_dirty := str(root.title)
_check(titel_dirty.contains("ungespeichert"),
"Titel bei dirty nennt „ungespeichert“ (%s)" % titel_dirty)
main.dirty = false
main.call("_refresh_file_label")
var titel_sauber := str(root.title)
_check(not titel_sauber.contains("ungespeichert"),
"Titel ohne dirty bleibt sauber (%s)" % titel_sauber)

1
tests/test_theme.gd.uid Normal file
View file

@ -0,0 +1 @@
uid://3lhyjrmnyfew

View file

@ -1,4 +1,4 @@
[gd_resource type="Theme" load_steps=10 format=3]
[gd_resource type="Theme" load_steps=23 format=3]
[sub_resource type="StyleBoxFlat" id="panel"]
bg_color = Color(0.12, 0.14, 0.17, 1)
@ -23,6 +23,17 @@ content_margin_right = 10.0
content_margin_top = 4.0
content_margin_bottom = 4.0
[sub_resource type="StyleBoxFlat" id="tab_hover"]
bg_color = Color(0.19, 0.24, 0.29, 1)
border_color = Color(0.35, 0.55, 0.7, 0.4)
border_width_top = 2
corner_radius_top_left = 4
corner_radius_top_right = 4
content_margin_left = 10.0
content_margin_right = 10.0
content_margin_top = 4.0
content_margin_bottom = 4.0
[sub_resource type="StyleBoxFlat" id="tab_unsel"]
bg_color = Color(0.15, 0.18, 0.21, 1)
corner_radius_top_left = 4
@ -77,6 +88,60 @@ corner_radius_bottom_left = 4
content_margin_left = 8.0
content_margin_right = 8.0
[sub_resource type="StyleBoxFlat" id="btn_disabled"]
bg_color = Color(0.16, 0.17, 0.19, 1)
border_color = Color(0.24, 0.26, 0.29, 1)
border_width_left = 1
border_width_top = 1
border_width_right = 1
border_width_bottom = 1
corner_radius_top_left = 4
corner_radius_top_right = 4
corner_radius_bottom_right = 4
corner_radius_bottom_left = 4
content_margin_left = 8.0
content_margin_right = 8.0
[sub_resource type="StyleBoxFlat" id="btn_focus"]
draw_center = false
border_color = Color(0.55, 0.8, 1, 0.85)
border_width_left = 1
border_width_top = 1
border_width_right = 1
border_width_bottom = 1
corner_radius_top_left = 4
corner_radius_top_right = 4
corner_radius_bottom_right = 4
corner_radius_bottom_left = 4
[sub_resource type="StyleBoxFlat" id="line_normal"]
bg_color = Color(0.09, 0.11, 0.13, 1)
border_color = Color(0.3, 0.36, 0.42, 1)
border_width_left = 1
border_width_top = 1
border_width_right = 1
border_width_bottom = 1
corner_radius_top_left = 4
corner_radius_top_right = 4
corner_radius_bottom_right = 4
corner_radius_bottom_left = 4
content_margin_left = 8.0
content_margin_right = 8.0
[sub_resource type="StyleBoxFlat" id="line_focus"]
bg_color = Color(0.1, 0.13, 0.15, 1)
border_color = Color(0.55, 0.8, 1, 1)
border_width_left = 1
border_width_top = 1
border_width_right = 1
border_width_bottom = 1
corner_radius_top_left = 4
corner_radius_top_right = 4
corner_radius_bottom_right = 4
corner_radius_bottom_left = 4
content_margin_left = 8.0
content_margin_right = 8.0
[sub_resource type="StyleBoxFlat" id="tooltip"]
bg_color = Color(0.08, 0.09, 0.11, 0.96)
border_color = Color(0.35, 0.55, 0.7, 1)
@ -93,7 +158,64 @@ content_margin_right = 6.0
content_margin_top = 4.0
content_margin_bottom = 4.0
[sub_resource type="StyleBoxEmpty" id="focus_empty"]
[sub_resource type="StyleBoxFlat" id="split_grab"]
bg_color = Color(0.22, 0.27, 0.32, 1)
corner_radius_top_left = 2
corner_radius_top_right = 2
corner_radius_bottom_right = 2
corner_radius_bottom_left = 2
[sub_resource type="StyleBoxFlat" id="split_grab_hover"]
bg_color = Color(0.35, 0.55, 0.7, 0.6)
corner_radius_top_left = 2
corner_radius_top_right = 2
corner_radius_bottom_right = 2
corner_radius_bottom_left = 2
[sub_resource type="StyleBoxFlat" id="scroll_bg"]
bg_color = Color(0.1, 0.12, 0.14, 0.4)
[sub_resource type="StyleBoxFlat" id="scroll_grab"]
bg_color = Color(0.42, 0.49, 0.56, 0.6)
corner_radius_top_left = 3
corner_radius_top_right = 3
corner_radius_bottom_right = 3
corner_radius_bottom_left = 3
[sub_resource type="StyleBoxFlat" id="scroll_grab_hover"]
bg_color = Color(0.55, 0.63, 0.7, 0.8)
corner_radius_top_left = 3
corner_radius_top_right = 3
corner_radius_bottom_right = 3
corner_radius_bottom_left = 3
[sub_resource type="StyleBoxFlat" id="scroll_grab_press"]
bg_color = Color(0.55, 0.8, 1, 0.85)
corner_radius_top_left = 3
corner_radius_top_right = 3
corner_radius_bottom_right = 3
corner_radius_bottom_left = 3
[sub_resource type="StyleBoxFlat" id="progress_bg"]
bg_color = Color(0.09, 0.11, 0.13, 1)
border_color = Color(0.3, 0.36, 0.42, 1)
border_width_left = 1
border_width_top = 1
border_width_right = 1
border_width_bottom = 1
corner_radius_top_left = 4
corner_radius_top_right = 4
corner_radius_bottom_right = 4
corner_radius_bottom_left = 4
[sub_resource type="StyleBoxFlat" id="progress_fill"]
bg_color = Color(0.55, 0.8, 1, 1)
corner_radius_top_left = 4
corner_radius_top_right = 4
corner_radius_bottom_right = 4
corner_radius_bottom_left = 4
[sub_resource type="StyleBoxEmpty" id="scroll_empty"]
[resource]
default_font_size = 16
@ -103,6 +225,8 @@ Editor/colors/status_error = Color(1, 0.6, 0.5, 1)
Editor/colors/muted = Color(1, 1, 1, 0.55)
Editor/colors/field = Color(1, 1, 1, 0.7)
Editor/colors/title = Color(1, 1, 1, 0.6)
Editor/colors/warning = Color(1, 0.62, 0.3, 1)
Editor/colors/badge_outline = Color(0, 0, 0, 1)
Editor/colors/help_bg = Color(0.09, 0.11, 0.13, 0.97)
Editor/colors/help_border = Color(0.35, 0.55, 0.7, 1)
Editor/colors/update_bg = Color(0.36, 0.25, 0.06, 0.97)
@ -118,6 +242,7 @@ Editor/constants/selection_outline_width_partner_mm = 45
PanelContainer/styles/panel = SubResource("panel")
TabContainer/styles/panel = SubResource("panel")
TabContainer/styles/tab_selected = SubResource("tab_sel")
TabContainer/styles/tab_hovered = SubResource("tab_hover")
TabContainer/styles/tab_unselected = SubResource("tab_unsel")
TabContainer/styles/tabbar_background = SubResource("tabbar")
TabContainer/colors/font_selected_color = Color(1, 1, 1, 1)
@ -125,6 +250,32 @@ TabContainer/colors/font_unselected_color = Color(1, 1, 1, 0.7)
Button/styles/normal = SubResource("btn_normal")
Button/styles/hover = SubResource("btn_hover")
Button/styles/pressed = SubResource("btn_pressed")
Button/styles/focus = SubResource("focus_empty")
Button/styles/disabled = SubResource("btn_disabled")
Button/styles/focus = SubResource("btn_focus")
Button/colors/font_hover_color = Color(1, 1, 1, 1)
Button/colors/font_pressed_color = Color(0.8, 0.9, 1, 1)
Button/colors/font_disabled_color = Color(1, 1, 1, 0.35)
LineEdit/styles/normal = SubResource("line_normal")
LineEdit/styles/focus = SubResource("line_focus")
LineEdit/colors/font_color = Color(1, 1, 1, 1)
LineEdit/colors/font_placeholder_color = Color(1, 1, 1, 0.4)
HSplitContainer/styles/grabber_area = SubResource("split_grab")
HSplitContainer/styles/grabber_area_highlight = SubResource("split_grab_hover")
VSplitContainer/styles/grabber_area = SubResource("split_grab")
VSplitContainer/styles/grabber_area_highlight = SubResource("split_grab_hover")
ScrollContainer/styles/panel = SubResource("scroll_empty")
VScrollBar/styles/scroll = SubResource("scroll_bg")
VScrollBar/styles/grabber = SubResource("scroll_grab")
VScrollBar/styles/grabber_highlight = SubResource("scroll_grab_hover")
VScrollBar/styles/grabber_pressed = SubResource("scroll_grab_press")
HScrollBar/styles/scroll = SubResource("scroll_bg")
HScrollBar/styles/grabber = SubResource("scroll_grab")
HScrollBar/styles/grabber_highlight = SubResource("scroll_grab_hover")
HScrollBar/styles/grabber_pressed = SubResource("scroll_grab_press")
ProgressBar/styles/background = SubResource("progress_bg")
ProgressBar/styles/fill = SubResource("progress_fill")
ProgressBar/colors/font_color = Color(1, 1, 1, 1)
HSlider/styles/grabber_area = SubResource("progress_fill")
HSlider/styles/grabber_area_highlight = SubResource("progress_fill")
TooltipPanel/styles/panel = SubResource("tooltip")
TooltipLabel/colors/font_color = Color(1, 1, 1, 1)