moduleGraphics.UI.Sifflet.Types(VPUI(..),WinId,VPUIWindow(..),vpuiFileChanged,vpuiUserEnvAList-- | Operations on a VPUI involving its window,vpuiInsertWindow,vpuiTryGetWindow,vpuiGetWindow,vpuiUpdateWindow,vpuiReplaceWindow,vpuiUpdateWindowIO,vpuiRemoveVPUIWindow-- | Operations on a window involving its canvas,vpuiWindowLookupCanvas,vpuiWindowGetCanvas,vpuiWindowSetCanvas,vpuiWindowModCanvas,vpuiWindowModCanvasIO-- | Operation on a VPUI involving the canvas of its window,vpuiModCanvas,vpuiModCanvasIO-- | Other operations on a window,vpuiWindowWindow,VPToolkit(..),Toolbox(..),Tool(..),ToolContext(..),CanvasToolOp,ToolOp,toToolOpVW,Workspace(..),VCanvas(..),Selection(..),Dragging(..))whereimportData.MapasMapimportData.Graph.InductiveasGimportGraphics.UI.Gtk.Gdk.EventM(Modifier(..))importData.Sifflet.GeometryimportData.Sifflet.TreeLayoutimportData.Sifflet.WGraphimportLanguage.Sifflet.ExprimportGraphics.UI.Sifflet.FrameimportGraphics.UI.Sifflet.LittleGtkimportGraphics.UI.Sifflet.RPanelimportLanguage.Sifflet.Util-- | VPUI: Sifflet (formerly VisiProg) User Interface-- The initialEnv is apt to contain "builtin" functions;-- it's preserved here so that when writing to a file,-- we can skip the functions that were in the initial env.dataVPUI=VPUI{vpuiWindows::MapWinIdVPUIWindow,-- ^ all the windows of the programvpuiToolkits::[(String,VPToolkit)],-- ^ ordered association list,-- collections of toolsvpuiFilePath::MaybeFilePath,-- ^ the file opened or to savevpuiStyle::Style,-- ^ for windows, canvases, editorsvpuiInitialEnv::Env,-- ^ initial value of global environmentvpuiGlobalEnv::Env,-- ^ the global environmentvpuiFileEnv::Env,-- ^ global env as of last file open or save,-- used to detect unsaved changesvpuiDebugging::Bool-- ^ include debug commands in context menu?}-- | Tell whether the global environmkent has changed since the-- last file open or savevpuiFileChanged::VPUI->BoolvpuiFileChangedvpui=vpuiGlobalEnvvpui/=vpuiFileEnvvpui-- | Extract from the environment the part defined by the user-- But you probably want to use Graphics.UI.Sifflet.Window.UserFunctions-- instead of this.vpuiUserEnvAList::VPUI->[(String,Value)]vpuiUserEnvAListvpui=letenv'=vpuiGlobalEnvvpui-- I hopeenv=vpuiInitialEnvvpuiiniflengthenv==1&&lengthenv'==1thenassocs(Map.difference(headenv')(headenv))elseerrcats["vpuiUserEnv: env lengths are not one","|env'|:",show(lengthenv'),"|env|:",show(lengthenv)]-- | Insert a window in the window mapvpuiInsertWindow::VPUI->WinId->VPUIWindow->VPUIvpuiInsertWindowvpuiwinIdvw=vpui{vpuiWindows=Map.insertwinIdvw(vpuiWindowsvpui)}-- | Try to get the VPUIWindow with the given window ID,-- return Just result or NothingvpuiTryGetWindow::VPUI->WinId->MaybeVPUIWindowvpuiTryGetWindowvpuiwinId=Map.lookupwinId(vpuiWindowsvpui)-- | Get the VPUIWindow with the given window ID;-- it is an error if this fails.vpuiGetWindow::VPUI->WinId->VPUIWindowvpuiGetWindowvpuiwinId=vpuiWindowsvpui!winId-- | Replace a VPUIWindow with given window ID;-- it is an error if this fails.vpuiReplaceWindow::VPUI->WinId->VPUIWindow->VPUIvpuiReplaceWindowvpuiwinIdvpuiWin=letwinMap=vpuiWindowsvpuiwinMap'=insertwinIdvpuiWinwinMapinvpui{vpuiWindows=winMap'}-- | Apply an update function to a VPUIWindow with given window ID;-- it is an error if this fails.vpuiUpdateWindow::VPUI->WinId->(VPUIWindow->VPUIWindow)->VPUIvpuiUpdateWindowvpuiwinIdupdater=letwinMap=vpuiWindowsvpuiwinMap'=adjustupdaterwinIdwinMapinvpui{vpuiWindows=winMap'}-- | Apply an update IO action to a VPUIWindow with given window ID;-- it is an error if this fails.vpuiUpdateWindowIO::WinId->(VPUIWindow->IOVPUIWindow)->VPUI->IOVPUIvpuiUpdateWindowIOwinIdupdatervpui=do{letwinMap=vpuiWindowsvpuivw=winMap!winId;vw'<-updatervw;letwinMap'=insertwinIdvw'winMap;return$vpui{vpuiWindows=winMap'}}-- | Remove a window from the windows map; it has already been destroyed-- in the GUIvpuiRemoveVPUIWindow::WinId->VPUI->VPUIvpuiRemoveVPUIWindowwinIdvpui=letwinMap=vpuiWindowsvpuiwinMap'=deletewinIdwinMapinvpui{vpuiWindows=winMap'}dataVPUIWindow=-- VPUIJustWindow Window VPUIWorkWinWorkspaceWindow|FunctionPadWindowWindow[(String,RPanel)]vpuiWindowWindow::VPUIWindow->WindowvpuiWindowWindowvw=casevwofVPUIWorkWin_w->wFunctionPadWindoww_->w-- | Try to find canvas; fail gracefullyvpuiWindowLookupCanvas::VPUIWindow->MaybeVCanvasvpuiWindowLookupCanvasvw=casevwofVPUIWorkWinws_->Just(wsCanvasws)_->Nothing-- | Find canvas or fail dramaticallyvpuiWindowGetCanvas::VPUIWindow->VCanvasvpuiWindowGetCanvasvw=casevpuiWindowLookupCanvasvwofNothing->error"vpuiWindowGetCanvas: no canvas found"Justcanvas->canvasvpuiWindowSetCanvas::VPUIWindow->VCanvas->VPUIWindowvpuiWindowSetCanvasvwcanvas=casevwofVPUIWorkWinwsw->VPUIWorkWin(ws{wsCanvas=canvas})w_->error"vpuiWindowSetCanvas: not a workspace window"vpuiWindowModCanvas::VPUIWindow->(VCanvas->VCanvas)->VPUIWindowvpuiWindowModCanvasvwf=casevpuiWindowLookupCanvasvwofNothing->error"vpuiWindowModCanvas: plain VPUIWindow"Justcanvas->vpuiWindowSetCanvasvw(fcanvas)vpuiWindowModCanvasIO::VPUIWindow->(VCanvas->IOVCanvas)->IOVPUIWindowvpuiWindowModCanvasIOvwf=casevpuiWindowLookupCanvasvwofNothing->error"vpuiWindowModCanvas: plain VPUIWindow"Justcanvas->do{canvas'<-fcanvas;return$vpuiWindowSetCanvasvwcanvas'}-- | Update the canvas of the specified window, without IOvpuiModCanvas::VPUI->WinId->(VCanvas->VCanvas)->VPUIvpuiModCanvasvpuiwinIdmodCanvas=letmodWindowvw=vpuiWindowModCanvasvwmodCanvasinvpuiUpdateWindowvpuiwinIdmodWindow-- | Update the canvas of the specified window, with IOvpuiModCanvasIO::VPUI->WinId->(VCanvas->IOVCanvas)->IOVPUIvpuiModCanvasIOvpuiwinIdmodCanvas=letmodWindowvw=vpuiWindowModCanvasIOvwmodCanvasinvpuiUpdateWindowIOwinIdmodWindowvpuitypeWinId=StringdataWorkspace=Workspace{wsRootWidget::VBox,-- ^ container of the restwsCanvas::VCanvas,-- ^ the canvaswsButtonBar::HBox,wsStatusbar::Statusbar,wsArgToolSpecs::[ArgSpec]-- ^ none if not editing}-- | Toolkit functions are organized in groups (rows) for presentation-- in a toolboxdataVPToolkit=VPToolkit{toolkitName::String,toolkitWidth::Int,-- (-1) = don't caretoolkitRows::[[Tool]]}-- | A Toolbox is a framed VBox with a set of Toolbars attacheddataToolbox=Toolbox{toolboxFrame::GtkFrame,toolboxVBox::VBox}-- | ToolOp a is intended for a = VPUIWindow or VCanvas-- type ToolOp a -- = VPUI -> a -> ToolContext -> [Modifier] -> Double -> Double -> IO atypeToolOp=VPUI->WinId->ToolContext->[Modifier]->Double->Double->IOVPUItypeCanvasToolOp=VCanvas->ToolContext->[Modifier]->Double->Double->IOVCanvasdataTool=Tool{toolName::String,-- the tool's name-- what to do when the tool is selected from the toolboxtoolActivated::VCanvas->IOVCanvas,-- what to do to apply the tool to a point on the canvastoolOp::ToolOp}-- | A helper for making toolOps from actions on VCanvastoToolOpVW::CanvasToolOp->ToolOptoToolOpVWvcOpvpuiwinIdtoolContextmodsxy=do{letvw=vpuiGetWindowvpuiwinIdcanv=vpuiWindowGetCanvasvw;canv'<-vcOpcanvtoolContextmodsxy;letvw'=vpuiWindowSetCanvasvwcanv';return$vpuiReplaceWindowvpuiwinIdvw'}-- | ToolContext: The way a tool should be applied depends on -- where it is being used dataToolContext=TCWorkspace|TCCallFrameCanvFrame|TCEditFrameCanvFrame|TCExprNode-- ???-- | A canvas that can display multiple boxes representing -- expressions or function definitions or callsdataVCanvas=VCanvas{vcLayout::GtkLayout,vcStyle::Style,vcGraph::WGraph,vcFrames::[CanvFrame],vcSize::Size,-- vcLocalEnv :: Env, -- only good for function editor, I think? vcMousePos::(Double,Double),vcTool::MaybeTool,-- current tool on this canvasvcActive::MaybeNode,-- active node, if anyvcSelected::MaybeSelection,-- selected node(s), if anyvcDragging::MaybeDragging-- what we're dragging, if anything}dataSelection=SelectionNode{selNode::G.Node}|SelectionInlet{selNode::G.Node,selInEdge::WEdge}-- numbered from 0|SelectionOutlet{selNode::G.Node,selOutEdge::WEdge}-- normally just 0deriving(Eq,Read,Show)-- | A Dragging keeps track of the object (node) being dragged-- and the current mouse position.dataDragging=Dragging{draggingNode::G.Node,draggingPosition::Position}deriving(Eq,Read,Show)