class_name BackgroundUtils extends RefCounted static func create_stylebox_from_styles(styles: Dictionary = {}, container: Control = null) -> StyleBoxFlat: var style_box = StyleBoxFlat.new() # Background color var bg_color = null if styles.has("background-color"): bg_color = styles["background-color"] elif container and container.has_meta("custom_css_background_color"): bg_color = container.get_meta("custom_css_background_color") if bg_color: style_box.bg_color = bg_color else: style_box.bg_color = Color.TRANSPARENT # Border radius var border_radius = null if styles.has("border-radius"): border_radius = styles["border-radius"] elif container and container.has_meta("custom_css_border_radius"): border_radius = container.get_meta("custom_css_border_radius") if border_radius: var radius = StyleManager.parse_radius(border_radius) style_box.corner_radius_top_left = radius style_box.corner_radius_top_right = radius style_box.corner_radius_bottom_left = radius style_box.corner_radius_bottom_right = radius # Border properties var has_border = false style_box.border_width_top = 0 style_box.border_width_right = 0 style_box.border_width_bottom = 0 style_box.border_width_left = 0 var general_border_width = null if styles.has("border-width"): general_border_width = styles["border-width"] elif container and container.has_meta("custom_css_border_width"): general_border_width = container.get_meta("custom_css_border_width") if general_border_width: has_border = true var parsed_width = StyleManager.parse_size(general_border_width) style_box.border_width_top = parsed_width style_box.border_width_right = parsed_width style_box.border_width_bottom = parsed_width style_box.border_width_left = parsed_width var individual_border_keys = [ ["border-top-width", "border_width_top"], ["border-right-width", "border_width_right"], ["border-bottom-width", "border_width_bottom"], ["border-left-width", "border_width_left"] ] for pair in individual_border_keys: var style_key = pair[0] var property_name = pair[1] var width = null var meta_key = "custom_css_" + style_key.replace("-", "_") if styles.has(style_key): width = styles[style_key] elif container and container.has_meta(meta_key): width = container.get_meta(meta_key) if width: has_border = true var parsed_width = StyleManager.parse_size(width) style_box.set(property_name, parsed_width) var border_color = Color.BLACK if styles.has("border-color"): border_color = styles["border-color"] elif container and container.has_meta("custom_css_border_color"): border_color = container.get_meta("custom_css_border_color") if has_border: style_box.border_color = border_color # Padding as content margins var has_padding = false if styles.size() > 0: has_padding = styles.has("padding") or styles.has("padding-top") or styles.has("padding-right") or styles.has("padding-bottom") or styles.has("padding-left") elif container: has_padding = container.has_meta("padding") or container.has_meta("padding_top") or container.has_meta("padding_right") or container.has_meta("padding_bottom") or container.has_meta("padding_left") if has_padding: # General padding var padding_val = null if styles.has("padding"): padding_val = StyleManager.parse_size(styles["padding"]) elif container and container.has_meta("padding"): padding_val = StyleManager.parse_size(container.get_meta("padding")) if padding_val: style_box.content_margin_left = padding_val style_box.content_margin_right = padding_val style_box.content_margin_top = padding_val style_box.content_margin_bottom = padding_val # Individual padding values override general padding var padding_mappings = [["padding-left", "content_margin_left"], ["padding-right", "content_margin_right"], ["padding-top", "content_margin_top"], ["padding-bottom", "content_margin_bottom"]] for mapping in padding_mappings: var style_key = mapping[0] var property_key = mapping[1] var val = get_style_or_meta_value(styles, container, style_key) if val != null: style_box.set(property_key, val) return style_box # for AutoSizingFlexContainer static func update_background_panel(container: Control) -> void: var needs_background = container.has_meta("custom_css_background_color") or container.has_meta("custom_css_border_radius") var needs_padding = container.has_meta("padding") or container.has_meta("padding_top") or container.has_meta("padding_right") or container.has_meta("padding_bottom") or container.has_meta("padding_left") var background_panel = get_background_panel(container) if needs_background or needs_padding: if not background_panel: background_panel = Panel.new() background_panel.name = "BackgroundPanel" background_panel.mouse_filter = Control.MOUSE_FILTER_IGNORE background_panel.set_anchors_and_offsets_preset(Control.PRESET_FULL_RECT) container.add_child(background_panel) container.move_child(background_panel, 0) # first child var style_box = create_stylebox_from_styles({}, container) background_panel.add_theme_stylebox_override("panel", style_box) elif background_panel: background_panel.queue_free() # Helper methods for AutoSizingFlexContainer static func get_background_panel(container: Control) -> Panel: for child in container.get_children(): if child.name == "BackgroundPanel" and child is Panel: return child return null static func is_background_panel(node: Node) -> bool: return node.name == "BackgroundPanel" and node is Panel # for any other tag static func create_panel_container_with_background(styles: Dictionary, hover_styles: Dictionary = {}) -> PanelContainer: var panel_container = PanelContainer.new() panel_container.name = "Div" var vbox = VBoxContainer.new() vbox.name = "VBoxContainer" # Allow mouse events to pass through to the parent PanelContainer vbox.mouse_filter = Control.MOUSE_FILTER_IGNORE vbox.size_flags_vertical = Control.SIZE_EXPAND_FILL panel_container.add_child(vbox) var style_box = create_stylebox_from_styles(styles) panel_container.add_theme_stylebox_override("panel", style_box) # Add hover support if hover styles exist if hover_styles.size() > 0: setup_panel_hover_support(panel_container, styles, hover_styles) return panel_container static func setup_panel_hover_support(panel: PanelContainer, normal_styles: Dictionary, hover_styles: Dictionary): var normal_stylebox = create_stylebox_from_styles(normal_styles) # Merge normal styles with hover styles for the hover state var merged_hover_styles = normal_styles.duplicate() for key in hover_styles: merged_hover_styles[key] = hover_styles[key] var hover_stylebox = create_stylebox_from_styles(merged_hover_styles) # Store references for the hover handlers panel.set_meta("normal_stylebox", normal_stylebox) panel.set_meta("hover_stylebox", hover_stylebox) # Connect mouse events panel.mouse_entered.connect(_on_panel_mouse_entered.bind(panel)) panel.mouse_exited.connect(_on_panel_mouse_exited.bind(panel)) static func _on_panel_mouse_entered(panel: PanelContainer): if panel.has_meta("hover_stylebox"): var hover_stylebox = panel.get_meta("hover_stylebox") panel.add_theme_stylebox_override("panel", hover_stylebox) static func _on_panel_mouse_exited(panel: PanelContainer): if panel.has_meta("normal_stylebox"): var normal_stylebox = panel.get_meta("normal_stylebox") panel.add_theme_stylebox_override("panel", normal_stylebox) static func needs_background_wrapper(styles: Dictionary) -> bool: return styles.has("background-color") or styles.has("border-radius") or styles.has("padding") or styles.has("padding-top") or styles.has("padding-right") or styles.has("padding-bottom") or styles.has("padding-left") or styles.has("border-width") or styles.has("border-top-width") or styles.has("border-right-width") or styles.has("border-bottom-width") or styles.has("border-left-width") or styles.has("border-color") or styles.has("border-style") or styles.has("border-top-color") or styles.has("border-right-color") or styles.has("border-bottom-color") or styles.has("border-left-color") static func get_style_or_meta_value(styles: Dictionary, container: Control, key: String): if styles.has(key): return StyleManager.parse_size(styles[key]) elif container and container.has_meta(key): return StyleManager.parse_size(container.get_meta(key)) return null