3

I have a timetable to display in a table.

Here is a sample of my current solution:

import Graphics.UI.Gtk
import Control.Monad.IO.Class

main = do
  initGUI
  window <- windowNew
  view <- treeViewNew
  store <- listStoreNew initialData
  treeViewSetModel view store
  containerAdd window view
  prepareCols view store
  window `on` deleteEvent $ liftIO mainQuit >> return False
  widgetShowAll window
  mainGUI

initialData :: [[String]]
initialData = [["foo", "bar"], ["baz", "42"]]

prepareCols :: TreeView -> ListStore [String] -> IO ()
prepareCols view store = do
  size <- listStoreGetSize store
  mapM_ (addColumn view store) [0..size-1]

addColumn :: TreeView -> ListStore [String] -> Int -> IO ()
addColumn view store i = addTextColumn view store (!! i) $ show i

addTextColumn :: (TreeViewClass view
                 , TreeModelClass (model row)
                 , TypedTreeModelClass model
                 )
                => view -> model row -> (row -> String) -> String -> IO ()
addTextColumn view model f name = do
  col <- treeViewColumnNew
  rend <- cellRendererTextNew
  treeViewColumnSetTitle col name
  treeViewColumnPackStart col rend True
  cellLayoutSetAttributes col rend model (\row -> [ cellText := f row ])
  treeViewColumnSetExpand col True
  treeViewAppendColumn view col
  return ()

Now I would like to make every cell right-clickable, but gtk2hs only offers to make a row activable, without information which cell was activated, or make the column header clickable.

What would be the way to go in gtk2hs, for a table that responds to click events with information, about which row and column was clicked (For the column a numeric index would be perfect, so I can use this index to modify the list I started with), without resorting to nasty things, like using a Table and deleting/adding labels to it at runtime.

Im using gtk2hs (gtk3) version 0.12.5.6

jub0bs
  • 60,866
  • 25
  • 183
  • 186
Kritzefitz
  • 2,644
  • 1
  • 20
  • 35

1 Answers1

1

You can adopt the solution described in this Python answer.

A buttonPressEvent callback can be installed in your prepareCols function that checks that the event is a right mouse click, and then decodes the event coordinates into a TreeStore path:

onPathRightClick :: (TreeViewClass view) 
                 => view
                 -> (TreePath -> Int -> IO ()) 
                 -> IO (ConnectId view)
onPathRightClick view callback =
    on view buttonReleaseEvent $ (return False <*) $ runMaybeT $ do
        RightButton <- lift eventButton
        (x, y) <- lift eventCoordinates
        let x' = round x
            y' = round y
        (path, col, _cellpoint) <- MaybeT . liftIO $ treeViewGetPathAtPos view (x', y')
        colIdx <- MaybeT . liftIO $ findIndex (== col) <$> treeViewGetColumns view
        liftIO $ callback path colIdx

prepareCols :: TreeView -> ListStore [String] -> IO ()
prepareCols view store = do
    size <- listStoreGetSize store
    mapM_ (addColumn view store) [0..size-1]
    void $ onPathRightClick view $ \path col -> do
        putStrLn . unwords $ [ "Column:" , show col]
        putStrLn . unwords $ [ "Path:" , show path]
Community
  • 1
  • 1
Cactus
  • 27,075
  • 9
  • 69
  • 149
  • Someone with more `gtk2hs` knowledge should probably transform `onPathRightClick` into a proper `Signal view (TreePath -> IO ())` but I don't know enough about the library to do that. – Cactus Jan 16 '15 at 14:28
  • I need the information what column was clicked, to modify the list I started with (`initialData` in the example). Unfortunately the `TreeViewColumn` I get, doesn't contain this information. So I can't figure out what data to modify. – Kritzefitz Jan 16 '15 at 18:11
  • 1
    I've edited my answer to look up the column index before passing it to the callback. Another thing you could do is to attach a custom attribute (by using `objectCreateAttribute`) to the `TreeViewColumn`s containing whatever column key you need. I got that working as well, but it requires far more plumbing. – Cactus Jan 18 '15 at 04:25