Randoloot/addons/godot_mcp_toolkit/ui/dock/dock_section_card.gd
2026-10-09 12:49:07 +02:00

96 lines
3.6 KiB
GDScript

@tool
extends RefCounted
## Section-card factory for the dock — styled cards and collapsible sections.
##
## A stateless `static func` helper (no instance). The dock and its sub-panels
## build several visually-identical "section" blocks (a titled card holding a
## section's controls, or a collapsible variant with a toggle header); this is
## the single place that card shape — its stylebox, header, and content layout —
## lives.
const Modules := preload("res://addons/godot_mcp_toolkit/core/modules.gd")
## Build the theme-adaptive stylebox shared by every section card and the footer.
## Samples the editor's "Panel" stylebox for a base colour so cards read as a
## darker, bordered inset against the current editor theme. Returned fresh per
## call (a StyleBoxFlat is owned by the Control it overrides — see §B.7).
static func make_section_style() -> StyleBoxFlat:
var style := StyleBoxFlat.new()
var scale := EditorInterface.get_editor_scale()
# Sample the editor Panel stylebox for a theme-adaptive base color.
var base := Color(0.22, 0.22, 0.22)
var theme := Modules.EditorAccess.get_editor_theme()
if theme:
var sb = theme.get_stylebox("panel", "Panel")
if sb is StyleBoxFlat:
base = sb.bg_color
style.bg_color = base.darkened(0.12)
style.border_color = base.lightened(0.15)
style.set_border_width_all(1)
style.set_corner_radius_all(int(3 * scale))
style.content_margin_left = 8.0 * scale
style.content_margin_right = 8.0 * scale
style.content_margin_top = 6.0 * scale
style.content_margin_bottom = 6.0 * scale
return style
## Build a styled section card with a header and content VBox.
## Access the content VBox via section.get_meta("content").
static func make_section(title: String) -> PanelContainer:
var panel := PanelContainer.new()
panel.add_theme_stylebox_override("panel", make_section_style())
panel.size_flags_vertical = Control.SIZE_EXPAND_FILL
var outer := VBoxContainer.new()
outer.size_flags_vertical = Control.SIZE_EXPAND_FILL
panel.add_child(outer)
var header := Label.new()
header.text = title
header.add_theme_font_size_override("font_size", 13)
outer.add_child(header)
outer.add_child(HSeparator.new())
var content := VBoxContainer.new()
content.size_flags_vertical = Control.SIZE_EXPAND_FILL
outer.add_child(content)
panel.set_meta("content", content)
return panel
## Build a collapsible section with a styled header bar and per-section
## ScrollContainer. The header is added to `parent` so it never scrolls away;
## only the section content scrolls. Returns the content VBoxContainer.
static func make_collapsible(parent: VBoxContainer, title: String, expanded: bool, min_height: float = 75.0) -> VBoxContainer:
var header := PanelContainer.new()
header.add_theme_stylebox_override("panel", make_section_style())
parent.add_child(header)
var toggle := Button.new()
toggle.flat = true
toggle.toggle_mode = true
toggle.button_pressed = expanded
toggle.text = "%s %s" % ["▼" if expanded else "▶", title]
toggle.alignment = HORIZONTAL_ALIGNMENT_LEFT
header.add_child(toggle)
var content_scroll := ScrollContainer.new()
content_scroll.size_flags_vertical = Control.SIZE_EXPAND_FILL
content_scroll.custom_minimum_size.y = int(min_height * EditorInterface.get_editor_scale())
content_scroll.visible = expanded
parent.add_child(content_scroll)
var content := VBoxContainer.new()
content.size_flags_horizontal = Control.SIZE_EXPAND_FILL
content_scroll.add_child(content)
var t := title # capture for lambda
toggle.toggled.connect(func(pressed: bool):
content_scroll.visible = pressed
toggle.text = "%s %s" % ["▼" if pressed else "▶", t]
)
return content