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 sys
import time
from enum import Enum, IntEnum, auto, unique
from enum import Enum, IntFlag, auto, unique
from pathlib import Path
from typing import Any, Dict, List, Optional, Tuple, Union
@ -52,16 +52,20 @@ RESIZE_MODES = {
@unique
class State(IntEnum):
class State(IntFlag):
"""Represents all possible states of a slide presentation."""
"""A video is actively being played."""
PLAYING = auto()
"""A video was manually paused."""
PAUSED = auto()
"""Waiting for user to press next (or else)."""
WAIT = auto()
"""Presentation was terminated."""
END = auto()
def __str__(self) -> str:
return self.name.capitalize()
return self.name.capitalize() # type: ignore
def now() -> float:
@ -271,10 +275,10 @@ class Presentation:
def load_last_slide(self) -> None:
"""Loads last slide."""
self.current_slide_index = len(self.slides) - 2
self.current_slide_index = len(self.slides) - 1
assert (
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.load_animation_cap(self.current_animation)
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 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:
_, self.lastframe = self.current_cap.read()
return self.lastframe, state
still_playing, frame = self.current_cap.read()
if still_playing:
self.lastframe = frame
elif state == state.WAIT or state == state.PAUSED: # type: ignore
return self.lastframe, state
elif self.current_slide.is_last() and self.current_slide.terminated:
return self.lastframe, State.END
else: # not still playing
if self.is_last_animation:
if self.current_slide.is_slide():
return self.lastframe, State.PLAYING
# Video was terminated
if self.is_last_animation:
if self.current_slide.is_loop():
if self.reverse:
state = State.WAIT
elif self.current_slide.is_loop():
if self.reverse:
state = State.WAIT
else:
self.current_animation = self.current_slide.start_animation
state = State.PLAYING
self.rewind_current_slide()
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:
self.current_animation = self.current_slide.start_animation
state = State.PLAYING
self.rewind_current_slide()
elif self.current_slide.is_last():
state = State.END
else:
# Play next video!
self.current_animation = self.next_animation
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)
state = State.WAIT
else:
# Play next video!
self.current_animation = self.next_animation
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
@ -423,6 +423,11 @@ class Display(QThread): # type: ignore
"""Returns the background color of the current presentation."""
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:
"""Runs a series of presentations until end or exit."""
while self.run_flag:
@ -430,18 +435,15 @@ class Display(QThread): # type: ignore
self.lastframe, self.state = self.current_presentation.update_state(
self.state
)
if self.state == State.PLAYING or self.state == State.PAUSED:
if self.state & (State.PLAYING | State.PAUSED):
if self.start_paused:
self.state = State.PAUSED
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.exit_after_last_slide:
self.run_flag = False
continue
else:
self.current_presentation_index += 1
self.state = State.PLAYING
self.handle_key()
self.show_video()
@ -548,10 +550,14 @@ class Display(QThread): # type: ignore
self.state = State.PAUSED
elif self.state == State.PAUSED and keys.PLAY_PAUSE.match(key):
self.state = State.PLAYING
elif self.state == State.WAIT and (
keys.CONTINUE.match(key) or keys.PLAY_PAUSE.match(key)
elif self.state & (State.END | State.WAIT) and (
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
elif (
self.state == State.PLAYING and keys.CONTINUE.match(key)
@ -562,6 +568,7 @@ class Display(QThread): # type: ignore
if self.current_presentation_index == 0:
self.current_presentation.load_previous_slide()
else:
self.current_presentation.cancel_reverse()
self.current_presentation_index -= 1
self.current_presentation.load_last_slide()
self.state = State.PLAYING