{-# LANGUAGE DeriveDataTypeable     #-}
{-# LANGUAGE FlexibleContexts       #-}
{-# LANGUAGE FlexibleInstances      #-}
{-# LANGUAGE FunctionalDependencies #-}
{-# LANGUAGE MultiParamTypeClasses  #-}
{-# LANGUAGE TemplateHaskell        #-}
{-# LANGUAGE TypeFamilies           #-}
-----------------------------------------------------------------------------
-- |
-- Module      :  Plots.Axis.Line
-- Copyright   :  (C) 2015 Christopher Chalmers
-- License     :  BSD-style (see the file LICENSE)
-- Maintainer  :  Christopher Chalmers
-- Stability   :  experimental
-- Portability :  non-portable
--
-- The lines that make up an axis.
--
----------------------------------------------------------------------------
module Plots.Axis.Line
  ( -- * Grid lines
    AxisLine
  , HasAxisLine (..)

    -- * Axis line types
  , AxisLineType (..)

  ) where

import           Control.Lens     hiding (( # ))
import           Data.Data
import           Data.Default

import           Diagrams.Prelude
import Plots.Types

-- | Where axis line for coordinate should be drawn. The 'Default' is
--   'BoxAxisLine'.
data AxisLineType
  = BoxAxisLine
  | LeftAxisLine
  | MiddleAxisLine
  | RightAxisLine
  | NoAxisLine
  deriving (Int -> AxisLineType -> ShowS
[AxisLineType] -> ShowS
AxisLineType -> String
(Int -> AxisLineType -> ShowS)
-> (AxisLineType -> String)
-> ([AxisLineType] -> ShowS)
-> Show AxisLineType
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
$cshowsPrec :: Int -> AxisLineType -> ShowS
showsPrec :: Int -> AxisLineType -> ShowS
$cshow :: AxisLineType -> String
show :: AxisLineType -> String
$cshowList :: [AxisLineType] -> ShowS
showList :: [AxisLineType] -> ShowS
Show, AxisLineType -> AxisLineType -> Bool
(AxisLineType -> AxisLineType -> Bool)
-> (AxisLineType -> AxisLineType -> Bool) -> Eq AxisLineType
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
$c== :: AxisLineType -> AxisLineType -> Bool
== :: AxisLineType -> AxisLineType -> Bool
$c/= :: AxisLineType -> AxisLineType -> Bool
/= :: AxisLineType -> AxisLineType -> Bool
Eq, Typeable)

instance Default AxisLineType where
  def :: AxisLineType
def = AxisLineType
BoxAxisLine

-- | Information about position and style of axis lines.
data AxisLine v n = AxisLine
  { forall (v :: * -> *) n. AxisLine v n -> AxisLineType
alType      :: AxisLineType
  , forall (v :: * -> *) n. AxisLine v n -> Maybe (ArrowOpts n)
alArrowOpts :: Maybe (ArrowOpts n)
  , forall (v :: * -> *) n. AxisLine v n -> Bool
alVisible   :: Bool
  , forall (v :: * -> *) n. AxisLine v n -> Style v n
alStyle     :: Style v n
  } deriving Typeable

type instance V (AxisLine v n) = v
type instance N (AxisLine v n) = n

-- | Class of object that have an 'AxisLine'.
class HasAxisLine f a where
  -- | Lens onto the 'AxisLine'.
  axisLine :: LensLike' f a (AxisLine (V a) (N a))

  -- | The position of the axis line around the axis.
  --
  --   'Default' is 'BoxAxisLine'.
  axisLineType :: Functor f => LensLike' f a AxisLineType
  axisLineType = LensLike' f a (AxisLine (V a) (N a))
forall (f :: * -> *) a.
HasAxisLine f a =>
LensLike' f a (AxisLine (V a) (N a))
axisLine LensLike' f a (AxisLine (V a) (N a))
-> ((AxisLineType -> f AxisLineType)
    -> AxisLine (V a) (N a) -> f (AxisLine (V a) (N a)))
-> LensLike' f a AxisLineType
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (AxisLine (V a) (N a) -> AxisLineType)
-> (AxisLine (V a) (N a) -> AxisLineType -> AxisLine (V a) (N a))
-> Lens
     (AxisLine (V a) (N a))
     (AxisLine (V a) (N a))
     AxisLineType
     AxisLineType
forall s a b t. (s -> a) -> (s -> b -> t) -> Lens s t a b
lens AxisLine (V a) (N a) -> AxisLineType
forall (v :: * -> *) n. AxisLine v n -> AxisLineType
alType (\AxisLine (V a) (N a)
al AxisLineType
sty -> AxisLine (V a) (N a)
al {alType = sty})

  -- | The options for if you want the axis line to have arrows at the
  --   end.
  --
  --   'Default' is 'Nothing'.
  --
  --   XXX (feature not currently implimented)
  axisLineArrowOpts :: Functor f => LensLike' f a (Maybe (ArrowOpts (N a)))
  axisLineArrowOpts = LensLike' f a (AxisLine (V a) (N a))
forall (f :: * -> *) a.
HasAxisLine f a =>
LensLike' f a (AxisLine (V a) (N a))
axisLine LensLike' f a (AxisLine (V a) (N a))
-> ((Maybe (ArrowOpts (N a)) -> f (Maybe (ArrowOpts (N a))))
    -> AxisLine (V a) (N a) -> f (AxisLine (V a) (N a)))
-> LensLike' f a (Maybe (ArrowOpts (N a)))
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (AxisLine (V a) (N a) -> Maybe (ArrowOpts (N a)))
-> (AxisLine (V a) (N a)
    -> Maybe (ArrowOpts (N a)) -> AxisLine (V a) (N a))
-> Lens
     (AxisLine (V a) (N a))
     (AxisLine (V a) (N a))
     (Maybe (ArrowOpts (N a)))
     (Maybe (ArrowOpts (N a)))
forall s a b t. (s -> a) -> (s -> b -> t) -> Lens s t a b
lens AxisLine (V a) (N a) -> Maybe (ArrowOpts (N a))
forall (v :: * -> *) n. AxisLine v n -> Maybe (ArrowOpts n)
alArrowOpts (\AxisLine (V a) (N a)
al Maybe (ArrowOpts (N a))
sty -> AxisLine (V a) (N a)
al {alArrowOpts = sty})

  -- | The 'Style' applied to the axis line
  axisLineStyle :: Functor f => LensLike' f a (Style (V a) (N a))
  axisLineStyle = LensLike' f a (AxisLine (V a) (N a))
forall (f :: * -> *) a.
HasAxisLine f a =>
LensLike' f a (AxisLine (V a) (N a))
axisLine LensLike' f a (AxisLine (V a) (N a))
-> ((Style (V a) (N a) -> f (Style (V a) (N a)))
    -> AxisLine (V a) (N a) -> f (AxisLine (V a) (N a)))
-> LensLike' f a (Style (V a) (N a))
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (AxisLine (V a) (N a) -> Style (V a) (N a))
-> (AxisLine (V a) (N a)
    -> Style (V a) (N a) -> AxisLine (V a) (N a))
-> Lens
     (AxisLine (V a) (N a))
     (AxisLine (V a) (N a))
     (Style (V a) (N a))
     (Style (V a) (N a))
forall s a b t. (s -> a) -> (s -> b -> t) -> Lens s t a b
lens AxisLine (V a) (N a) -> Style (V a) (N a)
forall (v :: * -> *) n. AxisLine v n -> Style v n
alStyle (\AxisLine (V a) (N a)
al Style (V a) (N a)
sty -> AxisLine (V a) (N a)
al {alStyle = sty})

instance HasAxisLine f (AxisLine v n) where
  axisLine :: LensLike'
  f (AxisLine v n) (AxisLine (V (AxisLine v n)) (N (AxisLine v n)))
axisLine = (AxisLine v n -> f (AxisLine v n))
-> AxisLine v n -> f (AxisLine v n)
LensLike'
  f (AxisLine v n) (AxisLine (V (AxisLine v n)) (N (AxisLine v n)))
forall a. a -> a
id

--   Note this is different from 'NoAxisLine'. Other parts that are
--   tied to the axis line will still be present when
--   'axisLineVisible' is 'False'. But if 'NoAxisLine' is set, there
--   never any line for those things to attach to, so they don't
--   exist.
instance HasVisibility (AxisLine v n) where
  visible :: Lens' (AxisLine v n) Bool
visible = (AxisLine v n -> Bool)
-> (AxisLine v n -> Bool -> AxisLine v n)
-> Lens' (AxisLine v n) Bool
forall s a b t. (s -> a) -> (s -> b -> t) -> Lens s t a b
lens AxisLine v n -> Bool
forall (v :: * -> *) n. AxisLine v n -> Bool
alVisible (\AxisLine v n
al Bool
b -> AxisLine v n
al {alVisible = b})

instance Typeable n => Default (AxisLine v n) where
  def :: AxisLine v n
def = AxisLine
    { alType :: AxisLineType
alType  = AxisLineType
forall a. Default a => a
def
    , alArrowOpts :: Maybe (ArrowOpts n)
alArrowOpts = Maybe (ArrowOpts n)
forall a. Default a => a
def
    , alVisible :: Bool
alVisible = Bool
True
    , alStyle :: Style v n
alStyle = Style v n
forall a. Monoid a => a
mempty
    }