packages feed

Blobs-0.1: src/ContextMenu.hs

module ContextMenu
    ( canvas, edge, node, via ) where

import State
import Network
import Document
import NetworkControl
import SafetyNet
import CommonIO
import Math (DoublePoint)
import qualified PersistentDocument as PD
import Palette
import InfoKind
import Text.Parse

import Graphics.UI.WX
import Graphics.UI.WXCore(windowGetMousePosition)

-- | Context menu for empty area of canvas
canvas :: (InfoKind n g, Show g, Parse g, Descriptor g) =>
          Frame () -> State g n e -> IO ()
canvas theFrame state =
  do{ contextMenu <- menuPane []
    ; menuItem contextMenu
        [ text := "Add node (shift-click)"
        , on command := safetyNet theFrame $ addNodeItem theFrame state
        ]
    ; g <- fmap (getGlobalInfo . getNetwork)
                (PD.getDocument =<< getDocument state)
    ; menuItem contextMenu
        [ text := ("Edit "++descriptor g)
        , on command := safetyNet theFrame $ changeGlobalInfo theFrame state
        ]

    ; pointWithinWindow <- windowGetMousePosition theFrame
    ; menuPopup contextMenu pointWithinWindow theFrame
    ; objectDelete contextMenu
    }

addNodeItem :: (InfoKind n g) => Frame () -> State g n e -> IO ()
addNodeItem theFrame state =
  do{ mousePoint <- windowGetMousePosition theFrame
    ; ppi <- getScreenPPI
    ; let doubleMousePoint = screenToLogicalPoint ppi mousePoint
    ; createNode doubleMousePoint state
    }

-- | Context menu for an edge
edge :: (InfoKind n g, InfoKind e g) =>
        EdgeNr -> Frame () -> DoublePoint -> State g n e -> IO ()
edge edgeNr theFrame mousepoint state =
  do{ contextMenu <- menuPane []

    ; pDoc <- getDocument state
    ; doc <- PD.getDocument pDoc
    ; let network       = getNetwork doc
          theEdge       = getEdge edgeNr network
          fromPort      = getEdgeFromPort theEdge
          toPort        = getEdgeToPort theEdge

    ; menuItem contextMenu
        [ text := "Add control point"
        , on command := safetyNet theFrame $ createVia mousepoint state
        ]
    ; menuItem contextMenu
        [ text := "Delete edge (Del)"
        , on command := safetyNet theFrame $ deleteSelection state
        ]
    ; menuItem contextMenu
        [ text := "Edit info (i)"
        , on command := safetyNet theFrame $ reinfoNodeOrEdge theFrame state
        ]
    ; menuLine contextMenu
    ; menuItem contextMenu
        [ text := "from port "++show fromPort
        ]
    ; menuItem contextMenu
        [ text := "to port "++show toPort
        ]
    ; pointWithinWindow <- windowGetMousePosition theFrame
    ; menuPopup contextMenu pointWithinWindow theFrame
    ; objectDelete contextMenu
    }

-- | Context menu for a 'via' point
via :: Frame () -> State g n e -> IO ()
via theFrame state =
  do{ contextMenu <- menuPane []
    ; menuItem contextMenu
        [ text := "Delete control point (Del)"
        , on command := safetyNet theFrame $ deleteSelection state
        ]
    ; pointWithinWindow <- windowGetMousePosition theFrame
    ; menuPopup contextMenu pointWithinWindow theFrame
    ; objectDelete contextMenu
    }

-- | Context menu for a node
node :: (InfoKind n g, InfoKind e g) => Int -> Frame () -> State g n e -> IO ()
node nodeNr theFrame state =
  do{ contextMenu <- menuPane []

    ; pDoc <- getDocument state
    ; doc <- PD.getDocument pDoc
    ; let network       = getNetwork doc
          theNode       = getNode nodeNr network
          labelAbove    = getNameAbove theNode
          palette       = getPalette network
          theShape      = getShape theNode
          theInfo       = getInfo theNode
          (i,o)         = maybe (0,0) id $ getArity theNode

    ; menuItem contextMenu
        [ text := "Rename (r)"
        , on command := safetyNet theFrame $ renameNode theFrame state
        ]
    ; menuItem contextMenu
        [ text := "Edit info (i)"
        , on command := safetyNet theFrame $ reinfoNodeOrEdge theFrame state
        ]
    ; menuItem contextMenu
        [ text := "Change arity (in/"++show i++", out/"++show o++")"
        , on command := safetyNet theFrame $ reArityNode theFrame state
        ]
    ; menuItem contextMenu
        [ text := "Delete (Del)"
        , on command := safetyNet theFrame $ deleteSelection state
        ]
    ; menuLine contextMenu

    ; menuItem contextMenu
        [ text := "Label position:" ]
    ; menuItem contextMenu
        [ text := "    above (up arrow)"
        , checkable := True
        , checked := labelAbove
        , on command := safetyNet theFrame $ changeNamePosition True state
        ]
    ; menuItem contextMenu
        [ text := "    below (down arrow)"
        , checkable := True
        , checked := not labelAbove
        ,  on command := safetyNet theFrame $ changeNamePosition False state
        ]
--  ; set (if labelAbove then aboveItem else belowItem) [ checked := True ]

    ; menuLine contextMenu

    -- work out whether to keep the info-field whilst changing shape
    -- (change if shape's default; keep if different i.e. user has changed it)
    ; let keepInfo = case theShape of
                        Left n  -> case lookup n (shapes palette) of
                                     Nothing -> const theInfo
                                     Just (_,Nothing) -> const theInfo
                                     Just (_,Just i)  -> if i==theInfo then id
                                                         else const theInfo
                        Right _ -> const theInfo
    ; menuItem contextMenu
        [ text := "Shape:" ]
    ; mapM_ (shapeItem theShape keepInfo contextMenu) (shapes palette)
    ; otherShape theShape contextMenu

    ; pointWithinWindow <- windowGetMousePosition theFrame
    ; menuPopup contextMenu pointWithinWindow theFrame
    ; objectDelete contextMenu

    }
  where
    shapeItem curShape keepInfo contextMenu (name,(_shape,info)) =
      menuItem contextMenu
        [ text := ("    "++name)
        , checkable := True
        , checked := case curShape of { Left n -> n==name; Right _ -> False; }
        , on command := safetyNet theFrame $ changeNodeShape name newinfo state
        ]
        where newinfo = keepInfo (maybe blank id info)
    otherShape curShape contextMenu =
        case curShape of
            Left _  -> return ()
            Right _ -> do{ menuItem contextMenu
                             [ text := "Other shape"
                             , checkable := True
                             , checked := True
                             ]
                         ; return ()
                         }