packages feed

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

{-# OPTIONS -fglasgow-exts #-}

----------------------------------------------------------------------
-- |
-- Module      :  Graphics.UI.Phooey.Applicative
-- Copyright   :  (c) Conal Elliott 2007
-- License     :  LGPL
-- 
-- Maintainer  :  conal@conal.net
-- Stability   :  experimental
-- Portability :  portable
-- 
-- UIs as applicative functors.  This module is a very simple layering
-- over "Graphics.UI.Phooey.Monad".  It serves to hide the 'Source' types
-- and give an applicative feel to UI construction.
----------------------------------------------------------------------

module Graphics.UI.Phooey.Applicative
  (
  -- * The UI applicative functor
    UI, runUI, runNamedUI, Upd, Snk
  -- * Tools for high-level widgets
  , IWidget, OWidget
  -- * Some high-level widgets
  , stringEntry, stringDisplay, showDisplay
  , islider, isliderDyn, isliderDisplay
  , checkBoxEntry, checkBoxDisplay
  , title
  -- * Explicit layout
  , fromTop, fromBottom, fromLeft, fromRight, flipLayout
  ) where

import Control.Monad.Reader
import Control.Applicative
import Control.Compose

import Graphics.UI.Phooey.LayoutT
import Graphics.UI.Phooey.TagT

import qualified Graphics.UI.Phooey.Monad as M
import Graphics.UI.Phooey.Monad (Source,Upd,Snk)


{----------------------------------------------------------
    The UI applicative functor
----------------------------------------------------------}

-- | The UI applicative functor.
type UI = Compose M.UI Source

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

-- | Run a 'UI' with given window title.
runNamedUI :: String -> UI Upd -> IO ()
runNamedUI name = M.runNamedUI' name . unComp


{----------------------------------------------------------
    Tools for high-level widgets
----------------------------------------------------------}

-- | Input widget, with initial value.
type IWidget a = a -> UI a

-- | Output widget.  Yields a sink of values
type OWidget a = UI (Snk a)

-- | Make an input widget
iwidget :: M.IWidget a -> IWidget a
iwidget mwid a = Comp (mwid a)

-- | Make an output widget
owidget :: M.OWidget' a -> OWidget a
owidget mwid = Comp (fmap pure mwid)


{----------------------------------------------------------
    Some high-level widgets
----------------------------------------------------------}

-- | String input widget
stringEntry :: IWidget String
stringEntry = iwidget M.stringEntry

-- | String display widget
stringDisplay :: OWidget String
stringDisplay = owidget M.stringDisplay'

-- | Showable output widget
showDisplay :: Show a => OWidget a
showDisplay = owidget M.showDisplay'


-- | Slider input widget with static bounds
islider :: (Int,Int) -> IWidget Int
islider bounds = iwidget (M.islider bounds)

-- | Slider output widget with static bounds
isliderDisplay :: (Int,Int) -> OWidget Int
isliderDisplay bounds = owidget (M.isliderDisplay' bounds)

-- | Slider widget with dynamic bounds.
isliderDyn :: UI (Int,Int) -> IWidget Int
isliderDyn (Comp bounds) initial = Comp $
  bounds >>= flip M.isliderDyn initial

-- | Boolean input widget
checkBoxEntry :: IWidget Bool
checkBoxEntry = iwidget M.checkBoxEntry

-- | Boolean display widget
checkBoxDisplay :: OWidget Bool
checkBoxDisplay = owidget M.checkBoxDisplay'

-- | Wrap a title around a 'UI'
title :: String -> Unop (UI a)
title str = onComp (M.title str)
            -- mapLayout (boxed str)

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

-- | Tweak the 'LayoutT'
onLayoutT :: LayoutTOp IO -> Unop (UI a)
onLayoutT f = onComp (M.onLayoutT f)

-- | Lay out from top to bottom
fromTop :: Unop (UI a)

-- | Lay out from bottom to top
fromBottom :: Unop (UI a)

-- | Lay out from left to right
fromLeft :: Unop (UI a)

-- | Lay out from right to left
fromRight :: Unop (UI a)

-- | Reverse layout
flipLayout :: Unop (UI a)

fromTop    = onLayoutT fromTopL
fromBottom = onLayoutT fromBottomL
fromLeft   = onLayoutT fromLeftL
fromRight  = onLayoutT fromRightL
flipLayout = onLayoutT flipL


-----

{-

-- Overloading mischief.  Standard incantation for applicative functors.

instance Show (UI a) where
  show _ = "<UI>"

instance Eq (UI a) where
   (==) = error "no Eq for UI"

instance Ord (UI a) where
  (<) = error "no Ord for UI"

instance Num a => Num (UI a) where
  (+) = liftA2 (+)
  fromInteger = pure . fromInteger
  -- etc

-}