diff --git a/Slideshow.gd b/Slideshow.gd index 3f3f68e..cf4c8d9 100644 --- a/Slideshow.gd +++ b/Slideshow.gd @@ -1,26 +1,65 @@ extends Control +class_name Slideshow + @onready var button_next := %Next @onready var button_previous := %Previous @onready var content := %Content @onready var frame := %Frame -var current_index := 0 -var duration := 0.5 +@export var transition_duration := 0.5 +@export var time_per_slide := 5.0 +@export var enable_timed_slides := true +@export var enable_slide_inputs := true +var _current_slide_index := 0 +var _slide_reset_time := 0.0 +var _block_inputs := false + + +func add_content(new_content: Control) -> void: + content.add_child(new_content) + if content.get_child_count() > 1: + _show_buttons(true) + func _ready() -> void: _initialize() +func _physics_process(delta: float) -> void: + if enable_timed_slides: + time_per_slide -= delta + # time's up so go to next slide and reset time + if time_per_slide <= 0: + _cycle_next() + time_per_slide = _slide_reset_time + + func _initialize() -> void: button_next.pressed.connect(_cycle_next) button_previous.pressed.connect(_cycle_previous) + content.gui_input.connect(_handle_input) + + # set the temporary variable to hold the value + _slide_reset_time = time_per_slide # move all slides off screen and fit to content frame (if not ignoring sizes) _content_fit_size() _content_reset_positions() - var initial_slide := content.get_child(0) - initial_slide.set_position(content.get_position()) + + # set the initial slide position if it exists + if content.get_child_count() > 0: + var initial_slide := content.get_child(_current_slide_index) + initial_slide.set_position(content.get_position()) + + # hide the next/previous buttons if slides <= 1 + if content.get_child_count() <= 1: + _show_buttons(false) + + +func _show_buttons(is_visible: bool) -> void: + button_next.set_visible(is_visible) + button_previous.set_visible(is_visible) func _content_fit_size() -> void: @@ -29,6 +68,7 @@ func _content_fit_size() -> void: func _content_reset_positions() -> void: + # move all slides off the screen to the left for slide in content.get_children(): slide.set_position( Vector2( @@ -38,73 +78,119 @@ func _content_reset_positions() -> void: ) +func _set_to_frame_left(slide: Control) -> void: + slide.set_position( + Vector2( + frame.get_position().x - frame.get_size().x, + slide.get_position().y + ) + ) + + +func _set_to_frame_right(slide: Control) -> void: + slide.set_position( + Vector2( + frame.get_position().x + frame.get_size().x, + slide.get_position().y + ) + ) + + +func _set_slide() -> void: + # TODO: add a way to go directly to slide in deck + pass + + func _cycle_next() -> void: - # get the index of the next node - var next_index := current_index + 1 + # if there's only one node or less or inputs are blocked, do nothing var slide_count := content.get_child_count() + if slide_count <= 1 or _block_inputs: + return + + # set variable to block trying to cycle to next/previous slide + _block_inputs = true + + # get the index of the next node + var next_index := _current_slide_index + 1 if next_index >= slide_count: next_index = 0 # set the initial position of next slide to the left of content before moving - var next_node := content.get_child(next_index) - next_node.set_position( - Vector2( - frame.get_position().x - content.get_size().x, - content.get_position().y - ) - ) + var next_slide := content.get_child(next_index) + _set_to_frame_left(next_slide) # slide the current and next nodes to the right simultaneously - var current_slide := content.get_child(current_index) + var current_slide := content.get_child(_current_slide_index) var tween := get_tree().create_tween().set_parallel(true) tween.tween_property( current_slide, "position:x", frame.get_position().x + frame.get_size().x, # at end of frame - duration + transition_duration ).set_trans(Tween.TRANS_CUBIC) tween.tween_property( - next_node, + next_slide, "position:x", - content.get_position().x, # at beginning of content - duration + frame.get_position().x, # target position + transition_duration ).set_trans(Tween.TRANS_CUBIC) + tween.chain().tween_callback(func() -> void: _block_inputs = false) # set the current index to the next one - current_index = next_index + _current_slide_index = next_index + time_per_slide = _slide_reset_time func _cycle_previous() -> void: - # get the index of the previous node - var previous_index := current_index - 1 + # if there's only one node or less or inputs are blocked, do nothing var slide_count := content.get_child_count() + if slide_count <= 1 or _block_inputs: + return + + # set variable to block trying to cycle to next/previous slide + _block_inputs = true + + # get the index of the previous node + var previous_index := _current_slide_index - 1 if previous_index < 0: previous_index = slide_count - 1 # set the initial position of previous slide to the right of content before moving - var previous_node := content.get_child(previous_index) - previous_node.set_position( - Vector2( - content.get_position().x + content.get_size().x, - content.get_position().y - ) - ) + var previous_slide := content.get_child(previous_index) + _set_to_frame_right(previous_slide) # slide the current and previous nodes to the left simultaneously - var current_slide := content.get_child(current_index) + var current_slide := content.get_child(_current_slide_index) var tween := get_tree().create_tween().set_parallel(true) tween.tween_property( current_slide, "position:x", frame.get_position().x - frame.get_size().x, # at left of frame - duration + transition_duration ).set_trans(Tween.TRANS_CUBIC) tween.tween_property( - previous_node, + previous_slide, "position:x", - content.get_position().x, # at beginning of content - duration + frame.get_position().x, # target position + transition_duration ).set_trans(Tween.TRANS_CUBIC) + tween.chain().tween_callback(func() -> void: _block_inputs = false) - # set the current index to the previous one - current_index = previous_index + # set the current index to the previous one and reset timer + _current_slide_index = previous_index + time_per_slide = _slide_reset_time + + +func _handle_input(event: InputEvent) -> void: + # handle inputs if enabled + if !enable_slide_inputs: + return + + # handle left and mouse clicks from mouse buttons only + if event is InputEventMouseButton: + if event.button_index == MOUSE_BUTTON_LEFT and event.is_released(): + _cycle_next() + if event.button_index == MOUSE_BUTTON_RIGHT and event.is_released(): + _cycle_previous() + + # TODO: handle events from touch screen diff --git a/Slideshow.tscn b/Slideshow.tscn index 0796316..b6885c5 100644 --- a/Slideshow.tscn +++ b/Slideshow.tscn @@ -33,15 +33,7 @@ size_flags_horizontal = 3 size_flags_vertical = 3 alignment = 1 -[node name="Previous" type="TextureButton" parent="Container/ScrollContainer/Frame"] -unique_name_in_owner = true -layout_mode = 2 -keep_pressed_outside = true -texture_normal = ExtResource("1_4ts6c") -stretch_mode = 3 - [node name="ContentFrame" type="PanelContainer" parent="Container/ScrollContainer/Frame"] -clip_children = 1 layout_mode = 2 size_flags_horizontal = 3 @@ -61,6 +53,8 @@ layout_mode = 1 anchors_preset = 15 anchor_right = 1.0 anchor_bottom = 1.0 +offset_left = 104.0 +offset_right = 104.0 grow_horizontal = 2 grow_vertical = 2 size_flags_horizontal = 3 @@ -70,8 +64,9 @@ expand_mode = 1 [node name="TextureRect2" type="TextureRect" parent="Container/ScrollContainer/Frame/ContentFrame/MarginContainer/Content"] custom_minimum_size = Vector2(300, 200) layout_mode = 2 +offset_left = 104.0 offset_top = 260.0 -offset_right = 912.0 +offset_right = 1016.0 offset_bottom = 516.0 size_flags_horizontal = 3 texture = ExtResource("3_a1d3h") @@ -80,16 +75,34 @@ expand_mode = 1 [node name="TextureRect3" type="TextureRect" parent="Container/ScrollContainer/Frame/ContentFrame/MarginContainer/Content"] custom_minimum_size = Vector2(200, 100) layout_mode = 2 -offset_left = 516.0 -offset_right = 1028.0 +offset_left = 620.0 +offset_right = 1132.0 offset_bottom = 608.0 size_flags_horizontal = 3 texture = ExtResource("3_a1d3h") expand_mode = 1 -[node name="Next" type="TextureButton" parent="Container/ScrollContainer/Frame"] +[node name="Previous" type="TextureButton" parent="Container/ScrollContainer/Frame/ContentFrame"] unique_name_in_owner = true +custom_minimum_size = Vector2(70, 0) layout_mode = 2 +size_flags_horizontal = 0 +keep_pressed_outside = true +texture_normal = ExtResource("1_4ts6c") +ignore_texture_size = true +stretch_mode = 5 + +[node name="Next" type="TextureButton" parent="Container/ScrollContainer/Frame/ContentFrame"] +unique_name_in_owner = true +custom_minimum_size = Vector2(70, 0) +layout_mode = 2 +size_flags_horizontal = 8 keep_pressed_outside = true texture_normal = ExtResource("2_15q3q") -stretch_mode = 3 +ignore_texture_size = true +stretch_mode = 5 + +[node name="Test" type="Control" parent="."] +anchors_preset = 0 +offset_right = 40.0 +offset_bottom = 40.0