width & height inheritance + support w/h on input tags & button

This commit is contained in:
Face
2025-07-28 19:43:19 +03:00
parent 0f061e4352
commit 8ca3337f56
8 changed files with 210 additions and 21 deletions

View File

@@ -11,8 +11,9 @@ script = ExtResource("1_button")
[node name="ButtonNode" type="Button" parent="."]
layout_mode = 1
offset_right = 100.0
offset_bottom = 30.0
anchors_preset = 15
anchor_right = 1.0
anchor_bottom = 1.0
grow_horizontal = 2
grow_vertical = 2
mouse_default_cursor_shape = 2

View File

@@ -71,10 +71,8 @@ layout_mode = 3
anchors_preset = 15
anchor_right = 1.0
anchor_bottom = 1.0
offset_left = -102.0
offset_top = -24.0
offset_right = -1893.0
offset_bottom = -1020.0
offset_right = -1791.0
offset_bottom = -996.0
grow_horizontal = 2
grow_vertical = 2
size_flags_horizontal = 3
@@ -84,7 +82,7 @@ script = ExtResource("1_input")
[node name="LineEdit" type="LineEdit" parent="."]
visible = false
layout_mode = 1
offset_right = 400.0
offset_right = 200.0
offset_bottom = 35.0
theme = ExtResource("2_theme")
text = "test"
@@ -110,7 +108,6 @@ button_group = SubResource("ButtonGroup_06us3")
flat = true
[node name="ColorPickerButton" type="ColorPickerButton" parent="."]
visible = false
layout_mode = 0
offset_right = 83.0
offset_bottom = 35.0
@@ -121,6 +118,7 @@ visible = false
layout_mode = 0
[node name="HSlider" type="HSlider" parent="."]
visible = false
layout_mode = 0
offset_right = 200.0
offset_bottom = 35.0

View File

