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
|