extends PanelContainer class_name Card ## Card Component ## ## Styled container for content with optional header and footer. ## Mimics the card design from the web UI. ## ## Structure: ## Card (PanelContainer) ## └─ VBoxContainer ## ├─ Header (optional) ## ├─ Body (content) ## └─ Footer (optional) ## ## Usage: ## var card = Card.new() ## card.set_header("Character Details") ## card.add_content(my_content_node) ## card.set_footer_buttons(["Save", "Cancel"]) signal header_action_pressed(action: String) signal footer_button_pressed(button_text: String) # Export variables @export var header_text: String = "" @export var show_header: bool = false @export var show_footer: bool = false @export var card_style: StyleVariant = StyleVariant.DEFAULT # Style variants enum StyleVariant { DEFAULT, # Standard card HIGHLIGHTED, # Gold border highlight SUBTLE # Minimal border } # Internal nodes var _container: VBoxContainer = null var _header_container: HBoxContainer = null var _header_label: Label = null var _body_container: MarginContainer = null var _body_content: VBoxContainer = null var _footer_container: HBoxContainer = null func _ready() -> void: _setup_structure() _apply_style() if not header_text.is_empty(): set_header(header_text) ## Setup card structure func _setup_structure() -> void: # Main container _container = VBoxContainer.new() add_child(_container) # Header _header_container = HBoxContainer.new() _header_container.visible = show_header _header_label = Label.new() _header_label.size_flags_horizontal = Control.SIZE_EXPAND_FILL # TODO: Set heading font when theme is set up _header_container.add_child(_header_label) _container.add_child(_header_container) # Add separator after header var separator = HSeparator.new() separator.visible = show_header _container.add_child(separator) # Body _body_container = MarginContainer.new() _body_container.add_theme_constant_override("margin_left", 16) _body_container.add_theme_constant_override("margin_right", 16) _body_container.add_theme_constant_override("margin_top", 16) _body_container.add_theme_constant_override("margin_bottom", 16) _body_content = VBoxContainer.new() _body_content.size_flags_horizontal = Control.SIZE_EXPAND_FILL _body_content.size_flags_vertical = Control.SIZE_EXPAND_FILL _body_container.add_child(_body_content) _container.add_child(_body_container) # Footer var footer_separator = HSeparator.new() footer_separator.visible = show_footer _container.add_child(footer_separator) _footer_container = HBoxContainer.new() _footer_container.visible = show_footer _footer_container.alignment = BoxContainer.ALIGNMENT_END _container.add_child(_footer_container) ## Apply card styling func _apply_style() -> void: var style = StyleBoxFlat.new() match card_style: StyleVariant.DEFAULT: style.bg_color = ThemeColors.BACKGROUND_CARD style.border_width_all = 1 style.border_color = ThemeColors.BORDER_DEFAULT style.corner_radius_all = 8 StyleVariant.HIGHLIGHTED: style.bg_color = ThemeColors.BACKGROUND_CARD style.border_width_all = 2 style.border_color = ThemeColors.GOLD_ACCENT style.corner_radius_all = 8 style.shadow_color = ThemeColors.SHADOW style.shadow_size = 4 StyleVariant.SUBTLE: style.bg_color = ThemeColors.BACKGROUND_CARD style.border_width_all = 1 style.border_color = ThemeColors.DIVIDER style.corner_radius_all = 4 add_theme_stylebox_override("panel", style) ## Set header text and show header func set_header(text: String) -> void: header_text = text _header_label.text = text _header_container.visible = true show_header = true # Show separator if _container.get_child_count() > 1: _container.get_child(1).visible = true ## Hide header func hide_header() -> void: _header_container.visible = false show_header = false # Hide separator if _container.get_child_count() > 1: _container.get_child(1).visible = false ## Add content to card body func add_content(node: Node) -> void: _body_content.add_child(node) ## Clear all content from body func clear_content() -> void: for child in _body_content.get_children(): child.queue_free() ## Set footer buttons func set_footer_buttons(button_labels: Array[String]) -> void: # Clear existing buttons for child in _footer_container.get_children(): child.queue_free() # Add new buttons for label in button_labels: var btn = Button.new() btn.text = label btn.pressed.connect(_on_footer_button_pressed.bind(label)) _footer_container.add_child(btn) # Show footer _footer_container.visible = true show_footer = true # Show separator if _container.get_child_count() > 2: _container.get_child(_container.get_child_count() - 2).visible = true ## Hide footer func hide_footer() -> void: _footer_container.visible = false show_footer = false # Hide separator if _container.get_child_count() > 2: _container.get_child(_container.get_child_count() - 2).visible = false ## Set card style variant func set_style_variant(variant: StyleVariant) -> void: card_style = variant _apply_style() ## Internal: Handle footer button press func _on_footer_button_pressed(button_text: String) -> void: footer_button_pressed.emit(button_text)