MItem - a frantk menu item, as well as basic tclhaskell menu item, it contains:
1) an event for adding commands, this allows more than one listener to a 
   command on an event.
2) an IORef containing current configuration information.

Also contains definition for a FranTk menu. This is a tclhaskell menu, but 
with an IORef containing configuration info. This is a mutable list pointing
to the IORefs of all child menu items. This makes it easy to move menu 
items. As we need to delete and redisplay in Tcl and so need to know the
current configuration options for a menu.

\begin{code}
module MItem where
import qualified TclPrimImpl as T
import FranPrim
import WidgetSetImpl
import Conf
import IOExts
import FM
import Identify
import WidgetExports (Config)
import WH
import GUI (GUI,liftIO )
import PrimWidget (actionE)
import TclTrie (getBoundArgs)
import AbstractInterface
\end{code}

a MenuPrim contains a tcl menu and item info which contains the type of the
menu item eg "cascade" (used by tcl) and an io action returning the current
config info for the item

\begin{code}
type ItemInfo = (String,IO String)

data MenuPrim = MenuPrim {
	theMen :: T.Menu, 
	children :: (IORef (FiniteMap Ident ItemInfo)) 
	}

mkMenuPrim :: T.WPath -> [Config] -> GUIInfo -> IO MenuPrim
mkMenuPrim pth cs g = do
   m <- T.menu' pth cs g
   ref <- newIORef emptyFM
   return $ MenuPrim m ref
\end{code}

Create an MItem
An MItem contains the actual item, a ref containing the current config info,
and an event listening to command actions. See PrimWidget.lhs for more on 
this last idea (they use this approach too)

\begin{code}
data MItem w = MItem {
	mitem :: w,
	mcfgref :: (IORef [Config]),
	maction :: (Event ())
	}
\end{code}

To create an MItem, get the item's numeric position, create a menu item,
make the config ref cell, create an action to access the current config
info, and then add this to the parent menu's finite map.
When the menu item is destroyed, remove it from the parent finite map.
\begin{code}
mkMItem :: String -> w 
	-> MenuPrim
	-> [Config]
	-> PlacePos Ident
	-> GUI (MItem (T.MWidget w))
mkMItem what w mp@(MenuPrim men ref) cs pos = liftIO $ do
 pos <- T.getItemPos men (fmap getWPath' pos)
 mi <- T.tcl_mwidget' (getMConfigs mp) men cs what w pos
 ref' <- newIORef cs
 let getcs = do
       cs <- readIORef ref'
       cms <- getBoundArgs (T.trieObj mi)
       return $! fst $ T.tcl_configure $ cs ++ map (\c -> "command" T.%% c) cms
 let idn = uniqueId mi
 updIORef ref $ \fm -> addToFM fm idn (what,getcs)
 addFinaliserW mi $ updIORef ref $ \fm -> delFromFM fm idn
 return $ MItem mi ref' neverE

-- make an MItem that can listen to action commands (see PrimWidget.lhs for
-- definition of actionE)
mkMItemAct :: Has_Action (T.MWidget w) => 
           String -> w 
	-> MenuPrim
	-> [Config]
	-> PlacePos Ident
	-> GUI (MItem (T.MWidget w))
mkMItemAct what w mp cs pos = do
 (MItem mi ref _) <- mkMItem what w mp cs pos
 ev <- actionE mi
 return $ MItem mi ref ev
\end{code}

Instances for WH.lhs

Instances for menu items
\begin{code}

--menu items are widget items (when setting config options make sure we update
--the config ref
instance WidgetItem (T.MWidget w) => WidgetItem (MItem (T.MWidget w)) where
 cset (MItem w ref _ ) cs = do
   cset w cs
   updIORef ref $ overideCfgs cs 
 destroy (MItem w _ _) = destroy w
 uniqueId (MItem w _ _) = uniqueId w
 addFinaliserW (MItem w _ _) f = addFinaliserW w f

-- some menu items can listen to action commands
-- if so listen to the action event
instance Has_Action (T.MWidget m) => Has_Action (MItem (T.MWidget m)) where
 action (MItem _ _ e) l = addListener e l
\end{code}

menus are widget items
\begin{code}
instance WidgetItem MenuPrim where
 cset (MenuPrim m _) = cset m
 destroy (MenuPrim m _) = destroy m
 uniqueId (MenuPrim m _) = uniqueId m
 addFinaliserW (MenuPrim m _) = addFinaliserW m
\end{code}

to move an item, use moveMItem' from TclPrimWidget.
We need to provide a function to get the type of menu item
and current config options for a given menu item. Do this with
getMConfigs.

\begin{code}
moveMItem :: MenuPrim -> Ident -> PlacePos Ident -> IO ()
moveMItem mp@(MenuPrim m _) id pos =
   T.moveMItem' m (getWPath' id) (fmap getWPath' pos) $ getMConfigs mp

getMConfigs :: MenuPrim -> Int -> T.WTag -> IO (String,String)
getMConfigs (MenuPrim m ref) n tg = do 
	fm <- readIORef ref
        case lookupFM fm (identify tg) of
	      -- if the item is not in the list something has gone wrong
	      -- resort to the TclHaskell less efficient mechanism
              Nothing -> T.mkconfigs (T.wpath m) (T.getTclGUIInfo m) n

	      Just (typ,ref) -> do
		cs <- ref
		return (typ,cs)
\end{code}	  



