phooey-2.0: src/Graphics/UI/Phooey/Applicative.hs
{-# LANGUAGE TypeSynonymInstances, TypeOperators #-}
-- For ghc 6.6 compatibility
-- {-# OPTIONS -fglasgow-exts #-}
----------------------------------------------------------------------
-- |
-- Module : Graphics.UI.Phooey.Applicative
-- Copyright : (c) Conal Elliott 2007
-- License : BSD3
--
-- Maintainer : conal@conal.net
-- Stability : experimental
-- Portability : TypeSynonymInstances
--
-- 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, Action, Sink
-- * Tools for high-level widgets
, IWidget, OWidget, iwidget, owidget
-- * Some high-level widgets
, stringEntry, stringDisplay, showDisplay
, islider, isliderDisplay
, fslider, fsliderDisplay
, checkBoxEntry, checkBoxDisplay, choices
, timedPoll
-- * Explicit layout
, fromTop, fromBottom, fromLeft, fromRight
) where
-- Base
import Control.Applicative (pure)
-- TypeCompose
import Control.Compose
import Data.Title
-- reactive
import Data.Reactive
-- phooey
import qualified Graphics.UI.Phooey.Monad as M
{----------------------------------------------------------
The UI applicative functor
----------------------------------------------------------}
-- | The UI applicative functor.
type UI = M.UI :. Source
-- | Run a 'UI' with window title \"Applicative Phooey GUI\".
runUI :: UI Action -> IO ()
runUI = runNamedUI "Applicative Phooey GUI"
-- | Run a 'UI' with given window title.
runNamedUI :: String -> UI Action -> IO ()
runNamedUI name =
-- convert the @UI (Source Action)@ to a @UI ()@ and run.
M.runNamedUI name . M.act . unO
{----------------------------------------------------------
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 (Sink a)
-- | Make an input widget
iwidget :: M.IWidget a -> IWidget a
iwidget mwid a = O (mwid a)
-- | Make an output widget
owidget :: M.OWidget' a -> OWidget a
owidget = O . fmap pure
{----------------------------------------------------------
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
islider :: (Int,Int) -> IWidget Int
islider bounds = iwidget (M.islider bounds)
-- | Slider input widget over fractional values
fslider :: RealFrac a => (a,a) -> IWidget a
fslider bounds = iwidget (M.fslider bounds)
-- | Slider output widget with static bounds
isliderDisplay :: (Int,Int) -> OWidget Int
isliderDisplay bounds = owidget (M.isliderDisplay' bounds)
-- | Slider input widget over fractional values
fsliderDisplay :: RealFrac a => (a,a) -> OWidget a
fsliderDisplay bounds = owidget (M.fsliderDisplay' bounds)
-- | Boolean input widget
checkBoxEntry :: IWidget Bool
checkBoxEntry = iwidget M.checkBoxEntry
-- | Boolean display widget
checkBoxDisplay :: OWidget Bool
checkBoxDisplay = owidget M.checkBoxDisplay'
-- | Input from a \"menu\" of choices.
choices :: [String] -> IWidget String
choices strings = iwidget (M.choices strings)
-- | Input from a timer and a means of polling. Interval is in seconds.
-- If 'poll' is expensive, then apply 'cache' to the resulting UI.
timedPoll :: Double -> IO a -> UI a
timedPoll secs poll = O (M.timedPoll secs poll)
-- Wrap a title around a 'UI'
instance Title_f UI where title_f str = inO (title_f str)
{----------------------------------------------------------
Layout
----------------------------------------------------------}
-- | Lay out from top to bottom
fromTop :: Unop (UI a)
fromTop = inO M.fromTop
-- | Lay out from bottom to top
fromBottom :: Unop (UI a)
fromBottom = inO M.fromBottom
-- | Lay out from left to right
fromLeft :: Unop (UI a)
fromLeft = inO M.fromLeft
-- | Lay out from right to left
fromRight :: Unop (UI a)
fromRight = inO M.fromRight
-----
{-
-- 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
-}