File: Notebook.hs

package info (click to toggle)
haskell-gtk 0.15.7-1
  • links: PTS, VCS
  • area: main
  • in suites: bookworm
  • size: 3,964 kB
  • sloc: haskell: 3,346; ansic: 826; makefile: 161
file content (145 lines) | stat: -rw-r--r-- 4,697 bytes parent folder | download | duplicates (9)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
{-# LANGUAGE OverloadedStrings #-}
-- | Notebook demo (include Spinner animation).
--  Author      :  Andy Stewart
--  Copyright   :  (c) 2010 Andy Stewart <lazycat.manatee@gmail.com>

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