% width/height, body background color, margin/padding

This commit is contained in:
Face
2025-07-30 14:39:33 +03:00
parent c67b8dc552
commit 4b58a77ec2
7 changed files with 347 additions and 64 deletions

View File

@@ -9,9 +9,9 @@ static func parse_size(val):
return float(val.replace("px", ""))
if val.ends_with("rem"):
return float(val.replace("rem", "")) * 16.0
if val.ends_with("%"):
# Not supported directly, skip
return null
if val.ends_with("%") or (val.ends_with("]") and "%" in val):
var clean_val = val.replace("[", "").replace("]", "")
return clean_val
if val == "full":
return null
return float(val)
@@ -35,14 +35,18 @@ static func apply_element_styles(node: Control, element: HTMLParser.HTMLElement,
var skip_sizing = should_skip_sizing(node, element, parser)
if (width != null or height != null) and not skip_sizing:
node.custom_minimum_size = Vector2(
width if width != null else node.custom_minimum_size.x,
height if height != null else node.custom_minimum_size.y
)
if width != null:
node.size_flags_horizontal = Control.SIZE_SHRINK_BEGIN
if height != null:
node.size_flags_vertical = Control.SIZE_SHRINK_BEGIN
# FlexContainers handle percentage sizing differently than regular controls
if node is FlexContainer:
if width != null and typeof(width) != TYPE_STRING:
node.custom_minimum_size.x = width
if height != null and typeof(height) != TYPE_STRING:
node.custom_minimum_size.y = height
elif node is VBoxContainer or node is HBoxContainer or node is Container:
# Hcontainer nodes (like ul, ol)
apply_container_dimension_sizing(node, width, height)
else:
# regular controls
apply_regular_control_sizing(node, width, height)
if label and label != node:
label.anchors_preset = Control.PRESET_FULL_RECT
@@ -62,6 +66,7 @@ static func apply_element_styles(node: Control, element: HTMLParser.HTMLElement,
static func apply_styles_to_label(label: RichTextLabel, styles: Dictionary, element: HTMLParser.HTMLElement, parser) -> void:
var text = element.get_preserved_text() if element.tag_name == "pre" else element.get_bbcode_formatted_text(parser)
var font_size = 24 # default
# Apply font size
if styles.has("font-size"):
@@ -120,7 +125,6 @@ static func apply_styles_to_label(label: RichTextLabel, styles: Dictionary, elem
bold_close,
"[/color]" if color_tag.length() > 0 else "",
]
label.text = styled_text
static func apply_flex_container_properties(node: FlexContainer, styles: Dictionary, element: HTMLParser.HTMLElement, parser: HTMLParser) -> void:
# Flex direction - default to row if not specified
@@ -180,6 +184,8 @@ static func apply_flex_container_properties(node: FlexContainer, styles: Diction
if width_val == "full":
# For flex containers, w-full should expand to fill parent
node.set_meta("should_fill_horizontal", true)
elif typeof(width_val) == TYPE_STRING and width_val.ends_with("%"):
node.set_meta("custom_css_width_percentage", width_val)
else:
node.set_meta("custom_css_width", parse_size(width_val))
if styles.has("height"):
@@ -187,6 +193,8 @@ static func apply_flex_container_properties(node: FlexContainer, styles: Diction
if height_val == "full":
# For flex containers, h-full should expand to fill parent
node.set_meta("should_fill_vertical", true)
elif typeof(height_val) == TYPE_STRING and height_val.ends_with("%"):
node.set_meta("custom_css_height_percentage", height_val)
else:
node.set_meta("custom_css_height", parse_size(height_val))
if styles.has("background-color"):
@@ -273,6 +281,137 @@ static func should_skip_sizing(node: Control, element: HTMLParser.HTMLElement, p
return false
static func apply_container_dimension_sizing(node: Control, width, height) -> void:
if width != null:
if is_percentage(width):
node.set_meta("container_percentage_width", width)
node.size_flags_horizontal = Control.SIZE_EXPAND_FILL
apply_container_percentage_sizing(node)
else:
node.custom_minimum_size.x = width
node.size_flags_horizontal = Control.SIZE_SHRINK_BEGIN
if height != null:
if is_percentage(height):
node.set_meta("container_percentage_height", height)
node.size_flags_vertical = Control.SIZE_EXPAND_FILL
apply_container_percentage_sizing(node)
else:
node.custom_minimum_size.y = height
node.size_flags_vertical = Control.SIZE_SHRINK_BEGIN
static func apply_regular_control_sizing(node: Control, width, height) -> void:
if width != null:
if is_percentage(width):
var estimated_width = calculate_percentage_size(width, 800.0)
node.custom_minimum_size.x = estimated_width
node.size_flags_horizontal = Control.SIZE_EXPAND_FILL
else:
node.custom_minimum_size.x = width
node.size_flags_horizontal = Control.SIZE_SHRINK_BEGIN
if height != null:
if is_percentage(height):
var estimated_height = calculate_percentage_size(height, 600.0)
node.custom_minimum_size.y = estimated_height
node.size_flags_vertical = Control.SIZE_EXPAND_FILL
else:
node.custom_minimum_size.y = height
node.size_flags_vertical = Control.SIZE_SHRINK_BEGIN
static func is_percentage(value) -> bool:
return typeof(value) == TYPE_STRING and value.ends_with("%")
static func calculate_percentage_size(percentage_str: String, fallback_size: float) -> float:
var clean_percentage = percentage_str.replace("%", "")
var percentage = float(clean_percentage) / 100.0
return fallback_size * percentage
static func apply_container_percentage_sizing(node: Control) -> void:
var parent = node.get_parent()
if not parent:
return
var new_min_size = node.custom_minimum_size
if node.has_meta("container_percentage_width"):
var percentage_str = node.get_meta("container_percentage_width")
var parent_width = get_parent_dimension(parent, true, 800.0)
new_min_size.x = calculate_percentage_size(percentage_str, parent_width)
if node.has_meta("container_percentage_height"):
var percentage_str = node.get_meta("container_percentage_height")
var parent_height = get_parent_dimension(parent, false, 600.0)
new_min_size.y = calculate_percentage_size(percentage_str, parent_height)
node.custom_minimum_size = new_min_size
static func get_parent_dimension(parent: Control, is_width: bool, fallback: float) -> float:
var size_value = parent.size.x if is_width else parent.size.y
if size_value > 0:
return size_value
var rect_size = parent.get_rect().size.x if is_width else parent.get_rect().size.y
if rect_size > 0:
return rect_size
var min_size = parent.custom_minimum_size.x if is_width else parent.custom_minimum_size.y
if min_size > 0:
return min_size
return fallback
static func apply_body_styles(body: HTMLParser.HTMLElement, parser: HTMLParser, website_container: Control, website_background: Control) -> void:
var styles = parser.get_element_styles_with_inheritance(body, "", [])
# Apply background color
if styles.has("background-color"):
var style_box = StyleBoxFlat.new()
style_box.bg_color = styles["background-color"] as Color
website_background.add_theme_stylebox_override("panel", style_box)
# Apply padding
var 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")
if has_padding:
var margin_container = MarginContainer.new()
margin_container.name = "BodyMarginContainer"
margin_container.size_flags_horizontal = website_container.size_flags_horizontal
margin_container.size_flags_vertical = website_container.size_flags_vertical
# ScrollContainer
# |__ BodyMarginContainer
# |__ WebsiteContainer
var original_parent = website_container.get_parent()
var container_index = website_container.get_index()
original_parent.remove_child(website_container)
original_parent.add_child(margin_container)
original_parent.move_child(margin_container, container_index)
margin_container.add_child(website_container)
var margin_val = parse_size(styles["padding"])
margin_container.add_theme_constant_override("margin_left", margin_val)
margin_container.add_theme_constant_override("margin_right", margin_val)
margin_container.add_theme_constant_override("margin_top", margin_val)
margin_container.add_theme_constant_override("margin_bottom", margin_val)
# Apply individual padding values
var padding_sides = [
["padding-top", "margin_top"],
["padding-right", "margin_right"],
["padding-bottom", "margin_bottom"],
["padding-left", "margin_left"]
]
for side_pair in padding_sides:
var style_key = side_pair[0]
var margin_key = side_pair[1]
if styles.has(style_key):
var margin_val2 = parse_size(styles[style_key])
margin_container.add_theme_constant_override(margin_key, margin_val2)
static func parse_radius(radius_str: String) -> int:
if radius_str.ends_with("px"):
return int(radius_str.replace("px", ""))