add button color, corner radius & hover/active states + fix input sizing
This commit is contained in:
@@ -148,7 +148,9 @@ func parse_rule(rule_data: Dictionary) -> CSSRule:
|
|||||||
|
|
||||||
return rule
|
return rule
|
||||||
|
|
||||||
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")
|
||||||
|
# Used as a translation layer for Tailwind-like utility classes, as it becomes easier to manage these programmatically
|
||||||
|
static func parse_utility_class(rule: CSSRule, utility_name: String) -> void:
|
||||||
# Handle color classes like text-[#ff0000]
|
# Handle 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 = extract_bracket_content(utility_name, 5) # after 'text-'
|
var color_value = extract_bracket_content(utility_name, 5) # after 'text-'
|
||||||
@@ -348,10 +350,45 @@ func parse_utility_class(rule: CSSRule, utility_name: String) -> void:
|
|||||||
rule.properties["order"] = val.to_int()
|
rule.properties["order"] = val.to_int()
|
||||||
return
|
return
|
||||||
|
|
||||||
|
# Handle border radius classes like rounded, rounded-lg, rounded-[12px]
|
||||||
|
if utility_name == "rounded":
|
||||||
|
rule.properties["border-radius"] = "4px"
|
||||||
|
return
|
||||||
|
if utility_name == "rounded-none":
|
||||||
|
rule.properties["border-radius"] = "0px"
|
||||||
|
return
|
||||||
|
if utility_name == "rounded-sm":
|
||||||
|
rule.properties["border-radius"] = "2px"
|
||||||
|
return
|
||||||
|
if utility_name == "rounded-md":
|
||||||
|
rule.properties["border-radius"] = "6px"
|
||||||
|
return
|
||||||
|
if utility_name == "rounded-lg":
|
||||||
|
rule.properties["border-radius"] = "8px"
|
||||||
|
return
|
||||||
|
if utility_name == "rounded-xl":
|
||||||
|
rule.properties["border-radius"] = "12px"
|
||||||
|
return
|
||||||
|
if utility_name == "rounded-2xl":
|
||||||
|
rule.properties["border-radius"] = "16px"
|
||||||
|
return
|
||||||
|
if utility_name == "rounded-3xl":
|
||||||
|
rule.properties["border-radius"] = "24px"
|
||||||
|
return
|
||||||
|
if utility_name == "rounded-full":
|
||||||
|
rule.properties["border-radius"] = "9999px"
|
||||||
|
return
|
||||||
|
|
||||||
|
# Handle custom border radius like rounded-[12px]
|
||||||
|
if utility_name.begins_with("rounded-[") and utility_name.ends_with("]"):
|
||||||
|
var radius_value = extract_bracket_content(utility_name, 8) # after 'rounded-'
|
||||||
|
rule.properties["border-radius"] = radius_value
|
||||||
|
return
|
||||||
|
|
||||||
# Handle more utility classes as needed
|
# Handle more utility classes as needed
|
||||||
# Add more cases here for other utilities
|
# Add more cases here for other utilities
|
||||||
|
|
||||||
func parse_size(val: String) -> String:
|
static func parse_size(val: String) -> String:
|
||||||
var named = {
|
var named = {
|
||||||
"0": "0px", "1": "4px", "2": "8px", "3": "12px", "4": "16px", "5": "20px", "6": "24px", "8": "32px", "10": "40px",
|
"0": "0px", "1": "4px", "2": "8px", "3": "12px", "4": "16px", "5": "20px", "6": "24px", "8": "32px", "10": "40px",
|
||||||
"12": "48px", "16": "64px", "20": "80px", "24": "96px", "28": "112px", "32": "128px", "36": "144px", "40": "160px",
|
"12": "48px", "16": "64px", "20": "80px", "24": "96px", "28": "112px", "32": "128px", "36": "144px", "40": "160px",
|
||||||
@@ -372,7 +409,7 @@ func parse_size(val: String) -> String:
|
|||||||
return val
|
return val
|
||||||
|
|
||||||
# Helper to extract content inside first matching brackets after a given index
|
# Helper to extract content inside first matching brackets after a given index
|
||||||
func extract_bracket_content(string: String, start_idx: int) -> String:
|
static func extract_bracket_content(string: String, start_idx: int) -> String:
|
||||||
var open_idx = string.find("[", start_idx)
|
var open_idx = string.find("[", start_idx)
|
||||||
if open_idx == -1:
|
if open_idx == -1:
|
||||||
return ""
|
return ""
|
||||||
@@ -381,7 +418,7 @@ func extract_bracket_content(string: String, start_idx: int) -> String:
|
|||||||
return ""
|
return ""
|
||||||
return string.substr(open_idx + 1, close_idx - open_idx - 1)
|
return string.substr(open_idx + 1, close_idx - open_idx - 1)
|
||||||
|
|
||||||
func parse_color(color_string: String) -> Color:
|
static func parse_color(color_string: String) -> Color:
|
||||||
color_string = color_string.strip_edges()
|
color_string = color_string.strip_edges()
|
||||||
|
|
||||||
# Handle hex colors
|
# Handle hex colors
|
||||||
|
|||||||
@@ -164,12 +164,40 @@ func get_element_styles_internal(element: HTMLElement, event: String = "") -> Di
|
|||||||
# Apply inline styles (higher priority) - force override CSS rules
|
# Apply inline styles (higher priority) - force override CSS rules
|
||||||
var inline_style = element.get_attribute("style")
|
var inline_style = element.get_attribute("style")
|
||||||
if inline_style.length() > 0:
|
if inline_style.length() > 0:
|
||||||
var inline_parsed = CSSParser.parse_inline_style(inline_style)
|
var inline_parsed = parse_inline_style_with_event(inline_style, event)
|
||||||
for property in inline_parsed:
|
for property in inline_parsed:
|
||||||
styles[property] = inline_parsed[property] # Force override
|
styles[property] = inline_parsed[property] # Force override
|
||||||
|
|
||||||
return styles
|
return styles
|
||||||
|
|
||||||
|
func parse_inline_style_with_event(style_string: String, event: String = "") -> Dictionary:
|
||||||
|
var properties = {}
|
||||||
|
|
||||||
|
# Split style string into individual utility classes
|
||||||
|
var utility_classes = style_string.split(" ") # e.g. ["bg-red-500, "text-lg", "hover:bg-blue-500"]
|
||||||
|
|
||||||
|
for utility_name in utility_classes:
|
||||||
|
utility_name = utility_name.strip_edges() # e.g. "bg-red-500"
|
||||||
|
if utility_name.is_empty():
|
||||||
|
continue
|
||||||
|
|
||||||
|
# Check if this utility is for the requested event
|
||||||
|
if event.length() > 0:
|
||||||
|
if utility_name.begins_with(event + ":"): # e.g. "hover:bg-blue-500"
|
||||||
|
var actual_utility = utility_name.substr(event.length() + 1) # bg-blue-500
|
||||||
|
var rule = CSSParser.CSSRule.new()
|
||||||
|
CSSParser.parse_utility_class(rule, actual_utility)
|
||||||
|
for property in rule.properties:
|
||||||
|
properties[property] = rule.properties[property]
|
||||||
|
else:
|
||||||
|
if not utility_name.contains(":"):
|
||||||
|
var rule = CSSParser.CSSRule.new()
|
||||||
|
CSSParser.parse_utility_class(rule, utility_name)
|
||||||
|
for property in rule.properties:
|
||||||
|
properties[property] = rule.properties[property]
|
||||||
|
|
||||||
|
return properties
|
||||||
|
|
||||||
# Creates element from CURRENT xml parser node
|
# Creates element from CURRENT xml parser node
|
||||||
func create_element() -> HTMLElement:
|
func create_element() -> HTMLElement:
|
||||||
var element = HTMLElement.new(xml_parser.get_node_name())
|
var element = HTMLElement.new(xml_parser.get_node_name())
|
||||||
|
|||||||
@@ -31,6 +31,7 @@ var HTML_CONTENT2 = "<head>
|
|||||||
<style>
|
<style>
|
||||||
h1 { text-[#ff0000] font-italic hover:text-[#00ff00] }
|
h1 { text-[#ff0000] font-italic hover:text-[#00ff00] }
|
||||||
p { text-[#333333] text-2xl }
|
p { text-[#333333] text-2xl }
|
||||||
|
button { hover:bg-[#FF6B35] hover:text-[#FFFFFF] active:bg-[#CC5429] active:text-[#F0F0F0] }
|
||||||
</style>
|
</style>
|
||||||
<style src=\"styles.css\">
|
<style src=\"styles.css\">
|
||||||
<script src=\"script.lua\" />
|
<script src=\"script.lua\" />
|
||||||
@@ -116,10 +117,6 @@ So
|
|||||||
<h2>File Upload</h2>
|
<h2>File Upload</h2>
|
||||||
<input type=\"file\" accept=\".txt,.pdf,image/*\" />
|
<input type=\"file\" accept=\".txt,.pdf,image/*\" />
|
||||||
|
|
||||||
<input type=\"password\" placeholder=\"your password...\" />
|
|
||||||
<button type=\"submit\">Submit</button>
|
|
||||||
</form>
|
|
||||||
|
|
||||||
<separator direction=\"horizontal\" />
|
<separator direction=\"horizontal\" />
|
||||||
# Ordered list
|
# Ordered list
|
||||||
<ol>
|
<ol>
|
||||||
@@ -241,7 +238,6 @@ var HTML_CONTENT = """<head>
|
|||||||
<style>
|
<style>
|
||||||
h1 { text-[#4ade80] text-3xl font-bold }
|
h1 { text-[#4ade80] text-3xl font-bold }
|
||||||
p { text-[#94a3b8] text-lg }
|
p { text-[#94a3b8] text-lg }
|
||||||
button { bg-[#4ade80] text-[#ffffff] hover:bg-[#22c55e] }
|
|
||||||
input { border border-[#cbd5e1] px-2 py-1 rounded }
|
input { border border-[#cbd5e1] px-2 py-1 rounded }
|
||||||
</style>
|
</style>
|
||||||
|
|
||||||
@@ -256,15 +252,15 @@ var HTML_CONTENT = """<head>
|
|||||||
<div style="flex flex-col gap-2 w-80 mx-auto bg-[#f8fafc] p-4 rounded">
|
<div style="flex flex-col gap-2 w-80 mx-auto bg-[#f8fafc] p-4 rounded">
|
||||||
<span style="flex justify-between items-center bg-[#e2e8f0] px-2 py-1 rounded">
|
<span style="flex justify-between items-center bg-[#e2e8f0] px-2 py-1 rounded">
|
||||||
<span>✅ Finish homework</span>
|
<span>✅ Finish homework</span>
|
||||||
<button>Delete</button>
|
<button style="bg-[#4ade80] text-[#ffffff] hover:bg-[#22c55e]">Delete</button>
|
||||||
</span>
|
</span>
|
||||||
<span style="flex justify-between items-center bg-[#e2e8f0] px-2 py-1 rounded">
|
<span style="flex justify-between items-center bg-[#e2e8f0] px-2 py-1 rounded">
|
||||||
<span>✍️ Write blog post</span>
|
<span>✍️ Write blog post</span>
|
||||||
<button>Delete</button>
|
<button style="bg-[#4ade80] text-[#ffffff] hover:bg-[#22c55e]">Delete</button>
|
||||||
</span>
|
</span>
|
||||||
<span style="flex justify-between items-center bg-[#e2e8f0] px-2 py-1 rounded">
|
<span style="flex justify-between items-center bg-[#e2e8f0] px-2 py-1 rounded">
|
||||||
<span>💪 Gym workout</span>
|
<span>💪 Gym workout</span>
|
||||||
<button>Delete</button>
|
<button style="bg-[#4ade80] text-[#ffffff] hover:bg-[#22c55e]">Delete</button>
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@@ -275,7 +271,7 @@ var HTML_CONTENT = """<head>
|
|||||||
<form action="/add-task" method="POST" style="flex flex-col gap-2 w-80 mx-auto">
|
<form action="/add-task" method="POST" style="flex flex-col gap-2 w-80 mx-auto">
|
||||||
<input type="text" placeholder="Enter task..." minlength="3" required="true" />
|
<input type="text" placeholder="Enter task..." minlength="3" required="true" />
|
||||||
<input type="date" />
|
<input type="date" />
|
||||||
<button type="submit">Add Task</button>
|
<button type="submit" style="bg-[#4ade80] text-[#ffffff] hover:bg-[#22c55e]">Add Task</button>
|
||||||
</form>
|
</form>
|
||||||
|
|
||||||
<separator direction="horizontal" />
|
<separator direction="horizontal" />
|
||||||
@@ -286,5 +282,70 @@ var HTML_CONTENT = """<head>
|
|||||||
<span style="bg-[#d1fae5] px-4 py-2 rounded">💼 Work</span>
|
<span style="bg-[#d1fae5] px-4 py-2 rounded">💼 Work</span>
|
||||||
<span style="bg-[#e0e7ff] px-4 py-2 rounded">🏋️ Health</span>
|
<span style="bg-[#e0e7ff] px-4 py-2 rounded">🏋️ Health</span>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<form>
|
||||||
|
<input type=\"password\" placeholder=\"your password...\" />
|
||||||
|
<button type=\"submit\" style=\"bg-[#4CAF50] rounded-lg text-[#FFFFFF]\">Submit</button>
|
||||||
|
<button style=\"bg-[#2196F3] rounded-xl text-[#FFFFFF]\">Blue Button</button>
|
||||||
|
<button style=\"bg-[#FF5722] rounded-full text-[#FFFFFF]\">Orange Pill</button>
|
||||||
|
<button style=\"bg-[#9C27B0] rounded-[20px] text-[#FFFFFF]\">Purple Custom</button>
|
||||||
|
<button style=\"bg-[#FFD700] rounded text-[#000000] hover:bg-[#FFA500] hover:text-[#FFFFFF]\">Hover Test</button>
|
||||||
|
</form>
|
||||||
|
|
||||||
|
<h2>Button Style Tests</h2>
|
||||||
|
|
||||||
|
<button>Normal, no-styling button.</button>
|
||||||
|
|
||||||
|
<h3>Corner Radius Variants</h3>
|
||||||
|
<button style=\"bg-[#E74C3C] text-[#FFFFFF] rounded-none\">No Radius</button>
|
||||||
|
<button style=\"bg-[#E74C3C] text-[#FFFFFF] rounded-sm\">Small (2px)</button>
|
||||||
|
<button style=\"bg-[#E74C3C] text-[#FFFFFF] rounded\">Default (4px)</button>
|
||||||
|
<button style=\"bg-[#E74C3C] text-[#FFFFFF] rounded-md\">Medium (6px)</button>
|
||||||
|
<button style=\"bg-[#E74C3C] text-[#FFFFFF] rounded-lg\">Large (8px)</button>
|
||||||
|
<button style=\"bg-[#E74C3C] text-[#FFFFFF] rounded-xl\">Extra Large (12px)</button>
|
||||||
|
<button style=\"bg-[#E74C3C] text-[#FFFFFF] rounded-2xl\">2XL (16px)</button>
|
||||||
|
<button style=\"bg-[#E74C3C] text-[#FFFFFF] rounded-3xl\">3XL (24px)</button>
|
||||||
|
<button style=\"bg-[#E74C3C] text-[#FFFFFF] rounded-full\">Full (Pill)</button>
|
||||||
|
<button style=\"bg-[#E74C3C] text-[#FFFFFF] rounded-[30px]\">Custom 30px</button>
|
||||||
|
|
||||||
|
<h3>Color Combinations</h3>
|
||||||
|
<button style=\"bg-[#FF6B6B] text-[#FFFFFF] rounded-lg\">Red Background</button>
|
||||||
|
<button style=\"bg-[#4ECDC4] text-[#2C3E50] rounded-lg\">Teal & Dark Text</button>
|
||||||
|
<button style=\"bg-[#45B7D1] text-[#FFFFFF] rounded-lg\">Sky Blue</button>
|
||||||
|
<button style=\"bg-[#96CEB4] text-[#2C3E50] rounded-lg\">Mint Green</button>
|
||||||
|
<button style=\"bg-[#FFEAA7] text-[#2D3436] rounded-lg\">Yellow Cream</button>
|
||||||
|
<button style=\"bg-[#DDA0DD] text-[#FFFFFF] rounded-lg\">Plum Purple</button>
|
||||||
|
<button style=\"bg-[#98D8C8] text-[#2C3E50] rounded-lg\">Seafoam</button>
|
||||||
|
|
||||||
|
<h3>Hover Effects</h3>
|
||||||
|
<button style=\"bg-[#3498DB] text-[#FFFFFF] rounded-lg hover:bg-[#2980B9] hover:text-[#F8F9FA]\">Blue Hover</button>
|
||||||
|
<button style=\"bg-[#E67E22] text-[#FFFFFF] rounded-xl hover:bg-[#D35400] hover:text-[#ECF0F1]\">Orange Hover</button>
|
||||||
|
<button style=\"bg-[#9B59B6] text-[#FFFFFF] rounded-full hover:bg-[#8E44AD] hover:text-[#F4F4F4]\">Purple Pill Hover</button>
|
||||||
|
<button style=\"bg-[#1ABC9C] text-[#FFFFFF] rounded-2xl hover:bg-[#16A085]\">Turquoise Hover</button>
|
||||||
|
|
||||||
|
<h3>Advanced Hover Combinations</h3>
|
||||||
|
<button style=\"bg-[#34495E] text-[#ECF0F1] rounded hover:bg-[#E74C3C] hover:text-[#FFFFFF]\">Dark to Red</button>
|
||||||
|
<button style=\"bg-[#F39C12] text-[#2C3E50] rounded-lg hover:bg-[#27AE60] hover:text-[#FFFFFF]\">Gold to Green</button>
|
||||||
|
<button style=\"bg-[#FFFFFF] text-[#2C3E50] rounded-xl hover:bg-[#2C3E50] hover:text-[#FFFFFF]\">Light to Dark</button>
|
||||||
|
|
||||||
|
<h3>Text Color Focus</h3>
|
||||||
|
<button style=\"text-[#E74C3C] rounded-lg\">Red Text Only</button>
|
||||||
|
<button style=\"text-[#27AE60] rounded-lg\">Green Text Only</button>
|
||||||
|
<button style=\"text-[#3498DB] rounded-lg\">Blue Text Only</button>
|
||||||
|
<button style=\"text-[#9B59B6] rounded-full\">Purple Text Pill</button>
|
||||||
|
|
||||||
|
<h3>Mixed Styles</h3>
|
||||||
|
<button style=\"bg-[#FF7675] text-[#FFFFFF] rounded-[15px] hover:bg-[#FD79A8] hover:text-[#2D3436]\">Custom Mix 1</button>
|
||||||
|
<button style=\"bg-[#6C5CE7] text-[#DDD] rounded-3xl hover:bg-[#A29BFE] hover:text-[#2D3436]\">Custom Mix 2</button>
|
||||||
|
<button style=\"bg-[#00B894] text-[#FFFFFF] rounded-[25px] hover:bg-[#00CEC9] hover:text-[#2D3436]\">Custom Mix 3</button>
|
||||||
|
<button style=\"bg-[#0000ff] text-[#FFFFFF] rounded-[25px] hover:bg-[#ff0000] hover:text-[#2D3436]\">Blue normal, red hover</button>
|
||||||
|
|
||||||
|
<h3>Active State Tests</h3>
|
||||||
|
<button style=\"bg-[#3498DB] text-[#FFFFFF] rounded-lg hover:bg-[#2980B9] active:bg-[#1F618D] active:text-[#F8F9FA]\">Blue with Active</button>
|
||||||
|
<button style=\"bg-[#E74C3C] text-[#FFFFFF] rounded-xl hover:bg-[#C0392B] active:bg-[#A93226] active:text-[#ECF0F1]\">Red with Active</button>
|
||||||
|
<button style=\"bg-[#27AE60] text-[#FFFFFF] rounded-full hover:bg-[#229954] active:bg-[#1E8449] active:text-[#D5DBDB]\">Green Pill Active</button>
|
||||||
|
<button style=\"bg-[#F39C12] text-[#2C3E50] rounded hover:bg-[#E67E22] hover:text-[#FFFFFF] active:bg-[#D35400] active:text-[#F7F9FC]\">Gold Multi-State</button>
|
||||||
|
<button style=\"bg-[#9B59B6] text-[#FFFFFF] rounded-2xl active:bg-[#7D3C98] active:text-[#E8DAEF]\">Purple Active Only</button>
|
||||||
|
|
||||||
</body>
|
</body>
|
||||||
""".to_utf8_buffer()
|
""".to_utf8_buffer()
|
||||||
|
|||||||
@@ -272,3 +272,13 @@ static func should_skip_sizing(node: Control, element: HTMLParser.HTMLElement, p
|
|||||||
return true
|
return true
|
||||||
|
|
||||||
return false
|
return false
|
||||||
|
|
||||||
|
static func parse_radius(radius_str: String) -> int:
|
||||||
|
if radius_str.ends_with("px"):
|
||||||
|
return int(radius_str.replace("px", ""))
|
||||||
|
elif radius_str.ends_with("rem"):
|
||||||
|
return int(radius_str.replace("rem", "")) * 16
|
||||||
|
elif radius_str.is_valid_float():
|
||||||
|
return int(radius_str)
|
||||||
|
else:
|
||||||
|
return 0
|
||||||
|
|||||||
@@ -1,6 +1,11 @@
|
|||||||
extends Control
|
extends Control
|
||||||
|
|
||||||
|
var current_element: HTMLParser.HTMLElement
|
||||||
|
var current_parser: HTMLParser
|
||||||
|
|
||||||
func init(element: HTMLParser.HTMLElement, parser: HTMLParser = null) -> void:
|
func init(element: HTMLParser.HTMLElement, parser: HTMLParser = null) -> void:
|
||||||
|
current_element = element
|
||||||
|
current_parser = parser
|
||||||
var button_node: Button = $ButtonNode
|
var button_node: Button = $ButtonNode
|
||||||
|
|
||||||
var button_text = element.text_content.strip_edges()
|
var button_text = element.text_content.strip_edges()
|
||||||
@@ -34,9 +39,30 @@ func apply_button_styles(element: HTMLParser.HTMLElement, parser: HTMLParser, na
|
|||||||
return
|
return
|
||||||
|
|
||||||
var styles = parser.get_element_styles_internal(element, "")
|
var styles = parser.get_element_styles_internal(element, "")
|
||||||
|
var hover_styles = parser.get_element_styles_internal(element, "hover")
|
||||||
|
var active_styles = parser.get_element_styles_internal(element, "active")
|
||||||
|
var button_node = $ButtonNode
|
||||||
|
|
||||||
|
# Apply text color with state-dependent colors
|
||||||
|
apply_button_text_color(button_node, styles, hover_styles, active_styles)
|
||||||
|
|
||||||
|
# Apply background color (hover: + active:)
|
||||||
if styles.has("background-color"):
|
if styles.has("background-color"):
|
||||||
set_meta("custom_css_background_color", styles["background-color"])
|
var normal_color = styles["background-color"] as Color
|
||||||
|
var hover_color: Color = Color()
|
||||||
|
var active_color: Color = Color()
|
||||||
|
|
||||||
|
if hover_styles.has("background-color"):
|
||||||
|
hover_color = hover_styles["background-color"] as Color
|
||||||
|
if active_styles.has("background-color"):
|
||||||
|
active_color = active_styles["background-color"] as Color
|
||||||
|
|
||||||
|
apply_button_color_with_states(button_node, normal_color, hover_color, active_color)
|
||||||
|
|
||||||
|
# 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
|
||||||
@@ -46,8 +72,6 @@ func apply_button_styles(element: HTMLParser.HTMLElement, parser: HTMLParser, na
|
|||||||
if styles.has("height"):
|
if styles.has("height"):
|
||||||
height = StyleManager.parse_size(styles["height"])
|
height = StyleManager.parse_size(styles["height"])
|
||||||
|
|
||||||
var button_node = $ButtonNode
|
|
||||||
|
|
||||||
# Only apply size flags if there's explicit sizing
|
# Only apply size flags if there's explicit sizing
|
||||||
if width != null or height != null:
|
if width != null or height != null:
|
||||||
apply_size_and_flags(self, width, height)
|
apply_size_and_flags(self, width, height)
|
||||||
@@ -59,6 +83,65 @@ func apply_button_styles(element: HTMLParser.HTMLElement, parser: HTMLParser, na
|
|||||||
button_node.custom_minimum_size = Vector2.ZERO
|
button_node.custom_minimum_size = Vector2.ZERO
|
||||||
button_node.anchors_preset = Control.PRESET_FULL_RECT
|
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:
|
||||||
|
var normal_color = normal_styles.get("color", Color.WHITE)
|
||||||
|
var hover_color = hover_styles.get("color", normal_color)
|
||||||
|
var active_color = active_styles.get("color", hover_color)
|
||||||
|
|
||||||
|
button.add_theme_color_override("font_color", normal_color)
|
||||||
|
button.add_theme_color_override("font_hover_color", hover_color)
|
||||||
|
button.add_theme_color_override("font_pressed_color", active_color)
|
||||||
|
button.add_theme_color_override("font_focus_color", normal_color)
|
||||||
|
|
||||||
|
func apply_button_color_with_states(button: Button, normal_color: Color, hover_color: Color, active_color: Color) -> void:
|
||||||
|
var existing_normal: StyleBoxFlat = button.get_theme_stylebox("normal") if button.has_theme_stylebox_override("normal") else null
|
||||||
|
|
||||||
|
var style_normal = StyleBoxFlat.new()
|
||||||
|
var style_hover = StyleBoxFlat.new()
|
||||||
|
var style_pressed = StyleBoxFlat.new()
|
||||||
|
|
||||||
|
var radius: int = existing_normal.corner_radius_top_left if existing_normal else 0
|
||||||
|
|
||||||
|
style_normal.set_corner_radius_all(radius)
|
||||||
|
style_hover.set_corner_radius_all(radius)
|
||||||
|
style_pressed.set_corner_radius_all(radius)
|
||||||
|
|
||||||
|
# Set normal color
|
||||||
|
style_normal.bg_color = normal_color
|
||||||
|
|
||||||
|
# Set hover: color
|
||||||
|
# If hover isn't default, use it
|
||||||
|
if hover_color != Color():
|
||||||
|
style_hover.bg_color = hover_color
|
||||||
|
else:
|
||||||
|
# If no hover, fallback to normal color
|
||||||
|
style_hover.bg_color = normal_color
|
||||||
|
|
||||||
|
# Set active: color
|
||||||
|
if active_color != Color():
|
||||||
|
style_pressed.bg_color = active_color
|
||||||
|
elif hover_color != Color():
|
||||||
|
style_pressed.bg_color = hover_color # Fallback to hover if defined
|
||||||
|
else:
|
||||||
|
style_pressed.bg_color = normal_color # Final fallback to normal
|
||||||
|
|
||||||
|
button.add_theme_stylebox_override("normal", style_normal)
|
||||||
|
button.add_theme_stylebox_override("hover", style_hover)
|
||||||
|
button.add_theme_stylebox_override("pressed", style_pressed)
|
||||||
|
|
||||||
|
func apply_button_radius(button: Button, radius: int) -> void:
|
||||||
|
var style_normal = button.get_theme_stylebox("normal")
|
||||||
|
var style_hover = button.get_theme_stylebox("hover")
|
||||||
|
var style_pressed = button.get_theme_stylebox("pressed")
|
||||||
|
|
||||||
|
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)
|
||||||
|
button.add_theme_stylebox_override("hover", style_hover)
|
||||||
|
button.add_theme_stylebox_override("pressed", style_pressed)
|
||||||
|
|
||||||
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, reset_layout := false) -> void:
|
||||||
if width != null or height != null:
|
if width != null or height != null:
|
||||||
ctrl.custom_minimum_size = Vector2(
|
ctrl.custom_minimum_size = Vector2(
|
||||||
|
|||||||
@@ -310,7 +310,7 @@ func apply_input_styles(element: HTMLParser.HTMLElement, parser: HTMLParser) ->
|
|||||||
var parent_styles = parser.get_element_styles_with_inheritance(element.parent, "", []) if element.parent else {}
|
var parent_styles = parser.get_element_styles_with_inheritance(element.parent, "", []) if element.parent else {}
|
||||||
if parent_styles.has("width"):
|
if parent_styles.has("width"):
|
||||||
var parent_width = StyleManager.parse_size(parent_styles["width"])
|
var parent_width = StyleManager.parse_size(parent_styles["width"])
|
||||||
if parent_width != null:
|
if parent_width:
|
||||||
width = parent_width
|
width = parent_width
|
||||||
else:
|
else:
|
||||||
width = StyleManager.parse_size(styles["width"])
|
width = StyleManager.parse_size(styles["width"])
|
||||||
@@ -323,23 +323,44 @@ func apply_input_styles(element: HTMLParser.HTMLElement, parser: HTMLParser) ->
|
|||||||
active_child = child
|
active_child = child
|
||||||
break
|
break
|
||||||
|
|
||||||
if active_child and (width != null or height != null):
|
if active_child:
|
||||||
var new_child_size = Vector2(
|
if width or height:
|
||||||
width if width != null else active_child.custom_minimum_size.x,
|
# Explicit sizing from CSS
|
||||||
height if height != null else max(active_child.custom_minimum_size.y, active_child.size.y)
|
var new_child_size = Vector2(
|
||||||
)
|
width if width else active_child.custom_minimum_size.x,
|
||||||
|
height if height else max(active_child.custom_minimum_size.y, active_child.size.y)
|
||||||
active_child.custom_minimum_size = new_child_size
|
)
|
||||||
|
|
||||||
if width != null:
|
active_child.custom_minimum_size = new_child_size
|
||||||
active_child.size_flags_horizontal = Control.SIZE_SHRINK_BEGIN
|
|
||||||
if height != null:
|
if width:
|
||||||
active_child.size_flags_vertical = Control.SIZE_SHRINK_BEGIN
|
active_child.size_flags_horizontal = Control.SIZE_SHRINK_BEGIN
|
||||||
|
if height:
|
||||||
if active_child.size.x < new_child_size.x or (new_child_size.y > 0 and active_child.size.y < new_child_size.y):
|
active_child.size_flags_vertical = Control.SIZE_SHRINK_BEGIN
|
||||||
active_child.size = new_child_size
|
|
||||||
|
if active_child.size.x < new_child_size.x or (new_child_size.y > 0 and active_child.size.y < new_child_size.y):
|
||||||
custom_minimum_size = new_child_size
|
active_child.size = new_child_size
|
||||||
|
|
||||||
|
custom_minimum_size = new_child_size
|
||||||
|
|
||||||
|
# Root Control adjusts size flags to match child
|
||||||
|
if width:
|
||||||
|
size_flags_horizontal = Control.SIZE_SHRINK_BEGIN
|
||||||
|
else:
|
||||||
|
size_flags_horizontal = Control.SIZE_EXPAND_FILL
|
||||||
|
if height:
|
||||||
|
size_flags_vertical = Control.SIZE_SHRINK_BEGIN
|
||||||
|
else:
|
||||||
|
size_flags_vertical = Control.SIZE_SHRINK_CENTER
|
||||||
|
else:
|
||||||
|
# No explicit CSS sizing - sync root Control with child's natural size
|
||||||
|
var child_natural_size = active_child.get_combined_minimum_size()
|
||||||
|
if child_natural_size == Vector2.ZERO:
|
||||||
|
child_natural_size = active_child.size
|
||||||
|
|
||||||
|
custom_minimum_size = child_natural_size
|
||||||
|
size_flags_horizontal = Control.SIZE_SHRINK_BEGIN
|
||||||
|
size_flags_vertical = Control.SIZE_SHRINK_CENTER
|
||||||
|
|
||||||
if active_child.name == "DateButton":
|
if active_child.name == "DateButton":
|
||||||
active_child.anchors_preset = Control.PRESET_TOP_LEFT
|
active_child.anchors_preset = Control.PRESET_TOP_LEFT
|
||||||
|
|||||||
@@ -164,8 +164,15 @@ func create_element_node(element: HTMLParser.HTMLElement, parser: HTMLParser) ->
|
|||||||
# Apply flex ITEM properties
|
# Apply flex ITEM properties
|
||||||
StyleManager.apply_flex_item_properties(final_node, styles)
|
StyleManager.apply_flex_item_properties(final_node, styles)
|
||||||
|
|
||||||
# Add child elements (but NOT for ul/ol which handle their own children)
|
# Skip ul/ol and non-flex forms, they handle their own children
|
||||||
if element.tag_name != "ul" and element.tag_name != "ol":
|
var skip_general_processing = false
|
||||||
|
|
||||||
|
if element.tag_name == "ul" or element.tag_name == "ol":
|
||||||
|
skip_general_processing = true
|
||||||
|
elif element.tag_name == "form":
|
||||||
|
skip_general_processing = not is_flex_container
|
||||||
|
|
||||||
|
if not skip_general_processing:
|
||||||
for child_element in element.children:
|
for child_element in element.children:
|
||||||
# Only add child nodes if the child is NOT an inline element
|
# Only add child nodes if the child is NOT an inline element
|
||||||
# UNLESS the parent is a flex container (inline elements become flex items)
|
# UNLESS the parent is a flex container (inline elements become flex items)
|
||||||
@@ -205,13 +212,21 @@ func create_element_node_internal(element: HTMLParser.HTMLElement, parser: HTMLP
|
|||||||
node = SEPARATOR.instantiate()
|
node = SEPARATOR.instantiate()
|
||||||
node.init(element)
|
node.init(element)
|
||||||
"form":
|
"form":
|
||||||
node = FORM.instantiate()
|
var form_styles = parser.get_element_styles_with_inheritance(element, "", [])
|
||||||
node.init(element)
|
var is_flex_form = form_styles.has("display") and ("flex" in form_styles["display"])
|
||||||
|
|
||||||
# Forms need to manually process their children
|
if is_flex_form:
|
||||||
for child_element in element.children:
|
# Don't create a form node here - return null so general processing takes over
|
||||||
var child_node = await create_element_node(child_element, parser)
|
return null
|
||||||
safe_add_child(node, child_node)
|
else:
|
||||||
|
node = FORM.instantiate()
|
||||||
|
node.init(element)
|
||||||
|
|
||||||
|
# Manually process children for non-flex forms
|
||||||
|
for child_element in element.children:
|
||||||
|
var child_node = await create_element_node(child_element, parser)
|
||||||
|
if child_node:
|
||||||
|
safe_add_child(node, child_node)
|
||||||
"input":
|
"input":
|
||||||
node = INPUT.instantiate()
|
node = INPUT.instantiate()
|
||||||
node.init(element, parser)
|
node.init(element, parser)
|
||||||
|
|||||||
Reference in New Issue
Block a user