{-# LANGUAGE BangPatterns #-}
{-|
Module      : Client.Image
Description : UI renderer
Copyright   : (c) Eric Mertens, 2016
License     : ISC
Maintainer  : emertens@gmail.com

This module provides the renderer for the client's UI.

-}
module Client.Image (clientPicture) where

import           Client.Image.Layout
import           Client.State
import           Control.Lens
import           Graphics.Vty            (Background (..), Cursor (..),
                                          Picture (..))
import           Graphics.Vty.Image

-- | Generate a 'Picture' for the current client state. The resulting
-- client state is updated for render specific information like scrolling.
clientPicture :: ClientState -> (Picture, ClientState)
clientPicture :: ClientState -> (Picture, ClientState)
clientPicture ClientState
st = (Picture
pic, ClientState
st')
    where
      (Int
row, Int
col, Image
img, ClientState
st') = ClientState -> (Int, Int, Image, ClientState)
clientImage ClientState
st
      pic :: Picture
pic = Picture :: Cursor -> [Image] -> Background -> Picture
Picture
              { picCursor :: Cursor
picCursor     = Int -> Int -> Cursor
AbsoluteCursor Int
col (Getting Int ClientState Int -> ClientState -> Int
forall s (m :: * -> *) a. MonadReader s m => Getting a s a -> m a
view Getting Int ClientState Int
Lens' ClientState Int
clientHeight ClientState
st Int -> Int -> Int
forall a. Num a => a -> a -> a
- Int
row)
              , picBackground :: Background
picBackground = Background
ClearBackground
              , picLayers :: [Image]
picLayers     = [Image
img]
              }

-- | Primary UI render logic
clientImage ::
  ClientState               {- ^ client state -} ->
  (Int, Int, Image, ClientState) {- ^ cursor row, cursor col, image, updated state -}
clientImage :: ClientState -> (Int, Int, Image, ClientState)
clientImage ClientState
st = (Int
row, Int
col, Image
img, ClientState
st')
  where
    -- update client state for scroll clamp
    !st' :: ClientState
st' = ASetter ClientState ClientState Int Int
-> Int -> ClientState -> ClientState
forall s t a b. ASetter s t a b -> b -> s -> t
set ASetter ClientState ClientState Int Int
Lens' ClientState Int
clientTextBoxOffset Int
nextOffset
         (ClientState -> ClientState) -> ClientState -> ClientState
forall a b. (a -> b) -> a -> b
$ ASetter ClientState ClientState Int Int
-> (Int -> Int) -> ClientState -> ClientState
forall s t a b. ASetter s t a b -> (a -> b) -> s -> t
over ASetter ClientState ClientState Int Int
Lens' ClientState Int
clientScroll (Int -> Int -> Int
forall a. Ord a => a -> a -> a
max Int
0 (Int -> Int) -> (Int -> Int) -> Int -> Int
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Int -> Int -> Int
forall a. Num a => a -> a -> a
subtract Int
overscroll) ClientState
st

    (Int
overscroll, Int
row, Int
col, Int
nextOffset, Image
img) = ClientState -> (Int, Int, Int, Int, Image)
drawLayout ClientState
st