{-# LANGUAGE OverloadedStrings #-} -- | Notebook demo (include Spinner animation). -- Author : Andy Stewart -- Copyright : (c) 2010 Andy Stewart module Main where import Control.Monad import Control.Monad.IO.Class import Data.Maybe import Data.Text (Text) import Data.Monoid ((<>)) import Graphics.UI.Gtk import qualified Data.Text as T (unpack) data NotebookTab = NotebookTab {ntBox :: HBox ,ntSpinner :: Spinner ,ntLabel :: Label ,ntCloseButton :: ToolButton ,ntSize :: Int} -- | Main main :: IO () main = do -- Init. initGUI -- Create window and notebook. window <- windowNew notebook <- notebookNew -- Set window. windowSetDefaultSize window 800 600 windowSetPosition window WinPosCenter set window [windowTitle := ("Press Ctrl + n to create new tab."::Text)] -- Handle key press action. window `on` keyPressEvent $ tryEvent $ do -- Create new tab when user press Ctrl+n [Control] <- eventModifier "n" <- eventKeyName liftIO $ do -- Create text view. textView <- textViewNew widgetShowAll textView -- must show before add notebook, -- otherwise notebook won't display child widget -- even have add in notebook. -- Create notebook tab. tab <- notebookTabNew (Just "Cool tab") Nothing menuLabel <- labelNew (Nothing :: Maybe Text) -- Add widgets in notebook. notebookAppendPageMenu notebook textView (ntBox tab) menuLabel -- Start spinner animation when create tab. notebookTabStart tab -- Stop spinner animation after finish load. timeoutAdd (notebookTabStop tab >> return False) 5000 -- Close tab when click button. ntCloseButton tab `onToolButtonClicked` do index <- notebookPageNum notebook textView index ?>= \i -> notebookRemovePage notebook i return () -- Show window. window `containerAdd` notebook widgetShowAll window on window objectDestroy mainQuit mainGUI -- | Create notebook tab. notebookTabNew :: Maybe Text -> Maybe Int -> IO NotebookTab notebookTabNew name size = do -- Init. let iconSize = fromMaybe 12 size box <- hBoxNew False 0 spinner <- spinnerNew label <- labelNew name image <- imageNewFromIcon "window-close" iconSize closeButton <- toolButtonNew (Just image) (Nothing::Maybe Text) -- Show. boxPackStart box label PackNatural 0 boxPackStart box closeButton PackNatural 0 widgetShowAll box return $ NotebookTab box spinner label closeButton iconSize -- | Set tab name. notebookTabSetName :: NotebookTab -> Text -> IO () notebookTabSetName tab = labelSetText (ntLabel tab) -- | Start spinner animation. notebookTabStart :: NotebookTab -> IO () notebookTabStart NotebookTab {ntBox = box ,ntSpinner = spinner ,ntSize = size} = do boxTryPack box spinner PackNatural (Just 0) (size `div` 2) spinnerStart spinner widgetShow spinner -- | Stop spinner animation. notebookTabStop :: NotebookTab -> IO () notebookTabStop NotebookTab {ntBox = box ,ntSpinner = spinner} = do containerTryRemove box spinner spinnerStop spinner -- | Create image widget with given icon name and size. imageNewFromIcon :: Text -> Int -> IO Image imageNewFromIcon iconName size = do iconTheme <- iconThemeGetDefault pixbuf <- do -- Function 'iconThemeLoadIcon' can scale icon with specified size. pixbuf <- iconThemeLoadIcon iconTheme iconName size IconLookupUseBuiltin case pixbuf of Just p -> return p Nothing -> error $ "imageNewFromIcon : search icon " <> T.unpack iconName <> " failed." imageNewFromPixbuf pixbuf -- | Try to packing widget in box. -- If @child@ have exist parent, do nothing, -- otherwise, add @child@ to @parent@. boxTryPack :: (BoxClass parent, WidgetClass child) => parent -> child -> Packing -> Maybe Int -> Int -> IO () boxTryPack box widget packing order space = do parent <- widgetGetParent widget when (isNothing parent) $ do boxPackStart box widget packing space order ?>= boxReorderChild box widget -- | Try to remove child from parent. containerTryRemove :: (ContainerClass parent, WidgetClass child) => parent -> child -> IO () containerTryRemove parent widget = do hasParent <- widgetGetParent widget unless (isNothing hasParent) $ containerRemove parent widget -- | Maybe. (?>=) :: Monad m => Maybe a -> (a -> m ()) -> m () m ?>= f = maybe (return ()) f m