Show.gd 4.4 KB

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