leksah-0.16.2.2: src/IDE/NotebookFlipper.hs
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE LambdaCase #-}
-----------------------------------------------------------------------------
--
-- Module : IDE.NotebookFlipper
-- Copyright : 2007-2011 Juergen Nicklisch-Franken, Hamish Mackenzie
-- License : GPL
--
-- Maintainer : <maintainer@leksah.org>
-- Stability : provisional
-- Portability :
--
-- |
--
-----------------------------------------------------------------------------
module IDE.NotebookFlipper (
flipDown
, flipUp
) where
import IDE.Core.State hiding (window, name)
import Control.Monad (when)
import IDE.Pane.SourceBuffer(recentSourceBuffers)
import Control.Monad.IO.Class (MonadIO(..))
import qualified Control.Monad.Reader as Gtk (liftIO)
import GI.Gtk.Objects.TreeView
(treeViewRowActivated, treeViewGetColumn, onTreeViewRowActivated,
treeViewGetSelection, setTreeViewHeadersVisible, treeViewAppendColumn,
treeViewSetModel, treeViewNew, treeViewSetCursor,
treeViewGetCursor, treeViewGetModel, IsTreeView)
import GI.Gtk.Interfaces.TreeModel (treeModelIterNChildren)
import GI.Gtk.Objects.Window
(setWindowWindowPosition, setWindowTransientFor, setWindowDefaultHeight,
setWindowDefaultWidth, setWindowResizable, setWindowDecorated,
setWindowTypeHint, windowNew, windowGetSize)
import GI.Gtk.Enums (WindowPosition(..), WindowType(..))
import Data.GI.Base (on, set)
import GI.Gdk.Enums (WindowTypeHint(..))
import GI.Gtk.Objects.ScrolledWindow (scrolledWindowNew)
import GI.Gtk.Objects.Adjustment (noAdjustment)
import GI.Gtk.Objects.Container (containerAdd)
import Data.GI.Gtk.ModelView.SeqStore
(seqStoreGetValue, seqStoreNew, SeqStore(..))
import GI.Gtk.Objects.TreeViewColumn
(noTreeViewColumn, treeViewColumnPackStart, treeViewColumnNew)
import GI.Gtk.Objects.CellRendererText
(setCellRendererTextText, cellRendererTextNew)
import Data.GI.Gtk.ModelView.CellLayout
(cellLayoutSetDataFunction)
import GI.Gtk.Objects.TreeSelection
(onTreeSelectionChanged)
import GI.Gtk.Objects.Widget
(widgetShowAll, widgetDestroy, widgetHide, onWidgetKeyReleaseEvent)
import GI.GObject.Functions (signalHandlerDisconnect)
import GI.Gdk.Structs.EventKey
(getEventKeyKeyval, EventKey(..))
import GI.Gdk.Functions (keyvalName)
import Data.GI.Gtk.ModelView.Types
(treeSelectionGetSelectedRows', treePathGetIndices',
treePathNewFromIndices')
flipDown :: IDEAction
flipDown = do
currentState' <- readIDE currentState
case currentState' of
IsFlipping tv -> moveFlipperDown tv
IsRunning -> initFlipper True
_ -> return ()
flipUp :: IDEAction
flipUp = do
currentState' <- readIDE currentState
case currentState' of
IsFlipping tv -> moveFlipperUp tv
IsRunning -> initFlipper False
_ -> return ()
-- | Moves down in the Flipper state
moveFlipperDown :: IsTreeView alpha => alpha -> IDEAction
moveFlipperDown tree = do
Just store <- treeViewGetModel tree
n <- treeModelIterNChildren store Nothing
when (n /= 0) $ do
indices <- treeViewGetCursor tree >>= \case
(Just path, _) ->
treePathGetIndices' path >>= \case
(current:_) -> let next = if current == n - 1
then 0
else current + 1
in return [min (n-1) next]
[] -> return [1]
_ -> return [1]
p <- treePathNewFromIndices' indices
treeViewSetCursor tree p noTreeViewColumn False
-- | Moves up in the Flipper state
moveFlipperUp :: IsTreeView alpha => alpha -> IDEAction
moveFlipperUp tree = liftIO $ do
Just store <- treeViewGetModel tree
n <- treeModelIterNChildren store Nothing
when (n /= 0) $ do
indices <- treeViewGetCursor tree >>= \case
(Just path, _) ->
treePathGetIndices' path >>= \case
(current:_) -> let next = if current == 0
then n - 1
else current - 1
in return [min (n-1) next]
[] -> return [1]
_ -> return [1]
p <- treePathNewFromIndices' indices
treeViewSetCursor tree p noTreeViewColumn False
-- | Initiate Filpper , If True moves down, if false up
initFlipper :: Bool -> IDEAction
initFlipper direction = do
mainWindow <- getMainWindow
recentPanes' <- recentSourceBuffers
(tree', store') <- reifyIDE $ \ideR -> do
window <- windowNew WindowTypePopup
(_, height) <- windowGetSize mainWindow
setWindowTypeHint window WindowTypeHintUtility
setWindowDecorated window False
setWindowResizable window True
setWindowDefaultWidth window 200
setWindowDefaultHeight window height
setWindowTransientFor window mainWindow
scrolledWindow <- scrolledWindowNew noAdjustment noAdjustment
containerAdd window scrolledWindow
tree <- treeViewNew
containerAdd scrolledWindow tree
store <- seqStoreNew recentPanes'
treeViewSetModel tree (Just store)
column <- treeViewColumnNew
_ <- treeViewAppendColumn tree column
renderer <- cellRendererTextNew
treeViewColumnPackStart column renderer True
cellLayoutSetDataFunction column renderer store $
setCellRendererTextText renderer
setTreeViewHeadersVisible tree False
cid <- onWidgetKeyReleaseEvent mainWindow (handleKeyRelease tree ideR)
_ <- onTreeViewRowActivated tree (\treePath _column -> do
signalHandlerDisconnect mainWindow cid
[row] <- treePathGetIndices' treePath
string <- seqStoreGetValue store row
reflectIDE (do
mbPane <- mbPaneFromName string
case mbPane of
Just (PaneC pane) -> do
makeActive pane
modifyIDE_ $ \ide -> ide{
recentPanes = paneName pane : filter (/= paneName pane) (recentPanes ide)}
Nothing -> return ()) ideR
widgetHide window
widgetDestroy window
reflectIDE (modifyIDE_ (\ide -> ide{currentState = IsRunning})) ideR)
treeSelection <- treeViewGetSelection tree
_ <- onTreeSelectionChanged treeSelection $ do
rows <- treeSelectionGetSelectedRows' treeSelection >>= mapM treePathGetIndices'
case rows of
[[row]] -> do
string <- seqStoreGetValue store row
reflectIDE (do
mbPane <- mbPaneFromName string
case mbPane of
Just (PaneC pane) -> makeActive pane
Nothing -> return ()) ideR
_ -> return ()
setWindowWindowPosition window WindowPositionCenterOnParent
widgetShowAll window
return (tree, store)
modifyIDE_ (\ide -> ide{currentState = IsFlipping tree'})
-- This is done after currentState is set so we know not to update the
-- previous panes list
n <- treeModelIterNChildren store' Nothing
p <- treePathNewFromIndices' [if direction then min 1 (n - 1) else n - 1]
treeViewSetCursor tree' p noTreeViewColumn False
handleKeyRelease :: IsTreeView alpha => alpha -> IDERef -> EventKey -> IO Bool
handleKeyRelease tree ideR e = do
name <- getEventKeyKeyval e >>= keyvalName
case name of
Just ctrl | (ctrl == "Control_L") || (ctrl == "Control_R") -> do
currentState' <- reflectIDE (readIDE currentState) ideR
case currentState' of
IsFlipping _tv ->
treeViewGetCursor tree >>= \case
(Just treePath, _) -> do
Just column <- treeViewGetColumn tree 0
treeViewRowActivated tree treePath column
return False
_ -> return False
_ -> return False
_ -> return False