{-# LANGUAGE ConstraintKinds #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE TypeFamilies     #-}

-----------------------------------------------------------------------------
-- |
-- Module      :  Diagrams.TwoD.Align
-- Copyright   :  (c) 2011 diagrams-lib team (see LICENSE)
-- License     :  BSD-style (see LICENSE)
-- Maintainer  :  diagrams-discuss@googlegroups.com
--
-- Alignment combinators specialized for two dimensions.  See
-- "Diagrams.Align" for more general alignment combinators.
--
-- The basic idea is that alignment is achieved by moving diagrams'
-- local origins relative to their envelopes or traces (or some other
-- sort of boundary).  For example, to align several diagrams along
-- their tops, we first move their local origins to the upper edge of
-- their boundary (using e.g. @map 'alignTop'@), and then put them
-- together with their local origins along a horizontal line (using
-- e.g. 'hcat' from "Diagrams.TwoD.Combinators").
--
-----------------------------------------------------------------------------

module Diagrams.TwoD.Align
    ( -- * Absolute alignment
      -- ** Align by envelope
      alignL, alignR, alignT, alignB
    , alignTL, alignTR, alignBL, alignBR

      -- ** Align by trace
    , snugL, snugR, snugT, snugB

      -- * Relative alignment
    , alignX, snugX, alignY, snugY

      -- * Centering
    , centerX, centerY, centerXY
    , snugCenterX, snugCenterY, snugCenterXY

    ) where

import           Diagrams.Core

import           Diagrams.Align
import           Diagrams.TwoD.Types
import           Diagrams.TwoD.Vector

-- | Align along the left edge, i.e. translate the diagram in a
--   horizontal direction so that the local origin is on the left edge
--   of the envelope.
alignL :: (InSpace V2 n a, Fractional n, Alignable a, HasOrigin a) => a -> a
alignL :: forall n a.
(InSpace V2 n a, Fractional n, Alignable a, HasOrigin a) =>
a -> a
alignL = V2 n -> a -> a
forall (v :: * -> *) n a.
(InSpace v n a, Fractional n, Alignable a, HasOrigin a) =>
v n -> a -> a
align V2 n
forall (v :: * -> *) n. (R1 v, Additive v, Num n) => v n
unit_X

snugL :: (InSpace V2 n a, Fractional n, Alignable a, Traced a, HasOrigin a) => a -> a
snugL :: forall n a.
(InSpace V2 n a, Fractional n, Alignable a, Traced a,
 HasOrigin a) =>
a -> a
snugL = V2 n -> a -> a
forall (v :: * -> *) n a.
(InSpace v n a, Fractional n, Alignable a, Traced a,
 HasOrigin a) =>
v n -> a -> a
snug V2 n
forall (v :: * -> *) n. (R1 v, Additive v, Num n) => v n
unit_X

-- | Align along the right edge.
alignR :: (InSpace V2 n a, Fractional n, Alignable a, HasOrigin a) => a -> a
alignR :: forall n a.
(InSpace V2 n a, Fractional n, Alignable a, HasOrigin a) =>
a -> a
alignR = V2 n -> a -> a
forall (v :: * -> *) n a.
(InSpace v n a, Fractional n, Alignable a, HasOrigin a) =>
v n -> a -> a
align V2 n
forall (v :: * -> *) n. (R1 v, Additive v, Num n) => v n
unitX

snugR :: (InSpace V2 n a, Fractional n, Alignable a, Traced a, HasOrigin a) => a -> a
snugR :: forall n a.
(InSpace V2 n a, Fractional n, Alignable a, Traced a,
 HasOrigin a) =>
a -> a
snugR = V2 n -> a -> a
forall (v :: * -> *) n a.
(InSpace v n a, Fractional n, Alignable a, Traced a,
 HasOrigin a) =>
v n -> a -> a
snug V2 n
forall (v :: * -> *) n. (R1 v, Additive v, Num n) => v n
unitX


-- | Align along the top edge.
alignT :: (InSpace V2 n a, Fractional n, Alignable a, HasOrigin a) => a -> a
alignT :: forall n a.
(InSpace V2 n a, Fractional n, Alignable a, HasOrigin a) =>
a -> a
alignT = V2 n -> a -> a
forall (v :: * -> *) n a.
(InSpace v n a, Fractional n, Alignable a, HasOrigin a) =>
v n -> a -> a
align V2 n
forall (v :: * -> *) n. (R2 v, Additive v, Num n) => v n
unitY

snugT:: (InSpace V2 n a, Fractional n, Alignable a, Traced a, HasOrigin a) => a -> a
snugT :: forall n a.
(InSpace V2 n a, Fractional n, Alignable a, Traced a,
 HasOrigin a) =>
a -> a
snugT = V2 n -> a -> a
forall (v :: * -> *) n a.
(InSpace v n a, Fractional n, Alignable a, Traced a,
 HasOrigin a) =>
v n -> a -> a
snug V2 n
forall (v :: * -> *) n. (R2 v, Additive v, Num n) => v n
unitY

-- | Align along the bottom edge.
alignB :: (InSpace V2 n a, Fractional n, Alignable a, HasOrigin a) => a -> a
alignB :: forall n a.
(InSpace V2 n a, Fractional n, Alignable a, HasOrigin a) =>
a -> a
alignB = V2 n -> a -> a
forall (v :: * -> *) n a.
(InSpace v n a, Fractional n, Alignable a, HasOrigin a) =>
v n -> a -> a
align V2 n
forall (v :: * -> *) n. (R2 v, Additive v, Num n) => v n
unit_Y

snugB :: (InSpace V2 n a, Fractional n, Alignable a, Traced a, HasOrigin a) => a -> a
snugB :: forall n a.
(InSpace V2 n a, Fractional n, Alignable a, Traced a,
 HasOrigin a) =>
a -> a
snugB = V2 n -> a -> a
forall (v :: * -> *) n a.
(InSpace v n a, Fractional n, Alignable a, Traced a,
 HasOrigin a) =>
v n -> a -> a
snug V2 n
forall (v :: * -> *) n. (R2 v, Additive v, Num n) => v n
unit_Y

alignTL, alignTR, alignBL, alignBR :: (InSpace V2 n a, Fractional n, Alignable a, HasOrigin a) => a -> a
alignTL :: forall n a.
(InSpace V2 n a, Fractional n, Alignable a, HasOrigin a) =>
a -> a
alignTL = a -> a
forall n a.
(InSpace V2 n a, Fractional n, Alignable a, HasOrigin a) =>
a -> a
alignT (a -> a) -> (a -> a) -> a -> a
forall b c a. (b -> c) -> (a -> b) -> a -> c
. a -> a
forall n a.
(InSpace V2 n a, Fractional n, Alignable a, HasOrigin a) =>
a -> a
alignL
alignTR :: forall n a.
(InSpace V2 n a, Fractional n, Alignable a, HasOrigin a) =>
a -> a
alignTR = a -> a
forall n a.
(InSpace V2 n a, Fractional n, Alignable a, HasOrigin a) =>
a -> a
alignT (a -> a) -> (a -> a) -> a -> a
forall b c a. (b -> c) -> (a -> b) -> a -> c
. a -> a
forall n a.
(InSpace V2 n a, Fractional n, Alignable a, HasOrigin a) =>
a -> a
alignR
alignBL :: forall n a.
(InSpace V2 n a, Fractional n, Alignable a, HasOrigin a) =>
a -> a
alignBL = a -> a
forall n a.
(InSpace V2 n a, Fractional n, Alignable a, HasOrigin a) =>
a -> a
alignB (a -> a) -> (a -> a) -> a -> a
forall b c a. (b -> c) -> (a -> b) -> a -> c
. a -> a
forall n a.
(InSpace V2 n a, Fractional n, Alignable a, HasOrigin a) =>
a -> a
alignL
alignBR :: forall n a.
(InSpace V2 n a, Fractional n, Alignable a, HasOrigin a) =>
a -> a
alignBR = a -> a
forall n a.
(InSpace V2 n a, Fractional n, Alignable a, HasOrigin a) =>
a -> a
alignB (a -> a) -> (a -> a) -> a -> a
forall b c a. (b -> c) -> (a -> b) -> a -> c
. a -> a
forall n a.
(InSpace V2 n a, Fractional n, Alignable a, HasOrigin a) =>
a -> a
alignR

-- | @alignX@ and @snugX@ move the local origin horizontally as follows:
--
--   * @alignX (-1)@ moves the local origin to the left edge of the boundary;
--
--   * @align 1@ moves the local origin to the right edge;
--
--   * any other argument interpolates linearly between these.  For
--     example, @alignX 0@ centers, @alignX 2@ moves the origin one
--     \"radius\" to the right of the right edge, and so on.
--
--   * @snugX@ works the same way.

alignX :: (InSpace v n a, R1 v, Fractional n, Alignable a, HasOrigin a) => n -> a -> a
alignX :: forall (v :: * -> *) n a.
(InSpace v n a, R1 v, Fractional n, Alignable a, HasOrigin a) =>
n -> a -> a
alignX = v n -> n -> a -> a
forall a (v :: * -> *) n.
(Alignable a, InSpace v n a, Fractional n, HasOrigin a) =>
v n -> n -> a -> a
forall (v :: * -> *) n.
(InSpace v n a, Fractional n, HasOrigin a) =>
v n -> n -> a -> a
alignBy v n
forall (v :: * -> *) n. (R1 v, Additive v, Num n) => v n
unitX

-- | See the documentation for 'alignX'.
snugX :: (InSpace v n a, R1 v, Fractional n, Alignable a, Traced a, HasOrigin a) => n -> a -> a
snugX :: forall (v :: * -> *) n a.
(InSpace v n a, R1 v, Fractional n, Alignable a, Traced a,
 HasOrigin a) =>
n -> a -> a
snugX = v n -> n -> a -> a
forall (v :: * -> *) n a.
(InSpace v n a, Fractional n, Alignable a, Traced a,
 HasOrigin a) =>
v n -> n -> a -> a
snugBy v n
forall (v :: * -> *) n. (R1 v, Additive v, Num n) => v n
unitX

-- | Like 'alignX', but moving the local origin vertically, with an
--   argument of @1@ corresponding to the top edge and @(-1)@ corresponding
--   to the bottom edge.
alignY :: (InSpace v n a, R2 v, Fractional n, Alignable a, HasOrigin a) => n -> a -> a
alignY :: forall (v :: * -> *) n a.
(InSpace v n a, R2 v, Fractional n, Alignable a, HasOrigin a) =>
n -> a -> a
alignY = v n -> n -> a -> a
forall a (v :: * -> *) n.
(Alignable a, InSpace v n a, Fractional n, HasOrigin a) =>
v n -> n -> a -> a
forall (v :: * -> *) n.
(InSpace v n a, Fractional n, HasOrigin a) =>
v n -> n -> a -> a
alignBy v n
forall (v :: * -> *) n. (R2 v, Additive v, Num n) => v n
unitY

-- | See the documentation for 'alignY'.
snugY :: (InSpace v n a, R2 v, Fractional n, Alignable a, Traced a, HasOrigin a) => n -> a -> a
snugY :: forall (v :: * -> *) n a.
(InSpace v n a, R2 v, Fractional n, Alignable a, Traced a,
 HasOrigin a) =>
n -> a -> a
snugY = v n -> n -> a -> a
forall (v :: * -> *) n a.
(InSpace v n a, Fractional n, Alignable a, Traced a,
 HasOrigin a) =>
v n -> n -> a -> a
snugBy v n
forall (v :: * -> *) n. (R2 v, Additive v, Num n) => v n
unitY

-- | Center the local origin along the X-axis.
centerX :: (InSpace v n a, R1 v, Fractional n, Alignable a, HasOrigin a) => a -> a
centerX :: forall (v :: * -> *) n a.
(InSpace v n a, R1 v, Fractional n, Alignable a, HasOrigin a) =>
a -> a
centerX = v n -> n -> a -> a
forall a (v :: * -> *) n.
(Alignable a, InSpace v n a, Fractional n, HasOrigin a) =>
v n -> n -> a -> a
forall (v :: * -> *) n.
(InSpace v n a, Fractional n, HasOrigin a) =>
v n -> n -> a -> a
alignBy v n
forall (v :: * -> *) n. (R1 v, Additive v, Num n) => v n
unitX n
0

snugCenterX :: (InSpace v n a, R1 v, Fractional n, Alignable a, Traced a, HasOrigin a) => a -> a
snugCenterX :: forall (v :: * -> *) n a.
(InSpace v n a, R1 v, Fractional n, Alignable a, Traced a,
 HasOrigin a) =>
a -> a
snugCenterX = v n -> n -> a -> a
forall (v :: * -> *) n a.
(InSpace v n a, Fractional n, Alignable a, Traced a,
 HasOrigin a) =>
v n -> n -> a -> a
snugBy v n
forall (v :: * -> *) n. (R1 v, Additive v, Num n) => v n
unitX n
0

-- | Center the local origin along the Y-axis.
centerY :: (InSpace v n a, R2 v, Fractional n, Alignable a, HasOrigin a) => a -> a
centerY :: forall (v :: * -> *) n a.
(InSpace v n a, R2 v, Fractional n, Alignable a, HasOrigin a) =>
a -> a
centerY = v n -> n -> a -> a
forall a (v :: * -> *) n.
(Alignable a, InSpace v n a, Fractional n, HasOrigin a) =>
v n -> n -> a -> a
forall (v :: * -> *) n.
(InSpace v n a, Fractional n, HasOrigin a) =>
v n -> n -> a -> a
alignBy v n
forall (v :: * -> *) n. (R2 v, Additive v, Num n) => v n
unitY n
0

snugCenterY :: (InSpace v n a, R2 v, Fractional n, Alignable a, Traced a, HasOrigin a) => a -> a
snugCenterY :: forall (v :: * -> *) n a.
(InSpace v n a, R2 v, Fractional n, Alignable a, Traced a,
 HasOrigin a) =>
a -> a
snugCenterY = v n -> n -> a -> a
forall (v :: * -> *) n a.
(InSpace v n a, Fractional n, Alignable a, Traced a,
 HasOrigin a) =>
v n -> n -> a -> a
snugBy v n
forall (v :: * -> *) n. (R2 v, Additive v, Num n) => v n
unitY n
0

-- | Center along both the X- and Y-axes.
centerXY :: (InSpace v n a, R2 v, Fractional n, Alignable a, HasOrigin a) => a -> a
centerXY :: forall (v :: * -> *) n a.
(InSpace v n a, R2 v, Fractional n, Alignable a, HasOrigin a) =>
a -> a
centerXY = a -> a
forall (v :: * -> *) n a.
(InSpace v n a, R1 v, Fractional n, Alignable a, HasOrigin a) =>
a -> a
centerX (a -> a) -> (a -> a) -> a -> a
forall b c a. (b -> c) -> (a -> b) -> a -> c
. a -> a
forall (v :: * -> *) n a.
(InSpace v n a, R2 v, Fractional n, Alignable a, HasOrigin a) =>
a -> a
centerY

snugCenterXY :: (InSpace v n a, R2 v, Fractional n, Alignable a, Traced a, HasOrigin a) => a -> a
snugCenterXY :: forall (v :: * -> *) n a.
(InSpace v n a, R2 v, Fractional n, Alignable a, Traced a,
 HasOrigin a) =>
a -> a
snugCenterXY = a -> a
forall (v :: * -> *) n a.
(InSpace v n a, R1 v, Fractional n, Alignable a, Traced a,
 HasOrigin a) =>
a -> a
snugCenterX (a -> a) -> (a -> a) -> a -> a
forall b c a. (b -> c) -> (a -> b) -> a -> c
. a -> a
forall (v :: * -> *) n a.
(InSpace v n a, R2 v, Fractional n, Alignable a, Traced a,
 HasOrigin a) =>
a -> a
snugCenterY