Adds steps logic for the register form.
@@ -0,0 +1,21 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2023 deadpixelsociety
|
||||
|
||||
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.
|
||||
@@ -0,0 +1,62 @@
|
||||
@tool
|
||||
extends Node
|
||||
class_name ControlValidator
|
||||
|
||||
@export var validator: Validator:
|
||||
set(value):
|
||||
validator = value
|
||||
_on_validator_added()
|
||||
|
||||
|
||||
func _ready() -> void:
|
||||
tree_entered.connect(_on_tree_entered)
|
||||
tree_exiting.connect(_on_tree_exiting)
|
||||
_configure_validator()
|
||||
_on_validator_added()
|
||||
|
||||
|
||||
func _configure_validator() -> void:
|
||||
if validator != null:
|
||||
return
|
||||
var parent = get_parent()
|
||||
if not parent:
|
||||
return
|
||||
var found = Validation.find_validator(parent)
|
||||
if found:
|
||||
validator = found.duplicate(true)
|
||||
else:
|
||||
validator = Validator.new()
|
||||
|
||||
|
||||
func _get_configuration_warnings() -> PackedStringArray:
|
||||
if not validator:
|
||||
return []
|
||||
var list = PackedStringArray()
|
||||
for rule in validator.rules:
|
||||
if not rule.is_valid():
|
||||
list.append(rule.get_invalid_message())
|
||||
return list
|
||||
|
||||
|
||||
func _on_tree_entered() -> void:
|
||||
_configure_validator()
|
||||
_on_validator_added()
|
||||
|
||||
|
||||
func _on_tree_exiting() -> void:
|
||||
_on_validator_removed()
|
||||
|
||||
|
||||
func _on_validator_added() -> void:
|
||||
var parent = get_parent()
|
||||
if not parent or not validator:
|
||||
return
|
||||
Validation.validator_added.emit(parent, validator)
|
||||
update_configuration_warnings()
|
||||
|
||||
|
||||
func _on_validator_removed() -> void:
|
||||
var parent = get_parent()
|
||||
if not parent:
|
||||
return
|
||||
Validation.validator_removed.emit(parent)
|
||||
|
After Width: | Height: | Size: 524 B |
@@ -0,0 +1,34 @@
|
||||
[remap]
|
||||
|
||||
importer="texture"
|
||||
type="CompressedTexture2D"
|
||||
uid="uid://hohynkx70xob"
|
||||
path="res://.godot/imported/editor_icon.png-6f130a2788dfaa185bebbdd85ed98d66.ctex"
|
||||
metadata={
|
||||
"vram_texture": false
|
||||
}
|
||||
|
||||
[deps]
|
||||
|
||||
source_file="res://addons/godot-form-validator/editor_icon.png"
|
||||
dest_files=["res://.godot/imported/editor_icon.png-6f130a2788dfaa185bebbdd85ed98d66.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
|
||||
@@ -0,0 +1,34 @@
|
||||
extends PanelContainer
|
||||
|
||||
@onready var form_validator_control: FormValidator = $MarginContainer/FormValidator
|
||||
|
||||
func _on_form_validator_control_control_validated(control, passed, messages) -> void:
|
||||
var error_label = _get_error_label(control)
|
||||
var valid_label = _get_valid_label(control)
|
||||
if passed:
|
||||
if error_label:
|
||||
error_label.hide()
|
||||
if valid_label:
|
||||
valid_label.show()
|
||||
else:
|
||||
if error_label:
|
||||
error_label.text = ", ".join(messages)
|
||||
error_label.show()
|
||||
if valid_label:
|
||||
valid_label.hide()
|
||||
|
||||
|
||||
func _get_error_label(control: Control) -> Label:
|
||||
return find_child(control.name + "Error", true, false) as Label
|
||||
|
||||
|
||||
func _get_valid_label(control: Control) -> Label:
|
||||
return find_child(control.name + "Valid", true, false) as Label
|
||||
|
||||
|
||||
func _on_validate_pressed() -> void:
|
||||
form_validator_control.validate()
|
||||
|
||||
|
||||
func _on_exit_pressed() -> void:
|
||||
get_tree().quit()
|
||||
@@ -0,0 +1,441 @@
|
||||
[gd_scene load_steps=41 format=3 uid="uid://dpi5vv8r80o7r"]
|
||||
|
||||
[ext_resource type="Script" path="res://addons/godot-form-validator/example/example.gd" id="1_8caq6"]
|
||||
[ext_resource type="Script" path="res://addons/godot-form-validator/form_validator.gd" id="2_mtxo0"]
|
||||
[ext_resource type="Script" path="res://addons/godot-form-validator/control_validator.gd" id="3_hkwup"]
|
||||
[ext_resource type="Script" path="res://addons/godot-form-validator/rules/alpha_rule.gd" id="4_dq1df"]
|
||||
[ext_resource type="Script" path="res://addons/godot-form-validator/rules/required_rule.gd" id="5_cu56g"]
|
||||
[ext_resource type="Script" path="res://addons/godot-form-validator/validators/line_edit_validator.gd" id="5_rknpr"]
|
||||
[ext_resource type="Script" path="res://addons/godot-form-validator/rules/numeric_rule.gd" id="7_6vtuw"]
|
||||
[ext_resource type="Script" path="res://addons/godot-form-validator/rules/alphanumeric_rule.gd" id="8_mu0ia"]
|
||||
[ext_resource type="Script" path="res://addons/godot-form-validator/rules/email_rule.gd" id="9_4ynyw"]
|
||||
[ext_resource type="Script" path="res://addons/godot-form-validator/rules/length_rule.gd" id="10_iuueu"]
|
||||
[ext_resource type="Script" path="res://addons/godot-form-validator/rules/greater_than_rule.gd" id="11_1tya3"]
|
||||
[ext_resource type="Script" path="res://addons/godot-form-validator/validators/range_validator.gd" id="11_51cp7"]
|
||||
[ext_resource type="Script" path="res://addons/godot-form-validator/validators/button_validator.gd" id="13_eri47"]
|
||||
[ext_resource type="Script" path="res://addons/godot-form-validator/rules/custom_rule.gd" id="13_ibg52"]
|
||||
[ext_resource type="Script" path="res://addons/godot-form-validator/rules/boolean_rule.gd" id="15_xjpko"]
|
||||
|
||||
[sub_resource type="LabelSettings" id="LabelSettings_nw8ds"]
|
||||
font_size = 24
|
||||
|
||||
[sub_resource type="Resource" id="Resource_i25hd"]
|
||||
script = ExtResource("5_cu56g")
|
||||
fail_message = "A value is required."
|
||||
|
||||
[sub_resource type="Resource" id="Resource_4mimn"]
|
||||
script = ExtResource("4_dq1df")
|
||||
fail_message = "Value must contain only alpha characters."
|
||||
|
||||
[sub_resource type="Resource" id="Resource_15man"]
|
||||
script = ExtResource("5_rknpr")
|
||||
validation_order = 1
|
||||
validation_method = 0
|
||||
skip_validation = false
|
||||
rules = Array[Resource("res://addons/godot-form-validator/rules/validator_rule.gd")]([SubResource("Resource_i25hd"), SubResource("Resource_4mimn")])
|
||||
|
||||
[sub_resource type="LabelSettings" id="LabelSettings_su7t3"]
|
||||
font_color = Color(1, 0.568627, 0.580392, 1)
|
||||
|
||||
[sub_resource type="LabelSettings" id="LabelSettings_urp4f"]
|
||||
font_color = Color(0.254902, 0.831373, 0.556863, 1)
|
||||
|
||||
[sub_resource type="Resource" id="Resource_j4pud"]
|
||||
script = ExtResource("5_cu56g")
|
||||
fail_message = "A value is required."
|
||||
|
||||
[sub_resource type="Resource" id="Resource_xxhfq"]
|
||||
script = ExtResource("7_6vtuw")
|
||||
fail_message = "Value must contain only numbers."
|
||||
|
||||
[sub_resource type="Resource" id="Resource_1t3q0"]
|
||||
script = ExtResource("5_rknpr")
|
||||
validation_order = 1
|
||||
validation_method = 0
|
||||
skip_validation = false
|
||||
rules = Array[Resource("res://addons/godot-form-validator/rules/validator_rule.gd")]([SubResource("Resource_j4pud"), SubResource("Resource_xxhfq")])
|
||||
|
||||
[sub_resource type="Resource" id="Resource_ftvbf"]
|
||||
script = ExtResource("8_mu0ia")
|
||||
fail_message = "Value must contain only alphanumeric cahracters."
|
||||
|
||||
[sub_resource type="Resource" id="Resource_my5ss"]
|
||||
script = ExtResource("5_cu56g")
|
||||
fail_message = "A value is required."
|
||||
|
||||
[sub_resource type="Resource" id="Resource_61y5a"]
|
||||
script = ExtResource("5_rknpr")
|
||||
validation_order = 1
|
||||
validation_method = 0
|
||||
skip_validation = false
|
||||
rules = Array[Resource("res://addons/godot-form-validator/rules/validator_rule.gd")]([SubResource("Resource_ftvbf"), SubResource("Resource_my5ss")])
|
||||
|
||||
[sub_resource type="Resource" id="Resource_f3i8j"]
|
||||
script = ExtResource("9_4ynyw")
|
||||
fail_message = "Value must be a valid email address."
|
||||
|
||||
[sub_resource type="Resource" id="Resource_l5e3w"]
|
||||
script = ExtResource("5_cu56g")
|
||||
fail_message = "A value is required."
|
||||
|
||||
[sub_resource type="Resource" id="Resource_q4oax"]
|
||||
script = ExtResource("5_rknpr")
|
||||
validation_order = 1
|
||||
validation_method = 0
|
||||
skip_validation = false
|
||||
rules = Array[Resource("res://addons/godot-form-validator/rules/validator_rule.gd")]([SubResource("Resource_f3i8j"), SubResource("Resource_l5e3w")])
|
||||
|
||||
[sub_resource type="Resource" id="Resource_d1g5r"]
|
||||
script = ExtResource("5_cu56g")
|
||||
fail_message = "A value is required."
|
||||
|
||||
[sub_resource type="Resource" id="Resource_jqdfw"]
|
||||
script = ExtResource("10_iuueu")
|
||||
min_length = 5
|
||||
max_length = 10
|
||||
fail_message = ""
|
||||
|
||||
[sub_resource type="Resource" id="Resource_62odm"]
|
||||
script = ExtResource("5_rknpr")
|
||||
validation_order = 1
|
||||
validation_method = 0
|
||||
skip_validation = false
|
||||
rules = Array[Resource("res://addons/godot-form-validator/rules/validator_rule.gd")]([SubResource("Resource_d1g5r"), SubResource("Resource_jqdfw")])
|
||||
|
||||
[sub_resource type="Resource" id="Resource_qm2iv"]
|
||||
script = ExtResource("5_cu56g")
|
||||
fail_message = "A value is required."
|
||||
|
||||
[sub_resource type="Resource" id="Resource_brbah"]
|
||||
script = ExtResource("11_1tya3")
|
||||
target_value = "3"
|
||||
fail_message = ""
|
||||
|
||||
[sub_resource type="Resource" id="Resource_smogv"]
|
||||
script = ExtResource("11_51cp7")
|
||||
validation_order = 1
|
||||
validation_method = 0
|
||||
skip_validation = false
|
||||
rules = Array[Resource("res://addons/godot-form-validator/rules/validator_rule.gd")]([SubResource("Resource_qm2iv"), SubResource("Resource_brbah")])
|
||||
|
||||
[sub_resource type="Resource" id="Resource_4riv3"]
|
||||
script = ExtResource("13_ibg52")
|
||||
expression = "control.color.r > 0.5"
|
||||
fail_message = "The red channel must be greater than 0.5."
|
||||
|
||||
[sub_resource type="Resource" id="Resource_mh7td"]
|
||||
script = ExtResource("13_eri47")
|
||||
validation_order = 1
|
||||
validation_method = 0
|
||||
skip_validation = false
|
||||
rules = Array[Resource("res://addons/godot-form-validator/rules/validator_rule.gd")]([SubResource("Resource_4riv3")])
|
||||
|
||||
[sub_resource type="Resource" id="Resource_3nuq2"]
|
||||
script = ExtResource("15_xjpko")
|
||||
target_value = true
|
||||
fail_message = "The check box must be checked."
|
||||
|
||||
[sub_resource type="Resource" id="Resource_kbsj8"]
|
||||
script = ExtResource("13_eri47")
|
||||
validation_order = -1
|
||||
validation_method = 0
|
||||
skip_validation = false
|
||||
rules = Array[Resource("res://addons/godot-form-validator/rules/validator_rule.gd")]([SubResource("Resource_3nuq2")])
|
||||
|
||||
[node name="Example" type="PanelContainer"]
|
||||
anchors_preset = 15
|
||||
anchor_right = 1.0
|
||||
anchor_bottom = 1.0
|
||||
grow_horizontal = 2
|
||||
grow_vertical = 2
|
||||
script = ExtResource("1_8caq6")
|
||||
|
||||
[node name="MarginContainer" type="MarginContainer" parent="."]
|
||||
layout_mode = 2
|
||||
theme_override_constants/margin_left = 32
|
||||
theme_override_constants/margin_top = 32
|
||||
theme_override_constants/margin_right = 32
|
||||
theme_override_constants/margin_bottom = 32
|
||||
|
||||
[node name="FormValidator" type="Control" parent="MarginContainer"]
|
||||
layout_mode = 2
|
||||
script = ExtResource("2_mtxo0")
|
||||
auto_validate = true
|
||||
|
||||
[node name="VBoxContainer2" type="VBoxContainer" parent="MarginContainer/FormValidator"]
|
||||
layout_mode = 1
|
||||
anchors_preset = 15
|
||||
anchor_right = 1.0
|
||||
anchor_bottom = 1.0
|
||||
grow_horizontal = 2
|
||||
grow_vertical = 2
|
||||
|
||||
[node name="Title" type="Label" parent="MarginContainer/FormValidator/VBoxContainer2"]
|
||||
layout_mode = 2
|
||||
text = "Godot Form Validator Examples"
|
||||
label_settings = SubResource("LabelSettings_nw8ds")
|
||||
horizontal_alignment = 1
|
||||
vertical_alignment = 1
|
||||
|
||||
[node name="GridContainer" type="GridContainer" parent="MarginContainer/FormValidator/VBoxContainer2"]
|
||||
layout_mode = 2
|
||||
size_flags_vertical = 3
|
||||
theme_override_constants/h_separation = 16
|
||||
theme_override_constants/v_separation = 16
|
||||
columns = 4
|
||||
|
||||
[node name="Label" type="Label" parent="MarginContainer/FormValidator/VBoxContainer2/GridContainer"]
|
||||
layout_mode = 2
|
||||
text = "Alpha"
|
||||
vertical_alignment = 1
|
||||
|
||||
[node name="VBoxContainer" type="VBoxContainer" parent="MarginContainer/FormValidator/VBoxContainer2/GridContainer"]
|
||||
layout_mode = 2
|
||||
size_flags_horizontal = 3
|
||||
|
||||
[node name="Alpha" type="LineEdit" parent="MarginContainer/FormValidator/VBoxContainer2/GridContainer/VBoxContainer"]
|
||||
layout_mode = 2
|
||||
|
||||
[node name="ControlValidator" type="Node" parent="MarginContainer/FormValidator/VBoxContainer2/GridContainer/VBoxContainer/Alpha"]
|
||||
script = ExtResource("3_hkwup")
|
||||
validator = SubResource("Resource_15man")
|
||||
|
||||
[node name="AlphaError" type="Label" parent="MarginContainer/FormValidator/VBoxContainer2/GridContainer/VBoxContainer"]
|
||||
visible = false
|
||||
layout_mode = 2
|
||||
text = "ERROR"
|
||||
label_settings = SubResource("LabelSettings_su7t3")
|
||||
autowrap_mode = 2
|
||||
|
||||
[node name="AlphaValid" type="Label" parent="MarginContainer/FormValidator/VBoxContainer2/GridContainer/VBoxContainer"]
|
||||
visible = false
|
||||
layout_mode = 2
|
||||
text = "Valid!"
|
||||
label_settings = SubResource("LabelSettings_urp4f")
|
||||
|
||||
[node name="Label2" type="Label" parent="MarginContainer/FormValidator/VBoxContainer2/GridContainer"]
|
||||
layout_mode = 2
|
||||
text = "Numeric"
|
||||
vertical_alignment = 1
|
||||
|
||||
[node name="VBoxContainer2" type="VBoxContainer" parent="MarginContainer/FormValidator/VBoxContainer2/GridContainer"]
|
||||
layout_mode = 2
|
||||
size_flags_horizontal = 3
|
||||
|
||||
[node name="Numeric" type="LineEdit" parent="MarginContainer/FormValidator/VBoxContainer2/GridContainer/VBoxContainer2"]
|
||||
layout_mode = 2
|
||||
|
||||
[node name="ControlValidator" type="Node" parent="MarginContainer/FormValidator/VBoxContainer2/GridContainer/VBoxContainer2/Numeric"]
|
||||
script = ExtResource("3_hkwup")
|
||||
validator = SubResource("Resource_1t3q0")
|
||||
|
||||
[node name="NumericError" type="Label" parent="MarginContainer/FormValidator/VBoxContainer2/GridContainer/VBoxContainer2"]
|
||||
visible = false
|
||||
layout_mode = 2
|
||||
text = "ERROR"
|
||||
label_settings = SubResource("LabelSettings_su7t3")
|
||||
autowrap_mode = 2
|
||||
|
||||
[node name="NumericValid" type="Label" parent="MarginContainer/FormValidator/VBoxContainer2/GridContainer/VBoxContainer2"]
|
||||
visible = false
|
||||
layout_mode = 2
|
||||
text = "Valid!"
|
||||
label_settings = SubResource("LabelSettings_urp4f")
|
||||
|
||||
[node name="Label3" type="Label" parent="MarginContainer/FormValidator/VBoxContainer2/GridContainer"]
|
||||
layout_mode = 2
|
||||
text = "Alphanumeric"
|
||||
vertical_alignment = 1
|
||||
|
||||
[node name="VBoxContainer3" type="VBoxContainer" parent="MarginContainer/FormValidator/VBoxContainer2/GridContainer"]
|
||||
layout_mode = 2
|
||||
size_flags_horizontal = 3
|
||||
|
||||
[node name="Alphanumeric" type="LineEdit" parent="MarginContainer/FormValidator/VBoxContainer2/GridContainer/VBoxContainer3"]
|
||||
layout_mode = 2
|
||||
|
||||
[node name="ControlValidator" type="Node" parent="MarginContainer/FormValidator/VBoxContainer2/GridContainer/VBoxContainer3/Alphanumeric"]
|
||||
script = ExtResource("3_hkwup")
|
||||
validator = SubResource("Resource_61y5a")
|
||||
|
||||
[node name="AlphanumericError" type="Label" parent="MarginContainer/FormValidator/VBoxContainer2/GridContainer/VBoxContainer3"]
|
||||
visible = false
|
||||
layout_mode = 2
|
||||
text = "ERROR"
|
||||
label_settings = SubResource("LabelSettings_su7t3")
|
||||
autowrap_mode = 2
|
||||
|
||||
[node name="AlphanumericValid" type="Label" parent="MarginContainer/FormValidator/VBoxContainer2/GridContainer/VBoxContainer3"]
|
||||
visible = false
|
||||
layout_mode = 2
|
||||
text = "Valid!"
|
||||
label_settings = SubResource("LabelSettings_urp4f")
|
||||
|
||||
[node name="Label4" type="Label" parent="MarginContainer/FormValidator/VBoxContainer2/GridContainer"]
|
||||
layout_mode = 2
|
||||
text = "Email"
|
||||
vertical_alignment = 1
|
||||
|
||||
[node name="VBoxContainer4" type="VBoxContainer" parent="MarginContainer/FormValidator/VBoxContainer2/GridContainer"]
|
||||
layout_mode = 2
|
||||
size_flags_horizontal = 3
|
||||
|
||||
[node name="Email" type="LineEdit" parent="MarginContainer/FormValidator/VBoxContainer2/GridContainer/VBoxContainer4"]
|
||||
layout_mode = 2
|
||||
|
||||
[node name="ControlValidator" type="Node" parent="MarginContainer/FormValidator/VBoxContainer2/GridContainer/VBoxContainer4/Email"]
|
||||
script = ExtResource("3_hkwup")
|
||||
validator = SubResource("Resource_q4oax")
|
||||
|
||||
[node name="EmailError" type="Label" parent="MarginContainer/FormValidator/VBoxContainer2/GridContainer/VBoxContainer4"]
|
||||
visible = false
|
||||
layout_mode = 2
|
||||
text = "ERROR"
|
||||
label_settings = SubResource("LabelSettings_su7t3")
|
||||
autowrap_mode = 2
|
||||
|
||||
[node name="EmailValid" type="Label" parent="MarginContainer/FormValidator/VBoxContainer2/GridContainer/VBoxContainer4"]
|
||||
visible = false
|
||||
layout_mode = 2
|
||||
text = "Valid!"
|
||||
label_settings = SubResource("LabelSettings_urp4f")
|
||||
|
||||
[node name="Label5" type="Label" parent="MarginContainer/FormValidator/VBoxContainer2/GridContainer"]
|
||||
layout_mode = 2
|
||||
text = "Length"
|
||||
vertical_alignment = 1
|
||||
|
||||
[node name="VBoxContainer5" type="VBoxContainer" parent="MarginContainer/FormValidator/VBoxContainer2/GridContainer"]
|
||||
layout_mode = 2
|
||||
size_flags_horizontal = 3
|
||||
|
||||
[node name="Length" type="LineEdit" parent="MarginContainer/FormValidator/VBoxContainer2/GridContainer/VBoxContainer5"]
|
||||
layout_mode = 2
|
||||
|
||||
[node name="ControlValidator" type="Node" parent="MarginContainer/FormValidator/VBoxContainer2/GridContainer/VBoxContainer5/Length"]
|
||||
script = ExtResource("3_hkwup")
|
||||
validator = SubResource("Resource_62odm")
|
||||
|
||||
[node name="LengthError" type="Label" parent="MarginContainer/FormValidator/VBoxContainer2/GridContainer/VBoxContainer5"]
|
||||
visible = false
|
||||
layout_mode = 2
|
||||
text = "ERROR"
|
||||
label_settings = SubResource("LabelSettings_su7t3")
|
||||
autowrap_mode = 2
|
||||
|
||||
[node name="LengthValid" type="Label" parent="MarginContainer/FormValidator/VBoxContainer2/GridContainer/VBoxContainer5"]
|
||||
visible = false
|
||||
layout_mode = 2
|
||||
text = "Valid!"
|
||||
label_settings = SubResource("LabelSettings_urp4f")
|
||||
|
||||
[node name="Label6" type="Label" parent="MarginContainer/FormValidator/VBoxContainer2/GridContainer"]
|
||||
layout_mode = 2
|
||||
text = "Value"
|
||||
vertical_alignment = 1
|
||||
|
||||
[node name="VBoxContainer6" type="VBoxContainer" parent="MarginContainer/FormValidator/VBoxContainer2/GridContainer"]
|
||||
layout_mode = 2
|
||||
size_flags_horizontal = 3
|
||||
|
||||
[node name="Value" type="SpinBox" parent="MarginContainer/FormValidator/VBoxContainer2/GridContainer/VBoxContainer6"]
|
||||
layout_mode = 2
|
||||
|
||||
[node name="ControlValidator" type="Node" parent="MarginContainer/FormValidator/VBoxContainer2/GridContainer/VBoxContainer6/Value"]
|
||||
script = ExtResource("3_hkwup")
|
||||
validator = SubResource("Resource_smogv")
|
||||
|
||||
[node name="ValueError" type="Label" parent="MarginContainer/FormValidator/VBoxContainer2/GridContainer/VBoxContainer6"]
|
||||
visible = false
|
||||
layout_mode = 2
|
||||
text = "ERROR"
|
||||
label_settings = SubResource("LabelSettings_su7t3")
|
||||
autowrap_mode = 2
|
||||
|
||||
[node name="ValueValid" type="Label" parent="MarginContainer/FormValidator/VBoxContainer2/GridContainer/VBoxContainer6"]
|
||||
visible = false
|
||||
layout_mode = 2
|
||||
text = "Valid!"
|
||||
label_settings = SubResource("LabelSettings_urp4f")
|
||||
|
||||
[node name="Label7" type="Label" parent="MarginContainer/FormValidator/VBoxContainer2/GridContainer"]
|
||||
layout_mode = 2
|
||||
text = "Custom"
|
||||
vertical_alignment = 1
|
||||
|
||||
[node name="VBoxContainer7" type="VBoxContainer" parent="MarginContainer/FormValidator/VBoxContainer2/GridContainer"]
|
||||
layout_mode = 2
|
||||
size_flags_horizontal = 3
|
||||
|
||||
[node name="ColorPicker" type="ColorPickerButton" parent="MarginContainer/FormValidator/VBoxContainer2/GridContainer/VBoxContainer7"]
|
||||
custom_minimum_size = Vector2(0, 32)
|
||||
layout_mode = 2
|
||||
size_flags_vertical = 3
|
||||
|
||||
[node name="ControlValidator" type="Node" parent="MarginContainer/FormValidator/VBoxContainer2/GridContainer/VBoxContainer7/ColorPicker"]
|
||||
script = ExtResource("3_hkwup")
|
||||
validator = SubResource("Resource_mh7td")
|
||||
|
||||
[node name="ColorPickerError" type="Label" parent="MarginContainer/FormValidator/VBoxContainer2/GridContainer/VBoxContainer7"]
|
||||
visible = false
|
||||
layout_mode = 2
|
||||
text = "ERROR"
|
||||
label_settings = SubResource("LabelSettings_su7t3")
|
||||
autowrap_mode = 2
|
||||
|
||||
[node name="ColorPickerValid" type="Label" parent="MarginContainer/FormValidator/VBoxContainer2/GridContainer/VBoxContainer7"]
|
||||
visible = false
|
||||
layout_mode = 2
|
||||
text = "Valid!"
|
||||
label_settings = SubResource("LabelSettings_urp4f")
|
||||
|
||||
[node name="Label8" type="Label" parent="MarginContainer/FormValidator/VBoxContainer2/GridContainer"]
|
||||
layout_mode = 2
|
||||
text = "Checked"
|
||||
vertical_alignment = 1
|
||||
|
||||
[node name="VBoxContainer8" type="VBoxContainer" parent="MarginContainer/FormValidator/VBoxContainer2/GridContainer"]
|
||||
layout_mode = 2
|
||||
size_flags_horizontal = 3
|
||||
|
||||
[node name="Checked" type="CheckBox" parent="MarginContainer/FormValidator/VBoxContainer2/GridContainer/VBoxContainer8"]
|
||||
custom_minimum_size = Vector2(0, 32)
|
||||
layout_mode = 2
|
||||
size_flags_vertical = 3
|
||||
|
||||
[node name="ControlValidator" type="Node" parent="MarginContainer/FormValidator/VBoxContainer2/GridContainer/VBoxContainer8/Checked"]
|
||||
script = ExtResource("3_hkwup")
|
||||
validator = SubResource("Resource_kbsj8")
|
||||
|
||||
[node name="CheckedError" type="Label" parent="MarginContainer/FormValidator/VBoxContainer2/GridContainer/VBoxContainer8"]
|
||||
visible = false
|
||||
layout_mode = 2
|
||||
text = "ERROR"
|
||||
label_settings = SubResource("LabelSettings_su7t3")
|
||||
autowrap_mode = 2
|
||||
|
||||
[node name="CheckedValid" type="Label" parent="MarginContainer/FormValidator/VBoxContainer2/GridContainer/VBoxContainer8"]
|
||||
visible = false
|
||||
layout_mode = 2
|
||||
text = "Valid!"
|
||||
label_settings = SubResource("LabelSettings_urp4f")
|
||||
|
||||
[node name="HBoxContainer" type="HBoxContainer" parent="MarginContainer/FormValidator/VBoxContainer2"]
|
||||
layout_mode = 2
|
||||
theme_override_constants/separation = 32
|
||||
|
||||
[node name="Validate" type="Button" parent="MarginContainer/FormValidator/VBoxContainer2/HBoxContainer"]
|
||||
layout_mode = 2
|
||||
size_flags_horizontal = 3
|
||||
theme_override_font_sizes/font_size = 16
|
||||
text = "Validate Form"
|
||||
|
||||
[node name="Exit" type="Button" parent="MarginContainer/FormValidator/VBoxContainer2/HBoxContainer"]
|
||||
layout_mode = 2
|
||||
size_flags_horizontal = 3
|
||||
theme_override_font_sizes/font_size = 16
|
||||
text = "Exit"
|
||||
|
||||
[connection signal="control_validated" from="MarginContainer/FormValidator" to="." method="_on_form_validator_control_control_validated"]
|
||||
[connection signal="pressed" from="MarginContainer/FormValidator/VBoxContainer2/HBoxContainer/Validate" to="." method="_on_validate_pressed"]
|
||||
[connection signal="pressed" from="MarginContainer/FormValidator/VBoxContainer2/HBoxContainer/Exit" to="." method="_on_exit_pressed"]
|
||||
@@ -0,0 +1,125 @@
|
||||
@tool
|
||||
extends Control
|
||||
class_name FormValidator
|
||||
|
||||
signal control_validated(control, passed, messages)
|
||||
|
||||
class ValidatorInfo extends RefCounted:
|
||||
var control: Control
|
||||
var validator: Validator
|
||||
|
||||
@export var auto_validate: bool = false
|
||||
@export var validation_method: Validation.Method = Validation.Method.BATCH:
|
||||
set(value):
|
||||
validation_method = value
|
||||
_update_validation_methods()
|
||||
|
||||
var _control_validator_map: Dictionary = {}
|
||||
var _control_messages_map: Dictionary = {}
|
||||
|
||||
|
||||
func _ready() -> void:
|
||||
Validation.validator_added.connect(_on_validator_added)
|
||||
Validation.validator_removed.connect(_on_validator_removed)
|
||||
_find_validators(self)
|
||||
|
||||
|
||||
func get_messages() -> Dictionary:
|
||||
return _control_messages_map
|
||||
|
||||
|
||||
func get_messages_for_control(control: Control) -> PackedStringArray:
|
||||
if not _control_messages_map.has(control):
|
||||
return PackedStringArray()
|
||||
return _control_messages_map[control]
|
||||
|
||||
|
||||
func validate() -> bool:
|
||||
_control_messages_map.clear()
|
||||
var list = _get_validator_info_list()
|
||||
var valid = true
|
||||
for info in list:
|
||||
if info.validator.skip_validation:
|
||||
continue
|
||||
var passed = info.validator.validate(info.control)
|
||||
var messages = info.validator.get_messages()
|
||||
if not passed:
|
||||
_control_messages_map[info.control] = messages
|
||||
control_validated.emit(info.control, passed, messages)
|
||||
valid = valid and passed
|
||||
if not valid and validation_method == Validation.Method.IMMEDIATE:
|
||||
return valid
|
||||
return valid
|
||||
|
||||
|
||||
func _get_validator_info_list() -> Array[ValidatorInfo]:
|
||||
var list: Array[ValidatorInfo] = []
|
||||
for control in _control_validator_map.keys():
|
||||
var validator = _control_validator_map[control]
|
||||
if not validator:
|
||||
continue
|
||||
var info = ValidatorInfo.new()
|
||||
info.control = control
|
||||
info.validator = validator
|
||||
list.append(info)
|
||||
list.sort_custom(func (a: ValidatorInfo, b: ValidatorInfo):
|
||||
return a.validator.validation_order < b.validator.validation_order
|
||||
)
|
||||
return list
|
||||
|
||||
|
||||
func _update_validation_methods() -> void:
|
||||
var validators = _control_validator_map.values()
|
||||
for item in validators:
|
||||
var validator = item as Validator
|
||||
if not validator:
|
||||
continue
|
||||
validator.validation_method = validation_method
|
||||
|
||||
|
||||
func _find_validators(node: Node) -> void:
|
||||
for child in node.get_children():
|
||||
var control_validator = child as ControlValidator
|
||||
if control_validator:
|
||||
control_validator._on_validator_added()
|
||||
_find_validators(child)
|
||||
|
||||
|
||||
func _auto_validate(control: Control) -> void:
|
||||
if not auto_validate:
|
||||
return
|
||||
var validator = _control_validator_map[control] as Validator
|
||||
if not validator:
|
||||
return
|
||||
var passed = validator.validate(control)
|
||||
control_validated.emit(control, passed, validator.get_messages())
|
||||
|
||||
|
||||
func _on_validator_added(control: Control, validator: Validator) -> void:
|
||||
if not control:
|
||||
return
|
||||
_control_validator_map[control] = validator
|
||||
if not control.focus_exited.is_connected(_on_control_focus_exited):
|
||||
control.focus_exited.connect(_on_control_focus_exited.bind(control))
|
||||
# Special case to handle range-type controls that don't respond to focus
|
||||
# events for editing.
|
||||
if control.has_signal("value_changed"):
|
||||
if not control.value_changed.is_connected(_on_control_value_changed):
|
||||
control.value_changed.connect(_on_control_value_changed.bind(control))
|
||||
|
||||
|
||||
func _on_validator_removed(control: Control) -> void:
|
||||
_control_validator_map.erase(control)
|
||||
if control.focus_exited.is_connected(_on_control_focus_exited):
|
||||
control.focus_exited.disconnect(_on_control_focus_exited)
|
||||
if control.has_signal("value_changed"):
|
||||
if control.value_changed.is_connected(_on_control_value_changed):
|
||||
control.value_changed.disconnect(_on_control_value_changed)
|
||||
|
||||
|
||||
func _on_control_focus_exited(control: Control) -> void:
|
||||
_auto_validate(control)
|
||||
|
||||
|
||||
func _on_control_value_changed(value: float, control: Control) -> void:
|
||||
_auto_validate(control)
|
||||
@@ -0,0 +1,7 @@
|
||||
[plugin]
|
||||
|
||||
name="Godot Form Validator"
|
||||
description="A plugin for Godot 4 that adds robust validation logic to any control."
|
||||
author="deadpixelsociety"
|
||||
version="1.0"
|
||||
script="plugin.gd"
|
||||
@@ -0,0 +1,14 @@
|
||||
@tool
|
||||
extends EditorPlugin
|
||||
|
||||
|
||||
func _enter_tree() -> void:
|
||||
add_autoload_singleton("Validation", "res://addons/godot-form-validator/validation.gd")
|
||||
add_custom_type("FormValidator", "Control", preload("form_validator.gd"), preload("editor_icon.png"))
|
||||
add_custom_type("ControlValidator", "Node", preload("control_validator.gd"), preload("editor_icon.png"))
|
||||
|
||||
|
||||
func _exit_tree() -> void:
|
||||
remove_custom_type("ControlValidator")
|
||||
remove_custom_type("FormValidator")
|
||||
remove_autoload_singleton("Validation")
|
||||
@@ -0,0 +1,16 @@
|
||||
@tool
|
||||
extends ValidatorRule
|
||||
class_name AlphaRule
|
||||
|
||||
|
||||
func _init() -> void:
|
||||
fail_message = "Value must contain only alpha characters."
|
||||
|
||||
|
||||
func apply(control: Control, value) -> RuleResult:
|
||||
var result = RuleResult.new()
|
||||
if value is String:
|
||||
result.passed = ValidatorFunctions.empty(value) or ValidatorFunctions.alpha(value)
|
||||
if not result.passed:
|
||||
result.message = fail_message
|
||||
return result
|
||||
@@ -0,0 +1,16 @@
|
||||
@tool
|
||||
extends ValidatorRule
|
||||
class_name AlphanumericRule
|
||||
|
||||
|
||||
func _init() -> void:
|
||||
fail_message = "Value must contain only alphanumeric cahracters."
|
||||
|
||||
|
||||
func apply(control: Control, value) -> RuleResult:
|
||||
var result = RuleResult.new()
|
||||
if value is String:
|
||||
result.passed = ValidatorFunctions.empty(value) or ValidatorFunctions.alphanumeric(value)
|
||||
if not result.passed:
|
||||
result.message = fail_message
|
||||
return result
|
||||
@@ -0,0 +1,15 @@
|
||||
@tool
|
||||
extends ValidatorRule
|
||||
class_name BooleanRule
|
||||
|
||||
@export var target_value: bool
|
||||
|
||||
|
||||
func apply(control: Control, value) -> RuleResult:
|
||||
if ValidatorFunctions.empty(fail_message):
|
||||
fail_message = "The value must equal %s." % target_value
|
||||
var result = RuleResult.new()
|
||||
result.passed = value is bool and value == target_value
|
||||
if not result.passed:
|
||||
result.message = fail_message
|
||||
return result
|
||||
@@ -0,0 +1,36 @@
|
||||
@tool
|
||||
extends ValidatorRule
|
||||
class_name CustomRule
|
||||
|
||||
@export_multiline var expression: String = ""
|
||||
|
||||
var _expression: Expression = Expression.new()
|
||||
|
||||
|
||||
func apply(control: Control, value) -> RuleResult:
|
||||
var result = RuleResult.new()
|
||||
if not _validate_expression():
|
||||
result.passed = false
|
||||
result.message = "Specified expression is not valid."
|
||||
return result
|
||||
var res = _expression.execute([ control, value ])
|
||||
if _expression.has_execute_failed():
|
||||
result.passed = false
|
||||
result.message = "Execution of the specified expression has failed."
|
||||
return result
|
||||
result.passed = res == true
|
||||
if not result.passed:
|
||||
result.message = fail_message
|
||||
return result
|
||||
|
||||
|
||||
func is_valid() -> bool:
|
||||
return _validate_expression()
|
||||
|
||||
|
||||
func get_invalid_message() -> String:
|
||||
return "Specified expression is not valid."
|
||||
|
||||
|
||||
func _validate_expression() -> bool:
|
||||
return _expression.parse(expression, [ "control", "value" ]) == OK
|
||||
@@ -0,0 +1,26 @@
|
||||
@tool
|
||||
extends ValidatorRule
|
||||
class_name DoesNotMatchRule
|
||||
|
||||
@export var pattern: String
|
||||
|
||||
|
||||
func _init() -> void:
|
||||
fail_message = "Invalid value."
|
||||
|
||||
|
||||
func apply(control: Control, value) -> RuleResult:
|
||||
var result = RuleResult.new()
|
||||
if value is String:
|
||||
result.passed = ValidatorFunctions.empty(value) or ValidatorFunctions.does_not_match(pattern, value)
|
||||
if not result.passed:
|
||||
result.message = fail_message
|
||||
return result
|
||||
|
||||
|
||||
func is_valid() -> bool:
|
||||
return RegEx.create_from_string(pattern).is_valid()
|
||||
|
||||
|
||||
func get_invalid_message() -> String:
|
||||
return "Specified regular expression is not valid."
|
||||
@@ -0,0 +1,16 @@
|
||||
@tool
|
||||
extends ValidatorRule
|
||||
class_name EmailRule
|
||||
|
||||
|
||||
func _init() -> void:
|
||||
fail_message = "Value must be a valid email address."
|
||||
|
||||
|
||||
func apply(control: Control, value) -> RuleResult:
|
||||
var result = RuleResult.new()
|
||||
if value is String:
|
||||
result.passed = ValidatorFunctions.empty(value) or ValidatorFunctions.email(value)
|
||||
if not result.passed:
|
||||
result.message = fail_message
|
||||
return result
|
||||
@@ -0,0 +1,15 @@
|
||||
@tool
|
||||
extends ValidatorRule
|
||||
class_name EqualsRule
|
||||
|
||||
@export var target_value: String
|
||||
|
||||
|
||||
func apply(control: Control, value) -> RuleResult:
|
||||
if ValidatorFunctions.empty(fail_message):
|
||||
fail_message = "The value must equal %s." % target_value
|
||||
var result = RuleResult.new()
|
||||
result.passed = str(value) == target_value
|
||||
if not result.passed:
|
||||
result.message = fail_message
|
||||
return result
|
||||
@@ -0,0 +1,15 @@
|
||||
@tool
|
||||
extends ValidatorRule
|
||||
class_name GreaterThanRule
|
||||
|
||||
@export var target_value: String
|
||||
|
||||
|
||||
func apply(control: Control, value) -> RuleResult:
|
||||
if ValidatorFunctions.empty(fail_message):
|
||||
fail_message = "The value must be greater than %s." % target_value
|
||||
var result = RuleResult.new()
|
||||
result.passed = str(value) > target_value
|
||||
if not result.passed:
|
||||
result.message = fail_message
|
||||
return result
|
||||
@@ -0,0 +1,28 @@
|
||||
@tool
|
||||
extends ValidatorRule
|
||||
class_name LengthRule
|
||||
|
||||
const FAIL_MESSAGE: String = "The value must be between %d and %d characters long."
|
||||
|
||||
@export var min_length: int = 0
|
||||
@export var max_length: int = 9999
|
||||
|
||||
|
||||
func apply(control: Control, value) -> RuleResult:
|
||||
var result = RuleResult.new()
|
||||
if value is String:
|
||||
result.passed = ValidatorFunctions.length(value, min_length, max_length)
|
||||
if not result.passed:
|
||||
if ValidatorFunctions.empty(fail_message):
|
||||
result.message = FAIL_MESSAGE % [ min_length, max_length ]
|
||||
else:
|
||||
result.message = fail_message
|
||||
return result
|
||||
|
||||
|
||||
func is_valid() -> bool:
|
||||
return min_length <= max_length
|
||||
|
||||
|
||||
func get_invalid_message() -> String:
|
||||
return "Minimum length must be less than or equal to maximum length."
|
||||
@@ -0,0 +1,15 @@
|
||||
@tool
|
||||
extends ValidatorRule
|
||||
class_name LessThanRule
|
||||
|
||||
@export var target_value: String
|
||||
|
||||
|
||||
func apply(control: Control, value) -> RuleResult:
|
||||
if ValidatorFunctions.empty(fail_message):
|
||||
fail_message = "The value must be less than %s." % target_value
|
||||
var result = RuleResult.new()
|
||||
result.passed = str(value) < target_value
|
||||
if not result.passed:
|
||||
result.message = fail_message
|
||||
return result
|
||||
@@ -0,0 +1,26 @@
|
||||
@tool
|
||||
extends ValidatorRule
|
||||
class_name MatchesRule
|
||||
|
||||
@export var pattern: String
|
||||
|
||||
|
||||
func _init() -> void:
|
||||
fail_message = "Invalid value."
|
||||
|
||||
|
||||
func apply(control: Control, value) -> RuleResult:
|
||||
var result = RuleResult.new()
|
||||
if value is String:
|
||||
result.passed = ValidatorFunctions.empty(value) or ValidatorFunctions.matches(pattern, value)
|
||||
if not result.passed:
|
||||
result.message = fail_message
|
||||
return result
|
||||
|
||||
|
||||
func is_valid() -> bool:
|
||||
return RegEx.create_from_string(pattern).is_valid()
|
||||
|
||||
|
||||
func get_invalid_message() -> String:
|
||||
return "Specified regular expression is not valid."
|
||||
@@ -0,0 +1,16 @@
|
||||
@tool
|
||||
extends ValidatorRule
|
||||
class_name NotBlankRule
|
||||
|
||||
|
||||
func _init() -> void:
|
||||
fail_message = "Value must not be blank."
|
||||
|
||||
|
||||
func apply(control: Control, value) -> RuleResult:
|
||||
var result = RuleResult.new()
|
||||
if value is String:
|
||||
result.passed = ValidatorFunctions.not_blank(value)
|
||||
if not result.passed:
|
||||
result.message = fail_message
|
||||
return result
|
||||
@@ -0,0 +1,16 @@
|
||||
@tool
|
||||
extends ValidatorRule
|
||||
class_name NotEmptyRule
|
||||
|
||||
|
||||
func _init() -> void:
|
||||
fail_message = "Value must not be empty."
|
||||
|
||||
|
||||
func apply(control: Control, value) -> RuleResult:
|
||||
var result = RuleResult.new()
|
||||
if value is String:
|
||||
result.passed = ValidatorFunctions.not_empty(value)
|
||||
if not result.passed:
|
||||
result.message = fail_message
|
||||
return result
|
||||
@@ -0,0 +1,16 @@
|
||||
@tool
|
||||
extends ValidatorRule
|
||||
class_name NumericRule
|
||||
|
||||
|
||||
func _init() -> void:
|
||||
fail_message = "Value must contain only numbers."
|
||||
|
||||
|
||||
func apply(control: Control, value) -> RuleResult:
|
||||
var result = RuleResult.new()
|
||||
if value is String:
|
||||
result.passed = ValidatorFunctions.empty(value) or ValidatorFunctions.numeric(value)
|
||||
if not result.passed:
|
||||
result.message = fail_message
|
||||
return result
|
||||
@@ -0,0 +1,18 @@
|
||||
@tool
|
||||
extends ValidatorRule
|
||||
class_name RequiredRule
|
||||
|
||||
|
||||
func _init():
|
||||
fail_message = "A value is required."
|
||||
|
||||
|
||||
func apply(control: Control, value) -> RuleResult:
|
||||
var result = RuleResult.new()
|
||||
if value is String:
|
||||
result.passed = ValidatorFunctions.not_blank(value)
|
||||
else:
|
||||
result.passed = value != null
|
||||
if not result.passed:
|
||||
result.message = fail_message
|
||||
return result
|
||||
@@ -0,0 +1,5 @@
|
||||
extends RefCounted
|
||||
class_name RuleResult
|
||||
|
||||
var passed: bool = false
|
||||
var message: String = ""
|
||||
@@ -0,0 +1,17 @@
|
||||
@tool
|
||||
extends Resource
|
||||
class_name ValidatorRule
|
||||
|
||||
@export var fail_message: String = ""
|
||||
|
||||
|
||||
func apply(control: Control, value) -> RuleResult:
|
||||
return RuleResult.new()
|
||||
|
||||
|
||||
func is_valid() -> bool:
|
||||
return true
|
||||
|
||||
|
||||
func get_invalid_message() -> String:
|
||||
return ""
|
||||
@@ -0,0 +1,39 @@
|
||||
@tool
|
||||
extends Node
|
||||
|
||||
signal validator_added(control, validator)
|
||||
signal validator_removed(control)
|
||||
|
||||
enum Method {
|
||||
# Processes all validators and rules before returning a result.
|
||||
BATCH,
|
||||
# Processes validators until a rule failure is encountered, then proceeds to the next validator.
|
||||
FAIL_FAST,
|
||||
# Processes validators until a rule failure is encountered and returns immediately.
|
||||
IMMEDIATE
|
||||
}
|
||||
|
||||
var _validators: Array[Validator] = []
|
||||
|
||||
|
||||
func _ready() -> void:
|
||||
add_validator(ButtonValidator.new())
|
||||
add_validator(LineEditValidator.new())
|
||||
add_validator(RangeValidator.new())
|
||||
add_validator(TextEditValidator.new())
|
||||
|
||||
|
||||
func add_validator(validator: Validator) -> void:
|
||||
if not _validators.has(validator):
|
||||
_validators.append(validator)
|
||||
|
||||
|
||||
func get_validators() -> Array[Validator]:
|
||||
return _validators
|
||||
|
||||
|
||||
func find_validator(node: Node) -> Validator:
|
||||
for validator in get_validators():
|
||||
if validator.is_type(node):
|
||||
return validator
|
||||
return null
|
||||
@@ -0,0 +1,66 @@
|
||||
extends Object
|
||||
class_name ValidatorFunctions
|
||||
|
||||
|
||||
static func matches(pattern: String, text: String) -> bool:
|
||||
var regex = RegEx.create_from_string(pattern)
|
||||
if not regex.is_valid():
|
||||
print_debug("WARNING: Invalid RegEx pattern supplied to matches function: ", pattern)
|
||||
return false
|
||||
var result = regex.search(text)
|
||||
return result != null and result.strings.size() > 0
|
||||
|
||||
|
||||
static func does_not_match(pattern: String, text: String) -> bool:
|
||||
var regex = RegEx.create_from_string(pattern)
|
||||
if not regex.is_valid():
|
||||
print_debug("WARNING: Invalid RegEx pattern supplied to matches function: ", pattern)
|
||||
return false
|
||||
var result = regex.search(text)
|
||||
return result == null
|
||||
|
||||
|
||||
static func not_empty(text: String) -> bool:
|
||||
return text != null and not text.is_empty()
|
||||
|
||||
|
||||
static func empty(text: String) -> bool:
|
||||
return not not_empty(text)
|
||||
|
||||
|
||||
static func not_blank(text: String) -> bool:
|
||||
if text == null:
|
||||
return false
|
||||
# Remove escape sequences
|
||||
text = text.strip_escapes()
|
||||
# Remove spaces
|
||||
text = text.replace(" ", "")
|
||||
return not text.is_empty()
|
||||
|
||||
|
||||
static func alpha(text: String) -> bool:
|
||||
var regex = RegEx.create_from_string("[^a-zA-Z]+")
|
||||
var result = regex.search(text)
|
||||
return result == null
|
||||
|
||||
|
||||
static func numeric(text: String) -> bool:
|
||||
var regex = RegEx.create_from_string("[^0-9]+")
|
||||
var result = regex.search(text)
|
||||
return result == null
|
||||
|
||||
|
||||
static func alphanumeric(text: String) -> bool:
|
||||
var regex = RegEx.create_from_string("[^a-zA-Z0-9]+")
|
||||
var result = regex.search(text)
|
||||
return result == null
|
||||
|
||||
|
||||
static func email(text: String) -> bool:
|
||||
var regex = RegEx.create_from_string("^[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\\.[A-Za-z]{2,6}$")
|
||||
var result = regex.search(text)
|
||||
return result != null and result.strings.size() > 0
|
||||
|
||||
|
||||
static func length(text: String, min_length: int = 0, max_length: int = 9999) -> bool:
|
||||
return text != null and text.length() >= min_length and text.length() <= max_length
|
||||
@@ -0,0 +1,14 @@
|
||||
@tool
|
||||
extends Validator
|
||||
class_name ButtonValidator
|
||||
|
||||
|
||||
func get_value(control: Control):
|
||||
var button = control as Button
|
||||
if not button:
|
||||
return null
|
||||
return button.button_pressed
|
||||
|
||||
|
||||
func is_type(node) -> bool:
|
||||
return node is Button
|
||||
@@ -0,0 +1,14 @@
|
||||
@tool
|
||||
extends Validator
|
||||
class_name LineEditValidator
|
||||
|
||||
|
||||
func get_value(control: Control):
|
||||
var line_edit = control as LineEdit
|
||||
if not line_edit:
|
||||
return null
|
||||
return line_edit.text
|
||||
|
||||
|
||||
func is_type(node) -> bool:
|
||||
return node is LineEdit
|
||||
@@ -0,0 +1,15 @@
|
||||
@tool
|
||||
extends Validator
|
||||
class_name RangeValidator
|
||||
|
||||
|
||||
func get_value(control: Control):
|
||||
var range_control = control as Range
|
||||
if not range_control:
|
||||
return null
|
||||
return range_control.value
|
||||
|
||||
|
||||
func is_type(node) -> bool:
|
||||
return node is Range and \
|
||||
not (node is ScrollBar or node is ProgressBar or node is TextureProgressBar)
|
||||
@@ -0,0 +1,14 @@
|
||||
@tool
|
||||
extends Validator
|
||||
class_name TextEditValidator
|
||||
|
||||
|
||||
func get_value(control: Control):
|
||||
var text_edit = control as TextEdit
|
||||
if not text_edit:
|
||||
return null
|
||||
return text_edit.text
|
||||
|
||||
|
||||
func is_type(node) -> bool:
|
||||
return node is TextEdit
|
||||
@@ -0,0 +1,37 @@
|
||||
@tool
|
||||
extends Resource
|
||||
class_name Validator
|
||||
|
||||
@export var validation_order: int = 1
|
||||
@export var validation_method: Validation.Method = Validation.Method.BATCH
|
||||
@export var skip_validation: bool = false
|
||||
@export var rules: Array[ValidatorRule] = []
|
||||
|
||||
var _messages: PackedStringArray = PackedStringArray()
|
||||
|
||||
|
||||
func get_value(control: Control):
|
||||
return null
|
||||
|
||||
|
||||
func is_type(node) -> bool:
|
||||
return node is Control
|
||||
|
||||
|
||||
func get_messages() -> PackedStringArray:
|
||||
return _messages
|
||||
|
||||
|
||||
func validate(control: Control) -> bool:
|
||||
_messages.clear()
|
||||
var valid = true
|
||||
for rule in rules:
|
||||
var result = rule.apply(control, get_value(control))
|
||||
if not result.passed:
|
||||
_messages.append(result.message)
|
||||
valid = valid and result.passed
|
||||
if not valid:
|
||||
# Not BATCH, exit early.
|
||||
if validation_method != Validation.Method.BATCH:
|
||||
return valid
|
||||
return valid
|
||||
|
After Width: | Height: | Size: 12 KiB |
@@ -0,0 +1,34 @@
|
||||
[remap]
|
||||
|
||||
importer="texture"
|
||||
type="CompressedTexture2D"
|
||||
uid="uid://cuk6aur2mqe6y"
|
||||
path="res://.godot/imported/bonuspath_a_01_complete.png-897bda4de5428c7b46c5eb63574d356c.ctex"
|
||||
metadata={
|
||||
"vram_texture": false
|
||||
}
|
||||
|
||||
[deps]
|
||||
|
||||
source_file="res://assets/bonuspath_a_01_complete.png"
|
||||
dest_files=["res://.godot/imported/bonuspath_a_01_complete.png-897bda4de5428c7b46c5eb63574d356c.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
|
||||
|
After Width: | Height: | Size: 3.7 KiB |
@@ -0,0 +1,34 @@
|
||||
[remap]
|
||||
|
||||
importer="texture"
|
||||
type="CompressedTexture2D"
|
||||
uid="uid://blxcf17gus8c"
|
||||
path="res://.godot/imported/bonuspath_a_01_not_complete.png-64b0f6f0d472897aab337e8a484b9938.ctex"
|
||||
metadata={
|
||||
"vram_texture": false
|
||||
}
|
||||
|
||||
[deps]
|
||||
|
||||
source_file="res://assets/bonuspath_a_01_not_complete.png"
|
||||
dest_files=["res://.godot/imported/bonuspath_a_01_not_complete.png-64b0f6f0d472897aab337e8a484b9938.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
|
||||
|
After Width: | Height: | Size: 51 KiB |
@@ -0,0 +1,34 @@
|
||||
[remap]
|
||||
|
||||
importer="texture"
|
||||
type="CompressedTexture2D"
|
||||
uid="uid://bb080qc6juomq"
|
||||
path="res://.godot/imported/path_a_01.png-93a1b4c2adfbc89d6517f795a9e687a9.ctex"
|
||||
metadata={
|
||||
"vram_texture": false
|
||||
}
|
||||
|
||||
[deps]
|
||||
|
||||
source_file="res://assets/path_a_01.png"
|
||||
dest_files=["res://.godot/imported/path_a_01.png-93a1b4c2adfbc89d6517f795a9e687a9.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
|
||||
|
After Width: | Height: | Size: 47 KiB |
@@ -0,0 +1,34 @@
|
||||
[remap]
|
||||
|
||||
importer="texture"
|
||||
type="CompressedTexture2D"
|
||||
uid="uid://byv4d55but7c"
|
||||
path="res://.godot/imported/path_b_01.png-17f14a7bc673650b104023018c190eb3.ctex"
|
||||
metadata={
|
||||
"vram_texture": false
|
||||
}
|
||||
|
||||
[deps]
|
||||
|
||||
source_file="res://assets/path_b_01.png"
|
||||
dest_files=["res://.godot/imported/path_b_01.png-17f14a7bc673650b104023018c190eb3.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
|
||||
|
After Width: | Height: | Size: 30 KiB |
@@ -0,0 +1,34 @@
|
||||
[remap]
|
||||
|
||||
importer="texture"
|
||||
type="CompressedTexture2D"
|
||||
uid="uid://c13odbsfv53he"
|
||||
path="res://.godot/imported/example_rules.png-faa9d2703b3ffa116338aa78beef009e.ctex"
|
||||
metadata={
|
||||
"vram_texture": false
|
||||
}
|
||||
|
||||
[deps]
|
||||
|
||||
source_file="res://example_rules.png"
|
||||
dest_files=["res://.godot/imported/example_rules.png-faa9d2703b3ffa116338aa78beef009e.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
|
||||
|
After Width: | Height: | Size: 22 KiB |
@@ -0,0 +1,34 @@
|
||||
[remap]
|
||||
|
||||
importer="texture"
|
||||
type="CompressedTexture2D"
|
||||
uid="uid://b1ynfmrih7ira"
|
||||
path="res://.godot/imported/example_tree.png-f962c768c2ced2db3f35399da01825e8.ctex"
|
||||
metadata={
|
||||
"vram_texture": false
|
||||
}
|
||||
|
||||
[deps]
|
||||
|
||||
source_file="res://example_tree.png"
|
||||
dest_files=["res://.godot/imported/example_tree.png-f962c768c2ced2db3f35399da01825e8.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
|
||||
@@ -0,0 +1,34 @@
|
||||
[remap]
|
||||
|
||||
importer="texture"
|
||||
type="CompressedTexture2D"
|
||||
uid="uid://d3n0k21jubf3p"
|
||||
path="res://.godot/imported/icon.png-487276ed1e3a0c39cad0279d744ee560.ctex"
|
||||
metadata={
|
||||
"vram_texture": false
|
||||
}
|
||||
|
||||
[deps]
|
||||
|
||||
source_file="res://icon.png"
|
||||
dest_files=["res://.godot/imported/icon.png-487276ed1e3a0c39cad0279d744ee560.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
|
||||
@@ -0,0 +1,34 @@
|
||||
[remap]
|
||||
|
||||
importer="texture"
|
||||
type="CompressedTexture2D"
|
||||
uid="uid://c3ykco3r3cbm4"
|
||||
path="res://.godot/imported/logo.png-cca8726399059c8d4f806e28e356b14d.ctex"
|
||||
metadata={
|
||||
"vram_texture": false
|
||||
}
|
||||
|
||||
[deps]
|
||||
|
||||
source_file="res://logo.png"
|
||||
dest_files=["res://.godot/imported/logo.png-cca8726399059c8d4f806e28e356b14d.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
|
||||
@@ -29,6 +29,8 @@ LessonLogger="*res://sources/utils/autoloads/lesson_logger.gd"
|
||||
Database="*res://sources/utils/autoloads/Database.gd"
|
||||
UserDataManager="*res://sources/utils/autoloads/user_data_manager.gd"
|
||||
MusicManager="*res://sources/utils/autoloads/music_manager.tscn"
|
||||
LessonLogger="*res://sources/utils/autoloads/lesson_logger.gd"
|
||||
Validation="*res://addons/godot-form-validator/validation.gd"
|
||||
|
||||
[display]
|
||||
|
||||
@@ -40,7 +42,7 @@ window/stretch/mode="canvas_items"
|
||||
|
||||
[editor_plugins]
|
||||
|
||||
enabled=PackedStringArray("res://addons/godot-sqlite/plugin.cfg")
|
||||
enabled=PackedStringArray("res://addons/godot-form-validator/plugin.cfg", "res://addons/godot-sqlite/plugin.cfg")
|
||||
|
||||
[gui]
|
||||
|
||||
|
||||
@@ -0,0 +1,4 @@
|
||||
extends Resource
|
||||
class_name RegisterQuestion
|
||||
|
||||
var txt : String
|
||||
@@ -0,0 +1,79 @@
|
||||
extends Control
|
||||
|
||||
@onready var teacher_steps : Array[PackedScene] = [
|
||||
preload("res://sources/menus/register/steps/teacher/method_step.tscn"),
|
||||
preload("res://sources/menus/register/steps/teacher/devices_count_step.tscn"),
|
||||
preload("res://sources/menus/register/steps/teacher/students_count_step.tscn"),
|
||||
preload("res://sources/menus/register/steps/credentials_step.tscn")
|
||||
]
|
||||
@onready var parent_steps : Array[PackedScene] = [
|
||||
|
||||
]
|
||||
var current_steps : Array[PackedScene]
|
||||
# TODO Change the resource
|
||||
@onready var register_data := UserSettings.new()
|
||||
@onready var progress_bar := %ProgressBar
|
||||
@onready var steps := %Steps
|
||||
|
||||
func _ready():
|
||||
current_steps = teacher_steps
|
||||
|
||||
# Handles the progress bar
|
||||
progress_bar.value = 0
|
||||
progress_bar.max_value = current_steps.size()
|
||||
|
||||
# Load new step
|
||||
_go_to_step(progress_bar.value)
|
||||
|
||||
|
||||
func _go_to_step(step_index: int):
|
||||
var next_step
|
||||
|
||||
# Check if step is already instantiated
|
||||
for step in steps.get_children(false):
|
||||
step.hide()
|
||||
|
||||
if step.name == str(progress_bar.value):
|
||||
step.completed.disconnect(_on_step_completed)
|
||||
pass
|
||||
|
||||
if step.name == str(step_index):
|
||||
next_step = step
|
||||
|
||||
# Instantiate the step
|
||||
if not next_step:
|
||||
next_step = teacher_steps[step_index].instantiate()
|
||||
next_step.name = str(step_index)
|
||||
next_step.object = register_data
|
||||
steps.add_child(next_step)
|
||||
else:
|
||||
next_step.show()
|
||||
|
||||
# Connect the step
|
||||
next_step.completed.connect(_on_step_completed)
|
||||
|
||||
# Handles progress bar
|
||||
progress_bar.value = step_index
|
||||
|
||||
|
||||
func _reset_steps():
|
||||
progress_bar.value = 0
|
||||
progress_bar.max_value = 0
|
||||
|
||||
for step in steps.get_children(false):
|
||||
step.queue_free()
|
||||
|
||||
|
||||
func _on_back_button_pressed():
|
||||
if progress_bar.value == 0:
|
||||
print("Back to title screen")
|
||||
# get_tree().change_scene_to_file()
|
||||
else:
|
||||
_go_to_step(progress_bar.value-1)
|
||||
|
||||
|
||||
func _on_step_completed():
|
||||
if progress_bar.value == current_steps.size()-1:
|
||||
print("Registering complete !")
|
||||
else:
|
||||
_go_to_step(progress_bar.value+1)
|
||||
@@ -0,0 +1,75 @@
|
||||
[gd_scene load_steps=7 format=3 uid="uid://b7cfjs2iipagq"]
|
||||
|
||||
[ext_resource type="Texture2D" uid="uid://wtx3wqs0l4si" path="res://assets/minigames/minigame_ui/graphic/button_back_up.png" id="1_g16n6"]
|
||||
[ext_resource type="Script" path="res://sources/menus/register/register_screen.gd" id="1_the3k"]
|
||||
[ext_resource type="Texture2D" uid="uid://cbhip35yyqneg" path="res://assets/minigames/minigame_ui/graphic/button_back_down.png" id="2_ufjlu"]
|
||||
[ext_resource type="Texture2D" uid="uid://tcapan0mj64o" path="res://assets/minigames/minigame_ui/graphic/button_back_disabled.png" id="3_svtfb"]
|
||||
|
||||
[sub_resource type="StyleBoxFlat" id="StyleBoxFlat_0rcyk"]
|
||||
border_width_left = 3
|
||||
border_width_top = 3
|
||||
border_width_right = 3
|
||||
border_width_bottom = 3
|
||||
expand_margin_top = 3.0
|
||||
expand_margin_bottom = 3.0
|
||||
|
||||
[sub_resource type="StyleBoxFlat" id="StyleBoxFlat_bhfkq"]
|
||||
bg_color = Color(0, 0.607843, 0.831373, 1)
|
||||
|
||||
[node name="RegisterScreen" type="Control"]
|
||||
layout_mode = 3
|
||||
anchors_preset = 15
|
||||
anchor_right = 1.0
|
||||
anchor_bottom = 1.0
|
||||
grow_horizontal = 2
|
||||
grow_vertical = 2
|
||||
script = ExtResource("1_the3k")
|
||||
|
||||
[node name="ProgressBarContainer" type="MarginContainer" parent="."]
|
||||
layout_mode = 1
|
||||
anchors_preset = 10
|
||||
anchor_right = 1.0
|
||||
offset_bottom = 256.0
|
||||
grow_horizontal = 2
|
||||
theme_override_constants/margin_left = 25
|
||||
theme_override_constants/margin_top = 50
|
||||
theme_override_constants/margin_right = 231
|
||||
theme_override_constants/margin_bottom = 50
|
||||
|
||||
[node name="HBoxContainer" type="HBoxContainer" parent="ProgressBarContainer"]
|
||||
layout_mode = 2
|
||||
theme_override_constants/separation = 50
|
||||
|
||||
[node name="BackButton" type="TextureButton" parent="ProgressBarContainer/HBoxContainer"]
|
||||
unique_name_in_owner = true
|
||||
custom_minimum_size = Vector2(156, 156)
|
||||
layout_mode = 2
|
||||
size_flags_horizontal = 0
|
||||
texture_normal = ExtResource("1_g16n6")
|
||||
texture_pressed = ExtResource("2_ufjlu")
|
||||
texture_disabled = ExtResource("3_svtfb")
|
||||
stretch_mode = 5
|
||||
|
||||
[node name="ProgressBar" type="ProgressBar" parent="ProgressBarContainer/HBoxContainer"]
|
||||
unique_name_in_owner = true
|
||||
layout_mode = 2
|
||||
size_flags_horizontal = 3
|
||||
size_flags_vertical = 4
|
||||
theme_override_colors/font_color = Color(0, 0, 0, 0)
|
||||
theme_override_colors/font_outline_color = Color(0, 0, 0, 0)
|
||||
theme_override_styles/background = SubResource("StyleBoxFlat_0rcyk")
|
||||
theme_override_styles/fill = SubResource("StyleBoxFlat_bhfkq")
|
||||
step = 1.0
|
||||
value = 50.0
|
||||
|
||||
[node name="Steps" type="Control" parent="."]
|
||||
unique_name_in_owner = true
|
||||
layout_mode = 1
|
||||
anchor_top = 0.142222
|
||||
anchor_right = 1.0
|
||||
anchor_bottom = 1.0
|
||||
grow_horizontal = 2
|
||||
grow_vertical = 2
|
||||
metadata/_edit_use_anchors_ = true
|
||||
|
||||
[connection signal="pressed" from="ProgressBarContainer/HBoxContainer/BackButton" to="." method="_on_back_button_pressed"]
|
||||
@@ -0,0 +1,68 @@
|
||||
@tool
|
||||
extends Control
|
||||
class_name Step
|
||||
|
||||
signal completed
|
||||
|
||||
const checked_properties := [
|
||||
"value",
|
||||
"text"
|
||||
]
|
||||
|
||||
@onready var question_label : Label = %QuestionLabel
|
||||
@onready var form_validator : FormValidator = %FormValidator
|
||||
@onready var form_container : Control = %FormContainer
|
||||
|
||||
@export var question_txt : String
|
||||
@export var object : Resource
|
||||
|
||||
func _ready():
|
||||
if question_txt:
|
||||
question_label.text = question_txt
|
||||
|
||||
_fill_form()
|
||||
|
||||
|
||||
func _fill_form():
|
||||
if not object:
|
||||
return
|
||||
|
||||
for node in form_container.get_children(false):
|
||||
if node.name in object:
|
||||
for property_name in checked_properties:
|
||||
if property_name in node:
|
||||
node.set(property_name, object.get(node.name))
|
||||
else:
|
||||
push_warning("Property not found in object for node: " + node.name + ". All nodes inside FormContainer must reflects a property from the resource.")
|
||||
|
||||
|
||||
func _write_object() -> bool:
|
||||
if not object:
|
||||
return false
|
||||
|
||||
for node in form_container.get_children(false):
|
||||
var value
|
||||
if node.name in object:
|
||||
for property_name in checked_properties:
|
||||
if property_name in node:
|
||||
value = node.get(property_name)
|
||||
|
||||
if value:
|
||||
object.set(node.name, value)
|
||||
else:
|
||||
return false
|
||||
|
||||
return true
|
||||
|
||||
|
||||
func _on_validate_button_pressed():
|
||||
|
||||
print(form_validator.validate())
|
||||
|
||||
# Writes data in object
|
||||
if _write_object():
|
||||
# Emit completed signal
|
||||
emit_signal("completed")
|
||||
else:
|
||||
# TODO Show error message
|
||||
print("Please fill all the fields")
|
||||
@@ -0,0 +1,101 @@
|
||||
[gd_scene load_steps=3 format=3 uid="uid://bxd3i06rqpxf0"]
|
||||
|
||||
[ext_resource type="Script" path="res://sources/menus/register/steps/base_step.gd" id="1_02ocl"]
|
||||
[ext_resource type="Script" path="res://addons/godot-form-validator/form_validator.gd" id="2_jbdsv"]
|
||||
|
||||
[node name="BaseRegisterForm" type="Control"]
|
||||
layout_mode = 3
|
||||
anchors_preset = 15
|
||||
anchor_right = 1.0
|
||||
anchor_bottom = 1.0
|
||||
grow_horizontal = 2
|
||||
grow_vertical = 2
|
||||
script = ExtResource("1_02ocl")
|
||||
|
||||
[node name="RightMargin" type="MarginContainer" parent="."]
|
||||
custom_minimum_size = Vector2(450, 2.08165e-12)
|
||||
layout_mode = 1
|
||||
anchors_preset = 11
|
||||
anchor_left = 1.0
|
||||
anchor_right = 1.0
|
||||
anchor_bottom = 1.0
|
||||
offset_left = -450.0
|
||||
grow_horizontal = 0
|
||||
grow_vertical = 2
|
||||
size_flags_horizontal = 3
|
||||
size_flags_stretch_ratio = 2.0
|
||||
mouse_filter = 2
|
||||
theme_override_constants/margin_left = 50
|
||||
theme_override_constants/margin_top = 50
|
||||
theme_override_constants/margin_right = 50
|
||||
theme_override_constants/margin_bottom = 50
|
||||
|
||||
[node name="RightContainer" type="VBoxContainer" parent="RightMargin"]
|
||||
layout_mode = 2
|
||||
mouse_filter = 2
|
||||
alignment = 2
|
||||
|
||||
[node name="ValidateButton" type="Button" parent="RightMargin/RightContainer"]
|
||||
layout_mode = 2
|
||||
theme_override_font_sizes/font_size = 70
|
||||
text = "Next"
|
||||
|
||||
[node name="PanelContainer" type="PanelContainer" parent="."]
|
||||
layout_mode = 1
|
||||
anchors_preset = 5
|
||||
anchor_left = 0.5
|
||||
anchor_right = 0.5
|
||||
offset_left = -775.0
|
||||
offset_right = 775.0
|
||||
offset_bottom = 502.0
|
||||
grow_horizontal = 2
|
||||
|
||||
[node name="QuestionContainer" type="MarginContainer" parent="PanelContainer"]
|
||||
layout_mode = 2
|
||||
theme_override_constants/margin_left = 25
|
||||
theme_override_constants/margin_right = 25
|
||||
|
||||
[node name="QuestionLabel" type="Label" parent="PanelContainer/QuestionContainer"]
|
||||
unique_name_in_owner = true
|
||||
custom_minimum_size = Vector2(1500, 500)
|
||||
layout_mode = 2
|
||||
size_flags_vertical = 1
|
||||
theme_override_font_sizes/font_size = 70
|
||||
horizontal_alignment = 1
|
||||
vertical_alignment = 1
|
||||
autowrap_mode = 2
|
||||
|
||||
[node name="FormValidator" type="Control" parent="."]
|
||||
unique_name_in_owner = true
|
||||
layout_mode = 1
|
||||
anchors_preset = 7
|
||||
anchor_left = 0.5
|
||||
anchor_top = 1.0
|
||||
anchor_right = 0.5
|
||||
anchor_bottom = 1.0
|
||||
offset_left = -20.0
|
||||
offset_top = -40.0
|
||||
offset_right = 20.0
|
||||
grow_horizontal = 2
|
||||
grow_vertical = 0
|
||||
script = ExtResource("2_jbdsv")
|
||||
auto_validate = true
|
||||
|
||||
[node name="FormContainer" type="VBoxContainer" parent="FormValidator"]
|
||||
unique_name_in_owner = true
|
||||
custom_minimum_size = Vector2(1624, 812)
|
||||
layout_mode = 1
|
||||
anchors_preset = 7
|
||||
anchor_left = 0.5
|
||||
anchor_top = 1.0
|
||||
anchor_right = 0.5
|
||||
anchor_bottom = 1.0
|
||||
offset_left = -812.0
|
||||
offset_top = -812.0
|
||||
offset_right = 812.0
|
||||
grow_horizontal = 2
|
||||
grow_vertical = 0
|
||||
theme_override_constants/separation = 25
|
||||
alignment = 1
|
||||
|
||||
[connection signal="pressed" from="RightMargin/RightContainer/ValidateButton" to="." method="_on_validate_button_pressed"]
|
||||
@@ -0,0 +1,13 @@
|
||||
extends Step
|
||||
|
||||
|
||||
@onready var password := %password
|
||||
@onready var password_confirm := %password_confirm
|
||||
|
||||
func _on_validate_button_pressed():
|
||||
|
||||
if password.text != password_confirm.text:
|
||||
print("Make sure the password is the same in both fields")
|
||||
return
|
||||
|
||||
super._on_validate_button_pressed()
|
||||
@@ -0,0 +1,54 @@
|
||||
[gd_scene load_steps=10 format=3 uid="uid://cwqcybk5tvbly"]
|
||||
|
||||
[ext_resource type="PackedScene" uid="uid://bxd3i06rqpxf0" path="res://sources/menus/register/steps/base_step.tscn" id="1_66bx5"]
|
||||
[ext_resource type="Script" path="res://sources/menus/register/steps/credentials_step.gd" id="2_uwjaa"]
|
||||
[ext_resource type="Script" path="res://addons/godot-form-validator/control_validator.gd" id="3_hblcf"]
|
||||
[ext_resource type="Script" path="res://addons/godot-form-validator/rules/required_rule.gd" id="4_4ltsd"]
|
||||
[ext_resource type="Script" path="res://addons/godot-form-validator/rules/email_rule.gd" id="5_cnymo"]
|
||||
[ext_resource type="Script" path="res://addons/godot-form-validator/validators/line_edit_validator.gd" id="6_viaho"]
|
||||
|
||||
[sub_resource type="Resource" id="Resource_os08u"]
|
||||
script = ExtResource("4_4ltsd")
|
||||
fail_message = "A value is required."
|
||||
|
||||
[sub_resource type="Resource" id="Resource_j7vhe"]
|
||||
script = ExtResource("5_cnymo")
|
||||
fail_message = "Value must be a valid email address."
|
||||
|
||||
[sub_resource type="Resource" id="Resource_84kj5"]
|
||||
script = ExtResource("6_viaho")
|
||||
validation_order = 1
|
||||
validation_method = 0
|
||||
skip_validation = false
|
||||
rules = Array[Resource("res://addons/godot-form-validator/rules/validator_rule.gd")]([SubResource("Resource_os08u"), SubResource("Resource_j7vhe")])
|
||||
|
||||
[node name="CredentialsStep" instance=ExtResource("1_66bx5")]
|
||||
script = ExtResource("2_uwjaa")
|
||||
question_txt = "Fill in your credentials"
|
||||
|
||||
[node name="ValidateButton" parent="RightMargin/RightContainer" index="0"]
|
||||
text = "Validate"
|
||||
|
||||
[node name="QuestionLabel" parent="PanelContainer/QuestionContainer" index="0"]
|
||||
text = "Fill in your credentials"
|
||||
|
||||
[node name="email" type="LineEdit" parent="FormValidator/FormContainer" index="0"]
|
||||
layout_mode = 2
|
||||
theme_override_font_sizes/font_size = 70
|
||||
placeholder_text = "Email"
|
||||
|
||||
[node name="ControlValidator" type="Node" parent="FormValidator/FormContainer/email" index="0"]
|
||||
script = ExtResource("3_hblcf")
|
||||
validator = SubResource("Resource_84kj5")
|
||||
|
||||
[node name="password" type="LineEdit" parent="FormValidator/FormContainer" index="1"]
|
||||
unique_name_in_owner = true
|
||||
layout_mode = 2
|
||||
theme_override_font_sizes/font_size = 70
|
||||
placeholder_text = "Password"
|
||||
|
||||
[node name="password_confirm" type="LineEdit" parent="FormValidator/FormContainer" index="2"]
|
||||
unique_name_in_owner = true
|
||||
layout_mode = 2
|
||||
theme_override_font_sizes/font_size = 70
|
||||
placeholder_text = "Confirm password"
|
||||
@@ -0,0 +1,20 @@
|
||||
[gd_scene load_steps=2 format=3 uid="uid://do5e7c1oxkn5g"]
|
||||
|
||||
[ext_resource type="PackedScene" uid="uid://bxd3i06rqpxf0" path="res://sources/menus/register/steps/base_step.tscn" id="1_w3urq"]
|
||||
|
||||
[node name="DevicesCountStep" instance=ExtResource("1_w3urq")]
|
||||
question_txt = "Choose the number of devices you are using"
|
||||
|
||||
[node name="QuestionLabel" parent="PanelContainer/QuestionContainer" index="0"]
|
||||
text = "Choose the number of devices you are using"
|
||||
|
||||
[node name="FormContainer" parent="." index="2"]
|
||||
offset_left = -812.0
|
||||
offset_top = -812.0
|
||||
offset_right = 812.0
|
||||
|
||||
[node name="devices_count" type="SpinBox" parent="FormContainer" index="0"]
|
||||
layout_mode = 2
|
||||
min_value = 1.0
|
||||
max_value = 90.0
|
||||
value = 1.0
|
||||
@@ -0,0 +1,19 @@
|
||||
[gd_scene load_steps=2 format=3 uid="uid://buhnx0oblueuq"]
|
||||
|
||||
[ext_resource type="PackedScene" uid="uid://bxd3i06rqpxf0" path="res://sources/menus/register/steps/base_step.tscn" id="1_ksrhk"]
|
||||
|
||||
[node name="MethodStep" instance=ExtResource("1_ksrhk")]
|
||||
question_txt = "Choose the education method you are using"
|
||||
|
||||
[node name="QuestionLabel" parent="PanelContainer/QuestionContainer" index="0"]
|
||||
text = "Choose the education method you are using"
|
||||
|
||||
[node name="method" type="ItemList" parent="FormContainer" index="0"]
|
||||
layout_mode = 2
|
||||
theme_override_constants/h_separation = 25
|
||||
theme_override_constants/v_separation = 25
|
||||
theme_override_font_sizes/font_size = 70
|
||||
auto_height = true
|
||||
item_count = 2
|
||||
item_0/text = "Complete"
|
||||
item_1/text = "App Only"
|
||||
@@ -0,0 +1,15 @@
|
||||
[gd_scene load_steps=2 format=3 uid="uid://cyhoa68y1yyyg"]
|
||||
|
||||
[ext_resource type="PackedScene" uid="uid://bxd3i06rqpxf0" path="res://sources/menus/register/steps/base_step.tscn" id="1_par6r"]
|
||||
|
||||
[node name="StudentsCountStep" instance=ExtResource("1_par6r")]
|
||||
question_txt = "Choose the total number of students"
|
||||
|
||||
[node name="QuestionLabel" parent="PanelContainer/QuestionContainer" index="0"]
|
||||
text = "Choose the total number of students"
|
||||
|
||||
[node name="students_count" type="SpinBox" parent="FormContainer" index="0"]
|
||||
layout_mode = 2
|
||||
min_value = 1.0
|
||||
max_value = 90.0
|
||||
value = 1.0
|
||||