packages feed

ghcprofview-0.1.0.0: src/Gui/Utils.hs

{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE OverloadedLabels #-}

module Gui.Utils where

import Control.Monad
import qualified Data.Text as T
import Data.Int
import Data.IORef
import Text.Regex.TDFA
import Text.Regex.TDFA.Text () -- instances only

import Data.GI.Base.GValue
import GI.Gtk hiding (main)

import Types

iterChildren :: TreeModel
             -> TreeIter  -- ^ Root
             -> (TreeIter -> IO (Bool, [a])) -- ^ Should return (whether to stop iterations; result)
             -> IO [a]
iterChildren store parent func = do
    (hasFirst, first) <- treeModelIterChildren store (Just parent)
    if not hasFirst
      then return []
      else go first
  where
    go iter = do
      (stop, results) <- func iter
      if stop
        then return results
        else do
          hasNext <- treeModelIterNext store iter
          if hasNext
            then do
                 rest <- go iter
                 return $ results ++ rest
            else return results

iterChildrenR :: TreeModel -> TreeIter -> (TreeIter -> IO (Bool, [a])) -> IO [a]
iterChildrenR store parent func = do
  childResults <- iterChildren store parent $ \child -> do
        (stop, result) <- func child
        if stop
          then return (True, [result])
          else do
               rest <- iterChildrenR store child func
               return (False, [result ++ rest])
  return $ concat childResults

treeSearch :: TreeView -> SearchMetohd -> T.Text -> IO [TreePath]
treeSearch view method needle = do
    Just store <- treeViewGetModel view
    (hasFirst, first) <- treeModelGetIterFirst store
    if not hasFirst
      then return []
      else iterChildrenR store first $ \child -> do
              found <- checkValue store child
              if found
                then do
                  path <- treeModelGetPath store child
                  return (False, [path])
                else return (False, [])
  where
    checkValue store row = do
      mbValue <- fromGValue =<< treeModelGetValue store row 1
      case mbValue of
        Nothing -> return False -- not ok
        Just value ->
          case method of
            Contains -> return $ needle `T.isInfixOf` value
            Exact -> return $ needle == value
            Regexp -> return $ value =~ needle

treeCheck :: TreeModel -> (TreeIter -> IO Bool) -> IO Bool
treeCheck store check = or <$> do
    (hasFirst, first) <- treeModelGetIterFirst store
    if not hasFirst
      then return []
      else iterChildrenR store first $ \child -> do
              found <- check child
              if found
                then return (True, [True])
                else return (False, [])

withSelected :: TreeView -> (TreeModel -> TreeIter -> IO ()) -> IO ()
withSelected tree fn = do
    (isSelected, store, selected) <- treeSelectionGetSelected =<< treeViewGetSelection tree
    when isSelected $ fn store selected

getTruePath :: TreeModel -> TreeIter -> IO TreePath
getTruePath top iter = do
  Just sorted <- castTo TreeModelSort top
  topPath <- treeModelGetPath top iter
  Just truePath <- treeModelSortConvertPathToChildPath sorted topPath
  return truePath

defFilterParams :: FilterParams
defFilterParams = FilterParams 0 0 0 0 0 "" ""

getItem :: IsGValue a => TreeModel -> TreeIter -> Int32 -> IO a
getItem store row col = 
    fromGValue =<< treeModelGetValue store row col

treeFilterFunc :: IORef FilterParams -> TreeModelFilterVisibleFunc
treeFilterFunc paramsRef store row = do
    params <- readIORef paramsRef
    hasChild <- treeModelIterHasChild store row
    good <- do
        entries <- getItem store row 2 :: IO Integer
        timeIndividual <- getItem store row 3
        allocIndividual <- getItem store row 4
        timeInherited <- getItem store row 5
        allocInherited <- getItem store row 6
        Just mod <- getItem store row 7
        Just src <- getItem store row 8
        return $
            entries >= fpEntries params &&
            timeIndividual >= fpTimeIndividual params &&
            allocIndividual >= fpAllocIndividual params &&
            timeInherited >= fpTimeInherited params &&
            allocInherited >= fpAllocInherited params &&
            fpModule params `T.isInfixOf` mod &&
            fpSource params `T.isInfixOf` src
    return $ hasChild || good

mkComboBox :: (Show a) => [(a, T.Text)] -> IO ComboBoxText
mkComboBox pairs = do
  combo <- comboBoxTextNew
  forM_ pairs $ \(value, title) -> do
    let id = T.pack (show value)
    comboBoxTextAppend combo (Just id) title
  comboBoxSetActive combo 0
  return combo

mkMenuItem :: Menu -> T.Text -> MenuItemActivateCallback -> IO ()
mkMenuItem menu label callback = do
  item <- menuItemNewWithLabel label
  menuShellAppend menu item
  on item #activate callback
  widgetShow item
  return ()

mkTabLabelWidget :: T.Text -> ButtonClickedCallback -> IO Box
mkTabLabelWidget text callback = do
    label <- labelNew (Just text)
    let size = fromIntegral $ fromEnum IconSizeMenu
    button <- buttonNewFromIconName (Just "window-close") size
    on button #clicked callback
    buttonSetRelief button ReliefStyleNone
    box <- boxNew OrientationHorizontal 0
    boxPackStart box label True True 0
    boxPackStart box button False False 0
    widgetShowAll box
    return box