extends Node class_name ContainerTween signal finished enum AnimateOrder { AS_IS, TOP_TO_BOTTOM, BOTTOM_TO_TOP, LEFT_TO_RIGHT, RIGHT_TO_LEFT } @export_group("Settings") @export var targets: Array[Control] @export var runtime_target_parent: Control @export var tween_types: Array[String] = ["punch_in"] @export var order: AnimateOrder = AnimateOrder.AS_IS @export var stagger_delay: float = 0.05 @export var show_on_start: bool = false @export var hide_on_finish: bool = false @export var reset_state_on_start: bool = true @export var max_targets: int = 9 var _tween_generation: int = 0 var is_running: bool = false func start_tween() -> void: if is_running: return is_running = true _tween_generation += 1 var current_gen = _tween_generation var sorted_targets: Array[Control] = _get_current_targets() match order: AnimateOrder.TOP_TO_BOTTOM: sorted_targets.sort_custom(func(a, b): return a.global_position.y < b.global_position.y) AnimateOrder.BOTTOM_TO_TOP: sorted_targets.sort_custom(func(a, b): return a.global_position.y > b.global_position.y) AnimateOrder.LEFT_TO_RIGHT: sorted_targets.sort_custom(func(a, b): return a.global_position.x < b.global_position.x) AnimateOrder.RIGHT_TO_LEFT: sorted_targets.sort_custom(func(a, b): return a.global_position.x > b.global_position.x) var last_tween: Tween = null for target in sorted_targets: if current_gen != _tween_generation: return if is_instance_valid(target): target.set_meta("pre_tween_mouse_filter", target.mouse_filter) target.mouse_filter = Control.MOUSE_FILTER_IGNORE if reset_state_on_start: target.scale = Vector2.ONE target.modulate.a = 1.0 if show_on_start: target.show() for type in tween_types: var tween = TweenFX.call(type, target) if tween is Tween: last_tween = tween if hide_on_finish and tween is Tween: tween.tween_callback(target.hide) if stagger_delay > 0.0: await get_tree().create_timer(stagger_delay).timeout if is_instance_valid(last_tween) and last_tween.is_running(): await last_tween.finished if current_gen == _tween_generation: is_running = false _restore_mouse_filters(sorted_targets) finished.emit() func stop_tween() -> void: is_running = false _tween_generation += 1 var current_targets: Array[Control] = _get_current_targets() _restore_mouse_filters(current_targets) for target in current_targets: if is_instance_valid(target): TweenFX.stop_all(target) func _restore_mouse_filters(targets_array: Array[Control]) -> void: for target in targets_array: if is_instance_valid(target) and target.has_meta("pre_tween_mouse_filter"): target.mouse_filter = target.get_meta("pre_tween_mouse_filter") target.remove_meta("pre_tween_mouse_filter") func _get_current_targets() -> Array[Control]: var current_targets: Array[Control] = [] if not targets.is_empty(): current_targets = targets.duplicate() elif runtime_target_parent != null: for child in runtime_target_parent.get_children(): var target := child as Control if target != null: current_targets.append(target) if max_targets > 0 and current_targets.size() > max_targets: return current_targets.slice(0, max_targets) return current_targets