    {-# LANGUAGE DeriveFunctor #-}
    {-# LANGUAGE MultiParamTypeClasses #-}
    {-# LANGUAGE TemplateHaskell #-}
    {-# LANGUAGE DeriveGeneric #-}
    {-# LANGUAGE DeriveAnyClass #-}
    module Brick.Types.Common
      ( Location(..)
      , locL
      , origin
      , Edges(..)
      , eTopL, eBottomL, eRightL, eLeftL
      ) where

    import Brick.Types.TH (suffixLenses)
    import qualified Data.Semigroup as Sem
    import GHC.Generics
    import Control.DeepSeq
    import Lens.Micro (_1, _2)
    import Lens.Micro.Internal (Field1, Field2)

    -- | A terminal screen location.
    data Location = Location { loc :: (Int, Int)
                             -- ^ (Column, Row)
                             }
                    deriving (Show, Eq, Ord, Read, Generic, NFData)

    suffixLenses ''Location

    instance Field1 Location Location Int Int where
        _1 = locL._1

    instance Field2 Location Location Int Int where
        _2 = locL._2

    -- | The origin (upper-left corner).
    origin :: Location
    origin = Location (0, 0)

    instance Sem.Semigroup Location where
        (Location (w1, h1)) <> (Location (w2, h2)) = Location (w1+w2, h1+h2)

    instance Monoid Location where
        mempty = origin
        mappend = (Sem.<>)

    data Edges a = Edges { eTop, eBottom, eLeft, eRight :: a }
        deriving (Eq, Ord, Read, Show, Functor, Generic, NFData)

    suffixLenses ''Edges

    instance Applicative Edges where
        pure a = Edges a a a a
        Edges ft fb fl fr <*> Edges vt vb vl vr =
            Edges (ft vt) (fb vb) (fl vl) (fr vr)

    instance Monad Edges where
        Edges vt vb vl vr >>= f = Edges
            (eTop    (f vt))
            (eBottom (f vb))
            (eLeft   (f vl))
            (eRight  (f vr))