uni-htk-2.2.0.0: HTk/Toolkit/SimpleListBox.hs
{-# LANGUAGE ScopedTypeVariables #-}
-- | This module implements a simple list box to which strings can be
-- added at the end and deleted.
module HTk.Toolkit.SimpleListBox(
SimpleListBox,
newSimpleListBox,
-- :: String -> (value -> String) -> (Distance,Distance)
-- -> IO (SimpleListBox value)
-- Create a ListBox. The String gives the title for the box; the
-- function argument gives the String's which
-- are displayed; the integers give the width (characters) and height
-- (rows) of the displayed section of the box.
-- This implements Destroyable.
SimpleListBoxItem,
-- Instance of Object, Eq, Ord.
addItemAtEnd,
-- :: SimpleListBox value -> value -> IO (SimpleListBoxItem value)
deleteItem,
-- :: SimpleListBox value -> SimpleListBoxItem value -> IO ()
getItems,
-- :: SimpleListBox value -> IO [value]
bindSelection,
-- :: SimpleListBox value
-- -> IO (Event [SimpleListBoxItem value]),IO ())
-- Returns an event for selections in this list box. ([] can happen,
-- for example, if the user selects or clicks an area into which no
-- item has yet been added.)
) where
import Data.Maybe
import Control.Concurrent.MVar
import Util.ExtendedPrelude
import Util.Object
import Util.Computation
import Events.Events
import HTk.Kernel.Core(GUIObject(..))
import HTk.Toplevel.HTk
-- -------------------------------------------------------------------------
-- Datatypes
-- -------------------------------------------------------------------------
data SimpleListBox val = SimpleListBox {
frame :: Frame, -- contains the list box, and the scroll-bar.
listBox :: ListBox String,
mkString :: val -> String,
contentsMVar :: MVar [SimpleListBoxItem val]
}
data SimpleListBoxItem val = SimpleListBoxItem {
val :: val,
oID :: ObjectID
}
-- -------------------------------------------------------------------------
-- Non-HTk Instances
-- -------------------------------------------------------------------------
instance Object (SimpleListBox val) where
objectID simpleListBox = objectID (toGUIObject simpleListBox)
instance Destroyable (SimpleListBox val) where
destroy simpleListBox = destroy (frame simpleListBox)
instance Object (SimpleListBoxItem val) where
objectID simpleListBoxItem = oID simpleListBoxItem
instance Eq (SimpleListBoxItem val) where
(==) = mapEq oID
instance Ord (SimpleListBoxItem val) where
compare = mapOrd oID
-- -------------------------------------------------------------------------
-- HTk instances (needed for packing a list box)
-- -------------------------------------------------------------------------
instance GUIObject (SimpleListBox val) where
toGUIObject simpleListBox = toGUIObject (frame simpleListBox)
cname _ = "SimpleListBox"
instance Widget (SimpleListBox val)
instance HasSize (SimpleListBox val)
-- -------------------------------------------------------------------------
-- Functions
-- -------------------------------------------------------------------------
newSimpleListBox
:: Container par
=> par -> (val -> String) -> [Config (SimpleListBox val)]
-> IO (SimpleListBox val)
newSimpleListBox parent mkString configs =
do
frame <- newFrame parent []
listBox <- newListBox frame [value ([] :: [String]),bg "white"]
pack listBox [Side AtLeft,Fill Y]
scroll <- newScrollBar frame []
pack scroll [Side AtRight,Fill Y]
listBox # scrollbar Vertical scroll
listBox # selectMode Extended
contentsMVar <- newMVar []
let
simpleListBox = SimpleListBox {
frame = frame,
listBox = listBox,
mkString = mkString,
contentsMVar = contentsMVar
}
configure simpleListBox configs
return simpleListBox
addItemAtEnd :: SimpleListBox val -> val -> IO (SimpleListBoxItem val)
addItemAtEnd simpleListBox (val1 :: val) =
do
-- We have to recompute the complete list of Strings, since
-- Einar doesn't seem to have provided a function for adding a single
-- item to a ListBox, and I can't be bothered to implement one.
let
mVar = contentsMVar simpleListBox
mkS = mkString simpleListBox
oID <- newObject
let
simpleListBoxItem = SimpleListBoxItem {
val = val1,
oID = oID
}
contents0 <- takeMVar mVar
let
contents1 :: [SimpleListBoxItem val]
contents1 = contents0 ++ [simpleListBoxItem]
newValue :: [String]
newValue = map (mkS . val) contents1
(listBox simpleListBox) # value newValue
putMVar mVar contents1
return simpleListBoxItem
deleteItem :: SimpleListBox val -> SimpleListBoxItem val -> IO ()
deleteItem simpleListBox simpleListBoxItem =
do
let
mVar = contentsMVar simpleListBox
mkS = mkString simpleListBox
contents0 <- takeMVar mVar
let
contents1 = deleteFirst (== simpleListBoxItem) contents0
(newValue :: [String]) = map (mkS . val) contents1
(listBox simpleListBox) # value newValue
putMVar mVar contents1
done
getItems :: SimpleListBox value -> IO [value]
getItems simpleListBox =
do
contents <- readMVar (contentsMVar simpleListBox)
return (map val contents)
bindSelection :: SimpleListBox val
-> IO (Event [SimpleListBoxItem val],IO ())
bindSelection simpleListBox =
do
(press,terminator)
<- bindSimple (listBox simpleListBox) (ButtonPress (Just 1))
let
event =
press
>>>
do
indexOpt <- getSelection (listBox simpleListBox)
contents0 <- readMVar (contentsMVar simpleListBox)
return (case indexOpt of
Nothing -> []
Just items ->
let
max = length contents0
in
mapMaybe
(\ index -> if index >= max
then
Nothing
-- can happen if events and a deletion
-- get processed in the wrong order.
else
Just (contents0 !! index)
)
items
)
return (event,terminator)