-- | A combined environment combines a view and a model in a MVC-structured
-- application. The environment can be passed around to the controller, which
-- must update each side accordingly and keep both in sync.
--
-- In this package, the view is built using GTK, and the model is implemented
-- as a 'ProtectedModel' (a safe-thread structure with a fine-grained notion
-- of change).
--
-- Copyright : (C) Keera Studios Ltd, 2013
-- License : BSD3
-- Maintainer : support@keera.co.uk
module Hails.MVC.GenericCombinedEnvironment
( -- * Combined Environments (CEnvs)
CEnv (view, model)
-- * CEnv construction
, createCEnv
-- * CEnv updates
, installCondition
, installConditions
)
where
-- Internal libraries
import Hails.MVC.Model.ProtectedModel (ProtectedModel, startProtectedModel)
import Hails.MVC.Model.ReactiveModel (Event)
import Hails.MVC.View (createView)
import Hails.MVC.View.GtkView (GtkGUI, GtkView)
-- | Given a GUI and a type for the events that capture the changes inside the
-- model, a CEnv contains a view and a protected model.
data (GtkGUI a, Event c) => CEnv a b c = CEnv
{ view :: GtkView a -- ^ View in the CEnv of an MVC application.
, model :: ProtectedModel b c -- ^ Model in the CEnv of an MVC application.
}
-- | Create a combined environment from a given model and initialize the
-- model and the view. The default model must be provided explicitly.
-- The initialisation operations for the view and the protected model
-- are called internally.
createCEnv :: (GtkGUI a, Event c) => b -> IO (CEnv a b c)
createCEnv emptyBM = CEnv <$> createView
<*> startProtectedModel emptyBM
-- | Install a condition in a Combined Environment. Conditions, or
-- reactive rules, are used to keep both the model and the view
-- in sync.
-- NOTE: This is an experimental function and might be removed in the future.
installCondition :: (GtkGUI a, Event c)
=> CEnv a b c
-> (CEnv a b c -> IO ())
-> IO ()
installCondition cenv cond = cond cenv
-- | Install several conditions in a Combined Environment. Conditions, or
-- reactive rules, are used to keep both the model and the view
-- in sync.
-- FIXME: I really don't like the syntax
-- installConditions cenv
-- [ rv1 =:= rf1
-- , ...
-- ]
--
-- I'd rather use
-- installConditions cenv $ do
-- rv1 =:= rf1
-- rv2 =:= rf2
-- ...
-- Which means that I would have to define a monad.
--
-- NOTE: This is an experimental function and might be removed in the future.
installConditions :: (GtkGUI a, Event c)
=> CEnv a b c
-> [CEnv a b c -> IO ()]
-> IO ()
installConditions cenv conds = mapM_ (installCondition cenv) conds