classList:add, classList:remove, classList:toggle, style handling
This commit is contained in:
@@ -3,22 +3,16 @@
|
|||||||
[ext_resource type="Script" uid="uid://cks35eudcm1wj" path="res://Scripts/Tags/button.gd" id="1_button"]
|
[ext_resource type="Script" uid="uid://cks35eudcm1wj" path="res://Scripts/Tags/button.gd" id="1_button"]
|
||||||
[ext_resource type="Theme" uid="uid://bn6rbmdy60lhr" path="res://Scenes/Styles/BrowserText.tres" id="2_theme"]
|
[ext_resource type="Theme" uid="uid://bn6rbmdy60lhr" path="res://Scenes/Styles/BrowserText.tres" id="2_theme"]
|
||||||
|
|
||||||
[node name="Button" type="Control"]
|
[node name="Button" type="HBoxContainer"]
|
||||||
custom_minimum_size = Vector2(64, 30)
|
offset_right = 54.0
|
||||||
layout_mode = 3
|
offset_bottom = 23.0
|
||||||
anchors_preset = 0
|
|
||||||
offset_right = 64.0
|
|
||||||
offset_bottom = 30.0
|
|
||||||
script = ExtResource("1_button")
|
script = ExtResource("1_button")
|
||||||
|
|
||||||
[node name="ButtonNode" type="Button" parent="."]
|
[node name="ButtonNode" type="Button" parent="."]
|
||||||
custom_minimum_size = Vector2(64, 0)
|
custom_minimum_size = Vector2(64, 30)
|
||||||
layout_mode = 1
|
layout_mode = 2
|
||||||
anchors_preset = 15
|
size_flags_horizontal = 0
|
||||||
anchor_right = 1.0
|
size_flags_vertical = 4
|
||||||
anchor_bottom = 1.0
|
|
||||||
grow_horizontal = 2
|
|
||||||
grow_vertical = 2
|
|
||||||
mouse_default_cursor_shape = 2
|
mouse_default_cursor_shape = 2
|
||||||
theme = ExtResource("2_theme")
|
theme = ExtResource("2_theme")
|
||||||
text = "Button"
|
text = "Button"
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
[gd_scene load_steps=2 format=3 uid="uid://bopt1234568aa"]
|
[gd_scene load_steps=3 format=3 uid="uid://bopt1234568aa"]
|
||||||
|
|
||||||
|
[ext_resource type="Script" uid="uid://c66r24cncb1dp" path="res://Scripts/Tags/option.gd" id="1_tq7db"]
|
||||||
[ext_resource type="Theme" uid="uid://bn6rbmdy60lhr" path="res://Scenes/Styles/BrowserText.tres" id="2_theme"]
|
[ext_resource type="Theme" uid="uid://bn6rbmdy60lhr" path="res://Scenes/Styles/BrowserText.tres" id="2_theme"]
|
||||||
|
|
||||||
[node name="option" type="Control"]
|
[node name="option" type="Control"]
|
||||||
@@ -7,6 +8,7 @@ layout_mode = 3
|
|||||||
anchors_preset = 10
|
anchors_preset = 10
|
||||||
anchor_right = 1.0
|
anchor_right = 1.0
|
||||||
grow_horizontal = 2
|
grow_horizontal = 2
|
||||||
|
script = ExtResource("1_tq7db")
|
||||||
|
|
||||||
[node name="RichTextLabel" type="RichTextLabel" parent="."]
|
[node name="RichTextLabel" type="RichTextLabel" parent="."]
|
||||||
layout_mode = 2
|
layout_mode = 2
|
||||||
|
|||||||
@@ -75,6 +75,16 @@ class CSSStylesheet:
|
|||||||
func add_rule(rule: CSSRule):
|
func add_rule(rule: CSSRule):
|
||||||
rules.append(rule)
|
rules.append(rule)
|
||||||
|
|
||||||
|
func find_rule_by_selector(selector: String) -> CSSRule:
|
||||||
|
for rule in rules:
|
||||||
|
if rule.selector == selector and rule.event_prefix == "":
|
||||||
|
return rule
|
||||||
|
|
||||||
|
for rule in rules:
|
||||||
|
if rule.selector == selector:
|
||||||
|
return rule
|
||||||
|
return null
|
||||||
|
|
||||||
func get_styles_for_element(tag_name: String, event: String = "", class_names: Array[String] = [], element: HTMLParser.HTMLElement = null) -> Dictionary:
|
func get_styles_for_element(tag_name: String, event: String = "", class_names: Array[String] = [], element: HTMLParser.HTMLElement = null) -> Dictionary:
|
||||||
var styles = {}
|
var styles = {}
|
||||||
|
|
||||||
@@ -362,8 +372,13 @@ func parse_utility_class(rule: CSSRule, utility_name: String) -> void:
|
|||||||
if utility_name.begins_with(prefix):
|
if utility_name.begins_with(prefix):
|
||||||
var actual_utility = utility_name.substr(prefix.length())
|
var actual_utility = utility_name.substr(prefix.length())
|
||||||
var pseudo_rule = CSSRule.new()
|
var pseudo_rule = CSSRule.new()
|
||||||
pseudo_rule.selector = rule.selector + ":" + pseudo
|
|
||||||
pseudo_rule.init(pseudo_rule.selector)
|
pseudo_rule.selector = rule.selector
|
||||||
|
pseudo_rule.event_prefix = pseudo
|
||||||
|
pseudo_rule.selector_type = "simple"
|
||||||
|
pseudo_rule.selector_parts = [rule.selector]
|
||||||
|
pseudo_rule.calculate_specificity()
|
||||||
|
|
||||||
parse_utility_class_internal(pseudo_rule, actual_utility)
|
parse_utility_class_internal(pseudo_rule, actual_utility)
|
||||||
stylesheet.add_rule(pseudo_rule)
|
stylesheet.add_rule(pseudo_rule)
|
||||||
return
|
return
|
||||||
@@ -374,10 +389,19 @@ func parse_utility_class(rule: CSSRule, utility_name: String) -> void:
|
|||||||
# Parses a utility class (e.g. "text-red-500") and adds properties to the rule (e.g. "color: red")
|
# Parses a utility class (e.g. "text-red-500") and adds properties to the rule (e.g. "color: red")
|
||||||
# Used as a translation layer for Tailwind-like utility classes, as it becomes easier to manage these programmatically
|
# Used as a translation layer for Tailwind-like utility classes, as it becomes easier to manage these programmatically
|
||||||
static func parse_utility_class_internal(rule: CSSRule, utility_name: String) -> void:
|
static func parse_utility_class_internal(rule: CSSRule, utility_name: String) -> void:
|
||||||
# Handle color classes like text-[#ff0000]
|
# Handle font size classes like text-[16px] or color classes like text-[#ff0000]
|
||||||
if utility_name.begins_with("text-[") and utility_name.ends_with("]"):
|
if utility_name.begins_with("text-[") and utility_name.ends_with("]"):
|
||||||
var color_value = SizeUtils.extract_bracket_content(utility_name, 5) # after 'text-'
|
var bracket_content = SizeUtils.extract_bracket_content(utility_name, 5) # after 'text-'
|
||||||
var parsed_color = ColorUtils.parse_color(color_value)
|
|
||||||
|
# Check if it's a font size by looking for size units or being a valid number
|
||||||
|
if bracket_content.ends_with("px") or bracket_content.ends_with("em") or bracket_content.ends_with("rem") or bracket_content.is_valid_int() or bracket_content.is_valid_float():
|
||||||
|
var font_size_value = SizingUtils.parse_size_value(bracket_content)
|
||||||
|
if font_size_value != null and typeof(font_size_value) != TYPE_STRING:
|
||||||
|
rule.properties["font-size"] = font_size_value
|
||||||
|
return
|
||||||
|
|
||||||
|
# Parse as color
|
||||||
|
var parsed_color = ColorUtils.parse_color(bracket_content)
|
||||||
rule.properties["color"] = parsed_color
|
rule.properties["color"] = parsed_color
|
||||||
return
|
return
|
||||||
|
|
||||||
|
|||||||
@@ -200,12 +200,30 @@ func parse_inline_style_with_event(style_string: String, event: String = "") ->
|
|||||||
CSSParser.parse_utility_class_internal(rule, actual_utility)
|
CSSParser.parse_utility_class_internal(rule, actual_utility)
|
||||||
for property in rule.properties:
|
for property in rule.properties:
|
||||||
properties[property] = rule.properties[property]
|
properties[property] = rule.properties[property]
|
||||||
|
else:
|
||||||
|
# Check if this is a CSS class that might have pseudo-class rules
|
||||||
|
if parse_result.css_parser and parse_result.css_parser.stylesheet:
|
||||||
|
var pseudo_styles = parse_result.css_parser.stylesheet.get_styles_for_element("", event, [utility_name], null)
|
||||||
|
if not pseudo_styles.is_empty():
|
||||||
|
for property in pseudo_styles:
|
||||||
|
properties[property] = pseudo_styles[property]
|
||||||
else:
|
else:
|
||||||
if not utility_name.contains(":"):
|
if not utility_name.contains(":"):
|
||||||
var rule = CSSParser.CSSRule.new()
|
if parse_result.css_parser and parse_result.css_parser.stylesheet:
|
||||||
CSSParser.parse_utility_class_internal(rule, utility_name)
|
var css_rule = parse_result.css_parser.stylesheet.find_rule_by_selector("." + utility_name)
|
||||||
for property in rule.properties:
|
if css_rule:
|
||||||
properties[property] = rule.properties[property]
|
for property in css_rule.properties:
|
||||||
|
properties[property] = css_rule.properties[property]
|
||||||
|
else:
|
||||||
|
var rule = CSSParser.CSSRule.new()
|
||||||
|
CSSParser.parse_utility_class_internal(rule, utility_name)
|
||||||
|
for property in rule.properties:
|
||||||
|
properties[property] = rule.properties[property]
|
||||||
|
else:
|
||||||
|
var rule = CSSParser.CSSRule.new()
|
||||||
|
CSSParser.parse_utility_class_internal(rule, utility_name)
|
||||||
|
for property in rule.properties:
|
||||||
|
properties[property] = rule.properties[property]
|
||||||
|
|
||||||
return properties
|
return properties
|
||||||
|
|
||||||
|
|||||||
@@ -213,6 +213,25 @@ func _element_index_handler(vm: LuauVM) -> int:
|
|||||||
vm.lua_rawseti(-2, index)
|
vm.lua_rawseti(-2, index)
|
||||||
index += 1
|
index += 1
|
||||||
|
|
||||||
|
return 1
|
||||||
|
"classList":
|
||||||
|
# Create classList object with add, remove, toggle methods
|
||||||
|
vm.lua_newtable()
|
||||||
|
|
||||||
|
# Add methods to classList using the utility class
|
||||||
|
vm.lua_pushcallable(_element_classlist_add_wrapper, "classList.add")
|
||||||
|
vm.lua_setfield(-2, "add")
|
||||||
|
|
||||||
|
vm.lua_pushcallable(_element_classlist_remove_wrapper, "classList.remove")
|
||||||
|
vm.lua_setfield(-2, "remove")
|
||||||
|
|
||||||
|
vm.lua_pushcallable(_element_classlist_toggle_wrapper, "classList.toggle")
|
||||||
|
vm.lua_setfield(-2, "toggle")
|
||||||
|
|
||||||
|
# Store element reference for the classList methods
|
||||||
|
vm.lua_getfield(1, "_element_id")
|
||||||
|
vm.lua_setfield(-2, "_element_id")
|
||||||
|
|
||||||
return 1
|
return 1
|
||||||
_:
|
_:
|
||||||
# Fall back to checking the original table for methods
|
# Fall back to checking the original table for methods
|
||||||
@@ -333,6 +352,15 @@ func _element_remove_handler(vm: LuauVM) -> int:
|
|||||||
|
|
||||||
return 0
|
return 0
|
||||||
|
|
||||||
|
func _element_classlist_add_wrapper(vm: LuauVM) -> int:
|
||||||
|
return LuaClassListUtils.element_classlist_add_handler(vm, dom_parser)
|
||||||
|
|
||||||
|
func _element_classlist_remove_wrapper(vm: LuauVM) -> int:
|
||||||
|
return LuaClassListUtils.element_classlist_remove_handler(vm, dom_parser)
|
||||||
|
|
||||||
|
func _element_classlist_toggle_wrapper(vm: LuauVM) -> int:
|
||||||
|
return LuaClassListUtils.element_classlist_toggle_handler(vm, dom_parser)
|
||||||
|
|
||||||
func _render_new_element(element: HTMLParser.HTMLElement, parent_node: Node) -> void:
|
func _render_new_element(element: HTMLParser.HTMLElement, parent_node: Node) -> void:
|
||||||
# Get reference to main scene for rendering
|
# Get reference to main scene for rendering
|
||||||
var main_scene = get_node("/root/Main")
|
var main_scene = get_node("/root/Main")
|
||||||
|
|||||||
@@ -21,7 +21,7 @@ code { text-xl font-mono }
|
|||||||
a { text-[#1a0dab] }
|
a { text-[#1a0dab] }
|
||||||
pre { text-xl font-mono }
|
pre { text-xl font-mono }
|
||||||
|
|
||||||
button { bg-[#1b1b1b] rounded-md text-white hover:bg-[#2a2a2a] active:bg-[#101010] }
|
button { text-[16px] bg-[#1b1b1b] rounded-md text-white hover:bg-[#2a2a2a] active:bg-[#101010] }
|
||||||
button[disabled] { bg-[#666666] text-[#999999] cursor-not-allowed }
|
button[disabled] { bg-[#666666] text-[#999999] cursor-not-allowed }
|
||||||
"""
|
"""
|
||||||
|
|
||||||
@@ -100,7 +100,7 @@ var HTML_CONTENT2 = """<head>
|
|||||||
|
|
||||||
</body>
|
</body>
|
||||||
""".to_utf8_buffer()
|
""".to_utf8_buffer()
|
||||||
var HTML_CONTENTbv = """<head>
|
var HTML_CONTENTvv = """<head>
|
||||||
<title>My cool web</title>
|
<title>My cool web</title>
|
||||||
<icon src=\"https://upload.wikimedia.org/wikipedia/commons/thumb/c/c1/Google_%22G%22_logo.svg/768px-Google_%22G%22_logo.svg.png\">
|
<icon src=\"https://upload.wikimedia.org/wikipedia/commons/thumb/c/c1/Google_%22G%22_logo.svg/768px-Google_%22G%22_logo.svg.png\">
|
||||||
|
|
||||||
@@ -599,9 +599,10 @@ var HTML_CONTENT = """
|
|||||||
|
|
||||||
<style>
|
<style>
|
||||||
body { bg-[#f8f9fa] p-6 }
|
body { bg-[#f8f9fa] p-6 }
|
||||||
h1 { text-[#2563eb] text-4xl font-bold }
|
h1 { text-[#2563eb] text-2xl font-bold }
|
||||||
.container { bg-[#ffffff] p-4 rounded-lg shadow-lg }
|
.container { bg-[#ffffff] p-4 rounded-lg shadow-lg }
|
||||||
.demo-button { bg-[#3b82f6] text-white px-4 py-2 rounded hover:bg-[#2563eb] }
|
.demo-button { bg-[#3b82f6] text-white px-4 py-2 rounded hover:bg-[#2563eb] }
|
||||||
|
.fancy { bg-green-500 text-red-500 p-2 rounded-full mt-2 mb-2 text-2xl hover:bg-red-300 hover:text-[#2563eb] }
|
||||||
</style>
|
</style>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
@@ -696,6 +697,21 @@ var HTML_CONTENT = """
|
|||||||
end, 3000)
|
end, 3000)
|
||||||
|
|
||||||
-- gurt.clearTimeout(test)
|
-- gurt.clearTimeout(test)
|
||||||
|
|
||||||
|
local addBtn = gurt.select('#add-class')
|
||||||
|
local removeBtn = gurt.select('#remove-class')
|
||||||
|
local btnTarget = gurt.select('#btnTarget')
|
||||||
|
|
||||||
|
addBtn:on('click', function()
|
||||||
|
btnTarget.classList:add('fancy')
|
||||||
|
-- btnTarget.classList:toggle('fancy')
|
||||||
|
print('Class added')
|
||||||
|
end)
|
||||||
|
|
||||||
|
removeBtn:on('click', function()
|
||||||
|
btnTarget.classList:remove('fancy')
|
||||||
|
print('Class removed')
|
||||||
|
end)
|
||||||
</script>
|
</script>
|
||||||
</head>
|
</head>
|
||||||
|
|
||||||
@@ -714,6 +730,14 @@ var HTML_CONTENT = """
|
|||||||
<p id="btnmouse" style="mt-4 p-4 bg-[#f3f4f6] rounded min-h-24">Move mouse over Button</p>
|
<p id="btnmouse" style="mt-4 p-4 bg-[#f3f4f6] rounded min-h-24">Move mouse over Button</p>
|
||||||
|
|
||||||
<p id="type" style="mt-4 p-4 bg-[#f3f4f6] rounded min-h-24">Type something</p>
|
<p id="type" style="mt-4 p-4 bg-[#f3f4f6] rounded min-h-24">Type something</p>
|
||||||
|
|
||||||
|
<div style="mt-6 flex gap-4 items-center">
|
||||||
|
<div style="text-lg font-semibold">Style Controls:</div>
|
||||||
|
<button id="add-class" style="bg-green-600 text-white px-4 py-2 rounded hover:bg-green-700">Add Class</button>
|
||||||
|
<button id="remove-class" style="bg-red-600 text-white px-4 py-2 rounded hover:bg-red-700">Remove Class</button>
|
||||||
|
</div>
|
||||||
|
<button id="btnTarget" style="bg-gray-600">Button</button>
|
||||||
|
|
||||||
</body>""".to_utf8_buffer()
|
</body>""".to_utf8_buffer()
|
||||||
|
|
||||||
var HTML_CONTENT_ADD_REMOVE = """<head>
|
var HTML_CONTENT_ADD_REMOVE = """<head>
|
||||||
|
|||||||
@@ -126,42 +126,180 @@ static func apply_element_styles(node: Control, element: HTMLParser.HTMLElement,
|
|||||||
|
|
||||||
# Check for margins first and wrap in MarginContainer if needed
|
# Check for margins first and wrap in MarginContainer if needed
|
||||||
var has_margin = styles.has("margin") or styles.has("margin-top") or styles.has("margin-right") or styles.has("margin-bottom") or styles.has("margin-left")
|
var has_margin = styles.has("margin") or styles.has("margin-top") or styles.has("margin-right") or styles.has("margin-bottom") or styles.has("margin-left")
|
||||||
|
node = handle_margin_wrapper(node, styles, has_margin)
|
||||||
|
|
||||||
if has_margin:
|
var needs_styling = styles.has("background-color") or styles.has("border-radius") 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("padding") or styles.has("padding-top") or styles.has("padding-right") or styles.has("padding-bottom") or styles.has("padding-left")
|
||||||
node = apply_margin_wrapper(node, styles)
|
|
||||||
|
|
||||||
# Apply background color, border radius, borders
|
|
||||||
var needs_styling = styles.has("background-color") or styles.has("border-radius") 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")
|
|
||||||
|
|
||||||
if needs_styling:
|
if needs_styling:
|
||||||
var target_node_for_bg = node if node is FlexContainer else label
|
# If node is a MarginContainer wrapper, get the actual content node for styling
|
||||||
|
var content_node = node
|
||||||
|
if node is MarginContainer and node.name.begins_with("MarginWrapper_"):
|
||||||
|
if node.get_child_count() > 0:
|
||||||
|
content_node = node.get_child(0)
|
||||||
|
|
||||||
|
var target_node_for_bg = content_node if content_node is FlexContainer else (label if label else content_node)
|
||||||
if target_node_for_bg:
|
if target_node_for_bg:
|
||||||
if styles.has("background-color"):
|
# Clear existing metadata first to ensure clean state
|
||||||
target_node_for_bg.set_meta("custom_css_background_color", styles["background-color"])
|
clear_styling_metadata(target_node_for_bg)
|
||||||
if styles.has("border-radius"):
|
|
||||||
target_node_for_bg.set_meta("custom_css_border_radius", styles["border-radius"])
|
|
||||||
|
|
||||||
# Border properties
|
# Set new metadata based on current styles
|
||||||
if styles.has("border-width"):
|
set_styling_metadata(target_node_for_bg, styles)
|
||||||
target_node_for_bg.set_meta("custom_css_border_width", styles["border-width"])
|
|
||||||
if styles.has("border-color"):
|
if target_node_for_bg is FlexContainer:
|
||||||
target_node_for_bg.set_meta("custom_css_border_color", styles["border-color"])
|
BackgroundUtils.update_background_panel(target_node_for_bg)
|
||||||
|
elif target_node_for_bg is PanelContainer:
|
||||||
|
apply_stylebox_to_panel_container(target_node_for_bg, styles)
|
||||||
|
else:
|
||||||
|
apply_stylebox_to_container_direct(target_node_for_bg, styles)
|
||||||
|
|
||||||
# Individual border sides
|
|
||||||
var border_sides = ["top", "right", "bottom", "left"]
|
|
||||||
for side in border_sides:
|
|
||||||
var width_key = "border-" + side + "-width"
|
|
||||||
if styles.has(width_key):
|
|
||||||
target_node_for_bg.set_meta("custom_css_" + width_key.replace("-", "_"), styles[width_key])
|
|
||||||
|
|
||||||
if target_node_for_bg.has_method("add_background_rect"):
|
if target_node_for_bg.has_method("add_background_rect"):
|
||||||
target_node_for_bg.call_deferred("add_background_rect")
|
target_node_for_bg.call_deferred("add_background_rect")
|
||||||
|
else:
|
||||||
|
var content_node = node
|
||||||
|
if node is MarginContainer and node.name.begins_with("MarginWrapper_"):
|
||||||
|
if node.get_child_count() > 0:
|
||||||
|
content_node = node.get_child(0)
|
||||||
|
|
||||||
|
var target_node_for_bg = content_node if content_node is FlexContainer else (label if label else content_node)
|
||||||
|
if target_node_for_bg:
|
||||||
|
clear_styling_metadata(target_node_for_bg)
|
||||||
|
|
||||||
|
if target_node_for_bg is FlexContainer:
|
||||||
|
BackgroundUtils.update_background_panel(target_node_for_bg)
|
||||||
|
elif target_node_for_bg is PanelContainer:
|
||||||
|
target_node_for_bg.remove_theme_stylebox_override("panel")
|
||||||
|
else:
|
||||||
|
target_node_for_bg.remove_theme_stylebox_override("panel")
|
||||||
|
target_node_for_bg.remove_theme_stylebox_override("background")
|
||||||
|
|
||||||
if label:
|
if label:
|
||||||
apply_styles_to_label(label, styles, element, parser)
|
apply_styles_to_label(label, styles, element, parser)
|
||||||
|
|
||||||
return node
|
return node
|
||||||
|
|
||||||
|
static func apply_stylebox_to_panel_container(panel_container: PanelContainer, styles: Dictionary) -> void:
|
||||||
|
var has_visual_styles = BackgroundUtils.needs_background_wrapper(styles)
|
||||||
|
|
||||||
|
if has_visual_styles:
|
||||||
|
var style_box = BackgroundUtils.create_stylebox_from_styles(styles, panel_container)
|
||||||
|
panel_container.add_theme_stylebox_override("panel", style_box)
|
||||||
|
else:
|
||||||
|
panel_container.remove_theme_stylebox_override("panel")
|
||||||
|
clear_styling_metadata(panel_container)
|
||||||
|
|
||||||
|
static func apply_stylebox_to_container_direct(container: Control, styles: Dictionary) -> void:
|
||||||
|
var has_visual_styles = BackgroundUtils.needs_background_wrapper(styles)
|
||||||
|
|
||||||
|
if has_visual_styles:
|
||||||
|
var style_box = BackgroundUtils.create_stylebox_from_styles(styles, container)
|
||||||
|
|
||||||
|
container.add_theme_stylebox_override("panel", style_box)
|
||||||
|
container.add_theme_stylebox_override("background", style_box)
|
||||||
|
else:
|
||||||
|
container.remove_theme_stylebox_override("panel")
|
||||||
|
container.remove_theme_stylebox_override("background")
|
||||||
|
clear_styling_metadata(container)
|
||||||
|
|
||||||
|
static func set_styling_metadata(node: Control, styles: Dictionary) -> void:
|
||||||
|
# Basic styling properties
|
||||||
|
var basic_properties = [
|
||||||
|
["background-color", "custom_css_background_color"],
|
||||||
|
["border-radius", "custom_css_border_radius"],
|
||||||
|
["border-width", "custom_css_border_width"],
|
||||||
|
["border-color", "custom_css_border_color"]
|
||||||
|
]
|
||||||
|
|
||||||
|
for prop in basic_properties:
|
||||||
|
if styles.has(prop[0]):
|
||||||
|
node.set_meta(prop[1], styles[prop[0]])
|
||||||
|
|
||||||
|
# Padding properties
|
||||||
|
var padding_properties = [
|
||||||
|
["padding", "padding"],
|
||||||
|
["padding-top", "padding_top"],
|
||||||
|
["padding-right", "padding_right"],
|
||||||
|
["padding-bottom", "padding_bottom"],
|
||||||
|
["padding-left", "padding_left"]
|
||||||
|
]
|
||||||
|
|
||||||
|
for prop in padding_properties:
|
||||||
|
if styles.has(prop[0]):
|
||||||
|
node.set_meta(prop[1], styles[prop[0]])
|
||||||
|
|
||||||
|
# Individual border sides
|
||||||
|
var border_sides = ["top", "right", "bottom", "left"]
|
||||||
|
for side in border_sides:
|
||||||
|
var width_key = "border-" + side + "-width"
|
||||||
|
if styles.has(width_key):
|
||||||
|
node.set_meta("custom_css_" + width_key.replace("-", "_"), styles[width_key])
|
||||||
|
|
||||||
|
static func clear_styling_metadata(node: Control) -> void:
|
||||||
|
var metadata_keys = [
|
||||||
|
"custom_css_background_color",
|
||||||
|
"custom_css_border_radius",
|
||||||
|
"custom_css_border_width",
|
||||||
|
"custom_css_border_color",
|
||||||
|
"padding",
|
||||||
|
"padding_top",
|
||||||
|
"padding_right",
|
||||||
|
"padding_bottom",
|
||||||
|
"padding_left"
|
||||||
|
]
|
||||||
|
|
||||||
|
for key in metadata_keys:
|
||||||
|
if node.has_meta(key):
|
||||||
|
node.remove_meta(key)
|
||||||
|
|
||||||
|
static func handle_margin_wrapper(node: Control, styles: Dictionary, needs_margin: bool):
|
||||||
|
var current_wrapper = null
|
||||||
|
|
||||||
|
if node is MarginContainer and node.name.begins_with("MarginWrapper_"):
|
||||||
|
current_wrapper = node
|
||||||
|
|
||||||
|
elif node.get_parent() and node.get_parent() is MarginContainer:
|
||||||
|
var parent = node.get_parent()
|
||||||
|
if parent.name.begins_with("MarginWrapper_"):
|
||||||
|
current_wrapper = parent
|
||||||
|
|
||||||
|
if needs_margin:
|
||||||
|
if current_wrapper:
|
||||||
|
update_margin_wrapper(current_wrapper, styles)
|
||||||
|
return current_wrapper
|
||||||
|
else:
|
||||||
|
return apply_margin_wrapper(node, styles)
|
||||||
|
else:
|
||||||
|
if current_wrapper:
|
||||||
|
if current_wrapper == node:
|
||||||
|
if node.get_child_count() > 0:
|
||||||
|
var content_node = node.get_child(0)
|
||||||
|
return remove_margin_wrapper(current_wrapper, content_node)
|
||||||
|
else:
|
||||||
|
return remove_margin_wrapper(current_wrapper, node)
|
||||||
|
else:
|
||||||
|
return node
|
||||||
|
|
||||||
|
static func update_margin_wrapper(margin_container: MarginContainer, styles: Dictionary) -> void:
|
||||||
|
clear_margin_overrides(margin_container)
|
||||||
|
apply_margin_styles_to_container(margin_container, styles)
|
||||||
|
|
||||||
|
static func remove_margin_wrapper(margin_container: MarginContainer, original_node: Control) -> Control:
|
||||||
|
var original_parent = margin_container.get_parent()
|
||||||
|
var node_index = margin_container.get_index()
|
||||||
|
|
||||||
|
original_node.size_flags_horizontal = margin_container.size_flags_horizontal
|
||||||
|
original_node.size_flags_vertical = margin_container.size_flags_vertical
|
||||||
|
|
||||||
|
margin_container.remove_child(original_node)
|
||||||
|
|
||||||
|
if original_parent:
|
||||||
|
original_parent.remove_child(margin_container)
|
||||||
|
original_parent.add_child(original_node)
|
||||||
|
original_parent.move_child(original_node, node_index)
|
||||||
|
|
||||||
|
margin_container.queue_free()
|
||||||
|
|
||||||
|
return original_node
|
||||||
|
|
||||||
static func apply_margin_wrapper(node: Control, styles: Dictionary) -> Control:
|
static func apply_margin_wrapper(node: Control, styles: Dictionary) -> Control:
|
||||||
var margin_container = MarginContainer.new()
|
var margin_container = MarginContainer.new()
|
||||||
margin_container.name = "MarginWrapper_" + node.name
|
margin_container.name = "MarginWrapper_" + node.name
|
||||||
@@ -170,35 +308,7 @@ static func apply_margin_wrapper(node: Control, styles: Dictionary) -> Control:
|
|||||||
margin_container.size_flags_horizontal = node.size_flags_horizontal
|
margin_container.size_flags_horizontal = node.size_flags_horizontal
|
||||||
margin_container.size_flags_vertical = node.size_flags_vertical
|
margin_container.size_flags_vertical = node.size_flags_vertical
|
||||||
|
|
||||||
# Set margin values using theme overrides
|
apply_margin_styles_to_container(margin_container, styles)
|
||||||
var general_margin_str = null
|
|
||||||
if styles.has("margin"):
|
|
||||||
general_margin_str = styles["margin"]
|
|
||||||
|
|
||||||
if general_margin_str != null:
|
|
||||||
var general_margin = parse_size(general_margin_str)
|
|
||||||
if general_margin != null:
|
|
||||||
margin_container.add_theme_constant_override("margin_top", general_margin)
|
|
||||||
margin_container.add_theme_constant_override("margin_right", general_margin)
|
|
||||||
margin_container.add_theme_constant_override("margin_bottom", general_margin)
|
|
||||||
margin_container.add_theme_constant_override("margin_left", general_margin)
|
|
||||||
|
|
||||||
# Individual margin overrides
|
|
||||||
var margin_sides = [
|
|
||||||
["margin-top", "margin_top"],
|
|
||||||
["margin-right", "margin_right"],
|
|
||||||
["margin-bottom", "margin_bottom"],
|
|
||||||
["margin-left", "margin_left"]
|
|
||||||
]
|
|
||||||
|
|
||||||
for side_pair in margin_sides:
|
|
||||||
var style_key = side_pair[0]
|
|
||||||
var theme_key = side_pair[1]
|
|
||||||
if styles.has(style_key):
|
|
||||||
var margin_val_str = styles[style_key]
|
|
||||||
var margin_val = parse_size(margin_val_str)
|
|
||||||
if margin_val != null:
|
|
||||||
margin_container.add_theme_constant_override(theme_key, margin_val)
|
|
||||||
|
|
||||||
# Reset the original node's size flags since they're now handled by the wrapper
|
# Reset the original node's size flags since they're now handled by the wrapper
|
||||||
node.size_flags_horizontal = Control.SIZE_EXPAND_FILL
|
node.size_flags_horizontal = Control.SIZE_EXPAND_FILL
|
||||||
@@ -217,6 +327,37 @@ static func apply_margin_wrapper(node: Control, styles: Dictionary) -> Control:
|
|||||||
|
|
||||||
return margin_container
|
return margin_container
|
||||||
|
|
||||||
|
static func clear_margin_overrides(margin_container: MarginContainer) -> void:
|
||||||
|
margin_container.remove_theme_constant_override("margin_top")
|
||||||
|
margin_container.remove_theme_constant_override("margin_right")
|
||||||
|
margin_container.remove_theme_constant_override("margin_bottom")
|
||||||
|
margin_container.remove_theme_constant_override("margin_left")
|
||||||
|
|
||||||
|
static func apply_margin_styles_to_container(margin_container: MarginContainer, styles: Dictionary) -> void:
|
||||||
|
# Apply general margin first
|
||||||
|
if styles.has("margin"):
|
||||||
|
var general_margin = parse_size(styles["margin"])
|
||||||
|
if general_margin != null:
|
||||||
|
var margin_sides = ["margin_top", "margin_right", "margin_bottom", "margin_left"]
|
||||||
|
for side in margin_sides:
|
||||||
|
margin_container.add_theme_constant_override(side, general_margin)
|
||||||
|
|
||||||
|
# Apply individual margin overrides
|
||||||
|
var margin_mappings = [
|
||||||
|
["margin-top", "margin_top"],
|
||||||
|
["margin-right", "margin_right"],
|
||||||
|
["margin-bottom", "margin_bottom"],
|
||||||
|
["margin-left", "margin_left"]
|
||||||
|
]
|
||||||
|
|
||||||
|
for mapping in margin_mappings:
|
||||||
|
var style_key = mapping[0]
|
||||||
|
var theme_key = mapping[1]
|
||||||
|
if styles.has(style_key):
|
||||||
|
var margin_val = parse_size(styles[style_key])
|
||||||
|
if margin_val != null:
|
||||||
|
margin_container.add_theme_constant_override(theme_key, margin_val)
|
||||||
|
|
||||||
static func apply_styles_to_label(label: Control, styles: Dictionary, element: HTMLParser.HTMLElement, parser, text_override: String = "") -> void:
|
static func apply_styles_to_label(label: Control, styles: Dictionary, element: HTMLParser.HTMLElement, parser, text_override: String = "") -> void:
|
||||||
if label is Button:
|
if label is Button:
|
||||||
apply_font_to_button(label, styles)
|
apply_font_to_button(label, styles)
|
||||||
@@ -359,27 +500,28 @@ static func apply_body_styles(body: HTMLParser.HTMLElement, parser: HTMLParser,
|
|||||||
original_parent.move_child(margin_container, container_index)
|
original_parent.move_child(margin_container, container_index)
|
||||||
margin_container.add_child(website_container)
|
margin_container.add_child(website_container)
|
||||||
|
|
||||||
var margin_val = parse_size(styles["padding"])
|
var padding_val = parse_size(styles["padding"])
|
||||||
|
|
||||||
margin_container.add_theme_constant_override("margin_left", margin_val)
|
margin_container.add_theme_constant_override("margin_left", padding_val)
|
||||||
margin_container.add_theme_constant_override("margin_right", margin_val)
|
margin_container.add_theme_constant_override("margin_right", padding_val)
|
||||||
margin_container.add_theme_constant_override("margin_top", margin_val)
|
margin_container.add_theme_constant_override("margin_top", padding_val)
|
||||||
margin_container.add_theme_constant_override("margin_bottom", margin_val)
|
margin_container.add_theme_constant_override("margin_bottom", padding_val)
|
||||||
|
|
||||||
# Apply individual padding values
|
# Apply individual padding values using our helper function
|
||||||
var padding_sides = [
|
var padding_mappings = [
|
||||||
["padding-top", "margin_top"],
|
["padding-top", "margin_top"],
|
||||||
["padding-right", "margin_right"],
|
["padding-right", "margin_right"],
|
||||||
["padding-bottom", "margin_bottom"],
|
["padding-bottom", "margin_bottom"],
|
||||||
["padding-left", "margin_left"]
|
["padding-left", "margin_left"]
|
||||||
]
|
]
|
||||||
|
|
||||||
for side_pair in padding_sides:
|
for mapping in padding_mappings:
|
||||||
var style_key = side_pair[0]
|
var style_key = mapping[0]
|
||||||
var margin_key = side_pair[1]
|
var margin_key = mapping[1]
|
||||||
if styles.has(style_key):
|
if styles.has(style_key):
|
||||||
var margin_val2 = parse_size(styles[style_key])
|
var margin_val = parse_size(styles[style_key])
|
||||||
margin_container.add_theme_constant_override(margin_key, margin_val2)
|
if margin_val != null:
|
||||||
|
margin_container.add_theme_constant_override(margin_key, margin_val)
|
||||||
|
|
||||||
static func parse_radius(radius_str: String) -> int:
|
static func parse_radius(radius_str: String) -> int:
|
||||||
return SizeUtils.parse_radius(radius_str)
|
return SizeUtils.parse_radius(radius_str)
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
class_name HTMLButton
|
class_name HTMLButton
|
||||||
extends Control
|
extends HBoxContainer
|
||||||
|
|
||||||
var current_element: HTMLParser.HTMLElement
|
var current_element: HTMLParser.HTMLElement
|
||||||
var current_parser: HTMLParser
|
var current_parser: HTMLParser
|
||||||
@@ -18,26 +18,17 @@ func init(element: HTMLParser.HTMLElement, parser: HTMLParser = null) -> void:
|
|||||||
if button_text.length() > 0:
|
if button_text.length() > 0:
|
||||||
button_node.text = button_text
|
button_node.text = button_text
|
||||||
|
|
||||||
var natural_size = button_node.get_theme_default_font().get_string_size(
|
# Set container to shrink to fit content
|
||||||
button_node.text,
|
|
||||||
HORIZONTAL_ALIGNMENT_LEFT,
|
|
||||||
-1,
|
|
||||||
button_node.get_theme_default_font_size()
|
|
||||||
) + Vector2(20, 10) # Add padding
|
|
||||||
|
|
||||||
# Force our container to use the natural size
|
|
||||||
custom_minimum_size = natural_size
|
|
||||||
size_flags_horizontal = Control.SIZE_SHRINK_BEGIN
|
size_flags_horizontal = Control.SIZE_SHRINK_BEGIN
|
||||||
size_flags_vertical = Control.SIZE_SHRINK_BEGIN
|
size_flags_vertical = Control.SIZE_SHRINK_BEGIN
|
||||||
|
|
||||||
# Make button node fill the container
|
# Let button size itself naturally
|
||||||
button_node.custom_minimum_size = Vector2.ZERO
|
button_node.size_flags_horizontal = Control.SIZE_SHRINK_BEGIN
|
||||||
button_node.size_flags_horizontal = Control.SIZE_FILL
|
button_node.size_flags_vertical = Control.SIZE_SHRINK_BEGIN
|
||||||
button_node.size_flags_vertical = Control.SIZE_FILL
|
|
||||||
|
|
||||||
apply_button_styles(element, parser, natural_size)
|
apply_button_styles(element, parser)
|
||||||
|
|
||||||
func apply_button_styles(element: HTMLParser.HTMLElement, parser: HTMLParser, natural_size: Vector2) -> void:
|
func apply_button_styles(element: HTMLParser.HTMLElement, parser: HTMLParser) -> void:
|
||||||
if not element or not parser:
|
if not element or not parser:
|
||||||
return
|
return
|
||||||
|
|
||||||
@@ -51,6 +42,11 @@ func apply_button_styles(element: HTMLParser.HTMLElement, parser: HTMLParser, na
|
|||||||
mouse_default_cursor_shape = cursor_shape
|
mouse_default_cursor_shape = cursor_shape
|
||||||
button_node.mouse_default_cursor_shape = cursor_shape
|
button_node.mouse_default_cursor_shape = cursor_shape
|
||||||
|
|
||||||
|
if styles.has("font-size"):
|
||||||
|
var font_size = int(styles["font-size"])
|
||||||
|
print("SETTING FONT SIZE: ", font_size, " FOR BUTTON NAME: ", element.tag_name)
|
||||||
|
button_node.add_theme_font_size_override("font_size", font_size)
|
||||||
|
|
||||||
# Apply text color with state-dependent colors
|
# Apply text color with state-dependent colors
|
||||||
apply_button_text_color(button_node, styles, hover_styles, active_styles)
|
apply_button_text_color(button_node, styles, hover_styles, active_styles)
|
||||||
|
|
||||||
@@ -87,12 +83,7 @@ func apply_button_styles(element: HTMLParser.HTMLElement, parser: HTMLParser, na
|
|||||||
# Fallback: if hover is defined but active isn't, use hover for active
|
# Fallback: if hover is defined but active isn't, use hover for active
|
||||||
active_color = hover_color
|
active_color = hover_color
|
||||||
|
|
||||||
apply_button_color_with_states(button_node, normal_color, hover_color, active_color)
|
apply_button_color_with_states(button_node, normal_color, hover_color, active_color, styles)
|
||||||
|
|
||||||
# Apply corner radius
|
|
||||||
if styles.has("border-radius"):
|
|
||||||
var radius = StyleManager.parse_radius(styles["border-radius"])
|
|
||||||
apply_button_radius(button_node, radius)
|
|
||||||
|
|
||||||
var width = null
|
var width = null
|
||||||
var height = null
|
var height = null
|
||||||
@@ -102,16 +93,10 @@ func apply_button_styles(element: HTMLParser.HTMLElement, parser: HTMLParser, na
|
|||||||
if styles.has("height"):
|
if styles.has("height"):
|
||||||
height = SizingUtils.parse_size_value(styles["height"])
|
height = SizingUtils.parse_size_value(styles["height"])
|
||||||
|
|
||||||
# Only apply size flags if there's explicit sizing
|
# Apply explicit sizing if provided
|
||||||
if width != null or height != null:
|
if width != null or height != null:
|
||||||
apply_size_and_flags(self, width, height)
|
apply_size_and_flags(button_node, width, height)
|
||||||
apply_size_and_flags(button_node, width, height, false)
|
# Container will automatically resize to fit the button
|
||||||
else:
|
|
||||||
# Keep the natural sizing we set earlier
|
|
||||||
custom_minimum_size = natural_size
|
|
||||||
# Also ensure the ButtonNode doesn't override our size
|
|
||||||
button_node.custom_minimum_size = Vector2.ZERO
|
|
||||||
button_node.anchors_preset = Control.PRESET_FULL_RECT
|
|
||||||
|
|
||||||
func apply_button_text_color(button: Button, normal_styles: Dictionary, hover_styles: Dictionary, active_styles: Dictionary) -> void:
|
func apply_button_text_color(button: Button, normal_styles: Dictionary, hover_styles: Dictionary, active_styles: Dictionary) -> void:
|
||||||
var normal_color = normal_styles.get("color", Color.WHITE)
|
var normal_color = normal_styles.get("color", Color.WHITE)
|
||||||
@@ -126,16 +111,23 @@ func apply_button_text_color(button: Button, normal_styles: Dictionary, hover_st
|
|||||||
if button.disabled:
|
if button.disabled:
|
||||||
button.add_theme_color_override("font_disabled_color", normal_color)
|
button.add_theme_color_override("font_disabled_color", normal_color)
|
||||||
|
|
||||||
func apply_button_color_with_states(button: Button, normal_color: Color, hover_color: Color, active_color: Color) -> void:
|
func apply_button_color_with_states(button: Button, normal_color: Color, hover_color: Color, active_color: Color, styles: Dictionary = {}) -> void:
|
||||||
var style_normal = StyleBoxFlat.new()
|
var style_normal = StyleBoxFlat.new()
|
||||||
var style_hover = StyleBoxFlat.new()
|
var style_hover = StyleBoxFlat.new()
|
||||||
var style_pressed = StyleBoxFlat.new()
|
var style_pressed = StyleBoxFlat.new()
|
||||||
|
|
||||||
var radius: int = 0
|
var radius: int = 0
|
||||||
|
if styles.has("border-radius"):
|
||||||
|
radius = StyleManager.parse_radius(styles["border-radius"])
|
||||||
|
|
||||||
style_normal.set_corner_radius_all(radius)
|
style_normal.set_corner_radius_all(radius)
|
||||||
style_hover.set_corner_radius_all(radius)
|
style_hover.set_corner_radius_all(radius)
|
||||||
style_pressed.set_corner_radius_all(radius)
|
style_pressed.set_corner_radius_all(radius)
|
||||||
|
|
||||||
|
# Apply padding to all style boxes
|
||||||
|
apply_padding_to_stylebox(style_normal, styles)
|
||||||
|
apply_padding_to_stylebox(style_hover, styles)
|
||||||
|
apply_padding_to_stylebox(style_pressed, styles)
|
||||||
|
|
||||||
# Set normal color
|
# Set normal color
|
||||||
style_normal.bg_color = normal_color
|
style_normal.bg_color = normal_color
|
||||||
@@ -161,28 +153,49 @@ func apply_button_color_with_states(button: Button, normal_color: Color, hover_c
|
|||||||
button.add_theme_stylebox_override("pressed", style_pressed)
|
button.add_theme_stylebox_override("pressed", style_pressed)
|
||||||
|
|
||||||
func apply_button_radius(button: Button, radius: int) -> void:
|
func apply_button_radius(button: Button, radius: int) -> void:
|
||||||
var style_normal = button.get_theme_stylebox("normal")
|
# Radius is now handled in create_button_stylebox
|
||||||
var style_hover = button.get_theme_stylebox("hover")
|
# This method is kept for backward compatibility but is deprecated
|
||||||
var style_pressed = button.get_theme_stylebox("pressed")
|
pass
|
||||||
|
|
||||||
style_normal.set_corner_radius_all(radius)
|
|
||||||
style_hover.set_corner_radius_all(radius)
|
|
||||||
style_pressed.set_corner_radius_all(radius)
|
|
||||||
|
|
||||||
button.add_theme_stylebox_override("normal", style_normal)
|
func apply_padding_to_stylebox(style_box: StyleBoxFlat, styles: Dictionary) -> void:
|
||||||
button.add_theme_stylebox_override("hover", style_hover)
|
# Apply general padding first
|
||||||
button.add_theme_stylebox_override("pressed", style_pressed)
|
if styles.has("padding"):
|
||||||
|
var padding_val = StyleManager.parse_size(styles["padding"])
|
||||||
|
if padding_val != null:
|
||||||
|
style_box.content_margin_top = padding_val
|
||||||
|
style_box.content_margin_right = padding_val
|
||||||
|
style_box.content_margin_bottom = padding_val
|
||||||
|
style_box.content_margin_left = padding_val
|
||||||
|
|
||||||
|
# Apply individual padding overrides
|
||||||
|
if styles.has("padding-top"):
|
||||||
|
var padding_val = StyleManager.parse_size(styles["padding-top"])
|
||||||
|
if padding_val != null:
|
||||||
|
style_box.content_margin_top = padding_val
|
||||||
|
|
||||||
|
if styles.has("padding-right"):
|
||||||
|
var padding_val = StyleManager.parse_size(styles["padding-right"])
|
||||||
|
if padding_val != null:
|
||||||
|
style_box.content_margin_right = padding_val
|
||||||
|
|
||||||
|
if styles.has("padding-bottom"):
|
||||||
|
var padding_val = StyleManager.parse_size(styles["padding-bottom"])
|
||||||
|
if padding_val != null:
|
||||||
|
style_box.content_margin_bottom = padding_val
|
||||||
|
|
||||||
|
if styles.has("padding-left"):
|
||||||
|
var padding_val = StyleManager.parse_size(styles["padding-left"])
|
||||||
|
if padding_val != null:
|
||||||
|
style_box.content_margin_left = padding_val
|
||||||
|
|
||||||
func apply_size_and_flags(ctrl: Control, width: Variant, height: Variant, reset_layout := false) -> void:
|
func apply_size_and_flags(ctrl: Control, width: Variant, height: Variant) -> void:
|
||||||
if width != null or height != null:
|
if width != null or height != null:
|
||||||
ctrl.custom_minimum_size = Vector2(
|
ctrl.custom_minimum_size = Vector2(
|
||||||
width if width != null else ctrl.custom_minimum_size.x,
|
width if width != null else 0,
|
||||||
height if height != null else ctrl.custom_minimum_size.y
|
height if height != null else 0
|
||||||
)
|
)
|
||||||
if width != null:
|
if width != null:
|
||||||
ctrl.size_flags_horizontal = Control.SIZE_SHRINK_BEGIN
|
ctrl.size_flags_horizontal = Control.SIZE_SHRINK_BEGIN
|
||||||
if height != null:
|
if height != null:
|
||||||
ctrl.size_flags_vertical = Control.SIZE_SHRINK_BEGIN
|
ctrl.size_flags_vertical = Control.SIZE_SHRINK_BEGIN
|
||||||
if reset_layout:
|
|
||||||
ctrl.position = Vector2.ZERO
|
|
||||||
ctrl.anchors_preset = Control.PRESET_FULL_RECT
|
|
||||||
|
|||||||
@@ -89,7 +89,7 @@ static func create_stylebox_from_styles(styles: Dictionary = {}, container: Cont
|
|||||||
if styles.size() > 0:
|
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")
|
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:
|
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")
|
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:
|
if has_padding:
|
||||||
# General padding
|
# General padding
|
||||||
@@ -106,27 +106,22 @@ static func create_stylebox_from_styles(styles: Dictionary = {}, container: Cont
|
|||||||
style_box.content_margin_bottom = padding_val
|
style_box.content_margin_bottom = padding_val
|
||||||
|
|
||||||
# Individual padding values override general padding
|
# Individual padding values override general padding
|
||||||
var padding_keys = [["padding-left", "content_margin_left"], ["padding-right", "content_margin_right"], ["padding-top", "content_margin_top"], ["padding-bottom", "content_margin_bottom"]]
|
var padding_mappings = [["padding-left", "content_margin_left"], ["padding-right", "content_margin_right"], ["padding-top", "content_margin_top"], ["padding-bottom", "content_margin_bottom"]]
|
||||||
|
|
||||||
for pair in padding_keys:
|
for mapping in padding_mappings:
|
||||||
var key = pair[0]
|
var style_key = mapping[0]
|
||||||
var property = pair[1]
|
var property_key = mapping[1]
|
||||||
var val = null
|
var val = get_style_or_meta_value(styles, container, style_key)
|
||||||
|
|
||||||
if styles.has(key):
|
if val != null:
|
||||||
val = StyleManager.parse_size(styles[key])
|
style_box.set(property_key, val)
|
||||||
elif container and container.has_meta(key):
|
|
||||||
val = StyleManager.parse_size(container.get_meta(key))
|
|
||||||
|
|
||||||
if val:
|
|
||||||
style_box.set(property, val)
|
|
||||||
|
|
||||||
return style_box
|
return style_box
|
||||||
|
|
||||||
# for AutoSizingFlexContainer
|
# for AutoSizingFlexContainer
|
||||||
static func update_background_panel(container: Control) -> void:
|
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_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 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)
|
var background_panel = get_background_panel(container)
|
||||||
|
|
||||||
if needs_background or needs_padding:
|
if needs_background or needs_padding:
|
||||||
@@ -203,3 +198,10 @@ static func _on_panel_mouse_exited(panel: PanelContainer):
|
|||||||
|
|
||||||
static func needs_background_wrapper(styles: Dictionary) -> bool:
|
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")
|
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
|
||||||
|
|||||||
188
flumi/Scripts/Utils/Lua/Class.gd
Normal file
188
flumi/Scripts/Utils/Lua/Class.gd
Normal file
@@ -0,0 +1,188 @@
|
|||||||
|
extends RefCounted
|
||||||
|
class_name LuaClassListUtils
|
||||||
|
|
||||||
|
static func element_classlist_add_handler(vm: LuauVM, dom_parser: HTMLParser) -> int:
|
||||||
|
vm.luaL_checktype(1, vm.LUA_TTABLE)
|
||||||
|
var css_class: String = vm.luaL_checkstring(2)
|
||||||
|
|
||||||
|
vm.lua_getfield(1, "_element_id")
|
||||||
|
var element_id: String = vm.lua_tostring(-1)
|
||||||
|
vm.lua_pop(1)
|
||||||
|
|
||||||
|
# Find the element
|
||||||
|
var element = dom_parser.find_by_id(element_id)
|
||||||
|
if not element:
|
||||||
|
print("DEBUG: Element not found!")
|
||||||
|
return 0
|
||||||
|
|
||||||
|
# Get classes
|
||||||
|
var current_style = element.get_attribute("style", "")
|
||||||
|
var style_classes = CSSParser.smart_split_utility_classes(current_style) if current_style.length() > 0 else []
|
||||||
|
|
||||||
|
# Add new css_class if not already present
|
||||||
|
if css_class not in style_classes:
|
||||||
|
style_classes.append(css_class)
|
||||||
|
var new_style_attr = " ".join(style_classes)
|
||||||
|
element.set_attribute("style", new_style_attr)
|
||||||
|
trigger_element_restyle(element, dom_parser)
|
||||||
|
else:
|
||||||
|
print("DEBUG: classList.add - Class already exists")
|
||||||
|
|
||||||
|
return 0
|
||||||
|
|
||||||
|
static func element_classlist_remove_handler(vm: LuauVM, dom_parser: HTMLParser) -> int:
|
||||||
|
vm.luaL_checktype(1, vm.LUA_TTABLE)
|
||||||
|
var css_class: String = vm.luaL_checkstring(2)
|
||||||
|
|
||||||
|
vm.lua_getfield(1, "_element_id")
|
||||||
|
var element_id: String = vm.lua_tostring(-1)
|
||||||
|
vm.lua_pop(1)
|
||||||
|
|
||||||
|
# Find the element
|
||||||
|
var element = dom_parser.find_by_id(element_id)
|
||||||
|
if not element:
|
||||||
|
return 0
|
||||||
|
|
||||||
|
# Get style attribute
|
||||||
|
var current_style = element.get_attribute("style", "")
|
||||||
|
if current_style.length() == 0:
|
||||||
|
return 0
|
||||||
|
|
||||||
|
var style_classes = CSSParser.smart_split_utility_classes(current_style)
|
||||||
|
var clean_classes = []
|
||||||
|
for style_cls in style_classes:
|
||||||
|
if style_cls != css_class:
|
||||||
|
clean_classes.append(style_cls)
|
||||||
|
|
||||||
|
# Update style attribute
|
||||||
|
if clean_classes.size() > 0:
|
||||||
|
var new_style_attr = " ".join(clean_classes)
|
||||||
|
element.set_attribute("style", new_style_attr)
|
||||||
|
else:
|
||||||
|
element.attributes.erase("style")
|
||||||
|
|
||||||
|
trigger_element_restyle(element, dom_parser)
|
||||||
|
return 0
|
||||||
|
|
||||||
|
static func element_classlist_toggle_handler(vm: LuauVM, dom_parser: HTMLParser) -> int:
|
||||||
|
vm.luaL_checktype(1, vm.LUA_TTABLE)
|
||||||
|
var css_class: String = vm.luaL_checkstring(2)
|
||||||
|
|
||||||
|
vm.lua_getfield(1, "_element_id")
|
||||||
|
var element_id: String = vm.lua_tostring(-1)
|
||||||
|
vm.lua_pop(1)
|
||||||
|
|
||||||
|
# Find the element
|
||||||
|
var element = dom_parser.find_by_id(element_id)
|
||||||
|
if not element:
|
||||||
|
vm.lua_pushboolean(false)
|
||||||
|
return 1
|
||||||
|
|
||||||
|
# Get style attribute
|
||||||
|
var current_style = element.get_attribute("style", "")
|
||||||
|
var style_classes = CSSParser.smart_split_utility_classes(current_style) if current_style.length() > 0 else []
|
||||||
|
|
||||||
|
var has_css_class = css_class in style_classes
|
||||||
|
|
||||||
|
if has_css_class:
|
||||||
|
# Remove css_class
|
||||||
|
var new_classes = []
|
||||||
|
for style_cls in style_classes:
|
||||||
|
if style_cls != css_class:
|
||||||
|
new_classes.append(style_cls)
|
||||||
|
|
||||||
|
if new_classes.size() > 0:
|
||||||
|
element.set_attribute("style", " ".join(new_classes))
|
||||||
|
else:
|
||||||
|
element.attributes.erase("style")
|
||||||
|
|
||||||
|
vm.lua_pushboolean(false)
|
||||||
|
else:
|
||||||
|
# Add css_class
|
||||||
|
style_classes.append(css_class)
|
||||||
|
element.set_attribute("style", " ".join(style_classes))
|
||||||
|
vm.lua_pushboolean(true)
|
||||||
|
|
||||||
|
trigger_element_restyle(element, dom_parser)
|
||||||
|
return 1
|
||||||
|
|
||||||
|
static func trigger_element_restyle(element: HTMLParser.HTMLElement, dom_parser: HTMLParser) -> void:
|
||||||
|
# Find DOM node for element
|
||||||
|
var element_id = element.get_attribute("id")
|
||||||
|
var dom_node = dom_parser.parse_result.dom_nodes.get(element_id, null)
|
||||||
|
if not dom_node:
|
||||||
|
return
|
||||||
|
|
||||||
|
# margins, wrappers, etc.
|
||||||
|
var updated_dom_node = StyleManager.apply_element_styles(dom_node, element, dom_parser)
|
||||||
|
|
||||||
|
# If the node was wrapped/unwrapped by margin handling, update DOM registration
|
||||||
|
if updated_dom_node != dom_node:
|
||||||
|
dom_parser.parse_result.dom_nodes[element_id] = updated_dom_node
|
||||||
|
dom_node = updated_dom_node
|
||||||
|
|
||||||
|
# Find node
|
||||||
|
var actual_element_node = dom_node
|
||||||
|
if dom_node is MarginContainer and dom_node.name.begins_with("MarginWrapper_"):
|
||||||
|
if dom_node.get_child_count() > 0:
|
||||||
|
actual_element_node = dom_node.get_child(0)
|
||||||
|
|
||||||
|
if actual_element_node is HTMLButton:
|
||||||
|
actual_element_node.apply_button_styles(element, dom_parser)
|
||||||
|
elif element.tag_name == "div":
|
||||||
|
update_div_hover_styles(actual_element_node, element, dom_parser)
|
||||||
|
else:
|
||||||
|
update_element_text_content(actual_element_node, element, dom_parser)
|
||||||
|
|
||||||
|
if actual_element_node.has_method("init"):
|
||||||
|
actual_element_node.init(element, dom_parser)
|
||||||
|
|
||||||
|
static func update_element_text_content(dom_node: Control, element: HTMLParser.HTMLElement, dom_parser: HTMLParser) -> void:
|
||||||
|
# Get node
|
||||||
|
var content_node = dom_node
|
||||||
|
if dom_node is MarginContainer and dom_node.name.begins_with("MarginWrapper_"):
|
||||||
|
if dom_node.get_child_count() > 0:
|
||||||
|
content_node = dom_node.get_child(0)
|
||||||
|
|
||||||
|
# Handle RichTextLabel elements (p, span, etc.)
|
||||||
|
if content_node is RichTextLabel:
|
||||||
|
var styles = dom_parser.get_element_styles_with_inheritance(element, "", [])
|
||||||
|
StyleManager.apply_styles_to_label(content_node, styles, element, dom_parser)
|
||||||
|
return
|
||||||
|
|
||||||
|
# Handle div elements that might contain RichTextLabel children
|
||||||
|
if element.tag_name == "div":
|
||||||
|
update_text_labels_recursive(content_node, element, dom_parser)
|
||||||
|
return
|
||||||
|
|
||||||
|
static func update_text_labels_recursive(node: Node, element: HTMLParser.HTMLElement, dom_parser: HTMLParser) -> void:
|
||||||
|
if node is RichTextLabel:
|
||||||
|
var styles = dom_parser.get_element_styles_with_inheritance(element, "", [])
|
||||||
|
StyleManager.apply_styles_to_label(node, styles, element, dom_parser)
|
||||||
|
return
|
||||||
|
|
||||||
|
for child in node.get_children():
|
||||||
|
update_text_labels_recursive(child, element, dom_parser)
|
||||||
|
|
||||||
|
static func update_div_hover_styles(dom_node: Control, element: HTMLParser.HTMLElement, dom_parser: HTMLParser) -> void:
|
||||||
|
var styles = dom_parser.get_element_styles_with_inheritance(element, "", [])
|
||||||
|
var hover_styles = dom_parser.get_element_styles_with_inheritance(element, "hover", [])
|
||||||
|
|
||||||
|
if dom_node is PanelContainer:
|
||||||
|
var normal_stylebox = BackgroundUtils.create_stylebox_from_styles(styles)
|
||||||
|
dom_node.add_theme_stylebox_override("panel", normal_stylebox)
|
||||||
|
|
||||||
|
if hover_styles.size() > 0:
|
||||||
|
BackgroundUtils.setup_panel_hover_support(dom_node, styles, hover_styles)
|
||||||
|
else:
|
||||||
|
if dom_node.has_meta("normal_stylebox"):
|
||||||
|
dom_node.remove_meta("normal_stylebox")
|
||||||
|
if dom_node.has_meta("hover_stylebox"):
|
||||||
|
dom_node.remove_meta("hover_stylebox")
|
||||||
|
|
||||||
|
if dom_node.mouse_entered.is_connected(BackgroundUtils._on_panel_mouse_entered):
|
||||||
|
dom_node.mouse_entered.disconnect(BackgroundUtils._on_panel_mouse_entered)
|
||||||
|
if dom_node.mouse_exited.is_connected(BackgroundUtils._on_panel_mouse_exited):
|
||||||
|
dom_node.mouse_exited.disconnect(BackgroundUtils._on_panel_mouse_exited)
|
||||||
|
|
||||||
|
update_element_text_content(dom_node, element, dom_parser)
|
||||||
1
flumi/Scripts/Utils/Lua/Class.gd.uid
Normal file
1
flumi/Scripts/Utils/Lua/Class.gd.uid
Normal file
@@ -0,0 +1 @@
|
|||||||
|
uid://dauvw3w3ly087
|
||||||
@@ -38,6 +38,9 @@ static func init_patterns():
|
|||||||
"^border-(t|r|b|l)-\\[.*\\]$", # custom individual border sides (e.g., border-t-[2px])
|
"^border-(t|r|b|l)-\\[.*\\]$", # custom individual border sides (e.g., border-t-[2px])
|
||||||
"^border-(t|r|b|l)-(white|black|transparent|slate-\\d+|gray-\\d+|red-\\d+|green-\\d+|blue-\\d+|yellow-\\d+)$", # individual border side colors
|
"^border-(t|r|b|l)-(white|black|transparent|slate-\\d+|gray-\\d+|red-\\d+|green-\\d+|blue-\\d+|yellow-\\d+)$", # individual border side colors
|
||||||
"^border-(white|black|transparent|slate-\\d+|gray-\\d+|red-\\d+|green-\\d+|blue-\\d+|yellow-\\d+)$", # border colors
|
"^border-(white|black|transparent|slate-\\d+|gray-\\d+|red-\\d+|green-\\d+|blue-\\d+|yellow-\\d+)$", # border colors
|
||||||
|
"^opacity-\\[.*\\]$", # custom opacity values
|
||||||
|
"^z-\\[.*\\]$", # custom z-index values
|
||||||
|
"^cursor-[a-zA-Z-]+$", # cursor types
|
||||||
"^(hover|active):", # pseudo classes
|
"^(hover|active):", # pseudo classes
|
||||||
]
|
]
|
||||||
for pattern in utility_patterns:
|
for pattern in utility_patterns:
|
||||||
|
|||||||
Reference in New Issue
Block a user