packages feed

gooey (empty) → 0.0.0.0

raw patch · 4 files changed

+281/−0 lines, 4 filesdep +basedep +hashabledep +renderablesetup-changed

Dependencies added: base, hashable, renderable, transformers, varying

Files

+ LICENSE view
@@ -0,0 +1,20 @@+Copyright (c) 2015 Schell Scivally++Permission is hereby granted, free of charge, to any person obtaining+a copy of this software and associated documentation files (the+"Software"), to deal in the Software without restriction, including+without limitation the rights to use, copy, modify, merge, publish,+distribute, sublicense, and/or sell copies of the Software, and to+permit persons to whom the Software is furnished to do so, subject to+the following conditions:++The above copyright notice and this permission notice shall be included+in all copies or substantial portions of the Software.++THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.+IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY+CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,+TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE+SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ Setup.hs view
@@ -0,0 +1,2 @@+import Distribution.Simple+main = defaultMain
+ gooey.cabal view
@@ -0,0 +1,75 @@+-- Initial gooey.cabal generated by cabal init.  For further documentation,+--  see http://haskell.org/cabal/users-guide/++-- The name of the package.+name:                gooey++-- The package version.  See the Haskell package versioning policy (PVP)+-- for standards guiding when and how versions should be incremented.+-- http://www.haskell.org/haskellwiki/Package_versioning_policy+-- PVP summary:      +-+------- breaking API changes+--                   | | +----- non-breaking API additions+--                   | | | +--- code changes with no API change+version:             0.0.0.0++-- A short (one-line) description of the package.+synopsis:            Graphical user interfaces that are renderable,+                     change over time and eventually produce a value.++-- A longer description of the package.+description:         Gooey provides a monadic interface on top of automaton+                     based FRP. It is targeted towards controlling renderable+                     interfaces that eventually produce values.++-- The license under which the package is released.+license:             MIT++-- The file containing the license text.+license-file:        LICENSE++-- The package author(s).+author:              Schell Scivally++-- An email address to which users can send suggestions, bug reports, and+-- patches.+maintainer:          efsubenovex@gmail.com++-- A copyright notice.+-- copyright:++category:            Control++build-type:          Simple++-- Extra files to be distributed with the package, such as examples or a+-- README.+-- extra-source-files:++-- Constraint on the version of Cabal needed to build this package.+cabal-version:       >=1.10+++library+  ghc-options:         -Wall+  -- Modules exported by the library.+  exposed-modules:     Control.GUI++  -- Modules included in this library but not exported.+  -- other-modules:++  -- LANGUAGE extensions used by modules in this package.+  -- other-extensions:++  -- Other library packages from which modules are imported.+  build-depends:       base >=4.8 && <4.9,+                       varying >= 0.1.4 && < 0.2,+                       renderable >= 0.0.0.2,+                       transformers >= 0.4 && < 0.5,+                       hashable >= 1.2 && < 1.3++  -- Directories containing source files.+  hs-source-dirs:      src++  -- Base language which the package is written in.+  default-language:    Haskell2010+
+ src/Control/GUI.hs view
@@ -0,0 +1,184 @@+-- |+--   Module:     Control.GUI+--   Copyright:  (c) 2015 Schell Scivally+--   License:    MIT+--   Maintainer: Schell Scivally <efsubenovex@gmail.com>+--+--   Graphical user interfaces that are renderable, change over time and+--   eventually produce a value.+--+--   GUIs are comprised of event streams and renderable datatypes that change+--   over time. A GUI is a monadic layer on top of automaton varying values+--   provided by the 'varying' library.++{-# LANGUAGE TypeFamilies #-}+{-# LANGUAGE FlexibleContexts #-}+module Control.GUI (+    -- * Definition+    UX(..),+    GUI(..),+    -- * Creation+    -- $creation+    gui,+    -- * Transformation+    -- $transformation+    transformGUI,+    -- * Combination+    -- $combination+    combineGUI+) where++import Control.Varying+import Control.Monad.IO.Class+import Data.Renderable+import Data.Hashable+import Data.Monoid++--------------------------------------------------------------------------------+-- Defining a GUI+--------------------------------------------------------------------------------+-- | A discrete step in a "user experience". This is simply a type that+-- discretely describes an eventual value on the right and a renderable datatype+-- on the left. It is assumed that the left value is a datatype+-- that represents a user inteface and that the user is interacting with it+-- to eventually produce the datatype on the right.+data UX a b = UX a (Event b)++-- | A UX is a functor by applying a function to the contained event's value.+instance Functor (UX a) where+    fmap f (UX a b) = UX a $ (fmap f b)++-- | A UX is an applicative if its left datatype is a monoid. It replies to+-- 'pure' with an empty left value while the right value is the argument+-- wrapped in an event. It means "the argument happens instantly with no+-- user interface".+instance Monoid a => Applicative (UX a) where+    pure a = UX mempty $ Event a+    (UX uia f) <*> (UX uib b) = UX (uia <> uib) (f <*> b)++-- | A UX is renderable if its left value is also renderable. It inherits all+-- Renderable type variables from its left value and simply renders that+-- value.+instance Renderable a => Renderable (UX a b) where+    type RenderMonad (UX a b) = RenderMonad a+    type RenderRsrc (UX a b) = RenderRsrc a+    type RenderTfrm (UX a b) = RenderTfrm a+    nameOf (UX ui _) = nameOf ui+    cache rz rs (UX ui _) = cache rz rs ui+    composite (UX ui _) = composite ui++-- | A GUI is a UX that varies over some domain. What this means is that a+-- graphical user interface is essentially a user experience that eventually+-- produces a value. 'm' is the underlying monad. 'i' is the type of the user+-- input.  'a' is the renderable type - the interface itself. 'b' is the+-- eventual produced value.+newtype GUI m i a b = GUI { runGUI :: Var m i (UX a b) }++-- | A GUI can be a monoid if its UX\'s left and right types are monoids.+-- The identity is a GUI that has no user interface and immediately+-- produces an event who\'s value is the identity of its UX's right type.+-- The associative operation is to combine the two GUIs with 'combineGUI'.+instance (Monad m, Monoid a, Monoid b) => Monoid (GUI m i a b) where+    mempty = pure mempty+    mappend g h = combineGUI g h mappend++-- | A GUI is a functor by applying a function to the eventual produced+-- value.+instance Monad m => Functor (GUI m i a) where+    fmap f (GUI v) = GUI $ fmap (fmap f) v++-- | A GUI is applicative if its UX\'s left value is a monoid. It responds+-- to 'pure' by returning a GUI that has no user interface and immediately+-- produces the argument. It responds to '<*>' by applying the left+-- argument to the right. Each side\'s left UX value will be 'mappend' \'d.+instance (Monad m, Monoid a) => Applicative (GUI m i a) where+    pure = GUI . pure . pure+    (GUI vf) <*> (GUI va) = GUI $ ((<*>) <$> vf) <*> va++-- | A GUI is a monad if its UX's left value is a monoid. It responds to+-- '>>=' by returning a new GUI that runs until it produces a value, then+-- that value is used to create yet another GUI.+instance (Monad m, Monoid a) => Monad (GUI m i a) where+    (GUI v) >>= f = GUI $ Var $ \i -> do+        (UX a e, v') <- runVar v i+        case e of+            NoEvent -> return (UX a NoEvent, runGUI $ GUI v' >>= f)+            Event b -> runVar (runGUI $ f b) i++-- | A GUI can perform IO if its underlying monad can perform IO.+instance (MonadIO m, Monoid a) => MonadIO (GUI m i a) where+    liftIO f = GUI $ Var $ \_ -> do+        a <- liftIO f+        return (UX mempty (Event a), runGUI $ pure a)+--------------------------------------------------------------------------------+-- $creation+-- In order to create a GUI you must first have a datatype that is+-- 'Renderable'. Then you must create a 'varying' value of that datatype.+-- Also needed is an event stream that eventually ends the user's interaction.+-- The idea is that your interface varies over time and/or user input but+-- eventually produces a result value that can be used in a monadic+-- sequence.+--------------------------------------------------------------------------------+-- | Creates a new GUI displaying an interface that eventually produces a value.+-- The type used to represent the user interface must have a 'Decomposable'+-- instance, that way the resulting GUI\'s discrete values can be rendered.+gui :: (Monad m, Decomposable a m r t)+    => Var m i a+    -- ^ The stream of a changing user interface.+    -> Var m i (Event b)+    -- ^ The event stream that concludes a user\'s interaction. When this+    -- stream produces an event the interaction will end and the merging+    -- function will be used to create the GUI\'s return type.+    -> (a -> b -> c)+    -- ^ The merging function that combines the interface's final value with the+    -- value produced by the event stream.+    -> GUI m i [Element m r t] c+gui v ve f = GUI $ Var $ \i -> do+    (a, v')  <- runVar v i+    (e, ve') <- runVar ve i+    let ui = decompose a+    case e of+        NoEvent -> return (UX ui NoEvent, runGUI $ gui v' ve' f)+        Event b -> return (UX ui (Event $ f a b), pure $ UX [] $ Event $ f a b)+--------------------------------------------------------------------------------+-- $transformation+-- Simply put - here we are applying some kind of transformation to your+-- renderable interface. This most likely a standard two or three dimensional+-- affine transformation. Since the transformation also changes over the+-- same domain it\'s possible to tween GUIs.+--------------------------------------------------------------------------------+-- | Transforms a GUI.+transformGUI :: (Monad m, Monad (RenderMonad t), Show t, Show (RenderTfrm t),+                 Hashable t, Hashable (RenderTfrm t), Monoid (RenderTfrm t),+                 Renderable t)+             => Var m i (RenderTfrm t)+             -- ^ The stream of a changing transformation.+             -> GUI m i t b+             -- ^ The GUI to transform.+             -> GUI m i [Element (RenderMonad t) (RenderRsrc t) (RenderTfrm t)] b+transformGUI vt g = GUI $ Var $ \i -> do+    (UX ui e, v) <- runVar (runGUI g) i+    (t, vt') <- runVar vt i+    return (UX [Element (t,ui)] e, runGUI $ transformGUI vt' $ GUI v)+--------------------------------------------------------------------------------+-- $combination+-- Combining two GUIs creates a new GUI.+--------------------------------------------------------------------------------+-- | Combines two GUIs. The resulting GUI will not produce a value until+-- both component GUIs have produced a value. At that moment a merging function+-- is used to combine the two values into the resulting GUI\'s return type.+-- The component GUIs\' graphical representations (the left UX values) are+-- 'mappend'\d together.+combineGUI :: (Monad m, Monoid u)+           => GUI m i u a+           -- ^ The first GUI.+           -> GUI m i u b+           -- ^ The second GUI.+           -> (a -> b -> c)+           -- ^ The merging function.+           -> GUI m i u c+combineGUI (GUI va) (GUI vb) f = GUI $ Var $ \i -> do+        (UX a ea, va') <- runVar va i+        (UX b eb, vb') <- runVar vb i+        return (UX (a <> b) (f <$> ea <*> eb),+                runGUI $ combineGUI (GUI va') (GUI vb') f)