{-# LANGUAGE FlexibleInstances #-} {-# LANGUAGE MultiParamTypeClasses #-} -- | Basic dialog window and a couple of predefined abstractions. module HTk.Toolkit.DialogWin ( Dialog, dialog, createAlertWin, createErrorWin, createWarningWin, createConfirmWin, createMessageWin, createAlertWin', createErrorWin', createWarningWin', createConfirmWin', createMessageWin', createDialogWin, createDialogWin', loadHTkImages, questionImg, useHTk, ) where import Data.Maybe(fromMaybe) import System.IO.Unsafe import Util.Messages import Util.ExtendedPrelude (newFallOut,mkBreakFn) import Util.Computation import Events.Events import HTk.Kernel.Core import qualified HTk.Toplevel.HTk as HTk (font) import HTk.Toplevel.HTk hiding (font) import HTk.Widgets.Space import HTk.Toolkit.SelectBox import HTk.Toolkit.ModalDialog import HTk.Toolkit.MarkupText import HTk.Toolkit.Separator -- -------------------------------------------------------------------------- -- Types -- -------------------------------------------------------------------------- -- | A @Choice@ represents the name of a button (@String@) and the -- value returned when this button is pressed. type Choice a = (String,a) -- | The @Dialog@ datatype. data Dialog a = Dialog { fWindow :: Toplevel, fEditor :: Maybe Editor, -- we only have fMsg :: Maybe Message, -- one of these two fLabel :: Label, fSelectBox :: SelectBox, fEvents :: (Event a) } -- -------------------------------------------------------------------------- -- Instances -- -------------------------------------------------------------------------- -- | Internal. instance GUIObject (Dialog a) where toGUIObject dlg = toGUIObject (fWindow dlg) cname dlg = cname (fWindow dlg) -- | A dialog can have an image instance HasPhoto (Dialog a) where photo p dlg = do {fLabel dlg # photo p; return dlg} -- | The programm message is displayed as @MarkupText@ instance HasMarkupText (Dialog a) where new t dlg = case fEditor dlg of Just e -> do {e # new t; return dlg} _ -> return dlg insertAt _ _ _ = error "HTk.Toolkit.DialogWin.instance HasMarkupText (Dialog a) insertAt" clear = error "HTk.Toolkit.DialogWin.instance HasMarkupText (Dialog a) clear" -- | The message displayed as plain text. instance GUIValue v=> HasText (Dialog a) v where text t dlg = case fMsg dlg of Just l -> do {l # text t; return dlg} _ -> return dlg -- | Returns configuration option for dialogs that displays text using a -- scrollbox if it is bigger than the default size (currently (60,6). -- It also returns a Bool which indicates if we are to use createDialogWin -- (False) or createDialogWin' (True). scrollText :: String -> (Config (Dialog a),Bool) scrollText = scrollText1 (60,6) -- | Configuration option for dialogs that displays text using a scrollbox -- if it is bigger than the given size. -- -- NB. The argument (39,6) to scrollMarkupText cannot be increased without -- increasing the size of the message window, which is hardcoded into this -- module. scrollText1 :: Size -> String -> (Config (Dialog a),Bool) scrollText1 size str = if biggerThan size str then (new [scrollMarkupText (39,6) [prose str]],True) else (text str,False) where biggerThan (xMax,yMax) str = let strl = lines str in length strl > fromIntegral yMax || any (\ line -> length line > fromIntegral xMax) strl -- -------------------------------------------------------------------------- -- Derived Dialog Window -- -------------------------------------------------------------------------- -- | Constructs an alert window with the given text createAlertWin :: String -- ^ the text to be displayed -> [Config Toplevel] -> IO () createAlertWin str wol = do catchDestroyedFallOut (createFn choices Nothing confs (defs ++ wol)) done where choices = [("Continue",())] defs = [text "Alert Window"] (scrollConf,complex) = scrollText str confs = [scrollConf,photo warningImg] createFn = if complex then createDialogWin' else createDialogWin -- | Constructs an alert window with the given markuptext createAlertWin' :: [MarkupText] -- ^ the markuptext to be displayed -> [Config Toplevel] -> IO () createAlertWin' str wol = do catchDestroyedFallOut ( createDialogWin' choices Nothing (confs++[photo warningImg]) (defs ++ wol) ) done where choices = [("Continue",())] defs = [text "Alert Window"] confs = [new str] -- | Constructs an error window with the given text createErrorWin :: String -- ^ the text to be displayed -> [Config Toplevel] -> IO () createErrorWin str wol = do catchDestroyedFallOut (createFn choices Nothing confs (defs++wol)) done where choices = [("Continue",())] defs = [text "Error Message"] (scrollConf,complex) = scrollText str confs = [scrollConf,photo errorImg] createFn = if complex then createDialogWin' else createDialogWin -- | Constructs an error window with the given markuptext createErrorWin' :: [MarkupText] -- ^ the markuptext to be displayed -> [Config Toplevel] -> IO () createErrorWin' str wol = do catchDestroyedFallOut ( createDialogWin' choices Nothing (confs++[photo errorImg]) (defs++wol) ) done where choices = [("Continue",())] defs = [text "Error Message"] confs = [new str] -- | Constructs an warning window with the given text createWarningWin :: String -- ^ the text to be displayed -> [Config Toplevel] -> IO () createWarningWin str confs = createAlertWin str (text "Warning Message": confs) -- | Constructs an warning window with the given markuptext createWarningWin' :: [MarkupText] -- ^ the markuptext to be displayed -> [Config Toplevel] -> IO () createWarningWin' str confs = createAlertWin' str (text "Warning Message": confs) -- | Constructs an confirm window with the given text createConfirmWin :: String -- ^ the text to be displayed -> [Config Toplevel] -> IO Bool -- ^ True(Ok) or False(Cancel) createConfirmWin str wol = do bOpt <- catchDestroyedFallOut ( createFn choices (Just 0) confs (defs ++ wol) ) return (fromMaybe False bOpt) where choices = [("Ok",True),("Cancel",False)] defs = [text "Confirm Window"] (scrollConf,complex) = scrollText str confs = [scrollConf,photo questionImg] createFn = if complex then createDialogWin' else createDialogWin -- | Constructs an confirm window with the given markuptext createConfirmWin' :: [MarkupText] -- ^ the markuptext to be displayed -> [Config Toplevel] -> IO Bool -- ^ True(Ok) or False(Cancel) createConfirmWin' str wol = do bOpt <- catchDestroyedFallOut ( createDialogWin' choices (Just 0) (confs++[photo questionImg]) (defs ++ wol) ) return (fromMaybe False bOpt) where choices = [("Ok",True),("Cancel",False)] defs = [text "Confirm Window"] confs = [new str] -- | Constructs a message (info) window with the given markuptext createMessageWin' :: [MarkupText] -- ^ the markup text to be displayed -> [Config Toplevel] -> IO () -- ^ () createMessageWin' str wol = do catchDestroyedFallOut ( createDialogWin' [("Dismiss", ())] Nothing [new str, photo infoImg] (text "Information": wol) ) done -- | Constructs a message (info) window with the given string. createMessageWin :: String -- ^ the string to be displayed -> [Config Toplevel] -> IO () -- ^ () createMessageWin str wol = do catchDestroyedFallOut ( createFn [("Dismiss", ())] Nothing confs (text "Information": wol) ) done where (scrollConf,complex) = scrollText str confs = [scrollConf,photo infoImg] createFn = if complex then createDialogWin' else createDialogWin -- | Constructs a new dialogue window for plain text createDialogWin :: [Choice a] -- ^ the available buttons in this window -> Maybe Int -- ^ default button -> [Config (Dialog a)] -- ^ the list of configuration options for this separator -> [Config Toplevel] -- ^ the list of configuration options for the window -> IO a -- ^ createDialogWin choices def confs wol = do dlg <- dialog True choices def confs wol result <- modalInteraction (fWindow dlg) True True (fEvents dlg) return result -- | Constructs a new dialow window for markup text createDialogWin' :: [Choice a] -- ^ the available buttons in this window -> Maybe Int -- ^ default button -> [Config (Dialog a)] -- ^ the list of configuration options for this separator -> [Config Toplevel] -- ^ the list of configuration options for the window -> IO a -- ^ createDialogWin' choices def confs wol = do dlg <- dialog False choices def confs wol result <- modalInteraction (fWindow dlg) True True (fEvents dlg) return result -- -------------------------------------------------------------------------- -- Base Dialog Window -- -------------------------------------------------------------------------- -- | Creates a new dialogue with its label, text and buttons. dialog :: Bool -- ^ the available button in this window -> [Choice a] -- ^ true if we just want a label to display message, false if we want a fancy read-only text editor -> Maybe Int -- ^ default button -> [Config (Dialog a)] -- ^ the list of configuration options for this separator -> [Config Toplevel] -- ^ the list of configuration options for the window -> IO (Dialog a) -- ^ a dialog dialog plain choices def confs tpconfs = do (tp, emsg, lmsg, lbl, sb, ev) <- delayWish $ do tp <- createToplevel tpconfs pack tp [Expand On, Fill Both] b <- newVBox tp [] pack b [Expand On, Fill Both] b2 <- newHBox b [] pack b2 [Expand On, Fill Both] lbl <- newLabel b2 [] pack lbl [Expand On, Fill Both, PadX (cm 0.5), PadY (cm 0.5)] (lmsg, emsg) <- if plain then do l <- newMessage b2 [borderwidth 0, justify JustCenter, aspect 750, HTk.font (Helvetica, Roman, 18::Int)] pack l [Expand On, Fill Both, PadX (cm 0.5), PadY (cm 0.5)] return (Just l, Nothing) else do msg <- newEditor b2 [size (30,5), borderwidth 0, state Disabled, wrap WordWrap, HTk.font (Helvetica, Roman, 18::Int)] pack msg [Expand On, Fill Both, PadX (cm 0.5), PadY (cm 0.5)] return (Nothing, Just msg) sp1 <- newSpace b (cm 0.15) [] pack sp1 [Expand Off, Fill X, Side AtBottom] newHSeparator b sp2 <- newSpace b (cm 0.15) [] pack sp2 [Expand Off, Fill X, Side AtBottom] sb <- newSelectBox b Nothing [] pack sb [Expand Off, Fill X, Side AtBottom] events0 <- mapM (createChoice sb) choices let ev0 = choose events0 -- Arrange for escape when the user destroys the window (destroyEvent,unbindAction) <- bindSimple tp Destroy let ev = (do result <- ev0 always unbindAction return result ) +> (do destroyEvent always unbindAction destroyedFallOut ) return (tp, emsg, lmsg, lbl,sb,ev) dlg <- configure (Dialog tp emsg lmsg lbl sb ev) confs return dlg where createChoice :: SelectBox -> Choice a -> IO (Event a) createChoice sb (str,val) = do but <- addButton sb [text str] [Expand On, Side AtRight] clickedbut <- clicked but return (clickedbut >> (always (return val))) destroyedFallOutPair :: (ObjectID,IO a -> IO (Either String a)) destroyedFallOutPair = unsafePerformIO newFallOut {-# NOINLINE destroyedFallOutPair #-} destroyedFallOut :: a destroyedFallOut = mkBreakFn (fst destroyedFallOutPair) "DESTROYED" catchDestroyedFallOut :: IO a -> IO (Maybe a) catchDestroyedFallOut act = do strOrA <- (snd destroyedFallOutPair) act return (case strOrA of Left "DESTROYED" -> Nothing Right a -> Just a ) -- -------------------------------------------------------------------------- -- The useHTk function -- -------------------------------------------------------------------------- htkMessFns :: MessFns htkMessFns = MessFns { alertFn = (\ mess -> createAlertWin mess []), errorFn = (\ mess -> createErrorWin mess []), warningFn = (\ mess -> createWarningWin mess []), confirmFn = (\ mess -> createConfirmWin mess []), messageFn = (\ mess -> createMessageWin mess []), htkPres = True } useHTk :: IO () useHTk = setMessFns htkMessFns -- Deprecate the alternative {-# DEPRECATED createAlertWin,createErrorWin,createWarningWin, createConfirmWin,createMessageWin "Please use the functions in util/Messages instead" #-} -- -------------------------------------------------------------------------- -- Images for the various Dialog Windows -- -------------------------------------------------------------------------- loadHTkImages :: () loadHTkImages = foldr seq () [errorImg,warningImg,questionImg,infoImg] -- It's important that we create these with unsafePerformIO, this lets -- Tk reuse the definition-- otherwise we send the whole image data -- over to the wish again every time somebody opens one of these windows. errorImg :: Image errorImg = unsafePerformIO (newImage [imgData GIF "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"]) {-# NOINLINE errorImg #-} warningImg :: Image warningImg = unsafePerformIO (newImage [imgData GIF "R0lGODlhMAAwAPU3AAAAABYKAhoUARQUFCcIBiUdAz0MCCsiAzUpBSsrK0YNCE0QDFIOB1wSC0U1BlE/B2kTC3QVDXgYEVJAB2hRCnNZC3thC4gYDYcbEpQbD5weFKQdDqEdEbMfD7IfELkgD7khEatCFrFAELpbEr9vFpJPSMkjEdYlE+opFPUqE8JtFMd+FbmTDr2TEsyHFMObD8ebE9GKE9uqFt+xEuCuEuCyE4CAgP///wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAFkADcALAAAAAAwADAAAAb+wNvtdrvdbrfb7Xa73W632+12u91ut9vtdrvdbrfb7Xa73W632+12u91ut9vtdrvdbrfb7Xa73YC32+12u91ut9vtdrvdbrfb7Xa73W632+12u91ut9vtdrvdbrfb7Xa73W632+12u91ut9vtdrsBb7fb7Xa73W632+12u91ut9vtdrvdbrfb7Xa73W632+12u91ut9vtdrvdbrfb7Xa73W632+12A95ut9vtdrvdbrfb7Xa73W632+12u91ut9vtdrvdbrfb7Xa73W632+12u91ut9vtdrvdbrfb7Qa83W632+12u91ut9vtdrvdbrfb7Xa73W632+12u91ut9v+7Xa73W632+12u91ut9vtdrvdbrfbDXi73W632+12u91ut9vtdrvdbrfb7Xa73W632+12u91ut9vtdrvdbrfb7Xa7oVKmjO12u91utxvwdrvdbrfb7Xa73W632+12u91ut9vtdrvdbrfb7Xa7oVKnzQUAuN1ut9vtdrvdbrfb7Xa73W434O12u91ut9vtdrvdbrfb7Xa7bVKnzSYDAQBut9vtdrvdbrfb7Xa73W632+12u91ut9vtdrvdbsDb7Xa7bVKoz2bDuRAGgNvtdrvdbrfb7Xa73W632+12u91ut9vtdrvdbrfb7Xa7pVKdzQa0yUCAAMDtdrvdbrfb7Xb+u91ut9vtdrvdbrfb7Xa73W632+12u21Sps1mRNpsMgYA4Ha73W632+12uwFvt9vtdrvdbrfb7Xa73W632+12u21Sp81mM5ttNhsJAAC43W632+12u91ut9vtdrvdbrfb7XYD3m632+12u91QqM5mM5vNYhtOZgEA3G632+12u91ut9vtdrvdbrfb7Xa73W632+12u21Sps1GBZzNZjMOhxMBAAC32+12u91ut9vtdrvdbrfb7Xa73W632+12u21SqM1mQ5uxZDLXRpNZAAC32w14u91ut9vtdrvdbrfb7Xa73W632+12u91Qqc5mE3sBAo6ZbLPRSAAAwO12u93+brfb7Xa73W63G/B2u91ut9vtdrvdNqnTZrOZWQABwIzm2mgwCwDgdrvdbrfb7Xa73W632+12u91ut9vtdrvdUCigZ7OZzQ4AgGBGk2k2GgkAALjdbrfb7Xa73W632+12u91ut9vtdrvdNinTZhOj0Q4AQIEmk7k2QI1mAQDcbrfb7Xa73W632+12u91ut9vtdrvdNqnTZrOh0WgFgMAhk8lkGo1GAgAAbrfb7Xa73YC32+12u91ut9vtdrvdbhFUZ7OJ0Wi0B8DhkMlkMpdGg1kAALfb7Xa73W632+12u91ut9vtdrsBb5vUabPZ0Gi0mQBQcMhoMplMo9FAAAD+wO12u91ut9vtdrvdbrfb7Xa73W4oFGizqdVmslkAEAAWZDKZTObSaCQEAOB2u91ut9vtdrvdbrfb7Xa73W4b1GmzidFqspkMEAAgZDKZTCbTaDQNwAAAvN1ut9vtdrvdbrfb7Xa73W43FArE2cxqsplsBggAJjKZTCaTuTQayQAAuN1ut9vtdrvdbrfbDXi73W63DerE4cRmNBlNNkNMBBWZTCaTyWQaDWYBANxut9vtdrvdbrfb7Xa73W43FOqz2cxmMxlwJpO1KIeWTCaTyWQyl0YjAQAAt9vtdrvdbrfb7Xa73W63Deq02cRmMtlMJpPJZDKZTCaTyWQyoAz+o8EsAIDb7Xa73W632+12u91utxsKBdJsZjIaTSaTyWCHQksmk8lkMpmMpNE0AADA7Xa73W7A2+12u91ut9sGddpsYjSajCaTyWQPAIAik8lkMplM5tJoJAQA4Ha73W632+12u91ut1sJBeJsgDJajSaTyWQyBCBQkclkMplMJpNpNJgFAHC73W632+12u91ut9sGddpwXDVaTSaTyWSyFsIikwFlMplMJpPJSBoNBDAA3G632+12u91ut9stggJtOBsOh8PhjFQul0wmk8lkMplMJpPBSCWNhAAAJm632+12u91ut9vtpjBtOBwOh8PhcDQcDkej0Wg0Go1Go9H+aDQajQazAAAAt9vtdrvdbrfb7QYMSBqRSOSCyWg0Go1Go+FoNBqNRqPRaDQajUajaQAAgNvtdrvdbrfb7XYDAACAAIFgWDQaDYgEKJFgMBgMBoPBSCQYDAYjkSwAA8Dtdrvdbrfb7Xa7AQAAAAAAAAAAAECAQCAQFAaDQmEwJAwGA9BgMBAGAADgdrvdbrfb7Xa73QAAAAAAAAAAAAAAAAAAAAAAAAAAAAYAAGAAAAwAAADgdrvdbjfg7Xa73W43AAAAGAQAAAAAAAAAAAAAAAAAAAAAwAAAAAAAAAAAcLvdbrfb7Xa73W632+12AwAAQAAAAAAAAIPAAAAAAAD+AAAAAAAAAAAAAAC43W632+12u91ut9vtdrvdbrfb7Xa7AQAAAAAAAACAAAAAAAAAAAAAAHC73W632+12u91ut9vtdrvdbrfb7Xa73W632+12u91ut9vtdrvdbrfb7Xa7AW+32+12u91ut9vtdrvdbrfb7Xa73W632+12u91ut9vtdrvdbrfb7Xa73W632+12u91ut9vtdgPebrfb7Xa73W632+12u91ut9vtdrvdbrfb7Xa73W632+12u91ut9vtdrvdbrfb7Xa73W632+0GvN1ut9vtdrvdbrfb7Xa73W632+12u91ut9vtdrvdbrfb7Xa73W632+12u91ut9sT7Xa73W632w14u91ut9vtdrsFAQA7"]) {-# NOINLINE warningImg #-} questionImg :: Image questionImg = unsafePerformIO (newImage [imgData GIF "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mUwmk8lkMplMJpPJZDKZTCaTyWQymUwmk8lkMgALSPpgAABAKiaTyWQymUwmk8lkMplMJpPJZDKZTCaTyWQymUwmk8lkMhngQ+IkAABAKiaTyWQyGVAmk8lkMplMJpPJZDKZTCaTyWQymUwmk8lkMplMBgAAAAAAIBWTyWQymUwmk8lkMplMJpPJZDKgTCaTyWQymUwmk8lkMplMJgMAAAAAwJGKyWQymUwmk8lkMplMJpPJZDKZTCaTyWQymUwmk8lkQJlMJpPJAAAAIOVIxWT+MplMJpPJZDKZTCaTyWQymUwmk8lkMplMJpPJZDKZTCaTyWQAh8ORismAMplMJpPJZDKZTCaTyWQymUwmk8lkMplMJpPJZDKZTCaTyWQymUwmk8lkMplMJpPJZDKZTCaTAWUymUwmk8lkMplMJpPJZDKZTCaTyWQymUwmk8lkMplMJpPJZDKZTCaTyWQymUwmk8lkMplMJgPKZDKZTCaTyWQymUwmk8lkMplMJpPJZDKZTCaTyWQymUwmk8lkMplMJpPJZDKZTCaTyWQymUwGlMlkMplMJpPJZDKZTCaTyWQymUwmk8lkMplMJpPJZDKZTCaTyWQymUwmk8lkMpkTTCaTyWQymQwok8lkMplMJpMFAQA7"]) {-# NOINLINE questionImg #-} infoImg :: Image infoImg = unsafePerformIO (newImage [imgData GIF "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"]) {-# NOINLINE infoImg #-}