module Graphics.UI.Sifflet.Types
( VPUI(..)
, WinId, VPUIWindow(..)
, vpuiFileChanged
, vpuiUserEnvAList
, vpuiInsertWindow
, vpuiTryGetWindow
, vpuiGetWindow
, vpuiUpdateWindow
, vpuiReplaceWindow
, vpuiUpdateWindowIO
, vpuiRemoveVPUIWindow
, vpuiWindowLookupCanvas, vpuiWindowGetCanvas
, vpuiWindowSetCanvas, vpuiWindowModCanvas
, vpuiWindowModCanvasIO
, vpuiModCanvas, vpuiModCanvasIO
, vpuiWindowWindow
, VPToolkit(..)
, Toolbox(..)
, Tool(..)
, ToolContext(..)
, CanvasToolOp
, ToolOp
, toToolOpVW
, Workspace(..)
, VCanvas(..)
, Selection(..)
, Dragging(..)
)
where
import Data.Map as Map
import Data.Graph.Inductive as G
import Graphics.UI.Gtk.Gdk.EventM (Modifier(..))
import Data.Sifflet.Geometry
import Data.Sifflet.TreeLayout
import Data.Sifflet.WGraph
import Language.Sifflet.Expr
import Graphics.UI.Sifflet.Frame
import Graphics.UI.Sifflet.LittleGtk
import Graphics.UI.Sifflet.RPanel
import Language.Sifflet.Util
data VPUI = VPUI {
vpuiWindows :: Map WinId VPUIWindow,
vpuiToolkits :: [(String, VPToolkit)],
vpuiInitialDir :: FilePath,
vpuiCurrentDir :: FilePath,
vpuiCurrentFile :: Maybe FilePath,
vpuiStyle :: Style,
vpuiInitialEnv :: Env,
vpuiGlobalEnv :: Env,
vpuiFileEnv :: Env,
vpuiDebugging :: Bool
}
vpuiFileChanged :: VPUI -> Bool
vpuiFileChanged vpui = vpuiGlobalEnv vpui /= vpuiFileEnv vpui
vpuiUserEnvAList :: VPUI -> [(String, Value)]
vpuiUserEnvAList vpui =
let env' = vpuiGlobalEnv vpui
env = vpuiInitialEnv vpui
in if length env == 1 && length env' == 1
then assocs (Map.difference (head env') (head env))
else errcats ["vpuiUserEnv: env lengths are not one",
"|env'|:", show (length env'),
"|env|:", show (length env)]
vpuiInsertWindow :: VPUI -> WinId -> VPUIWindow -> VPUI
vpuiInsertWindow vpui winId vw =
vpui {vpuiWindows = Map.insert winId vw (vpuiWindows vpui)}
vpuiTryGetWindow :: VPUI -> WinId -> Maybe VPUIWindow
vpuiTryGetWindow vpui winId = Map.lookup winId (vpuiWindows vpui)
vpuiGetWindow :: VPUI -> WinId -> VPUIWindow
vpuiGetWindow vpui winId = vpuiWindows vpui ! winId
vpuiReplaceWindow :: VPUI -> WinId -> VPUIWindow -> VPUI
vpuiReplaceWindow vpui winId vpuiWin =
let winMap = vpuiWindows vpui
winMap' = insert winId vpuiWin winMap
in vpui {vpuiWindows = winMap'}
vpuiUpdateWindow :: VPUI -> WinId -> (VPUIWindow -> VPUIWindow) -> VPUI
vpuiUpdateWindow vpui winId updater =
let winMap = vpuiWindows vpui
winMap' = adjust updater winId winMap
in vpui {vpuiWindows = winMap'}
vpuiUpdateWindowIO :: WinId -> (VPUIWindow -> IO VPUIWindow) -> VPUI -> IO VPUI
vpuiUpdateWindowIO winId updater vpui = do
{
let winMap = vpuiWindows vpui
vw = winMap ! winId
; vw' <- updater vw
; let winMap' = insert winId vw' winMap
; return $ vpui {vpuiWindows = winMap'}
}
vpuiRemoveVPUIWindow :: WinId -> VPUI -> VPUI
vpuiRemoveVPUIWindow winId vpui =
let winMap = vpuiWindows vpui
winMap' = delete winId winMap
in vpui {vpuiWindows = winMap'}
data VPUIWindow =
VPUIWorkWin Workspace Window
| FunctionPadWindow Window [(String, RPanel)]
vpuiWindowWindow :: VPUIWindow -> Window
vpuiWindowWindow vw =
case vw of
VPUIWorkWin _ w -> w
FunctionPadWindow w _ -> w
vpuiWindowLookupCanvas :: VPUIWindow -> Maybe VCanvas
vpuiWindowLookupCanvas vw =
case vw of
VPUIWorkWin ws _ -> Just (wsCanvas ws)
_ -> Nothing
vpuiWindowGetCanvas :: VPUIWindow -> VCanvas
vpuiWindowGetCanvas vw =
case vpuiWindowLookupCanvas vw of
Nothing -> error "vpuiWindowGetCanvas: no canvas found"
Just canvas -> canvas
vpuiWindowSetCanvas :: VPUIWindow -> VCanvas -> VPUIWindow
vpuiWindowSetCanvas vw canvas =
case vw of
VPUIWorkWin ws w -> VPUIWorkWin (ws {wsCanvas = canvas}) w
_ -> error "vpuiWindowSetCanvas: not a workspace window"
vpuiWindowModCanvas :: VPUIWindow -> (VCanvas -> VCanvas) -> VPUIWindow
vpuiWindowModCanvas vw f =
case vpuiWindowLookupCanvas vw of
Nothing -> error "vpuiWindowModCanvas: plain VPUIWindow"
Just canvas -> vpuiWindowSetCanvas vw (f canvas)
vpuiWindowModCanvasIO :: VPUIWindow -> (VCanvas -> IO VCanvas) -> IO VPUIWindow
vpuiWindowModCanvasIO vw f =
case vpuiWindowLookupCanvas vw of
Nothing -> error "vpuiWindowModCanvas: plain VPUIWindow"
Just canvas ->
do
{
canvas' <- f canvas
; return $ vpuiWindowSetCanvas vw canvas'
}
vpuiModCanvas :: VPUI -> WinId -> (VCanvas -> VCanvas) -> VPUI
vpuiModCanvas vpui winId modCanvas =
let modWindow vw = vpuiWindowModCanvas vw modCanvas
in vpuiUpdateWindow vpui winId modWindow
vpuiModCanvasIO :: VPUI -> WinId -> (VCanvas -> IO VCanvas) -> IO VPUI
vpuiModCanvasIO vpui winId modCanvas =
let modWindow vw = vpuiWindowModCanvasIO vw modCanvas
in vpuiUpdateWindowIO winId modWindow vpui
type WinId = String
data Workspace =
Workspace {wsRootWidget :: VBox,
wsCanvas :: VCanvas,
wsButtonBar :: HBox,
wsStatusbar :: Statusbar,
wsArgToolSpecs :: [ArgSpec]
}
data VPToolkit = VPToolkit {toolkitName :: String,
toolkitWidth :: Int,
toolkitRows :: [[Tool]]}
data Toolbox = Toolbox {toolboxFrame :: GtkFrame
, toolboxVBox :: VBox}
type ToolOp
= VPUI -> WinId -> ToolContext -> [Modifier] -> Double -> Double -> IO VPUI
type CanvasToolOp
= VCanvas -> ToolContext -> [Modifier] -> Double -> Double -> IO VCanvas
data Tool = Tool {toolName :: String,
toolActivated :: VCanvas -> IO VCanvas,
toolOp :: ToolOp
}
toToolOpVW :: CanvasToolOp -> ToolOp
toToolOpVW vcOp vpui winId toolContext mods x y = do
{
let vw = vpuiGetWindow vpui winId
canv = vpuiWindowGetCanvas vw
; canv' <- vcOp canv toolContext mods x y
; let vw' = vpuiWindowSetCanvas vw canv'
; return $ vpuiReplaceWindow vpui winId vw'
}
data ToolContext = TCWorkspace
| TCCallFrame CanvFrame
| TCEditFrame CanvFrame
| TCExprNode
data VCanvas = VCanvas {
vcLayout :: GtkLayout,
vcStyle :: Style,
vcGraph :: WGraph,
vcFrames :: [CanvFrame],
vcSize :: Size,
vcMousePos :: (Double, Double),
vcTool :: Maybe Tool,
vcActive :: Maybe Node,
vcSelected :: Maybe Selection,
vcDragging :: Maybe Dragging
}
data Selection = SelectionNode {selNode :: G.Node}
| SelectionInlet {selNode :: G.Node,
selInEdge :: WEdge}
| SelectionOutlet {selNode :: G.Node,
selOutEdge :: WEdge}
deriving (Eq, Read, Show)
data Dragging = Dragging { draggingNode :: G.Node,
draggingPosition :: Position
}
deriving (Eq, Read, Show)