packages feed

billeksah-forms-1.0.0: src/Graphics/Forms/Description.hs

{-# Language EmptyDataDecls, DeriveDataTypeable, ExistentialQuantification,
    StandaloneDeriving, TypeFamilies #-}
-----------------------------------------------------------------------------
--
-- Module      :  Graphics.UI.Editor.DescriptionPP
-- Copyright   :  (c) Juergen Nicklisch-Franken, Hamish Mackenzie
-- License     :  GNU-GPL
--
-- Maintainer  :  <maintainer at leksah.org>
-- Stability   :  provisional
-- Portability :  portable
--
-- | Description of a editor with additional fileds for printing and parsing
--
-----------------------------------------------------------------------------------
module Graphics.Forms.Description (
    mkField
,   formsPluginInterface
,   initPrefs
) where

import Graphics.Forms.Basics
import Graphics.Forms.Parameters
import Graphics.Forms.Build
import Graphics.Forms.GUIEvent
import Graphics.Forms.Composite (pairEditor)
import Graphics.Forms.Simple (genericEditor, stringEditor)
import Graphics.Forms.Sets
import Graphics.Pane
import Base

import Graphics.UI.Gtk
import qualified Text.PrettyPrint.HughesPJ as PP
import qualified Text.ParserCombinators.Parsec as P
import Data.Version (Version(..))
import qualified Data.Map as Map (empty)
import Base.Preferences (loadPrefs, validatePrefs)
import Data.List (sortBy)
import Graphics.Panes.Preferences
       (PreferencesPane, openPreferencesPane)
import Control.Monad (liftM, when)
import System.FilePath ((</>), dropFileName)
import System.Directory (doesFileExist)
import Control.Monad.IO.Class (MonadIO(..))

-- ----------------------------------------------
-- * It's a plugin
--

formsPluginInterface :: StateM (PluginInterface FormsEvent)
formsPluginInterface = do
    fe <- makeEvent FormsEventSel
    return $ PluginInterface {
         piInit1   = formsInit1,
         piInit2   = formsInit2,
         piEvent   = fe,
         piName    = pluginNameForms,
         piVersion = Version [1,0,0][]}

-- -----------------------------------------------
-- * Initialization
--

formsInit1 :: BaseEvent -> EventChannel FormsEvent -> StateM ()
formsInit1 _baseEvent _myEvent = do
    message Debug ("init1 " ++ pluginNameForms)
    initialRegister
    return ()

formsInit2 :: BaseEvent -> EventChannel FormsEvent -> StateM ()
formsInit2 _baseEvent _myEvent = do
    message Debug ("init2 " ++ pluginNameForms)
    registerFrameEvent handler >> return ()
  where handler (RegisterActions actions) = return $ RegisterActions $ actions ++ myActions
        handler (RegisterPane paneTypes)  = return $ RegisterPane $ paneTypes ++ myPaneTypes
        handler e                         = return e

myActions :: [ActionDescr]
myActions =
    [AD "Configuration" "_Configuration" Nothing Nothing (return ()) Nothing ActionSubmenu
            (Just $ MPAfter ["View"] False) Nothing [],
     AD "EditPrefs" "EditPrefs" Nothing Nothing openPreferencesPane Nothing ActionNormal
        (Just $ MPLast ["Configuration"] False) Nothing []]

myPaneTypes :: [(String,GenPane)]
myPaneTypes =
    [asRegisterType (undefined :: PreferencesPane)]

defaultPrefsName :: String
defaultPrefsName = "Default.prefs"

initialRegister :: StateM (Maybe String)
initialRegister = do
    registerState GuiHandlerStateSel (Handlers Map.empty)
    registerState GtkEventsStateSel (GtkRegMap Map.empty)
    registerState PrefsDescrState []
    currentConfigPath <- liftM dropFileName getCurrentConfigPath
    registerCurrentPrefsPath (currentConfigPath </> defaultPrefsName)

type MkFieldDescription alpha beta =
    Parameters      ->
    (Printer beta)     ->
    (Parser beta)      ->
    (Getter alpha beta)    ->
    (Setter alpha beta)    ->
    (Editor beta)      ->
    (Applicator beta)  ->
    FieldDescription alpha

mkField :: Eq beta => MkFieldDescription alpha beta
mkField parameters printer parser getter setter editor applicator  =
    let FieldG _ ed = mkFieldG (getParaS "Name" parameters) parameters getter setter editor
    in Field parameters
        (\ dat -> (PP.text (getParaS "Name" parameters) PP.<> PP.colon)
                PP.$$ (PP.nest 15 (printer (getter dat)))
                PP.$$ (PP.nest 5 (case getPara "Synopsis" parameters of
                                    ParaString "" -> PP.empty
                                    ParaString str -> PP.text $"--" ++ str
                                    _ -> error "Description>>mkField: impossible")))
        (\ dat -> P.try (do
            symbol (let ParaString str = getPara "Name" parameters in str)
            colon
            val <- parser
            return (setter val dat)))
        ed
        (\ newDat oldDat -> do --applicator
            let newField = getter newDat
            let oldField = getter oldDat
            if newField == oldField
                then return ()
                else applicator newField)

-- ----------------------------------------------
-- * Editing preferences
--

initPrefs :: StateM ()
initPrefs  = do
    prefsPath <- getCurrentPrefsPath
    RegisterPrefs allPrefs <- triggerFormsEvent
        (RegisterPrefs [("Frame",GenF panesPrefs defaultPanePrefs)])
    liftIO $ putStrLn ("Categories: " ++ show (map fst allPrefs))
    case validatePrefs allPrefs of
        Nothing -> return ()
        Just str -> error $ "Description>>formsInit2::"++ str
    setState PrefsDescrState allPrefs
    hasPrefsFile <- liftIO $ doesFileExist prefsPath
    when hasPrefsFile $
        loadPrefs prefsPath

defaultPanePrefs :: PanePrefs
defaultPanePrefs =  PanePrefs [] [] [SplitP LeftP]

panesPrefs :: FieldDescription PanePrefs
panesPrefs =
    VertBox defaultParams
        [mkField
            (("Name",ParaString "Categories for panes") <<<
             ("Shadow",ParaShadow ShadowIn) <<<
             ("Direction",ParaDir Vertical) <<<
             ("MinSize",ParaSize (-1,130)) <<<
             defaultParams)
            (PP.text . show)
            readParser
            (\ a -> ppCategoryForPane a)
            (\ b a -> a{ppCategoryForPane = b})
            (multisetEditor
                (ColumnsDescr True [
                    ColumnDescr{
                        tcdLabel = "Pane Id",
                        tcdRenderer = cellRendererTextNew,
                        tcdRenderFunc = \(n,_) -> [cellText := n],
                        tcdMbEditFunc = Nothing},
                    ColumnDescr{
                        tcdLabel = "Pane category",
                        tcdRenderer = cellRendererTextNew,
                        tcdRenderFunc = \(_,v) -> [cellText := v],
                        tcdMbEditFunc = Nothing}])
                ((pairEditor
                    (stringEditor (\s -> not (null s)) True,defaultParams)
                    (stringEditor (\s -> not (null s)) True,defaultParams)),defaultParams)
                (Just (sortBy (\(a,_) (a2,_) -> compare a a2)))
                (Just (\(a,_) (a2,_) -> a == a2)))
            (\_i -> return ())
    ,   mkField
            (("Name", ParaString "Pane path for category") <<<
            ("Shadow", ParaShadow ShadowIn) <<<
            ("Direction", ParaDir Vertical) <<<
            ("MinSize", ParaSize (-1,130)) <<<
                defaultParams)
            (PP.text . show)
            readParser
            ppPathForCategory
            (\b a -> a{ppPathForCategory = b})
            (multisetEditor
                (ColumnsDescr True [
                    ColumnDescr{
                        tcdLabel = "Pane category",
                        tcdRenderer = cellRendererTextNew,
                        tcdRenderFunc = \(n,_) -> [cellText := n],
                        tcdMbEditFunc = Nothing},
                    ColumnDescr{
                        tcdLabel = "Pane path",
                        tcdRenderer = cellRendererTextNew,
                        tcdRenderFunc = \(_,v) -> [cellText := show v],
                        tcdMbEditFunc = Nothing}])
                ((pairEditor
                    (stringEditor (\s -> not (null s)) True,defaultParams)
                    (genericEditor,defaultParams)),defaultParams)
                (Just (sortBy (\(a,_) (a2,_) -> compare a a2)))
                (Just (\(a,_) (a2,_) -> a == a2)))
            (\_i -> return ())
    ,   mkField
            (("Name", ParaString "Default pane path") <<< defaultParams)
            (PP.text . show)
            readParser
            ppDefaultPath
            (\b a -> a{ppDefaultPath = b})
            genericEditor
            (\_i -> return ())]