Skip to content
Snippets Groups Projects
Select Git revision
  • bdd77470739bdb23944ac3940184a70c14fbcc95
  • master default protected
  • v1.10
  • v1.9
  • v1.8
  • v1.7
  • v1.6
  • v1.5
  • v1.4
  • v1.3
  • v1.2
  • v1.1
  • v1.0
  • release-1
  • bootloader-v1
  • v0.0
16 results

board.c

Blame
  • Forked from card10 / firmware
    Source project has a limited visibility.
    view.py 6.05 KiB
    from st3m.reactor import Responder
    from st3m.goose import ABCBase, abstractmethod, Optional, List
    from st3m.input import InputState, InputController
    from st3m.ui.ctx import Ctx
    
    
    class View(Responder):
        """
        A View extends a reactor Responder with callbacks related to the Responder's
        lifecycle in terms of being foregrounded or backgrounded.
    
        These signals can be used to alter input processing, se the
        ViewWithInputState class.
        """
    
        def on_enter(self) -> None:
            """
            Called when the View has just become active. This is guaranteed to be
            called before think().
            """
            pass
    
    
    class ViewWithInputState(View):
        """
        A base class helper for implementing views which respond to inputs and who
        want to do their own, separate input processing.
    
        Derive this class, then use self.input to access the InputController.
    
        Remember to call super().think() in think()!
        """
    
        __slots__ = ("input",)
    
        def __init__(self) -> None:
            self.input = InputController()
    
        def on_enter(self) -> None:
            self.input._ignore_pressed()
    
        def think(self, ins: InputState, delta_ms: int) -> None:
            self.input.think(ins, delta_ms)
    
    
    class ViewTransition(ABCBase):
        """
        A transition from one View/Responder to another.
    
        Can be implemented by the user to provide transition animations.
        """
    
        @abstractmethod
        def draw(
            self, ctx: Ctx, transition: float, incoming: Responder, outgoing: Responder
        ) -> None:
            """
            Called when the ViewManager performs a transition from the outgoing
            responder to the incoming responder. The implementer should draw both
            Responders when appropriate.
    
            The transition value is a float from 0 to 1 which represents the
            progress of the transition.
            """
            pass
    
    
    class ViewTransitionBlend(ViewTransition):
        """
        Transition from one view to another by opacity blending.
        """
    
        def draw(
            self, ctx: Ctx, transition: float, incoming: Responder, outgoing: Responder
        ) -> None:
            ctx.start_group()
            outgoing.draw(ctx)
            ctx.end_group()
    
            ctx.start_group()
            ctx.global_alpha = transition
            incoming.draw(ctx)
            ctx.end_group()
    
    
    class ViewTransitionSwipeLeft(ViewTransition):
        """
        Swipe the outoing view to the left and replace it with the incoming view.
        """
    
        def draw(
            self, ctx: Ctx, transition: float, incoming: Responder, outgoing: Responder
        ) -> None:
            ctx.save()
            ctx.translate(transition * -240, 0)
            outgoing.draw(ctx)
            ctx.restore()
    
            ctx.save()
            ctx.translate(240 + transition * -240, 0)
            incoming.draw(ctx)
            ctx.restore()
    
    
    class ViewTransitionSwipeRight(ViewTransition):
        """
        Swipe the outoing view to the right and replace it with the incoming view.
        """
    
        def draw(
            self, ctx: Ctx, transition: float, incoming: Responder, outgoing: Responder
        ) -> None:
            ctx.save()
            ctx.translate(transition * 240, 0)
            outgoing.draw(ctx)
            ctx.restore()
    
            ctx.save()
            ctx.translate(-240 + transition * 240, 0)
            incoming.draw(ctx)
            ctx.restore()
    
    
    class ViewManager(Responder):
        """
        The ViewManager implements stateful routing between Views.
    
        It manages a history of Views, to which new Views can be pushed and then
        popped.
        """
    
        def __init__(self, vt: ViewTransition) -> None:
            """
            Create a new ViewManager with a default ViewTransition.
            """
            self._incoming: Optional[View] = None
            self._outgoing: Optional[View] = None
    
            # Transition time.
            self._time_ms = 150
    
            self._default_vt = vt
            self._overriden_vt: Optional[ViewTransition] = None
    
            self._transitioning = False
            self._transition = 0.0
            self._history: List[View] = []
    
        def think(self, ins: InputState, delta_ms: int) -> None:
            if self._transitioning:
                self._transition += (delta_ms / 1000.0) * (1000 / self._time_ms)
                if self._transition >= 1.0:
                    self._transition = 0
                    self._transitioning = False
    
                    self._outgoing = None
    
            if self._outgoing is not None:
                self._outgoing.think(ins, delta_ms)
            if self._incoming is not None:
                self._incoming.think(ins, delta_ms)
    
        def draw(self, ctx: Ctx) -> None:
            if self._transitioning:
                vt = self._default_vt
                if self._overriden_vt is not None:
                    vt = self._overriden_vt
    
                if self._incoming is not None and self._outgoing is not None:
                    vt.draw(ctx, self._transition, self._incoming, self._outgoing)
                    return
            if self._incoming is not None:
                self._incoming.draw(ctx)
    
        def replace(self, r: View, overide_vt: Optional[ViewTransition] = None) -> None:
            """
            Replace the existing view with the given View, optionally using a given
            ViewTransition instead of the default.
    
            The new view will _not_ be added to history!
            """
            self._outgoing = self._incoming
            self._incoming = r
            self._incoming.on_enter()
            self._overriden_vt = overide_vt
            if self._outgoing is None:
                return
    
            self._transitioning = True
            self._transition = 0.0
    
        def push(self, r: View, override_vt: Optional[ViewTransition] = None) -> None:
            """
            Push a View to the history stack and start transitioning to it. If set,
            override_vt will be used instead of the default ViewTransition
            animation.
            """
            if self._incoming is not None:
                self._history.append(self._incoming)
    
            self.replace(r, override_vt)
    
        def pop(self, override_vt: Optional[ViewTransition] = None) -> None:
            """
            Pop a view from the history stack and start transitioning to it. If set,
            override_vt will be used instead of the default ViewTransition
            animation.
            """
            r = self._history.pop()
            self.replace(r, override_vt)