{-# LANGUAGE CPP #-} {-# LANGUAGE FlexibleContexts #-} module TreeCallbacks where import qualified Data.ByteString.Char8 as C import Data.IORef import Data.Maybe import qualified Graphics.UI.FLTK.LowLevel.FL as FL import Graphics.UI.FLTK.LowLevel.Fl_Enumerations import Graphics.UI.FLTK.LowLevel.Fl_Types import Graphics.UI.FLTK.LowLevel.FLTKHS import System.IO.Unsafe import Text.Printf import Foreign.C.String import Foreign.C.Types import Data.Bits g_cb_counter :: IORef Int g_cb_counter = unsafePerformIO $ newIORef 0 tree_in :: IORef (Maybe (Ref Input)) tree_in = unsafePerformIO $ newIORef Nothing tree_but :: IORef (Maybe (Ref Button)) tree_but = unsafePerformIO $ newIORef Nothing tree_grp :: IORef (Maybe (Ref Group)) tree_grp = unsafePerformIO $ newIORef Nothing item_id :: IORef Int item_id = unsafePerformIO $ newIORef 0 helpDialog :: IORef (Maybe (Ref DoubleWindow, Ref TextDisplay, Ref TextBuffer)) helpDialog = unsafePerformIO $ newIORef Nothing treeCallback :: Ref Tree -> IO () treeCallback tree = do modifyIORef g_cb_counter (\c' -> c' + 1) item <- getCallbackItem tree reason <- getCallbackReason tree let reason_string = case reason of TreeReasonNone -> "none" TreeReasonSelected -> "selected" TreeReasonDeselected -> "deselected" TreeReasonOpened -> "opened" TreeReasonClosed -> "closed" TreeReasonDragged -> "dragged" has_changed <- changed tree case item of Just i -> do itemLabel <- getLabel i printf "TREE CALLBACK: label='%s' reason='%s' changed='%s'" itemLabel reason_string (show has_changed) clicks <- FL.eventClicks if (clicks > 0) then printf ", clicks=%d\n" (clicks + 1) else print "\n" Nothing -> do printf "TREE CALLBACK: reason='%s' changed='%s' item=(no item -- probably multiple items were changed at once)\n" reason_string (show has_changed) clearChanged tree margintop_slider_callback :: Ref Tree -> Ref ValueSlider -> IO () margintop_slider_callback tree slider = do val <- getValue slider setMargintop tree (truncate val) redraw tree marginleft_slider_callback :: Ref Tree -> Ref ValueSlider -> IO () marginleft_slider_callback tree slider = do val <- getValue slider setMarginleft tree (truncate val) redraw tree marginbottom_slider_callback :: Ref Tree -> Ref ValueSlider -> IO () marginbottom_slider_callback tree slider = do deactivate slider setTooltip slider ("DISABLED.\n" ++ "Set FLTK_ABI_VERSION to 10301 (or higher)\n" ++ "to enable this feature") linespacing_slider_callback :: Ref Tree -> Ref ValueSlider -> IO () linespacing_slider_callback tree slider = do val <- getValue slider setLinespacing tree (truncate val) redraw tree usericonmarginleft_slider_callback :: Ref Tree -> Ref ValueSlider -> IO () usericonmarginleft_slider_callback tree slider = do val <- getValue slider setUsericonmarginleft tree (truncate val) redraw tree labelmarginleft_slider_callback :: Ref Tree -> Ref ValueSlider -> IO () labelmarginleft_slider_callback tree slider = do val <- getValue slider setLabelmarginleft tree (truncate val) redraw tree widgetmarginleft_slider_callback :: Ref Tree -> Ref ValueSlider -> IO () widgetmarginleft_slider_callback tree slider = do deactivate slider setTooltip slider ("DISABLED.\n" ++ "Set FLTK_ABI_VERSION to 10301 (or higher)\n" ++ "to enable this feature") openchild_marginbottom_slider_callback :: Ref Tree -> Ref ValueSlider -> IO () openchild_marginbottom_slider_callback tree slider = do val <- getValue slider setOpenchildMarginbottom tree (truncate val) redraw tree connectorwidth_slider_callback :: Ref Tree -> Ref ValueSlider -> IO () connectorwidth_slider_callback tree slider = do val <- getValue slider setConnectorwidth tree (truncate val) return () collapseicons_chooser_callback :: Ref Tree -> Ref Choice -> IO () collapseicons_chooser_callback tree chooser = let openXpm = #ifdef __APPLE__ [ "11 11 3 1", ". c #fefefe", "# c #444444", "@ c #000000", "###########", "#.........#", "#.........#", "#....@....#", "#....@....#", "#..@@@@@..#", "#....@....#", "#....@....#", "#.........#", "#.........#", "###########" ] #else [ "11 11 2 1", ". c None", "@ c #000000", "...@.......", "...@@......", "...@@@.....", "...@@@@....", "...@@@@@...", "...@@@@@@..", "...@@@@@...", "...@@@@....", "...@@@.....", "...@@......", "...@......." ] #endif closeXpm = #ifdef __APPLE__ [ "11 11 3 1", ". c #fefefe", "# c #444444", "@ c #000000", "###########", "#.........#", "#.........#", "#.........#", "#.........#", "#..@@@@@..#", "#.........#", "#.........#", "#.........#", "#.........#", "###########" ] #else [ "11 11 2 1", ". c none", "@ c #000000", "...........", "...........", "...........", "...........", "...........", "@@@@@@@@@@@", ".@@@@@@@@@.", "..@@@@@@@..", "...@@@@@...", "....@@@....", ".....@....." ] #endif in do val <- getValue chooser case val of (MenuItemIndex 0)-> do setShowcollapse tree True setOpenicon tree (Nothing :: Maybe (Ref Image)) setCloseicon tree (Nothing :: Maybe (Ref Image)) (MenuItemIndex 1) -> do setShowcollapse tree True openPixmap <- pixmapNew (PixmapHs openXpm) setOpenicon tree (Just openPixmap) closePixmap <- pixmapNew (PixmapHs closeXpm) setCloseicon tree (Just closePixmap) (MenuItemIndex 2) -> setShowcollapse tree False _ -> return () connectorstyle_chooser_callback :: Ref Tree -> Ref Choice -> IO () connectorstyle_chooser_callback tree chooser = do val <- getValue chooser case val of (MenuItemIndex 0) -> setConnectorstyle tree TreeConnectorNone (MenuItemIndex 1) -> setConnectorstyle tree TreeConnectorDotted (MenuItemIndex 2) -> setConnectorstyle tree TreeConnectorSolid _ -> return () set_connectorstyle_chooser :: Ref Choice -> TreeConnector -> IO () set_connectorstyle_chooser chooser connectorStyle = case connectorStyle of TreeConnectorNone -> setValue chooser (MenuItemByIndex (MenuItemIndex 0)) >> return () TreeConnectorDotted -> setValue chooser (MenuItemByIndex (MenuItemIndex 1)) >> return () TreeConnectorSolid -> setValue chooser (MenuItemByIndex (MenuItemIndex 2)) >> return () selectmode_chooser_callback :: Ref Tree -> Ref Choice -> IO () selectmode_chooser_callback tree chooser = do val <- getValue chooser let mode = case val of (MenuItemIndex 0) -> TreeSelectNone (MenuItemIndex 1) -> TreeSelectSingle (MenuItemIndex 2) -> TreeSelectMulti (MenuItemIndex 3) -> TreeSelectSingleDraggable (MenuItemIndex _) -> TreeSelectSingle setSelectmode tree mode reselectmode_chooser_callback :: Ref Tree -> Ref Choice -> IO () reselectmode_chooser_callback _ chooser = do deactivate chooser setTooltip chooser ("DISABLED.\n" ++ "Set FLTK_ABI_VERSION to 10301 (or higher)\n" ++ "to enable this feature") whenmode_chooser_callback :: Ref Tree -> Ref Choice -> IO () whenmode_chooser_callback tree chooser = do val <- getValue chooser let whenMode = case val of (MenuItemIndex 0) -> WhenRelease (MenuItemIndex 1) -> WhenChanged (MenuItemIndex 2) -> WhenNever (MenuItemIndex _) -> WhenRelease setWhen tree [whenMode] set_tree_showroot :: Ref Tree -> Ref CheckButton -> IO () set_tree_showroot tree button = getValue button >>= setShowroot tree radio_button_deactivate_callback :: Ref Window -> Ref CheckButton -> IO () radio_button_deactivate_callback window button = do deactivate button setTooltip button ("DISABLED.\n" ++ "Set FLTK_ABI_VERSION to 10301 (or higher)\n" ++ "to enable this feature") redraw window goto_next_selected_item :: Ref Tree -> Ref Button -> IO () goto_next_selected_item tree _ = do item <- nextSelectedItem tree maybe (return ()) (showItemTop tree) item goto_next_selected_item_bottom :: Ref Tree -> Ref Button -> IO () goto_next_selected_item_bottom tree _ = do item <- nextSelectedItem tree maybe (return ()) (showItemBottom tree) item goto_next_selected_item_middle :: Ref Tree -> Ref Button -> IO () goto_next_selected_item_middle tree _ = do item <- nextSelectedItem tree maybe (return ()) (showItemMiddle tree) item openall_button_callback :: Ref Tree -> Ref Button -> IO () openall_button_callback tree button = do item <- getFirst tree go item redraw tree where go :: Maybe (Ref TreeItem) -> IO () go Nothing = return () go (Just i) = do children <- hasChildren i if children then open i else return () next tree >>= go insertabove_button_callback :: Ref Tree -> Ref Button -> IO () insertabove_button_callback tree button = do item <- getFirst tree go item redraw tree where go :: Maybe (Ref TreeItem) -> IO () go Nothing = return () go (Just i) = do selected <- isSelected tree (TreeItemPointerLocator (TreeItemPointer i)) if selected then do insertAbove tree i "AaaAaa" insertAbove tree i "BbbBbb" insertAbove tree i "CccCcc" return () else return () next tree >>= go assignUserIcons :: Ref Tree -> Ref CheckButton -> IO () assignUserIcons tree button = do first <- getFirst tree go first redraw tree where go :: Maybe (Ref TreeItem) -> IO () go Nothing = return () go (Just i) = do val <- getValue button if val then do children <- hasChildren i if children then pixmapNew (PixmapHs folderXpm) >>= setUsericon i . Just else pixmapNew (PixmapHs documentXpm) >>= setUsericon i . Just else setUsericon i (Nothing :: Maybe (Ref Image)) folderXpm = [ "11 11 3 1", ". c None", "x c #d8d833", "@ c #808011", "...........", ".....@@@@..", "....@xxxx@.", "@@@@@xxxx@@", "@xxxxxxxxx@", "@xxxxxxxxx@", "@xxxxxxxxx@", "@xxxxxxxxx@", "@xxxxxxxxx@", "@xxxxxxxxx@", "@@@@@@@@@@@" ] documentXpm = [ "11 11 3 1", ". c None", "x c #d8d8f8", "@ c #202060", ".@@@@@@@@@.", ".@xxxxxxx@.", ".@xxxxxxx@.", ".@xxxxxxx@.", ".@xxxxxxx@.", ".@xxxxxxx@.", ".@xxxxxxx@.", ".@xxxxxxx@.", ".@xxxxxxx@.", ".@xxxxxxx@.", ".@@@@@@@@@." ] tree_button_cb :: Ref Tree -> Ref Button -> IO () tree_button_cb tree button = do button_label <- getLabel button cw <- if (button_label == "ccc button") then return (Just (safeCast button :: Ref Widget)) else getParent button >>= return . maybe Nothing (Just . safeCast) case cw of Just cw' -> do cwh <- getH cw' cwx <- getX cw' cwy <- getY cw' cww <- getW cw' let newHeight = if (cwh + 10 > 50) then 20 else cwh + 10 resize cw' (toRectangle (cwx, cwy, cww, newHeight)) redraw tree printf "'%s' button pushed (height=%d)\n" button_label newHeight rebuildTree :: Ref Tree -> Ref CheckButton -> Ref Button -> IO () rebuildTree tree button _ = do clear tree _ <- add tree "Aaa" _ <- add tree "Bbb" _ <- add tree "Ccc" _ <- add tree "Ddd" _ <- add tree "Bbb/child-01" _ <- add tree "Bbb/child-01/111" _ <- add tree "Bbb/child-01/222" _ <- add tree "Bbb/child-01/333" _ <- add tree "Bbb/child-02" _ <- add tree "Bbb/child-03" _ <- add tree "Bbb/child-04" bbChild02 <- findItem tree "Bbb/child-02" maybe (return ()) (\child -> do input <- readIORef tree_in case input of Nothing -> do begin tree newIn <- inputNew (toRectangle (1,1,100,1)) (Just "Input Test") Nothing writeIORef tree_in (Just newIn) setLabelsize newIn (FontSize 10) setTextsize newIn (FontSize 10) setAlign newIn alignRight setTooltip newIn ("Fl_Input inside tree.\n" ++ "The widget's label 'Fl_Input test' should appear to the widget's right.") setWidget child (Just newIn) end tree _ -> setWidget child input) bbChild02 bbChild03 <- findItem tree "Bbb/child-03" maybe (return ()) (\child -> do tree_button <- readIORef tree_but case tree_button of Nothing -> do begin tree newButton <- buttonNew (toRectangle (1,1,140,1)) (Just "ccc button") writeIORef tree_but (Just newButton) setLabelsize newButton (FontSize 10) setCallback newButton (tree_button_cb tree) setTooltip newButton ("Button inside tree.\n" ++ "If 'Item h() from widget' enabled, " ++ "pressing button enlarges it.") setWidget child (Just newButton) end tree _ -> setWidget child tree_button) bbChild03 bbChild04 <- findItem tree "Bbb/child-04" maybe (return ()) (\child -> let tipmsg = "A group of two buttons inside the tree.\n" ++ "If 'Item h() from widget' enabled, " ++ "pressing either button enlarges the group " ++ "and both buttons together." in do tree_group <- readIORef tree_grp case tree_group of Nothing -> do begin tree newGroup <- groupNew (toRectangle (100,100,140,18)) Nothing writeIORef tree_grp (Just newGroup) setColor newGroup whiteColor grpX <- getX newGroup grpY <- getY newGroup begin newGroup abut <- buttonNew (toRectangle (grpX, grpY + 2, 65,15)) (Just "D1") setLabelsize abut (FontSize 10) setCallback abut (tree_button_cb tree) bbut <- buttonNew (toRectangle (grpX + 75, grpY + 2, 65,15)) (Just "D2") setLabelsize bbut (FontSize 10) setCallback bbut (tree_button_cb tree) end newGroup setResizable newGroup (Just newGroup) setWidget child (Just newGroup) end tree Just _ -> setWidget child tree_group ) bbChild04 setSortorder tree TreeSortNone add tree "Ascending" >>= maybe (return ()) close setSortorder tree TreeSortAscending add tree "Ascending/Zzz" add tree "Ascending/Xxx" add tree "Ascending/Aaa" add tree "Ascending/Bbb" add tree "Ascending/Yyy" add tree "Ascending/Ccc" setSortorder tree TreeSortNone add tree "Descending" >>= maybe (return ()) close setSortorder tree TreeSortDescending add tree "Descending/Zzz" add tree "Descending/Xxx" add tree "Descending/Aaa" add tree "Descending/Bbb" add tree "Descending/Yyy" add tree "Descending/Ccc" setSortorder tree TreeSortNone add tree "Long Line" >>= maybe (return ()) close add tree "Long Line/The quick brown fox jumped over the lazy dog. 0123456789" add tree "Long Line/Longer Line" add tree "Long Line/Longer Line/The quick brown fox jumped over the lazy dog. ---------------- 0123456789" mapM_ (\t -> let s :: String s = printf "500 Items/item %04d" ((t + 1) :: Int) in add tree s) [0 .. 499] close tree (TreeItemNameLocator (TreeItemName "500 Items")) assignUserIcons tree button redraw tree showpathname_button_callback :: Ref Tree -> Ref Button -> IO () showpathname_button_callback tree button = do item <- firstSelectedItem tree maybe (flMessage "No item was selected") (\i -> do path <- itemPathname tree i case path of Just p -> do l <- getLabel i >>= \s -> return (if (null s) then "???" else s) flMessage (printf "Pathname for '%s' is: \"%s\"" l p) Nothing -> flMessage "itemPathname returned Nothing (NOT FOUND)") item closeall_button_callback :: Ref Tree -> Ref Button -> IO () closeall_button_callback tree button = do first <- getFirst tree go first redraw tree where go :: Maybe (Ref TreeItem) -> IO () go Nothing = return () go (Just i) = do children <- hasChildren i root <- isRoot i if ((not root) && children) then close i else return () clearall_button_callback :: Ref Tree -> Ref Button -> IO () clearall_button_callback tree _ = do clear tree redraw tree testcallbackflag_button_callback :: Ref Tree -> Ref Button -> IO () testcallbackflag_button_callback tree button = do root' <- root tree print "--- Checking docallback of\n" case root' of Nothing -> return () Just root'' -> do let rootItemLocator = TreeItemPointerLocator (TreeItemPointer root'') let rootNameLocator = TreeItemNameLocator (TreeItemName "ROOT") writeIORef g_cb_counter 0 closeAndCallback tree rootItemLocator False readIORef g_cb_counter >>= \c -> if (c > 0) then flAlert("FAILED 'OFF' TEST\n closeAndCallback item false triggered cb!") else return () writeIORef g_cb_counter 0 openAndCallback tree rootItemLocator False readIORef g_cb_counter >>= \c -> if (c > 0) then flAlert("FAILED 'OFF' TEST\n openAndCallback item false triggered cb!") else return () writeIORef g_cb_counter 0 openToggleAndCallback tree root'' False readIORef g_cb_counter >>= \c -> if (c > 0) then flAlert("FAILED 'OFF' TEST\n openToggleAndCallback item false triggered cb!") else return () writeIORef g_cb_counter 0 closeAndCallback tree rootNameLocator False readIORef g_cb_counter >>= \c -> if (c > 0) then flAlert("FAILED 'OFF' TEST\n closeAndCallback path False triggered cb!") else return () writeIORef g_cb_counter 0 openAndCallback tree rootNameLocator False readIORef g_cb_counter >>= \c -> if (c > 0) then flAlert("FAILED 'OFF' TEST\n openAndCallback path False triggered cb!") else return () openAndCallback tree rootItemLocator False writeIORef g_cb_counter 0 deselectAndCallback tree rootItemLocator False readIORef g_cb_counter >>= \c -> if (c > 0) then flAlert("FAILED 'OFF' TEST\n deselectAndCallback item false triggered cb!") else return () writeIORef g_cb_counter 0 selectAndCallback tree rootItemLocator False readIORef g_cb_counter >>= \c -> if (c > 0) then flAlert("FAILED 'OFF' TEST\n selectAndCallback item false triggered cb!") else return () writeIORef g_cb_counter 0 selectToggleAndCallback tree root'' False readIORef g_cb_counter >>= \c -> if (c > 0) then flAlert("FAILED 'OFF' TEST\n selectToggleAndCallback item false triggered cb!") else return () writeIORef g_cb_counter 0 deselectAndCallback tree rootNameLocator False readIORef g_cb_counter >>= \c -> if (c > 0) then flAlert("FAILED 'OFF' TEST\n deselectAndCallback path False triggered cb!") else return () writeIORef g_cb_counter 0 selectAndCallback tree rootNameLocator False readIORef g_cb_counter >>= \c -> if (c > 0) then flAlert("FAILED 'OFF' TEST\n selectAndCallback path False triggered cb!") else return () deselectAndCallback tree rootItemLocator False writeIORef g_cb_counter 0 closeAndCallback tree rootItemLocator True readIORef g_cb_counter >>= \c -> if (c == 0) then flAlert("FAILED 'ON' TEST\n closeAndCallback item True did not trigger cb!") else return () writeIORef g_cb_counter 0 openAndCallback tree rootItemLocator True readIORef g_cb_counter >>= \c -> if (c == 0) then flAlert("FAILED 'ON' TEST\n openAndCallback item True did not trigger cb!") else return () writeIORef g_cb_counter 0 openToggleAndCallback tree root'' True readIORef g_cb_counter >>= \c -> if (c == 0) then flAlert("FAILED 'ON' TEST\n openToggleAndCallback item True did not trigger cb!") else return () writeIORef g_cb_counter 0 openAndCallback tree rootItemLocator True readIORef g_cb_counter >>= \c -> if (c == 0) then flAlert("FAILED 'ON' TEST\n openAndCallback [2] item True did not trigger cb!") else return () writeIORef g_cb_counter 0 closeAndCallback tree rootItemLocator True readIORef g_cb_counter >>= \c -> if (c == 0) then flAlert("FAILED 'ON' TEST\n closeAndCallback [2] item True did not trigger cb!") else return () writeIORef g_cb_counter 0 openAndCallback tree rootNameLocator True readIORef g_cb_counter >>= \c -> if (c == 0) then flAlert("FAILED 'ON' TEST\n openAndCallback path True did not trigger cb!") else return () writeIORef g_cb_counter 0 closeAndCallback tree rootNameLocator True readIORef g_cb_counter >>= \c -> if (c == 0) then flAlert("FAILED 'ON' TEST\n closeAndCallback path True did not trigger cb!") else return () openAndCallback tree rootItemLocator False writeIORef g_cb_counter 0 selectAndCallback tree rootItemLocator True readIORef g_cb_counter >>= \c -> if (c == 0) then flAlert("FAILED 'ON' TEST\n selectAndCallback item True did not trigger cb!") else return () writeIORef g_cb_counter 0 deselectAndCallback tree rootItemLocator True readIORef g_cb_counter >>= \c -> if (c == 0) then flAlert("FAILED 'ON' TEST\n deselectAndCallback item True did not trigger cb!") else return () writeIORef g_cb_counter 0 selectToggleAndCallback tree root'' True readIORef g_cb_counter >>= \c -> if (c == 0) then flAlert("FAILED 'ON' TEST\n selectToggleAndCallback item True did not trigger cb!") else return () writeIORef g_cb_counter 0 deselectAndCallback tree rootNameLocator True readIORef g_cb_counter >>= \c -> if (c == 0) then flAlert("FAILED 'ON' TEST\n deselectAndCallback path True did not trigger cb!") else return () writeIORef g_cb_counter 0 selectAndCallback tree rootNameLocator True readIORef g_cb_counter >>= \c -> if (c == 0) then flAlert("FAILED 'ON' TEST\n selectAndCallback path True did not trigger cb!") else return () deselectAndCallback tree rootNameLocator False writeIORef g_cb_counter 0 close tree rootItemLocator readIORef g_cb_counter >>= \c -> if (c == 0) then flAlert("FAILED 'DEFAULT' TEST\n close item false did not trigger cb!") else return () writeIORef g_cb_counter 0 open tree rootItemLocator readIORef g_cb_counter >>= \c -> if (c == 0) then flAlert("FAILED 'DEFAULT' TEST\n open item false did not trigger cb!") else return () writeIORef g_cb_counter 0 openToggle tree root'' readIORef g_cb_counter >>= \c -> if (c == 0) then flAlert("FAILED 'DEFAULT' TEST\n openToggle item false did not trigger cb!") else return () writeIORef g_cb_counter 0 open tree rootNameLocator readIORef g_cb_counter >>= \c -> if (c == 0) then flAlert("FAILED 'DEFAULT' TEST\n open path did not trigger cb!") else return () writeIORef g_cb_counter 0 close tree rootNameLocator readIORef g_cb_counter >>= \c -> if (c == 0) then flAlert("FAILED 'DEFAULT' TEST\n close path did not trigger cb!") else return () openAndCallback tree rootItemLocator False writeIORef g_cb_counter 0 select tree rootItemLocator readIORef g_cb_counter >>= \c -> if (c == 0) then flAlert("FAILED 'DEFAULT' TEST\n select item false did not trigger cb!") else return () writeIORef g_cb_counter 0 deselect tree rootItemLocator readIORef g_cb_counter >>= \c -> if (c == 0) then flAlert("FAILED 'DEFAULT' TEST\n deselect item false did not trigger cb!") else return () writeIORef g_cb_counter 0 selectToggle tree root'' readIORef g_cb_counter >>= \c -> if (c == 0) then flAlert("FAILED 'DEFAULT' TEST\n selectToggle item false did not trigger cb!") else return () writeIORef g_cb_counter 0 deselect tree rootNameLocator readIORef g_cb_counter >>= \c -> if (c == 0) then flAlert("FAILED 'DEFAULT' TEST\n deselect path did not trigger cb!") else return () writeIORef g_cb_counter 0 select tree rootNameLocator readIORef g_cb_counter >>= \c -> if (c == 0) then flAlert("FAILED 'DEFAULT' TEST\n select path did not trigger cb!") else return () deselect tree rootNameLocator flAlert "TEST COMPLETED\n If you didn't see any error dialogs, test PASSED." testrootshowself_button_callback :: Ref Tree -> Ref Button -> IO () testrootshowself_button_callback tree _ = do root' <- root tree maybe (return ()) (\root'' -> showSelf root'' Nothing) root' add20k_button_callback :: Ref Tree -> Ref Button -> IO () add20k_button_callback tree _ = do first <- getFirst tree go first redraw tree where go :: Maybe (Ref TreeItem) -> IO () go Nothing = return () go (Just i) = do selected <- isSelected i root' <- root tree if selected then do parent' <- getParent i >>= maybe (return root') (return . Just) maybe (return ()) (\p' -> do mapM_ (\item_id' -> let s :: String s = printf "Item #%d" ((item_id' :: Int) + 1) in add tree s) [0 .. 19999] modifyIORef item_id (\i -> i + 20000)) parent' else next i >>= go getMatchingItems :: Ref Tree -> (Ref TreeItem -> IO Bool) -> IO [Ref TreeItem] getMatchingItems tree pred = do first <- getFirst tree go first pred [] where go :: Maybe (Ref TreeItem) -> (Ref TreeItem -> IO Bool) -> [Ref TreeItem] -> IO [Ref TreeItem] go Nothing _ accum = return accum go (Just i) pred accum = do passes <- pred i next' <- next i if passes then go next' pred (accum ++ [i]) else go next' pred accum toSelectedItemOrAll :: Ref Tree -> (Ref TreeItem -> IO()) -> IO () toSelectedItemOrAll tree f = do items' <- getMatchingItems tree isSelected if (null items') then do allItems' <- getMatchingItems tree (\_ -> return True) mapM_ f allItems' else mapM_ f items' redraw tree withFoundItemOrDefault :: Ref Tree -> (Ref TreeItem -> IO a) -> (Ref TreeItem -> IO Bool) -> IO a -> IO a withFoundItemOrDefault tree f pred fallback = do first <- getFirst tree res <- go first f pred maybe fallback return res where go :: Maybe (Ref TreeItem) -> (Ref TreeItem -> IO a ) -> (Ref TreeItem -> IO Bool) -> IO (Maybe a) go Nothing _ _ = return Nothing go (Just i) f pred = do passes <- pred i if passes then f i >>= return . Just else next i >>= \i' -> go i' f pred selected_labelfont_choice_callback :: Ref Tree -> Ref Choice -> IO () selected_labelfont_choice_callback tree chooser = do (MenuItemIndex idx) <- getValue chooser toSelectedItemOrAll tree (\i -> setLabelfont i (Font idx)) assignTreeFontToButton :: Ref Tree -> Ref Choice -> IO () assignTreeFontToButton tree chooser = do (Font fontNumber) <- getItemLabelfont tree setValue chooser (MenuItemByIndex (MenuItemIndex fontNumber)) return () selected_labelsize_slider_callback :: Ref Tree -> Ref ValueSlider -> IO () selected_labelsize_slider_callback tree slider = do val <- getValue slider toSelectedItemOrAll tree (\i -> setLabelsize i (FontSize (truncate val))) assignTreeLabelsizeToSlider :: Ref Tree -> Ref ValueSlider -> IO () assignTreeLabelsizeToSlider tree slider = do (FontSize size) <- getLabelsize tree setValue slider (fromIntegral size) return () editColor :: Color -> IO (Maybe Color) editColor val = do (r,g,b) <- FL.getColorRgb val rgb <- flcColorChooser "Choose Color" (Words (r,g,b)) Nothing case rgb of (Just (Words rgb'@(r',g',b'))) -> rgbColorWithRgb rgb' >>= return . Just _ -> return Nothing getSelectedItemFgColor :: Ref Tree -> IO Color getSelectedItemFgColor tree = withFoundItemOrDefault tree getLabelfgcolor isSelected (getItemLabelfgcolor tree) getSelectedItemBgColor :: Ref Tree -> IO Color getSelectedItemBgColor tree = withFoundItemOrDefault tree getLabelbgcolor isSelected (getItemLabelbgcolor tree) all_labelfgcolor_button_callback :: Ref Tree -> Ref Button -> IO () all_labelfgcolor_button_callback tree button = do fgColor <- getSelectedItemFgColor tree newColor <- editColor fgColor maybe (return ()) (\color' -> toSelectedItemOrAll tree (\i -> setLabelfgcolor i color')) newColor all_labelbgcolor_button_callback :: Ref Tree -> Ref Button -> IO () all_labelbgcolor_button_callback tree button = do bgColor <- getSelectedItemBgColor tree newColor <- editColor bgColor maybe (return ()) (\color' -> toSelectedItemOrAll tree (\i -> setLabelbgcolor i color')) newColor deactivate_toggle_callback :: Ref Tree -> Ref LightButton -> IO () deactivate_toggle_callback tree button = do toggleValue <- getValue button toSelectedItemOrAll tree (\i -> activateWith i (not toggleValue)) bold_toggle_callback :: Ref Tree -> Ref LightButton -> IO () bold_toggle_callback tree button = do toggleValue <- getValue button toSelectedItemOrAll tree (\i -> setLabelfont i (if toggleValue then helveticaBold else helvetica)) showselected_button_callback :: Ref Tree -> Ref Button -> IO () showselected_button_callback tree button = do print "--- SELECTED ITEMS\n" items' <- getMatchingItems tree isSelected mapM_ (\i -> getLabel i >>= \l -> printf "\t%s\n" (if (null l) then "???" else l)) items' clearselected_button_callback :: Ref Tree -> Ref Button -> IO () clearselected_button_callback tree button = do items' <- getMatchingItems tree isSelected mapM_ (\i -> remove tree i >> return ()) items' swapselected_button_callback :: Ref Tree -> Ref Button -> IO () swapselected_button_callback tree button = do items' <- getMatchingItems tree isSelected case items' of (a':b':[]) -> do pa' <- getParent a' pb' <- getParent b' if (isNothing pa' || isNothing pb') then flAlert "Could not get the parent." else if (pa' /= pb') then flAlert "The two selected items must be siblings." else swapChildrenByTreeItem (fromJust pa') a' b' >> return () is' | length is' > 2 -> flAlert "Too many items selected. (must select only two)" | length is' < 1 -> flAlert "Too few items selected. (you must select two)" | otherwise -> return () setLabelfontFromTree :: Ref Tree -> Ref Choice -> IO () setLabelfontFromTree tree chooser = do (Font f) <- getLabelfont tree setValue chooser (MenuItemByIndex (MenuItemIndex f)) redraw tree labelfont_choice_callback :: Ref Tree -> Ref Window -> Ref Choice -> IO () labelfont_choice_callback tree window chooser = do (MenuItemIndex val) <- getValue chooser setLabelfont tree (Font val) redraw window item_labelfont_choice_callback :: Ref Tree -> Ref Choice -> IO () item_labelfont_choice_callback tree chooser = do (MenuItemIndex val) <- getValue chooser setLabelfont tree (Font val) redraw tree labelsize_slider_callback :: Ref Tree -> Ref Window -> Ref ValueSlider -> IO () labelsize_slider_callback tree window slider = do val <- getValue slider setLabelsize tree (FontSize (truncate val)) redraw window selectall_button_callback :: Ref Tree -> Ref Button -> IO () selectall_button_callback tree button = do selectAllAndCallback tree Nothing False redraw tree deselectall_button_callback :: Ref Tree -> Ref Button -> IO () deselectall_button_callback tree button = do deselectAllAndCallback tree Nothing False redraw tree nextselected_button_callback :: Ref Tree -> Ref Button -> IO () nextselected_button_callback tree button = do print "--- TEST nextSelectedItemAfterItem\n" print " Walk down the tree (forwards) \n" first' <- firstSelectedItem tree walkDown first' print " Walk up the tree (backwards) \n" last' <- lastSelectedItem tree walkUp last' where walkDown :: Maybe (Ref TreeItem) -> IO () walkDown Nothing = return () walkDown (Just i) = do next' <- nextSelectedItemAfterItem tree i (Just SearchDirectionDown) l' <- getLabel i printf " Selected item: %s\n" (if (null l') then "" else l') walkDown next' walkUp :: Maybe (Ref TreeItem) -> IO () walkUp Nothing = return () walkUp (Just i) = do next' <- nextSelectedItemAfterItem tree i (Just SearchDirectionUp) l' <- getLabel i printf " Selected item: %s\n" (if (null l') then "" else l') walkUp next' selectPath :: Ref Tree -> String -> Ref LightButton -> IO () selectPath tree path button = do i <- findItem tree path case i of Nothing -> flAlert $ "FAIL: Couldn't find item " ++ (show path) ++ "???" (Just i') -> do onoff <- getValue button if onoff then select tree (TreeItemPointerLocator (TreeItemPointer i')) >> return () else deselect tree (TreeItemPointerLocator (TreeItemPointer i')) >> return () selectChildrenWithPath :: Ref Tree -> String -> Ref LightButton -> IO () selectChildrenWithPath tree path button = do i <- findItem tree path case i of Nothing -> flAlert $ "FAIL: Couldn't find item " ++ (show path) ++ "???" (Just _) -> do onoff <- getValue button if onoff then selectAllAndCallback tree i True else deselectAllAndCallback tree i True tree_scrollbar_size_slider_callback :: Ref Tree -> Ref ValueSlider -> IO () tree_scrollbar_size_slider_callback tree slider = do v <- getValue slider setScrollbarSize tree (truncate v) redraw tree scrollbar_size_slider_callback :: Ref Tree -> Ref ValueSlider -> IO () scrollbar_size_slider_callback tree slider = getValue slider >>= FL.setScrollbarSize . truncate >> redraw tree item_labelsize_slider_callback :: Ref Tree -> Ref ValueSlider -> IO () item_labelsize_slider_callback tree slider = do v <- getValue slider setLabelsize tree (FontSize (truncate v)) redraw tree updateColorChips :: Ref Button -> Ref Button -> Ref Button -> Ref Button -> Ref Button -> Ref Button -> Ref Button -> Ref Tree -> Ref Window -> IO () updateColorChips color_button labelcolor_button selection_color_button item_labelfgcolor_button item_labelbgcolor_button all_labelfgcolor_button all_labelbgcolor_button tree window = do getColor tree >>= setColor color_button getLabelcolor tree >>= setColor labelcolor_button getSelectionColor tree >>= setColor selection_color_button getItemLabelfgcolor tree >>= setColor item_labelfgcolor_button getItemLabelbgcolor tree >>= setColor item_labelbgcolor_button getItemLabelfgcolor tree >>= setColor all_labelfgcolor_button getItemLabelbgcolor tree >>= setColor all_labelbgcolor_button redraw window updateColor :: Ref Tree -> (Ref Tree -> IO Color) -> (Ref Button -> Color -> IO ()) -> (Ref Tree -> Color -> IO ()) -> Ref Window -> Ref Button -> IO () updateColor tree colorGetter buttonColorSetter treeColorSetter window button = do v <- colorGetter tree res <- editColor v maybe (return ()) (\c -> do buttonColorSetter button c treeColorSetter tree c redraw window ) res color_button_callback :: Ref Tree -> IO () -> Ref Button -> IO () color_button_callback tree _updateColorChips button = do v <- getColor tree res <- editColor v maybe (return ()) (\c -> do setColor tree c _updateColorChips redraw tree ) res x_item_labelbgcolor_button_callback :: Ref Tree -> IO () -> Ref Button -> IO () x_item_labelbgcolor_button_callback tree _updateColorChips _ = do setItemLabelbgcolor tree (Color 0xffffffff) _updateColorChips redraw tree testsuggs_button_callback :: Ref Button -> IO () testsuggs_button_callback button = let helpmsg = "CHILD WIDGET SIZING TESTS\n" ++ "=========================\n" ++ " 1) Start program\n" ++ " 2) Click the 'ccc button' and D1/D2 buttons.\n" ++ " Their sizes should not change.\n" ++ " 3) Click the 'Item h() from widget' checkbox.\n" ++ " 4) Click the 'ccc button' and D1/D2 buttons.\n" ++ " Their sizes should change, getting larger vertically.\n" ++ " This validates that widget's size can affect the tree.\n" ++ " 5) Disable the checkbox, widgets should resize back to the\n" ++ " size of the other items.\n" ++ " 6) Hit ^A to select all items\n" ++ " 7) Under 'Selected Items', drag the 'Label Size' slider around.\n" ++ " All the item's height should change, as well as child widgets.\n" ++ " 8) Put Label Size' slider back to normal\n" ++ "\n" ++ "CHILD WIDGET + LABEL ITEM DRAWING TESTS\n" ++ "=======================================\n" ++ " 1) Start program\n" ++ " 2) Click 'Show label + widget'.\n" ++ " The widgets should all show item labels to their left.\n" ++ " 3) Disable same, item labels should disappear,\n" ++ " showing the widgets in their place.\n" ++ "\n" ++ "COLORS\n" ++ "======\n" ++ " 1) Start program\n" ++ " 2) Change 'Tree Fonts+Colors' -> color()\n" ++ " 3) Entire tree's background color will change, including items.\n" ++ " 4) Change the 'Tree Fonts + Colors -> item_labelbgcolor()'\n" ++ " 6) Click the '111' item to select it.\n" ++ " 7) Click 'Test Operations -> Insert Above'\n" ++ " New items should appear above the selected item using the new color.\n" ++ " This color will be different from the background color.\n" ++ " 8) Change the 'Tree Fonts+Colors' -> color()\n" ++ " The entire tree's bg should change, except the new items.\n" ++ " 9) Click the Tree Fonts+Colors -> item_labelbgcolor() 'X' button.\n" ++ " This resets item_labelbgcolor() to the default 'transparent' color (0xffffffff)\n" ++ " 10) Again, click the 'Insert Above' button.\n" ++ " New items will be created in the background color, and changing the color()\n" ++ " should affect the new items too.\n" ++ "\n" ++ "SCROLLING\n" ++ "=========\n" ++ " 1) Open '500 items' and 'Long Line' so that both scrollbars appear:\n" ++ " * The 'focus box' for the selected item should not be clipped\n" ++ " horizontally by the vertical scrollbar.\n" ++ " * Resizing the window horizontally should resize the focus box\n" ++ " * Scrolling vertically/horizontally should show reveal all\n" ++ " edges of the tree. One *exception* is the widget label\n" ++ " to the right of the 'ccc button'; labels aren't part\n" ++ " of the widget, and therefore don't affect scroll tabs\n" ++ " 2) Scroll vertical scroller to the middle of the tree\n" ++ " 3) Left click and drag up/down to extend the selection:\n" ++ " * Selection should autoscroll if you drag off the top/bottom\n" ++ " * Selection should work *even* if you drag horizontally\n" ++ " off the window edge; moving up/down outside the window\n" ++ " should continue to autoscroll\n" ++ " 4) Click either of the the scrollbar tabs and drag:\n" ++ " * Even if you drag off the scrollbar, the scrollbar\n" ++ " tab should continue to move\n" ++ " * Should continue to work if you drag off the window edge\n" ++ " horizontally drag off the window.\n" ++ " 5) Click 'Bbb' and hit 'Add 20,000', then position the\n" ++ " 'ccc button' so it's partially obscured by a scrollbar tab:\n" ++ " * Clicking the obscured button should work\n" ++ " * Clicking on the tab over the button should not 'click through'\n" ++ " to the button.\n" ++ "" in do dialog' <- readIORef helpDialog case dialog' of Nothing -> do groupSetCurrent (Nothing :: Maybe (Ref Group)) win <- doubleWindowNew (toSize (600,600)) Nothing (Just "Test Suggestions") winW <- getW win winH <- getH win disp <- textDisplayNew (toRectangle (0,0,winW,winH)) Nothing buff <- textBufferNew Nothing Nothing setBuffer disp (Just buff) setTextfont disp courier setTextsize disp (FontSize 12) setText buff helpmsg end win writeIORef helpDialog (Just (win, disp, buff)) setResizable win (Just disp) >> showWidget win Just (win, disp, buff) -> setResizable win (Just disp) >> showWidget win