Nomenclatures corrections
This commit is contained in:
@@ -57,10 +57,7 @@ def split_params(param_string: str):
|
|||||||
return params
|
return params
|
||||||
|
|
||||||
EXCLUDED_DIRS = {"addons", ".git", ".github"}
|
EXCLUDED_DIRS = {"addons", ".git", ".github"}
|
||||||
|
EXCLUDED_FILES = {os.path.normpath("script_templates/Node/default.gd")}
|
||||||
PASCAL_CASE = re.compile(r"^[A-Z][A-Za-z0-9]*$")
|
|
||||||
SNAKE_CASE = re.compile(r"^_?[a-z][a-z0-9_]*$")
|
|
||||||
UPPER_SNAKE_CASE = re.compile(r"^_?[A-Z][A-Z0-9_]*$")
|
|
||||||
|
|
||||||
issues = []
|
issues = []
|
||||||
MESSAGES = {
|
MESSAGES = {
|
||||||
@@ -69,63 +66,317 @@ MESSAGES = {
|
|||||||
'variable': 'is a variable name and should be in snake_case',
|
'variable': 'is a variable name and should be in snake_case',
|
||||||
'constant': 'is a constant name and should be in UPPER_SNAKE_CASE',
|
'constant': 'is a constant name and should be in UPPER_SNAKE_CASE',
|
||||||
'signal': 'is a signal name and should be in snake_case',
|
'signal': 'is a signal name and should be in snake_case',
|
||||||
|
'annotation_order': 'annotations must be on the first line and include only \@tool, \@icon or \@static_unload',
|
||||||
|
'class_position': 'class_name must appear after annotations (if any)',
|
||||||
|
'extends_position': 'extends must appear after annotation and class_name',
|
||||||
|
'extends_missing': 'extends is required and must follow annotation and class_name',
|
||||||
|
'func_blank': 'functions must be preceded by exactly two empty lines (or only one if preceded by a #region comment)',
|
||||||
|
'signal_position': 'signals must come right after extends',
|
||||||
|
'signal_format': 'signals must end with ()',
|
||||||
|
'signal_blank': 'signals must not be separated by empty lines',
|
||||||
|
'enum_position': 'enums must come after signals and be grouped together',
|
||||||
|
'enum_format': "enum declaration should be 'enum Name {'",
|
||||||
|
'enum_member_blank': 'enum members must not be separated by empty lines',
|
||||||
|
'enum_member_indent': 'enum members must be indented with a single tab',
|
||||||
|
'enum_no_close': 'enum declaration is missing a closing }',
|
||||||
|
'enum_blank': 'enums must be preceded by one empty line and must not be separated by empty lines',
|
||||||
|
'const_position': 'constants must come after enums and be grouped together',
|
||||||
|
'const_blank': 'constants must be preceded by one empty line and must not be separated by empty lines',
|
||||||
|
'static_position': 'static variables must come after constants and be grouped together',
|
||||||
|
'static_blank': 'static variables must be preceded by one empty line and must not be separated by empty lines',
|
||||||
|
'export_position': 'export variables must come after static variables and be grouped together',
|
||||||
|
'export_blank': 'export variables must be preceded by one empty line and must not be separated by empty lines',
|
||||||
|
'var_position': 'variables must come after export variables and be grouped together',
|
||||||
|
'var_blank': 'variables must be preceded by one empty line and must not be separated by empty lines',
|
||||||
|
'onready_position': '@onready variables must come after other variables and be grouped together',
|
||||||
|
'onready_blank': '@onready variables must be preceded by one empty line and must not be separated by empty lines',
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# Naming conventions
|
||||||
|
PASCAL_CASE = re.compile(r"^[A-Z][A-Za-z0-9]*$")
|
||||||
|
SNAKE_CASE = re.compile(r"^_?[a-z][a-z0-9_]*$")
|
||||||
|
UPPER_SNAKE_CASE = re.compile(r"^_?[A-Z][A-Z0-9_]*$")
|
||||||
|
REGION_RE = re.compile(r"#\s*(region|endregion)\b", re.IGNORECASE)
|
||||||
|
|
||||||
|
def check_naming(path: str, lines: list[str]):
|
||||||
|
for idx, line in enumerate(lines, 1):
|
||||||
|
stripped = line.strip()
|
||||||
|
if stripped.startswith('#') or stripped.startswith('@warning_ignore(') or not stripped:
|
||||||
|
continue
|
||||||
|
match_class = re.match(r"class_name\s+([A-Za-z0-9_]+)", stripped)
|
||||||
|
if match_class:
|
||||||
|
name = match_class.group(1)
|
||||||
|
if not PASCAL_CASE.match(name):
|
||||||
|
issues.append((path, idx, 'class', name))
|
||||||
|
match_func = re.match(r"(?:static\s+)?func\s+([A-Za-z0-9_]+)\s*(\([^)]*\))?", stripped)
|
||||||
|
if match_func:
|
||||||
|
name = match_func.group(1)
|
||||||
|
if not SNAKE_CASE.match(name):
|
||||||
|
issues.append((path, idx, 'function', name))
|
||||||
|
params = match_func.group(2)
|
||||||
|
if params:
|
||||||
|
params = params.strip('()')
|
||||||
|
for param in split_params(params):
|
||||||
|
param_name = param.split(':')[0].split('=')[0].strip()
|
||||||
|
if param_name and not SNAKE_CASE.match(param_name):
|
||||||
|
issues.append((path, idx, 'variable', param_name))
|
||||||
|
match_export = re.match(r"(?:@export\s+)?var\s+([A-Za-z0-9_]+)", stripped)
|
||||||
|
if match_export:
|
||||||
|
name = match_export.group(1)
|
||||||
|
if not SNAKE_CASE.match(name):
|
||||||
|
issues.append((path, idx, 'variable', name))
|
||||||
|
match_const = re.match(r"const\s+([A-Za-z0-9_]+)", stripped)
|
||||||
|
if match_const:
|
||||||
|
name = match_const.group(1)
|
||||||
|
if not UPPER_SNAKE_CASE.match(name):
|
||||||
|
issues.append((path, idx, 'constant', name))
|
||||||
|
match_signal = re.match(r"signal\s+([A-Za-z0-9_]+)", stripped)
|
||||||
|
if match_signal:
|
||||||
|
name = match_signal.group(1)
|
||||||
|
if not SNAKE_CASE.match(name):
|
||||||
|
issues.append((path, idx, 'signal', name))
|
||||||
|
match_for = re.match(r"for\s+([A-Za-z0-9_]+)(?:\s*:\s*[^\s]+)?\s+in\b", stripped)
|
||||||
|
if match_for:
|
||||||
|
name = match_for.group(1)
|
||||||
|
if not SNAKE_CASE.match(name):
|
||||||
|
issues.append((path, idx, 'variable', name))
|
||||||
|
|
||||||
|
# Content order
|
||||||
|
ANNOTATION_LINE_RE = re.compile(
|
||||||
|
r"^(?:@(tool|icon|static_unload)(?:\([^\n]*\))?)(?:,\s*@(tool|icon|static_unload)(?:\([^\n]*\))?)*$"
|
||||||
|
)
|
||||||
|
ALLOWED_ANNOTATION_RE = re.compile(r"@(tool|icon|static_unload)\b")
|
||||||
|
|
||||||
|
def check_content_order(path: str, lines: list[str]):
|
||||||
|
content = [
|
||||||
|
(line.rstrip('\n'), idx)
|
||||||
|
for idx, line in enumerate(lines, 1)
|
||||||
|
if not line.startswith(' ') # Line is not indented
|
||||||
|
and not line.lstrip().startswith('#')
|
||||||
|
and not line.lstrip().startswith('@warning_ignore(')
|
||||||
|
]
|
||||||
|
idx = 0
|
||||||
|
n = len(content)
|
||||||
|
|
||||||
|
# 1) annotations
|
||||||
|
if idx < n and ANNOTATION_LINE_RE.fullmatch(content[idx][0].strip()):
|
||||||
|
idx += 1
|
||||||
|
else:
|
||||||
|
for j in range(idx, n):
|
||||||
|
if ALLOWED_ANNOTATION_RE.search(content[j][0]):
|
||||||
|
issues.append((path, content[j][1], 'annotation_order', content[j][0].strip()))
|
||||||
|
break
|
||||||
|
|
||||||
|
# 2) class_name (optional)
|
||||||
|
for j in range(idx, n):
|
||||||
|
if content[j][0].strip().startswith('class_name'):
|
||||||
|
if j != idx:
|
||||||
|
issues.append((path, content[j][1], 'class_position', 'class_name'))
|
||||||
|
else:
|
||||||
|
idx += 1
|
||||||
|
break
|
||||||
|
|
||||||
|
# 3) extends (required)
|
||||||
|
extends_pos = None
|
||||||
|
for j in range(idx, n):
|
||||||
|
if content[j][0].strip().startswith('extends'):
|
||||||
|
extends_pos = j
|
||||||
|
break
|
||||||
|
if extends_pos is None:
|
||||||
|
issues.append((path, 0, 'extends_missing', 'extends'))
|
||||||
|
return
|
||||||
|
if extends_pos != idx:
|
||||||
|
issues.append((path, content[extends_pos][1], 'extends_position', 'extends'))
|
||||||
|
idx = extends_pos + 1
|
||||||
|
|
||||||
|
order = ['signal', 'enum', 'const', 'static var', '@export', 'var', '@onready var']
|
||||||
|
order_index = {name: i for i, name in enumerate(order)}
|
||||||
|
seen: set[str] = set()
|
||||||
|
current_order = -1
|
||||||
|
prev_token: str | None = content[extends_pos][0].strip()
|
||||||
|
j = idx
|
||||||
|
while j < n:
|
||||||
|
line, line_no = content[j]
|
||||||
|
stripped = line.strip()
|
||||||
|
if stripped == '':
|
||||||
|
prev_token = ''
|
||||||
|
j += 1
|
||||||
|
continue
|
||||||
|
if re.match(r'(?:static\s+)?func\b', stripped):
|
||||||
|
break
|
||||||
|
token = None
|
||||||
|
if stripped.startswith('signal'):
|
||||||
|
token = 'signal'
|
||||||
|
if not re.fullmatch(r"signal\s+\w+\([^)]*\)", stripped):
|
||||||
|
issues.append((path, line_no, 'signal_format', stripped))
|
||||||
|
if 'signal' in seen and prev_token == '':
|
||||||
|
issues.append((path, content[j - 1][1], 'signal_blank', 'signal'))
|
||||||
|
seen.add('signal')
|
||||||
|
elif stripped.startswith('enum'):
|
||||||
|
token = 'enum'
|
||||||
|
if not re.fullmatch(r"enum\s+\w+\s*{", stripped):
|
||||||
|
issues.append((path, line_no, 'enum_format', stripped))
|
||||||
|
if 'enum' not in seen:
|
||||||
|
if prev_token != '':
|
||||||
|
issues.append((path, line_no, 'enum_blank', 'enum'))
|
||||||
|
else:
|
||||||
|
if prev_token != '}' and prev_token != ']':
|
||||||
|
issues.append((path, line_no, 'enum_blank', 'enum'))
|
||||||
|
k = j + 1
|
||||||
|
while k < n and content[k][0].strip() != '}':
|
||||||
|
member, m_line_no = content[k]
|
||||||
|
if member.strip() == '':
|
||||||
|
issues.append((path, m_line_no, 'enum_member_blank', 'enum'))
|
||||||
|
if not member.startswith('\t') or member.startswith('\t\t'):
|
||||||
|
issues.append((path, m_line_no, 'enum_member_indent', member.strip()))
|
||||||
|
k += 1
|
||||||
|
if k >= n:
|
||||||
|
issues.append((path, line_no, 'enum_no_close', 'enum'))
|
||||||
|
return
|
||||||
|
j = k
|
||||||
|
prev_token = '}'
|
||||||
|
seen.add('enum')
|
||||||
|
curr_order = order_index['enum']
|
||||||
|
if curr_order < current_order:
|
||||||
|
issues.append((path, line_no, 'enum_position', 'enum'))
|
||||||
|
else:
|
||||||
|
current_order = max(current_order, curr_order)
|
||||||
|
j += 1
|
||||||
|
continue
|
||||||
|
elif stripped.startswith('const '):
|
||||||
|
token = 'const'
|
||||||
|
if 'const' not in seen:
|
||||||
|
if prev_token != '':
|
||||||
|
issues.append((path, line_no, 'const_blank', 'const'))
|
||||||
|
else:
|
||||||
|
if prev_token != 'const' and prev_token != '}' and prev_token != ']':
|
||||||
|
issues.append((path, line_no, 'const_blank', 'const'))
|
||||||
|
seen.add('const')
|
||||||
|
elif stripped.startswith('static var '):
|
||||||
|
token = 'static var'
|
||||||
|
if 'static var' not in seen:
|
||||||
|
if prev_token != '':
|
||||||
|
issues.append((path, line_no, 'static_blank', 'static var'))
|
||||||
|
else:
|
||||||
|
if prev_token != 'static var' and prev_token != '}' and prev_token != ']':
|
||||||
|
issues.append((path, line_no, 'static_blank', 'static var'))
|
||||||
|
seen.add('static var')
|
||||||
|
elif stripped.startswith('@export'):
|
||||||
|
token = '@export'
|
||||||
|
if '@export' not in seen:
|
||||||
|
if prev_token != '':
|
||||||
|
issues.append((path, line_no, 'export_blank', '@export'))
|
||||||
|
else:
|
||||||
|
if prev_token != '@export' and prev_token != '}' and prev_token != ']':
|
||||||
|
issues.append((path, line_no, 'export_blank', '@export'))
|
||||||
|
seen.add('@export')
|
||||||
|
elif stripped.startswith('var '):
|
||||||
|
token = 'var'
|
||||||
|
if 'var' not in seen:
|
||||||
|
if prev_token != '':
|
||||||
|
issues.append((path, line_no, 'var_blank', 'var'))
|
||||||
|
else:
|
||||||
|
if prev_token != 'var' and prev_token != '}' and prev_token != ']':
|
||||||
|
issues.append((path, line_no, 'var_blank', 'var'))
|
||||||
|
seen.add('var')
|
||||||
|
elif stripped.startswith('@onready var '):
|
||||||
|
token = '@onready var'
|
||||||
|
if '@onready var' not in seen:
|
||||||
|
if prev_token != '':
|
||||||
|
issues.append((path, line_no, 'onready_blank', '@onready var'))
|
||||||
|
else:
|
||||||
|
if prev_token != '@onready var' and prev_token != '}' and prev_token != ']':
|
||||||
|
issues.append((path, line_no, 'onready_blank', '@onready var'))
|
||||||
|
seen.add('@onready var')
|
||||||
|
else:
|
||||||
|
prev_token = stripped
|
||||||
|
j += 1
|
||||||
|
continue
|
||||||
|
curr_order = order_index[token]
|
||||||
|
key_map = {
|
||||||
|
'signal': 'signal_position',
|
||||||
|
'enum': 'enum_position',
|
||||||
|
'const': 'const_position',
|
||||||
|
'static var': 'static_position',
|
||||||
|
'@export': 'export_position',
|
||||||
|
'var': 'var_position',
|
||||||
|
'@onready var': 'onready_position',
|
||||||
|
}
|
||||||
|
if curr_order < current_order:
|
||||||
|
issues.append((path, line_no, key_map[token], token))
|
||||||
|
else:
|
||||||
|
current_order = max(current_order, curr_order)
|
||||||
|
|
||||||
|
prev_token = token
|
||||||
|
j += 1
|
||||||
|
|
||||||
|
|
||||||
|
# Spacing for functions
|
||||||
|
def check_func_spacing(path: str):
|
||||||
|
with open(path, 'r', encoding='utf-8') as file:
|
||||||
|
lines = file.readlines()
|
||||||
|
for idx, line in enumerate(lines):
|
||||||
|
stripped_line = line.lstrip()
|
||||||
|
if re.match(r'(?:static\s+)?func\b', stripped_line):
|
||||||
|
if re.match(r'(?:static\s+)?func\s*\(', stripped_line):
|
||||||
|
continue
|
||||||
|
start_idx = idx
|
||||||
|
# Skip annotations and regular comments above the function
|
||||||
|
while start_idx > 0:
|
||||||
|
prev_line = lines[start_idx - 1].lstrip()
|
||||||
|
if prev_line.startswith('@warning_ignore('):
|
||||||
|
start_idx -= 1
|
||||||
|
elif prev_line.startswith('#') and not REGION_RE.match(prev_line):
|
||||||
|
start_idx -= 1
|
||||||
|
else:
|
||||||
|
break
|
||||||
|
test_index = start_idx - 1
|
||||||
|
blank_count = 0
|
||||||
|
while test_index >= 0:
|
||||||
|
stripped = lines[test_index].lstrip()
|
||||||
|
if stripped == '':
|
||||||
|
blank_count += 1
|
||||||
|
test_index -= 1
|
||||||
|
continue
|
||||||
|
if stripped.startswith('@warning_ignore('):
|
||||||
|
test_index -= 1
|
||||||
|
continue
|
||||||
|
if stripped.startswith('#') and not REGION_RE.match(stripped):
|
||||||
|
test_index -= 1
|
||||||
|
continue
|
||||||
|
break
|
||||||
|
region_above = test_index >= 0 and REGION_RE.match(lines[test_index].lstrip())
|
||||||
|
if region_above:
|
||||||
|
if blank_count > 1:
|
||||||
|
issues.append((path, idx + 1, 'func_blank', 'func'))
|
||||||
|
continue
|
||||||
|
elif blank_count != 2:
|
||||||
|
if not (blank_count == 1 and test_index >= 0 and lines[test_index].lstrip().startswith('#region')):
|
||||||
|
issues.append((path, idx + 1, 'func_blank', 'func'))
|
||||||
|
|
||||||
|
|
||||||
|
# Main function
|
||||||
for root, dirs, files in os.walk('.', topdown=True):
|
for root, dirs, files in os.walk('.', topdown=True):
|
||||||
rel_root = os.path.relpath(root, '.')
|
rel_root = os.path.relpath(root, '.')
|
||||||
if any(rel_root == excluded or rel_root.startswith(f"{excluded}{os.sep}") for excluded in EXCLUDED_DIRS):
|
if any(rel_root == excluded or rel_root.startswith(f"{excluded}{os.sep}") for excluded in EXCLUDED_DIRS):
|
||||||
dirs[:] = []
|
dirs[:] = []
|
||||||
continue
|
continue
|
||||||
for fname in files:
|
for fname in files:
|
||||||
if fname.endswith('.gd'):
|
if not fname.endswith('.gd'):
|
||||||
path = os.path.join(root, fname)
|
continue
|
||||||
try:
|
path = os.path.join(root, fname)
|
||||||
with open(path, 'r', encoding='utf-8') as file:
|
rel_path = os.path.normpath(os.path.relpath(path, '.'))
|
||||||
lines = file.readlines()
|
if rel_path in EXCLUDED_FILES:
|
||||||
except Exception as e:
|
continue
|
||||||
issues.append((path, 0, 'error', f'Could not read file: {e}'))
|
try:
|
||||||
continue
|
with open(path, 'r', encoding='utf-8') as file:
|
||||||
for idx, line in enumerate(lines, 1):
|
lines = file.readlines()
|
||||||
stripped = line.strip()
|
except Exception as e:
|
||||||
if stripped.startswith('#') or not stripped:
|
issues.append((path, 0, 'error', f'Could not read file: {e}'))
|
||||||
continue
|
continue
|
||||||
match_class = re.match(r"class_name\s+([A-Za-z0-9_]+)", stripped)
|
check_naming(path, lines)
|
||||||
if match_class:
|
check_content_order(path, lines)
|
||||||
name = match_class.group(1)
|
check_func_spacing(path)
|
||||||
if not PASCAL_CASE.match(name):
|
|
||||||
issues.append((path, idx, 'class', name))
|
|
||||||
match_func = re.match(r"func\s+([A-Za-z0-9_]+)\s*(\([^)]*\))?", stripped)
|
|
||||||
if match_func:
|
|
||||||
name = match_func.group(1)
|
|
||||||
if not SNAKE_CASE.match(name):
|
|
||||||
issues.append((path, idx, 'function', name))
|
|
||||||
params = match_func.group(2)
|
|
||||||
if params:
|
|
||||||
params = params.strip('()')
|
|
||||||
for param in split_params(params):
|
|
||||||
param_name = param.split(':')[0].split('=')[0].strip()
|
|
||||||
if param_name and not SNAKE_CASE.match(param_name):
|
|
||||||
issues.append((path, idx, 'variable', param_name))
|
|
||||||
match_export = re.match(r"(?:@export\s+)?var\s+([A-Za-z0-9_]+)", stripped)
|
|
||||||
if match_export:
|
|
||||||
name = match_export.group(1)
|
|
||||||
if not SNAKE_CASE.match(name):
|
|
||||||
issues.append((path, idx, 'variable', name))
|
|
||||||
match_const = re.match(r"const\s+([A-Za-z0-9_]+)", stripped)
|
|
||||||
if match_const:
|
|
||||||
name = match_const.group(1)
|
|
||||||
if not UPPER_SNAKE_CASE.match(name):
|
|
||||||
issues.append((path, idx, 'constant', name))
|
|
||||||
match_signal = re.match(r"signal\s+([A-Za-z0-9_]+)", stripped)
|
|
||||||
if match_signal:
|
|
||||||
name = match_signal.group(1)
|
|
||||||
if not SNAKE_CASE.match(name):
|
|
||||||
issues.append((path, idx, 'signal', name))
|
|
||||||
match_for = re.match(r"for\s+([A-Za-z0-9_]+)(?:\s*:\s*[^\s]+)?\s+in\b", stripped)
|
|
||||||
if match_for:
|
|
||||||
name = match_for.group(1)
|
|
||||||
if not SNAKE_CASE.match(name):
|
|
||||||
issues.append((path, idx, 'variable', name))
|
|
||||||
|
|
||||||
if issues:
|
if issues:
|
||||||
print("### \u274c GDScript Naming Convention Check Failed\n")
|
print("### \u274c GDScript Naming Convention Check Failed\n")
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ const CONFIG_PATH: String = "user://environment.cfg"
|
|||||||
var env_selector: OptionButton
|
var env_selector: OptionButton
|
||||||
var current_environment: EnvType = EnvType.DEV
|
var current_environment: EnvType = EnvType.DEV
|
||||||
|
|
||||||
|
|
||||||
func _enter_tree() -> void:
|
func _enter_tree() -> void:
|
||||||
# Create OptionButton
|
# Create OptionButton
|
||||||
env_selector = OptionButton.new()
|
env_selector = OptionButton.new()
|
||||||
@@ -25,27 +26,32 @@ func _enter_tree() -> void:
|
|||||||
# Reflect the current environment in UI
|
# Reflect the current environment in UI
|
||||||
env_selector.select(current_environment)
|
env_selector.select(current_environment)
|
||||||
|
|
||||||
|
|
||||||
func _exit_tree() -> void:
|
func _exit_tree() -> void:
|
||||||
# Clean up the UI and save state
|
# Clean up the UI and save state
|
||||||
remove_control_from_container(EditorPlugin.CONTAINER_TOOLBAR, env_selector)
|
remove_control_from_container(EditorPlugin.CONTAINER_TOOLBAR, env_selector)
|
||||||
env_selector.queue_free()
|
env_selector.queue_free()
|
||||||
|
|
||||||
|
|
||||||
func _on_env_selected(index: int) -> void:
|
func _on_env_selected(index: int) -> void:
|
||||||
current_environment = index
|
current_environment = index
|
||||||
save_environment()
|
save_environment()
|
||||||
print("Environment switched to:", _environment_to_string(current_environment))
|
print("Environment switched to:", _environment_to_string(current_environment))
|
||||||
|
|
||||||
|
|
||||||
func _environment_to_string(env: EnvType) -> String:
|
func _environment_to_string(env: EnvType) -> String:
|
||||||
match env:
|
match env:
|
||||||
EnvType.DEV: return "DEV"
|
EnvType.DEV: return "DEV"
|
||||||
EnvType.PROD: return "PROD"
|
EnvType.PROD: return "PROD"
|
||||||
_: return "Unknown"
|
_: return "Unknown"
|
||||||
|
|
||||||
|
|
||||||
func save_environment() -> void:
|
func save_environment() -> void:
|
||||||
var config = ConfigFile.new()
|
var config = ConfigFile.new()
|
||||||
config.set_value("environment", "current", str(current_environment))
|
config.set_value("environment", "current", str(current_environment))
|
||||||
config.save(CONFIG_PATH)
|
config.save(CONFIG_PATH)
|
||||||
|
|
||||||
|
|
||||||
func load_environment() -> void:
|
func load_environment() -> void:
|
||||||
var config = ConfigFile.new()
|
var config = ConfigFile.new()
|
||||||
if config.load(CONFIG_PATH) == OK:
|
if config.load(CONFIG_PATH) == OK:
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ extends PanelContainer
|
|||||||
|
|
||||||
@onready var form_validator_control: FormValidator = $MarginContainer/FormValidator
|
@onready var form_validator_control: FormValidator = $MarginContainer/FormValidator
|
||||||
|
|
||||||
|
|
||||||
func _on_form_validator_control_control_validated(control, passed, messages) -> void:
|
func _on_form_validator_control_control_validated(control, passed, messages) -> void:
|
||||||
var error_label = _get_error_label(control)
|
var error_label = _get_error_label(control)
|
||||||
var valid_label = _get_valid_label(control)
|
var valid_label = _get_valid_label(control)
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
@tool
|
@tool
|
||||||
extends ValidatorRule
|
|
||||||
class_name AlphanumericRule
|
class_name AlphanumericRule
|
||||||
|
extends ValidatorRule
|
||||||
|
|
||||||
|
|
||||||
func _init() -> void:
|
func _init() -> void:
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
@tool
|
@tool
|
||||||
extends ValidatorRule
|
|
||||||
class_name BooleanRule
|
class_name BooleanRule
|
||||||
|
extends ValidatorRule
|
||||||
|
|
||||||
@export var target_value: bool
|
@export var target_value: bool
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
@tool
|
@tool
|
||||||
extends ValidatorRule
|
|
||||||
class_name DoesNotMatchRule
|
class_name DoesNotMatchRule
|
||||||
|
extends ValidatorRule
|
||||||
|
|
||||||
@export var pattern: String
|
@export var pattern: String
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
@tool
|
@tool
|
||||||
extends ValidatorRule
|
|
||||||
class_name EqualsRule
|
class_name EqualsRule
|
||||||
|
extends ValidatorRule
|
||||||
|
|
||||||
@export var target_value: String
|
@export var target_value: String
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
@tool
|
@tool
|
||||||
extends ValidatorRule
|
|
||||||
class_name NotBlankRule
|
class_name NotBlankRule
|
||||||
|
extends ValidatorRule
|
||||||
|
|
||||||
|
|
||||||
func _init() -> void:
|
func _init() -> void:
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
extends RefCounted
|
|
||||||
class_name RuleResult
|
class_name RuleResult
|
||||||
|
extends RefCounted
|
||||||
|
|
||||||
var passed: bool = false
|
var passed: bool = false
|
||||||
var message: String = ""
|
var message: String = ""
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
@tool
|
@tool
|
||||||
extends Resource
|
|
||||||
class_name ValidatorRule
|
class_name ValidatorRule
|
||||||
|
extends Resource
|
||||||
|
|
||||||
@export var fail_message: String = ""
|
@export var fail_message: String = ""
|
||||||
|
|
||||||
|
|||||||
+1
-1
@@ -1,5 +1,5 @@
|
|||||||
extends ZIPReader
|
|
||||||
class_name FolderUnzipper
|
class_name FolderUnzipper
|
||||||
|
extends ZIPReader
|
||||||
|
|
||||||
signal file_count(count: int)
|
signal file_count(count: int)
|
||||||
signal file_copied(count: int, name: String)
|
signal file_copied(count: int, name: String)
|
||||||
|
|||||||
+1
-1
@@ -1,5 +1,5 @@
|
|||||||
extends ZIPPacker
|
|
||||||
class_name FolderZipper
|
class_name FolderZipper
|
||||||
|
extends ZIPPacker
|
||||||
|
|
||||||
|
|
||||||
func write_folder_recursive(abs_path: String, rel_path: String) -> Error:
|
func write_folder_recursive(abs_path: String, rel_path: String) -> Error:
|
||||||
|
|||||||
+1
-1
@@ -1,4 +1,4 @@
|
|||||||
extends Resource
|
|
||||||
class_name ProfToolSave
|
class_name ProfToolSave
|
||||||
|
extends Resource
|
||||||
|
|
||||||
@export var selected_language: String = ""
|
@export var selected_language: String = ""
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
@tool
|
@tool
|
||||||
extends Resource
|
|
||||||
class_name DeviceSettings
|
class_name DeviceSettings
|
||||||
|
extends Resource
|
||||||
|
|
||||||
const SUPPORTED_LOCALES: Array[String] = [
|
const SUPPORTED_LOCALES: Array[String] = [
|
||||||
# French France
|
# French France
|
||||||
@@ -26,25 +25,21 @@ const SUPPORTED_LOCALES: Array[String] = [
|
|||||||
@export var device_id: int
|
@export var device_id: int
|
||||||
@export var language_versions: Dictionary = {} # locale: datetime
|
@export var language_versions: Dictionary = {} # locale: datetime
|
||||||
@export var game_version: String = "0.0.1"
|
@export var game_version: String = "0.0.1"
|
||||||
|
|
||||||
@export var master_volume: float = 0.0:
|
@export var master_volume: float = 0.0:
|
||||||
set(volume):
|
set(volume):
|
||||||
master_volume = volume
|
master_volume = volume
|
||||||
var ind: int = AudioServer.get_bus_index("Master")
|
var ind: int = AudioServer.get_bus_index("Master")
|
||||||
AudioServer.set_bus_volume_db(ind, volume)
|
AudioServer.set_bus_volume_db(ind, volume)
|
||||||
|
|
||||||
@export var music_volume: float = 0.0:
|
@export var music_volume: float = 0.0:
|
||||||
set(volume):
|
set(volume):
|
||||||
music_volume = volume
|
music_volume = volume
|
||||||
var ind: int = AudioServer.get_bus_index("Music")
|
var ind: int = AudioServer.get_bus_index("Music")
|
||||||
AudioServer.set_bus_volume_db(ind, volume)
|
AudioServer.set_bus_volume_db(ind, volume)
|
||||||
|
|
||||||
@export var voice_volume: float = 0.0:
|
@export var voice_volume: float = 0.0:
|
||||||
set(volume):
|
set(volume):
|
||||||
voice_volume = volume
|
voice_volume = volume
|
||||||
var ind: int = AudioServer.get_bus_index("Voice")
|
var ind: int = AudioServer.get_bus_index("Voice")
|
||||||
AudioServer.set_bus_volume_db(ind, volume)
|
AudioServer.set_bus_volume_db(ind, volume)
|
||||||
|
|
||||||
@export var effects_volume: float = 0.0:
|
@export var effects_volume: float = 0.0:
|
||||||
set(volume):
|
set(volume):
|
||||||
effects_volume = volume
|
effects_volume = volume
|
||||||
|
|||||||
+15
-17
@@ -1,15 +1,28 @@
|
|||||||
@tool
|
@tool
|
||||||
extends Control
|
|
||||||
class_name Garden
|
class_name Garden
|
||||||
|
extends Control
|
||||||
|
|
||||||
|
enum FlowerSizes{
|
||||||
|
NOT_STARTED,
|
||||||
|
SMALL,
|
||||||
|
MEDIUM,
|
||||||
|
LARGE
|
||||||
|
}
|
||||||
|
|
||||||
const FLOWER_PATH_MODEL: String = "res://assets/gardens/flowers/plant_%02d_%02d_%s.png"
|
const FLOWER_PATH_MODEL: String = "res://assets/gardens/flowers/plant_%02d_%02d_%s.png"
|
||||||
const BACKGROUND_PATH_MODEL: String = "res://assets/gardens/gardens/garden_%02d_open.png"
|
const BACKGROUND_PATH_MODEL: String = "res://assets/gardens/gardens/garden_%02d_open.png"
|
||||||
|
|
||||||
@export var garden_layout: GardenLayout:
|
@export var garden_layout: GardenLayout:
|
||||||
set = set_garden_layout
|
set = set_garden_layout
|
||||||
|
|
||||||
@export var garden_colors: Array[Color] = []
|
@export var garden_colors: Array[Color] = []
|
||||||
|
|
||||||
|
var flowers: Array[GardenLayout.Flower] = []
|
||||||
|
var flowers_sizes: Array[FlowerSizes] = []
|
||||||
|
var color: Color
|
||||||
|
var current_progression: float = 0.0
|
||||||
|
var max_progression: float = 0.0
|
||||||
|
var garden_index: int = -1
|
||||||
|
|
||||||
@onready var buttons: Control = $Buttons
|
@onready var buttons: Control = $Buttons
|
||||||
@onready var flower_controls: Array[TextureRect] = [
|
@onready var flower_controls: Array[TextureRect] = [
|
||||||
%Flower1,
|
%Flower1,
|
||||||
@@ -26,21 +39,6 @@ const BACKGROUND_PATH_MODEL: String = "res://assets/gardens/gardens/garden_%02d_
|
|||||||
%Button4,
|
%Button4,
|
||||||
]
|
]
|
||||||
|
|
||||||
enum FlowerSizes{
|
|
||||||
NOT_STARTED,
|
|
||||||
SMALL,
|
|
||||||
MEDIUM,
|
|
||||||
LARGE
|
|
||||||
}
|
|
||||||
|
|
||||||
var flowers: Array[GardenLayout.Flower] = []
|
|
||||||
var flowers_sizes: Array[FlowerSizes] = []
|
|
||||||
var color: Color
|
|
||||||
|
|
||||||
var current_progression: float = 0.0
|
|
||||||
var max_progression: float = 0.0
|
|
||||||
|
|
||||||
var garden_index: int = -1
|
|
||||||
|
|
||||||
func get_button_size() -> Vector2:
|
func get_button_size() -> Vector2:
|
||||||
return lesson_button_controls[0].get_size()
|
return lesson_button_controls[0].get_size()
|
||||||
|
|||||||
@@ -1,46 +1,6 @@
|
|||||||
@tool
|
@tool
|
||||||
extends Resource
|
|
||||||
class_name GardenLayout
|
class_name GardenLayout
|
||||||
|
extends Resource
|
||||||
|
|
||||||
class Flower:
|
|
||||||
var color: int = 0
|
|
||||||
var type: int = 0
|
|
||||||
var position: Vector2 = Vector2i.ZERO
|
|
||||||
|
|
||||||
func _init(p_color: int = 0, p_type: int = 0, p_position: Vector2i = Vector2i.ZERO) -> void:
|
|
||||||
color = p_color
|
|
||||||
type = p_type
|
|
||||||
position = p_position
|
|
||||||
|
|
||||||
static func from_dict(d: Dictionary) -> Flower:
|
|
||||||
return Flower.new(d.color as int, d.type as int, d.position as Vector2i)
|
|
||||||
|
|
||||||
func to_dict() -> Dictionary:
|
|
||||||
return {
|
|
||||||
color = color,
|
|
||||||
type = type,
|
|
||||||
position = position,
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
class GardenLayoutLessonButton:
|
|
||||||
var position: Vector2i = Vector2i.ZERO
|
|
||||||
var path_out_position: Vector2i = Vector2i.ZERO
|
|
||||||
|
|
||||||
func _init(p_position: Vector2i = Vector2i.ZERO, p_path_out_position: Vector2i = Vector2i.ZERO) -> void:
|
|
||||||
position = p_position
|
|
||||||
path_out_position = p_path_out_position
|
|
||||||
|
|
||||||
static func from_dict(d: Dictionary) -> GardenLayoutLessonButton:
|
|
||||||
return GardenLayoutLessonButton.new(d.position as Vector2i, d.path_out_position as Vector2i)
|
|
||||||
|
|
||||||
func to_dict() -> Dictionary:
|
|
||||||
return {
|
|
||||||
position = position,
|
|
||||||
path_out_position = path_out_position
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
enum FirstOrLast {
|
enum FirstOrLast {
|
||||||
First,
|
First,
|
||||||
@@ -48,18 +8,18 @@ enum FirstOrLast {
|
|||||||
Last
|
Last
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@export var color: int = 0
|
@export var color: int = 0
|
||||||
var flowers: Array[Flower] = []:
|
|
||||||
set = set_flowers
|
|
||||||
@export var flowers_export: Array[Dictionary] = []:
|
@export var flowers_export: Array[Dictionary] = []:
|
||||||
set = set_flowers_export
|
set = set_flowers_export
|
||||||
var lesson_buttons: Array[GardenLayoutLessonButton] = []:
|
|
||||||
set = set_lesson_buttons
|
|
||||||
@export var lesson_buttons_export: Array[Dictionary] = []:
|
@export var lesson_buttons_export: Array[Dictionary] = []:
|
||||||
set = set_lesson_buttons_export
|
set = set_lesson_buttons_export
|
||||||
@export var is_first_or_last: FirstOrLast = FirstOrLast.Neither
|
@export var is_first_or_last: FirstOrLast = FirstOrLast.Neither
|
||||||
|
|
||||||
|
var flowers: Array[Flower] = []:
|
||||||
|
set = set_flowers
|
||||||
|
var lesson_buttons: Array[GardenLayoutLessonButton] = []:
|
||||||
|
set = set_lesson_buttons
|
||||||
|
|
||||||
|
|
||||||
func set_flowers_export(p_flowers_export: Array[Dictionary]) -> void:
|
func set_flowers_export(p_flowers_export: Array[Dictionary]) -> void:
|
||||||
flowers_export = p_flowers_export
|
flowers_export = p_flowers_export
|
||||||
@@ -87,3 +47,48 @@ func set_lesson_buttons(p_lesson_buttons: Array[GardenLayoutLessonButton]) -> vo
|
|||||||
lesson_buttons_export.clear()
|
lesson_buttons_export.clear()
|
||||||
for lesson_button: GardenLayoutLessonButton in lesson_buttons:
|
for lesson_button: GardenLayoutLessonButton in lesson_buttons:
|
||||||
lesson_buttons_export.append(lesson_button.to_dict())
|
lesson_buttons_export.append(lesson_button.to_dict())
|
||||||
|
|
||||||
|
|
||||||
|
class Flower:
|
||||||
|
var color: int = 0
|
||||||
|
var type: int = 0
|
||||||
|
var position: Vector2 = Vector2i.ZERO
|
||||||
|
|
||||||
|
|
||||||
|
func _init(p_color: int = 0, p_type: int = 0, p_position: Vector2i = Vector2i.ZERO) -> void:
|
||||||
|
color = p_color
|
||||||
|
type = p_type
|
||||||
|
position = p_position
|
||||||
|
|
||||||
|
|
||||||
|
static func from_dict(d: Dictionary) -> Flower:
|
||||||
|
return Flower.new(d.color as int, d.type as int, d.position as Vector2i)
|
||||||
|
|
||||||
|
|
||||||
|
func to_dict() -> Dictionary:
|
||||||
|
return {
|
||||||
|
color = color,
|
||||||
|
type = type,
|
||||||
|
position = position,
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
class GardenLayoutLessonButton:
|
||||||
|
var position: Vector2i = Vector2i.ZERO
|
||||||
|
var path_out_position: Vector2i = Vector2i.ZERO
|
||||||
|
|
||||||
|
|
||||||
|
func _init(p_position: Vector2i = Vector2i.ZERO, p_path_out_position: Vector2i = Vector2i.ZERO) -> void:
|
||||||
|
position = p_position
|
||||||
|
path_out_position = p_path_out_position
|
||||||
|
|
||||||
|
|
||||||
|
static func from_dict(d: Dictionary) -> GardenLayoutLessonButton:
|
||||||
|
return GardenLayoutLessonButton.new(d.position as Vector2i, d.path_out_position as Vector2i)
|
||||||
|
|
||||||
|
|
||||||
|
func to_dict() -> Dictionary:
|
||||||
|
return {
|
||||||
|
position = position,
|
||||||
|
path_out_position = path_out_position
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
@tool
|
@tool
|
||||||
extends Resource
|
|
||||||
class_name GardensLayout
|
class_name GardensLayout
|
||||||
|
extends Resource
|
||||||
|
|
||||||
@export var gardens: Array[GardenLayout] = []
|
@export var gardens: Array[GardenLayout] = []
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
extends Resource
|
|
||||||
class_name StudentData
|
class_name StudentData
|
||||||
|
extends Resource
|
||||||
|
|
||||||
enum Level {
|
enum Level {
|
||||||
Beginner,
|
Beginner,
|
||||||
@@ -14,6 +13,7 @@ enum Level {
|
|||||||
@export var age: int = 0
|
@export var age: int = 0
|
||||||
@export var last_modified: String = ""
|
@export var last_modified: String = ""
|
||||||
|
|
||||||
|
|
||||||
func to_dict() -> Dictionary:
|
func to_dict() -> Dictionary:
|
||||||
return {
|
return {
|
||||||
"code": code,
|
"code": code,
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
extends Resource
|
|
||||||
class_name StudentProgression
|
class_name StudentProgression
|
||||||
|
extends Resource
|
||||||
|
|
||||||
signal unlocks_changed()
|
signal unlocks_changed()
|
||||||
|
|
||||||
@@ -17,6 +17,7 @@ enum Status{
|
|||||||
func _init() -> void:
|
func _init() -> void:
|
||||||
init_unlocks()
|
init_unlocks()
|
||||||
|
|
||||||
|
|
||||||
# Make sure the unlocks are correct
|
# Make sure the unlocks are correct
|
||||||
func init_unlocks() -> void:
|
func init_unlocks() -> void:
|
||||||
if not unlocks:
|
if not unlocks:
|
||||||
@@ -73,6 +74,7 @@ func look_and_learn_completed(lesson_number: int) -> bool:
|
|||||||
unlocks_changed.emit()
|
unlocks_changed.emit()
|
||||||
return true
|
return true
|
||||||
|
|
||||||
|
|
||||||
# Return true if the progression is saved or false if the game was already completed
|
# Return true if the progression is saved or false if the game was already completed
|
||||||
func game_completed(lesson_number: int, game_number: int) -> bool:
|
func game_completed(lesson_number: int, game_number: int) -> bool:
|
||||||
# If the game is already completed, do nothing
|
# If the game is already completed, do nothing
|
||||||
|
|||||||
@@ -1,28 +1,28 @@
|
|||||||
extends Resource
|
|
||||||
class_name TeacherSettings
|
class_name TeacherSettings
|
||||||
|
extends Resource
|
||||||
const AVAILABLE_CODES: Array[int] = [123, 124, 125, 126, 132, 134, 135, 136, 142, 143, 145, 146, 152, 153, 154, 213, 214, 215, 216, 231, 234, 235, 236, 241, 243, 245, 246, 251, 253, 254, 321, 324, 325, 326, 312, 314, 315, 316, 342, 341, 345, 346, 352, 351, 354, 423, 421, 425, 426, 432, 431, 435, 436, 412, 413, 415, 416, 452, 453, 451, 523, 524, 521, 526, 532, 534, 531, 536, 542, 543, 541, 546, 512, 513, 514, 623, 624, 625, 621, 632, 634, 635, 631, 642, 643, 645, 641, 652, 653, 654]
|
|
||||||
|
|
||||||
|
|
||||||
enum AccountType {
|
enum AccountType {
|
||||||
Teacher,
|
Teacher,
|
||||||
Parent
|
Parent
|
||||||
}
|
}
|
||||||
|
|
||||||
enum EducationMethod {
|
enum EducationMethod {
|
||||||
AppOnly,
|
AppOnly,
|
||||||
Complete
|
Complete
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const AVAILABLE_CODES: Array[int] = [123, 124, 125, 126, 132, 134, 135, 136, 142, 143, 145, 146, 152, 153, 154, 213, 214, 215, 216, 231, 234, 235, 236, 241, 243, 245, 246, 251, 253, 254, 321, 324, 325, 326, 312, 314, 315, 316, 342, 341, 345, 346, 352, 351, 354, 423, 421, 425, 426, 432, 431, 435, 436, 412, 413, 415, 416, 452, 453, 451, 523, 524, 521, 526, 532, 534, 531, 536, 542, 543, 541, 546, 512, 513, 514, 623, 624, 625, 621, 632, 634, 635, 631, 642, 643, 645, 641, 652, 653, 654]
|
||||||
|
|
||||||
@export var account_type: AccountType
|
@export var account_type: AccountType
|
||||||
@export var education_method: EducationMethod
|
@export var education_method: EducationMethod
|
||||||
var devices_count: int
|
|
||||||
@export var students: Dictionary[int, Array] = {} # int (device): Array[StudentData]
|
@export var students: Dictionary[int, Array] = {} # int (device): Array[StudentData]
|
||||||
@export var email: String
|
@export var email: String
|
||||||
var password: String
|
|
||||||
@export var token: String
|
@export var token: String
|
||||||
@export var last_modified: String = ""
|
@export var last_modified: String = ""
|
||||||
|
|
||||||
|
var devices_count: int
|
||||||
|
var password: String
|
||||||
|
|
||||||
|
|
||||||
func update_from_dict(dict: Dictionary) -> void:
|
func update_from_dict(dict: Dictionary) -> void:
|
||||||
if dict.has("account_type"):
|
if dict.has("account_type"):
|
||||||
account_type = dict.account_type
|
account_type = dict.account_type
|
||||||
@@ -104,6 +104,7 @@ func get_new_code() -> int:
|
|||||||
var code: int = codes.pick_random()
|
var code: int = codes.pick_random()
|
||||||
return code
|
return code
|
||||||
|
|
||||||
|
|
||||||
func to_dict() -> Dictionary:
|
func to_dict() -> Dictionary:
|
||||||
var dict: Dictionary = {
|
var dict: Dictionary = {
|
||||||
"account_type": account_type,
|
"account_type": account_type,
|
||||||
@@ -122,6 +123,7 @@ func to_dict() -> Dictionary:
|
|||||||
|
|
||||||
return dict
|
return dict
|
||||||
|
|
||||||
|
|
||||||
func get_number_of_students() -> int:
|
func get_number_of_students() -> int:
|
||||||
if not students:
|
if not students:
|
||||||
return 0
|
return 0
|
||||||
@@ -130,12 +132,14 @@ func get_number_of_students() -> int:
|
|||||||
result += data.size()
|
result += data.size()
|
||||||
return result
|
return result
|
||||||
|
|
||||||
|
|
||||||
func get_all_students_data() -> Array[StudentData]:
|
func get_all_students_data() -> Array[StudentData]:
|
||||||
var result: Array[StudentData] = []
|
var result: Array[StudentData] = []
|
||||||
for data: Array[StudentData] in students.values():
|
for data: Array[StudentData] in students.values():
|
||||||
result.append_array(data)
|
result.append_array(data)
|
||||||
return result
|
return result
|
||||||
|
|
||||||
|
|
||||||
func delete_student(student_code: int) -> void:
|
func delete_student(student_code: int) -> void:
|
||||||
for device: int in students.keys():
|
for device: int in students.keys():
|
||||||
for index: int in range(students[device].size()):
|
for index: int in range(students[device].size()):
|
||||||
@@ -146,12 +150,14 @@ func delete_student(student_code: int) -> void:
|
|||||||
return
|
return
|
||||||
Logger.warn("TeacherSettings: Trying to delete student, but code %d not found" % student_code)
|
Logger.warn("TeacherSettings: Trying to delete student, but code %d not found" % student_code)
|
||||||
|
|
||||||
|
|
||||||
func get_student_with_code(student_code: int) -> StudentData:
|
func get_student_with_code(student_code: int) -> StudentData:
|
||||||
for student_data: StudentData in get_all_students_data():
|
for student_data: StudentData in get_all_students_data():
|
||||||
if student_data.code == student_code:
|
if student_data.code == student_code:
|
||||||
return student_data
|
return student_data
|
||||||
return null
|
return null
|
||||||
|
|
||||||
|
|
||||||
func get_student_device(student_code: int) -> int:
|
func get_student_device(student_code: int) -> int:
|
||||||
for device: int in students.keys():
|
for device: int in students.keys():
|
||||||
for index: int in range(students[device].size()):
|
for index: int in range(students[device].size()):
|
||||||
@@ -159,6 +165,7 @@ func get_student_device(student_code: int) -> int:
|
|||||||
return device
|
return device
|
||||||
return -1
|
return -1
|
||||||
|
|
||||||
|
|
||||||
func set_data_student_with_code(student_code: int, new_device_id: int, new_name: String, new_age: int, new_last_modified: String) -> void:
|
func set_data_student_with_code(student_code: int, new_device_id: int, new_name: String, new_age: int, new_last_modified: String) -> void:
|
||||||
update_student_device(student_code, new_device_id)
|
update_student_device(student_code, new_device_id)
|
||||||
for student_data: StudentData in students[new_device_id]:
|
for student_data: StudentData in students[new_device_id]:
|
||||||
|
|||||||
@@ -39,11 +39,9 @@ func append_and_trim(target: Dictionary[int, PackedInt32Array], expected_id: int
|
|||||||
|
|
||||||
# Key is the ID of the expected answer
|
# Key is the ID of the expected answer
|
||||||
# Value is a PackedInt32Array whose entries are the IDs of the answers
|
# Value is a PackedInt32Array whose entries are the IDs of the answers
|
||||||
@export
|
@export var gp_scores: Dictionary[int, PackedInt32Array] = {}
|
||||||
var gp_scores: Dictionary[int, PackedInt32Array] = {}
|
@export var gp_last_modified: String = ""
|
||||||
|
|
||||||
@export
|
|
||||||
var gp_last_modified: String = ""
|
|
||||||
|
|
||||||
# Gets (a copy of) the data of a GP
|
# Gets (a copy of) the data of a GP
|
||||||
func get_gp_scores(id: int) -> PackedInt32Array:
|
func get_gp_scores(id: int) -> PackedInt32Array:
|
||||||
@@ -52,6 +50,7 @@ func get_gp_scores(id: int) -> PackedInt32Array:
|
|||||||
return PackedInt32Array(gp_scores[id])
|
return PackedInt32Array(gp_scores[id])
|
||||||
return PackedInt32Array()
|
return PackedInt32Array()
|
||||||
|
|
||||||
|
|
||||||
# Updates the confusion matrix from a minigame scores
|
# Updates the confusion matrix from a minigame scores
|
||||||
func update_gp_scores(minigame_scores: Dictionary[int, PackedInt32Array]) -> void:
|
func update_gp_scores(minigame_scores: Dictionary[int, PackedInt32Array]) -> void:
|
||||||
if not minigame_scores or minigame_scores.is_empty():
|
if not minigame_scores or minigame_scores.is_empty():
|
||||||
@@ -63,6 +62,7 @@ func update_gp_scores(minigame_scores: Dictionary[int, PackedInt32Array]) -> voi
|
|||||||
set_gp_last_modified(Time.get_datetime_string_from_system(true))
|
set_gp_last_modified(Time.get_datetime_string_from_system(true))
|
||||||
score_changed.emit()
|
score_changed.emit()
|
||||||
|
|
||||||
|
|
||||||
func set_gp_scores(new_scores: Dictionary[int, PackedInt32Array]) -> void:
|
func set_gp_scores(new_scores: Dictionary[int, PackedInt32Array]) -> void:
|
||||||
var cleaned: Dictionary[int, PackedInt32Array] = {}
|
var cleaned: Dictionary[int, PackedInt32Array] = {}
|
||||||
for expected_id: int in new_scores.keys():
|
for expected_id: int in new_scores.keys():
|
||||||
@@ -71,6 +71,7 @@ func set_gp_scores(new_scores: Dictionary[int, PackedInt32Array]) -> void:
|
|||||||
gp_scores = cleaned
|
gp_scores = cleaned
|
||||||
set_gp_last_modified(Time.get_datetime_string_from_system(true))
|
set_gp_last_modified(Time.get_datetime_string_from_system(true))
|
||||||
|
|
||||||
|
|
||||||
func set_gp_last_modified(new_date: String) -> void:
|
func set_gp_last_modified(new_date: String) -> void:
|
||||||
gp_last_modified = new_date
|
gp_last_modified = new_date
|
||||||
|
|
||||||
|
|||||||
@@ -1,13 +1,12 @@
|
|||||||
extends Resource
|
|
||||||
class_name UserDifficulty
|
class_name UserDifficulty
|
||||||
|
extends Resource
|
||||||
|
|
||||||
signal difficulty_changed()
|
signal difficulty_changed()
|
||||||
|
|
||||||
# Stores the user history for all the minigames
|
# Stores the user history for all the minigames
|
||||||
# Key -> minigame_name: String
|
# Key -> minigame_name: String
|
||||||
# Value -> UserMinigameHistory
|
# Value -> UserMinigameHistory
|
||||||
@export
|
@export var minigames_histories: Dictionary = {}
|
||||||
var minigames_histories: Dictionary = {}
|
|
||||||
|
|
||||||
|
|
||||||
# Gets the difficulty of the user for the given minigame
|
# Gets the difficulty of the user for the given minigame
|
||||||
|
|||||||
@@ -1,19 +1,16 @@
|
|||||||
extends Resource
|
|
||||||
class_name UserMinigameHistory
|
class_name UserMinigameHistory
|
||||||
|
extends Resource
|
||||||
|
|
||||||
const MIN_DIFFICULTY: int = 0
|
const MIN_DIFFICULTY: int = 0
|
||||||
const MAX_DIFFICULTY: int = 4
|
const MAX_DIFFICULTY: int = 4
|
||||||
const CONSECUTIVE_WINS_TO_PROMOTE: int = 2
|
const CONSECUTIVE_WINS_TO_PROMOTE: int = 2
|
||||||
const CONSECUTIVE_LOSSES_TO_DEMOTE: int = 2
|
const CONSECUTIVE_LOSSES_TO_DEMOTE: int = 2
|
||||||
|
|
||||||
@export
|
@export var difficulty: int = 0
|
||||||
var difficulty: int = 0
|
@export var consecutives_losses: int = 0
|
||||||
@export
|
@export var consecutives_wins: int = 0
|
||||||
var consecutives_losses: int = 0
|
@export var history: Array[bool] = []
|
||||||
@export
|
|
||||||
var consecutives_wins: int = 0
|
|
||||||
@export
|
|
||||||
var history: Array[bool] = []
|
|
||||||
|
|
||||||
func add_game(is_won: bool) -> void:
|
func add_game(is_won: bool) -> void:
|
||||||
history.append(is_won)
|
history.append(is_won)
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
class_name UserRemediation
|
class_name UserRemediation
|
||||||
extends Resource
|
extends Resource
|
||||||
|
|
||||||
## A remediation score indicates how much extra practice an item needs.
|
## A remediation score indicates how much extra practice an item needs.
|
||||||
## It is a cumulative value that becomes more negative when the student struggles
|
## It is a cumulative value that becomes more negative when the student struggles
|
||||||
## and rises back toward 0 as they succeed. Items at or below a defined
|
## and rises back toward 0 as they succeed. Items at or below a defined
|
||||||
@@ -19,11 +18,9 @@ const REMEDIATION_SCORE: int = -2
|
|||||||
|
|
||||||
# Key is the ID of the GP
|
# Key is the ID of the GP
|
||||||
# Value is the score of the GP
|
# Value is the score of the GP
|
||||||
@export
|
@export var gps_scores: Dictionary[int, int] = {}
|
||||||
var gps_scores: Dictionary[int, int] = {}
|
@export var gp_last_modified: String = ""
|
||||||
|
|
||||||
@export
|
|
||||||
var gp_last_modified: String = ""
|
|
||||||
|
|
||||||
# Gets the score of a GP if it is below or equals to the remediation score
|
# Gets the score of a GP if it is below or equals to the remediation score
|
||||||
func get_gp_score(id: int) -> int:
|
func get_gp_score(id: int) -> int:
|
||||||
@@ -31,6 +28,7 @@ func get_gp_score(id: int) -> int:
|
|||||||
return gps_scores[id] if gps_scores[id] <= REMEDIATION_SCORE else 0
|
return gps_scores[id] if gps_scores[id] <= REMEDIATION_SCORE else 0
|
||||||
return 0
|
return 0
|
||||||
|
|
||||||
|
|
||||||
# Updates the gp scores from a minigame scores
|
# Updates the gp scores from a minigame scores
|
||||||
func update_gp_scores(minigame_scores: Dictionary) -> void:
|
func update_gp_scores(minigame_scores: Dictionary) -> void:
|
||||||
if not minigame_scores:
|
if not minigame_scores:
|
||||||
@@ -47,9 +45,11 @@ func update_gp_scores(minigame_scores: Dictionary) -> void:
|
|||||||
set_gp_last_modified(Time.get_datetime_string_from_system(true))
|
set_gp_last_modified(Time.get_datetime_string_from_system(true))
|
||||||
score_changed.emit()
|
score_changed.emit()
|
||||||
|
|
||||||
|
|
||||||
func set_gp_scores(new_scores: Dictionary[int, int]) -> void:
|
func set_gp_scores(new_scores: Dictionary[int, int]) -> void:
|
||||||
gps_scores = new_scores
|
gps_scores = new_scores
|
||||||
|
|
||||||
|
|
||||||
func set_gp_last_modified(new_date: String) -> void:
|
func set_gp_last_modified(new_date: String) -> void:
|
||||||
gp_last_modified = new_date
|
gp_last_modified = new_date
|
||||||
|
|
||||||
@@ -59,11 +59,9 @@ func set_gp_last_modified(new_date: String) -> void:
|
|||||||
|
|
||||||
# Key is the ID of the syllable
|
# Key is the ID of the syllable
|
||||||
# Value is the score of the syllable
|
# Value is the score of the syllable
|
||||||
@export
|
@export var syllables_scores: Dictionary[int, int] = {}
|
||||||
var syllables_scores: Dictionary[int, int] = {}
|
@export var syllables_last_modified: String = ""
|
||||||
|
|
||||||
@export
|
|
||||||
var syllables_last_modified: String = ""
|
|
||||||
|
|
||||||
# Gets the score of a syllable if it is below or equals to the remediation score
|
# Gets the score of a syllable if it is below or equals to the remediation score
|
||||||
func get_syllable_score(id: int) -> int:
|
func get_syllable_score(id: int) -> int:
|
||||||
@@ -71,6 +69,7 @@ func get_syllable_score(id: int) -> int:
|
|||||||
return syllables_scores[id] if syllables_scores[id] <= REMEDIATION_SCORE else 0
|
return syllables_scores[id] if syllables_scores[id] <= REMEDIATION_SCORE else 0
|
||||||
return 0
|
return 0
|
||||||
|
|
||||||
|
|
||||||
# Updates the syllables scores from a minigame scores
|
# Updates the syllables scores from a minigame scores
|
||||||
func update_syllables_scores(minigame_scores: Dictionary) -> void:
|
func update_syllables_scores(minigame_scores: Dictionary) -> void:
|
||||||
if not minigame_scores:
|
if not minigame_scores:
|
||||||
@@ -87,9 +86,11 @@ func update_syllables_scores(minigame_scores: Dictionary) -> void:
|
|||||||
set_syllables_last_modified(Time.get_datetime_string_from_system(true))
|
set_syllables_last_modified(Time.get_datetime_string_from_system(true))
|
||||||
score_changed.emit()
|
score_changed.emit()
|
||||||
|
|
||||||
|
|
||||||
func set_syllables_scores(new_scores: Dictionary[int, int]) -> void:
|
func set_syllables_scores(new_scores: Dictionary[int, int]) -> void:
|
||||||
syllables_scores = new_scores
|
syllables_scores = new_scores
|
||||||
|
|
||||||
|
|
||||||
func set_syllables_last_modified(new_date: String) -> void:
|
func set_syllables_last_modified(new_date: String) -> void:
|
||||||
syllables_last_modified = new_date
|
syllables_last_modified = new_date
|
||||||
|
|
||||||
@@ -99,11 +100,9 @@ func set_syllables_last_modified(new_date: String) -> void:
|
|||||||
|
|
||||||
# Key is the ID of the word
|
# Key is the ID of the word
|
||||||
# Value is the score of the word
|
# Value is the score of the word
|
||||||
@export
|
@export var words_scores: Dictionary[int, int] = {}
|
||||||
var words_scores: Dictionary[int, int] = {}
|
@export var words_last_modified: String = ""
|
||||||
|
|
||||||
@export
|
|
||||||
var words_last_modified: String = ""
|
|
||||||
|
|
||||||
# Gets the score of a word if it is below or equals to the remediation score
|
# Gets the score of a word if it is below or equals to the remediation score
|
||||||
func get_word_score(id: int) -> int:
|
func get_word_score(id: int) -> int:
|
||||||
@@ -111,6 +110,7 @@ func get_word_score(id: int) -> int:
|
|||||||
return words_scores[id] if words_scores[id] <= REMEDIATION_SCORE else 0
|
return words_scores[id] if words_scores[id] <= REMEDIATION_SCORE else 0
|
||||||
return 0
|
return 0
|
||||||
|
|
||||||
|
|
||||||
# Updates the words scores from a minigame scores
|
# Updates the words scores from a minigame scores
|
||||||
func update_words_scores(minigame_scores: Dictionary) -> void:
|
func update_words_scores(minigame_scores: Dictionary) -> void:
|
||||||
if not minigame_scores:
|
if not minigame_scores:
|
||||||
@@ -127,9 +127,11 @@ func update_words_scores(minigame_scores: Dictionary) -> void:
|
|||||||
set_words_last_modified(Time.get_datetime_string_from_system(true))
|
set_words_last_modified(Time.get_datetime_string_from_system(true))
|
||||||
score_changed.emit()
|
score_changed.emit()
|
||||||
|
|
||||||
|
|
||||||
func set_words_scores(new_scores: Dictionary[int, int]) -> void:
|
func set_words_scores(new_scores: Dictionary[int, int]) -> void:
|
||||||
words_scores = new_scores
|
words_scores = new_scores
|
||||||
|
|
||||||
|
|
||||||
func set_words_last_modified(new_date: String) -> void:
|
func set_words_last_modified(new_date: String) -> void:
|
||||||
words_last_modified = new_date
|
words_last_modified = new_date
|
||||||
|
|
||||||
|
|||||||
@@ -1,15 +1,17 @@
|
|||||||
extends Resource
|
|
||||||
class_name UserSpeeches
|
class_name UserSpeeches
|
||||||
|
extends Resource
|
||||||
|
|
||||||
signal speeches_changed
|
signal speeches_changed()
|
||||||
|
|
||||||
# Contains the list of speeches already played
|
# Contains the list of speeches already played
|
||||||
@export var speeches_played: Array[String] = []
|
@export var speeches_played: Array[String] = []
|
||||||
|
|
||||||
|
|
||||||
func add_speech(speech: String) -> void:
|
func add_speech(speech: String) -> void:
|
||||||
if not speeches_played.has(speech):
|
if not speeches_played.has(speech):
|
||||||
speeches_played.append(speech)
|
speeches_played.append(speech)
|
||||||
speeches_changed.emit()
|
speeches_changed.emit()
|
||||||
|
|
||||||
|
|
||||||
func is_speech_played(speech: String) -> bool:
|
func is_speech_played(speech: String) -> bool:
|
||||||
return speeches_played.has(speech)
|
return speeches_played.has(speech)
|
||||||
|
|||||||
@@ -22,13 +22,20 @@ extends _BASE_
|
|||||||
## and any further detail.
|
## and any further detail.
|
||||||
|
|
||||||
#05. signals
|
#05. signals
|
||||||
|
|
||||||
#06. enums
|
#06. enums
|
||||||
|
|
||||||
#07. constants
|
#07. constants
|
||||||
|
|
||||||
#08. static variables
|
#08. static variables
|
||||||
|
|
||||||
#09. @export variables
|
#09. @export variables
|
||||||
|
|
||||||
#10. remaning regular variables
|
#10. remaning regular variables
|
||||||
|
|
||||||
#11. @onready variables
|
#11. @onready variables
|
||||||
|
|
||||||
|
|
||||||
#12. static_init
|
#12. static_init
|
||||||
# Called automatically when the class is loaded, after the static variables have been initialized
|
# Called automatically when the class is loaded, after the static variables have been initialized
|
||||||
static func _static_init():
|
static func _static_init():
|
||||||
@@ -38,6 +45,8 @@ static func _static_init():
|
|||||||
|
|
||||||
|
|
||||||
#13. remaining static methods
|
#13. remaining static methods
|
||||||
|
|
||||||
|
|
||||||
#14-1. overridden built-in virtual methods:
|
#14-1. overridden built-in virtual methods:
|
||||||
# Called upon creating the object in memory.
|
# Called upon creating the object in memory.
|
||||||
func _init():
|
func _init():
|
||||||
@@ -66,6 +75,11 @@ func _physics_process(float) -> void:
|
|||||||
|
|
||||||
#14-2. remaining virtual methods
|
#14-2. remaining virtual methods
|
||||||
|
|
||||||
|
|
||||||
#15. overridden custom methods
|
#15. overridden custom methods
|
||||||
|
|
||||||
|
|
||||||
#16. remaining methods
|
#16. remaining methods
|
||||||
|
|
||||||
|
|
||||||
#17. subclasses
|
#17. subclasses
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
extends Control
|
|
||||||
class_name FlowerVFX
|
class_name FlowerVFX
|
||||||
|
extends Control
|
||||||
|
|
||||||
@export var sounds: Array[AudioStream] = []
|
@export var sounds: Array[AudioStream] = []
|
||||||
|
|
||||||
@@ -8,9 +8,9 @@ class_name FlowerVFX
|
|||||||
$Particles2,
|
$Particles2,
|
||||||
$Particles3
|
$Particles3
|
||||||
]
|
]
|
||||||
|
|
||||||
@onready var audio_stream_player: AudioStreamPlayer2D = $AudioStreamPlayer2D
|
@onready var audio_stream_player: AudioStreamPlayer2D = $AudioStreamPlayer2D
|
||||||
|
|
||||||
|
|
||||||
func play() -> void:
|
func play() -> void:
|
||||||
audio_stream_player.stream = sounds.pick_random()
|
audio_stream_player.stream = sounds.pick_random()
|
||||||
audio_stream_player.play()
|
audio_stream_player.play()
|
||||||
|
|||||||
+15
-23
@@ -1,30 +1,39 @@
|
|||||||
extends Control
|
|
||||||
class_name Gardens
|
class_name Gardens
|
||||||
|
extends Control
|
||||||
|
|
||||||
signal minigame_layout_opened()
|
signal minigame_layout_opened()
|
||||||
|
|
||||||
# Namespace
|
|
||||||
const KALULU := preload("res://sources/minigames/base/kalulu.gd")
|
const KALULU := preload("res://sources/minigames/base/kalulu.gd")
|
||||||
|
|
||||||
const GARDEN_SCENE: PackedScene = preload("res://resources/gardens/garden.tscn")
|
const GARDEN_SCENE: PackedScene = preload("res://resources/gardens/garden.tscn")
|
||||||
const LOOK_AND_LEARN_SCENE: PackedScene = preload("res://sources/look_and_learn/look_and_learn.tscn")
|
const LOOK_AND_LEARN_SCENE: PackedScene = preload("res://sources/look_and_learn/look_and_learn.tscn")
|
||||||
const FLOWER_FVX: PackedScene = preload("res://sources/gardens/flower_particle.tscn")
|
const FLOWER_FVX: PackedScene = preload("res://sources/gardens/flower_particle.tscn")
|
||||||
|
|
||||||
const GARDEN_SIZE: int = 2400
|
const GARDEN_SIZE: int = 2400
|
||||||
|
|
||||||
|
static var transition_data: Dictionary = {}
|
||||||
|
|
||||||
@export_category("Layout")
|
@export_category("Layout")
|
||||||
@export var gardens_layout: GardensLayout:
|
@export var gardens_layout: GardensLayout:
|
||||||
set = set_gardens_layout
|
set = set_gardens_layout
|
||||||
@export var starting_garden: int = -1
|
@export var starting_garden: int = -1
|
||||||
|
|
||||||
@export_category("Colors")
|
@export_category("Colors")
|
||||||
@export var unlocked_color: Color = Color("1c2662") #blue
|
@export var unlocked_color: Color = Color("1c2662") #blue
|
||||||
@export var locked_color: Color = Color("1d2229") #black
|
@export var locked_color: Color = Color("1d2229") #black
|
||||||
|
|
||||||
@export_group("Minigames")
|
@export_group("Minigames")
|
||||||
@export var minigames_scenes: Array[PackedScene] = []
|
@export var minigames_scenes: Array[PackedScene] = []
|
||||||
@export var minigames_icons: Array[Texture] = []
|
@export var minigames_icons: Array[Texture] = []
|
||||||
|
|
||||||
|
var lessons: Dictionary = {}
|
||||||
|
var points: Array[Array] = []
|
||||||
|
var is_scrolling: bool = false
|
||||||
|
var scroll_beginning_garden: int = 0
|
||||||
|
var scroll_tween: Tween
|
||||||
|
var is_locked: bool = false
|
||||||
|
var in_minigame_selection: bool = false
|
||||||
|
var current_lesson_number: int = -1
|
||||||
|
var current_garden: Garden
|
||||||
|
var current_button_global_position: Vector2 = Vector2.ZERO
|
||||||
|
var current_button: LessonButton
|
||||||
|
|
||||||
@onready var garden_parent: HBoxContainer = %GardenParent
|
@onready var garden_parent: HBoxContainer = %GardenParent
|
||||||
@onready var locked_line: Line2D = $ScrollContainer/LockedLine
|
@onready var locked_line: Line2D = $ScrollContainer/LockedLine
|
||||||
@onready var unlocked_line: Line2D = $ScrollContainer/UnlockedLine
|
@onready var unlocked_line: Line2D = $ScrollContainer/UnlockedLine
|
||||||
@@ -48,26 +57,10 @@ const GARDEN_SIZE: int = 2400
|
|||||||
@onready var lock: Control = %Lock
|
@onready var lock: Control = %Lock
|
||||||
@onready var kalulu: KALULU = %Kalulu
|
@onready var kalulu: KALULU = %Kalulu
|
||||||
@onready var kalulu_button: CanvasItem = %KaluluButton
|
@onready var kalulu_button: CanvasItem = %KaluluButton
|
||||||
|
|
||||||
@onready var intro_speech: AudioStreamMP3 = Database.load_external_sound(Database.get_kalulu_speech_path("gardens_screen", "intro"))
|
@onready var intro_speech: AudioStreamMP3 = Database.load_external_sound(Database.get_kalulu_speech_path("gardens_screen", "intro"))
|
||||||
@onready var help_few_plants_speech: AudioStreamMP3 = Database.load_external_sound(Database.get_kalulu_speech_path("gardens_screen", "help_few_plants"))
|
@onready var help_few_plants_speech: AudioStreamMP3 = Database.load_external_sound(Database.get_kalulu_speech_path("gardens_screen", "help_few_plants"))
|
||||||
@onready var help_many_plants_speech: AudioStreamMP3 = Database.load_external_sound(Database.get_kalulu_speech_path("gardens_screen", "help_many_plants"))
|
@onready var help_many_plants_speech: AudioStreamMP3 = Database.load_external_sound(Database.get_kalulu_speech_path("gardens_screen", "help_many_plants"))
|
||||||
|
|
||||||
var lessons: Dictionary = {}
|
|
||||||
var points: Array[Array] = []
|
|
||||||
var is_scrolling: bool = false
|
|
||||||
var scroll_beginning_garden: int = 0
|
|
||||||
var scroll_tween: Tween
|
|
||||||
var is_locked: bool = false
|
|
||||||
|
|
||||||
var in_minigame_selection: bool = false
|
|
||||||
var current_lesson_number: int = -1
|
|
||||||
var current_garden: Garden
|
|
||||||
var current_button_global_position: Vector2 = Vector2.ZERO
|
|
||||||
var current_button: LessonButton
|
|
||||||
|
|
||||||
static var transition_data: Dictionary = {}
|
|
||||||
|
|
||||||
|
|
||||||
func _ready() -> void:
|
func _ready() -> void:
|
||||||
|
|
||||||
@@ -382,7 +375,6 @@ func _ready() -> void:
|
|||||||
await kalulu.play_kalulu_speech(intro_speech)
|
await kalulu.play_kalulu_speech(intro_speech)
|
||||||
kalulu_button.show()
|
kalulu_button.show()
|
||||||
UserDataManager.mark_speech_as_played("gardens")
|
UserDataManager.mark_speech_as_played("gardens")
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
static func compute_lessons_distribution(total_lessons: int, garden_layouts: Array[GardenLayout]) -> Array[int]:
|
static func compute_lessons_distribution(total_lessons: int, garden_layouts: Array[GardenLayout]) -> Array[int]:
|
||||||
|
|||||||
@@ -5,7 +5,6 @@ const GARDEN_TEXTURES_NB: int = 20
|
|||||||
const FLOWER_TYPES_NB: int = 5
|
const FLOWER_TYPES_NB: int = 5
|
||||||
const GARDENS_LAYOUT_RESOURCE_PATH: String = "res://resources/gardens/gardens_layout.tres"
|
const GARDENS_LAYOUT_RESOURCE_PATH: String = "res://resources/gardens/gardens_layout.tres"
|
||||||
|
|
||||||
|
|
||||||
var dragging_element: Variant
|
var dragging_element: Variant
|
||||||
var drag_data: Dictionary = {}
|
var drag_data: Dictionary = {}
|
||||||
|
|
||||||
|
|||||||
@@ -1,20 +1,23 @@
|
|||||||
extends TextureRect
|
|
||||||
class_name MinigameLayout
|
class_name MinigameLayout
|
||||||
|
extends TextureRect
|
||||||
|
|
||||||
signal pressed()
|
signal pressed()
|
||||||
|
|
||||||
|
var is_disabled: bool = false
|
||||||
|
|
||||||
@onready var icon: TextureRect = $TextureRect
|
@onready var icon: TextureRect = $TextureRect
|
||||||
@onready var area: Area2D = $Area2D
|
@onready var area: Area2D = $Area2D
|
||||||
@onready var right_fx: RightFX = $TextureRect/RightFX
|
@onready var right_fx: RightFX = $TextureRect/RightFX
|
||||||
|
|
||||||
var is_disabled: bool = false
|
|
||||||
|
|
||||||
func _ready() -> void:
|
func _ready() -> void:
|
||||||
area.connect("input_event", _on_click)
|
area.connect("input_event", _on_click)
|
||||||
|
|
||||||
|
|
||||||
func _on_click(_viewport: Node, event: InputEvent, _shape_idx: int) -> void:
|
func _on_click(_viewport: Node, event: InputEvent, _shape_idx: int) -> void:
|
||||||
if event.is_action_pressed("left_click") and not is_disabled:
|
if event.is_action_pressed("left_click") and not is_disabled:
|
||||||
pressed.emit()
|
pressed.emit()
|
||||||
|
|
||||||
|
|
||||||
func right() -> void:
|
func right() -> void:
|
||||||
right_fx.play()
|
right_fx.play()
|
||||||
|
|||||||
+1
-2
@@ -1,12 +1,11 @@
|
|||||||
extends AnimatedSprite2D
|
extends AnimatedSprite2D
|
||||||
|
|
||||||
|
|
||||||
func _on_animation_finished() -> void:
|
func _on_animation_finished() -> void:
|
||||||
|
|
||||||
if animation in ["Hide", "Show"]:
|
if animation in ["Hide", "Show"]:
|
||||||
return
|
return
|
||||||
|
|
||||||
var rand: float = randf()
|
var rand: float = randf()
|
||||||
|
|
||||||
match animation:
|
match animation:
|
||||||
"Idle1", "Idle2":
|
"Idle1", "Idle2":
|
||||||
if rand < 0.5:
|
if rand < 0.5:
|
||||||
|
|||||||
@@ -2,10 +2,10 @@ extends Control
|
|||||||
|
|
||||||
const ELEMENT_SCENE: PackedScene = preload("res://sources/language_tool/fish_word_list_element.tscn")
|
const ELEMENT_SCENE: PackedScene = preload("res://sources/language_tool/fish_word_list_element.tscn")
|
||||||
|
|
||||||
@onready var elements_container: VBoxContainer = %ElementsContainer
|
|
||||||
|
|
||||||
var word_list: Array = []
|
var word_list: Array = []
|
||||||
|
|
||||||
|
@onready var elements_container: VBoxContainer = %ElementsContainer
|
||||||
|
|
||||||
|
|
||||||
func _ready() -> void:
|
func _ready() -> void:
|
||||||
var query: String = "SELECT name FROM sqlite_master WHERE type='table' AND name='Pseudowords'"
|
var query: String = "SELECT name FROM sqlite_master WHERE type='table' AND name='Pseudowords'"
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
extends MarginContainer
|
|
||||||
class_name FishWordListElement
|
class_name FishWordListElement
|
||||||
|
extends MarginContainer
|
||||||
|
|
||||||
@export var word_id: int = 1:
|
@export var word_id: int = 1:
|
||||||
set = set_word_id
|
set = set_word_id
|
||||||
@@ -10,13 +9,13 @@ class_name FishWordListElement
|
|||||||
set = set_lesson_nb
|
set = set_lesson_nb
|
||||||
@export var pseudoword_id: int = -1
|
@export var pseudoword_id: int = -1
|
||||||
|
|
||||||
|
var is_in_line_edit_changed: bool = false
|
||||||
|
var word: String = ""
|
||||||
|
|
||||||
@onready var option_button: OptionButton = %OptionButton
|
@onready var option_button: OptionButton = %OptionButton
|
||||||
@onready var line_edit: LineEdit = %LineEdit
|
@onready var line_edit: LineEdit = %LineEdit
|
||||||
@onready var lesson_label: Label = %LessonLabel
|
@onready var lesson_label: Label = %LessonLabel
|
||||||
|
|
||||||
var is_in_line_edit_changed: bool = false
|
|
||||||
var word: String = ""
|
|
||||||
|
|
||||||
|
|
||||||
func set_word_id(p_word_id: int) -> void:
|
func set_word_id(p_word_id: int) -> void:
|
||||||
word_id = p_word_id
|
word_id = p_word_id
|
||||||
|
|||||||
@@ -1,8 +1,7 @@
|
|||||||
extends Node
|
extends Node
|
||||||
|
## Global data for prof_tool only
|
||||||
|
|
||||||
# For prof_tool only
|
|
||||||
var main_menu_selected_tab: int = 0
|
var main_menu_selected_tab: int = 0
|
||||||
|
|
||||||
var device_colors: Array[Color] = [
|
var device_colors: Array[Color] = [
|
||||||
Color("9670e0"),
|
Color("9670e0"),
|
||||||
Color("ffe823"),
|
Color("ffe823"),
|
||||||
|
|||||||
@@ -1,10 +1,10 @@
|
|||||||
extends Control
|
|
||||||
class_name GPImageAndSoundDescriptions
|
class_name GPImageAndSoundDescriptions
|
||||||
|
extends Control
|
||||||
@onready var description_container: VBoxContainer = %DescriptionsContainer
|
|
||||||
|
|
||||||
const DESCRIPTION_LINE_SCENE: PackedScene = preload("res://sources/language_tool/image_and_sound_gp_description.tscn")
|
const DESCRIPTION_LINE_SCENE: PackedScene = preload("res://sources/language_tool/image_and_sound_gp_description.tscn")
|
||||||
|
|
||||||
|
@onready var description_container: VBoxContainer = %DescriptionsContainer
|
||||||
|
|
||||||
|
|
||||||
func _ready() -> void:
|
func _ready() -> void:
|
||||||
DirAccess.make_dir_recursive_absolute(Database.BASE_PATH + Database.language + Database.LOOK_AND_LEARN_IMAGES)
|
DirAccess.make_dir_recursive_absolute(Database.BASE_PATH + Database.language + Database.LOOK_AND_LEARN_IMAGES)
|
||||||
|
|||||||
@@ -1,12 +1,11 @@
|
|||||||
extends Control
|
extends Control
|
||||||
|
|
||||||
|
var undo_redo: UndoRedo = UndoRedo.new()
|
||||||
var element_scene: PackedScene = preload("res://sources/language_tool/gp_list_element.tscn")
|
var element_scene: PackedScene = preload("res://sources/language_tool/gp_list_element.tscn")
|
||||||
|
|
||||||
@onready var elements_container: VBoxContainer = %ElementsContainer
|
@onready var elements_container: VBoxContainer = %ElementsContainer
|
||||||
@onready var error_label: Label = %ErrorLabel
|
@onready var error_label: Label = %ErrorLabel
|
||||||
|
|
||||||
var undo_redo: UndoRedo = UndoRedo.new()
|
|
||||||
|
|
||||||
|
|
||||||
func _ready() -> void:
|
func _ready() -> void:
|
||||||
var query: String = "Select * FROM GPs ORDER BY GPs.Grapheme"
|
var query: String = "Select * FROM GPs ORDER BY GPs.Grapheme"
|
||||||
@@ -79,7 +78,6 @@ func _on_back_button_pressed() -> void:
|
|||||||
get_tree().change_scene_to_file("res://sources/language_tool/prof_tool_menu.tscn")
|
get_tree().change_scene_to_file("res://sources/language_tool/prof_tool_menu.tscn")
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
func _on_grapheme_gui_input(event: InputEvent) -> void:
|
func _on_grapheme_gui_input(event: InputEvent) -> void:
|
||||||
if event.is_action_pressed("left_click"):
|
if event.is_action_pressed("left_click"):
|
||||||
_reorder_by("grapheme")
|
_reorder_by("grapheme")
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
extends OptionButton
|
|
||||||
class_name GPListButton
|
class_name GPListButton
|
||||||
|
extends OptionButton
|
||||||
|
|
||||||
signal gp_selected(id: int)
|
signal gp_selected(id: int)
|
||||||
signal new_selected()
|
signal new_selected()
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
extends MarginContainer
|
|
||||||
class_name GPListElement
|
class_name GPListElement
|
||||||
|
extends MarginContainer
|
||||||
|
|
||||||
signal delete_pressed()
|
signal delete_pressed()
|
||||||
signal validated()
|
signal validated()
|
||||||
@@ -10,18 +10,6 @@ enum Type {
|
|||||||
Consonant,
|
Consonant,
|
||||||
}
|
}
|
||||||
|
|
||||||
@onready var exception_checkbox: CheckBox = %ExceptionCheckBox
|
|
||||||
@onready var exception_edit_checkbox: CheckBox = %ExceptionEditCheckBox
|
|
||||||
@onready var grapheme_label: Label = $%Grapheme
|
|
||||||
@onready var phoneme_label: Label = $%Phoneme
|
|
||||||
@onready var type_label: Label = $%Type
|
|
||||||
@onready var grapheme_edit: LineEdit = $%GraphemeEdit
|
|
||||||
@onready var phoneme_edit: LineEdit = $%PhonemeEdit
|
|
||||||
@onready var type_edit: OptionButton = $%TypeEdit
|
|
||||||
@onready var tab_container: TabContainer = $%TabContainer
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
var grapheme: String = "":
|
var grapheme: String = "":
|
||||||
set = set_grapheme
|
set = set_grapheme
|
||||||
var phoneme: String = "":
|
var phoneme: String = "":
|
||||||
@@ -37,6 +25,16 @@ var undo_redo: UndoRedo:
|
|||||||
undo_redo = UndoRedo.new()
|
undo_redo = UndoRedo.new()
|
||||||
return undo_redo
|
return undo_redo
|
||||||
|
|
||||||
|
@onready var exception_checkbox: CheckBox = %ExceptionCheckBox
|
||||||
|
@onready var exception_edit_checkbox: CheckBox = %ExceptionEditCheckBox
|
||||||
|
@onready var grapheme_label: Label = $%Grapheme
|
||||||
|
@onready var phoneme_label: Label = $%Phoneme
|
||||||
|
@onready var type_label: Label = $%Type
|
||||||
|
@onready var grapheme_edit: LineEdit = $%GraphemeEdit
|
||||||
|
@onready var phoneme_edit: LineEdit = $%PhonemeEdit
|
||||||
|
@onready var type_edit: OptionButton = $%TypeEdit
|
||||||
|
@onready var tab_container: TabContainer = $%TabContainer
|
||||||
|
|
||||||
|
|
||||||
func set_grapheme(p_grapheme: String) -> void:
|
func set_grapheme(p_grapheme: String) -> void:
|
||||||
grapheme = p_grapheme
|
grapheme = p_grapheme
|
||||||
@@ -61,6 +59,7 @@ func set_type(p_type: Type) -> void:
|
|||||||
if type_edit:
|
if type_edit:
|
||||||
type_edit.selected = type
|
type_edit.selected = type
|
||||||
|
|
||||||
|
|
||||||
func set_exception(p_exception: bool) -> void:
|
func set_exception(p_exception: bool) -> void:
|
||||||
exception = p_exception
|
exception = p_exception
|
||||||
if exception_checkbox:
|
if exception_checkbox:
|
||||||
|
|||||||
@@ -4,14 +4,12 @@ signal gp_selected(grapheme_ind: int, gp_id: int, text: String)
|
|||||||
signal focus_changed(has_focus: bool)
|
signal focus_changed(has_focus: bool)
|
||||||
signal new_gp_asked()
|
signal new_gp_asked()
|
||||||
|
|
||||||
@onready var container: VBoxContainer = $VBoxContainer
|
|
||||||
@onready var button: Button = $Button
|
|
||||||
|
|
||||||
|
|
||||||
var grapheme_ind: int = -1
|
var grapheme_ind: int = -1
|
||||||
var ind_selected: int = -1:
|
var ind_selected: int = -1:
|
||||||
set = set_ind_selected
|
set = set_ind_selected
|
||||||
|
|
||||||
|
@onready var container: VBoxContainer = $VBoxContainer
|
||||||
|
@onready var button: Button = $Button
|
||||||
|
|
||||||
|
|
||||||
func _ready() -> void:
|
func _ready() -> void:
|
||||||
|
|||||||
@@ -1,9 +1,9 @@
|
|||||||
extends Control
|
extends Control
|
||||||
|
|
||||||
@onready var description_container: VBoxContainer = %DescriptionsContainer
|
|
||||||
|
|
||||||
const DESCRIPTION_LINE_SCENE: PackedScene = preload("res://sources/language_tool/video_gp_description.tscn")
|
const DESCRIPTION_LINE_SCENE: PackedScene = preload("res://sources/language_tool/video_gp_description.tscn")
|
||||||
|
|
||||||
|
@onready var description_container: VBoxContainer = %DescriptionsContainer
|
||||||
|
|
||||||
|
|
||||||
func _ready() -> void:
|
func _ready() -> void:
|
||||||
var _description_line: VideoGPDescription = DESCRIPTION_LINE_SCENE.instantiate()
|
var _description_line: VideoGPDescription = DESCRIPTION_LINE_SCENE.instantiate()
|
||||||
|
|||||||
@@ -1,7 +1,11 @@
|
|||||||
extends HBoxContainer
|
|
||||||
class_name ImageAndSoundGPDescription
|
class_name ImageAndSoundGPDescription
|
||||||
|
extends HBoxContainer
|
||||||
|
|
||||||
signal delete
|
signal deleted()
|
||||||
|
|
||||||
|
var gp: Dictionary = {}
|
||||||
|
var get_image_path: Callable = Database.get_gp_look_and_learn_image_path
|
||||||
|
var get_sound_path: Callable = Database.get_gp_look_and_learn_sound_path
|
||||||
|
|
||||||
@onready var gp_menu_button: MenuButton = %GPMenuButton
|
@onready var gp_menu_button: MenuButton = %GPMenuButton
|
||||||
@onready var image_preview: TextureRect = %ImagePreview
|
@onready var image_preview: TextureRect = %ImagePreview
|
||||||
@@ -13,10 +17,6 @@ signal delete
|
|||||||
@onready var image_clear_button: MarginContainer = %ImageClearButton
|
@onready var image_clear_button: MarginContainer = %ImageClearButton
|
||||||
@onready var sound_clear_button: MarginContainer = %SoundClearButton
|
@onready var sound_clear_button: MarginContainer = %SoundClearButton
|
||||||
|
|
||||||
var gp: Dictionary = {}
|
|
||||||
var get_image_path: Callable = Database.get_gp_look_and_learn_image_path
|
|
||||||
var get_sound_path: Callable = Database.get_gp_look_and_learn_sound_path
|
|
||||||
|
|
||||||
|
|
||||||
func _image_file_selected(file_path: String) -> void:
|
func _image_file_selected(file_path: String) -> void:
|
||||||
file_dialog.files_selected.connect(_image_file_selected.bind(file_dialog))
|
file_dialog.files_selected.connect(_image_file_selected.bind(file_dialog))
|
||||||
@@ -114,7 +114,7 @@ func _on_sound_upload_button_pressed() -> void:
|
|||||||
|
|
||||||
|
|
||||||
func _on_button_pressed() -> void:
|
func _on_button_pressed() -> void:
|
||||||
delete.emit()
|
deleted.emit()
|
||||||
|
|
||||||
|
|
||||||
func _on_sound_preview_pressed() -> void:
|
func _on_sound_preview_pressed() -> void:
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
extends GPImageAndSoundDescriptions
|
extends GPImageAndSoundDescriptions
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
func _ready() -> void:
|
func _ready() -> void:
|
||||||
DirAccess.make_dir_recursive_absolute(Database.BASE_PATH + Database.language + Database.LANGUAGE_SOUNDS)
|
DirAccess.make_dir_recursive_absolute(Database.BASE_PATH + Database.language + Database.LANGUAGE_SOUNDS)
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
extends PanelContainer
|
|
||||||
class_name KaluluSpeech
|
class_name KaluluSpeech
|
||||||
|
extends PanelContainer
|
||||||
|
|
||||||
@export var speech_category: String
|
@export var speech_category: String
|
||||||
@export var speech_name: String:
|
@export var speech_name: String:
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
extends PanelContainer
|
|
||||||
class_name KaluluTitle
|
class_name KaluluTitle
|
||||||
|
extends PanelContainer
|
||||||
|
|
||||||
@export var title: String = "":
|
@export var title: String = "":
|
||||||
set = _set_title
|
set = _set_title
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
extends Control
|
extends Control
|
||||||
|
|
||||||
|
|
||||||
const TITLE_SCENE: PackedScene = preload("res://sources/language_tool/kalulu_speech_title.tscn")
|
const TITLE_SCENE: PackedScene = preload("res://sources/language_tool/kalulu_speech_title.tscn")
|
||||||
const SPEECH_SCENE: PackedScene = preload("res://sources/language_tool/kalulu_speech.tscn")
|
const SPEECH_SCENE: PackedScene = preload("res://sources/language_tool/kalulu_speech.tscn")
|
||||||
|
|
||||||
|
|||||||
@@ -1,14 +1,12 @@
|
|||||||
extends MarginContainer
|
|
||||||
class_name LessonContainer
|
class_name LessonContainer
|
||||||
|
extends MarginContainer
|
||||||
var gp_label_scene: PackedScene = preload("res://sources/language_tool/lesson_gp_label.tscn")
|
|
||||||
|
|
||||||
signal lesson_dropped(before: bool, number: int, dropped_number: int)
|
signal lesson_dropped(before: bool, number: int, dropped_number: int)
|
||||||
|
|
||||||
|
var gp_label_scene: PackedScene = preload("res://sources/language_tool/lesson_gp_label.tscn")
|
||||||
var number: int = 0:
|
var number: int = 0:
|
||||||
set = set_number
|
set = set_number
|
||||||
|
|
||||||
|
|
||||||
@onready var gp_container: HBoxContainer = $%GPContainer
|
@onready var gp_container: HBoxContainer = $%GPContainer
|
||||||
@onready var number_label: Label = $%NumberLabel
|
@onready var number_label: Label = $%NumberLabel
|
||||||
|
|
||||||
|
|||||||
@@ -1,9 +1,11 @@
|
|||||||
extends PanelContainer
|
|
||||||
class_name LessonExerciseContainer
|
class_name LessonExerciseContainer
|
||||||
|
extends PanelContainer
|
||||||
|
|
||||||
@export var lesson_number: int = -1:
|
@export var lesson_number: int = -1:
|
||||||
set = _set_lesson_number
|
set = _set_lesson_number
|
||||||
|
|
||||||
|
var sentences_by_lesson: Dictionary = {}
|
||||||
|
|
||||||
@onready var lesson_id_label: Label = %LessonIDLabel
|
@onready var lesson_id_label: Label = %LessonIDLabel
|
||||||
@onready var lesson_gps: HBoxContainer = %LessonGPs
|
@onready var lesson_gps: HBoxContainer = %LessonGPs
|
||||||
@onready var exercise_buttons: Array[OptionButton] = [%ExerciseButton1, %ExerciseButton2, %ExerciseButton3]
|
@onready var exercise_buttons: Array[OptionButton] = [%ExerciseButton1, %ExerciseButton2, %ExerciseButton3]
|
||||||
@@ -13,8 +15,6 @@ class_name LessonExerciseContainer
|
|||||||
@onready var number_of_words: Label = %NumberOfWords
|
@onready var number_of_words: Label = %NumberOfWords
|
||||||
@onready var number_of_sentences: Label = %NumberOfSentences
|
@onready var number_of_sentences: Label = %NumberOfSentences
|
||||||
|
|
||||||
var sentences_by_lesson: Dictionary = {}
|
|
||||||
|
|
||||||
|
|
||||||
func _ready() -> void:
|
func _ready() -> void:
|
||||||
Database.db.query("Select * FROM ExerciseTypes")
|
Database.db.query("Select * FROM ExerciseTypes")
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
extends Label
|
|
||||||
class_name LessonGPLabel
|
class_name LessonGPLabel
|
||||||
|
extends Label
|
||||||
|
|
||||||
signal gp_dropped(before: bool, data: Dictionary)
|
signal gp_dropped(before: bool, data: Dictionary)
|
||||||
|
|
||||||
|
|||||||
@@ -1,13 +1,12 @@
|
|||||||
extends Control
|
extends Control
|
||||||
|
|
||||||
@onready var lessons_container: VBoxContainer = $%LessonsContainer
|
|
||||||
@onready var unused_gp_container: GridContainer = $%UnusedGPContainer
|
|
||||||
|
|
||||||
var lesson_container_scene: PackedScene = preload("res://sources/language_tool/lesson_container.tscn")
|
var lesson_container_scene: PackedScene = preload("res://sources/language_tool/lesson_container.tscn")
|
||||||
var gp_label_scene: PackedScene = preload("res://sources/language_tool/lesson_gp_label.tscn")
|
var gp_label_scene: PackedScene = preload("res://sources/language_tool/lesson_gp_label.tscn")
|
||||||
|
|
||||||
var lessons: Dictionary[int, LessonContainer] = {}
|
var lessons: Dictionary[int, LessonContainer] = {}
|
||||||
|
|
||||||
|
@onready var lessons_container: VBoxContainer = $%LessonsContainer
|
||||||
|
@onready var unused_gp_container: GridContainer = $%UnusedGPContainer
|
||||||
|
|
||||||
|
|
||||||
func _ready() -> void:
|
func _ready() -> void:
|
||||||
Database.db.query("Select Grapheme, Phoneme, LessonNb, GPID FROM Lessons
|
Database.db.query("Select Grapheme, Phoneme, LessonNb, GPID FROM Lessons
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
extends MarginContainer
|
|
||||||
class_name ListTitle
|
class_name ListTitle
|
||||||
|
extends MarginContainer
|
||||||
|
|
||||||
signal add_pressed()
|
signal add_pressed()
|
||||||
signal save_pressed()
|
signal save_pressed()
|
||||||
@@ -7,10 +7,11 @@ signal back_pressed()
|
|||||||
signal new_search(new_text: String)
|
signal new_search(new_text: String)
|
||||||
signal import_path_selected(path: String, match_to_file: bool)
|
signal import_path_selected(path: String, match_to_file: bool)
|
||||||
|
|
||||||
|
var my_button: Button
|
||||||
|
|
||||||
@onready var title_label: Label = %TitleLabel
|
@onready var title_label: Label = %TitleLabel
|
||||||
@onready var file_dialog: FileDialog = $FileDialog
|
@onready var file_dialog: FileDialog = $FileDialog
|
||||||
|
|
||||||
var my_button: Button
|
|
||||||
|
|
||||||
func _ready() -> void:
|
func _ready() -> void:
|
||||||
my_button = file_dialog.add_button("Match list to file (delete elements not in file)", true, "act")
|
my_button = file_dialog.add_button("Match list to file (delete elements not in file)", true, "act")
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
extends MarginContainer
|
|
||||||
class_name PlusButton
|
class_name PlusButton
|
||||||
|
extends MarginContainer
|
||||||
|
|
||||||
signal pressed()
|
signal pressed()
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,14 @@
|
|||||||
extends Control
|
extends Control
|
||||||
|
|
||||||
|
enum FileCheckResult {
|
||||||
|
OK,
|
||||||
|
ERROR_NOT_FOUND,
|
||||||
|
ERROR_CASE_MISMATCH
|
||||||
|
}
|
||||||
|
|
||||||
const BASE_PATH: String = "user://language_resources/"
|
const BASE_PATH: String = "user://language_resources/"
|
||||||
const SAVE_FILE_PATH: String = "user://prof_tool_save.tres"
|
const SAVE_FILE_PATH: String = "user://prof_tool_save.tres"
|
||||||
|
|
||||||
var save_file: ProfToolSave
|
var save_file: ProfToolSave
|
||||||
|
|
||||||
@onready var language_select_button: OptionButton = %LanguageSelectButton
|
@onready var language_select_button: OptionButton = %LanguageSelectButton
|
||||||
@@ -140,6 +147,7 @@ var integrity_checking: bool = false
|
|||||||
var integrity_log_path: String = "user://database-integrity-log.txt"
|
var integrity_log_path: String = "user://database-integrity-log.txt"
|
||||||
var total_integrity_warnings: int = 0
|
var total_integrity_warnings: int = 0
|
||||||
|
|
||||||
|
|
||||||
func _check_db_integrity() -> void:
|
func _check_db_integrity() -> void:
|
||||||
if integrity_checking:
|
if integrity_checking:
|
||||||
return
|
return
|
||||||
@@ -258,6 +266,7 @@ func _check_db_integrity() -> void:
|
|||||||
var file_path: String = ProjectSettings.globalize_path(integrity_log_path)
|
var file_path: String = ProjectSettings.globalize_path(integrity_log_path)
|
||||||
Logger.trace("ProfToolMenu: Logs saved at " + file_path)
|
Logger.trace("ProfToolMenu: Logs saved at " + file_path)
|
||||||
OS.shell_open(file_path)
|
OS.shell_open(file_path)
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
func log_message(message: String) -> bool:
|
func log_message(message: String) -> bool:
|
||||||
@@ -281,11 +290,6 @@ func log_message(message: String) -> bool:
|
|||||||
integrity_checking = false
|
integrity_checking = false
|
||||||
return false
|
return false
|
||||||
|
|
||||||
enum FileCheckResult {
|
|
||||||
OK,
|
|
||||||
ERROR_NOT_FOUND,
|
|
||||||
ERROR_CASE_MISMATCH
|
|
||||||
}
|
|
||||||
|
|
||||||
func file_exists_case_sensitive(path: String) -> Dictionary:
|
func file_exists_case_sensitive(path: String) -> Dictionary:
|
||||||
var result: Dictionary = {
|
var result: Dictionary = {
|
||||||
@@ -325,6 +329,7 @@ func file_exists_case_sensitive(path: String) -> Dictionary:
|
|||||||
|
|
||||||
return result
|
return result
|
||||||
|
|
||||||
|
|
||||||
func _get_available_languages() -> Array[String]:
|
func _get_available_languages() -> Array[String]:
|
||||||
var available_languages: Array[String] = []
|
var available_languages: Array[String] = []
|
||||||
var dir: DirAccess = DirAccess.open(BASE_PATH)
|
var dir: DirAccess = DirAccess.open(BASE_PATH)
|
||||||
@@ -523,8 +528,8 @@ func _on_open_folder_button_pressed() -> void:
|
|||||||
func _on_tab_container_tab_changed(tab: int) -> void:
|
func _on_tab_container_tab_changed(tab: int) -> void:
|
||||||
Globals.main_menu_selected_tab = tab
|
Globals.main_menu_selected_tab = tab
|
||||||
|
|
||||||
|
|
||||||
#region Book Generation
|
#region Book Generation
|
||||||
|
|
||||||
func create_book() -> void:
|
func create_book() -> void:
|
||||||
var lang_path: String = BASE_PATH.path_join(Database.language)
|
var lang_path: String = BASE_PATH.path_join(Database.language)
|
||||||
var file_names: Dictionary[String, String] = {
|
var file_names: Dictionary[String, String] = {
|
||||||
@@ -635,6 +640,7 @@ func create_book() -> void:
|
|||||||
error_label.text = "📘 Export data of the booklet finished to path: " + output_path
|
error_label.text = "📘 Export data of the booklet finished to path: " + output_path
|
||||||
Logger.trace("ProfToolMenu: " + error_label.text)
|
Logger.trace("ProfToolMenu: " + error_label.text)
|
||||||
|
|
||||||
|
|
||||||
# Fonction qui ajoute une ligne au dictionnaire
|
# Fonction qui ajoute une ligne au dictionnaire
|
||||||
func add_row(dict: Dictionary[String, PackedStringArray], row_data: Dictionary[String, String], categorie: String, all_headers: Array) -> void:
|
func add_row(dict: Dictionary[String, PackedStringArray], row_data: Dictionary[String, String], categorie: String, all_headers: Array) -> void:
|
||||||
# Nombre de lignes déjà enregistrées (doit être égal pour chaque colonne)
|
# Nombre de lignes déjà enregistrées (doit être égal pour chaque colonne)
|
||||||
@@ -688,6 +694,7 @@ func parse_csv_line(line: String) -> PackedStringArray:
|
|||||||
result.append(current)
|
result.append(current)
|
||||||
return result
|
return result
|
||||||
|
|
||||||
|
|
||||||
# Transforme une ligne pour l'écriture CSV, avec échappement
|
# Transforme une ligne pour l'écriture CSV, avec échappement
|
||||||
func escape_csv_line(fields: PackedStringArray) -> String:
|
func escape_csv_line(fields: PackedStringArray) -> String:
|
||||||
var output: String = ""
|
var output: String = ""
|
||||||
@@ -700,10 +707,12 @@ func escape_csv_line(fields: PackedStringArray) -> String:
|
|||||||
output += ","
|
output += ","
|
||||||
return output
|
return output
|
||||||
|
|
||||||
|
|
||||||
# Normalise les noms de colonnes (ex: writing page -> Writing page)
|
# Normalise les noms de colonnes (ex: writing page -> Writing page)
|
||||||
func normalize_header(header_name: String) -> String:
|
func normalize_header(header_name: String) -> String:
|
||||||
return header_name.strip_edges()[0].to_upper() + header_name.strip_edges().substr(1, -1).to_lower()
|
return header_name.strip_edges()[0].to_upper() + header_name.strip_edges().substr(1, -1).to_lower()
|
||||||
|
|
||||||
|
|
||||||
# Lit une "ligne logique" complète d’un CSV (même si elle est sur plusieurs lignes à cause des guillemets)
|
# Lit une "ligne logique" complète d’un CSV (même si elle est sur plusieurs lignes à cause des guillemets)
|
||||||
func read_csv_record(file: FileAccess) -> String:
|
func read_csv_record(file: FileAccess) -> String:
|
||||||
var record: String = ""
|
var record: String = ""
|
||||||
@@ -727,5 +736,4 @@ func read_csv_record(file: FileAccess) -> String:
|
|||||||
|
|
||||||
return record
|
return record
|
||||||
|
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|||||||
@@ -1,14 +1,14 @@
|
|||||||
extends HBoxContainer
|
|
||||||
class_name SegmentBuild
|
class_name SegmentBuild
|
||||||
|
extends HBoxContainer
|
||||||
|
|
||||||
signal modify()
|
signal modified()
|
||||||
signal delete()
|
signal deleted()
|
||||||
|
|
||||||
|
var points: Array[Vector2] = []
|
||||||
|
|
||||||
@onready var number_of_points_labels: Label = %NumberOfPointsLabel
|
@onready var number_of_points_labels: Label = %NumberOfPointsLabel
|
||||||
@onready var color_rect: ColorRect = %ColorRect
|
@onready var color_rect: ColorRect = %ColorRect
|
||||||
|
|
||||||
var points: Array[Vector2] = []
|
|
||||||
|
|
||||||
|
|
||||||
func add_point(point: Vector2) -> void:
|
func add_point(point: Vector2) -> void:
|
||||||
points.append(point)
|
points.append(point)
|
||||||
@@ -35,9 +35,9 @@ func set_color(color: Color) -> void:
|
|||||||
|
|
||||||
|
|
||||||
func _on_modify_button_pressed() -> void:
|
func _on_modify_button_pressed() -> void:
|
||||||
modify.emit()
|
modified.emit()
|
||||||
|
|
||||||
|
|
||||||
func _on_delete_button_pressed() -> void:
|
func _on_delete_button_pressed() -> void:
|
||||||
delete.emit()
|
deleted.emit()
|
||||||
queue_free()
|
queue_free()
|
||||||
|
|||||||
@@ -1,25 +1,24 @@
|
|||||||
extends HBoxContainer
|
|
||||||
class_name SegmentContainer
|
class_name SegmentContainer
|
||||||
|
extends HBoxContainer
|
||||||
|
|
||||||
signal changed()
|
signal changed()
|
||||||
|
|
||||||
|
const SEGMENT_BUILD_SCENE: PackedScene = preload("res://sources/language_tool/segment_build.tscn")
|
||||||
|
const POINT_BUTTON_SCENE: PackedScene = preload("res://sources/language_tool/segment_point_button.tscn")
|
||||||
|
|
||||||
@export var points_per_lines: int = 25
|
@export var points_per_lines: int = 25
|
||||||
@export var points_per_gradient: int = 7
|
@export var points_per_gradient: int = 7
|
||||||
|
|
||||||
|
var gradient: Gradient
|
||||||
|
var current_segment: SegmentBuild
|
||||||
|
var current_button: SegmentPointButton
|
||||||
|
var buttons: Array[SegmentPointButton] = []
|
||||||
|
|
||||||
@onready var grapheme_label: Label = %GraphemeLabel
|
@onready var grapheme_label: Label = %GraphemeLabel
|
||||||
@onready var buttons_parent: Control = %ButtonsParent
|
@onready var buttons_parent: Control = %ButtonsParent
|
||||||
@onready var segments_container: VBoxContainer = %SegmentsContainer
|
@onready var segments_container: VBoxContainer = %SegmentsContainer
|
||||||
@onready var lines: Node2D = %Lines
|
@onready var lines: Node2D = %Lines
|
||||||
|
|
||||||
const SEGMENT_BUILD_SCENE: PackedScene = preload("res://sources/language_tool/segment_build.tscn")
|
|
||||||
const POINT_BUTTON_SCENE: PackedScene = preload("res://sources/language_tool/segment_point_button.tscn")
|
|
||||||
|
|
||||||
var gradient: Gradient
|
|
||||||
|
|
||||||
var current_segment: SegmentBuild
|
|
||||||
var current_button: SegmentPointButton
|
|
||||||
var buttons: Array[SegmentPointButton] = []
|
|
||||||
|
|
||||||
|
|
||||||
func reset() -> void:
|
func reset() -> void:
|
||||||
var to_free: Array[Node] = lines.get_children()
|
var to_free: Array[Node] = lines.get_children()
|
||||||
@@ -126,8 +125,8 @@ func _on_add_segment_button_pressed() -> void:
|
|||||||
segments_container.add_child(new_segment)
|
segments_container.add_child(new_segment)
|
||||||
|
|
||||||
# Connect signals for modifying and deleting the segment
|
# Connect signals for modifying and deleting the segment
|
||||||
new_segment.modify.connect(_on_segment_modify.bind(new_segment))
|
new_segment.modified.connect(_on_segment_modified.bind(new_segment))
|
||||||
new_segment.delete.connect(_on_segment_delete.bind(new_segment))
|
new_segment.deleted.connect(_on_segment_deleted.bind(new_segment))
|
||||||
|
|
||||||
# Store the new segment as the currently selected one
|
# Store the new segment as the currently selected one
|
||||||
current_segment = new_segment
|
current_segment = new_segment
|
||||||
@@ -156,15 +155,13 @@ func _on_add_segment_button_pressed() -> void:
|
|||||||
changed.emit()
|
changed.emit()
|
||||||
|
|
||||||
|
|
||||||
func _on_segment_modify(segment: SegmentBuild) -> void:
|
func _on_segment_modified(segment: SegmentBuild) -> void:
|
||||||
current_segment = segment
|
current_segment = segment
|
||||||
|
|
||||||
match_segment_with_buttons()
|
match_segment_with_buttons()
|
||||||
|
|
||||||
changed.emit()
|
changed.emit()
|
||||||
|
|
||||||
|
|
||||||
func _on_segment_delete(segment: SegmentBuild) -> void:
|
func _on_segment_deleted(segment: SegmentBuild) -> void:
|
||||||
if segment == current_segment:
|
if segment == current_segment:
|
||||||
var possible_segments: Array[Node] = segments_container.get_children()
|
var possible_segments: Array[Node] = segments_container.get_children()
|
||||||
if not possible_segments.is_empty():
|
if not possible_segments.is_empty():
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
extends Control
|
|
||||||
class_name SegmentPointButton
|
class_name SegmentPointButton
|
||||||
|
extends Control
|
||||||
|
|
||||||
signal point_down()
|
signal point_down()
|
||||||
signal point_up()
|
signal point_up()
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
extends WordList
|
extends WordList
|
||||||
|
|
||||||
var not_found_list: String = ""
|
var not_found_list: String = ""
|
||||||
|
|
||||||
@onready var export_not_found_button: Button = %ExportNotFoundButton
|
@onready var export_not_found_button: Button = %ExportNotFoundButton
|
||||||
@onready var file_dialog_export: FileDialog = $FileDialogExport
|
@onready var file_dialog_export: FileDialog = $FileDialogExport
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
extends WordListElement
|
|
||||||
class_name SentenceListElement
|
class_name SentenceListElement
|
||||||
|
extends WordListElement
|
||||||
|
|
||||||
signal not_found(text: String)
|
signal not_found(text: String)
|
||||||
|
|
||||||
@@ -13,8 +13,6 @@ func _ready() -> void:
|
|||||||
graphemes_label.hide()
|
graphemes_label.hide()
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
func update_lesson() -> void:
|
func update_lesson() -> void:
|
||||||
var highest_min_lesson: int = -1
|
var highest_min_lesson: int = -1
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
extends "res://sources/language_tool/word_list.gd"
|
extends WordList
|
||||||
|
|
||||||
|
|
||||||
func _on_list_title_import_path_selected(path: String, match_to_file: bool) -> void:
|
func _on_list_title_import_path_selected(path: String, match_to_file: bool) -> void:
|
||||||
|
|||||||
@@ -1,18 +1,18 @@
|
|||||||
extends Control
|
extends Control
|
||||||
|
|
||||||
|
const EXTENSION: String = ".csv"
|
||||||
|
|
||||||
@export var gradient: Gradient
|
@export var gradient: Gradient
|
||||||
|
|
||||||
|
var letters: Array[String] = []
|
||||||
|
var current_letter: int = -1
|
||||||
|
|
||||||
@onready var lower_container: SegmentContainer = %Lower
|
@onready var lower_container: SegmentContainer = %Lower
|
||||||
@onready var upper_container: SegmentContainer = %Upper
|
@onready var upper_container: SegmentContainer = %Upper
|
||||||
@onready var letter_picker: OptionButton = %LetterPicker
|
@onready var letter_picker: OptionButton = %LetterPicker
|
||||||
@onready var save_ok: TextureRect = %SaveOk
|
@onready var save_ok: TextureRect = %SaveOk
|
||||||
@onready var copy_from: MenuButton = %CopyFrom
|
@onready var copy_from: MenuButton = %CopyFrom
|
||||||
|
|
||||||
const EXTENSION: String = ".csv"
|
|
||||||
|
|
||||||
var letters: Array[String] = []
|
|
||||||
var current_letter: int = -1
|
|
||||||
|
|
||||||
|
|
||||||
func _ready() -> void:
|
func _ready() -> void:
|
||||||
copy_from.get_popup().id_pressed.connect(_on_copy_from_id_pressed)
|
copy_from.get_popup().id_pressed.connect(_on_copy_from_id_pressed)
|
||||||
|
|||||||
@@ -1,16 +1,16 @@
|
|||||||
extends HBoxContainer
|
|
||||||
class_name VideoGPDescription
|
class_name VideoGPDescription
|
||||||
|
extends HBoxContainer
|
||||||
|
|
||||||
@warning_ignore("unused_signal")
|
@warning_ignore("unused_signal")
|
||||||
signal delete
|
signal deleted()
|
||||||
|
|
||||||
|
var gp: Dictionary = {}
|
||||||
|
|
||||||
@onready var gp_menu_button: MenuButton = %GPMenuButton
|
@onready var gp_menu_button: MenuButton = %GPMenuButton
|
||||||
@onready var video_player: VideoStreamPlayer = %VideoStreamPlayer
|
@onready var video_player: VideoStreamPlayer = %VideoStreamPlayer
|
||||||
@onready var video_upload_button: PlusButton = %VideoUploadButton
|
@onready var video_upload_button: PlusButton = %VideoUploadButton
|
||||||
@onready var file_dialog: FileDialog = $FileDialog
|
@onready var file_dialog: FileDialog = $FileDialog
|
||||||
|
|
||||||
var gp: Dictionary = {}
|
|
||||||
|
|
||||||
|
|
||||||
func _video_file_selected(file_path: String) -> void:
|
func _video_file_selected(file_path: String) -> void:
|
||||||
file_dialog.files_selected.connect(_video_file_selected.bind(file_dialog))
|
file_dialog.files_selected.connect(_video_file_selected.bind(file_dialog))
|
||||||
|
|||||||
@@ -1,8 +1,16 @@
|
|||||||
extends Control
|
|
||||||
class_name WordList
|
class_name WordList
|
||||||
|
extends Control
|
||||||
|
|
||||||
@export var element_scene: PackedScene = preload("res://sources/language_tool/word_list_element.tscn")
|
@export var element_scene: PackedScene = preload("res://sources/language_tool/word_list_element.tscn")
|
||||||
|
|
||||||
|
var undo_redo: UndoRedo = UndoRedo.new()
|
||||||
|
var in_new_gp_mode: bool = false:
|
||||||
|
set = set_in_new_gp_mode
|
||||||
|
var _element: WordListElement
|
||||||
|
var sub_elements_list: Dictionary = {}
|
||||||
|
var new_gp_asked_element: WordListElement
|
||||||
|
var new_gp_asked_ind: int
|
||||||
|
|
||||||
@onready var elements_container: VBoxContainer = %ElementsContainer
|
@onready var elements_container: VBoxContainer = %ElementsContainer
|
||||||
@onready var new_gp_layer: CanvasLayer = $NewGPLayer
|
@onready var new_gp_layer: CanvasLayer = $NewGPLayer
|
||||||
@onready var new_gp: Variant = %NewGP
|
@onready var new_gp: Variant = %NewGP
|
||||||
@@ -12,14 +20,6 @@ class_name WordList
|
|||||||
@onready var graphemes_title: Label = %Graphemes
|
@onready var graphemes_title: Label = %Graphemes
|
||||||
@onready var error_label: Label = %ErrorLabel
|
@onready var error_label: Label = %ErrorLabel
|
||||||
|
|
||||||
var undo_redo: UndoRedo = UndoRedo.new()
|
|
||||||
var in_new_gp_mode: bool = false:
|
|
||||||
set = set_in_new_gp_mode
|
|
||||||
var _element: WordListElement
|
|
||||||
var sub_elements_list: Dictionary = {}
|
|
||||||
var new_gp_asked_element: WordListElement
|
|
||||||
var new_gp_asked_ind: int
|
|
||||||
|
|
||||||
|
|
||||||
func create_sub_elements_list() -> void:
|
func create_sub_elements_list() -> void:
|
||||||
sub_elements_list.clear()
|
sub_elements_list.clear()
|
||||||
@@ -190,7 +190,6 @@ func _on_save_button_pressed() -> void:
|
|||||||
undo_redo.clear_history()
|
undo_redo.clear_history()
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
func _on_back_button_pressed() -> void:
|
func _on_back_button_pressed() -> void:
|
||||||
get_tree().change_scene_to_file("res://sources/language_tool/prof_tool_menu.tscn")
|
get_tree().change_scene_to_file("res://sources/language_tool/prof_tool_menu.tscn")
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
extends MarginContainer
|
|
||||||
class_name WordListElement
|
class_name WordListElement
|
||||||
|
extends MarginContainer
|
||||||
|
|
||||||
signal delete_pressed()
|
signal delete_pressed()
|
||||||
signal new_gp_asked(i: int)
|
signal new_gp_asked(i: int)
|
||||||
@@ -17,21 +17,6 @@ const PLUS_BUTTON_SCENE: PackedScene = preload("res://sources/language_tool/plus
|
|||||||
@export var relational_table: String = "GPsInWords"
|
@export var relational_table: String = "GPsInWords"
|
||||||
@export var sub_table_id: String = "GPID"
|
@export var sub_table_id: String = "GPID"
|
||||||
|
|
||||||
@onready var word_label: Label = %Word
|
|
||||||
@onready var graphemes_label: Label = %Graphemes
|
|
||||||
@onready var word_edit: LineEdit = %WordEdit
|
|
||||||
@onready var tab_container: TabContainer = $TabContainer
|
|
||||||
@onready var lesson_label: Label = %Lesson
|
|
||||||
@onready var exception_checkbox: CheckBox = %ExceptionCheckBox
|
|
||||||
@onready var exception_edit_checkbox: CheckBox = %ExceptionEditCheckBox
|
|
||||||
@onready var reading_checkbox: CheckBox = %ReadingCheckBox
|
|
||||||
@onready var writing_checkbox: CheckBox = %WritingCheckBox
|
|
||||||
@onready var reading_edit_checkbox: CheckBox = %ReadingEditCheckBox
|
|
||||||
@onready var writing_edit_checkbox: CheckBox = %WritingEditCheckBox
|
|
||||||
@onready var graphemes_edit_container: HBoxContainer = %GraphemesEditContainer
|
|
||||||
@onready var add_gp_button: MarginContainer = %AddGPButton
|
|
||||||
@onready var remove_gp_button: MarginContainer = %RemoveGPButton2
|
|
||||||
|
|
||||||
var word: String = "":
|
var word: String = "":
|
||||||
set = set_word
|
set = set_word
|
||||||
var lesson: int = 0:
|
var lesson: int = 0:
|
||||||
@@ -53,6 +38,21 @@ var writing: int = 0:
|
|||||||
set = set_writing
|
set = set_writing
|
||||||
var sub_elements_list: Dictionary = {}
|
var sub_elements_list: Dictionary = {}
|
||||||
|
|
||||||
|
@onready var word_label: Label = %Word
|
||||||
|
@onready var graphemes_label: Label = %Graphemes
|
||||||
|
@onready var word_edit: LineEdit = %WordEdit
|
||||||
|
@onready var tab_container: TabContainer = $TabContainer
|
||||||
|
@onready var lesson_label: Label = %Lesson
|
||||||
|
@onready var exception_checkbox: CheckBox = %ExceptionCheckBox
|
||||||
|
@onready var exception_edit_checkbox: CheckBox = %ExceptionEditCheckBox
|
||||||
|
@onready var reading_checkbox: CheckBox = %ReadingCheckBox
|
||||||
|
@onready var writing_checkbox: CheckBox = %WritingCheckBox
|
||||||
|
@onready var reading_edit_checkbox: CheckBox = %ReadingEditCheckBox
|
||||||
|
@onready var writing_edit_checkbox: CheckBox = %WritingEditCheckBox
|
||||||
|
@onready var graphemes_edit_container: HBoxContainer = %GraphemesEditContainer
|
||||||
|
@onready var add_gp_button: MarginContainer = %AddGPButton
|
||||||
|
@onready var remove_gp_button: MarginContainer = %RemoveGPButton2
|
||||||
|
|
||||||
|
|
||||||
func set_exception(p_exception: bool) -> void:
|
func set_exception(p_exception: bool) -> void:
|
||||||
exception = p_exception
|
exception = p_exception
|
||||||
@@ -61,6 +61,7 @@ func set_exception(p_exception: bool) -> void:
|
|||||||
if exception_edit_checkbox:
|
if exception_edit_checkbox:
|
||||||
exception_edit_checkbox.button_pressed = bool(exception)
|
exception_edit_checkbox.button_pressed = bool(exception)
|
||||||
|
|
||||||
|
|
||||||
func set_reading(p_reading: bool) -> void:
|
func set_reading(p_reading: bool) -> void:
|
||||||
reading = p_reading
|
reading = p_reading
|
||||||
if reading_checkbox:
|
if reading_checkbox:
|
||||||
@@ -68,6 +69,7 @@ func set_reading(p_reading: bool) -> void:
|
|||||||
if reading_edit_checkbox:
|
if reading_edit_checkbox:
|
||||||
reading_edit_checkbox.button_pressed = bool(reading)
|
reading_edit_checkbox.button_pressed = bool(reading)
|
||||||
|
|
||||||
|
|
||||||
func set_writing(p_writing: bool) -> void:
|
func set_writing(p_writing: bool) -> void:
|
||||||
writing = p_writing
|
writing = p_writing
|
||||||
if writing_checkbox:
|
if writing_checkbox:
|
||||||
@@ -367,7 +369,6 @@ func _on_add_gp_button_pressed(element: Node) -> void:
|
|||||||
add_gp_list_button(gp_id, ind_gp_id + 1)
|
add_gp_list_button(gp_id, ind_gp_id + 1)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
func _on_empty_add_gp_button_pressed() -> void:
|
func _on_empty_add_gp_button_pressed() -> void:
|
||||||
var gp_id: int = sub_elements_list.keys()[0]
|
var gp_id: int = sub_elements_list.keys()[0]
|
||||||
unvalidated_gp_ids.append(gp_id)
|
unvalidated_gp_ids.append(gp_id)
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
extends TextureButton
|
|
||||||
class_name LessonButton
|
class_name LessonButton
|
||||||
|
extends TextureButton
|
||||||
|
|
||||||
@export_color_no_alpha var base_color: Color:
|
@export_color_no_alpha var base_color: Color:
|
||||||
set = _set_base_color
|
set = _set_base_color
|
||||||
@@ -15,11 +15,12 @@ class_name LessonButton
|
|||||||
@onready var placeholder: TextureRect = %Placeholder
|
@onready var placeholder: TextureRect = %Placeholder
|
||||||
@onready var right_fx: RightFX = %RightFX
|
@onready var right_fx: RightFX = %RightFX
|
||||||
|
|
||||||
|
|
||||||
func _ready() -> void:
|
func _ready() -> void:
|
||||||
_set_base_color(base_color)
|
_set_base_color(base_color)
|
||||||
_set_completed_color(completed_color)
|
_set_completed_color(completed_color)
|
||||||
_set_text(text)
|
_set_text(text)
|
||||||
|
|
||||||
|
|
||||||
func show_placeholder(is_shown: bool) -> void:
|
func show_placeholder(is_shown: bool) -> void:
|
||||||
placeholder.visible = is_shown
|
placeholder.visible = is_shown
|
||||||
@@ -30,6 +31,7 @@ func right() -> void:
|
|||||||
right_fx.play()
|
right_fx.play()
|
||||||
await right_fx.finished
|
await right_fx.finished
|
||||||
|
|
||||||
|
|
||||||
func _set_base_color(color: Color) -> void:
|
func _set_base_color(color: Color) -> void:
|
||||||
base_color = color
|
base_color = color
|
||||||
if center and not completed:
|
if center and not completed:
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
extends Node2D
|
|
||||||
class_name LetterSegment
|
class_name LetterSegment
|
||||||
|
extends Node2D
|
||||||
|
|
||||||
signal finished()
|
signal finished()
|
||||||
|
|
||||||
@@ -25,6 +25,7 @@ func start() -> void:
|
|||||||
func stop() -> void:
|
func stop() -> void:
|
||||||
finished.emit()
|
finished.emit()
|
||||||
|
|
||||||
|
|
||||||
func demo() -> void:
|
func demo() -> void:
|
||||||
tracing_path.demo()
|
tracing_path.demo()
|
||||||
|
|
||||||
|
|||||||
@@ -1,9 +1,20 @@
|
|||||||
extends Control
|
|
||||||
class_name LookAndLearn
|
class_name LookAndLearn
|
||||||
|
extends Control
|
||||||
|
|
||||||
|
static var transition_data: Dictionary = {}
|
||||||
|
|
||||||
@export var lesson_nb: int = 1
|
@export var lesson_nb: int = 1
|
||||||
@export var current_button_pressed: int = 0
|
@export var current_button_pressed: int = 0
|
||||||
|
|
||||||
|
var gp_list: Array[Dictionary] = []
|
||||||
|
var current_video: int = 0
|
||||||
|
var videos: Array[VideoStream] = []
|
||||||
|
var current_image_and_sound: int = 0
|
||||||
|
var images: Array[Texture] = []
|
||||||
|
var sounds: Array[AudioStream] = []
|
||||||
|
var gardens_data: Dictionary = {}
|
||||||
|
var current_tracing: int = 0
|
||||||
|
|
||||||
@onready var animation_player: AnimationPlayer = $AnimationPlayer
|
@onready var animation_player: AnimationPlayer = $AnimationPlayer
|
||||||
@onready var audio_player: AudioStreamPlayer = $AudioStreamPlayer
|
@onready var audio_player: AudioStreamPlayer = $AudioStreamPlayer
|
||||||
@onready var video_player: VideoStreamPlayer = %VideoStreamPlayer
|
@onready var video_player: VideoStreamPlayer = %VideoStreamPlayer
|
||||||
@@ -13,21 +24,6 @@ class_name LookAndLearn
|
|||||||
@onready var grapheme_particles: GPUParticles2D = $GraphemeParticles
|
@onready var grapheme_particles: GPUParticles2D = $GraphemeParticles
|
||||||
|
|
||||||
|
|
||||||
var gp_list: Array[Dictionary] = []
|
|
||||||
var current_video: int = 0
|
|
||||||
var videos: Array[VideoStream] = []
|
|
||||||
|
|
||||||
var current_image_and_sound: int = 0
|
|
||||||
var images: Array[Texture] = []
|
|
||||||
var sounds: Array[AudioStream] = []
|
|
||||||
|
|
||||||
static var transition_data: Dictionary = {}
|
|
||||||
var gardens_data: Dictionary = {}
|
|
||||||
|
|
||||||
|
|
||||||
var current_tracing: int = 0
|
|
||||||
|
|
||||||
|
|
||||||
func _ready() -> void:
|
func _ready() -> void:
|
||||||
MusicManager.stop()
|
MusicManager.stop()
|
||||||
|
|
||||||
@@ -157,7 +153,6 @@ func _on_tracing_manager_finished() -> void:
|
|||||||
_back_to_gardens()
|
_back_to_gardens()
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
func _back_to_gardens() -> void:
|
func _back_to_gardens() -> void:
|
||||||
await OpeningCurtain.close()
|
await OpeningCurtain.close()
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
extends Node2D
|
|
||||||
class_name TracingEffects
|
class_name TracingEffects
|
||||||
|
extends Node2D
|
||||||
|
|
||||||
@onready var particles_effect: GPUParticles2D = $TracingParticles
|
@onready var particles_effect: GPUParticles2D = $TracingParticles
|
||||||
@onready var sound_effect: AudioStreamPlayer = $TracingAudioStreamPlayer
|
@onready var sound_effect: AudioStreamPlayer = $TracingAudioStreamPlayer
|
||||||
|
|||||||
@@ -1,16 +1,16 @@
|
|||||||
extends Control
|
|
||||||
class_name TracingManager
|
class_name TracingManager
|
||||||
|
extends Control
|
||||||
|
|
||||||
signal finished()
|
signal finished()
|
||||||
|
|
||||||
const LETTER_SEGMENT_CLASS: PackedScene = preload("res://sources/look_and_learn/letter_segment.tscn")
|
const LETTER_SEGMENT_CLASS: PackedScene = preload("res://sources/look_and_learn/letter_segment.tscn")
|
||||||
|
const EXTENSION: String = ".csv"
|
||||||
|
|
||||||
@export var label_settings: LabelSettings
|
@export var label_settings: LabelSettings
|
||||||
|
|
||||||
@onready var lower_labels: HBoxContainer = %LowerLabels
|
@onready var lower_labels: HBoxContainer = %LowerLabels
|
||||||
@onready var upper_labels: HBoxContainer = %UpperLabels
|
@onready var upper_labels: HBoxContainer = %UpperLabels
|
||||||
|
|
||||||
const EXTENSION: String = ".csv"
|
|
||||||
|
|
||||||
func _process(_delta: float) -> void:
|
func _process(_delta: float) -> void:
|
||||||
place_segments(upper_labels.get_children())
|
place_segments(upper_labels.get_children())
|
||||||
@@ -34,8 +34,6 @@ func reset() -> void:
|
|||||||
await get_tree().process_frame
|
await get_tree().process_frame
|
||||||
|
|
||||||
|
|
||||||
# --- Setup ---
|
|
||||||
|
|
||||||
func setup(grapheme: String) -> void:
|
func setup(grapheme: String) -> void:
|
||||||
await reset()
|
await reset()
|
||||||
for letter: String in grapheme:
|
for letter: String in grapheme:
|
||||||
@@ -118,10 +116,6 @@ func _real_path(path: String) -> String:
|
|||||||
return Database.BASE_PATH.path_join(Database.language).path_join(Database.TRACING_DATA_FOLDER).path_join(path) + EXTENSION
|
return Database.BASE_PATH.path_join(Database.language).path_join(Database.TRACING_DATA_FOLDER).path_join(path) + EXTENSION
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
# --- Start ---
|
|
||||||
|
|
||||||
|
|
||||||
func start() -> void:
|
func start() -> void:
|
||||||
if upper_labels.get_child_count(false) > 0:
|
if upper_labels.get_child_count(false) > 0:
|
||||||
lower_labels.visible = false
|
lower_labels.visible = false
|
||||||
|
|||||||
@@ -1,30 +1,28 @@
|
|||||||
extends Path2D
|
|
||||||
class_name TracingPath
|
class_name TracingPath
|
||||||
|
extends Path2D
|
||||||
|
|
||||||
signal finished
|
signal finished()
|
||||||
signal demo_finished
|
signal demo_finished()
|
||||||
|
|
||||||
@export var points_per_curve: int = 25
|
@export var points_per_curve: int = 25
|
||||||
@export var hand_min_travel_time: float = 0.5
|
@export var hand_min_travel_time: float = 0.5
|
||||||
@export var hand_max_travel_time: float = 2.0
|
@export var hand_max_travel_time: float = 2.0
|
||||||
@export var distance: float = 100.0
|
@export var distance: float = 100.0
|
||||||
|
|
||||||
@export var color_gradient: Gradient
|
@export var color_gradient: Gradient
|
||||||
|
|
||||||
|
var curve_points: PackedVector2Array
|
||||||
|
var is_playing: bool = false
|
||||||
|
var is_in_demo: bool = false
|
||||||
|
var touch_positions: Array[Vector2] = []
|
||||||
|
var should_play_effects: bool = false
|
||||||
|
|
||||||
@onready var line: Line2D = $Line2D
|
@onready var line: Line2D = $Line2D
|
||||||
@onready var guide: PathFollow2D = $GuidePathFollow
|
@onready var guide: PathFollow2D = $GuidePathFollow
|
||||||
@onready var hand: PathFollow2D = $HandPathFollow2D
|
@onready var hand: PathFollow2D = $HandPathFollow2D
|
||||||
@onready var guide_sprite: Sprite2D = $GuidePathFollow/Guide
|
@onready var guide_sprite: Sprite2D = $GuidePathFollow/Guide
|
||||||
@onready var hand_sprite: Sprite2D = $HandPathFollow2D/Hand
|
@onready var hand_sprite: Sprite2D = $HandPathFollow2D/Hand
|
||||||
|
|
||||||
var curve_points: PackedVector2Array
|
|
||||||
@onready var remaining_curve: Curve2D = Curve2D.new()
|
@onready var remaining_curve: Curve2D = Curve2D.new()
|
||||||
|
|
||||||
var is_playing: bool = false
|
|
||||||
var is_in_demo: bool = false
|
|
||||||
var touch_positions: Array[Vector2] = []
|
|
||||||
var should_play_effects: bool = false
|
|
||||||
|
|
||||||
|
|
||||||
func _ready() -> void:
|
func _ready() -> void:
|
||||||
guide_sprite.visible = false
|
guide_sprite.visible = false
|
||||||
|
|||||||
@@ -11,10 +11,11 @@ const SYMBOLS_NAMES: Dictionary[String, String] = {
|
|||||||
"6": "TRIANGLE",
|
"6": "TRIANGLE",
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var password: String = ""
|
||||||
|
|
||||||
@onready var code_keyboard: CodeKeyboard = %CodeKeyboard
|
@onready var code_keyboard: CodeKeyboard = %CodeKeyboard
|
||||||
@onready var password_label: Label = %PasswordLabel
|
@onready var password_label: Label = %PasswordLabel
|
||||||
|
|
||||||
var password: String = ""
|
|
||||||
|
|
||||||
func _ready() -> void:
|
func _ready() -> void:
|
||||||
_reset_password()
|
_reset_password()
|
||||||
|
|||||||
@@ -10,7 +10,6 @@ const KALULU := preload("res://sources/minigames/base/kalulu.gd")
|
|||||||
@onready var kalulu: KALULU = $Kalulu
|
@onready var kalulu: KALULU = $Kalulu
|
||||||
@onready var kalulu_button: TextureButton = %KaluluButton
|
@onready var kalulu_button: TextureButton = %KaluluButton
|
||||||
@onready var audio_stream_player: AudioStreamPlayer = $AudioStreamPlayer
|
@onready var audio_stream_player: AudioStreamPlayer = $AudioStreamPlayer
|
||||||
|
|
||||||
@onready var garden_buttons: Array[TextureButton] = [
|
@onready var garden_buttons: Array[TextureButton] = [
|
||||||
%GardenButton1,
|
%GardenButton1,
|
||||||
%GardenButton2,
|
%GardenButton2,
|
||||||
@@ -33,7 +32,6 @@ const KALULU := preload("res://sources/minigames/base/kalulu.gd")
|
|||||||
%GardenButton19,
|
%GardenButton19,
|
||||||
%GardenButton20,
|
%GardenButton20,
|
||||||
]
|
]
|
||||||
|
|
||||||
@onready var particles: Array[GPUParticles2D] = [
|
@onready var particles: Array[GPUParticles2D] = [
|
||||||
%Particles1,
|
%Particles1,
|
||||||
%Particles2,
|
%Particles2,
|
||||||
@@ -56,18 +54,18 @@ const KALULU := preload("res://sources/minigames/base/kalulu.gd")
|
|||||||
%Particles19,
|
%Particles19,
|
||||||
%Particles20,
|
%Particles20,
|
||||||
]
|
]
|
||||||
|
|
||||||
@onready var tutorial_speeches: Array[AudioStream]= [
|
@onready var tutorial_speeches: Array[AudioStream]= [
|
||||||
Database.load_external_sound(Database.get_kalulu_speech_path("brain_screen", "intro_1")),
|
Database.load_external_sound(Database.get_kalulu_speech_path("brain_screen", "intro_1")),
|
||||||
Database.load_external_sound(Database.get_kalulu_speech_path("brain_screen", "intro_2")),
|
Database.load_external_sound(Database.get_kalulu_speech_path("brain_screen", "intro_2")),
|
||||||
Database.load_external_sound(Database.get_kalulu_speech_path("brain_screen", "intro_3"))
|
Database.load_external_sound(Database.get_kalulu_speech_path("brain_screen", "intro_3"))
|
||||||
]
|
]
|
||||||
|
|
||||||
@onready var help_speech: AudioStream = Database.load_external_sound(Database.get_kalulu_speech_path("brain_screen", "help"))
|
@onready var help_speech: AudioStream = Database.load_external_sound(Database.get_kalulu_speech_path("brain_screen", "help"))
|
||||||
|
|
||||||
|
|
||||||
static func _compute_lessons_distribution(total_lessons: int, garden_layouts: Array[GardenLayout]) -> Array[int]:
|
static func _compute_lessons_distribution(total_lessons: int, garden_layouts: Array[GardenLayout]) -> Array[int]:
|
||||||
return Gardens.compute_lessons_distribution(total_lessons, garden_layouts)
|
return Gardens.compute_lessons_distribution(total_lessons, garden_layouts)
|
||||||
|
|
||||||
|
|
||||||
func _ready() -> void:
|
func _ready() -> void:
|
||||||
UserDataManager.start_synchronization_timer()
|
UserDataManager.start_synchronization_timer()
|
||||||
|
|
||||||
|
|||||||
@@ -1,14 +1,15 @@
|
|||||||
extends Control
|
|
||||||
class_name CodeKeyboard
|
class_name CodeKeyboard
|
||||||
|
extends Control
|
||||||
|
|
||||||
signal button_pressed(key: String, password: Array[String])
|
signal button_pressed(key: String, password: Array[String])
|
||||||
signal password_entered(password: String)
|
signal password_entered(password: String)
|
||||||
|
|
||||||
|
var password: Array[String] = []
|
||||||
|
|
||||||
@onready var password_visualizer: PasswordVisualizer = %PasswordVisualizer
|
@onready var password_visualizer: PasswordVisualizer = %PasswordVisualizer
|
||||||
@onready var buttons: GridContainer = %Buttons
|
@onready var buttons: GridContainer = %Buttons
|
||||||
@onready var sound_player: AudioStreamPlayer = $ButtonSoundPlayer
|
@onready var sound_player: AudioStreamPlayer = $ButtonSoundPlayer
|
||||||
|
|
||||||
var password: Array[String] = []
|
|
||||||
|
|
||||||
func _ready() -> void:
|
func _ready() -> void:
|
||||||
for button: TextureButton in buttons.get_children(false):
|
for button: TextureButton in buttons.get_children(false):
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
@tool
|
@tool
|
||||||
extends HBoxContainer
|
|
||||||
class_name PasswordVisualizer
|
class_name PasswordVisualizer
|
||||||
|
extends HBoxContainer
|
||||||
|
|
||||||
const ICONS_TEXTURES: Dictionary[String, CompressedTexture2D] = {
|
const ICONS_TEXTURES: Dictionary[String, CompressedTexture2D] = {
|
||||||
"1": preload("res://assets/menus/login/symbol_01.png"),
|
"1": preload("res://assets/menus/login/symbol_01.png"),
|
||||||
@@ -24,12 +24,14 @@ const ICONS_TEXTURES: Dictionary[String, CompressedTexture2D] = {
|
|||||||
|
|
||||||
@onready var icons: Array[TextureRect] = []
|
@onready var icons: Array[TextureRect] = []
|
||||||
|
|
||||||
|
|
||||||
func _ready() -> void:
|
func _ready() -> void:
|
||||||
_draw_password()
|
_draw_password()
|
||||||
for icon: TextureRect in icons:
|
for icon: TextureRect in icons:
|
||||||
icon.custom_minimum_size.x = key_size
|
icon.custom_minimum_size.x = key_size
|
||||||
icon.custom_minimum_size.y = key_size
|
icon.custom_minimum_size.y = key_size
|
||||||
|
|
||||||
|
|
||||||
func _draw_password() -> void:
|
func _draw_password() -> void:
|
||||||
|
|
||||||
if not icons:
|
if not icons:
|
||||||
|
|||||||
@@ -5,9 +5,11 @@ const LOGIN_SCENE_PATH: String = "res://sources/menus/login/login.tscn"
|
|||||||
|
|
||||||
@onready var container: GridContainer = %GridContainer
|
@onready var container: GridContainer = %GridContainer
|
||||||
|
|
||||||
|
|
||||||
func _ready() -> void:
|
func _ready() -> void:
|
||||||
_refresh()
|
_refresh()
|
||||||
|
|
||||||
|
|
||||||
func _refresh() -> void:
|
func _refresh() -> void:
|
||||||
if not UserDataManager.teacher_settings:
|
if not UserDataManager.teacher_settings:
|
||||||
return
|
return
|
||||||
@@ -23,6 +25,7 @@ func _refresh() -> void:
|
|||||||
button.pressed.connect(_device_button_pressed.bind(device))
|
button.pressed.connect(_device_button_pressed.bind(device))
|
||||||
OpeningCurtain.open()
|
OpeningCurtain.open()
|
||||||
|
|
||||||
|
|
||||||
func _device_button_pressed(device: int) -> void:
|
func _device_button_pressed(device: int) -> void:
|
||||||
Logger.trace("DeviceSelection: User selected device %d" % device)
|
Logger.trace("DeviceSelection: User selected device %d" % device)
|
||||||
if UserDataManager.set_device_id(device):
|
if UserDataManager.set_device_id(device):
|
||||||
|
|||||||
@@ -1,11 +1,10 @@
|
|||||||
extends Control
|
|
||||||
class_name PackageDownloader
|
class_name PackageDownloader
|
||||||
|
extends Control
|
||||||
|
|
||||||
const MAIN_MENU_SCENE_PATH: String = "res://sources/menus/main/main_menu.tscn"
|
const MAIN_MENU_SCENE_PATH: String = "res://sources/menus/main/main_menu.tscn"
|
||||||
const DEVICE_SELECTION_SCENE_PATH: String = "res://sources/menus/device_selection/device_selection.tscn"
|
const DEVICE_SELECTION_SCENE_PATH: String = "res://sources/menus/device_selection/device_selection.tscn"
|
||||||
const LOGIN_SCENE_PATH: String = "res://sources/menus/login/login.tscn"
|
const LOGIN_SCENE_PATH: String = "res://sources/menus/login/login.tscn"
|
||||||
const USER_LANGUAGE_RESOURCES_PATH: String = "user://language_resources"
|
const USER_LANGUAGE_RESOURCES_PATH: String = "user://language_resources"
|
||||||
|
|
||||||
const ERROR_MESSAGES: Array[String] = [
|
const ERROR_MESSAGES: Array[String] = [
|
||||||
"DISCONNECTED_ERROR",
|
"DISCONNECTED_ERROR",
|
||||||
"NO_INTERNET_ACCESS",
|
"NO_INTERNET_ACCESS",
|
||||||
@@ -13,6 +12,12 @@ const ERROR_MESSAGES: Array[String] = [
|
|||||||
"INVALID_LANGUAGE_DIRECTORY",
|
"INVALID_LANGUAGE_DIRECTORY",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
var device_language: String
|
||||||
|
var current_language_path: String
|
||||||
|
var mutex: Mutex
|
||||||
|
var thread: Thread
|
||||||
|
var server_language_version: Dictionary = {}
|
||||||
|
var current_language_version: Dictionary = {}
|
||||||
|
|
||||||
@onready var http_request: HTTPRequest = $HTTPRequest
|
@onready var http_request: HTTPRequest = $HTTPRequest
|
||||||
@onready var checking_label: Label = %CheckingLabel
|
@onready var checking_label: Label = %CheckingLabel
|
||||||
@@ -25,13 +30,6 @@ const ERROR_MESSAGES: Array[String] = [
|
|||||||
@onready var error_label: Label = %ErrorLabel
|
@onready var error_label: Label = %ErrorLabel
|
||||||
@onready var error_popup: ConfirmPopup = $ErrorPopup
|
@onready var error_popup: ConfirmPopup = $ErrorPopup
|
||||||
|
|
||||||
var device_language: String
|
|
||||||
var current_language_path: String
|
|
||||||
var mutex: Mutex
|
|
||||||
var thread: Thread
|
|
||||||
|
|
||||||
var server_language_version: Dictionary = {}
|
|
||||||
var current_language_version: Dictionary = {}
|
|
||||||
|
|
||||||
func _ready() -> void:
|
func _ready() -> void:
|
||||||
await get_tree().process_frame
|
await get_tree().process_frame
|
||||||
|
|||||||
@@ -5,9 +5,12 @@ const BACK_SCENE_PATH: String = "res://sources/menus/main/main_menu.tscn"
|
|||||||
const NEXT_SCENE_PATH: String = "res://sources/menus/brain/brain.tscn"
|
const NEXT_SCENE_PATH: String = "res://sources/menus/brain/brain.tscn"
|
||||||
const TEACHER_SCENE_PATH: String = "res://sources/menus/settings/teacher_settings.tscn"
|
const TEACHER_SCENE_PATH: String = "res://sources/menus/settings/teacher_settings.tscn"
|
||||||
const PACKAGE_LOADER_SCENE_PATH: String = "res://sources/menus/language_selection/package_downloader.tscn"
|
const PACKAGE_LOADER_SCENE_PATH: String = "res://sources/menus/language_selection/package_downloader.tscn"
|
||||||
|
|
||||||
const KALULU := preload("res://sources/minigames/base/kalulu.gd")
|
const KALULU := preload("res://sources/minigames/base/kalulu.gd")
|
||||||
|
|
||||||
|
var help_speech: AudioStream
|
||||||
|
var wrong_password_speech: AudioStream
|
||||||
|
var right_password_speech: AudioStream
|
||||||
|
|
||||||
@onready var kalulu: KALULU = $Kalulu
|
@onready var kalulu: KALULU = $Kalulu
|
||||||
@onready var music_player: AudioStreamPlayer = $MusicStreamPlayer
|
@onready var music_player: AudioStreamPlayer = $MusicStreamPlayer
|
||||||
@onready var device_number_label: Label = $DeviceNumber
|
@onready var device_number_label: Label = $DeviceNumber
|
||||||
@@ -16,9 +19,6 @@ const KALULU := preload("res://sources/minigames/base/kalulu.gd")
|
|||||||
@onready var teacher_help_label: Label = %TeacherHelpLabel
|
@onready var teacher_help_label: Label = %TeacherHelpLabel
|
||||||
@onready var kalulu_button: CanvasItem = %KaluluButton
|
@onready var kalulu_button: CanvasItem = %KaluluButton
|
||||||
|
|
||||||
var help_speech: AudioStream
|
|
||||||
var wrong_password_speech: AudioStream
|
|
||||||
var right_password_speech: AudioStream
|
|
||||||
|
|
||||||
func _ready() -> void:
|
func _ready() -> void:
|
||||||
UserDataManager.stop_synchronization_timer()
|
UserDataManager.stop_synchronization_timer()
|
||||||
|
|||||||
@@ -1,23 +1,22 @@
|
|||||||
@tool
|
@tool
|
||||||
extends TextureButton
|
|
||||||
class_name DeviceButton
|
class_name DeviceButton
|
||||||
|
extends TextureButton
|
||||||
@onready var background: TextureRect = $Background
|
|
||||||
@onready var label: Label = $Label
|
|
||||||
|
|
||||||
|
|
||||||
@export_range(1, 99) var number: int:
|
@export_range(1, 99) var number: int:
|
||||||
set(value):
|
set(value):
|
||||||
number = value
|
number = value
|
||||||
if label:
|
if label:
|
||||||
label.text = str(value)
|
label.text = str(value)
|
||||||
|
|
||||||
@export var background_color: Color:
|
@export var background_color: Color:
|
||||||
set(value):
|
set(value):
|
||||||
background_color = value
|
background_color = value
|
||||||
if background:
|
if background:
|
||||||
background.self_modulate = background_color
|
background.self_modulate = background_color
|
||||||
|
|
||||||
|
@onready var background: TextureRect = $Background
|
||||||
|
@onready var label: Label = $Label
|
||||||
|
|
||||||
|
|
||||||
func _ready() -> void:
|
func _ready() -> void:
|
||||||
label.text = str(number)
|
label.text = str(number)
|
||||||
background.self_modulate = background_color
|
background.self_modulate = background_color
|
||||||
|
|||||||
@@ -1,11 +1,7 @@
|
|||||||
extends Control
|
extends Control
|
||||||
|
|
||||||
@onready var speech_player: AudioStreamPlayer = $SpeechPlayer
|
|
||||||
@onready var sprite: AnimatedSprite2D = $Sprite
|
|
||||||
|
|
||||||
var tuto_speech: AudioStreamMP3
|
var tuto_speech: AudioStreamMP3
|
||||||
var feedback_speech: AudioStreamMP3
|
var feedback_speech: AudioStreamMP3
|
||||||
|
|
||||||
var is_speaking: bool = false:
|
var is_speaking: bool = false:
|
||||||
set(value):
|
set(value):
|
||||||
is_speaking = value
|
is_speaking = value
|
||||||
@@ -16,6 +12,9 @@ var is_speaking: bool = false:
|
|||||||
sprite.play("Tc_Idle1")
|
sprite.play("Tc_Idle1")
|
||||||
var elapsed_time: float = 0.0
|
var elapsed_time: float = 0.0
|
||||||
|
|
||||||
|
@onready var speech_player: AudioStreamPlayer = $SpeechPlayer
|
||||||
|
@onready var sprite: AnimatedSprite2D = $Sprite
|
||||||
|
|
||||||
|
|
||||||
func _ready() -> void:
|
func _ready() -> void:
|
||||||
tuto_speech = Database.load_external_sound(Database.get_kalulu_speech_path("title_screen", "tuto_welcome_oneshot"))
|
tuto_speech = Database.load_external_sound(Database.get_kalulu_speech_path("title_screen", "tuto_welcome_oneshot"))
|
||||||
@@ -26,27 +25,23 @@ func _ready() -> void:
|
|||||||
func _process(delta: float) -> void:
|
func _process(delta: float) -> void:
|
||||||
if not visible:
|
if not visible:
|
||||||
return
|
return
|
||||||
|
|
||||||
if not sprite.is_playing():
|
if not sprite.is_playing():
|
||||||
sprite.play("Tc_Idle1")
|
sprite.play("Tc_Idle1")
|
||||||
|
|
||||||
if not is_speaking:
|
if not is_speaking:
|
||||||
elapsed_time += delta
|
elapsed_time += delta
|
||||||
if elapsed_time > 20:
|
if elapsed_time > 20:
|
||||||
start_speech()
|
start_speech()
|
||||||
|
|
||||||
|
|
||||||
func _play_speech(speech: AudioStream) -> void:
|
func _play_speech(speech: AudioStream) -> void:
|
||||||
if not speech:
|
if not speech:
|
||||||
Logger.warn("Kalulu: Speech not found")
|
Logger.warn("Kalulu: Speech not found")
|
||||||
is_speaking = false
|
is_speaking = false
|
||||||
return
|
return
|
||||||
|
|
||||||
is_speaking = true
|
is_speaking = true
|
||||||
|
|
||||||
speech_player.stream = speech
|
speech_player.stream = speech
|
||||||
speech_player.play()
|
speech_player.play()
|
||||||
await speech_player.finished
|
await speech_player.finished
|
||||||
|
|
||||||
is_speaking = false
|
is_speaking = false
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ extends OptionButton
|
|||||||
|
|
||||||
var items: Array[String] = []
|
var items: Array[String] = []
|
||||||
|
|
||||||
|
|
||||||
func _ready() -> void:
|
func _ready() -> void:
|
||||||
# Adds the supported locales to the field
|
# Adds the supported locales to the field
|
||||||
var idx: int = 0
|
var idx: int = 0
|
||||||
|
|||||||
@@ -1,12 +1,11 @@
|
|||||||
extends Control
|
extends Control
|
||||||
|
|
||||||
signal logged_in
|
signal logged_in()
|
||||||
|
|
||||||
@onready var validator: FormValidator = %LoginFormValidator
|
@onready var validator: FormValidator = %LoginFormValidator
|
||||||
@onready var email_field: LineEdit = %EmailField
|
@onready var email_field: LineEdit = %EmailField
|
||||||
@onready var password_field: LineEdit = %PasswordField
|
@onready var password_field: LineEdit = %PasswordField
|
||||||
@onready var login_message: Label = %LoginError
|
@onready var login_message: Label = %LoginError
|
||||||
|
|
||||||
@onready var device_id_container: VBoxContainer = %DeviceIDContainer
|
@onready var device_id_container: VBoxContainer = %DeviceIDContainer
|
||||||
@onready var device_id_field: SpinBox = %DeviceIDField
|
@onready var device_id_field: SpinBox = %DeviceIDField
|
||||||
|
|
||||||
|
|||||||
@@ -1,14 +1,12 @@
|
|||||||
extends Control
|
extends Control
|
||||||
|
|
||||||
const KALULU := preload("res://sources/menus/main/kalulu.gd")
|
const KALULU := preload("res://sources/menus/main/kalulu.gd")
|
||||||
|
|
||||||
const ADULT_CHECK_SCENE_PATH: String = "res://sources/menus/adult_check/adult_check.tscn"
|
const ADULT_CHECK_SCENE_PATH: String = "res://sources/menus/adult_check/adult_check.tscn"
|
||||||
const PACKAGE_LOADER_SCENE_PATH: String = "res://sources/menus/language_selection/package_downloader.tscn"
|
const PACKAGE_LOADER_SCENE_PATH: String = "res://sources/menus/language_selection/package_downloader.tscn"
|
||||||
|
|
||||||
@onready var version_label: Label = $Informations/BuildVersionValue
|
@onready var version_label: Label = $Informations/BuildVersionValue
|
||||||
@onready var teacher_label: Label = $Informations/TeacherValue
|
@onready var teacher_label: Label = $Informations/TeacherValue
|
||||||
@onready var device_id_label: Label = $Informations/DeviceIDValue
|
@onready var device_id_label: Label = $Informations/DeviceIDValue
|
||||||
|
|
||||||
@onready var kalulu: KALULU = $Kalulu
|
@onready var kalulu: KALULU = $Kalulu
|
||||||
@onready var play_button: Button = %PlayButton
|
@onready var play_button: Button = %PlayButton
|
||||||
@onready var interface_left: MarginContainer = %InterfaceLeft
|
@onready var interface_left: MarginContainer = %InterfaceLeft
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
extends ProgressBar
|
|
||||||
class_name RegisterProgressBar
|
class_name RegisterProgressBar
|
||||||
|
extends ProgressBar
|
||||||
|
|
||||||
|
|
||||||
func set_value_with_tween(new_value: float) -> void:
|
func set_value_with_tween(new_value: float) -> void:
|
||||||
create_tween().tween_property(self, "value", new_value, 0.15).set_trans(Tween.TRANS_LINEAR)
|
create_tween().tween_property(self, "value", new_value, 0.15).set_trans(Tween.TRANS_LINEAR)
|
||||||
|
|||||||
@@ -3,6 +3,8 @@ extends Control
|
|||||||
const MAIN_MENU_PATH: String = "res://sources/menus/main/main_menu.tscn"
|
const MAIN_MENU_PATH: String = "res://sources/menus/main/main_menu.tscn"
|
||||||
const NEXT_SCENE_PATH: String = "res://sources/menus/language_selection/package_downloader.tscn"
|
const NEXT_SCENE_PATH: String = "res://sources/menus/language_selection/package_downloader.tscn"
|
||||||
|
|
||||||
|
var current_steps: Array[Step] = []
|
||||||
|
|
||||||
@onready var teacher_steps: Array[PackedScene] = [
|
@onready var teacher_steps: Array[PackedScene] = [
|
||||||
preload("res://sources/menus/register/steps/teacher/method_step.tscn"),
|
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/devices_count_step.tscn")
|
||||||
@@ -18,15 +20,13 @@ const NEXT_SCENE_PATH: String = "res://sources/menus/language_selection/package_
|
|||||||
@onready var account_type_step: PackedScene = preload("res://sources/menus/register/steps/account_type_step.tscn")
|
@onready var account_type_step: PackedScene = preload("res://sources/menus/register/steps/account_type_step.tscn")
|
||||||
@onready var students_step: PackedScene = preload("res://sources/menus/register/steps/teacher/students_count_step.tscn")
|
@onready var students_step: PackedScene = preload("res://sources/menus/register/steps/teacher/students_count_step.tscn")
|
||||||
@onready var player_step: PackedScene = preload("res://sources/menus/register/steps/parent/player_step.tscn")
|
@onready var player_step: PackedScene = preload("res://sources/menus/register/steps/parent/player_step.tscn")
|
||||||
|
|
||||||
var current_steps: Array[Step] = []
|
|
||||||
|
|
||||||
@onready var register_data: TeacherSettings = TeacherSettings.new()
|
@onready var register_data: TeacherSettings = TeacherSettings.new()
|
||||||
@onready var progress_bar: RegisterProgressBar = %ProgressBar
|
@onready var progress_bar: RegisterProgressBar = %ProgressBar
|
||||||
@onready var steps: Control = %Steps
|
@onready var steps: Control = %Steps
|
||||||
@onready var popup: TextureRect = %Popup
|
@onready var popup: TextureRect = %Popup
|
||||||
@onready var popup_info_label: Label = %PopupInfo
|
@onready var popup_info_label: Label = %PopupInfo
|
||||||
|
|
||||||
|
|
||||||
func _ready() -> void:
|
func _ready() -> void:
|
||||||
current_steps = [account_type_step.instantiate()]
|
current_steps = [account_type_step.instantiate()]
|
||||||
_go_to_step(int(progress_bar.value))
|
_go_to_step(int(progress_bar.value))
|
||||||
@@ -129,5 +129,6 @@ func _remove_future_steps() -> void:
|
|||||||
# Resize the array to remove unwanted steps
|
# Resize the array to remove unwanted steps
|
||||||
current_steps.resize(int(progress_bar.value + 1))
|
current_steps.resize(int(progress_bar.value + 1))
|
||||||
|
|
||||||
|
|
||||||
func _on_popup_button_pressed() -> void:
|
func _on_popup_button_pressed() -> void:
|
||||||
popup.hide()
|
popup.hide()
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ extends Step
|
|||||||
|
|
||||||
@onready var type: ItemList = %TypeSelect
|
@onready var type: ItemList = %TypeSelect
|
||||||
|
|
||||||
|
|
||||||
func _ready() -> void:
|
func _ready() -> void:
|
||||||
type.clear()
|
type.clear()
|
||||||
type.add_item(tr("TEACHER"))
|
type.add_item(tr("TEACHER"))
|
||||||
|
|||||||
@@ -1,20 +1,21 @@
|
|||||||
@tool
|
@tool
|
||||||
extends Control
|
|
||||||
class_name Step
|
class_name Step
|
||||||
|
extends Control
|
||||||
|
|
||||||
signal back(step: Step)
|
signal back(step: Step)
|
||||||
signal next(step: Step)
|
signal next(step: Step)
|
||||||
|
|
||||||
|
@export var step_name: String
|
||||||
|
@export_multiline var question: String
|
||||||
|
@export_multiline var infos: String
|
||||||
|
@export var data: Resource
|
||||||
|
|
||||||
@onready var question_label: Label = %QuestionLabel
|
@onready var question_label: Label = %QuestionLabel
|
||||||
@onready var info_label: Label = %InfoLabel
|
@onready var info_label: Label = %InfoLabel
|
||||||
@onready var form_validator: FormValidator = %FormValidator
|
@onready var form_validator: FormValidator = %FormValidator
|
||||||
@onready var form_binder: FormBinder = %FormBinder
|
@onready var form_binder: FormBinder = %FormBinder
|
||||||
@onready var form_container: Control = %FormContainer
|
@onready var form_container: Control = %FormContainer
|
||||||
|
|
||||||
@export var step_name: String
|
|
||||||
@export_multiline var question: String
|
|
||||||
@export_multiline var infos: String
|
|
||||||
@export var data: Resource
|
|
||||||
|
|
||||||
func on_enter() -> void:
|
func on_enter() -> void:
|
||||||
form_binder.read(data)
|
form_binder.read(data)
|
||||||
@@ -25,6 +26,7 @@ func on_enter() -> void:
|
|||||||
else:
|
else:
|
||||||
info_label.visible = false
|
info_label.visible = false
|
||||||
|
|
||||||
|
|
||||||
func _on_back() -> bool:
|
func _on_back() -> bool:
|
||||||
return true
|
return true
|
||||||
|
|
||||||
@@ -32,6 +34,7 @@ func _on_back() -> bool:
|
|||||||
func _on_next() -> bool:
|
func _on_next() -> bool:
|
||||||
return true
|
return true
|
||||||
|
|
||||||
|
|
||||||
# Display error messages
|
# Display error messages
|
||||||
func _on_form_validator_control_validated(control: Control, passed: bool, messages: PackedStringArray) -> void:
|
func _on_form_validator_control_validated(control: Control, passed: bool, messages: PackedStringArray) -> void:
|
||||||
var label: Label = find_child(control.name as String + "Error", true, false) as Label
|
var label: Label = find_child(control.name as String + "Error", true, false) as Label
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ extends Step
|
|||||||
|
|
||||||
@onready var api_email_field_error: Label = %APIEmailFieldError
|
@onready var api_email_field_error: Label = %APIEmailFieldError
|
||||||
|
|
||||||
|
|
||||||
func _on_validate_button_pressed() -> void:
|
func _on_validate_button_pressed() -> void:
|
||||||
api_email_field_error.visible = false
|
api_email_field_error.visible = false
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
extends Control
|
|
||||||
class_name DeviceRecap
|
class_name DeviceRecap
|
||||||
|
extends Control
|
||||||
|
|
||||||
const STUDENT_PANEL_SCENE: PackedScene = preload("res://sources/menus/settings/student_panel.tscn")
|
const STUDENT_PANEL_SCENE: PackedScene = preload("res://sources/menus/settings/student_panel.tscn")
|
||||||
|
|
||||||
@@ -9,6 +9,7 @@ const STUDENT_PANEL_SCENE: PackedScene = preload("res://sources/menus/settings/s
|
|||||||
@onready var title_label: Label = %Title
|
@onready var title_label: Label = %Title
|
||||||
@onready var students_container: GridContainer = %StudentsContainer
|
@onready var students_container: GridContainer = %StudentsContainer
|
||||||
|
|
||||||
|
|
||||||
func _ready() -> void:
|
func _ready() -> void:
|
||||||
|
|
||||||
if title:
|
if title:
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
@tool
|
@tool
|
||||||
extends Step
|
|
||||||
class_name RecapStep
|
class_name RecapStep
|
||||||
|
extends Step
|
||||||
|
|
||||||
const DEVICE_RECAP_SCENE: PackedScene = preload("res://sources/menus/register/steps/device_recap.tscn")
|
const DEVICE_RECAP_SCENE: PackedScene = preload("res://sources/menus/register/steps/device_recap.tscn")
|
||||||
|
|
||||||
@@ -11,6 +11,7 @@ const DEVICE_RECAP_SCENE: PackedScene = preload("res://sources/menus/register/st
|
|||||||
@onready var devices_count: Label = %DevicesCount
|
@onready var devices_count: Label = %DevicesCount
|
||||||
@onready var students_count: Label = %StudentsCount
|
@onready var students_count: Label = %StudentsCount
|
||||||
|
|
||||||
|
|
||||||
func on_enter() -> void:
|
func on_enter() -> void:
|
||||||
super.on_enter()
|
super.on_enter()
|
||||||
|
|
||||||
|
|||||||
@@ -1,10 +1,12 @@
|
|||||||
@tool
|
@tool
|
||||||
extends Step
|
|
||||||
class_name StudentsCountStep
|
class_name StudentsCountStep
|
||||||
|
extends Step
|
||||||
|
|
||||||
@export var device_id: int
|
@export var device_id: int
|
||||||
|
|
||||||
@onready var students_count_field: SpinBox = %StudentsCountField
|
@onready var students_count_field: SpinBox = %StudentsCountField
|
||||||
|
|
||||||
|
|
||||||
func _on_back() -> bool:
|
func _on_back() -> bool:
|
||||||
var register_data: TeacherSettings = data as TeacherSettings
|
var register_data: TeacherSettings = data as TeacherSettings
|
||||||
if register_data:
|
if register_data:
|
||||||
|
|||||||
@@ -1,9 +1,10 @@
|
|||||||
@tool
|
@tool
|
||||||
extends ValidatorRule
|
|
||||||
class_name ConfirmRule
|
class_name ConfirmRule
|
||||||
|
extends ValidatorRule
|
||||||
|
|
||||||
@export_node_path("Control") var confirm_control_path: NodePath
|
@export_node_path("Control") var confirm_control_path: NodePath
|
||||||
|
|
||||||
|
|
||||||
func _init() -> void:
|
func _init() -> void:
|
||||||
fail_message = "Value must be the same in both fields."
|
fail_message = "Value must be the same in both fields."
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
@tool
|
@tool
|
||||||
extends Validator
|
|
||||||
class_name ItemListValidator
|
class_name ItemListValidator
|
||||||
|
extends Validator
|
||||||
|
|
||||||
|
|
||||||
func get_value(control: Control) -> Variant:
|
func get_value(control: Control) -> Variant:
|
||||||
|
|||||||
@@ -1,15 +1,15 @@
|
|||||||
extends TabBar
|
|
||||||
class_name DeviceTab
|
class_name DeviceTab
|
||||||
|
extends TabBar
|
||||||
|
|
||||||
signal student_pressed(code: int)
|
signal student_pressed(code: int)
|
||||||
|
|
||||||
const STUDENT_PANEL_SCENE: PackedScene = preload("res://sources/menus/settings/student_panel.tscn")
|
const STUDENT_PANEL_SCENE: PackedScene = preload("res://sources/menus/settings/student_panel.tscn")
|
||||||
|
|
||||||
@onready var students_container: GridContainer = %StudentsContainer
|
|
||||||
|
|
||||||
@export var device_id: int
|
@export var device_id: int
|
||||||
@export var students: Array[StudentData] = []
|
@export var students: Array[StudentData] = []
|
||||||
|
|
||||||
|
@onready var students_container: GridContainer = %StudentsContainer
|
||||||
|
|
||||||
|
|
||||||
func _ready() -> void:
|
func _ready() -> void:
|
||||||
refresh()
|
refresh()
|
||||||
|
|||||||
@@ -1,14 +1,12 @@
|
|||||||
extends MarginContainer
|
|
||||||
class_name LessonUnlock
|
class_name LessonUnlock
|
||||||
|
extends MarginContainer
|
||||||
|
|
||||||
signal unlocks_changed
|
signal unlocks_changed()
|
||||||
|
|
||||||
@export var lesson_number: int:
|
@export var lesson_number: int:
|
||||||
set = _set_lesson_number
|
set = _set_lesson_number
|
||||||
|
|
||||||
@export var lesson_gps: String:
|
@export var lesson_gps: String:
|
||||||
set = _set_lesson_gps
|
set = _set_lesson_gps
|
||||||
|
|
||||||
@export var unlocks: Dictionary = {}
|
@export var unlocks: Dictionary = {}
|
||||||
|
|
||||||
@onready var lesson_label: Label = %LessonLabel
|
@onready var lesson_label: Label = %LessonLabel
|
||||||
|
|||||||
@@ -1,24 +1,24 @@
|
|||||||
extends Control
|
|
||||||
class_name LessonUnlocks
|
class_name LessonUnlocks
|
||||||
|
extends Control
|
||||||
|
|
||||||
signal student_deleted(code: int)
|
signal student_deleted(code: int)
|
||||||
|
|
||||||
const DEVICE_BUTTON_SCENE: PackedScene = preload("res://sources/menus/main/device_button.tscn")
|
const DEVICE_BUTTON_SCENE: PackedScene = preload("res://sources/menus/main/device_button.tscn")
|
||||||
const LESSON_UNLOCK_SCENE: PackedScene = preload("res://sources/menus/settings/lesson_unlock.tscn")
|
const LESSON_UNLOCK_SCENE: PackedScene = preload("res://sources/menus/settings/lesson_unlock.tscn")
|
||||||
|
|
||||||
@onready var lesson_container: VBoxContainer = %LessonContainer
|
|
||||||
@onready var name_line_edit: LineEdit = %NameLineEdit
|
|
||||||
@onready var device_selection_container: PanelContainer = %DeviceSelectionContainer
|
|
||||||
@onready var container: GridContainer = %GridContainer
|
|
||||||
|
|
||||||
var teacher_settings: SettingsTeacherSettings = null
|
|
||||||
|
|
||||||
@export var device: int:
|
@export var device: int:
|
||||||
set = _on_device_changed
|
set = _on_device_changed
|
||||||
@export var student: int:
|
@export var student: int:
|
||||||
set = _on_student_changed
|
set = _on_student_changed
|
||||||
|
|
||||||
var progression: StudentProgression
|
var progression: StudentProgression
|
||||||
|
var teacher_settings: SettingsTeacherSettings = null
|
||||||
|
|
||||||
|
@onready var lesson_container: VBoxContainer = %LessonContainer
|
||||||
|
@onready var name_line_edit: LineEdit = %NameLineEdit
|
||||||
|
@onready var device_selection_container: PanelContainer = %DeviceSelectionContainer
|
||||||
|
@onready var container: GridContainer = %GridContainer
|
||||||
|
|
||||||
|
|
||||||
func _ready() -> void:
|
func _ready() -> void:
|
||||||
name_line_edit.connect("text_submitted", _on_name_changed)
|
name_line_edit.connect("text_submitted", _on_name_changed)
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ extends TextureButton
|
|||||||
@onready var voice_volume_slider: HSlider = %VoiceVolumeSlider
|
@onready var voice_volume_slider: HSlider = %VoiceVolumeSlider
|
||||||
@onready var effects_volume_slider: HSlider = %EffectsVolumeSlider
|
@onready var effects_volume_slider: HSlider = %EffectsVolumeSlider
|
||||||
|
|
||||||
|
|
||||||
func _ready() -> void:
|
func _ready() -> void:
|
||||||
set_master_volume_slider(UserDataManager.get_master_volume())
|
set_master_volume_slider(UserDataManager.get_master_volume())
|
||||||
set_music_volume_slider(UserDataManager.get_music_volume())
|
set_music_volume_slider(UserDataManager.get_music_volume())
|
||||||
|
|||||||
@@ -1,13 +1,14 @@
|
|||||||
extends Control
|
|
||||||
class_name StudentPanel
|
class_name StudentPanel
|
||||||
|
extends Control
|
||||||
|
|
||||||
signal pressed
|
signal pressed()
|
||||||
|
|
||||||
|
@export var student_count: int
|
||||||
|
@export var student_data: StudentData
|
||||||
|
|
||||||
@onready var name_label: Label = %NameLabel
|
@onready var name_label: Label = %NameLabel
|
||||||
@onready var password_visualizer: PasswordVisualizer = %PasswordVisualizer
|
@onready var password_visualizer: PasswordVisualizer = %PasswordVisualizer
|
||||||
|
|
||||||
@export var student_count: int
|
|
||||||
@export var student_data: StudentData
|
|
||||||
|
|
||||||
func _ready() -> void:
|
func _ready() -> void:
|
||||||
if not student_data:
|
if not student_data:
|
||||||
|
|||||||
@@ -1,31 +1,26 @@
|
|||||||
extends Control
|
|
||||||
class_name SettingsTeacherSettings
|
class_name SettingsTeacherSettings
|
||||||
|
extends Control
|
||||||
|
|
||||||
const MAIN_MENU_PATH: String = "res://sources/menus/main/main_menu.tscn"
|
const MAIN_MENU_PATH: String = "res://sources/menus/main/main_menu.tscn"
|
||||||
const LOGIN_MENU_PATH: String = "res://sources/menus/login/login.tscn"
|
const LOGIN_MENU_PATH: String = "res://sources/menus/login/login.tscn"
|
||||||
const DEVICE_SELECTION_SCENE_PATH: String = "res://sources/menus/device_selection/device_selection.tscn"
|
const DEVICE_SELECTION_SCENE_PATH: String = "res://sources/menus/device_selection/device_selection.tscn"
|
||||||
|
|
||||||
const DEVICE_TAB_SCENE: PackedScene = preload("res://sources/menus/settings/device_tab.tscn")
|
const DEVICE_TAB_SCENE: PackedScene = preload("res://sources/menus/settings/device_tab.tscn")
|
||||||
|
|
||||||
|
var last_device_id: int = -1
|
||||||
|
|
||||||
@onready var devices_tab_container: TabContainer = %DevicesTabContainer
|
@onready var devices_tab_container: TabContainer = %DevicesTabContainer
|
||||||
@onready var lesson_unlocks: LessonUnlocks = $LessonUnlocks
|
@onready var lesson_unlocks: LessonUnlocks = $LessonUnlocks
|
||||||
@onready var delete_popup: ConfirmPopup = %DeletePopup
|
@onready var delete_popup: ConfirmPopup = %DeletePopup
|
||||||
@onready var loading_popup: LoadingPopup = %LoadingPopup
|
@onready var loading_popup: LoadingPopup = %LoadingPopup
|
||||||
|
|
||||||
|
|
||||||
@onready var account_type_option_button: OptionButton = %AccountTypeOptionButton
|
@onready var account_type_option_button: OptionButton = %AccountTypeOptionButton
|
||||||
@onready var education_method_option_button: OptionButton = %EducationMethodOptionButton
|
@onready var education_method_option_button: OptionButton = %EducationMethodOptionButton
|
||||||
|
|
||||||
@onready var add_device_button: Button = %AddDeviceButton
|
@onready var add_device_button: Button = %AddDeviceButton
|
||||||
@onready var add_student_button: Button = %AddStudentButton
|
@onready var add_student_button: Button = %AddStudentButton
|
||||||
@onready var label_internet_mandatory: Label = %LabelInternetMandatory
|
@onready var label_internet_mandatory: Label = %LabelInternetMandatory
|
||||||
|
|
||||||
@onready var add_device_popup: CanvasLayer = %AddDevicePopup
|
@onready var add_device_popup: CanvasLayer = %AddDevicePopup
|
||||||
@onready var add_student_popup: CanvasLayer = %AddStudentPopup
|
@onready var add_student_popup: CanvasLayer = %AddStudentPopup
|
||||||
@onready var delete_student_popup: CanvasLayer = %DeleteStudentPopup
|
@onready var delete_student_popup: CanvasLayer = %DeleteStudentPopup
|
||||||
|
|
||||||
var last_device_id: int = -1
|
|
||||||
|
|
||||||
|
|
||||||
func _ready() -> void:
|
func _ready() -> void:
|
||||||
refresh_devices_tabs()
|
refresh_devices_tabs()
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
extends Area2D
|
|
||||||
class_name Ant
|
class_name Ant
|
||||||
|
extends Area2D
|
||||||
|
|
||||||
@onready var animation_player: AnimationPlayer = $AnimationPlayer
|
@onready var animation_player: AnimationPlayer = $AnimationPlayer
|
||||||
@onready var anchor: Node2D = $Anchor
|
@onready var anchor: Node2D = $Anchor
|
||||||
|
|||||||
@@ -4,9 +4,12 @@ extends Minigame
|
|||||||
const BLANK_SCENE: PackedScene = preload("res://sources/minigames/ants/blank.tscn")
|
const BLANK_SCENE: PackedScene = preload("res://sources/minigames/ants/blank.tscn")
|
||||||
const ANT_SCENE: PackedScene = preload("res://sources/minigames/ants/ant.tscn")
|
const ANT_SCENE: PackedScene = preload("res://sources/minigames/ants/ant.tscn")
|
||||||
const WORD_SCENE: PackedScene = preload("res://sources/minigames/ants/word.tscn")
|
const WORD_SCENE: PackedScene = preload("res://sources/minigames/ants/word.tscn")
|
||||||
|
|
||||||
const LABEL_SETTINGS: LabelSettings = preload("res://resources/themes/minigames_label_settings.tres")
|
const LABEL_SETTINGS: LabelSettings = preload("res://resources/themes/minigames_label_settings.tres")
|
||||||
|
|
||||||
|
var current_sentence: Dictionary = {}
|
||||||
|
var answer_input_done: Array[bool] = []
|
||||||
|
var answers: Dictionary[String, String] # Expected, current
|
||||||
|
|
||||||
@onready var sentence_container: HFlowContainer = %Sentence
|
@onready var sentence_container: HFlowContainer = %Sentence
|
||||||
@onready var ants_spawn: Node2D = %AntsSpawn
|
@onready var ants_spawn: Node2D = %AntsSpawn
|
||||||
@onready var ants_start: Node2D = %AntsStart
|
@onready var ants_start: Node2D = %AntsStart
|
||||||
@@ -15,10 +18,6 @@ const LABEL_SETTINGS: LabelSettings = preload("res://resources/themes/minigames_
|
|||||||
@onready var ants: Node2D = %Ants
|
@onready var ants: Node2D = %Ants
|
||||||
@onready var words: Node2D = %Words
|
@onready var words: Node2D = %Words
|
||||||
|
|
||||||
var current_sentence: Dictionary = {}
|
|
||||||
var answer_input_done: Array[bool] = []
|
|
||||||
var answers: Dictionary[String, String] # Expected, current
|
|
||||||
|
|
||||||
|
|
||||||
func _find_stimuli_and_distractions() -> void:
|
func _find_stimuli_and_distractions() -> void:
|
||||||
var sentences_list: Array = Database.get_sentences_for_lesson(lesson_nb, difficulty + 2, 50)
|
var sentences_list: Array = Database.get_sentences_for_lesson(lesson_nb, difficulty + 2, 50)
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
extends TextureRect
|
|
||||||
|
|
||||||
class_name Blank
|
class_name Blank
|
||||||
|
extends TextureRect
|
||||||
|
|
||||||
const IMAGES: Array[String] = [
|
const IMAGES: Array[String] = [
|
||||||
"res://assets/minigames/ants/graphics/hole_02.png",
|
"res://assets/minigames/ants/graphics/hole_02.png",
|
||||||
|
|||||||
@@ -1,20 +1,19 @@
|
|||||||
extends TextureButton
|
|
||||||
|
|
||||||
class_name Word
|
class_name Word
|
||||||
|
extends TextureButton
|
||||||
|
|
||||||
signal answer(stimulus: String, expected_stimulus: String)
|
signal answer(stimulus: String, expected_stimulus: String)
|
||||||
signal no_answer()
|
signal no_answer()
|
||||||
|
|
||||||
@onready var area: Area2D = $Area2D
|
|
||||||
@onready var label: Label = %Label
|
|
||||||
@onready var right_fx: RightFX = $RightFX
|
|
||||||
@onready var wrong_fx: WrongFX = $WrongFX
|
|
||||||
|
|
||||||
var stimulus: String:
|
var stimulus: String:
|
||||||
set = _set_stimulus
|
set = _set_stimulus
|
||||||
var follow_mouse: bool = false
|
var follow_mouse: bool = false
|
||||||
var current_anchor: CanvasItem
|
var current_anchor: CanvasItem
|
||||||
|
|
||||||
|
@onready var area: Area2D = $Area2D
|
||||||
|
@onready var label: Label = %Label
|
||||||
|
@onready var right_fx: RightFX = $RightFX
|
||||||
|
@onready var wrong_fx: WrongFX = $WrongFX
|
||||||
|
|
||||||
|
|
||||||
func right() -> void:
|
func right() -> void:
|
||||||
right_fx.play()
|
right_fx.play()
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user