{-# LANGUAGE TypeFamilies #-} {-# OPTIONS -Wall #-} -------------------------------------------------------------------------------- -- | -- Module : Wumpus.Basic.Kernal.Base.BaseDefs -- Copyright : (c) Stephen Tetley 2010-2011 -- License : BSD3 -- -- Maintainer : stephen.tetley@gmail.com -- Stability : highly unstable -- Portability : GHC -- -- The elementary base types and classes. -- -- -------------------------------------------------------------------------------- module Wumpus.Basic.Kernel.Base.BaseDefs ( -- * Constants quarter_pi , half_pi , two_pi , ang180 , ang150 , ang120 , ang90 , ang60 , ang45 , ang30 , ang15 -- * Unit phantom type , UNil(..) , ureturn , uvoid -- * Non-contextual unit conversion. , ScalarUnit(..) -- * Unit interpretation with respect to the current Point size , InterpretUnit(..) , dinterpF , normalizeF , uconvert1 , uconvertF , intraMapPoint , intraMapFunctor -- * KernChar , KernChar -- * Drawing paths and shapes (closed paths) , PathMode(..) , DrawMode(..) , closedMode -- * Drawing layers , ZDeco(..) -- * Alignment , HAlign(..) , VAlign(..) -- * Text height , TextHeight(..) -- * Cardinal (compass) positions , Cardinal(..) -- * Direction enumeration , Direction(..) , ClockDirection(..) -- * Misc , both , monPreRepeatPost ) where import Wumpus.Core -- package: wumpus-core import Control.Applicative import Data.Monoid quarter_pi :: Radian quarter_pi = 0.25 * pi half_pi :: Radian half_pi = 0.5 * pi two_pi :: Radian two_pi = 2.0 * pi ang180 :: Radian ang180 = pi ang150 :: Radian ang150 = 5 * ang30 ang120 :: Radian ang120 = 3 * ang60 ang90 :: Radian ang90 = pi / 2 ang60 :: Radian ang60 = pi / 3 ang45 :: Radian ang45 = pi / 4 ang30 :: Radian ang30 = pi / 6 ang15 :: Radian ang15 = pi / 12 -------------------------------------------------------------------------------- -- Simple objects wrapped with unit phatom type -- | The empty data type - i.e. @()@ - wrapped with a phantom unit -- parameter. -- data UNil u = UNil deriving (Eq,Ord,Read,Show) type instance DUnit (UNil u) = u instance Functor UNil where fmap _ UNil= UNil instance Monoid (UNil u) where mempty = UNil _ `mappend` _ = UNil instance Rotate (UNil u) where rotate _ = id instance RotateAbout (UNil u) where rotateAbout _ _ = id instance Scale (UNil u) where scale _ _ = id instance Translate (UNil u) where translate _ _ = id -- | Return a 'UNil' rather than @()@ at the end of sequence of -- monadic commands. -- -- Many Wumpus objects are usefully constructed in the -- @do-notation@, but because Wumpus has to expose the type of -- the @unit@ to the type checker we must finish the do-block -- with: -- -- > ureturn -- -- or: -- -- > return UNil -- -- rather than: -- -- > return () -- -- ureturn :: Monad m => m (UNil u) ureturn = return UNil -- | 'uvoid' runs a monadic computation and returns @UNil@. -- uvoid :: Monad m => m a -> m (UNil u) uvoid ma = ma >> return UNil -------------------------------------------------------------------------------- -- Non-contextual units class ScalarUnit a where fromPsPoint :: Double -> a toPsPoint :: a -> Double instance ScalarUnit Double where fromPsPoint = id toPsPoint = id -------------------------------------------------------------------------------- -- Interpreting units -- Units may or may not depend on current font size -- class Num u => InterpretUnit u where normalize :: FontSize -> u -> Double dinterp :: FontSize -> Double -> u instance InterpretUnit Double where normalize _ = id dinterp _ = id instance InterpretUnit AfmUnit where normalize sz = afmValue sz dinterp sz = afmUnit sz -- | 'dinterp' an object that gives access to its unit at the -- functor position. -- dinterpF :: (Functor t, InterpretUnit u) => FontSize -> t Double -> t u dinterpF sz = fmap (dinterp sz) -- | 'normalize' an object that gives access to its unit at the -- functor position. -- normalizeF :: (Functor t, InterpretUnit u) => FontSize -> t u -> t Double normalizeF sz = fmap (normalize sz) -- | Convert a scalar value from one unit to another. -- uconvert1 :: (InterpretUnit u, InterpretUnit u1) => FontSize -> u -> u1 uconvert1 sz = dinterp sz . normalize sz -- | Unit convert an object that gives access to its unit at the -- Functor position. -- -- In practive this will be \*all\* Image answers. -- uconvertF :: (Functor t, InterpretUnit u, InterpretUnit u1) => FontSize -> t u -> t u1 uconvertF sz = fmap (uconvert1 sz) -- Helper for defining Affine instances. This function allows -- scaling etc to be applied on a Point coerced to a Double then -- converted back to the original unit. Thus transformations can -- work in contextual units. -- intraMapPoint :: InterpretUnit u => FontSize -> (DPoint2 -> DPoint2) -> Point2 u -> Point2 u intraMapPoint sz fn (P2 x y) = let P2 x' y' = fn $ P2 (normalize sz x) (normalize sz y) in P2 (dinterp sz x') (dinterp sz y') -- Helper for defining Affine instances. This function allows -- scaling etc to be applied on a Point coerced to a Double then -- converted back to the original unit. Thus transformations can -- work in contextual units. -- intraMapFunctor :: (Functor f, InterpretUnit u) => FontSize -> (f Double -> f Double) -> f u -> f u intraMapFunctor sz fn ma = dinterpF sz $ fn $ normalizeF sz ma -------------------------------------------------------------------------------- -- KernChar -- | Unit parametric version of KerningChar from Wumpus-Core. -- type KernChar u = (u,EscapedChar) -------------------------------------------------------------------------------- -- Drawing closed paths -- | Draw closed paths. -- -- > OSTROKE - open and stroked -- > CSTROKE - closed and stroke -- -- > CFILL - closed and filled -- -- > CFILL_STROKE - closed, the path is filled, its edge is stroked. -- data PathMode = OSTROKE | CSTROKE | CFILL | CFILL_STROKE deriving (Bounded,Enum,Eq,Ord,Show) -- | Draw closed paths and shapes. -- -- > DRAW_STROKE - closed and stroked -- -- > DRAW_FILL - closed and filled -- -- > CLOSED_FILL_STROKE - the path is filled, its edge is stroked. -- data DrawMode = DRAW_STROKE | DRAW_FILL | DRAW_FILL_STROKE deriving (Bounded,Enum,Eq,Ord,Show) -- | Interpret a 'DrawMode' for a closed path. -- closedMode :: DrawMode -> PathMode closedMode DRAW_STROKE = CSTROKE closedMode DRAW_FILL = CFILL closedMode DRAW_FILL_STROKE = CFILL_STROKE -- | Decorating with resepct to the Z-order -- -- > SUPERIOR - in front. -- -- > ANTERIOR - behind. -- data ZDeco = SUPERIOR | ANTERIOR deriving (Bounded,Enum,Eq,Ord,Show) -------------------------------------------------------------------------------- -- Alignment -- | Horizontal alignment - align to the top, center or bottom. -- data HAlign = HALIGN_TOP | HALIGN_CENTER | HALIGN_BASE deriving (Enum,Eq,Ord,Show) -- | Vertical alignment - align to the left, center or bottom. -- data VAlign = VALIGN_LEFT | VALIGN_CENTER | VALIGN_RIGHT deriving (Enum,Eq,Ord,Show) -------------------------------------------------------------------------------- -- Text height -- | Wumpus distinguishes two use-cases for displaying vertically -- centered text. -- -- Arbitrary text that is expected to contain lower case letters -- with descenders, show take the vertical center as the mid-point -- between the cap height and the descender depth. -- -- Unfortunately, including the descender depth can produce -- unbalanced results for text which is not expected to have -- descenders (e.g. numbers within a bordered box), visually this -- makes the center too high. -- data TextHeight = JUST_CAP_HEIGHT | CAP_HEIGHT_PLUS_DESCENDER deriving (Enum,Eq,Ord,Show) -------------------------------------------------------------------------------- -- Compass positions -- | An enumeratied type representing the compass positions. -- data Cardinal = NORTH | NORTH_EAST | EAST | SOUTH_EAST | SOUTH | SOUTH_WEST | WEST | NORTH_WEST deriving (Enum,Eq,Ord,Show) -- | An enumerated type representing horizontal and vertical -- directions. -- data Direction = UP | DOWN | LEFT | RIGHT deriving (Enum,Eq,Ord,Show) -- | An enumerated type representing /clock/ directions. -- data ClockDirection = CW | CCW deriving (Enum,Eq,Ord,Show) -- | Applicative /both/ - run both computations return the pair -- of the the answers. -- both :: Applicative f => f a -> f b -> f (a,b) both fa fb = (,) <$> fa <*> fb -- | Monodial scheme - prefix, repeat body n times, suffix. -- monPreRepeatPost :: Monoid a => a -> (Int, a) -> a -> a monPreRepeatPost pre (n,body1) post = step pre n where step ac i | i < 1 = ac `mappend` post | otherwise = step (ac `mappend` body1) (i - 1)