mirror of
https://github.com/rgleichman/glance.git
synced 2024-08-16 18:30:36 +03:00
Implement undo for adding nodes. (Issue #12)
This commit is contained in:
parent
4bfbb4736a
commit
064aff1138
80
gui/Main.hs
80
gui/Main.hs
@ -87,7 +87,8 @@ data AppState = AppState
|
|||||||
_asEdges :: [(Element, Element)],
|
_asEdges :: [(Element, Element)],
|
||||||
_asElements :: IntMap.IntMap Element,
|
_asElements :: IntMap.IntMap Element,
|
||||||
-- | FPS rounded down to nearest hundred if over 200 fps.
|
-- | FPS rounded down to nearest hundred if over 200 fps.
|
||||||
_asFPSr :: Double
|
_asFPSr :: Double,
|
||||||
|
_asHistory :: [HistoryEvent]
|
||||||
}
|
}
|
||||||
|
|
||||||
data InputEvent
|
data InputEvent
|
||||||
@ -96,6 +97,14 @@ data InputEvent
|
|||||||
ElemId
|
ElemId
|
||||||
(Double, Double) -- relative mouse position
|
(Double, Double) -- relative mouse position
|
||||||
| AddNode (Double, Double) -- where to add the node
|
| AddNode (Double, Double) -- where to add the node
|
||||||
|
| Undo
|
||||||
|
|
||||||
|
-- | Records actions so that they can be undone.
|
||||||
|
data HistoryEvent
|
||||||
|
= MovedNode -- TODO Record which node, and where the node was moved
|
||||||
|
-- from (and to).
|
||||||
|
| AddedNode ElemId -- TODO Record which node was added.
|
||||||
|
deriving (Show, Eq)
|
||||||
|
|
||||||
emptyAppState :: AppState
|
emptyAppState :: AppState
|
||||||
emptyAppState =
|
emptyAppState =
|
||||||
@ -103,7 +112,8 @@ emptyAppState =
|
|||||||
{ _asMovingNode = Nothing,
|
{ _asMovingNode = Nothing,
|
||||||
_asEdges = [],
|
_asEdges = [],
|
||||||
_asElements = mempty,
|
_asElements = mempty,
|
||||||
_asFPSr = 0
|
_asFPSr = 0,
|
||||||
|
_asHistory = []
|
||||||
}
|
}
|
||||||
|
|
||||||
emptyInputs :: Inputs
|
emptyInputs :: Inputs
|
||||||
@ -212,9 +222,19 @@ getFps inputs =
|
|||||||
then fromIntegral $ div (truncate fps) 100 * (100 :: Int)
|
then fromIntegral $ div (truncate fps) 100 * (100 :: Int)
|
||||||
else fps
|
else fps
|
||||||
|
|
||||||
|
clickOnNode :: ElemId -> AppState -> AppState
|
||||||
|
clickOnNode elemId oldState@AppState {_asMovingNode, _asHistory} =
|
||||||
|
case _asMovingNode of
|
||||||
|
Nothing -> oldState {_asMovingNode = Just elemId}
|
||||||
|
Just _ ->
|
||||||
|
oldState
|
||||||
|
{ _asMovingNode = Nothing,
|
||||||
|
_asHistory = MovedNode : _asHistory
|
||||||
|
}
|
||||||
|
|
||||||
-- | Add a node to the canvas at the given position.
|
-- | Add a node to the canvas at the given position.
|
||||||
addNode :: (Double, Double) -> AppState -> AppState
|
addNode :: (Double, Double) -> AppState -> AppState
|
||||||
addNode addPosition s@AppState {_asElements} =
|
addNode addPosition s@AppState {_asElements, _asHistory} =
|
||||||
let biggestKey = maybe 0 fst (IntMap.lookupMax _asElements)
|
let biggestKey = maybe 0 fst (IntMap.lookupMax _asElements)
|
||||||
newNode =
|
newNode =
|
||||||
Element
|
Element
|
||||||
@ -222,19 +242,35 @@ addNode addPosition s@AppState {_asElements} =
|
|||||||
_elSize = nodeSize,
|
_elSize = nodeSize,
|
||||||
_elZ = 0
|
_elZ = 0
|
||||||
}
|
}
|
||||||
|
nodeId = (biggestKey + 1)
|
||||||
newElements =
|
newElements =
|
||||||
IntMap.insert (biggestKey + 1) newNode _asElements
|
IntMap.insert nodeId newNode _asElements
|
||||||
in s {_asElements = newElements}
|
in s
|
||||||
|
{ _asElements = newElements,
|
||||||
|
_asHistory = AddedNode (ElemId nodeId) : _asHistory
|
||||||
|
}
|
||||||
|
|
||||||
|
removeNode :: ElemId -> AppState -> AppState
|
||||||
|
removeNode nodeId oldState@AppState {_asElements} =
|
||||||
|
oldState {_asElements = IntMap.delete (_unElemId nodeId) _asElements}
|
||||||
|
|
||||||
|
undo :: AppState -> AppState
|
||||||
|
undo oldState@AppState {_asHistory} = newState
|
||||||
|
where
|
||||||
|
newState = case _asHistory of
|
||||||
|
[] -> oldState
|
||||||
|
historyEvent : restOfHistory -> undidState {_asHistory = restOfHistory}
|
||||||
|
where
|
||||||
|
undidState = case historyEvent of
|
||||||
|
MovedNode -> oldState -- TODO Implement undo move node.
|
||||||
|
AddedNode nodeId -> removeNode nodeId oldState
|
||||||
|
|
||||||
processInput :: InputEvent -> AppState -> AppState
|
processInput :: InputEvent -> AppState -> AppState
|
||||||
processInput inputEvent oldState@AppState {_asMovingNode} =
|
processInput inputEvent oldState =
|
||||||
case inputEvent of
|
case inputEvent of
|
||||||
ClickOnNode elemId _relativePosition ->
|
ClickOnNode elemId _relativePosition -> clickOnNode elemId oldState
|
||||||
let newMovingNodeId = case _asMovingNode of
|
|
||||||
Nothing -> Just elemId
|
|
||||||
Just _ -> Nothing
|
|
||||||
in oldState {_asMovingNode = newMovingNodeId}
|
|
||||||
AddNode addPosition -> addNode addPosition oldState
|
AddNode addPosition -> addNode addPosition oldState
|
||||||
|
Undo -> undo oldState
|
||||||
|
|
||||||
processInputs :: Inputs -> AppState -> AppState
|
processInputs :: Inputs -> AppState -> AppState
|
||||||
processInputs
|
processInputs
|
||||||
@ -352,6 +388,24 @@ backgroundPress inputsRef stateRef eventButton = do
|
|||||||
_ -> mempty
|
_ -> mempty
|
||||||
pure Gdk.EVENT_STOP
|
pure Gdk.EVENT_STOP
|
||||||
|
|
||||||
|
addUndoInputAction :: IORef Inputs -> IO ()
|
||||||
|
addUndoInputAction inputsRef = do
|
||||||
|
putStrLn "Adding Undo input action."
|
||||||
|
modifyIORef' inputsRef (addEvent Undo)
|
||||||
|
pure ()
|
||||||
|
|
||||||
|
keyPress :: IORef Inputs -> Gdk.EventKey -> IO Bool
|
||||||
|
keyPress inputsRef eventKey = do
|
||||||
|
-- TODO May want to check that ctrl is pressed by checking that
|
||||||
|
-- getEventKeyState is ModifierTypeControlMask. May also want to use
|
||||||
|
-- Gdk.KEY_?.
|
||||||
|
key <- Gdk.getEventKeyString eventKey
|
||||||
|
print key
|
||||||
|
case key of
|
||||||
|
Just "\SUB" -> addUndoInputAction inputsRef -- putStrLn "ctrl-z pressed"
|
||||||
|
_ -> pure ()
|
||||||
|
pure Gdk.EVENT_STOP
|
||||||
|
|
||||||
startApp :: Gtk.Application -> IO ()
|
startApp :: Gtk.Application -> IO ()
|
||||||
startApp app = do
|
startApp app = do
|
||||||
stateRef <- newIORef emptyAppState
|
stateRef <- newIORef emptyAppState
|
||||||
@ -366,6 +420,7 @@ startApp app = do
|
|||||||
#borderWidth := 0
|
#borderWidth := 0
|
||||||
]
|
]
|
||||||
backgroundArea <- new Gtk.DrawingArea []
|
backgroundArea <- new Gtk.DrawingArea []
|
||||||
|
Gtk.widgetAddEvents window [Gdk.EventMaskKeyPressMask]
|
||||||
Gtk.widgetAddEvents
|
Gtk.widgetAddEvents
|
||||||
backgroundArea
|
backgroundArea
|
||||||
[ Gdk.EventMaskPointerMotionMask,
|
[ Gdk.EventMaskPointerMotionMask,
|
||||||
@ -399,7 +454,8 @@ startApp app = do
|
|||||||
1
|
1
|
||||||
(timeoutCallback inputsRef stateRef gdkWindow device backgroundArea)
|
(timeoutCallback inputsRef stateRef gdkWindow device backgroundArea)
|
||||||
|
|
||||||
_ <- on backgroundArea #buttonPressEvent (backgroundPress inputsRef stateRef)
|
_ <- Gtk.onWidgetButtonPressEvent backgroundArea (backgroundPress inputsRef stateRef)
|
||||||
|
_ <- Gtk.onWidgetKeyPressEvent window (keyPress inputsRef)
|
||||||
|
|
||||||
#showAll window
|
#showAll window
|
||||||
pure ()
|
pure ()
|
||||||
|
Loading…
Reference in New Issue
Block a user