p, pre, br, b, img, separator, i, u, small, mark, code tags
2
Assets/Icons/23x23-empty.svg
Normal file
@@ -0,0 +1,2 @@
|
||||
<svg width="23" height="23" viewBox="0 0 23 23" xmlns="http://www.w3.org/2000/svg">
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 90 B |
@@ -2,16 +2,16 @@
|
||||
|
||||
importer="texture"
|
||||
type="CompressedTexture2D"
|
||||
uid="uid://dioe63fr47oq7"
|
||||
path="res://.godot/imported/youtube.png-5feacc6342e9a438cbbd6a63702ea1ce.ctex"
|
||||
uid="uid://dglkjumm1q4lo"
|
||||
path="res://.godot/imported/23x23-empty.svg-f79aa182e01c658978086a2615b5cbce.ctex"
|
||||
metadata={
|
||||
"vram_texture": false
|
||||
}
|
||||
|
||||
[deps]
|
||||
|
||||
source_file="res://Scripts/youtube.png"
|
||||
dest_files=["res://.godot/imported/youtube.png-5feacc6342e9a438cbbd6a63702ea1ce.ctex"]
|
||||
source_file="res://Assets/Icons/23x23-empty.svg"
|
||||
dest_files=["res://.godot/imported/23x23-empty.svg-f79aa182e01c658978086a2615b5cbce.ctex"]
|
||||
|
||||
[params]
|
||||
|
||||
@@ -32,3 +32,6 @@ process/hdr_as_srgb=false
|
||||
process/hdr_clamp_exposure=false
|
||||
process/size_limit=0
|
||||
detect_3d/compress_to=1
|
||||
svg/scale=1.0
|
||||
editor/scale_with_editor_scale=false
|
||||
editor/convert_colors_with_editor_theme=false
|
||||
|
Before Width: | Height: | Size: 284 B After Width: | Height: | Size: 284 B |
@@ -3,15 +3,15 @@
|
||||
importer="texture"
|
||||
type="CompressedTexture2D"
|
||||
uid="uid://bp42ccs2nmbmw"
|
||||
path="res://.godot/imported/arrow-left.svg-6665bd65bdc7655f58ffd2c77101e033.ctex"
|
||||
path="res://.godot/imported/arrow-left.svg-5f99da4595c3d8d0d08c3c956ebfe3c3.ctex"
|
||||
metadata={
|
||||
"vram_texture": false
|
||||
}
|
||||
|
||||
[deps]
|
||||
|
||||
source_file="res://Icons/arrow-left.svg"
|
||||
dest_files=["res://.godot/imported/arrow-left.svg-6665bd65bdc7655f58ffd2c77101e033.ctex"]
|
||||
source_file="res://Assets/Icons/arrow-left.svg"
|
||||
dest_files=["res://.godot/imported/arrow-left.svg-5f99da4595c3d8d0d08c3c956ebfe3c3.ctex"]
|
||||
|
||||
[params]
|
||||
|
||||
|
Before Width: | Height: | Size: 285 B After Width: | Height: | Size: 285 B |
@@ -3,15 +3,15 @@
|
||||
importer="texture"
|
||||
type="CompressedTexture2D"
|
||||
uid="uid://dyyylow47qd0k"
|
||||
path="res://.godot/imported/arrow-right.svg-952a316afcd4823b2076bf76a665b17d.ctex"
|
||||
path="res://.godot/imported/arrow-right.svg-c769bf30dd1a5a6c76e989455e94e01b.ctex"
|
||||
metadata={
|
||||
"vram_texture": false
|
||||
}
|
||||
|
||||
[deps]
|
||||
|
||||
source_file="res://Icons/arrow-right.svg"
|
||||
dest_files=["res://.godot/imported/arrow-right.svg-952a316afcd4823b2076bf76a665b17d.ctex"]
|
||||
source_file="res://Assets/Icons/arrow-right.svg"
|
||||
dest_files=["res://.godot/imported/arrow-right.svg-c769bf30dd1a5a6c76e989455e94e01b.ctex"]
|
||||
|
||||
[params]
|
||||
|
||||
|
Before Width: | Height: | Size: 266 B After Width: | Height: | Size: 266 B |
@@ -3,15 +3,15 @@
|
||||
importer="texture"
|
||||
type="CompressedTexture2D"
|
||||
uid="uid://df1m4j7uxi63v"
|
||||
path="res://.godot/imported/chevron-down.svg-484378157f0927346bbcbdbf4232b051.ctex"
|
||||
path="res://.godot/imported/chevron-down.svg-549b6fd6d6d40e9ebd832012d163f272.ctex"
|
||||
metadata={
|
||||
"vram_texture": false
|
||||
}
|
||||
|
||||
[deps]
|
||||
|
||||
source_file="res://Icons/chevron-down.svg"
|
||||
dest_files=["res://.godot/imported/chevron-down.svg-484378157f0927346bbcbdbf4232b051.ctex"]
|
||||
source_file="res://Assets/Icons/chevron-down.svg"
|
||||
dest_files=["res://.godot/imported/chevron-down.svg-549b6fd6d6d40e9ebd832012d163f272.ctex"]
|
||||
|
||||
[params]
|
||||
|
||||
1
Assets/Icons/loader-circle.svg
Normal file
@@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="#ffffff" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-loader-circle-icon lucide-loader-circle"><path d="M21 12a9 9 0 1 1-6.219-8.56"/></svg>
|
||||
|
After Width: | Height: | Size: 283 B |
37
Assets/Icons/loader-circle.svg.import
Normal file
@@ -0,0 +1,37 @@
|
||||
[remap]
|
||||
|
||||
importer="texture"
|
||||
type="CompressedTexture2D"
|
||||
uid="uid://cttplkybt1dxv"
|
||||
path="res://.godot/imported/loader-circle.svg-c17ccf4fea88a610c3708518f9137af7.ctex"
|
||||
metadata={
|
||||
"vram_texture": false
|
||||
}
|
||||
|
||||
[deps]
|
||||
|
||||
source_file="res://Assets/Icons/loader-circle.svg"
|
||||
dest_files=["res://.godot/imported/loader-circle.svg-c17ccf4fea88a610c3708518f9137af7.ctex"]
|
||||
|
||||
[params]
|
||||
|
||||
compress/mode=0
|
||||
compress/high_quality=false
|
||||
compress/lossy_quality=0.7
|
||||
compress/hdr_compression=1
|
||||
compress/normal_map=0
|
||||
compress/channel_pack=0
|
||||
mipmaps/generate=false
|
||||
mipmaps/limit=-1
|
||||
roughness/mode=0
|
||||
roughness/src_normal=""
|
||||
process/fix_alpha_border=true
|
||||
process/premult_alpha=false
|
||||
process/normal_map_invert_y=false
|
||||
process/hdr_as_srgb=false
|
||||
process/hdr_clamp_exposure=false
|
||||
process/size_limit=0
|
||||
detect_3d/compress_to=1
|
||||
svg/scale=1.0
|
||||
editor/scale_with_editor_scale=false
|
||||
editor/convert_colors_with_editor_theme=false
|
||||
|
Before Width: | Height: | Size: 266 B After Width: | Height: | Size: 266 B |
@@ -3,15 +3,15 @@
|
||||
importer="texture"
|
||||
type="CompressedTexture2D"
|
||||
uid="uid://cehbtwq6gq0cn"
|
||||
path="res://.godot/imported/plus.svg-dfcf01023e04ffbd2a1c50b2672d981c.ctex"
|
||||
path="res://.godot/imported/plus.svg-f4b3570cb7fae700c6a08ebce6d60d56.ctex"
|
||||
metadata={
|
||||
"vram_texture": false
|
||||
}
|
||||
|
||||
[deps]
|
||||
|
||||
source_file="res://Icons/plus.svg"
|
||||
dest_files=["res://.godot/imported/plus.svg-dfcf01023e04ffbd2a1c50b2672d981c.ctex"]
|
||||
source_file="res://Assets/Icons/plus.svg"
|
||||
dest_files=["res://.godot/imported/plus.svg-f4b3570cb7fae700c6a08ebce6d60d56.ctex"]
|
||||
|
||||
[params]
|
||||
|
||||
|
Before Width: | Height: | Size: 319 B After Width: | Height: | Size: 319 B |
@@ -3,15 +3,15 @@
|
||||
importer="texture"
|
||||
type="CompressedTexture2D"
|
||||
uid="uid://cu4hjoba6etf"
|
||||
path="res://.godot/imported/rotate-cw.svg-868e19f6bcf83d62897eb2ac44a0b471.ctex"
|
||||
path="res://.godot/imported/rotate-cw.svg-dc1ce1f9471720aef7c52da0114941eb.ctex"
|
||||
metadata={
|
||||
"vram_texture": false
|
||||
}
|
||||
|
||||
[deps]
|
||||
|
||||
source_file="res://Icons/rotate-cw.svg"
|
||||
dest_files=["res://.godot/imported/rotate-cw.svg-868e19f6bcf83d62897eb2ac44a0b471.ctex"]
|
||||
source_file="res://Assets/Icons/rotate-cw.svg"
|
||||
dest_files=["res://.godot/imported/rotate-cw.svg-dc1ce1f9471720aef7c52da0114941eb.ctex"]
|
||||
|
||||
[params]
|
||||
|
||||
|
Before Width: | Height: | Size: 289 B After Width: | Height: | Size: 289 B |
@@ -3,15 +3,15 @@
|
||||
importer="texture"
|
||||
type="CompressedTexture2D"
|
||||
uid="uid://bf0vx7qwo28k6"
|
||||
path="res://.godot/imported/search.svg-597dbc74e85ee7dfea046ab610b3d4ad.ctex"
|
||||
path="res://.godot/imported/search.svg-1a2b06368a6d95d720ef3acf028b44e6.ctex"
|
||||
metadata={
|
||||
"vram_texture": false
|
||||
}
|
||||
|
||||
[deps]
|
||||
|
||||
source_file="res://Icons/search.svg"
|
||||
dest_files=["res://.godot/imported/search.svg-597dbc74e85ee7dfea046ab610b3d4ad.ctex"]
|
||||
source_file="res://Assets/Icons/search.svg"
|
||||
dest_files=["res://.godot/imported/search.svg-1a2b06368a6d95d720ef3acf028b44e6.ctex"]
|
||||
|
||||
[params]
|
||||
|
||||
|
Before Width: | Height: | Size: 264 B After Width: | Height: | Size: 264 B |
@@ -3,15 +3,15 @@
|
||||
importer="texture"
|
||||
type="CompressedTexture2D"
|
||||
uid="uid://gq8g7t4s3ryg"
|
||||
path="res://.godot/imported/x.svg-4402340e2f725e924f2e7d83afde3bea.ctex"
|
||||
path="res://.godot/imported/x.svg-0cde62f4f4d7229f6d4217f24c8f641d.ctex"
|
||||
metadata={
|
||||
"vram_texture": false
|
||||
}
|
||||
|
||||
[deps]
|
||||
|
||||
source_file="res://Icons/x.svg"
|
||||
dest_files=["res://.godot/imported/x.svg-4402340e2f725e924f2e7d83afde3bea.ctex"]
|
||||
source_file="res://Assets/Icons/x.svg"
|
||||
dest_files=["res://.godot/imported/x.svg-0cde62f4f4d7229f6d4217f24c8f641d.ctex"]
|
||||
|
||||
[params]
|
||||
|
||||
7
README.md
Normal file
@@ -0,0 +1,7 @@
|
||||
TODO:
|
||||
1. Write a new **selection system**. Godot's built-in `RichTextLabel` selection is limited by the node's boundaries. In normal web, holding click and dragging your mouse across the screen will select text across multiple nodes. Godot doesn't have a "set_selected_text" property, despite having one for "get_selected_text".
|
||||
2. **Right-click Dropdown** for basic text operations (Copy, Paste, Cut). Download options for images
|
||||
3. **Select-all CTRL+A shortcut**
|
||||
4. **Scrolling** in the website container
|
||||
5. **Store** tab containers so switching tabs won't erase previous tab.
|
||||
6. **GIF** support
|
||||
@@ -69,4 +69,4 @@ func _log_element_tree(element: HTMLParser.HTMLElement, depth: int):
|
||||
_log_result(element_info)
|
||||
|
||||
for child in element.children:
|
||||
_log_element_tree(child, depth + 1)
|
||||
_log_element_tree(child, depth + 1)
|
||||
|
||||
32
Scenes/Styles/BrowserText.tres
Normal file
@@ -0,0 +1,32 @@
|
||||
[gd_resource type="Theme" load_steps=7 format=3 uid="uid://bn6rbmdy60lhr"]
|
||||
|
||||
[sub_resource type="SystemFont" id="SystemFont_jecr6"]
|
||||
font_names = PackedStringArray("Serif")
|
||||
font_weight = 700
|
||||
|
||||
[sub_resource type="SystemFont" id="SystemFont_75mhk"]
|
||||
font_names = PackedStringArray("Serif")
|
||||
font_italic = true
|
||||
font_weight = 700
|
||||
|
||||
[sub_resource type="SystemFont" id="SystemFont_3k2jb"]
|
||||
font_names = PackedStringArray("Serif")
|
||||
font_italic = true
|
||||
|
||||
[sub_resource type="SystemFont" id="SystemFont_u0shw"]
|
||||
font_names = PackedStringArray("Monospace")
|
||||
|
||||
[sub_resource type="SystemFont" id="SystemFont_g4dwp"]
|
||||
font_names = PackedStringArray("Serif")
|
||||
|
||||
[sub_resource type="StyleBoxEmpty" id="StyleBoxEmpty_jecr6"]
|
||||
|
||||
[resource]
|
||||
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")
|
||||
RichTextLabel/fonts/bold_italics_font = SubResource("SystemFont_75mhk")
|
||||
RichTextLabel/fonts/italics_font = SubResource("SystemFont_3k2jb")
|
||||
RichTextLabel/fonts/mono_font = SubResource("SystemFont_u0shw")
|
||||
RichTextLabel/fonts/normal_font = SubResource("SystemFont_g4dwp")
|
||||
RichTextLabel/styles/focus = SubResource("StyleBoxEmpty_jecr6")
|
||||
@@ -1,11 +1,12 @@
|
||||
[gd_scene load_steps=11 format=3 uid="uid://sqhcxhcre081"]
|
||||
[gd_scene load_steps=12 format=3 uid="uid://sqhcxhcre081"]
|
||||
|
||||
[ext_resource type="Script" uid="uid://crpnnfqm3k5xv" path="res://Scripts/Tab.gd" id="1_q3baj"]
|
||||
[ext_resource type="Texture2D" uid="uid://gq8g7t4s3ryg" path="res://Icons/x.svg" id="2_pisds"]
|
||||
[ext_resource type="Texture2D" uid="uid://gq8g7t4s3ryg" path="res://Assets/Icons/x.svg" id="2_pisds"]
|
||||
[ext_resource type="StyleBox" uid="uid://fd1nftmqox32" path="res://Scenes/Styles/TabHoverDefault.tres" id="3_kjcxk"]
|
||||
[ext_resource type="Texture2D" uid="uid://c7u7a1u1v04bx" path="res://Scenes/Styles/TabGradientDefault.tres" id="3_q3baj"]
|
||||
[ext_resource type="StyleBox" uid="uid://bx3sgro1ageff" path="res://Scenes/Styles/TabDefault.tres" id="4_ib6pj"]
|
||||
[ext_resource type="Texture2D" uid="uid://dioe63fr47oq7" path="res://Scripts/youtube.png" id="6_bdsd2"]
|
||||
[ext_resource type="Texture2D" uid="uid://dglkjumm1q4lo" path="res://Assets/Icons/23x23-empty.svg" id="5_ib6pj"]
|
||||
[ext_resource type="Texture2D" uid="uid://70k6bw18rsri" path="res://icon.svg" id="6_ib6pj"]
|
||||
[ext_resource type="StyleBox" uid="uid://dn8exdnk8tjce" path="res://Scenes/Styles/CloseButtonHover.tres" id="6_pisds"]
|
||||
[ext_resource type="StyleBox" uid="uid://dn6r16retee3l" path="res://Scenes/Styles/CloseButtonNormal.tres" id="7_1ohlo"]
|
||||
|
||||
@@ -45,10 +46,20 @@ theme_override_styles/pressed = ExtResource("3_kjcxk")
|
||||
theme_override_styles/normal = ExtResource("4_ib6pj")
|
||||
action_mode = 0
|
||||
text = "(2) YouTube - STOP PLAYING WITH ME BITCHES FR"
|
||||
icon = ExtResource("6_bdsd2")
|
||||
icon = ExtResource("5_ib6pj")
|
||||
alignment = 0
|
||||
text_overrun_behavior = 3
|
||||
|
||||
[node name="Icon" type="TextureRect" parent="."]
|
||||
custom_minimum_size = Vector2(23, 23)
|
||||
layout_mode = 0
|
||||
offset_left = 8.0
|
||||
offset_top = 13.0
|
||||
offset_right = 31.0
|
||||
offset_bottom = 36.0
|
||||
texture = ExtResource("6_ib6pj")
|
||||
expand_mode = 1
|
||||
|
||||
[node name="CloseButton" type="Button" parent="."]
|
||||
z_index = 2
|
||||
custom_minimum_size = Vector2(34, 34)
|
||||
|
||||
23
Scenes/Tags/bold.tscn
Normal file
@@ -0,0 +1,23 @@
|
||||
[gd_scene load_steps=3 format=3 uid="uid://ijrbim6j8e36"]
|
||||
|
||||
[ext_resource type="Script" uid="uid://chdftsciuecfk" path="res://Scripts/Tags/bold.gd" id="1_04sgx"]
|
||||
[ext_resource type="Theme" uid="uid://bn6rbmdy60lhr" path="res://Scenes/Styles/BrowserText.tres" id="1_mtsji"]
|
||||
|
||||
[node name="BOLD" type="VBoxContainer"]
|
||||
anchors_preset = 10
|
||||
anchor_right = 1.0
|
||||
grow_horizontal = 2
|
||||
theme = ExtResource("1_mtsji")
|
||||
script = ExtResource("1_04sgx")
|
||||
|
||||
[node name="RichTextLabel" type="RichTextLabel" parent="."]
|
||||
layout_mode = 2
|
||||
size_flags_horizontal = 3
|
||||
focus_mode = 2
|
||||
mouse_default_cursor_shape = 1
|
||||
theme = ExtResource("1_mtsji")
|
||||
theme_override_colors/default_color = Color(0, 0, 0, 1)
|
||||
bbcode_enabled = true
|
||||
text = "What the sigma"
|
||||
fit_content = true
|
||||
selection_enabled = true
|
||||
10
Scenes/Tags/br.tscn
Normal file
@@ -0,0 +1,10 @@
|
||||
[gd_scene load_steps=2 format=3 uid="uid://dmnpful5xhtrk"]
|
||||
|
||||
[ext_resource type="Script" uid="uid://csd2kcqixac65" path="res://Scripts/Tags/br.gd" id="1_7hb8m"]
|
||||
|
||||
[node name="BR" type="Control"]
|
||||
layout_mode = 3
|
||||
anchors_preset = 10
|
||||
anchor_right = 1.0
|
||||
grow_horizontal = 2
|
||||
script = ExtResource("1_7hb8m")
|
||||
22
Scenes/Tags/code.tscn
Normal file
@@ -0,0 +1,22 @@
|
||||
[gd_scene load_steps=3 format=3 uid="uid://i5otagppegeo"]
|
||||
|
||||
[ext_resource type="Script" uid="uid://c3dnmqsnj0akr" path="res://Scripts/Tags/code.gd" id="1_g4dwp"]
|
||||
[ext_resource type="Theme" uid="uid://bn6rbmdy60lhr" path="res://Scenes/Styles/BrowserText.tres" id="2_u0shw"]
|
||||
|
||||
[node name="CODE" type="VBoxContainer"]
|
||||
anchors_preset = 10
|
||||
anchor_right = 1.0
|
||||
grow_horizontal = 2
|
||||
script = ExtResource("1_g4dwp")
|
||||
|
||||
[node name="RichTextLabel" type="RichTextLabel" parent="."]
|
||||
layout_mode = 2
|
||||
size_flags_horizontal = 3
|
||||
focus_mode = 2
|
||||
mouse_default_cursor_shape = 1
|
||||
theme = ExtResource("2_u0shw")
|
||||
theme_override_colors/default_color = Color(0, 0, 0, 1)
|
||||
bbcode_enabled = true
|
||||
text = "What the sigma"
|
||||
fit_content = true
|
||||
selection_enabled = true
|
||||
0
Scenes/Tags/h1.tscn
Normal file
10
Scenes/Tags/img.tscn
Normal file
@@ -0,0 +1,10 @@
|
||||
[gd_scene load_steps=2 format=3 uid="uid://b5rpke43iqfkt"]
|
||||
|
||||
[ext_resource type="Script" uid="uid://dgakysfyq773t" path="res://Scripts/Tags/img.gd" id="1_clm6l"]
|
||||
|
||||
[node name="TextureRect" type="TextureRect"]
|
||||
size_flags_horizontal = 0
|
||||
size_flags_vertical = 0
|
||||
expand_mode = 1
|
||||
stretch_mode = 2
|
||||
script = ExtResource("1_clm6l")
|
||||
22
Scenes/Tags/italic.tscn
Normal file
@@ -0,0 +1,22 @@
|
||||
[gd_scene load_steps=3 format=3 uid="uid://bdw0ahhesgnvr"]
|
||||
|
||||
[ext_resource type="Script" uid="uid://bamty87whxwxi" path="res://Scripts/Tags/italic.gd" id="1_ch1cm"]
|
||||
[ext_resource type="Theme" uid="uid://bn6rbmdy60lhr" path="res://Scenes/Styles/BrowserText.tres" id="1_vh1cg"]
|
||||
|
||||
[node name="ITALIC" type="VBoxContainer"]
|
||||
anchors_preset = 10
|
||||
anchor_right = 1.0
|
||||
grow_horizontal = 2
|
||||
theme = ExtResource("1_vh1cg")
|
||||
script = ExtResource("1_ch1cm")
|
||||
|
||||
[node name="RichTextLabel" type="RichTextLabel" parent="."]
|
||||
layout_mode = 2
|
||||
size_flags_horizontal = 3
|
||||
focus_mode = 2
|
||||
mouse_default_cursor_shape = 1
|
||||
theme_override_colors/default_color = Color(0, 0, 0, 1)
|
||||
bbcode_enabled = true
|
||||
text = "What the sigma"
|
||||
fit_content = true
|
||||
selection_enabled = true
|
||||
22
Scenes/Tags/mark.tscn
Normal file
@@ -0,0 +1,22 @@
|
||||
[gd_scene load_steps=3 format=3 uid="uid://dlj64k35igexw"]
|
||||
|
||||
[ext_resource type="Script" uid="uid://c2i8dwyyuufff" path="res://Scripts/Tags/mark.gd" id="1_j8rvb"]
|
||||
[ext_resource type="Theme" uid="uid://bn6rbmdy60lhr" path="res://Scenes/Styles/BrowserText.tres" id="1_jr508"]
|
||||
|
||||
[node name="MARK" type="VBoxContainer"]
|
||||
anchors_preset = 10
|
||||
anchor_right = 1.0
|
||||
grow_horizontal = 2
|
||||
theme = ExtResource("1_jr508")
|
||||
script = ExtResource("1_j8rvb")
|
||||
|
||||
[node name="RichTextLabel" type="RichTextLabel" parent="."]
|
||||
layout_mode = 2
|
||||
size_flags_horizontal = 3
|
||||
focus_mode = 2
|
||||
mouse_default_cursor_shape = 1
|
||||
theme_override_colors/default_color = Color(0, 0, 0, 1)
|
||||
bbcode_enabled = true
|
||||
text = "What the sigma"
|
||||
fit_content = true
|
||||
selection_enabled = true
|
||||
22
Scenes/Tags/p.tscn
Normal file
@@ -0,0 +1,22 @@
|
||||
[gd_scene load_steps=3 format=3 uid="uid://fr6lovy4ikok"]
|
||||
|
||||
[ext_resource type="Script" uid="uid://cg6kjvlx3an1j" path="res://Scripts/Tags/p.gd" id="1_pnbfg"]
|
||||
[ext_resource type="Theme" uid="uid://bn6rbmdy60lhr" path="res://Scenes/Styles/BrowserText.tres" id="2_1glvj"]
|
||||
|
||||
[node name="P" type="VBoxContainer"]
|
||||
anchors_preset = 10
|
||||
anchor_right = 1.0
|
||||
grow_horizontal = 2
|
||||
script = ExtResource("1_pnbfg")
|
||||
|
||||
[node name="RichTextLabel" type="RichTextLabel" parent="."]
|
||||
layout_mode = 2
|
||||
size_flags_horizontal = 3
|
||||
focus_mode = 2
|
||||
mouse_default_cursor_shape = 1
|
||||
theme = ExtResource("2_1glvj")
|
||||
theme_override_colors/default_color = Color(0, 0, 0, 1)
|
||||
bbcode_enabled = true
|
||||
text = "What the sigma"
|
||||
fit_content = true
|
||||
selection_enabled = true
|
||||
22
Scenes/Tags/pre.tscn
Normal file
@@ -0,0 +1,22 @@
|
||||
[gd_scene load_steps=3 format=3 uid="uid://byt2tvxanciuk"]
|
||||
|
||||
[ext_resource type="Script" uid="uid://8mam5rvtx72x" path="res://Scripts/Tags/pre.gd" id="1_7hb8m"]
|
||||
[ext_resource type="Theme" uid="uid://bn6rbmdy60lhr" path="res://Scenes/Styles/BrowserText.tres" id="1_xp1ft"]
|
||||
|
||||
[node name="PRE" type="VBoxContainer"]
|
||||
anchors_preset = 10
|
||||
anchor_right = 1.0
|
||||
grow_horizontal = 2
|
||||
theme = ExtResource("1_xp1ft")
|
||||
script = ExtResource("1_7hb8m")
|
||||
|
||||
[node name="RichTextLabel" type="RichTextLabel" parent="."]
|
||||
layout_mode = 2
|
||||
size_flags_horizontal = 3
|
||||
focus_mode = 2
|
||||
mouse_default_cursor_shape = 1
|
||||
theme_override_colors/default_color = Color(0, 0, 0, 1)
|
||||
bbcode_enabled = true
|
||||
text = "What the sigma"
|
||||
fit_content = true
|
||||
selection_enabled = true
|
||||
8
Scenes/Tags/separator.tscn
Normal file
@@ -0,0 +1,8 @@
|
||||
[gd_scene load_steps=2 format=3 uid="uid://drfl5d5o2cudk"]
|
||||
|
||||
[ext_resource type="Script" uid="uid://rol353cupbbf" path="res://Scripts/Tags/separator.gd" id="1_pu577"]
|
||||
|
||||
[node name="Separator" type="Control"]
|
||||
layout_mode = 3
|
||||
anchors_preset = 0
|
||||
script = ExtResource("1_pu577")
|
||||
22
Scenes/Tags/small.tscn
Normal file
@@ -0,0 +1,22 @@
|
||||
[gd_scene load_steps=3 format=3 uid="uid://btiiex1eu1krs"]
|
||||
|
||||
[ext_resource type="Script" uid="uid://xr7n1lat501x" path="res://Scripts/Tags/small.gd" id="1_5vt6h"]
|
||||
[ext_resource type="Theme" uid="uid://bn6rbmdy60lhr" path="res://Scenes/Styles/BrowserText.tres" id="1_yi3vu"]
|
||||
|
||||
[node name="SMALL" type="VBoxContainer"]
|
||||
anchors_preset = 10
|
||||
anchor_right = 1.0
|
||||
grow_horizontal = 2
|
||||
theme = ExtResource("1_yi3vu")
|
||||
script = ExtResource("1_5vt6h")
|
||||
|
||||
[node name="RichTextLabel" type="RichTextLabel" parent="."]
|
||||
layout_mode = 2
|
||||
size_flags_horizontal = 3
|
||||
focus_mode = 2
|
||||
mouse_default_cursor_shape = 1
|
||||
theme_override_colors/default_color = Color(0, 0, 0, 1)
|
||||
bbcode_enabled = true
|
||||
text = "What the sigma"
|
||||
fit_content = true
|
||||
selection_enabled = true
|
||||
22
Scenes/Tags/underline.tscn
Normal file
@@ -0,0 +1,22 @@
|
||||
[gd_scene load_steps=3 format=3 uid="uid://br7ys1wgsp5om"]
|
||||
|
||||
[ext_resource type="Script" uid="uid://x0hphtm8kf12" path="res://Scripts/Tags/underline.gd" id="1_7hb8m"]
|
||||
[ext_resource type="Theme" uid="uid://bn6rbmdy60lhr" path="res://Scenes/Styles/BrowserText.tres" id="1_xp1ft"]
|
||||
|
||||
[node name="UNDERLINE" type="VBoxContainer"]
|
||||
anchors_preset = 10
|
||||
anchor_right = 1.0
|
||||
grow_horizontal = 2
|
||||
theme = ExtResource("1_xp1ft")
|
||||
script = ExtResource("1_7hb8m")
|
||||
|
||||
[node name="RichTextLabel" type="RichTextLabel" parent="."]
|
||||
layout_mode = 2
|
||||
size_flags_horizontal = 3
|
||||
focus_mode = 2
|
||||
mouse_default_cursor_shape = 1
|
||||
theme_override_colors/default_color = Color(0, 0, 0, 1)
|
||||
bbcode_enabled = true
|
||||
text = "What the sigma"
|
||||
fit_content = true
|
||||
selection_enabled = true
|
||||
@@ -1,14 +1,14 @@
|
||||
[gd_scene load_steps=22 format=3 uid="uid://bytm7bt2s4ak8"]
|
||||
[gd_scene load_steps=23 format=3 uid="uid://bytm7bt2s4ak8"]
|
||||
|
||||
[ext_resource type="Script" uid="uid://bg5iqnwic1rio" path="res://Scripts/main.gd" id="1_8q3xr"]
|
||||
[ext_resource type="Texture2D" uid="uid://df1m4j7uxi63v" path="res://Icons/chevron-down.svg" id="2_6bp64"]
|
||||
[ext_resource type="Texture2D" uid="uid://df1m4j7uxi63v" path="res://Assets/Icons/chevron-down.svg" id="2_6bp64"]
|
||||
[ext_resource type="Script" uid="uid://cy0c74thgjwok" path="res://Scripts/TabContainer.gd" id="2_hptm8"]
|
||||
[ext_resource type="Texture2D" uid="uid://bf0vx7qwo28k6" path="res://Icons/search.svg" id="3_8gbba"]
|
||||
[ext_resource type="Texture2D" uid="uid://bp42ccs2nmbmw" path="res://Icons/arrow-left.svg" id="3_21xkr"]
|
||||
[ext_resource type="Texture2D" uid="uid://dyyylow47qd0k" path="res://Icons/arrow-right.svg" id="4_6bp64"]
|
||||
[ext_resource type="Texture2D" uid="uid://bf0vx7qwo28k6" path="res://Assets/Icons/search.svg" id="3_8gbba"]
|
||||
[ext_resource type="Texture2D" uid="uid://bp42ccs2nmbmw" path="res://Assets/Icons/arrow-left.svg" id="3_21xkr"]
|
||||
[ext_resource type="Texture2D" uid="uid://dyyylow47qd0k" path="res://Assets/Icons/arrow-right.svg" id="4_6bp64"]
|
||||
[ext_resource type="PackedScene" uid="uid://sqhcxhcre081" path="res://Scenes/Tab.tscn" id="4_344ge"]
|
||||
[ext_resource type="Texture2D" uid="uid://cu4hjoba6etf" path="res://Icons/rotate-cw.svg" id="5_344ge"]
|
||||
[ext_resource type="Texture2D" uid="uid://cehbtwq6gq0cn" path="res://Icons/plus.svg" id="5_ynf5e"]
|
||||
[ext_resource type="Texture2D" uid="uid://cu4hjoba6etf" path="res://Assets/Icons/rotate-cw.svg" id="5_344ge"]
|
||||
[ext_resource type="Texture2D" uid="uid://cehbtwq6gq0cn" path="res://Assets/Icons/plus.svg" id="5_ynf5e"]
|
||||
|
||||
[sub_resource type="StyleBoxEmpty" id="StyleBoxEmpty_344ge"]
|
||||
|
||||
@@ -61,13 +61,16 @@ expand_margin_left = 40.0
|
||||
LineEdit/styles/focus = SubResource("StyleBoxEmpty_8gbba")
|
||||
LineEdit/styles/normal = SubResource("StyleBoxFlat_8gbba")
|
||||
|
||||
[sub_resource type="StyleBoxFlat" id="StyleBoxFlat_white"]
|
||||
bg_color = Color(1, 1, 1, 1)
|
||||
|
||||
[sub_resource type="StyleBoxFlat" id="StyleBoxFlat_6iyac"]
|
||||
bg_color = Color(0.105882, 0.105882, 0.105882, 1)
|
||||
|
||||
[sub_resource type="StyleBoxFlat" id="StyleBoxFlat_21xkr"]
|
||||
bg_color = Color(0.168627, 0.168627, 0.168627, 1)
|
||||
|
||||
[node name="Control" type="Control"]
|
||||
[node name="Main" type="Control"]
|
||||
layout_mode = 3
|
||||
anchors_preset = 15
|
||||
anchor_right = 1.0
|
||||
@@ -187,17 +190,23 @@ stretch_mode = 5
|
||||
custom_minimum_size = Vector2(0, 5)
|
||||
layout_mode = 2
|
||||
|
||||
[node name="BottomContainer" type="Control" parent="VBoxContainer"]
|
||||
[node name="WebsiteContainer" type="VBoxContainer" parent="VBoxContainer"]
|
||||
unique_name_in_owner = true
|
||||
layout_mode = 2
|
||||
size_flags_vertical = 3
|
||||
theme_override_constants/separation = 22
|
||||
|
||||
[node name="ColorRect2" type="ColorRect" parent="VBoxContainer/BottomContainer"]
|
||||
[node name="WebsiteBackground" type="Panel" parent="."]
|
||||
z_index = -1
|
||||
layout_mode = 1
|
||||
anchors_preset = 15
|
||||
anchor_right = 1.0
|
||||
anchor_bottom = 1.0
|
||||
offset_top = 125.0
|
||||
grow_horizontal = 2
|
||||
grow_vertical = 2
|
||||
mouse_filter = 2
|
||||
theme_override_styles/panel = SubResource("StyleBoxFlat_white")
|
||||
|
||||
[node name="Panel" type="Panel" parent="."]
|
||||
z_index = -5
|
||||
@@ -212,7 +221,7 @@ theme_override_styles/panel = SubResource("StyleBoxFlat_6iyac")
|
||||
z_index = -6
|
||||
layout_mode = 2
|
||||
offset_right = 1920.0
|
||||
offset_bottom = 117.0
|
||||
offset_bottom = 125.0
|
||||
mouse_filter = 2
|
||||
theme_override_styles/panel = SubResource("StyleBoxFlat_21xkr")
|
||||
|
||||
|
||||
@@ -23,6 +23,18 @@ class HTMLElement:
|
||||
|
||||
func get_id() -> String:
|
||||
return get_attribute("id")
|
||||
|
||||
func get_collapsed_text() -> String:
|
||||
# Collapse whitespace: replace multiple spaces, tabs, newlines with single space
|
||||
var collapsed = text_content.strip_edges()
|
||||
# Replace multiple whitespace characters with single space
|
||||
var regex = RegEx.new()
|
||||
regex.compile("\\s+")
|
||||
return regex.sub(collapsed, " ", true)
|
||||
|
||||
func get_preserved_text() -> String:
|
||||
# For pre tags - preserve all whitespace
|
||||
return text_content
|
||||
|
||||
class ParseResult:
|
||||
var root: HTMLElement
|
||||
@@ -149,6 +161,10 @@ func get_title() -> String:
|
||||
var title_element = find_first("title")
|
||||
return title_element.text_content if title_element != null else ""
|
||||
|
||||
func get_icon() -> String:
|
||||
var icon_element = find_first("icon")
|
||||
return icon_element.get_attribute("src")
|
||||
|
||||
func get_meta_content(name_: String) -> String:
|
||||
var meta_elements = find_all("meta", "name")
|
||||
for element in meta_elements:
|
||||
|
||||
61
Scripts/Network.gd
Normal file
@@ -0,0 +1,61 @@
|
||||
extends Node
|
||||
|
||||
func fetch_image(url: String) -> ImageTexture:
|
||||
var http_request = HTTPRequest.new()
|
||||
add_child(http_request)
|
||||
|
||||
var error = http_request.request(url)
|
||||
if error != OK:
|
||||
print("Error making HTTP request: ", error)
|
||||
http_request.queue_free()
|
||||
return null
|
||||
|
||||
var response = await http_request.request_completed
|
||||
|
||||
var result = response[0] # HTTPClient.Result
|
||||
var response_code = response[1] # int
|
||||
var headers = response[2] # PackedStringArray
|
||||
var body = response[3] # PackedByteArray
|
||||
|
||||
http_request.queue_free()
|
||||
|
||||
if result != HTTPRequest.RESULT_SUCCESS or response_code != 200:
|
||||
print("Failed to fetch image. Result: ", result, " Response code: ", response_code)
|
||||
return null
|
||||
|
||||
# Get content type from headers
|
||||
var content_type = ""
|
||||
for header in headers:
|
||||
if header.to_lower().begins_with("content-type:"):
|
||||
content_type = header.split(":")[1].strip_edges().to_lower()
|
||||
break
|
||||
|
||||
var image: Image = Image.new()
|
||||
var load_error
|
||||
|
||||
# Load image based on content type
|
||||
if content_type.contains("png") or url.to_lower().ends_with(".png"):
|
||||
load_error = image.load_png_from_buffer(body)
|
||||
elif content_type.contains("jpeg") or content_type.contains("jpg") or url.to_lower().ends_with(".jpg") or url.to_lower().ends_with(".jpeg"):
|
||||
load_error = image.load_jpg_from_buffer(body)
|
||||
elif content_type.contains("webp") or url.to_lower().ends_with(".webp"):
|
||||
load_error = image.load_webp_from_buffer(body)
|
||||
elif content_type.contains("bmp"):
|
||||
load_error = image.load_bmp_from_buffer(body)
|
||||
elif content_type.contains("tga"):
|
||||
load_error = image.load_tga_from_buffer(body)
|
||||
else:
|
||||
print("Unknown or missing content-type. Attempting bruteforce converting across PNG, JPG and WebP...")
|
||||
load_error = image.load_png_from_buffer(body)
|
||||
if load_error != OK:
|
||||
load_error = image.load_jpg_from_buffer(body)
|
||||
if load_error != OK:
|
||||
load_error = image.load_webp_from_buffer(body)
|
||||
|
||||
if load_error != OK:
|
||||
print("Failed to load image from buffer. Content-Type: ", content_type, " Error: ", load_error)
|
||||
return null
|
||||
|
||||
var texture = ImageTexture.create_from_image(image)
|
||||
|
||||
return texture
|
||||
1
Scripts/Network.gd.uid
Normal file
@@ -0,0 +1 @@
|
||||
uid://bbfpng3opsnyp
|
||||
@@ -7,6 +7,7 @@ signal tab_closed
|
||||
@onready var gradient_texture: TextureRect = $GradientTexture
|
||||
@onready var button: Button = $Button
|
||||
@onready var close_button: Button = $CloseButton
|
||||
@onready var icon: TextureRect = $Icon
|
||||
|
||||
const TAB_GRADIENT: GradientTexture2D = preload("res://Scenes/Styles/TabGradient.tres")
|
||||
const TAB_GRADIENT_DEFAULT: GradientTexture2D = preload("res://Scenes/Styles/TabGradientDefault.tres")
|
||||
@@ -36,6 +37,13 @@ func _process(_delta):
|
||||
else:
|
||||
close_button.add_theme_stylebox_override("normal", CLOSE_BUTTON_NORMAL)
|
||||
|
||||
func set_title(title: String) -> void:
|
||||
button.text = title
|
||||
|
||||
func set_icon(new_icon: Texture) -> void:
|
||||
icon.texture = new_icon
|
||||
icon.rotation = 0
|
||||
|
||||
func _on_button_mouse_entered() -> void:
|
||||
mouse_over_tab = true
|
||||
if is_active: return
|
||||
|
||||
@@ -1,8 +1,11 @@
|
||||
class_name TabManager
|
||||
extends HFlowContainer
|
||||
|
||||
var tabs: Array[Tab] = []
|
||||
var active_tab := 0
|
||||
|
||||
@onready var main: Main = $"../.."
|
||||
|
||||
const TAB = preload("res://Scenes/Tab.tscn")
|
||||
|
||||
const TAB_NORMAL: StyleBoxFlat = preload("res://Scenes/Styles/TabNormal.tres")
|
||||
@@ -79,6 +82,9 @@ func create_tab() -> void:
|
||||
h_box_container.add_child(tab)
|
||||
|
||||
set_active_tab(index)
|
||||
|
||||
# WARNING: temporary
|
||||
main.render()
|
||||
|
||||
func _input(event: InputEvent) -> void:
|
||||
if Input.is_action_just_pressed("NewTab"):
|
||||
|
||||
5
Scripts/Tags/bold.gd
Normal file
@@ -0,0 +1,5 @@
|
||||
extends VBoxContainer
|
||||
|
||||
func init(element: HTMLParser.HTMLElement) -> void:
|
||||
var label: RichTextLabel = $RichTextLabel
|
||||
label.text = "[font_size=24][b]%s[/b][/font_size]" % element.get_collapsed_text()
|
||||
1
Scripts/Tags/bold.gd.uid
Normal file
@@ -0,0 +1 @@
|
||||
uid://chdftsciuecfk
|
||||
4
Scripts/Tags/br.gd
Normal file
@@ -0,0 +1,4 @@
|
||||
extends Control
|
||||
|
||||
func init(element: HTMLParser.HTMLElement) -> void:
|
||||
custom_minimum_size.y = 24
|
||||
1
Scripts/Tags/br.gd.uid
Normal file
@@ -0,0 +1 @@
|
||||
uid://csd2kcqixac65
|
||||
5
Scripts/Tags/code.gd
Normal file
@@ -0,0 +1,5 @@
|
||||
extends VBoxContainer
|
||||
|
||||
func init(element: HTMLParser.HTMLElement) -> void:
|
||||
var label: RichTextLabel = $RichTextLabel
|
||||
label.text = "[font_size=20][code]%s[/code][/font_size]" % element.get_collapsed_text()
|
||||
1
Scripts/Tags/code.gd.uid
Normal file
@@ -0,0 +1 @@
|
||||
uid://c3dnmqsnj0akr
|
||||
11
Scripts/Tags/img.gd
Normal file
@@ -0,0 +1,11 @@
|
||||
extends TextureRect
|
||||
|
||||
func init(element: HTMLParser.HTMLElement) -> void:
|
||||
var src = element.get_attribute("src")
|
||||
if !src: return print("Ignoring <img/> tag without \"src\" attribute.")
|
||||
|
||||
texture = await Network.fetch_image(src)
|
||||
|
||||
var texture_size = texture.get_size()
|
||||
custom_minimum_size = texture_size
|
||||
size = texture_size
|
||||
1
Scripts/Tags/img.gd.uid
Normal file
@@ -0,0 +1 @@
|
||||
uid://dgakysfyq773t
|
||||
5
Scripts/Tags/italic.gd
Normal file
@@ -0,0 +1,5 @@
|
||||
extends VBoxContainer
|
||||
|
||||
func init(element: HTMLParser.HTMLElement) -> void:
|
||||
var label: RichTextLabel = $RichTextLabel
|
||||
label.text = "[font_size=24][i]%s[/i][/font_size]" % element.get_collapsed_text()
|
||||
1
Scripts/Tags/italic.gd.uid
Normal file
@@ -0,0 +1 @@
|
||||
uid://bamty87whxwxi
|
||||
5
Scripts/Tags/mark.gd
Normal file
@@ -0,0 +1,5 @@
|
||||
extends VBoxContainer
|
||||
|
||||
func init(element: HTMLParser.HTMLElement) -> void:
|
||||
var label: RichTextLabel = $RichTextLabel
|
||||
label.text = "[font_size=24][bgcolor=#FFFF00]%s[/bgcolor][/font_size]" % element.get_collapsed_text()
|
||||
1
Scripts/Tags/mark.gd.uid
Normal file
@@ -0,0 +1 @@
|
||||
uid://c2i8dwyyuufff
|
||||
5
Scripts/Tags/p.gd
Normal file
@@ -0,0 +1,5 @@
|
||||
extends Control
|
||||
|
||||
func init(element: HTMLParser.HTMLElement) -> void:
|
||||
var label: RichTextLabel = $RichTextLabel
|
||||
label.text = "[font_size=24]%s[/font_size]" % element.get_collapsed_text()
|
||||
1
Scripts/Tags/p.gd.uid
Normal file
@@ -0,0 +1 @@
|
||||
uid://cg6kjvlx3an1j
|
||||
5
Scripts/Tags/pre.gd
Normal file
@@ -0,0 +1,5 @@
|
||||
extends VBoxContainer
|
||||
|
||||
func init(element: HTMLParser.HTMLElement) -> void:
|
||||
var label: RichTextLabel = $RichTextLabel
|
||||
label.text = "[font_size=20][code]%s[/code][/font_size]" % element.get_preserved_text()
|
||||
1
Scripts/Tags/pre.gd.uid
Normal file
@@ -0,0 +1 @@
|
||||
uid://8mam5rvtx72x
|
||||
26
Scripts/Tags/separator.gd
Normal file
@@ -0,0 +1,26 @@
|
||||
extends Control
|
||||
|
||||
var separator_node: Separator
|
||||
|
||||
func init(element: HTMLParser.HTMLElement) -> void:
|
||||
var direction = element.get_attribute("direction")
|
||||
|
||||
if direction == "vertical":
|
||||
separator_node = VSeparator.new()
|
||||
separator_node.size_flags_vertical = Control.SIZE_EXPAND_FILL
|
||||
separator_node.custom_minimum_size.x = 2
|
||||
separator_node.layout_mode = 1
|
||||
separator_node.anchors_preset = Control.PRESET_LEFT_WIDE
|
||||
else:
|
||||
separator_node = HSeparator.new()
|
||||
separator_node.size_flags_horizontal = Control.SIZE_EXPAND_FILL
|
||||
separator_node.custom_minimum_size.y = 2
|
||||
separator_node.layout_mode = 1
|
||||
separator_node.anchors_preset = Control.PRESET_FULL_RECT
|
||||
|
||||
add_child(separator_node)
|
||||
|
||||
# Make the parent control also expand to fill available space
|
||||
size_flags_horizontal = Control.SIZE_EXPAND_FILL
|
||||
if direction == "vertical":
|
||||
size_flags_vertical = Control.SIZE_EXPAND_FILL
|
||||
1
Scripts/Tags/separator.gd.uid
Normal file
@@ -0,0 +1 @@
|
||||
uid://rol353cupbbf
|
||||
5
Scripts/Tags/small.gd
Normal file
@@ -0,0 +1,5 @@
|
||||
extends VBoxContainer
|
||||
|
||||
func init(element: HTMLParser.HTMLElement) -> void:
|
||||
var label: RichTextLabel = $RichTextLabel
|
||||
label.text = "[font_size=18]%s[/font_size]" % element.get_collapsed_text()
|
||||
1
Scripts/Tags/small.gd.uid
Normal file
@@ -0,0 +1 @@
|
||||
uid://xr7n1lat501x
|
||||
5
Scripts/Tags/underline.gd
Normal file
@@ -0,0 +1,5 @@
|
||||
extends VBoxContainer
|
||||
|
||||
func init(element: HTMLParser.HTMLElement) -> void:
|
||||
var label: RichTextLabel = $RichTextLabel
|
||||
label.text = "[font_size=24][u]%s[/u][/font_size]" % element.get_collapsed_text()
|
||||
1
Scripts/Tags/underline.gd.uid
Normal file
@@ -0,0 +1 @@
|
||||
uid://x0hphtm8kf12
|
||||
123
Scripts/main.gd
@@ -1,12 +1,32 @@
|
||||
class_name Main
|
||||
extends Control
|
||||
|
||||
func _ready():
|
||||
render()
|
||||
@onready var website_container: Control = %WebsiteContainer
|
||||
@onready var tab_container: TabManager = $VBoxContainer/TabContainer
|
||||
const LOADER_CIRCLE = preload("res://Assets/Icons/loader-circle.svg")
|
||||
|
||||
var loading_tween: Tween
|
||||
|
||||
const P = preload("res://Scenes/Tags/p.tscn")
|
||||
const IMG = preload("res://Scenes/Tags/img.tscn")
|
||||
const SEPARATOR = preload("res://Scenes/Tags/separator.tscn")
|
||||
const BOLD = preload("res://Scenes/Tags/bold.tscn")
|
||||
const ITALIC = preload("res://Scenes/Tags/italic.tscn")
|
||||
const UNDERLINE = preload("res://Scenes/Tags/underline.tscn")
|
||||
const SMALL = preload("res://Scenes/Tags/small.tscn")
|
||||
const MARK = preload("res://Scenes/Tags/mark.tscn")
|
||||
const CODE = preload("res://Scenes/Tags/code.tscn")
|
||||
const PRE = preload("res://Scenes/Tags/pre.tscn")
|
||||
const BR = preload("res://Scenes/Tags/br.tscn")
|
||||
|
||||
func render():
|
||||
# Clear existing content
|
||||
for child in website_container.get_children():
|
||||
child.queue_free()
|
||||
|
||||
var html_bytes = "<head>
|
||||
<title>My cool web</title>
|
||||
<icon href=\"https://buss.log/icon.ico\"> <!--This image will be the page's icon-->
|
||||
<icon src=\"https://upload.wikimedia.org/wikipedia/commons/thumb/c/c1/Google_%22G%22_logo.svg/768px-Google_%22G%22_logo.svg.png\"> <!--This image will be the page's icon-->
|
||||
|
||||
<meta name=\"theme-color\" content=\"#000000\">
|
||||
<meta name=\"description\" content=\"My cool web\">
|
||||
@@ -16,14 +36,29 @@ func render():
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<h1>Hey there!</h1>
|
||||
<img href=\"https://buss.log/rick-astley.png\" />
|
||||
<p>Hey there! this is a test</p>
|
||||
<b>This is bold</b>
|
||||
<i>This is italic</i>
|
||||
<u>This is underline</u>
|
||||
<small>this is small</small>
|
||||
<mark>this is marked</mark>
|
||||
<code>this is code</code>
|
||||
|
||||
<pre>
|
||||
Text in a pre element
|
||||
is displayed in a fixed-width
|
||||
font, and it preserves
|
||||
both spaces and
|
||||
line breaks
|
||||
</pre>
|
||||
|
||||
<script src=\"script2.lua\" />
|
||||
<separator direction=\"horizontal\" />
|
||||
<img src=\"https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcQMNUPIKabszX0Js_c0kfa4cz_JQYKfGTuBUA&s\" />
|
||||
<separator direction=\"vertical\" />
|
||||
</body>".to_utf8_buffer()
|
||||
|
||||
# Create parser and parse
|
||||
var parser = HTMLParser.new(html_bytes)
|
||||
var parser: HTMLParser = HTMLParser.new(html_bytes)
|
||||
var parse_result = parser.parse()
|
||||
|
||||
print("Total elements found: " + str(parse_result.all_elements.size()))
|
||||
@@ -32,3 +67,77 @@ func render():
|
||||
print("Parse errors: " + str(parse_result.errors))
|
||||
|
||||
# TODO: render the shit on the screen
|
||||
var tab = tab_container.tabs[tab_container.active_tab]
|
||||
|
||||
var title = parser.get_title()
|
||||
tab.set_title(title)
|
||||
|
||||
var icon = parser.get_icon()
|
||||
set_loading_icon(tab)
|
||||
tab.set_icon(await Network.fetch_image(icon))
|
||||
stop_loading_icon()
|
||||
|
||||
var body = parser.find_first("body")
|
||||
for element: HTMLParser.HTMLElement in body.children:
|
||||
match element.tag_name:
|
||||
"p":
|
||||
var p = P.instantiate()
|
||||
p.init(element)
|
||||
website_container.add_child(p)
|
||||
"pre":
|
||||
var pre = PRE.instantiate()
|
||||
pre.init(element)
|
||||
website_container.add_child(pre)
|
||||
"br":
|
||||
var br = BR.instantiate()
|
||||
br.init(element)
|
||||
website_container.add_child(br)
|
||||
"b":
|
||||
var bold = BOLD.instantiate()
|
||||
bold.init(element)
|
||||
website_container.add_child(bold)
|
||||
"img":
|
||||
var img = IMG.instantiate()
|
||||
img.init(element)
|
||||
website_container.add_child(img)
|
||||
"separator":
|
||||
var separator = SEPARATOR.instantiate()
|
||||
separator.init(element)
|
||||
website_container.add_child(separator)
|
||||
"i":
|
||||
var italic = ITALIC.instantiate()
|
||||
italic.init(element)
|
||||
website_container.add_child(italic)
|
||||
"u":
|
||||
var underline = UNDERLINE.instantiate()
|
||||
underline.init(element)
|
||||
website_container.add_child(underline)
|
||||
"small":
|
||||
var small = SMALL.instantiate()
|
||||
small.init(element)
|
||||
website_container.add_child(small)
|
||||
"mark":
|
||||
var mark = MARK.instantiate()
|
||||
mark.init(element)
|
||||
website_container.add_child(mark)
|
||||
"code":
|
||||
var code = CODE.instantiate()
|
||||
code.init(element)
|
||||
website_container.add_child(code)
|
||||
_:
|
||||
print("Couldn't parse unsupported HTML tag \"%s\"" % element.tag_name)
|
||||
|
||||
func set_loading_icon(tab: Tab) -> void:
|
||||
tab.set_icon(LOADER_CIRCLE)
|
||||
|
||||
loading_tween = create_tween()
|
||||
loading_tween.set_loops()
|
||||
|
||||
var icon = tab.icon
|
||||
icon.pivot_offset = Vector2(11.5, 11.5)
|
||||
loading_tween.tween_method(func(angle): icon.rotation = angle, 0.0, TAU, 1.0)
|
||||
|
||||
func stop_loading_icon() -> void:
|
||||
if loading_tween:
|
||||
loading_tween.kill()
|
||||
loading_tween = null
|
||||
|
||||
|
Before Width: | Height: | Size: 2.2 KiB |
21
godotgif/LICENSE.txt
Normal file
@@ -0,0 +1,21 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2023 B0TLANNER Games
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
139
godotgif/README.md
Normal file
@@ -0,0 +1,139 @@
|
||||
# Godot GIF
|
||||
<br>
|
||||
|
||||
<p align="center">
|
||||
<img src="./docs-images/logo.gif" alt="Logo" width="128" height="128" />
|
||||
</p>
|
||||
|
||||
<p align="center">
|
||||
<a href="https://github.com/BOTLANNER/godot-gif/actions/workflows/build_releases.yml"><img alt="GitHub Build" src="https://github.com/BOTLANNER/godot-gif/actions/workflows/build_releases.yml/badge.svg" height="20"/></a>
|
||||
<a href="https://github.com/BOTLANNER/godot-gif/blob/develop/LICENSE.txt"><img alt="MIT License" src="https://img.shields.io/github/license/BOTLANNER/godot-gif" height="20"/></a>
|
||||
</p>
|
||||
|
||||
|
||||
## Description
|
||||
GDExtension for Godot 4+ to load GIF files as [AnimatedTexture](https://docs.godotengine.org/en/stable/classes/class_animatedtexture.html) and/or [SpriteFrames](https://docs.godotengine.org/en/stable/classes/class_spriteframes.html).
|
||||
|
||||
NOTE: ~~**AnimatedTexture**~~ has been marked as deprecated according to development docs and could be removed in a future version of Godot.
|
||||
|
||||
|
||||
## Usage
|
||||
|
||||
### Editor
|
||||
|
||||
Gif files can be imported at edit time as one of the supported types via Import options.
|
||||
|
||||
<details open>
|
||||
<summary>Editor Imports Options</summary>
|
||||
|
||||

|
||||
</details>
|
||||
|
||||
See the [Editor Imports](./demo/editor_imports_example.tscn) example scene.
|
||||
<details open>
|
||||
<summary>Editor Imports Example</summary>
|
||||
|
||||

|
||||
</details>
|
||||
|
||||
<hr/>
|
||||
|
||||
### Runtime
|
||||
|
||||
Gif files can be loaded at runtime as one of the supported types via the `GifManager` singleton.
|
||||
|
||||
`GifManager` exposes the following methods for loading gifs either from file or from bytes directly:
|
||||

|
||||
|
||||
e.g. to load from file
|
||||
```py
|
||||
get_node("AnimFromRuntimeFile").texture = GifManager.animated_texture_from_file("res://examples/file/optic.gif")
|
||||
|
||||
get_node("AnimatedSprite2RuntimeFile").sprite_frames = GifManager.sprite_frames_from_file("res://examples/file/optic.gif")
|
||||
```
|
||||
|
||||
See the [Runtime Imports](./demo/main.tscn) example scene.
|
||||
<details open>
|
||||
<summary>Runtime Imports Example</summary>
|
||||
|
||||

|
||||
</details>
|
||||
|
||||
|
||||
## Installation
|
||||
|
||||
Download the `gdextension` artifact from the [latest successful build](https://github.com/BOTLANNER/godot-gif/actions/workflows/build_releases.yml). (It should be right at the bottom of the **Summary**)
|
||||

|
||||
|
||||
Extract the contents to your Godot project directory.
|
||||
|
||||
You should have an `addons` directory at the root with the following structure:
|
||||
```bash
|
||||
└───addons
|
||||
└───godotgif
|
||||
│ godotgif.gdextension
|
||||
│ LICENSE.txt
|
||||
│ README.md
|
||||
│
|
||||
└───bin
|
||||
│ godotgif.windows.template_debug.x86_32.dll
|
||||
│ godotgif.windows.template_debug.x86_64.dll
|
||||
│ godotgif.windows.template_release.x86_32.dll
|
||||
│ godotgif.windows.template_release.x86_64.dll
|
||||
│ libgodotgif.android.template_debug.arm64.so
|
||||
│ libgodotgif.android.template_release.arm64.so
|
||||
│ libgodotgif.linux.template_debug.x86_32.so
|
||||
│ libgodotgif.linux.template_debug.x86_64.so
|
||||
│ libgodotgif.linux.template_release.x86_32.so
|
||||
│ libgodotgif.linux.template_release.x86_64.so
|
||||
│
|
||||
├───godotgif.macos.template_debug.framework
|
||||
│ libgodotgif.macos.template_debug
|
||||
│
|
||||
└───godotgif.macos.template_release.framework
|
||||
libgodotgif.macos.template_release
|
||||
```
|
||||
|
||||
Open your project. Any exisitng gifs should auto-import. New gifs in the project directory will automatically import as `SpriteFrames`. To convert them into `AnimatedTexture`, update the [import settings](#editor).
|
||||
|
||||
The `GifManager` class should also now be available for access within GDScript.
|
||||
|
||||
## Contributing
|
||||
|
||||
### Setup
|
||||
|
||||
Ensure **SCons** is setup. Refer to [Introduction to the buildsystem](https://docs.godotengine.org/en/stable/contributing/development/compiling/introduction_to_the_buildsystem.html)
|
||||
|
||||
* If using a different version of Godot, be sure to dump the bindings e.g.
|
||||
```sh
|
||||
godot --dump-extension-api extension_api.json
|
||||
```
|
||||
* Compile with
|
||||
```sh
|
||||
scons platform=<platform> custom_api_file=extension_api.json
|
||||
```
|
||||
|
||||
### Debugging
|
||||
|
||||
This repository is configured for use with [VSCode](https://code.visualstudio.com/)
|
||||
|
||||
[Launch configurations](./.vscode/launch.json) have been setup for both debugging in editor and in runtime provided certain **VSCode** extensions are present and environment variables are defined.
|
||||
|
||||
The following environment variables are required:
|
||||
|
||||
1. `GODOT_PATH` - The directory in which Godot is installed
|
||||
1. `GODOT_EXECUTABLE` - The executable name of the Godot installation
|
||||
|
||||
### More Details
|
||||
Refer to [GDExtension C++ example](https://docs.godotengine.org/en/stable/tutorials/scripting/gdextension/gdextension_cpp_example.html)
|
||||
|
||||
|
||||
## License
|
||||
|
||||
Unless otherwise specified, the extension is released under the
|
||||
[MIT license](LICENSE.txt).
|
||||
|
||||
See the full list of third-party libraries with their licenses used by this
|
||||
extension at [src/thirdparty/README.md](src/thirdparty/README.md).
|
||||
|
||||
This implementation heavily borrowed inspiration from the [gif module](https://github.com/goostengine/goost/tree/gd3/modules/gif) for [Goost](https://github.com/goostengine/goost) that is currently only based on Godot 3
|
||||
BIN
godotgif/bin/godotgif.windows.template_debug.x86_32.dll
Normal file
BIN
godotgif/bin/godotgif.windows.template_debug.x86_64.dll
Normal file
BIN
godotgif/bin/godotgif.windows.template_release.x86_32.dll
Normal file
BIN
godotgif/bin/godotgif.windows.template_release.x86_64.dll
Normal file
BIN
godotgif/bin/libgodotgif.android.template_debug.arm64.so
Normal file
BIN
godotgif/bin/libgodotgif.android.template_release.arm64.so
Normal file
BIN
godotgif/bin/libgodotgif.linux.template_debug.x86_32.so
Normal file
BIN
godotgif/bin/libgodotgif.linux.template_debug.x86_64.so
Normal file
BIN
godotgif/bin/libgodotgif.linux.template_release.x86_32.so
Normal file
BIN
godotgif/bin/libgodotgif.linux.template_release.x86_64.so
Normal file
BIN
godotgif/bin/~godotgif.windows.template_debug.x86_64.dll
Normal file
23
godotgif/godotgif.gdextension
Normal file
@@ -0,0 +1,23 @@
|
||||
[configuration]
|
||||
|
||||
entry_symbol = "godot_gif_library_init"
|
||||
compatibility_minimum = "4.4"
|
||||
|
||||
[libraries]
|
||||
|
||||
macos.debug = "bin/godotgif.macos.template_debug.framework/libgodotgif.macos.template_debug"
|
||||
macos.release = "bin/godotgif.macos.template_release.framework/libgodotgif.macos.template_release"
|
||||
windows.debug.x86_32 = "bin/godotgif.windows.template_debug.x86_32.dll"
|
||||
windows.release.x86_32 = "bin/godotgif.windows.template_release.x86_32.dll"
|
||||
windows.debug.x86_64 = "bin/godotgif.windows.template_debug.x86_64.dll"
|
||||
windows.release.x86_64 = "bin/godotgif.windows.template_release.x86_64.dll"
|
||||
linux.debug.x86_64 = "bin/libgodotgif.linux.template_debug.x86_64.so"
|
||||
linux.release.x86_64 = "bin/libgodotgif.linux.template_release.x86_64.so"
|
||||
linux.debug.arm64 = "bin/libgodotgif.linux.template_debug.arm64.so"
|
||||
linux.release.arm64 = "bin/libgodotgif.linux.template_release.arm64.so"
|
||||
linux.debug.rv64 = "bin/libgodotgif.linux.template_debug.rv64.so"
|
||||
linux.release.rv64 = "bin/libgodotgif.linux.template_release.rv64.so"
|
||||
android.debug.x86_64 = "bin/libgodotgif.android.template_debug.x86_64.so"
|
||||
android.release.x86_64 = "bin/libgodotgif.android.template_release.x86_64.so"
|
||||
android.debug.arm64 = "bin/libgodotgif.android.template_debug.arm64.so"
|
||||
android.release.arm64 = "bin/libgodotgif.android.template_release.arm64.so"
|
||||
1
godotgif/godotgif.gdextension.uid
Normal file
@@ -0,0 +1 @@
|
||||
uid://dsrtogrtghklj
|
||||
@@ -18,6 +18,7 @@ config/icon="res://icon.svg"
|
||||
[autoload]
|
||||
|
||||
Constants="*res://Scripts/Constants.gd"
|
||||
Network="*res://Scripts/Network.gd"
|
||||
|
||||
[display]
|
||||
|
||||
@@ -25,6 +26,14 @@ window/size/viewport_width=1920
|
||||
window/size/viewport_height=1080
|
||||
window/stretch/aspect="ignore"
|
||||
|
||||
[file_customization]
|
||||
|
||||
folder_colors={
|
||||
"res://Assets/": "yellow",
|
||||
"res://Scenes/": "red",
|
||||
"res://Scripts/": "blue"
|
||||
}
|
||||
|
||||
[input]
|
||||
|
||||
NewTab={
|
||||
|
||||