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="."]
|
||||
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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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":
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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")
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
|
||||
Reference in New Issue
Block a user