File: ListDND.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 (248 lines) | stat: -rw-r--r-- 8,936 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
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
module Main where

import Graphics.UI.Gtk
import Graphics.UI.Gtk.Gdk.EventM

import System.Glib.GObject ( toGObject )
import System.FilePath
import Control.Concurrent.MVar
import Control.Monad ( liftM )
import Control.Monad.Trans ( liftIO )
import Data.Maybe ( fromMaybe )
import Data.List ( findIndex )

roomStrCol :: ColumnId String String
roomStrCol = makeColumnIdString 1

-- Define a string column and an image column on the store holding the
-- computer types.
compPicCol :: ColumnId CompType Pixbuf
compPicCol = makeColumnIdPixbuf 1

compStrCol :: ColumnId CompType String
compStrCol = makeColumnIdString 2

data Computer = Computer {
        name :: String,
        addr :: (Int, Int, Int, Int),
        roomStore  :: ListStore String,
        roomSel :: Int,
        cType :: CompType }

data CompType
  = MacBookPro
  | MacBook
  | Printer
  | MacPro
  | Xserve
  | IMac
  deriving (Enum, Bounded, Show)

showCT :: CompType -> String
showCT ct = case show ct of
  'I':xs -> 'i':xs
  xs -> xs

main = do
  initGUI

  win <- windowNew
  on win objectDestroy mainQuit

  -- create a tag that we use as selection, target and selection type
  compTypeTag <- atomNew "_CompType"

  let pNames = map ("resListDND" </>)
               ["laptop.png","laptopSmall.png","printer.png",
                "tower.png","server.png","desktop.png"]
  pics <- mapM pixbufNewFromFile pNames

  smallPics <- mapM (\n -> pixbufNewFromFileAtScale n 48 48 True) pNames

  [noRoom, publicRoom, restrictedRoom] <- mapM listStoreNew
    [["Paul (Home)","John (Home)","Fred (Home)"],
     ["N12","S112", "S113", "S114"],
     ["Server Room Upstairs", "Server Room Downstairs"]]

  -- define extractor function for the string column
  treeModelSetColumn noRoom roomStrCol id
  treeModelSetColumn publicRoom roomStrCol id
  treeModelSetColumn restrictedRoom roomStrCol id

  let genRoomStore MacBookPro = noRoom
      genRoomStore MacBook = noRoom
      genRoomStore Printer = publicRoom
      genRoomStore MacPro = publicRoom
      genRoomStore Xserve = restrictedRoom
      genRoomStore IMac = publicRoom

  -- the initial computer list - it's a coincidence that there's
  -- one computer of each type
  content <- listStoreNewDND
    (map (\t -> Computer { name = showCT t, addr = (192,168,0,fromEnum t+1),
                          roomStore = genRoomStore t, roomSel = 0, cType = t})
              [minBound :: CompType .. maxBound])
    (Just listStoreDefaultDragSourceIface)
    (Just DragDestIface {
      treeDragDestRowDropPossible = \store path@(i:_) -> do
        mCT <- selectionDataGet compTypeTag
        case mCT :: Maybe [Int] of
          Just [ct] -> return True
          Nothing ->
            (treeDragDestRowDropPossible listStoreDefaultDragDestIface)
            store path
          _ -> return False,
      treeDragDestDragDataReceived = \store path@(i:_) -> do
        mCT <- selectionDataGet compTypeTag
        case mCT of
          Just [ct] -> do
            let t = toEnum ct
            liftIO $ listStoreInsert store i
              Computer { name = showCT t, addr = (192,168,0,254),
                         roomStore = genRoomStore t, roomSel = 0,
                         cType = t }
            return True
          Nothing ->
            (treeDragDestDragDataReceived listStoreDefaultDragDestIface)
              store path
      })
  -- the area with the possible computer types
  compTypes <- listStoreNewDND [minBound :: CompType .. maxBound]
    (Just DragSourceIface {
      treeDragSourceRowDraggable = \store (i:_) -> return True,
      treeDragSourceDragDataGet = \store (i:_) -> do
        ty <- selectionDataGetTarget
        ct <- liftIO $ listStoreGetValue store i
        selectionDataSet compTypeTag [fromEnum ct]
        return True,
      treeDragSourceDragDataDelete = \store path -> return True
    })
    Nothing

  -- define extractor functions for the two column
  treeModelSetColumn compTypes compPicCol $
    \t -> pics !! fromEnum t
  treeModelSetColumn compTypes compStrCol showCT

  -- create an icon view of all the computer types
  typesView <- iconViewNew
  set typesView [iconViewModel := Just compTypes,
                 iconViewPixbufColumn := compPicCol,
                 iconViewTextColumn := compStrCol,
                 iconViewColumns := 6]

  -- create an editable list of computers
  inventory <- treeViewNewWithModel content

  tyCol <- treeViewColumnNew
  treeViewColumnSetTitle tyCol "Type"
  picRen <- cellRendererPixbufNew
  treeViewColumnPackStart tyCol picRen False
  cellLayoutSetAttributes tyCol picRen content
    (\Computer { cType = t} -> [cellPixbuf := smallPics !! fromEnum t])
  tyRen <- cellRendererTextNew
  treeViewColumnPackStart tyCol tyRen False
  cellLayoutSetAttributes tyCol tyRen content
    (\Computer { cType = t} -> [cellText := showCT t])
  treeViewAppendColumn inventory tyCol

  nameCol <- treeViewColumnNew
  treeViewColumnSetTitle nameCol "Name"
  treeViewColumnSetResizable nameCol True
  treeViewColumnSetMinWidth nameCol 100
  nameRen <- cellRendererTextNew
  set nameRen [ cellTextEditable := True,
                cellTextEditableSet := True,
                cellTextEllipsize := EllipsizeEnd,
                cellTextEllipsizeSet := True]
  treeViewColumnPackStart nameCol nameRen True
  cellLayoutSetAttributes nameCol nameRen content
    (\Computer { name = n } -> [cellText := n])
  treeViewAppendColumn inventory nameCol
  on nameRen edited $ \[i] str -> do
    val <- listStoreGetValue content i
    listStoreSetValue content i val { name = str }

  addrCol <- treeViewColumnNew
  treeViewColumnSetTitle addrCol "Address"
  oct1 <- cellRendererTextNew
  dot1 <- cellRendererTextNew
  oct2 <- cellRendererTextNew
  dot2 <- cellRendererTextNew
  oct3 <- cellRendererTextNew
  dot3 <- cellRendererTextNew
  oct4 <- cellRendererTextNew
  mapM_ (uncurry (cellLayoutPackStart addrCol))
    [(oct1, True), (dot1, False), (oct2, True),
     (dot2, False), (oct3, True), (dot3, False), (oct4, True)]
  mapM_ (\d -> set d [cellText := ".",
                      cellTextWidthChars := 0]) [dot1, dot2, dot3]
  mapM_ (\o -> set o [cellXAlign := 1.0,
                      cellTextWidthChars := 3]) [oct1, oct2, oct3, oct4]
  cellLayoutSetAttributes addrCol oct1 content
    (\Computer { addr = (o1,_,_,_)} -> [cellText := show o1])
  cellLayoutSetAttributes addrCol oct2 content
    (\Computer { addr = (_,o2,_,_)} -> [cellText := show o2])
  cellLayoutSetAttributes addrCol oct3 content
    (\Computer { addr = (_,_,o3,_)} -> [cellText := show o3])
  cellLayoutSetAttributes addrCol oct4 content
    (\Computer { addr = (_,_,_,o4)} -> [cellText := show o4])
  treeViewAppendColumn inventory addrCol

  roomCol <- treeViewColumnNew
  treeViewColumnSetTitle roomCol "Room"
  treeViewColumnSetResizable roomCol True
  treeViewColumnSetSizing roomCol TreeViewColumnAutosize
  roomRen <- cellRendererComboNew
  set roomRen [ cellTextEditable := True,
                cellTextEditableSet := True,
                cellComboHasEntry := True ]
  treeViewColumnPackStart roomCol roomRen True
  cellLayoutSetAttributes roomCol roomRen content
    (\Computer { roomStore = t, roomSel = idx } ->
    [cellText :=> listStoreGetValue t idx,
    cellComboTextModel := (t, roomStrCol)])
  on roomRen edited $ \[i] str -> do
    row@Computer { roomStore = t } <- listStoreGetValue content i
    elems <- listStoreToList t
    idx <- case (findIndex ((==) str) elems) of
      Just idx -> return idx
      Nothing -> listStoreAppend t str
    listStoreSetValue content i row { roomSel = idx }
  treeViewAppendColumn inventory roomCol

  -- make typesView a drag source for compTypeTag values
  tl <- targetListNew
  targetListAdd tl compTypeTag [TargetSameApp] 0
  iconViewEnableModelDragSource typesView [Button1] tl [ActionCopy]

  -- Due to a bug in Gtk+, the treeDragSourceDragDataGet handler in
  -- the DND source handler is not called unless the IconView is also
  -- set to be a DND destination. Bugzilla 550528
  tl <- targetListNew
  iconViewEnableModelDragDest typesView tl []

  -- make the inventory widget a drag destination for compTypeTag values
  tl <- targetListNew
  targetListAdd tl compTypeTag [TargetSameApp] 0
  targetListAdd tl targetTreeModelRow [TargetSameWidget] 0
  treeViewEnableModelDragDest inventory tl [ActionMove]
  tl <- targetListNew
  targetListAdd tl targetTreeModelRow [TargetSameWidget] 0
  treeViewEnableModelDragSource inventory [Button1] tl [ActionMove]

  -- Install drag and drop for permuting rows. This is now done above using
  -- the explicit target 'targetTreeModelRow'. Calling the function below
  -- will set a completely new 'TargetList' thereby removing our own
  -- 'compTypeTag' from the inventory widget's target list.

  --treeViewSetReorderable inventory True

  -- arrange the widgets
  v <- vPanedNew
  panedAdd1 v typesView
  panedAdd2 v inventory
  containerAdd win v

  widgetShowAll win
  mainGUI