input (radio/password), max/min length, pattern
This commit is contained in:
1
Assets/Icons/radio.svg
Normal file
1
Assets/Icons/radio.svg
Normal file
@@ -0,0 +1 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg width="100%" height="100%" viewBox="0 0 134 134" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xml:space="preserve" xmlns:serif="http://www.serif.com/" style="fill-rule:evenodd;clip-rule:evenodd;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:1.5;"><ellipse cx="66.61" cy="66.646" rx="62.416" ry="62.478" style="fill:none;stroke:#000;stroke-width:8.33px;"/></svg>
|
||||||
|
After Width: | Height: | Size: 579 B |
37
Assets/Icons/radio.svg.import
Normal file
37
Assets/Icons/radio.svg.import
Normal file
@@ -0,0 +1,37 @@
|
|||||||
|
[remap]
|
||||||
|
|
||||||
|
importer="texture"
|
||||||
|
type="CompressedTexture2D"
|
||||||
|
uid="uid://b2v8ee23580c3"
|
||||||
|
path="res://.godot/imported/radio.svg-320eafa791feaf0d1d926ec0d2ba3722.ctex"
|
||||||
|
metadata={
|
||||||
|
"vram_texture": false
|
||||||
|
}
|
||||||
|
|
||||||
|
[deps]
|
||||||
|
|
||||||
|
source_file="res://Assets/Icons/radio.svg"
|
||||||
|
dest_files=["res://.godot/imported/radio.svg-320eafa791feaf0d1d926ec0d2ba3722.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
|
||||||
1
Assets/Icons/radio_checked.svg
Normal file
1
Assets/Icons/radio_checked.svg
Normal file
@@ -0,0 +1 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg width="100%" height="100%" viewBox="0 0 134 134" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xml:space="preserve" xmlns:serif="http://www.serif.com/" style="fill-rule:evenodd;clip-rule:evenodd;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:1.5;"><ellipse cx="66.61" cy="66.646" rx="62.416" ry="62.478" style="fill:none;stroke:#3f77ce;stroke-width:8.33px;"/><ellipse cx="66.667" cy="66.646" rx="45.648" ry="45.693" style="fill:#3f77ce;"/></svg>
|
||||||
|
After Width: | Height: | Size: 662 B |
37
Assets/Icons/radio_checked.svg.import
Normal file
37
Assets/Icons/radio_checked.svg.import
Normal file
@@ -0,0 +1,37 @@
|
|||||||
|
[remap]
|
||||||
|
|
||||||
|
importer="texture"
|
||||||
|
type="CompressedTexture2D"
|
||||||
|
uid="uid://bj7bpovnm25ml"
|
||||||
|
path="res://.godot/imported/radio_checked.svg-81396277cd631c074cae607c415d3a5c.ctex"
|
||||||
|
metadata={
|
||||||
|
"vram_texture": false
|
||||||
|
}
|
||||||
|
|
||||||
|
[deps]
|
||||||
|
|
||||||
|
source_file="res://Assets/Icons/radio_checked.svg"
|
||||||
|
dest_files=["res://.godot/imported/radio_checked.svg-81396277cd631c074cae607c415d3a5c.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
|
||||||
1
Assets/Icons/radio_checked_grayscale.svg
Normal file
1
Assets/Icons/radio_checked_grayscale.svg
Normal file
@@ -0,0 +1 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:serif="http://www.serif.com/" width="100%" height="100%" viewBox="0 0 134 134" version="1.1" xml:space="preserve" style="fill-rule:evenodd;clip-rule:evenodd;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:1.5;"><ellipse cx="66.61" cy="66.646" rx="62.416" ry="62.478" style="fill: none;stroke: #707070;stroke-width:8.33px;"/><ellipse cx="66.667" cy="66.646" rx="45.648" ry="45.693" style="fill: #707070;"/></svg>
|
||||||
|
After Width: | Height: | Size: 513 B |
37
Assets/Icons/radio_checked_grayscale.svg.import
Normal file
37
Assets/Icons/radio_checked_grayscale.svg.import
Normal file
@@ -0,0 +1,37 @@
|
|||||||
|
[remap]
|
||||||
|
|
||||||
|
importer="texture"
|
||||||
|
type="CompressedTexture2D"
|
||||||
|
uid="uid://y1xqfcd8ro5t"
|
||||||
|
path="res://.godot/imported/radio_checked_grayscale.svg-6ce9eb51f7fcbe2c1034ed12866d95cf.ctex"
|
||||||
|
metadata={
|
||||||
|
"vram_texture": false
|
||||||
|
}
|
||||||
|
|
||||||
|
[deps]
|
||||||
|
|
||||||
|
source_file="res://Assets/Icons/radio_checked_grayscale.svg"
|
||||||
|
dest_files=["res://.godot/imported/radio_checked_grayscale.svg-6ce9eb51f7fcbe2c1034ed12866d95cf.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
|
||||||
1
Assets/Icons/radio_disabled.svg
Normal file
1
Assets/Icons/radio_disabled.svg
Normal file
@@ -0,0 +1 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg width="100%" height="100%" viewBox="0 0 134 134" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xml:space="preserve" xmlns:serif="http://www.serif.com/" style="fill-rule:evenodd;clip-rule:evenodd;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:1.5;"><ellipse cx="66.61" cy="66.646" rx="62.416" ry="62.478" style="fill:none;stroke:#707070;stroke-width:8.33px;"/></svg>
|
||||||
|
After Width: | Height: | Size: 582 B |
37
Assets/Icons/radio_disabled.svg.import
Normal file
37
Assets/Icons/radio_disabled.svg.import
Normal file
@@ -0,0 +1,37 @@
|
|||||||
|
[remap]
|
||||||
|
|
||||||
|
importer="texture"
|
||||||
|
type="CompressedTexture2D"
|
||||||
|
uid="uid://bs414mrvwdmcn"
|
||||||
|
path="res://.godot/imported/radio_disabled.svg-04a182ffa1f439025aa6457482c84d92.ctex"
|
||||||
|
metadata={
|
||||||
|
"vram_texture": false
|
||||||
|
}
|
||||||
|
|
||||||
|
[deps]
|
||||||
|
|
||||||
|
source_file="res://Assets/Icons/radio_disabled.svg"
|
||||||
|
dest_files=["res://.godot/imported/radio_disabled.svg-04a182ffa1f439025aa6457482c84d92.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
|
||||||
@@ -6,7 +6,8 @@ TODO:
|
|||||||
5. **Store** tab containers so switching tabs won't erase previous tab.
|
5. **Store** tab containers so switching tabs won't erase previous tab.
|
||||||
6. **GIF** support
|
6. **GIF** support
|
||||||
7. **Video** support via [GDE GoZen](https://github.com/VoylinsGamedevJourney/gde_gozen)
|
7. **Video** support via [GDE GoZen](https://github.com/VoylinsGamedevJourney/gde_gozen)
|
||||||
8. **More input types** (password, email, number, etc.)
|
8. **More input types** (url, tel, date, time, etc.)
|
||||||
|
9. **Required** attribute for inputs
|
||||||
|
|
||||||
Issues:
|
Issues:
|
||||||
1. **< br />** counts as 1 element in **WebsiteContainer**, therefore despite being (0,0) in size, it counts as double in spacing.
|
1. **< br />** counts as 1 element in **WebsiteContainer**, therefore despite being (0,0) in size, it counts as double in spacing.
|
||||||
@@ -1,9 +1,13 @@
|
|||||||
[gd_resource type="Theme" load_steps=17 format=3 uid="uid://bn6rbmdy60lhr"]
|
[gd_resource type="Theme" load_steps=21 format=3 uid="uid://bn6rbmdy60lhr"]
|
||||||
|
|
||||||
[ext_resource type="Texture2D" uid="uid://dn4dxn8hkrd64" path="res://Assets/Icons/checkbox.svg" id="1_75mhk"]
|
[ext_resource type="Texture2D" uid="uid://dn4dxn8hkrd64" path="res://Assets/Icons/checkbox.svg" id="1_75mhk"]
|
||||||
[ext_resource type="Texture2D" uid="uid://b6ucuyluuw43" path="res://Assets/Icons/checkbox_pressed_grayscale.svg" id="2_2abar"]
|
[ext_resource type="Texture2D" uid="uid://b6ucuyluuw43" path="res://Assets/Icons/checkbox_pressed_grayscale.svg" id="2_2abar"]
|
||||||
[ext_resource type="Texture2D" uid="uid://c5scqw224r2e5" path="res://Assets/Icons/checkbox_pressed.svg" id="2_3k2jb"]
|
[ext_resource type="Texture2D" uid="uid://c5scqw224r2e5" path="res://Assets/Icons/checkbox_pressed.svg" id="2_3k2jb"]
|
||||||
|
[ext_resource type="Texture2D" uid="uid://b2v8ee23580c3" path="res://Assets/Icons/radio.svg" id="3_3weog"]
|
||||||
[ext_resource type="Texture2D" uid="uid://bap17ryrkcyey" path="res://Assets/Icons/checkbox_disabled.svg" id="4_c32on"]
|
[ext_resource type="Texture2D" uid="uid://bap17ryrkcyey" path="res://Assets/Icons/checkbox_disabled.svg" id="4_c32on"]
|
||||||
|
[ext_resource type="Texture2D" uid="uid://y1xqfcd8ro5t" path="res://Assets/Icons/radio_checked_grayscale.svg" id="4_n77xs"]
|
||||||
|
[ext_resource type="Texture2D" uid="uid://bj7bpovnm25ml" path="res://Assets/Icons/radio_checked.svg" id="4_sesrd"]
|
||||||
|
[ext_resource type="Texture2D" uid="uid://bs414mrvwdmcn" path="res://Assets/Icons/radio_disabled.svg" id="6_r011l"]
|
||||||
|
|
||||||
[sub_resource type="StyleBoxEmpty" id="StyleBoxEmpty_c32on"]
|
[sub_resource type="StyleBoxEmpty" id="StyleBoxEmpty_c32on"]
|
||||||
|
|
||||||
@@ -77,6 +81,10 @@ Button/styles/hover = SubResource("StyleBoxFlat_7g0pl")
|
|||||||
Button/styles/normal = SubResource("StyleBoxFlat_c32on")
|
Button/styles/normal = SubResource("StyleBoxFlat_c32on")
|
||||||
CheckBox/icons/checked = ExtResource("2_3k2jb")
|
CheckBox/icons/checked = ExtResource("2_3k2jb")
|
||||||
CheckBox/icons/checked_disabled = ExtResource("2_2abar")
|
CheckBox/icons/checked_disabled = ExtResource("2_2abar")
|
||||||
|
CheckBox/icons/radio_checked = ExtResource("4_sesrd")
|
||||||
|
CheckBox/icons/radio_checked_disabled = ExtResource("4_n77xs")
|
||||||
|
CheckBox/icons/radio_unchecked = ExtResource("3_3weog")
|
||||||
|
CheckBox/icons/radio_unchecked_disabled = ExtResource("6_r011l")
|
||||||
CheckBox/icons/unchecked = ExtResource("1_75mhk")
|
CheckBox/icons/unchecked = ExtResource("1_75mhk")
|
||||||
CheckBox/icons/unchecked_disabled = ExtResource("4_c32on")
|
CheckBox/icons/unchecked_disabled = ExtResource("4_c32on")
|
||||||
CheckBox/styles/focus = SubResource("StyleBoxEmpty_75mhk")
|
CheckBox/styles/focus = SubResource("StyleBoxEmpty_75mhk")
|
||||||
|
|||||||
@@ -1,7 +1,8 @@
|
|||||||
[gd_scene load_steps=3 format=3 uid="uid://c7yay102a3b4c"]
|
[gd_scene load_steps=4 format=3 uid="uid://c7yay102a3b4c"]
|
||||||
|
|
||||||
[ext_resource type="Script" uid="uid://kv6ebscarj2e" path="res://Scripts/Tags/input.gd" id="1_input"]
|
[ext_resource type="Script" uid="uid://kv6ebscarj2e" path="res://Scripts/Tags/input.gd" id="1_input"]
|
||||||
[ext_resource type="Theme" uid="uid://bn6rbmdy60lhr" path="res://Scenes/Styles/BrowserText.tres" id="2_theme"]
|
[ext_resource type="Theme" uid="uid://bn6rbmdy60lhr" path="res://Scenes/Styles/BrowserText.tres" id="2_theme"]
|
||||||
|
[ext_resource type="ButtonGroup" uid="uid://dgvdef1uht5ht" path="res://Scenes/Tags/new_button_group.tres" id="3_a88g6"]
|
||||||
|
|
||||||
[node name="Input" type="Control"]
|
[node name="Input" type="Control"]
|
||||||
layout_mode = 3
|
layout_mode = 3
|
||||||
@@ -21,6 +22,7 @@ layout_mode = 1
|
|||||||
offset_right = 400.0
|
offset_right = 400.0
|
||||||
offset_bottom = 35.0
|
offset_bottom = 35.0
|
||||||
theme = ExtResource("2_theme")
|
theme = ExtResource("2_theme")
|
||||||
|
text = "test"
|
||||||
placeholder_text = "Enter text..."
|
placeholder_text = "Enter text..."
|
||||||
caret_blink = true
|
caret_blink = true
|
||||||
|
|
||||||
@@ -32,3 +34,13 @@ offset_bottom = 31.0
|
|||||||
theme = ExtResource("2_theme")
|
theme = ExtResource("2_theme")
|
||||||
theme_override_constants/icon_max_width = 24
|
theme_override_constants/icon_max_width = 24
|
||||||
flat = true
|
flat = true
|
||||||
|
|
||||||
|
[node name="RadioButton" type="CheckBox" parent="."]
|
||||||
|
visible = false
|
||||||
|
layout_mode = 0
|
||||||
|
offset_right = 31.0
|
||||||
|
offset_bottom = 31.0
|
||||||
|
theme = ExtResource("2_theme")
|
||||||
|
theme_override_constants/icon_max_width = 24
|
||||||
|
button_group = ExtResource("3_a88g6")
|
||||||
|
flat = true
|
||||||
|
|||||||
45
Scenes/Tags/input.tscn8601746517.tmp
Normal file
45
Scenes/Tags/input.tscn8601746517.tmp
Normal file
@@ -0,0 +1,45 @@
|
|||||||
|
[gd_scene load_steps=4 format=3 uid="uid://c7yay102a3b4c"]
|
||||||
|
|
||||||
|
[ext_resource type="Script" uid="uid://kv6ebscarj2e" path="res://Scripts/Tags/input.gd" id="1_input"]
|
||||||
|
[ext_resource type="Theme" uid="uid://bn6rbmdy60lhr" path="res://Scenes/Styles/BrowserText.tres" id="2_theme"]
|
||||||
|
[ext_resource type="ButtonGroup" uid="uid://dgvdef1uht5ht" path="res://Scenes/Tags/new_button_group.tres" id="3_a88g6"]
|
||||||
|
|
||||||
|
[node name="Input" type="Control"]
|
||||||
|
layout_mode = 3
|
||||||
|
anchors_preset = 15
|
||||||
|
anchor_right = 1.0
|
||||||
|
anchor_bottom = 1.0
|
||||||
|
offset_right = 400.0
|
||||||
|
offset_bottom = 31.0
|
||||||
|
grow_horizontal = 2
|
||||||
|
grow_vertical = 2
|
||||||
|
size_flags_horizontal = 3
|
||||||
|
size_flags_vertical = 0
|
||||||
|
script = ExtResource("1_input")
|
||||||
|
|
||||||
|
[node name="LineEdit" type="LineEdit" parent="."]
|
||||||
|
visible = false
|
||||||
|
layout_mode = 1
|
||||||
|
offset_right = 400.0
|
||||||
|
offset_bottom = 35.0
|
||||||
|
theme = ExtResource("2_theme")
|
||||||
|
placeholder_text = "Enter text..."
|
||||||
|
caret_blink = true
|
||||||
|
|
||||||
|
[node name="CheckBox" type="CheckBox" parent="."]
|
||||||
|
visible = false
|
||||||
|
layout_mode = 0
|
||||||
|
offset_right = 31.0
|
||||||
|
offset_bottom = 31.0
|
||||||
|
theme = ExtResource("2_theme")
|
||||||
|
theme_override_constants/icon_max_width = 24
|
||||||
|
flat = true
|
||||||
|
|
||||||
|
[node name="RadioButton" type="CheckBox" parent="."]
|
||||||
|
layout_mode = 0
|
||||||
|
offset_right = 31.0
|
||||||
|
offset_bottom = 31.0
|
||||||
|
theme = ExtResource("2_theme")
|
||||||
|
theme_override_constants/icon_max_width = 24
|
||||||
|
button_group = ExtResource("3_a88g6")
|
||||||
|
flat = true
|
||||||
3
Scenes/Tags/new_button_group.tres
Normal file
3
Scenes/Tags/new_button_group.tres
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
[gd_resource type="ButtonGroup" format=3 uid="uid://dgvdef1uht5ht"]
|
||||||
|
|
||||||
|
[resource]
|
||||||
@@ -1,23 +1,93 @@
|
|||||||
extends Control
|
extends Control
|
||||||
|
static var button_groups: Dictionary = {}
|
||||||
|
|
||||||
func init(element: HTMLParser.HTMLElement) -> void:
|
func init(element: HTMLParser.HTMLElement) -> void:
|
||||||
var line_edit: LineEdit = $LineEdit
|
var line_edit: LineEdit = $LineEdit
|
||||||
var check_box: CheckBox = $CheckBox
|
var check_box: CheckBox = $CheckBox
|
||||||
|
var radio_button: CheckBox = $RadioButton
|
||||||
|
|
||||||
var input_type = element.get_attribute("type").to_lower()
|
var input_type = element.get_attribute("type").to_lower()
|
||||||
var placeholder = element.get_attribute("placeholder")
|
var placeholder = element.get_attribute("placeholder")
|
||||||
var value = element.get_attribute("value")
|
var value = element.get_attribute("value")
|
||||||
|
var group = element.get_attribute("group")
|
||||||
|
var minlength = element.get_attribute("minlength")
|
||||||
|
var maxlength = element.get_attribute("maxlength")
|
||||||
|
var pattern = element.get_attribute("pattern")
|
||||||
|
|
||||||
|
# Hide all inputs initially
|
||||||
|
line_edit.visible = false
|
||||||
|
check_box.visible = false
|
||||||
|
radio_button.visible = false
|
||||||
|
|
||||||
match input_type:
|
match input_type:
|
||||||
"checkbox":
|
"checkbox":
|
||||||
line_edit.visible = false
|
|
||||||
check_box.visible = true
|
check_box.visible = true
|
||||||
if value and value == "true": check_box.button_pressed = true
|
if value and value == "true": check_box.button_pressed = true
|
||||||
custom_minimum_size = check_box.size
|
custom_minimum_size = check_box.size
|
||||||
|
"radio":
|
||||||
|
radio_button.visible = true
|
||||||
|
radio_button.toggle_mode = true
|
||||||
|
if value and value == "true": radio_button.button_pressed = true
|
||||||
|
custom_minimum_size = radio_button.size
|
||||||
|
|
||||||
|
if group.length() > 0:
|
||||||
|
if not button_groups.has(group):
|
||||||
|
button_groups[group] = ButtonGroup.new()
|
||||||
|
radio_button.button_group = button_groups[group]
|
||||||
|
"password":
|
||||||
|
line_edit.visible = true
|
||||||
|
line_edit.secret = true
|
||||||
|
custom_minimum_size = line_edit.size
|
||||||
|
setup_text_input(line_edit, placeholder, value, minlength, maxlength, pattern)
|
||||||
_: # Default to text input
|
_: # Default to text input
|
||||||
line_edit.visible = true
|
line_edit.visible = true
|
||||||
check_box.visible = false
|
line_edit.secret = false
|
||||||
custom_minimum_size = line_edit.size
|
custom_minimum_size = line_edit.size
|
||||||
|
setup_text_input(line_edit, placeholder, value, minlength, maxlength, pattern)
|
||||||
|
|
||||||
|
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
|
if placeholder: line_edit.placeholder_text = placeholder
|
||||||
if value: line_edit.text = value
|
if value: line_edit.text = value
|
||||||
|
|
||||||
|
line_edit.max_length = maxlength.to_int()
|
||||||
|
|
||||||
|
if minlength.length() > 0 or pattern.length() > 0:
|
||||||
|
line_edit.text_changed.connect(_on_text_changed.bind(minlength, pattern))
|
||||||
|
|
||||||
|
func _on_text_changed(new_text: String, minlength: String, pattern: String) -> void:
|
||||||
|
var line_edit = get_node("LineEdit") as LineEdit
|
||||||
|
var is_valid = true
|
||||||
|
|
||||||
|
# Check minimum length
|
||||||
|
if minlength.length() > 0 and minlength.is_valid_int():
|
||||||
|
var min_len = minlength.to_int()
|
||||||
|
if new_text.length() < min_len and new_text.length() > 0:
|
||||||
|
is_valid = false
|
||||||
|
|
||||||
|
# Check pattern (regex)
|
||||||
|
if pattern.length() > 0 and new_text.length() > 0:
|
||||||
|
var regex = RegEx.new()
|
||||||
|
if regex.compile(pattern) == OK:
|
||||||
|
if not regex.search(new_text):
|
||||||
|
is_valid = false
|
||||||
|
|
||||||
|
if is_valid:
|
||||||
|
# Reset to default styles
|
||||||
|
line_edit.remove_theme_stylebox_override("normal")
|
||||||
|
line_edit.remove_theme_stylebox_override("focus")
|
||||||
|
line_edit.modulate = Color.WHITE
|
||||||
|
else:
|
||||||
|
var normal_style = create_red_border_style_from_theme(line_edit, "normal")
|
||||||
|
var focus_style = create_red_border_style_from_theme(line_edit, "focus")
|
||||||
|
|
||||||
|
line_edit.add_theme_stylebox_override("normal", normal_style)
|
||||||
|
line_edit.add_theme_stylebox_override("focus", focus_style)
|
||||||
|
line_edit.modulate = Color.WHITE
|
||||||
|
|
||||||
|
func create_red_border_style_from_theme(line_edit: LineEdit, style_name: String) -> StyleBoxFlat:
|
||||||
|
var original_style: StyleBoxFlat = line_edit.get_theme_stylebox(style_name)
|
||||||
|
var style: StyleBoxFlat = original_style.duplicate()
|
||||||
|
|
||||||
|
style.border_color = Color.RED
|
||||||
|
|
||||||
|
return style
|
||||||
|
|||||||
172
Scripts/main.gd
172
Scripts/main.gd
@@ -74,15 +74,28 @@ both spaces and
|
|||||||
line breaks
|
line breaks
|
||||||
</pre>
|
</pre>
|
||||||
|
|
||||||
<form>
|
<!-- action, method, and type=submit are for when we implement Lua -->
|
||||||
|
<form action=\"/submit\" method=\"POST\">
|
||||||
<span>Name:</span>
|
<span>Name:</span>
|
||||||
<input type=\"text\" placeholder=\"First name\" value=\"John\" />
|
<input type=\"text\" placeholder=\"First name\" value=\"John\" maxlength=\"20\" minlength=\"3\" />
|
||||||
<span>Surname:</span>
|
<span>Email regex:</span>
|
||||||
<input type=\"text\" placeholder=\"Last name\" value=\"Doe\" />
|
<input type=\"text\" placeholder=\"Last name\" value=\"Doe\" pattern=\"^[^@\\s]+@[^@\\s]+\\.[^@\\s]+$\" />
|
||||||
<span>Smart:</span>
|
<span>Smart:</span>
|
||||||
<input type=\"checkbox\" />
|
<input type=\"checkbox\" />
|
||||||
<input type=\"checkbox\" value=\"true\" />
|
<input type=\"checkbox\" value=\"true\" />
|
||||||
<button>Submit</button>
|
|
||||||
|
<p>favorite food</p>
|
||||||
|
<input type=\"radio\" group=\"food\" />
|
||||||
|
<span>Pizza</span>
|
||||||
|
<input type=\"radio\" group=\"food\" />
|
||||||
|
<span>Berry</span>
|
||||||
|
<input type=\"radio\" group=\"food\" />
|
||||||
|
<span>Gary</span>
|
||||||
|
|
||||||
|
<input type=\"password\" placeholder=\"your password...\" />
|
||||||
|
<button type=\"submit\">Submit</button>
|
||||||
|
|
||||||
|
|
||||||
</form>
|
</form>
|
||||||
|
|
||||||
<separator direction=\"horizontal\" />
|
<separator direction=\"horizontal\" />
|
||||||
@@ -138,88 +151,13 @@ line breaks
|
|||||||
|
|
||||||
continue
|
continue
|
||||||
|
|
||||||
match element.tag_name:
|
var element_node = create_element_node(element)
|
||||||
"p":
|
if element_node:
|
||||||
var p = P.instantiate()
|
website_container.add_child(element_node)
|
||||||
p.init(element)
|
# Handle hyperlinks for all elements
|
||||||
website_container.add_child(p)
|
if contains_hyperlink(element) and element_node.has_method("get") and element_node.get("rich_text_label"):
|
||||||
if contains_hyperlink(element):
|
element_node.rich_text_label.meta_clicked.connect(func(meta): OS.shell_open(str(meta)))
|
||||||
p.rich_text_label.meta_clicked.connect(func(meta): OS.shell_open(str(meta)))
|
else:
|
||||||
"h1":
|
|
||||||
var h1 = H1.instantiate()
|
|
||||||
h1.init(element)
|
|
||||||
website_container.add_child(h1)
|
|
||||||
if contains_hyperlink(element):
|
|
||||||
h1.rich_text_label.meta_clicked.connect(func(meta): OS.shell_open(str(meta)))
|
|
||||||
"h2":
|
|
||||||
var h2 = H2.instantiate()
|
|
||||||
h2.init(element)
|
|
||||||
website_container.add_child(h2)
|
|
||||||
if contains_hyperlink(element):
|
|
||||||
h2.rich_text_label.meta_clicked.connect(func(meta): OS.shell_open(str(meta)))
|
|
||||||
"h3":
|
|
||||||
var h3 = H3.instantiate()
|
|
||||||
h3.init(element)
|
|
||||||
website_container.add_child(h3)
|
|
||||||
if contains_hyperlink(element):
|
|
||||||
h3.rich_text_label.meta_clicked.connect(func(meta): OS.shell_open(str(meta)))
|
|
||||||
"h4":
|
|
||||||
var h4 = H4.instantiate()
|
|
||||||
h4.init(element)
|
|
||||||
website_container.add_child(h4)
|
|
||||||
if contains_hyperlink(element):
|
|
||||||
h4.rich_text_label.meta_clicked.connect(func(meta): OS.shell_open(str(meta)))
|
|
||||||
"h5":
|
|
||||||
var h5 = H5.instantiate()
|
|
||||||
h5.init(element)
|
|
||||||
website_container.add_child(h5)
|
|
||||||
if contains_hyperlink(element):
|
|
||||||
h5.rich_text_label.meta_clicked.connect(func(meta): OS.shell_open(str(meta)))
|
|
||||||
"h6":
|
|
||||||
var h6 = H6.instantiate()
|
|
||||||
h6.init(element)
|
|
||||||
website_container.add_child(h6)
|
|
||||||
if contains_hyperlink(element):
|
|
||||||
h6.rich_text_label.meta_clicked.connect(func(meta): OS.shell_open(str(meta)))
|
|
||||||
"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)
|
|
||||||
"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)
|
|
||||||
"form":
|
|
||||||
var form = FORM.instantiate()
|
|
||||||
form.init(element)
|
|
||||||
website_container.add_child(form)
|
|
||||||
|
|
||||||
# Render form children
|
|
||||||
for child_element in element.children:
|
|
||||||
var child_node = create_element_node(child_element)
|
|
||||||
if child_node:
|
|
||||||
form.add_child(child_node)
|
|
||||||
"input":
|
|
||||||
var input = INPUT.instantiate()
|
|
||||||
input.init(element)
|
|
||||||
website_container.add_child(input)
|
|
||||||
"button":
|
|
||||||
var button = BUTTON.instantiate()
|
|
||||||
button.init(element)
|
|
||||||
website_container.add_child(button)
|
|
||||||
"span":
|
|
||||||
var span = SPAN.instantiate()
|
|
||||||
span.init(element)
|
|
||||||
website_container.add_child(span)
|
|
||||||
_:
|
|
||||||
print("Couldn't parse unsupported HTML tag \"%s\"" % element.tag_name)
|
print("Couldn't parse unsupported HTML tag \"%s\"" % element.tag_name)
|
||||||
|
|
||||||
i += 1
|
i += 1
|
||||||
@@ -254,18 +192,60 @@ func contains_hyperlink(element: HTMLParser.HTMLElement) -> bool:
|
|||||||
return false
|
return false
|
||||||
|
|
||||||
func create_element_node(element: HTMLParser.HTMLElement) -> Control:
|
func create_element_node(element: HTMLParser.HTMLElement) -> Control:
|
||||||
|
var node: Control = null
|
||||||
|
|
||||||
match element.tag_name:
|
match element.tag_name:
|
||||||
|
"p":
|
||||||
|
node = P.instantiate()
|
||||||
|
node.init(element)
|
||||||
|
"h1":
|
||||||
|
node = H1.instantiate()
|
||||||
|
node.init(element)
|
||||||
|
"h2":
|
||||||
|
node = H2.instantiate()
|
||||||
|
node.init(element)
|
||||||
|
"h3":
|
||||||
|
node = H3.instantiate()
|
||||||
|
node.init(element)
|
||||||
|
"h4":
|
||||||
|
node = H4.instantiate()
|
||||||
|
node.init(element)
|
||||||
|
"h5":
|
||||||
|
node = H5.instantiate()
|
||||||
|
node.init(element)
|
||||||
|
"h6":
|
||||||
|
node = H6.instantiate()
|
||||||
|
node.init(element)
|
||||||
|
"pre":
|
||||||
|
node = PRE.instantiate()
|
||||||
|
node.init(element)
|
||||||
|
"br":
|
||||||
|
node = BR.instantiate()
|
||||||
|
node.init(element)
|
||||||
|
"img":
|
||||||
|
node = IMG.instantiate()
|
||||||
|
node.init(element)
|
||||||
|
"separator":
|
||||||
|
node = SEPARATOR.instantiate()
|
||||||
|
node.init(element)
|
||||||
|
"form":
|
||||||
|
node = FORM.instantiate()
|
||||||
|
node.init(element)
|
||||||
|
|
||||||
|
for child_element in element.children:
|
||||||
|
var child_node = create_element_node(child_element)
|
||||||
|
if child_node:
|
||||||
|
node.add_child(child_node)
|
||||||
"input":
|
"input":
|
||||||
var input = INPUT.instantiate()
|
node = INPUT.instantiate()
|
||||||
input.init(element)
|
node.init(element)
|
||||||
return input
|
|
||||||
"button":
|
"button":
|
||||||
var button = BUTTON.instantiate()
|
node = BUTTON.instantiate()
|
||||||
button.init(element)
|
node.init(element)
|
||||||
return button
|
|
||||||
"span":
|
"span":
|
||||||
var span = SPAN.instantiate()
|
node = SPAN.instantiate()
|
||||||
span.init(element)
|
node.init(element)
|
||||||
return span
|
|
||||||
_:
|
_:
|
||||||
return null
|
return null
|
||||||
|
|
||||||
|
return node
|
||||||
|
|||||||
Reference in New Issue
Block a user