handle font cascading on body (+button & li font support)

This commit is contained in:
Face
2025-08-01 14:44:06 +03:00
parent 49b0e357c9
commit 02f7730436
7 changed files with 120 additions and 88 deletions

View File

@@ -144,7 +144,7 @@ func get_element_styles_with_inheritance(element: HTMLElement, event: String = "
# Inherit certain properties from parent elements # Inherit certain properties from parent elements
var inheritable_properties = ["width", "height", "font-size", "color", "font-family"] var inheritable_properties = ["width", "height", "font-size", "color", "font-family"]
var parent_element = element.parent var parent_element = element.parent
while parent_element and parent_element.tag_name != "body": while parent_element:
var parent_styles = get_element_styles_internal(parent_element, event) var parent_styles = get_element_styles_internal(parent_element, event)
for property in inheritable_properties: for property in inheritable_properties:
# Only inherit if child doesn't already have this property # Only inherit if child doesn't already have this property

View File

@@ -92,92 +92,100 @@ static func apply_element_styles(node: Control, element: HTMLParser.HTMLElement,
return node return node
static func apply_styles_to_label(label: RichTextLabel, styles: Dictionary, element: HTMLParser.HTMLElement, parser, text_override: String = "") -> void: static func apply_styles_to_label(label: Control, styles: Dictionary, element: HTMLParser.HTMLElement, parser, text_override: String = "") -> void:
var text = text_override if text_override != "" else (element.get_preserved_text() if element.tag_name == "pre" else element.get_bbcode_formatted_text(parser)) if label is Button:
apply_font_to_button(label, styles)
return
if not label is RichTextLabel:
return
var text = text_override if text_override != "" else (element.get_preserved_text() if element.tag_name == "pre" else element.get_bbcode_formatted_text(parser))
var font_size = 24 # default var font_size = 24 # default
if styles.has("font-family"): if styles.has("font-family"):
var font_family = styles["font-family"] var font_family = styles["font-family"]
var font_resource = FontManager.get_font(font_family) var font_resource = FontManager.get_font(font_family)
# set a sans-serif fallback first # set a sans-serif fallback first
if font_family not in ["sans-serif", "serif", "monospace"]: if font_family not in ["sans-serif", "serif", "monospace"]:
if not FontManager.loaded_fonts.has(font_family): if not FontManager.loaded_fonts.has(font_family):
# Font not loaded yet, use sans-serif as fallback # Font not loaded yet, use sans-serif as fallback
var fallback_font = FontManager.get_font("sans-serif") var fallback_font = FontManager.get_font("sans-serif")
apply_font_to_label(label, fallback_font) apply_font_to_label(label, fallback_font)
if font_resource: if font_resource:
apply_font_to_label(label, font_resource) apply_font_to_label(label, font_resource)
# Apply font size # Apply font size
if styles.has("font-size"): if styles.has("font-size"):
font_size = int(styles["font-size"]) font_size = int(styles["font-size"])
# Apply color # Apply color
var color_tag = "" var color_tag = ""
if styles.has("color"): if styles.has("color"):
var color = styles["color"] as Color var color = styles["color"] as Color
if color == Color.BLACK and StyleManager.body_text_color != Color.BLACK: if color == Color.BLACK and StyleManager.body_text_color != Color.BLACK:
color = StyleManager.body_text_color color = StyleManager.body_text_color
color_tag = "[color=#%s]" % color.to_html(false) color_tag = "[color=#%s]" % color.to_html(false)
else: else:
if StyleManager.body_text_color != Color.BLACK: if StyleManager.body_text_color != Color.BLACK:
color_tag = "[color=#%s]" % StyleManager.body_text_color.to_html(false) color_tag = "[color=#%s]" % StyleManager.body_text_color.to_html(false)
# Apply bold
var bold_open = "" # Apply bold
var bold_close = "" var bold_open = ""
if styles.has("font-bold") and styles["font-bold"]: var bold_close = ""
bold_open = "[b]" if styles.has("font-bold") and styles["font-bold"]:
bold_close = "[/b]" bold_open = "[b]"
# Apply italic bold_close = "[/b]"
var italic_open = "" # Apply italic
var italic_close = "" var italic_open = ""
if styles.has("font-italic") and styles["font-italic"]: var italic_close = ""
italic_open = "[i]" if styles.has("font-italic") and styles["font-italic"]:
italic_close = "[/i]" italic_open = "[i]"
# Apply underline italic_close = "[/i]"
var underline_open = "" # Apply underline
var underline_close = "" var underline_open = ""
if styles.has("underline") and styles["underline"]: var underline_close = ""
underline_open = "[u]" if styles.has("underline") and styles["underline"]:
underline_close = "[/u]" underline_open = "[u]"
# Apply monospace font underline_close = "[/u]"
var mono_open = "" # Apply monospace font
var mono_close = "" var mono_open = ""
if styles.has("font-mono") and styles["font-mono"]: var mono_close = ""
# If font-family is already monospace, just use BBCode for styling if styles.has("font-mono") and styles["font-mono"]:
if not (styles.has("font-family") and styles["font-family"] == "monospace"): # If font-family is already monospace, just use BBCode for styling
mono_open = "[code]" if not (styles.has("font-family") and styles["font-family"] == "monospace"):
mono_close = "[/code]" mono_open = "[code]"
if styles.has("text-align"): mono_close = "[/code]"
match styles["text-align"]: if styles.has("text-align"):
"left": match styles["text-align"]:
label.horizontal_alignment = HORIZONTAL_ALIGNMENT_LEFT "left":
"center": label.horizontal_alignment = HORIZONTAL_ALIGNMENT_LEFT
label.horizontal_alignment = HORIZONTAL_ALIGNMENT_CENTER "center":
"right": label.horizontal_alignment = HORIZONTAL_ALIGNMENT_CENTER
label.horizontal_alignment = HORIZONTAL_ALIGNMENT_RIGHT "right":
"justify": label.horizontal_alignment = HORIZONTAL_ALIGNMENT_RIGHT
label.horizontal_alignment = HORIZONTAL_ALIGNMENT_FILL "justify":
# Construct final text label.horizontal_alignment = HORIZONTAL_ALIGNMENT_FILL
var styled_text = "[font_size=%d]%s%s%s%s%s%s%s%s%s%s%s[/font_size]" % [ # Construct final text
font_size, var styled_text = "[font_size=%d]%s%s%s%s%s%s%s%s%s%s%s[/font_size]" % [
color_tag, font_size,
bold_open, color_tag,
italic_open, bold_open,
underline_open, italic_open,
mono_open, underline_open,
text, mono_open,
mono_close, text,
underline_close, mono_close,
italic_close, underline_close,
bold_close, italic_close,
"[/color]" if color_tag.length() > 0 else "", bold_close,
] "[/color]" if color_tag.length() > 0 else "",
]
label.text = styled_text label.text = styled_text
static func apply_flex_container_properties(node: FlexContainer, styles: Dictionary) -> void: static func apply_flex_container_properties(node: FlexContainer, styles: Dictionary) -> void:
FlexUtils.apply_flex_container_properties(node, styles) FlexUtils.apply_flex_container_properties(node, styles)
@@ -249,3 +257,17 @@ static func apply_font_to_label(label: RichTextLabel, font_resource: Font) -> vo
label.add_theme_font_override("bold_font", font_resource) label.add_theme_font_override("bold_font", font_resource)
label.add_theme_font_override("italics_font", font_resource) label.add_theme_font_override("italics_font", font_resource)
label.add_theme_font_override("bold_italics_font", font_resource) label.add_theme_font_override("bold_italics_font", font_resource)
static func apply_font_to_button(button: Button, styles: Dictionary) -> void:
if styles.has("font-family"):
var font_family = styles["font-family"]
var font_resource = FontManager.get_font(font_family)
# Set fallback first for FOUT prevention
if font_family not in ["sans-serif", "serif", "monospace"]:
if not FontManager.loaded_fonts.has(font_family):
var fallback_font = FontManager.get_font("sans-serif")
button.add_theme_font_override("font", fallback_font)
if font_resource:
button.add_theme_font_override("font", font_resource)

View File

@@ -39,9 +39,9 @@ func apply_button_styles(element: HTMLParser.HTMLElement, parser: HTMLParser, na
if not element or not parser: if not element or not parser:
return return
var styles = parser.get_element_styles_internal(element, "") var styles = parser.get_element_styles_with_inheritance(element, "", [])
var hover_styles = parser.get_element_styles_internal(element, "hover") var hover_styles = parser.get_element_styles_with_inheritance(element, "hover", [])
var active_styles = parser.get_element_styles_internal(element, "active") var active_styles = parser.get_element_styles_with_inheritance(element, "active", [])
var button_node = $ButtonNode var button_node = $ButtonNode
# Apply text color with state-dependent colors # Apply text color with state-dependent colors

View File

@@ -3,4 +3,6 @@ extends Control
func init(element: HTMLParser.HTMLElement, parser: HTMLParser = null) -> void: func init(element: HTMLParser.HTMLElement, parser: HTMLParser = null) -> void:
# This is mainly for cases where <li> appears outside of <ul>/<ol> # This is mainly for cases where <li> appears outside of <ul>/<ol>
var label: RichTextLabel = $RichTextLabel var label: RichTextLabel = $RichTextLabel
label.text = "[font_size=24]%s[/font_size]" % element.get_bbcode_formatted_text(parser) var styles = parser.get_element_styles_with_inheritance(element, "", [])
StyleManager.apply_styles_to_label(label, styles, element, parser)

View File

@@ -55,7 +55,9 @@ func create_li_node(element: HTMLParser.HTMLElement, list_type: String, index: i
marker_label.theme = BROWSER_TEXT marker_label.theme = BROWSER_TEXT
var marker_text = get_marker_for_type(list_type, index) var marker_text = get_marker_for_type(list_type, index)
StyleManager.apply_styles_to_label(marker_label, {}, null, null, marker_text)
var marker_styles = parser.get_element_styles_with_inheritance(element, "", []) if parser else {}
StyleManager.apply_styles_to_label(marker_label, marker_styles, element, parser, marker_text)
# Create content # Create content
var content_label = RichTextLabel.new() var content_label = RichTextLabel.new()
@@ -66,7 +68,9 @@ func create_li_node(element: HTMLParser.HTMLElement, list_type: String, index: i
content_label.theme = BROWSER_TEXT content_label.theme = BROWSER_TEXT
var content_text = element.get_bbcode_formatted_text(parser) var content_text = element.get_bbcode_formatted_text(parser)
StyleManager.apply_styles_to_label(content_label, {}, null, null, content_text)
var content_styles = parser.get_element_styles_with_inheritance(element, "", []) if parser else {}
StyleManager.apply_styles_to_label(content_label, content_styles, element, parser, content_text)
li_container.add_theme_constant_override("separation", 0) li_container.add_theme_constant_override("separation", 0)
li_container.add_child(marker_label) li_container.add_child(marker_label)

View File

@@ -50,7 +50,9 @@ func create_li_node(element: HTMLParser.HTMLElement, list_type: String, marker_w
bullet_label.theme = BROWSER_TEXT bullet_label.theme = BROWSER_TEXT
var bullet_text = get_bullet_for_type(list_type) var bullet_text = get_bullet_for_type(list_type)
StyleManager.apply_styles_to_label(bullet_label, {}, null, null, bullet_text)
var bullet_styles = parser.get_element_styles_with_inheritance(element, "", []) if parser else {}
StyleManager.apply_styles_to_label(bullet_label, bullet_styles, element, parser, bullet_text)
# Create content # Create content
var content_label = RichTextLabel.new() var content_label = RichTextLabel.new()
@@ -60,7 +62,9 @@ func create_li_node(element: HTMLParser.HTMLElement, list_type: String, marker_w
content_label.theme = BROWSER_TEXT content_label.theme = BROWSER_TEXT
content_label.scroll_active = false content_label.scroll_active = false
var content_text = element.get_bbcode_formatted_text(parser) var content_text = element.get_bbcode_formatted_text(parser)
StyleManager.apply_styles_to_label(content_label, {}, null, null, content_text)
var content_styles = parser.get_element_styles_with_inheritance(element, "", []) if parser else {}
StyleManager.apply_styles_to_label(content_label, content_styles, element, parser, content_text)
li_container.add_theme_constant_override("separation", 0) li_container.add_theme_constant_override("separation", 0)
li_container.add_child(bullet_label) li_container.add_child(bullet_label)

View File

@@ -305,7 +305,7 @@ func create_element_node_internal(element: HTMLParser.HTMLElement, parser: HTMLP
return node return node
func register_font_dependent_element(label: RichTextLabel, styles: Dictionary, element: HTMLParser.HTMLElement, parser: HTMLParser) -> void: func register_font_dependent_element(label: Control, styles: Dictionary, element: HTMLParser.HTMLElement, parser: HTMLParser) -> void:
font_dependent_elements.append({ font_dependent_elements.append({
"label": label, "label": label,
"styles": styles, "styles": styles,