aboutsummaryrefslogtreecommitdiff
path: root/src/Chelleport/AppShell.hs
blob: 06ffa1a6acac688ae5f818671f20eca8e4fb46c6 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
module Chelleport.AppShell where

import Chelleport.Config
import Chelleport.Control (MonadControl (releaseMouseButton))
import Chelleport.Types
import Control.Monad.IO.Class (MonadIO (liftIO))
import Control.Monad.RWS (MonadReader (ask), asks)
import qualified Graphics.X11 as X11
import SDL (($=))
import qualified SDL
import System.Exit (exitSuccess)

class (Monad m) => MonadAppShell m where
  hideWindow :: m ()
  showWindow :: m ()
  shutdownApp :: m ()

instance (MonadIO m) => MonadAppShell (AppM m) where
  hideWindow = asks ctxWindow >>= SDL.hideWindow
  showWindow = asks ctxWindow >>= SDL.showWindow
  shutdownApp = do
    ctx <- ask
    SDL.destroyRenderer $ ctxRenderer ctx
    SDL.destroyWindow $ ctxWindow ctx
    releaseMouseButton
    SDL.quit
    liftIO $ do
      X11.closeDisplay $ ctxX11Display ctx
      exitSuccess

type Flush m = m ()

type Update m state appAction = Flush m -> state -> appAction -> m (state, Maybe appAction)

type EventHandler state appAction = state -> SDL.Event -> Maybe appAction

type View m state = state -> m ()

type Initializer m state appAction = m (state, Maybe appAction)

setupAppShell ::
  (MonadIO m, Show state) =>
  DrawContext ->
  Initializer m state appAction ->
  Update m state appAction ->
  EventHandler state appAction ->
  View m state ->
  m ()
setupAppShell (DrawContext {ctxRenderer = renderer}) getInitState update eventHandler draw = do
  state <- getInitState >>= evalUpdateResult
  appLoop state
  where
    appLoop currentState = do
      renderScreen currentState
      newState <- SDL.waitEvent >>= evaluateEvent currentState
      appLoop newState

    renderScreen state = do
      SDL.rendererDrawColor renderer $= colorBackground
      SDL.clear renderer
      draw state
      SDL.present renderer

    evaluateEvent state event =
      maybe (pure state) (updateState state) (eventHandler state event)

    updateState state action =
      update (renderScreen state) state action >>= evalUpdateResult

    evalUpdateResult (state, Nothing) = pure state
    evalUpdateResult (state, Just action) = updateState state action