Show.gd 5.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212
  1. class_name Show
  2. extends Node2D
  3. # Manage slide cycling
  4. signal end_reached
  5. const VOID_SLIDE_ID := -1
  6. @export_group("Slide management")
  7. @export var start_slide := 0 ## Id of the slide focused at startup
  8. @export var home_slide := -1 ## Id of the slide to focus when triggering "Home Slide" action ; fallback to start_slide id when negative
  9. @export var hide_slides := false ## Hide every slide at startup (except the ones with always_visible enabled)
  10. @export_group("Input setup", "action_")
  11. @export var action_finish_slide := "ui_accept"
  12. @export var action_skip_slide := "ui_right"
  13. @export var action_previous_slide := "ui_left"
  14. @export var action_home_slide := "ui_cancel"
  15. @export_group("Export")
  16. @export var one_slide_per_frame := true
  17. @export var quit_after_last_slide := true
  18. var current_id := VOID_SLIDE_ID
  19. var current_slide: Slide
  20. @onready var focus: Focus = $"../Focus"
  21. @onready var slides: Array = get_children()
  22. @onready var movie_enabled: bool = OS.has_feature("movie")
  23. @onready var auto_next_slide: bool = movie_enabled and one_slide_per_frame
  24. func _ready() -> void:
  25. _enforce()
  26. print("The show contains %s slides" % slides.size())
  27. if hide_slides:
  28. _hide_every_slide()
  29. _global_slide_setup()
  30. if auto_next_slide:
  31. end_reached.connect(get_tree().quit)
  32. return
  33. go_slowly_to_next_slide()
  34. func _process(_delta: float) -> void:
  35. if auto_next_slide:
  36. go_fast_to_next_slide()
  37. func go_slowly_to_next_slide() -> void:
  38. next_slide(Focus.Transit.SMOOTH)
  39. func go_fast_to_next_slide() -> void:
  40. next_slide(Focus.Transit.BEAM)
  41. func go_fast_to_previous_slide() -> void:
  42. next_slide_at(_previous_id(), Focus.Transit.BEAM)
  43. func next_slide(trans: Focus.Transit) -> void:
  44. next_slide_at(_next_id(), trans)
  45. func next_slide_at(next_id: int, trans: Focus.Transit) -> void:
  46. _disable_current_slide()
  47. current_id = next_id
  48. current_slide = _focus_slide(current_id, trans)
  49. if is_last_slide():
  50. end_reached.emit()
  51. _enable_current_slide()
  52. func is_last_slide() -> bool:
  53. return current_id == _last_slide_id()
  54. func _focus_slide(id: int, trans: Focus.Transit) -> Slide:
  55. var slide: Slide = slides[id]
  56. focus.focus_on(slide.get_center(), slide.get_scale().x, trans)
  57. return slide
  58. func _hide_every_slide() -> void:
  59. for slide in slides:
  60. slide.gently_hide()
  61. func _global_slide_setup() -> void:
  62. for slide in slides:
  63. slide.set_action_finish(action_finish_slide)
  64. func _disable_current_slide() -> void:
  65. if current_slide != null:
  66. current_slide.disable()
  67. current_slide.finished.disconnect(_on_current_slide_finished)
  68. func _enable_current_slide() -> void:
  69. current_slide.enable()
  70. current_slide.finished.connect(_on_current_slide_finished)
  71. func _enforce() -> void:
  72. _enforce_parameters()
  73. _enforce_children()
  74. func _enforce_parameters() -> void:
  75. assert(focus, "A Focus node must be next to the Show node")
  76. assert(start_slide >= 0,
  77. "Negative index is not supported for start_slide")
  78. assert(start_slide < slides.size(),
  79. "start_slide index is out of bound (max is %s)" % (_last_slide_id()))
  80. assert(home_slide < slides.size(),
  81. "home_slide index is out of bound (max is %s)" % (_last_slide_id()))
  82. func _enforce_children() -> void:
  83. assert(!slides.is_empty(), "A slideshow must contain slides")
  84. for object in slides:
  85. assert(object is Slide, "A slideshow can only contain slides but encontered %s" % object)
  86. func _next_id() -> int:
  87. if current_id == VOID_SLIDE_ID:
  88. return start_slide
  89. elif is_last_slide():
  90. return 0
  91. return current_id + 1
  92. func _previous_id() -> int:
  93. var next_id: int = current_id - 1
  94. if next_id < 0:
  95. return _last_slide_id()
  96. return next_id
  97. func _last_slide_id() -> int:
  98. return slides.size() - 1
  99. func _unhandled_key_input(event: InputEvent) -> void:
  100. if !event.is_pressed():
  101. return
  102. if event.is_action(action_skip_slide):
  103. get_viewport().set_input_as_handled()
  104. go_fast_to_next_slide()
  105. elif event.is_action(action_previous_slide):
  106. get_viewport().set_input_as_handled()
  107. go_fast_to_previous_slide()
  108. elif event.is_action(action_home_slide):
  109. get_viewport().set_input_as_handled()
  110. _reset_id_just_before_home()
  111. go_slowly_to_next_slide()
  112. func _unhandled_input(event: InputEvent) -> void:
  113. if event is InputEventMouseButton and event.is_pressed():
  114. _focus_nearest_slide_from(get_global_mouse_position())
  115. func _focus_nearest_slide_from(target_pos: Vector2) -> void:
  116. var next_slide = _search_nearest_slide_from(target_pos)
  117. var next_id = slides.find(next_slide)
  118. next_slide_at(next_id, Focus.Transit.SMOOTH)
  119. func _search_nearest_slide_from(target_pos: Vector2) -> Slide:
  120. var nearest_slide = current_slide
  121. var shortest_distance = target_pos.distance_squared_to(nearest_slide.get_center())
  122. for current_slide in slides:
  123. var current_distance = target_pos.distance_squared_to(current_slide.get_center())
  124. if current_distance < shortest_distance:
  125. nearest_slide = current_slide
  126. shortest_distance = current_distance
  127. return nearest_slide
  128. func _reset_id_just_before_home() -> void:
  129. var home_id = _get_home_slide_id()
  130. current_id = home_id - 1
  131. ## Get Home slide id, with backup
  132. func _get_home_slide_id() -> int:
  133. if home_slide >= 0:
  134. return home_slide
  135. elif start_slide >= 0:
  136. return start_slide
  137. else:
  138. return 0
  139. func _on_current_slide_finished() -> void:
  140. go_slowly_to_next_slide()