fix(present): finish up state machine

This commit is contained in:
Jérome Eertmans
2023-08-04 16:03:52 +02:00
parent aace5dea11
commit 0f9048a27b

View File

@ -3,7 +3,7 @@ import platform
import signal import signal
import sys import sys
import time import time
from enum import Enum, IntEnum, auto, unique from enum import Enum, IntFlag, auto, unique
from pathlib import Path from pathlib import Path
from typing import Any, Dict, List, Optional, Tuple, Union from typing import Any, Dict, List, Optional, Tuple, Union
@ -52,16 +52,20 @@ RESIZE_MODES = {
@unique @unique
class State(IntEnum): class State(IntFlag):
"""Represents all possible states of a slide presentation.""" """Represents all possible states of a slide presentation."""
"""A video is actively being played."""
PLAYING = auto() PLAYING = auto()
"""A video was manually paused."""
PAUSED = auto() PAUSED = auto()
"""Waiting for user to press next (or else)."""
WAIT = auto() WAIT = auto()
"""Presentation was terminated."""
END = auto() END = auto()
def __str__(self) -> str: def __str__(self) -> str:
return self.name.capitalize() return self.name.capitalize() # type: ignore
def now() -> float: def now() -> float:
@ -271,10 +275,10 @@ class Presentation:
def load_last_slide(self) -> None: def load_last_slide(self) -> None:
"""Loads last slide.""" """Loads last slide."""
self.current_slide_index = len(self.slides) - 2 self.current_slide_index = len(self.slides) - 1
assert ( assert (
self.current_slide_index >= 0 self.current_slide_index >= 0
), "Slides should be at list of a least two elements" ), "Slides should be at list of a least one element"
self.current_animation = self.current_slide.start_animation self.current_animation = self.current_slide.start_animation
self.load_animation_cap(self.current_animation) self.load_animation_cap(self.current_animation)
self.slides[-1].terminated = False self.slides[-1].terminated = False
@ -307,41 +311,37 @@ class Presentation:
It does this by reading the video information and checking if the state is still correct. It does this by reading the video information and checking if the state is still correct.
It returns the frame to show (lastframe) and the new state. It returns the frame to show (lastframe) and the new state.
""" """
if state == State.PAUSED: if state ^ State.PLAYING: # If not playing, we return the same
if self.lastframe is None: if self.lastframe is None:
_, self.lastframe = self.current_cap.read() _, self.lastframe = self.current_cap.read()
return self.lastframe, state return self.lastframe, state
still_playing, frame = self.current_cap.read() still_playing, frame = self.current_cap.read()
if still_playing: if still_playing:
self.lastframe = frame self.lastframe = frame
elif state == state.WAIT or state == state.PAUSED: # type: ignore return self.lastframe, State.PLAYING
return self.lastframe, state
elif self.current_slide.is_last() and self.current_slide.terminated: # Video was terminated
return self.lastframe, State.END if self.is_last_animation:
else: # not still playing if self.current_slide.is_loop():
if self.is_last_animation: if self.reverse:
if self.current_slide.is_slide():
state = State.WAIT state = State.WAIT
elif self.current_slide.is_loop():
if self.reverse: else:
state = State.WAIT self.current_animation = self.current_slide.start_animation
else: state = State.PLAYING
self.current_animation = self.current_slide.start_animation self.rewind_current_slide()
state = State.PLAYING elif self.current_slide.is_last():
self.rewind_current_slide() state = State.END
elif self.current_slide.is_last():
self.current_slide.terminated = True
elif (
self.current_slide.is_last()
and self.current_slide.end_animation == self.current_animation
):
state = State.WAIT
else: else:
# Play next video! state = State.WAIT
self.current_animation = self.next_animation else:
self.load_animation_cap(self.current_animation) # Play next video!
# Reset video to position zero if it has been played before self.current_animation = self.next_animation
self.current_cap.set(cv2.CAP_PROP_POS_FRAMES, 0) self.load_animation_cap(self.current_animation)
# Reset video to position zero if it has been played before
self.current_cap.set(cv2.CAP_PROP_POS_FRAMES, 0)
return self.lastframe, state return self.lastframe, state
@ -423,6 +423,11 @@ class Display(QThread): # type: ignore
"""Returns the background color of the current presentation.""" """Returns the background color of the current presentation."""
return self.current_presentation.background_color return self.current_presentation.background_color
@property
def is_last_presentation(self) -> bool:
"""Returns True if current presentation is the last one."""
return self.current_presentation_index == len(self) - 1
def run(self) -> None: def run(self) -> None:
"""Runs a series of presentations until end or exit.""" """Runs a series of presentations until end or exit."""
while self.run_flag: while self.run_flag:
@ -430,18 +435,15 @@ class Display(QThread): # type: ignore
self.lastframe, self.state = self.current_presentation.update_state( self.lastframe, self.state = self.current_presentation.update_state(
self.state self.state
) )
if self.state == State.PLAYING or self.state == State.PAUSED: if self.state & (State.PLAYING | State.PAUSED):
if self.start_paused: if self.start_paused:
self.state = State.PAUSED self.state = State.PAUSED
self.start_paused = False self.start_paused = False
if self.state == State.END: if self.state & State.END:
if self.current_presentation_index == len(self.presentations) - 1: if self.current_presentation_index == len(self.presentations) - 1:
if self.exit_after_last_slide: if self.exit_after_last_slide:
self.run_flag = False self.run_flag = False
continue continue
else:
self.current_presentation_index += 1
self.state = State.PLAYING
self.handle_key() self.handle_key()
self.show_video() self.show_video()
@ -548,10 +550,14 @@ class Display(QThread): # type: ignore
self.state = State.PAUSED self.state = State.PAUSED
elif self.state == State.PAUSED and keys.PLAY_PAUSE.match(key): elif self.state == State.PAUSED and keys.PLAY_PAUSE.match(key):
self.state = State.PLAYING self.state = State.PLAYING
elif self.state == State.WAIT and ( elif self.state & (State.END | State.WAIT) and (
keys.CONTINUE.match(key) or keys.PLAY_PAUSE.match(key) keys.CONTINUE.match(key) or keys.PLAY_PAUSE.match(key) or self.skip_all
): ):
self.current_presentation.load_next_slide() if (self.state & State.END) and not self.is_last_presentation:
self.current_presentation_index += 1
self.current_presentation.rewind_current_slide()
else:
self.current_presentation.load_next_slide()
self.state = State.PLAYING self.state = State.PLAYING
elif ( elif (
self.state == State.PLAYING and keys.CONTINUE.match(key) self.state == State.PLAYING and keys.CONTINUE.match(key)
@ -562,6 +568,7 @@ class Display(QThread): # type: ignore
if self.current_presentation_index == 0: if self.current_presentation_index == 0:
self.current_presentation.load_previous_slide() self.current_presentation.load_previous_slide()
else: else:
self.current_presentation.cancel_reverse()
self.current_presentation_index -= 1 self.current_presentation_index -= 1
self.current_presentation.load_last_slide() self.current_presentation.load_last_slide()
self.state = State.PLAYING self.state = State.PLAYING