gtk-0.12.0: demo/treelist/ListDND.hs
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
onDestroy win 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