@@ -123,18 +123,50 @@ func process_styles() -> void:
for child: CSSParser.CSSRule in parse_result.css_parser.stylesheet.rules:
print("INFO: for selector \"%s\" we have props: %s" % [child.selector, child.properties])
func get_element_styles(element: HTMLElement, event: String = "") -> Dictionary:
func get_element_styles_with_inheritance(element: HTMLElement, event: String = "", visited_elements: Array = []) -> Dictionary:
# Prevent infinite recursion
if element in visited_elements:
return {}
visited_elements.append(element)
var styles = {}
styles.merge(parse_result.css_parser.stylesheet.get_styles_for_element(element.tag_name, event))
# Apply inline styles (higher priority) - force override CSS rules
var inline_style = element.get_attribute("style")
if inline_style.length() > 0:
var inline_parsed = CSSParser.parse_inline_style(inline_style)
for property in inline_parsed:
styles[property] = inline_parsed[property]
# Inherit certain properties from parent elements
var inheritable_properties = ["width", "height", "font-size", "color", "font-family"]
var parent_element = element.parent
while parent_element and parent_element.tag_name != "body":
var parent_styles = get_element_styles_internal(parent_element, event)
for property in inheritable_properties:
# Only inherit if child doesn't already have this property
if not styles.has(property) and parent_styles.has(property):
styles[property] = parent_styles[property]
parent_element = parent_element.parent
return styles
func get_element_styles_internal(element: HTMLElement, event: String = "") -> Dictionary:
var styles = {}
# Apply CSS rules
if parse_result.css_parser:
styles.merge(parse_result.css_parser.stylesheet.get_styles_for_element(element.tag_name, event))
# Apply inline styles (higher priority)
# Apply inline styles (higher priority) - force override CSS rules
var inline_style = element.get_attribute("style")
if inline_style.length() > 0:
var inline_parsed = CSSParser.parse_inline_style(inline_style)
styles.merge(inline_parsed)
for property in inline_parsed:
styles[property] = inline_parsed[property] # Force override
return styles
@@ -241,7 +273,7 @@ func get_all_stylesheets() -> Array[String]:
return get_attribute_values("style", "src")
func apply_element_styles(node: Control, element: HTMLElement, parser: HTMLParser) -> void:
var styles = parser.get_element_styles(element)
var styles = parser.get_element_styles_with_inheritance(element, "", [])
if node.get("rich_text_label"):
var label = node.rich_text_label
var text = HTMLParser.get_bbcode_with_styles(element, styles, parser)
@@ -255,7 +287,7 @@ static func get_bbcode_with_styles(element: HTMLElement, styles: Dictionary, par
for child in element.children:
var child_styles = styles
if parser != null:
child_styles = parser.get_element_styles(child)
child_styles = parser.get_element_styles_with_inheritance(child, "", [])
var child_content = HTMLParser.get_bbcode_with_styles(child, child_styles, parser)
match child.tag_name:
"b":

View File

@@ -21,7 +21,7 @@ a { text-[#1a0dab] }
pre { text-xl font-mono }
"""
var HTML_CONTENT = "<head>
var HTML_CONTENT2 = "<head>
<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\">
@@ -230,3 +230,68 @@ So
<span style=\"bg-[#ffffaa] w-12 h-8 self-stretch flex items-center justify-center\">Stretch</span>
</div>
</body>".to_utf8_buffer()
var HTML_CONTENT = """<head>
<title>Task Manager</title>
<icon src="https://cdn-icons-png.flaticon.com/512/126/126472.png">
<meta name="theme-color" content="#1e1e2f">
<meta name="description" content="Manage your tasks easily.">
<style>
h1 { text-[#4ade80] text-2xl font-bold text-center }
p { text-[#94a3b8] text-lg text-center }
button { bg-[#4ade80] text-[#ffffff] hover:bg-[#22c55e] }
input { bg-[#f0f0f0] text-[#111111] w-full }
</style>
<script src="logic.lua" />
</head>
<body>
<h1>📝 My Task Manager</h1>
<p>Keep track of your to-do list</p>
<!-- Task List -->
<div style="flex flex-col gap-2 w-64 bg-[#f8fafc] items-center justify-center">
<span style="flex justify-between items-center bg-[#e2e8f0] w-full h-8">
<span>✅ Finish homework</span>
<button>Delete</button>
</span>
<span style="flex justify-between items-center bg-[#e2e8f0] w-full h-8">
<span>✍️ Write blog post</span>
<button>Delete</button>
</span>
<span style="flex justify-between items-center bg-[#e2e8f0] w-full h-8">
<span>💪 Gym workout</span>
<button>Delete</button>
</span>
</div>
<separator direction="horizontal" />
<!-- Add Task Form -->
<h2 style="text-center">Add a New Task</h2>
<form action="/add-task" method="POST" style="flex flex-col gap-2 items-center justify-center w-xl">
<input type="text" placeholder="Enter text..." />
<input type="password" placeholder="Enter password..." />
<input type="date" />
<input type="color" />
<input type="number" min="0" max="100" />
<input type="range" min="0" max="100" />
<input type="checkbox" />
<input type="radio" name="test" />
<input type="file" />
<button type="submit">Add Task</button>
</form>
<separator direction="horizontal" />
<!-- Categories Section -->
<h2 style="text-center">Task Categories</h2>
<div style="flex flex-row gap-2 justify-center items-center w-64">
<span style="bg-[#fef3c7] w-32 h-8 flex items-center justify-center">📚 Study</span>
<span style="bg-[#d1fae5] w-32 h-8 flex items-center justify-center">💼 Work</span>
<span style="bg-[#e0e7ff] w-32 h-8 flex items-center justify-center">🏋️ Health</span>
</div>
</body>
""".to_utf8_buffer()

View File

@@ -12,10 +12,12 @@ static func parse_size(val):
if val.ends_with("%"):
# Not supported directly, skip
return null
if val == "full":
return null
return float(val)
static func apply_element_styles(node: Control, element: HTMLParser.HTMLElement, parser: HTMLParser) -> Control:
var styles = parser.get_element_styles(element)
var styles = parser.get_element_styles_with_inheritance(element, "", [])
var label = null
if not (node is FlexContainer):
@@ -47,7 +49,6 @@ static func apply_element_styles(node: Control, element: HTMLParser.HTMLElement,
if styles.has("background-color"):
var target_node_for_bg = node if node is FlexContainer else label
if target_node_for_bg:
print("SETTING BACKGROUND FOR ", target_node_for_bg, " TO COLOR: ", styles)
target_node_for_bg.set_meta("custom_css_background_color", styles["background-color"])
if target_node_for_bg.has_method("add_background_rect"):
target_node_for_bg.call_deferred("add_background_rect")

View File

@@ -16,3 +16,40 @@ func init(element: HTMLParser.HTMLElement, parser: HTMLParser = null) -> void:
-1,
button_node.get_theme_default_font_size()
) + Vector2(20, 10) # Add padding
apply_button_styles(element, parser)
func apply_button_styles(element: HTMLParser.HTMLElement, parser: HTMLParser) -> void:
if not element or not parser:
return
StyleManager.apply_element_styles(self, element, parser)
var styles = parser.get_element_styles_with_inheritance(element, "", [])
var width = null
var height = null
if styles.has("width"):
width = StyleManager.parse_size(styles["width"])
if styles.has("height"):
height = StyleManager.parse_size(styles["height"])
var button_node = $ButtonNode
apply_size_and_flags(self, width, height)
apply_size_and_flags(button_node, width, height, false)
func apply_size_and_flags(ctrl: Control, width: Variant, height: Variant, reset_layout := false) -> void:
if width != null or height != null:
ctrl.custom_minimum_size = Vector2(
width if width != null else ctrl.custom_minimum_size.x,
height if height != null else ctrl.custom_minimum_size.y
)
if width != null:
ctrl.size_flags_horizontal = Control.SIZE_SHRINK_BEGIN
if height != null:
ctrl.size_flags_vertical = Control.SIZE_SHRINK_BEGIN
if reset_layout:
ctrl.position = Vector2.ZERO
ctrl.anchors_preset = Control.PRESET_FULL_RECT

View File

@@ -7,7 +7,7 @@ var custom_hex_input: LineEdit
var _file_text_content: String = ""
var _file_binary_content: PackedByteArray = PackedByteArray()
func init(element: HTMLParser.HTMLElement) -> void:
func init(element: HTMLParser.HTMLElement, parser: HTMLParser = null) -> void:
var color_picker_button: ColorPickerButton = $ColorPickerButton
var picker: ColorPicker = color_picker_button.get_picker()
@@ -74,7 +74,6 @@ func init(element: HTMLParser.HTMLElement) -> void:
var active_child = get_node(active_child_name)
active_child.visible = true
custom_minimum_size = active_child.size
match input_type:
"checkbox":
@@ -127,11 +126,16 @@ func init(element: HTMLParser.HTMLElement) -> void:
var line_edit = active_child as LineEdit
line_edit.secret = false
setup_text_input(line_edit, placeholder, value, minlength, maxlength, pattern)
apply_input_styles(element, parser)
func remove_unused_children(keep_child_name: String) -> void:
for child in get_children():
if child.name != keep_child_name:
child.visible = false
child.queue_free()
else:
child.visible = true
func setup_text_input(line_edit: LineEdit, placeholder: String, value: String, minlength: String, maxlength: String, pattern: String) -> void:
if placeholder: line_edit.placeholder_text = placeholder
@@ -289,3 +293,54 @@ func _on_file_selected(path: String) -> void:
file.close()
# TODO: when adding Lua, make these actually usable
func apply_input_styles(element: HTMLParser.HTMLElement, parser: HTMLParser) -> void:
if not element or not parser:
return
StyleManager.apply_element_styles(self, element, parser)
var styles = parser.get_element_styles_with_inheritance(element, "", [])
var width = null
var height = null
if styles.has("width"):
if styles["width"] == "full":
var parent_styles = parser.get_element_styles_with_inheritance(element.parent, "", []) if element.parent else {}
if parent_styles.has("width"):
var parent_width = StyleManager.parse_size(parent_styles["width"])
if parent_width != null:
width = parent_width
else:
width = StyleManager.parse_size(styles["width"])
if styles.has("height"):
height = StyleManager.parse_size(styles["height"])
var active_child = null
for child in get_children():
if child.visible:
active_child = child
break
if active_child and (width != null or height != null):
var new_child_size = Vector2(
width if width != null else active_child.custom_minimum_size.x,
height if height != null 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.size_flags_horizontal = Control.SIZE_SHRINK_BEGIN
if height != null:
active_child.size_flags_vertical = Control.SIZE_SHRINK_BEGIN
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 = new_child_size
custom_minimum_size = new_child_size
if active_child.name == "DateButton":
active_child.anchors_preset = Control.PRESET_TOP_LEFT
active_child.position = Vector2.ZERO

View File

@@ -120,7 +120,7 @@ func contains_hyperlink(element: HTMLParser.HTMLElement) -> bool:
return false
func create_element_node(element: HTMLParser.HTMLElement, parser: HTMLParser) -> Control:
var styles = parser.get_element_styles(element)
var styles = parser.get_element_styles_with_inheritance(element, "", [])
var is_flex_container = styles.has("display") and ("flex" in styles["display"])
var final_node: Control
@@ -214,10 +214,10 @@ func create_element_node_internal(element: HTMLParser.HTMLElement, parser: HTMLP
safe_add_child(node, child_node)
"input":
node = INPUT.instantiate()
node.init(element)
node.init(element, parser)
"button":
node = BUTTON.instantiate()
node.init(element)
node.init(element, parser)
"span", "b", "i", "u", "small", "mark", "code", "a":
node = SPAN.instantiate()
node.init(element)