module System.Terminal.MonadScreen where

import           System.Terminal.MonadPrinter

data Size = Size
    { Size -> Int
height :: {-# UNPACK #-} !Int
    , Size -> Int
width  :: {-# UNPACK #-} !Int
    } deriving (Size -> Size -> Bool
(Size -> Size -> Bool) -> (Size -> Size -> Bool) -> Eq Size
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
$c== :: Size -> Size -> Bool
== :: Size -> Size -> Bool
$c/= :: Size -> Size -> Bool
/= :: Size -> Size -> Bool
Eq, Eq Size
Eq Size =>
(Size -> Size -> Ordering)
-> (Size -> Size -> Bool)
-> (Size -> Size -> Bool)
-> (Size -> Size -> Bool)
-> (Size -> Size -> Bool)
-> (Size -> Size -> Size)
-> (Size -> Size -> Size)
-> Ord Size
Size -> Size -> Bool
Size -> Size -> Ordering
Size -> Size -> Size
forall a.
Eq a =>
(a -> a -> Ordering)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> a)
-> (a -> a -> a)
-> Ord a
$ccompare :: Size -> Size -> Ordering
compare :: Size -> Size -> Ordering
$c< :: Size -> Size -> Bool
< :: Size -> Size -> Bool
$c<= :: Size -> Size -> Bool
<= :: Size -> Size -> Bool
$c> :: Size -> Size -> Bool
> :: Size -> Size -> Bool
$c>= :: Size -> Size -> Bool
>= :: Size -> Size -> Bool
$cmax :: Size -> Size -> Size
max :: Size -> Size -> Size
$cmin :: Size -> Size -> Size
min :: Size -> Size -> Size
Ord, Int -> Size -> ShowS
[Size] -> ShowS
Size -> String
(Int -> Size -> ShowS)
-> (Size -> String) -> ([Size] -> ShowS) -> Show Size
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
$cshowsPrec :: Int -> Size -> ShowS
showsPrec :: Int -> Size -> ShowS
$cshow :: Size -> String
show :: Size -> String
$cshowList :: [Size] -> ShowS
showList :: [Size] -> ShowS
Show)

data Position = Position
    { Position -> Int
row    :: {-# UNPACK #-} !Int
    , Position -> Int
col    :: {-# UNPACK #-} !Int
    } deriving (Position -> Position -> Bool
(Position -> Position -> Bool)
-> (Position -> Position -> Bool) -> Eq Position
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
$c== :: Position -> Position -> Bool
== :: Position -> Position -> Bool
$c/= :: Position -> Position -> Bool
/= :: Position -> Position -> Bool
Eq, Eq Position
Eq Position =>
(Position -> Position -> Ordering)
-> (Position -> Position -> Bool)
-> (Position -> Position -> Bool)
-> (Position -> Position -> Bool)
-> (Position -> Position -> Bool)
-> (Position -> Position -> Position)
-> (Position -> Position -> Position)
-> Ord Position
Position -> Position -> Bool
Position -> Position -> Ordering
Position -> Position -> Position
forall a.
Eq a =>
(a -> a -> Ordering)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> a)
-> (a -> a -> a)
-> Ord a
$ccompare :: Position -> Position -> Ordering
compare :: Position -> Position -> Ordering
$c< :: Position -> Position -> Bool
< :: Position -> Position -> Bool
$c<= :: Position -> Position -> Bool
<= :: Position -> Position -> Bool
$c> :: Position -> Position -> Bool
> :: Position -> Position -> Bool
$c>= :: Position -> Position -> Bool
>= :: Position -> Position -> Bool
$cmax :: Position -> Position -> Position
max :: Position -> Position -> Position
$cmin :: Position -> Position -> Position
min :: Position -> Position -> Position
Ord, Int -> Position -> ShowS
[Position] -> ShowS
Position -> String
(Int -> Position -> ShowS)
-> (Position -> String) -> ([Position] -> ShowS) -> Show Position
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
$cshowsPrec :: Int -> Position -> ShowS
showsPrec :: Int -> Position -> ShowS
$cshow :: Position -> String
show :: Position -> String
$cshowList :: [Position] -> ShowS
showList :: [Position] -> ShowS
Show)

data EraseMode
    = EraseBackward  -- ^ Erase left of/above current cursor position.
    | EraseForward   -- ^ Erase right of/below current cursor position.
    | EraseAll       -- ^ Erase whole line/screen.
    deriving (EraseMode -> EraseMode -> Bool
(EraseMode -> EraseMode -> Bool)
-> (EraseMode -> EraseMode -> Bool) -> Eq EraseMode
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
$c== :: EraseMode -> EraseMode -> Bool
== :: EraseMode -> EraseMode -> Bool
$c/= :: EraseMode -> EraseMode -> Bool
/= :: EraseMode -> EraseMode -> Bool
Eq, Eq EraseMode
Eq EraseMode =>
(EraseMode -> EraseMode -> Ordering)
-> (EraseMode -> EraseMode -> Bool)
-> (EraseMode -> EraseMode -> Bool)
-> (EraseMode -> EraseMode -> Bool)
-> (EraseMode -> EraseMode -> Bool)
-> (EraseMode -> EraseMode -> EraseMode)
-> (EraseMode -> EraseMode -> EraseMode)
-> Ord EraseMode
EraseMode -> EraseMode -> Bool
EraseMode -> EraseMode -> Ordering
EraseMode -> EraseMode -> EraseMode
forall a.
Eq a =>
(a -> a -> Ordering)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> a)
-> (a -> a -> a)
-> Ord a
$ccompare :: EraseMode -> EraseMode -> Ordering
compare :: EraseMode -> EraseMode -> Ordering
$c< :: EraseMode -> EraseMode -> Bool
< :: EraseMode -> EraseMode -> Bool
$c<= :: EraseMode -> EraseMode -> Bool
<= :: EraseMode -> EraseMode -> Bool
$c> :: EraseMode -> EraseMode -> Bool
> :: EraseMode -> EraseMode -> Bool
$c>= :: EraseMode -> EraseMode -> Bool
>= :: EraseMode -> EraseMode -> Bool
$cmax :: EraseMode -> EraseMode -> EraseMode
max :: EraseMode -> EraseMode -> EraseMode
$cmin :: EraseMode -> EraseMode -> EraseMode
min :: EraseMode -> EraseMode -> EraseMode
Ord, Int -> EraseMode -> ShowS
[EraseMode] -> ShowS
EraseMode -> String
(Int -> EraseMode -> ShowS)
-> (EraseMode -> String)
-> ([EraseMode] -> ShowS)
-> Show EraseMode
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
$cshowsPrec :: Int -> EraseMode -> ShowS
showsPrec :: Int -> EraseMode -> ShowS
$cshow :: EraseMode -> String
show :: EraseMode -> String
$cshowList :: [EraseMode] -> ShowS
showList :: [EraseMode] -> ShowS
Show)

class (MonadPrinter m) => MonadScreen m where
    -- | Get the dimensions of the visible window.
    getWindowSize               :: m Size
    -- | Move the cursor `n` lines up. Do not change column.
    moveCursorUp                :: Int -> m ()
    -- | Move the cursor `n` lines down. Do not change column.
    moveCursorDown              :: Int -> m ()
    -- | Move the cursor `n` columns to the right. Do not change line.
    moveCursorForward           :: Int -> m ()
    -- | Move the cursor `n` columns to the left. Do not change line.
    moveCursorBackward          :: Int -> m ()
    -- | Get the current cursor position as reported by the terminal.
    --
    -- * @Position 0 0@ is the upper left of the window.
    -- * The cursor is always within window bounds.
    -- * This operation causes a round-trip to the terminal and
    --   shall be used sparely (e.g. on window size change).
    getCursorPosition           :: m Position
    -- | Set the cursor position.
    --
    -- * @Position 0 0@ is the upper left of the window.
    -- * The resulting cursor position is undefined when it is outside
    --   the window bounds.
    setCursorPosition           :: Position -> m ()
    -- | Set the cursor row.
    --
    -- * @0@ is the topmost row.
    setCursorRow                :: Int -> m ()
    -- | Set the cursor column.
    --
    -- * @0@ is the leftmost column.
    setCursorColumn             :: Int -> m ()
    -- | Save cursor position and attributes.
    saveCursor                  :: m ()
    -- | Restore cursor position and attributes.
    --
    -- * Restores the cursor as previously saved by `saveCursor`.
    -- * The cursor position is strictly relative to the visible
    --   window and does not take eventual scrolling into account.
    --   The advantage of this operation is that it does not require
    --   transmission of coordinates and attributes to the terminal
    --   and is therefor slightly more efficient than all other alternatives.
    -- * Only use this when auto-wrap is disabled, alternate screen
    --   buffer is enabled or you can otherwise guarantee that the
    --   window does not scroll between `saveCursor` and `restoreCursor`!
    restoreCursor               :: m ()
    -- | Insert whitespace at the cursor position and
    --   shift existing characters to the right.
    insertChars                 :: Int -> m ()
    -- | Delete characters and shift existing characters from the right.
    deleteChars                 :: Int -> m ()
    -- | Replace characters with whitespace.
    eraseChars                  :: Int -> m ()
    -- | Insert lines and shift existing lines downwards.
    insertLines                 :: Int -> m ()
    -- | Delete lines and shift up existing lines from below.
    deleteLines                 :: Int -> m ()
    -- | Clears characters in the current line.
    eraseInLine                 :: EraseMode -> m ()
    -- | Clears lines above/below the current line.
    eraseInDisplay              :: EraseMode -> m ()
    -- | Show the cursor.
    showCursor                  :: m ()
    -- | Hide the cursor.
    hideCursor                  :: m ()
    -- | Whether or not to automatically wrap on line ends.
    setAutoWrap                 :: Bool -> m ()
    -- | Whether or not to use the alternate screen buffer.
    --
    --   - The main screen buffer content is preserved and restored
    --     when leaving the alternate screen screen buffer.
    --   - The dimensions of the alternate screen buffer are
    --     exactly those of the screen.
    setAlternateScreenBuffer    :: Bool -> m ()