Files
Kalulu/sources/language_tool/segment_container.gd
T
2025-09-05 15:55:48 +02:00

178 lines
5.4 KiB
GDScript

class_name SegmentContainer
extends HBoxContainer
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_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 buttons_parent: Control = %ButtonsParent
@onready var segments_container: VBoxContainer = %SegmentsContainer
@onready var lines: Node2D = %Lines
func reset() -> void:
var to_free: Array[Node] = lines.get_children()
to_free.append_array(segments_container.get_children())
for node: Node in to_free:
node.queue_free()
current_segment = null
current_button = null
await get_tree().process_frame
func load_segment(points: Array[Vector2]) -> void:
_on_add_segment_button_pressed()
current_segment.points = points
draw_segment(current_segment)
func _process(_delta: float) -> void:
lines.global_position = grapheme_label.global_position + grapheme_label.size / 2.0
draw_all_segments()
match_segment_with_buttons()
if not is_instance_valid(current_segment):
current_button = null
if is_instance_valid(current_button):
var ind: int = current_segment.remove_point(current_button.global_position - lines.global_position)
current_button.global_position = get_global_mouse_position()
current_segment.add_point_at(current_button.global_position - lines.global_position, ind)
func draw_segment(segment: SegmentBuild) -> void:
if not is_instance_valid(segment):
return
var ind_seg: int = segments_container.get_children().find(segment)
var line: Line2D = lines.get_child(ind_seg)
line.points = Bezier.bezier_sampling(segment.points, maxi(points_per_lines, segment.points.size()))
func draw_all_segments() -> void:
for segment: SegmentBuild in segments_container.get_children():
draw_segment(segment)
func match_segment_with_buttons() -> void:
var points: PackedVector2Array = []
if is_instance_valid(current_segment):
points = current_segment.points
for index: int in range(points.size()):
while index >= buttons.size():
var button: SegmentPointButton = POINT_BUTTON_SCENE.instantiate()
buttons_parent.add_child(button)
buttons.append(button)
button.point_down.connect(_on_button_point_down.bind(button))
button.point_up.connect(_on_button_point_up.bind(button))
button.minus_pressed.connect(_on_button_minus_pressed.bind(button))
buttons[index].global_position = points[index] + lines.global_position
buttons[index].set_index(index + 1)
for index: int in range(buttons.size() - 1, points.size() - 1, -1):
buttons[index].queue_free()
buttons.remove_at(index)
func _on_button_point_down(button: SegmentPointButton) -> void:
current_button = button
changed.emit()
func _on_button_point_up(_button: SegmentPointButton) -> void:
current_button = null
changed.emit()
func _on_button_minus_pressed(button: SegmentPointButton) -> void:
if is_instance_valid(current_segment):
current_segment.remove_point(button.global_position - lines.global_position)
buttons.erase(button)
button.queue_free()
changed.emit()
func _on_place_point_button_pressed() -> void:
if is_instance_valid(current_segment):
current_segment.add_point(get_global_mouse_position() - lines.global_position)
changed.emit()
func _on_add_segment_button_pressed() -> void:
# Create a new segment build instance from the scene
var new_segment: SegmentBuild = SEGMENT_BUILD_SCENE.instantiate()
segments_container.add_child(new_segment)
# Connect signals for modifying and deleting the segment
new_segment.modified.connect(_on_segment_modified.bind(new_segment))
new_segment.deleted.connect(_on_segment_deleted.bind(new_segment))
# Store the new segment as the currently selected one
current_segment = new_segment
# Create a new visual line for the segment
var segment_line: Line2D = Line2D.new()
segment_line.width = 25
segment_line.begin_cap_mode = Line2D.LINE_CAP_ROUND
segment_line.end_cap_mode = Line2D.LINE_CAP_ROUND
segment_line.joint_mode = Line2D.LINE_JOINT_ROUND
lines.add_child(segment_line)
# Compute the segment's color based on its position in the container
var segment_index: int = segments_container.get_child_count()
var gradient_position: float = float(segment_index % points_per_gradient) / float(points_per_gradient)
var segment_color: Color = gradient.sample(gradient_position)
# Apply the color to the segment and its line
new_segment.set_color(segment_color)
segment_line.default_color = segment_color
# Sync segment states with any associated UI or logic
match_segment_with_buttons()
# Notify that something has changed (e.g., for undo, saving, etc.)
changed.emit()
func _on_segment_modified(segment: SegmentBuild) -> void:
current_segment = segment
match_segment_with_buttons()
changed.emit()
func _on_segment_deleted(segment: SegmentBuild) -> void:
if segment == current_segment:
var possible_segments: Array[Node] = segments_container.get_children()
if not possible_segments.is_empty():
current_segment = possible_segments[0] as SegmentBuild
else:
current_segment = null
match_segment_with_buttons()
var ind_seg: int = segments_container.get_children().find(segment)
lines.get_child(ind_seg).queue_free()
changed.emit()