packages feed

phooey-1.0: src/Graphics/UI/Phooey/Arrow.hs

{-# OPTIONS -fglasgow-exts #-}

----------------------------------------------------------------------
-- |
-- Module      :  Graphics.UI.Phooey.Arrow
-- Copyright   :  (c) Conal Elliott 2006
-- License     :  LGPL
-- 
-- Maintainer  :  conal@conal.net
-- Stability   :  provisional
-- Portability :  portable
-- 
-- A functional UI arrow.  See explanation and examples in
-- "Graphics.UI.Phooey".
----------------------------------------------------------------------

module Graphics.UI.Phooey.Arrow
  ( 
  -- * The UI arrow
    UI(..), runUI, runNamedUI
  -- * High-level widgets
  , IWidget, OWidget
  , stringDisplay, showDisplay, stringEntry, islider, isliderDyn
  , checkBoxDisplay, checkBoxEntry, title
  -- * Explicit layout
  , fromTop, fromBottom, fromLeft, fromRight, flipLayout
  -- * Internal (extensibility)
  , ui, sourceOp, onLayoutT
  ) where


import Control.Arrow
import Data.Monoid

import Graphics.UI.Phooey.TagT (Unop)
import Graphics.UI.Phooey.LayoutT
import qualified Graphics.UI.Phooey.Monad as M

import Control.Compose

{----------------------------------------------------------
    The UI arrow
----------------------------------------------------------}

-- | The UI arrow
newtype UI i o = UI ((ArrowAp (Kleisli M.UI) M.Source) i o)
  deriving (Arrow,ArrowLoop)

-- | Run a 'UI' with window title \"Phooey Arrow GUI\".
runUI :: UI () () -> IO ()
runUI = runNamedUI "Phooey Arrow GUI"

-- | Run a 'UI' with given window title.
runNamedUI :: String -> UI () () -> IO ()
runNamedUI str (UI (ArrowAp (Kleisli f))) = M.runNamedUI str (f mempty)

-- runNamedUI str (UI (ArrowAp (Kleisli f))) = M.runNamedUI str (f mempty)

-- | Wrap up monadic UI function as a 'UI'
ui :: (M.Source i -> M.UI (M.Source o)) -> UI i o
ui = UI . ArrowAp . Kleisli


{----------------------------------------------------------
    High-level widgets
----------------------------------------------------------}

-- | Input widget type (with initial value)
type IWidget  a = a -> UI () a
-- | Output widget type
type OWidget  a = UI a ()

-- | String display widget
stringDisplay :: OWidget String
stringDisplay = ui M.stringDisplay

-- | Showable display widget
showDisplay :: Show a => OWidget a
showDisplay = pure show >>> stringDisplay
              -- or: ui M.showDisplay

-- | Simple text input widget
stringEntry :: IWidget String
stringEntry initial = ui (const (M.stringEntry initial))

-- | Slider widget with initial value and /static/ bounds (min,max)
islider :: (Int,Int) -> IWidget Int
islider bounds initial = ui (const (M.islider bounds initial))

-- | Slider widget with static initial value and /dynamic/ bounds (min,max)
isliderDyn :: Int -> UI (Int,Int) Int
isliderDyn initial = ui (flip M.isliderDyn initial)

-- | String display widget
checkBoxDisplay :: UI Bool ()
checkBoxDisplay = ui M.checkBoxDisplay

-- | Simple checkbox input widget
checkBoxEntry :: Bool -> UI () Bool
checkBoxEntry initial = ui (const (M.checkBoxEntry initial))

-- | Wrap a title around a 'UI'
title :: String -> Unop (UI a b)
title str = sourceOp (M.title str)


{----------------------------------------------------------
    Layout
----------------------------------------------------------}

-- | Lay out from top to bottom
fromTop :: Unop (UI a b)
fromTop = onLayoutT fromTopL

-- | Lay out from bottom to top
fromBottom :: Unop (UI a b)
fromBottom = onLayoutT fromBottomL

-- | Lay out from left to right
fromLeft :: Unop (UI a b)
fromLeft = onLayoutT fromLeftL

-- | Lay out from right to left
fromRight :: Unop (UI a b)
fromRight = onLayoutT fromRightL

-- | Reverse layout
flipLayout :: Unop (UI a b)
flipLayout = onLayoutT flipL


---- Misc unexported

sourceOp :: Unop (M.UI (M.Source b)) -> Unop (UI a b)
sourceOp f (UI (ArrowAp (Kleisli g))) = ui (f . g)

onLayoutT :: LayoutTOp IO -> Unop (UI a b)
onLayoutT f = sourceOp (M.onLayoutT f)