vision-0.0.2.2: src/Editor.hs
-- -*-haskell-*-
-- Vision (for the Voice): an XMMS2 client.
--
-- Author: Oleg Belozeorov
-- Created: 1 Sep. 2010
--
-- Copyright (C) 2010 Oleg Belozeorov
--
-- This program is free software; you can redistribute it and/or
-- modify it under the terms of the GNU General Public License as
-- published by the Free Software Foundation; either version 3 of
-- the License, or (at your option) any later version.
--
-- This program is distributed in the hope that it will be useful,
-- but WITHOUT ANY WARRANTY; without even the implied warranty of
-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
-- General Public License for more details.
--
{-# LANGUAGE DoRec #-}
module Editor
( EditorWidget (..)
, EditorDialog
, makeEditorDialog
, runEditorDialog
) where
import Control.Applicative
import Control.Monad
import Control.Concurrent.MVar
import Data.Maybe
import Graphics.UI.Gtk
import Compound
import Utils
class CompoundWidget w => EditorWidget w where
type Data w
setData :: w -> Data w -> IO ()
getData :: w -> IO (Data w)
clearData :: w -> IO ()
setupView :: w -> IO ()
focusView :: w -> IO ()
getState :: w -> IO (Bool, Bool)
resetModified :: w -> IO ()
clearData = const $ return ()
setupView = const $ return ()
focusView = const $ return ()
data EditorWidget e => EditorDialog e
= EditorDialog
{ eLock :: MVar ()
, eDialog :: Dialog
, eEditor :: e
}
instance EditorWidget e => CompoundWidget (EditorDialog e) where
type Outer (EditorDialog e) = Dialog
outer = eDialog
makeEditorDialog buttons makeEditor setup = do
lock <- newMVar ()
dialog <- dialogNew
hideOnDeleteEvent dialog
dialogSetHasSeparator dialog False
mapM_ (uncurry $ dialogAddButton dialog) buttons
dialogAddButton dialog stockCancel ResponseCancel
dialogAddButtonCR dialog stockOk ResponseOk
rec { editor <- makeEditor dialog $ updateState dialog editor }
upper <- dialogGetUpper dialog
boxPackStartDefaults upper $ outer editor
widgetShowAll $ outer editor
let e = EditorDialog { eLock = lock
, eDialog = dialog
, eEditor = editor
}
setup e
return e
runEditorDialog e get set modal parent = do
let dialog = eDialog e
editor = eEditor e
lock = eLock e
locked <- isJust <$> tryTakeMVar lock
when locked $ do
windowSetModal dialog modal
windowSetTransientFor dialog parent
when modal $ do
windowGroup <- windowGroupNew
windowGroupAddWindow windowGroup parent
windowGroupAddWindow windowGroup dialog
setData editor =<< get
resetModified editor
updateState dialog editor
dialogSetDefaultResponse dialog ResponseOk
setupView editor
focusView editor
rec { cid <- dialog `onResponse` \resp -> do
let done = do
signalDisconnect cid
widgetHide dialog
clearData editor
putMVar lock ()
dialogSetDefaultResponse dialog ResponseOk
focusView editor
case resp of
ResponseApply -> do
(valid, modified) <- getState editor
when (valid && modified) (set =<< getData editor)
resetModified editor
updateState dialog editor
ResponseOk -> do
(valid, modified) <- getState editor
when valid $ do
when modified (set =<< getData editor)
done
_ -> done
}
return ()
windowPresent dialog
updateState dialog editor = do
(valid, modified) <- getState editor
dialogSetResponseSensitive dialog ResponseOk valid
dialogSetResponseSensitive dialog ResponseApply modified