From 1435ec6f9406bb2c8e3c20c5f49e09ead98c5c93 Mon Sep 17 00:00:00 2001
From: Face <69168154+face-hh@users.noreply.github.com>
Date: Fri, 25 Jul 2025 15:46:18 +0300
Subject: [PATCH]
, , -
---
Scenes/Styles/BrowserText.tres | 1 +
Scenes/Tags/li.tscn | 22 +++
Scenes/Tags/ol.tscn | 10 ++
Scenes/Tags/ul.tscn | 10 ++
Scripts/Tags/li.gd | 6 +
Scripts/Tags/li.gd.uid | 1 +
Scripts/Tags/ol.gd | 101 ++++++++++++++
Scripts/Tags/ol.gd.uid | 1 +
Scripts/Tags/ul.gd | 81 +++++++++++
Scripts/Tags/ul.gd.uid | 1 +
Scripts/main.gd | 238 ++++++++++++++++++++++++++++++++-
11 files changed, 467 insertions(+), 5 deletions(-)
create mode 100644 Scenes/Tags/li.tscn
create mode 100644 Scenes/Tags/ol.tscn
create mode 100644 Scenes/Tags/ul.tscn
create mode 100644 Scripts/Tags/li.gd
create mode 100644 Scripts/Tags/li.gd.uid
create mode 100644 Scripts/Tags/ol.gd
create mode 100644 Scripts/Tags/ol.gd.uid
create mode 100644 Scripts/Tags/ul.gd
create mode 100644 Scripts/Tags/ul.gd.uid
diff --git a/Scenes/Styles/BrowserText.tres b/Scenes/Styles/BrowserText.tres
index 4f7fe68..bb4b543 100644
--- a/Scenes/Styles/BrowserText.tres
+++ b/Scenes/Styles/BrowserText.tres
@@ -210,6 +210,7 @@ PopupMenu/icons/unchecked_disabled = ExtResource("12_0an8v")
PopupMenu/styles/hover = SubResource("StyleBoxFlat_luhv8")
PopupMenu/styles/panel = SubResource("StyleBoxFlat_ya683")
PopupPanel/styles/panel = SubResource("StyleBoxFlat_06us3")
+RichTextLabel/colors/default_color = Color(0, 0, 0, 1)
RichTextLabel/colors/font_selected_color = Color(1, 1, 1, 1)
RichTextLabel/colors/selection_color = Color(0.313726, 0.403922, 0.8, 1)
RichTextLabel/fonts/bold_font = SubResource("SystemFont_jecr6")
diff --git a/Scenes/Tags/li.tscn b/Scenes/Tags/li.tscn
new file mode 100644
index 0000000..4602565
--- /dev/null
+++ b/Scenes/Tags/li.tscn
@@ -0,0 +1,22 @@
+[gd_scene load_steps=3 format=3 uid="uid://bli1234568aa"]
+
+[ext_resource type="Script" uid="uid://ps8duq0aw3tu" path="res://Scripts/Tags/li.gd" id="1_li"]
+[ext_resource type="Theme" uid="uid://bn6rbmdy60lhr" path="res://Scenes/Styles/BrowserText.tres" id="2_theme"]
+
+[node name="LI" type="VBoxContainer"]
+anchors_preset = 10
+anchor_right = 1.0
+grow_horizontal = 2
+script = ExtResource("1_li")
+
+[node name="RichTextLabel" type="RichTextLabel" parent="."]
+layout_mode = 2
+size_flags_horizontal = 3
+focus_mode = 2
+mouse_default_cursor_shape = 1
+theme = ExtResource("2_theme")
+theme_override_colors/default_color = Color(0, 0, 0, 1)
+bbcode_enabled = true
+text = "Placeholder"
+fit_content = true
+selection_enabled = true
diff --git a/Scenes/Tags/ol.tscn b/Scenes/Tags/ol.tscn
new file mode 100644
index 0000000..f5269f6
--- /dev/null
+++ b/Scenes/Tags/ol.tscn
@@ -0,0 +1,10 @@
+[gd_scene load_steps=2 format=3 uid="uid://bol1234568aa"]
+
+[ext_resource type="Script" uid="uid://bbkebg4aihve3" path="res://Scripts/Tags/ol.gd" id="1_ol"]
+
+[node name="OL" type="VBoxContainer"]
+anchors_preset = 10
+anchor_right = 1.0
+grow_horizontal = 2
+theme_override_constants/separation = 2
+script = ExtResource("1_ol")
diff --git a/Scenes/Tags/ul.tscn b/Scenes/Tags/ul.tscn
new file mode 100644
index 0000000..896ce40
--- /dev/null
+++ b/Scenes/Tags/ul.tscn
@@ -0,0 +1,10 @@
+[gd_scene load_steps=2 format=3 uid="uid://bul1234568aa"]
+
+[ext_resource type="Script" uid="uid://cu1g4a1tv6ngw" path="res://Scripts/Tags/ul.gd" id="1_ul"]
+
+[node name="UL" type="VBoxContainer"]
+anchors_preset = 10
+anchor_right = 1.0
+grow_horizontal = 2
+theme_override_constants/separation = 2
+script = ExtResource("1_ul")
diff --git a/Scripts/Tags/li.gd b/Scripts/Tags/li.gd
new file mode 100644
index 0000000..2c87493
--- /dev/null
+++ b/Scripts/Tags/li.gd
@@ -0,0 +1,6 @@
+extends Control
+
+func init(element: HTMLParser.HTMLElement) -> void:
+ # This is mainly for cases where
- appears outside of
/
+ var label: RichTextLabel = $RichTextLabel
+ label.text = "[font_size=24]%s[/font_size]" % element.get_bbcode_formatted_text()
diff --git a/Scripts/Tags/li.gd.uid b/Scripts/Tags/li.gd.uid
new file mode 100644
index 0000000..968d6d5
--- /dev/null
+++ b/Scripts/Tags/li.gd.uid
@@ -0,0 +1 @@
+uid://ps8duq0aw3tu
diff --git a/Scripts/Tags/ol.gd b/Scripts/Tags/ol.gd
new file mode 100644
index 0000000..fafd9be
--- /dev/null
+++ b/Scripts/Tags/ol.gd
@@ -0,0 +1,101 @@
+extends VBoxContainer
+
+const BROWSER_TEXT = preload("res://Scenes/Styles/BrowserText.tres")
+
+func init(element: HTMLParser.HTMLElement) -> void:
+ var list_type = element.get_attribute("type").to_lower()
+ if list_type == "": list_type = "decimal" # Default
+
+ var item_count = 0
+ for child_element in element.children:
+ if child_element.tag_name == "li":
+ item_count += 1
+
+ var marker_min_width = await calculate_marker_width(list_type, item_count)
+
+ var index = 1
+ for child_element in element.children:
+ if child_element.tag_name == "li":
+ var li_node = create_li_node(child_element, list_type, index, marker_min_width)
+ if li_node:
+ add_child(li_node)
+ index += 1
+
+func calculate_marker_width(list_type: String, max_index: int) -> float:
+ var temp_label = RichTextLabel.new()
+ temp_label.bbcode_enabled = true
+ temp_label.fit_content = true
+ temp_label.scroll_active = false
+ temp_label.theme = BROWSER_TEXT
+ add_child(temp_label)
+
+ var marker_text = get_marker_for_type(list_type, max_index)
+ temp_label.text = "[font_size=24]%s[/font_size]" % marker_text
+
+ await get_tree().process_frame
+
+ var width = temp_label.get_content_width() + 5
+
+ remove_child(temp_label)
+ temp_label.queue_free()
+
+ return max(width, 30) # Minimum pixels
+
+func create_li_node(element: HTMLParser.HTMLElement, list_type: String, index: int, marker_width: float = 30) -> Control:
+ var li_container = HBoxContainer.new()
+
+ # Create number/letter marker
+ var marker_label = RichTextLabel.new()
+ marker_label.custom_minimum_size = Vector2(marker_width, 0)
+ marker_label.size_flags_horizontal = Control.SIZE_SHRINK_CENTER
+ marker_label.size_flags_vertical = Control.SIZE_SHRINK_CENTER
+ marker_label.bbcode_enabled = true
+ marker_label.fit_content = true
+ marker_label.scroll_active = false
+ marker_label.theme = BROWSER_TEXT
+
+ var marker_text = get_marker_for_type(list_type, index)
+ marker_label.text = "[font_size=24]%s[/font_size]" % marker_text
+
+ # Create content
+ var content_label = RichTextLabel.new()
+ content_label.size_flags_horizontal = Control.SIZE_EXPAND_FILL
+ content_label.bbcode_enabled = true
+ content_label.fit_content = true
+ content_label.scroll_active = false
+ content_label.theme = BROWSER_TEXT
+
+ content_label.text = "[font_size=24]%s[/font_size]" % element.get_bbcode_formatted_text()
+
+ li_container.add_theme_constant_override("separation", 0)
+ li_container.add_child(marker_label)
+ li_container.add_child(content_label)
+
+ return li_container
+
+func get_marker_for_type(list_type: String, index: int) -> String:
+ match list_type:
+ "decimal":
+ return str(index) + "."
+ "zero-lead":
+ return "%02d." % index
+ "lower-alpha", "lower-roman":
+ return char(96 + index) + "." if list_type == "lower-alpha" else int_to_roman(index).to_lower() + "."
+ "upper-alpha", "upper-roman":
+ return char(64 + index) + "." if list_type == "upper-alpha" else int_to_roman(index) + "."
+ "none":
+ return ""
+ _:
+ return str(index) + "." # Default to decimal
+
+func int_to_roman(num: int) -> String:
+ var values = [1000, 900, 500, 400, 100, 90, 50, 40, 10, 9, 5, 4, 1]
+ var symbols = ["M", "CM", "D", "CD", "C", "XC", "L", "XL", "X", "IX", "V", "IV", "I"]
+ var result = ""
+
+ for i in range(values.size()):
+ while num >= values[i]:
+ result += symbols[i]
+ num -= values[i]
+
+ return result
diff --git a/Scripts/Tags/ol.gd.uid b/Scripts/Tags/ol.gd.uid
new file mode 100644
index 0000000..5bc8ab7
--- /dev/null
+++ b/Scripts/Tags/ol.gd.uid
@@ -0,0 +1 @@
+uid://bbkebg4aihve3
diff --git a/Scripts/Tags/ul.gd b/Scripts/Tags/ul.gd
new file mode 100644
index 0000000..4396634
--- /dev/null
+++ b/Scripts/Tags/ul.gd
@@ -0,0 +1,81 @@
+extends VBoxContainer
+
+const BROWSER_TEXT = preload("res://Scenes/Styles/BrowserText.tres")
+
+func init(element: HTMLParser.HTMLElement) -> void:
+ var list_type = element.get_attribute("type").to_lower()
+ if list_type == "": list_type = "disc" # Default
+
+ var marker_min_width = await calculate_marker_width(list_type)
+
+ for child_element in element.children:
+ if child_element.tag_name == "li":
+ var li_node = create_li_node(child_element, list_type, marker_min_width)
+ if li_node:
+ add_child(li_node)
+
+func calculate_marker_width(list_type: String) -> float:
+ var temp_label = RichTextLabel.new()
+ temp_label.bbcode_enabled = true
+ temp_label.fit_content = true
+ temp_label.scroll_active = false
+ temp_label.theme = BROWSER_TEXT
+ add_child(temp_label)
+
+ var bullet_text = get_bullet_for_type(list_type)
+ temp_label.text = "[font_size=24]%s[/font_size]" % bullet_text
+
+ await get_tree().process_frame
+
+ var width = temp_label.get_content_width() + 5 # padding
+
+ remove_child(temp_label)
+ temp_label.queue_free()
+
+ return max(width, 20) # Minimum pixels
+
+func create_li_node(element: HTMLParser.HTMLElement, list_type: String, marker_width: float = 20) -> Control:
+ var li_container = HBoxContainer.new()
+
+ # Create bullet point
+ var bullet_label = RichTextLabel.new()
+ bullet_label.custom_minimum_size = Vector2(marker_width, 0)
+ bullet_label.size_flags_horizontal = Control.SIZE_SHRINK_CENTER
+ bullet_label.size_flags_vertical = Control.SIZE_SHRINK_CENTER
+ bullet_label.bbcode_enabled = true
+ bullet_label.fit_content = true
+ bullet_label.scroll_active = false
+ bullet_label.horizontal_alignment = HORIZONTAL_ALIGNMENT_CENTER
+ bullet_label.vertical_alignment = VERTICAL_ALIGNMENT_CENTER
+ bullet_label.theme = BROWSER_TEXT
+
+ var bullet_text = get_bullet_for_type(list_type)
+ bullet_label.text = "[font_size=24]%s[/font_size]" % bullet_text
+
+ # Create content
+ var content_label = RichTextLabel.new()
+ content_label.size_flags_horizontal = Control.SIZE_EXPAND_FILL
+ content_label.bbcode_enabled = true
+ content_label.fit_content = true
+ content_label.theme = BROWSER_TEXT
+ content_label.scroll_active = false
+ content_label.text = "[font_size=24]%s[/font_size]" % element.get_bbcode_formatted_text()
+
+ li_container.add_theme_constant_override("separation", 0)
+ li_container.add_child(bullet_label)
+ li_container.add_child(content_label)
+
+ return li_container
+
+func get_bullet_for_type(list_type: String) -> String:
+ match list_type:
+ "circle":
+ return "◦"
+ "disc":
+ return "•"
+ "square":
+ return "■"
+ "none":
+ return " "
+ _:
+ return "•" # Default to disc
diff --git a/Scripts/Tags/ul.gd.uid b/Scripts/Tags/ul.gd.uid
new file mode 100644
index 0000000..0807c55
--- /dev/null
+++ b/Scripts/Tags/ul.gd.uid
@@ -0,0 +1 @@
+uid://cu1g4a1tv6ngw
diff --git a/Scripts/main.gd b/Scripts/main.gd
index 6638d76..0fd8996 100644
--- a/Scripts/main.gd
+++ b/Scripts/main.gd
@@ -20,6 +20,9 @@ const H6 = preload("res://Scenes/Tags/h6.tscn")
const FORM = preload("res://Scenes/Tags/form.tscn")
const INPUT = preload("res://Scenes/Tags/input.tscn")
const BUTTON = preload("res://Scenes/Tags/button.tscn")
+const UL = preload("res://Scenes/Tags/ul.tscn")
+const OL = preload("res://Scenes/Tags/ol.tscn")
+const LI = preload("res://Scenes/Tags/li.tscn")
const MIN_SIZE = Vector2i(750, 200)
@@ -106,11 +109,220 @@ line breaks
-
-
+# Ordered list
+
+- hello gang
+- this
+- is
+- a test
+- a test
+- a test
+- a test
+- a test
+- a test
+- a test
+- a test
+- a test
+- a test
+- a test
+- a test
+- a test
+- a test
+- a test
+- a test
+- a test
+- a test
+- a test
+- a test
+- a test
+- a test
+- a test
+- a test
+- a test
+- a test
+- a test
+- a test
+- a test
+- a test
+- a test
+- a test
+- a test
+- a test
+- a test
+- a test
+- a test
+- a test
+- a test
+- a test
+- a test
+- a test
+- a test
+- a test
+- a test
+- a test
+- a test
+- a test
+- a test
+- a test
+- a test
+- a test
+- a test
+- a test
+- a test
+- a test
+- a test
+- a test
+- a test
+- a test
+- a test
+- a test
+- a test
+- a test
+- a test
+- a test
+- a test
+- a test
+- a test
+- a test
+- a test
+- a test
+- a test
+- a test
+- a test
+- a test
+- a test
+- a test
+- a test
+- a test
+- a test
+- a test
+- a test
+- a test
+- a test
+- a test
+- a test
+- a test
+- a test
+- a test
+- a test
+- a test
+- a test
+- a test
+- a test
+- a test
+- a test
+- a test
+- a test
+- a test
+- a test
+- a test
+- a test
+- a test
+- a test
+- a test
+- a test
+- a test
+- a test
+- a test
+- a test
+- a test
+- a test
+- a test
+- a test
+- a test
+- a test
+- a test
+- a test
+- a test
+- a test
+- a test
+- a test
+- a test
+- a test
+- a test
+- a test
+- a test
+- a test
+- a test
+- a test
+- a test
+- a test
+- a test
+- a test
+- a test
+- a test
+- a test
+- a test
+- a test
+- a test
+- a test
+- a test
+
+
+
+- hello gang
+- this
+- is
+- a test
+
+
+
+- hello gang
+- this
+- is
+- a test
+
+
+
+- hello gang
+- this
+- is
+- a test
+
+
+
+
+- hello gang
+- this
+- is
+- a test
+
+
+
+- hello gang
+- this
+- is
+- a test
+
+
+
+- hello gang
+- this
+- is
+- a test
+
+
+
+- hello gang
+- this
+- is
+- a test
+
+
+- hello gang
+- this
+- is
+- a test
+
+
+- hello gang
+- this
+- is
+- a test
+