width & height inheritance + support w/h on input tags & button
This commit is contained in:
@@ -11,8 +11,9 @@ script = ExtResource("1_button")
|
|||||||
|
|
||||||
[node name="ButtonNode" type="Button" parent="."]
|
[node name="ButtonNode" type="Button" parent="."]
|
||||||
layout_mode = 1
|
layout_mode = 1
|
||||||
offset_right = 100.0
|
anchors_preset = 15
|
||||||
offset_bottom = 30.0
|
anchor_right = 1.0
|
||||||
|
anchor_bottom = 1.0
|
||||||
grow_horizontal = 2
|
grow_horizontal = 2
|
||||||
grow_vertical = 2
|
grow_vertical = 2
|
||||||
mouse_default_cursor_shape = 2
|
mouse_default_cursor_shape = 2
|
||||||
|
|||||||
@@ -71,10 +71,8 @@ layout_mode = 3
|
|||||||
anchors_preset = 15
|
anchors_preset = 15
|
||||||
anchor_right = 1.0
|
anchor_right = 1.0
|
||||||
anchor_bottom = 1.0
|
anchor_bottom = 1.0
|
||||||
offset_left = -102.0
|
offset_right = -1791.0
|
||||||
offset_top = -24.0
|
offset_bottom = -996.0
|
||||||
offset_right = -1893.0
|
|
||||||
offset_bottom = -1020.0
|
|
||||||
grow_horizontal = 2
|
grow_horizontal = 2
|
||||||
grow_vertical = 2
|
grow_vertical = 2
|
||||||
size_flags_horizontal = 3
|
size_flags_horizontal = 3
|
||||||
@@ -84,7 +82,7 @@ script = ExtResource("1_input")
|
|||||||
[node name="LineEdit" type="LineEdit" parent="."]
|
[node name="LineEdit" type="LineEdit" parent="."]
|
||||||
visible = false
|
visible = false
|
||||||
layout_mode = 1
|
layout_mode = 1
|
||||||
offset_right = 400.0
|
offset_right = 200.0
|
||||||
offset_bottom = 35.0
|
offset_bottom = 35.0
|
||||||
theme = ExtResource("2_theme")
|
theme = ExtResource("2_theme")
|
||||||
text = "test"
|
text = "test"
|
||||||
@@ -110,7 +108,6 @@ button_group = SubResource("ButtonGroup_06us3")
|
|||||||
flat = true
|
flat = true
|
||||||
|
|
||||||
[node name="ColorPickerButton" type="ColorPickerButton" parent="."]
|
[node name="ColorPickerButton" type="ColorPickerButton" parent="."]
|
||||||
visible = false
|
|
||||||
layout_mode = 0
|
layout_mode = 0
|
||||||
offset_right = 83.0
|
offset_right = 83.0
|
||||||
offset_bottom = 35.0
|
offset_bottom = 35.0
|
||||||
@@ -121,6 +118,7 @@ visible = false
|
|||||||
layout_mode = 0
|
layout_mode = 0
|
||||||
|
|
||||||
[node name="HSlider" type="HSlider" parent="."]
|
[node name="HSlider" type="HSlider" parent="."]
|
||||||
|
visible = false
|
||||||
layout_mode = 0
|
layout_mode = 0
|
||||||
offset_right = 200.0
|
offset_right = 200.0
|
||||||
offset_bottom = 35.0
|
offset_bottom = 35.0
|
||||||
|
|||||||
@@ -123,18 +123,50 @@ func process_styles() -> void:
|
|||||||
for child: CSSParser.CSSRule in parse_result.css_parser.stylesheet.rules:
|
for child: CSSParser.CSSRule in parse_result.css_parser.stylesheet.rules:
|
||||||
print("INFO: for selector \"%s\" we have props: %s" % [child.selector, child.properties])
|
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 = {}
|
var styles = {}
|
||||||
|
|
||||||
# Apply CSS rules
|
# Apply CSS rules
|
||||||
if parse_result.css_parser:
|
if parse_result.css_parser:
|
||||||
styles.merge(parse_result.css_parser.stylesheet.get_styles_for_element(element.tag_name, event))
|
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")
|
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 = CSSParser.parse_inline_style(inline_style)
|
||||||
styles.merge(inline_parsed)
|
for property in inline_parsed:
|
||||||
|
styles[property] = inline_parsed[property] # Force override
|
||||||
|
|
||||||
return styles
|
return styles
|
||||||
|
|
||||||
@@ -241,7 +273,7 @@ func get_all_stylesheets() -> Array[String]:
|
|||||||
return get_attribute_values("style", "src")
|
return get_attribute_values("style", "src")
|
||||||
|
|
||||||
func apply_element_styles(node: Control, element: HTMLElement, parser: HTMLParser) -> void:
|
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"):
|
if node.get("rich_text_label"):
|
||||||
var label = node.rich_text_label
|
var label = node.rich_text_label
|
||||||
var text = HTMLParser.get_bbcode_with_styles(element, styles, parser)
|
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:
|
for child in element.children:
|
||||||
var child_styles = styles
|
var child_styles = styles
|
||||||
if parser != null:
|
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)
|
var child_content = HTMLParser.get_bbcode_with_styles(child, child_styles, parser)
|
||||||
match child.tag_name:
|
match child.tag_name:
|
||||||
"b":
|
"b":
|
||||||
|
|||||||
@@ -21,7 +21,7 @@ a { text-[#1a0dab] }
|
|||||||
pre { text-xl font-mono }
|
pre { text-xl font-mono }
|
||||||
"""
|
"""
|
||||||
|
|
||||||
var HTML_CONTENT = "<head>
|
var HTML_CONTENT2 = "<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\">
|
||||||
|
|
||||||
@@ -230,3 +230,68 @@ So
|
|||||||
<span style=\"bg-[#ffffaa] w-12 h-8 self-stretch flex items-center justify-center\">Stretch</span>
|
<span style=\"bg-[#ffffaa] w-12 h-8 self-stretch flex items-center justify-center\">Stretch</span>
|
||||||
</div>
|
</div>
|
||||||
</body>".to_utf8_buffer()
|
</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()
|
||||||
|
|||||||
@@ -12,10 +12,12 @@ static func parse_size(val):
|
|||||||
if val.ends_with("%"):
|
if val.ends_with("%"):
|
||||||
# Not supported directly, skip
|
# Not supported directly, skip
|
||||||
return null
|
return null
|
||||||
|
if val == "full":
|
||||||
|
return null
|
||||||
return float(val)
|
return float(val)
|
||||||
|
|
||||||
static func apply_element_styles(node: Control, element: HTMLParser.HTMLElement, parser: HTMLParser) -> Control:
|
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
|
var label = null
|
||||||
|
|
||||||
if not (node is FlexContainer):
|
if not (node is FlexContainer):
|
||||||
@@ -47,7 +49,6 @@ static func apply_element_styles(node: Control, element: HTMLParser.HTMLElement,
|
|||||||
if styles.has("background-color"):
|
if styles.has("background-color"):
|
||||||
var target_node_for_bg = node if node is FlexContainer else label
|
var target_node_for_bg = node if node is FlexContainer else label
|
||||||
if target_node_for_bg:
|
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"])
|
target_node_for_bg.set_meta("custom_css_background_color", styles["background-color"])
|
||||||
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")
|
||||||
|
|||||||
@@ -16,3 +16,40 @@ func init(element: HTMLParser.HTMLElement, parser: HTMLParser = null) -> void:
|
|||||||
-1,
|
-1,
|
||||||
button_node.get_theme_default_font_size()
|
button_node.get_theme_default_font_size()
|
||||||
) + Vector2(20, 10) # Add padding
|
) + 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
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ var custom_hex_input: LineEdit
|
|||||||
var _file_text_content: String = ""
|
var _file_text_content: String = ""
|
||||||
var _file_binary_content: PackedByteArray = PackedByteArray()
|
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 color_picker_button: ColorPickerButton = $ColorPickerButton
|
||||||
var picker: ColorPicker = color_picker_button.get_picker()
|
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)
|
var active_child = get_node(active_child_name)
|
||||||
active_child.visible = true
|
active_child.visible = true
|
||||||
custom_minimum_size = active_child.size
|
|
||||||
|
|
||||||
match input_type:
|
match input_type:
|
||||||
"checkbox":
|
"checkbox":
|
||||||
@@ -128,10 +127,15 @@ func init(element: HTMLParser.HTMLElement) -> void:
|
|||||||
line_edit.secret = false
|
line_edit.secret = false
|
||||||
setup_text_input(line_edit, placeholder, value, minlength, maxlength, pattern)
|
setup_text_input(line_edit, placeholder, value, minlength, maxlength, pattern)
|
||||||
|
|
||||||
|
apply_input_styles(element, parser)
|
||||||
|
|
||||||
func remove_unused_children(keep_child_name: String) -> void:
|
func remove_unused_children(keep_child_name: String) -> void:
|
||||||
for child in get_children():
|
for child in get_children():
|
||||||
if child.name != keep_child_name:
|
if child.name != keep_child_name:
|
||||||
|
child.visible = false
|
||||||
child.queue_free()
|
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:
|
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
|
if placeholder: line_edit.placeholder_text = placeholder
|
||||||
@@ -289,3 +293,54 @@ func _on_file_selected(path: String) -> void:
|
|||||||
file.close()
|
file.close()
|
||||||
|
|
||||||
# TODO: when adding Lua, make these actually usable
|
# 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
|
||||||
|
|||||||
@@ -120,7 +120,7 @@ func contains_hyperlink(element: HTMLParser.HTMLElement) -> bool:
|
|||||||
return false
|
return false
|
||||||
|
|
||||||
func create_element_node(element: HTMLParser.HTMLElement, parser: HTMLParser) -> Control:
|
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 is_flex_container = styles.has("display") and ("flex" in styles["display"])
|
||||||
|
|
||||||
var final_node: Control
|
var final_node: Control
|
||||||
@@ -214,10 +214,10 @@ func create_element_node_internal(element: HTMLParser.HTMLElement, parser: HTMLP
|
|||||||
safe_add_child(node, child_node)
|
safe_add_child(node, child_node)
|
||||||
"input":
|
"input":
|
||||||
node = INPUT.instantiate()
|
node = INPUT.instantiate()
|
||||||
node.init(element)
|
node.init(element, parser)
|
||||||
"button":
|
"button":
|
||||||
node = BUTTON.instantiate()
|
node = BUTTON.instantiate()
|
||||||
node.init(element)
|
node.init(element, parser)
|
||||||
"span", "b", "i", "u", "small", "mark", "code", "a":
|
"span", "b", "i", "u", "small", "mark", "code", "a":
|
||||||
node = SPAN.instantiate()
|
node = SPAN.instantiate()
|
||||||
node.init(element)
|
node.init(element)
|
||||||
|
|||||||
Reference in New Issue
Block a user