goatee-gtk-0.4.0: src/Game/Goatee/Ui/Gtk/Tool/Line.hs
-- This file is part of Goatee.
--
-- Copyright 2014-2021 Bryan Gardiner
--
-- Goatee is free software: you can redistribute it and/or modify
-- it under the terms of the GNU Affero General Public License as published by
-- the Free Software Foundation, either version 3 of the License, or
-- (at your option) any later version.
--
-- Goatee is distributed in the hope that it will be useful,
-- but WITHOUT ANY WARRANTY; without even the implied warranty of
-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-- GNU Affero General Public License for more details.
--
-- You should have received a copy of the GNU Affero General Public License
-- along with Goatee. If not, see <http://www.gnu.org/licenses/>.
module Game.Goatee.Ui.Gtk.Tool.Line (
LineTool, create,
LinelikeDescriptor, arrowDescriptor, lineDescriptor,
) where
import Data.List (delete)
import Game.Goatee.Lib.Board
import Game.Goatee.Lib.Monad
import Game.Goatee.Lib.Property
import Game.Goatee.Lib.Types
import Game.Goatee.Ui.Gtk.Common
-- | A 'UiTool' that toggles lines between points on the board.
data LineTool ui = LineTool
{ myUi :: ui
, myViewState :: ViewState
, myToolState :: ToolState
, myDescriptor :: AnyLinelikeDescriptor
}
-- | A descriptor for a line-like property: a valued property that contains a
-- list of connections between two points on the board.
data LinelikeDescriptor v = LinelikeDescriptor
{ linelikeDescriptor :: ValuedPropertyInfo [v]
, linelikeLift :: (Coord, Coord) -> v
}
-- | An existential type for any linelike descriptor.
data AnyLinelikeDescriptor = forall v. Eq v => AnyLinelikeDescriptor (LinelikeDescriptor v)
-- | A descriptor for directed arrows ('AR').
arrowDescriptor :: AnyLinelikeDescriptor
arrowDescriptor = AnyLinelikeDescriptor LinelikeDescriptor
{ linelikeDescriptor = propertyAR
, linelikeLift = id
}
-- | A descriptor for undirected lines ('LN').
lineDescriptor :: AnyLinelikeDescriptor
lineDescriptor = AnyLinelikeDescriptor LinelikeDescriptor
{ linelikeDescriptor = propertyLN
, linelikeLift = uncurry Line
}
instance UiCtrl go ui => UiView go ui (LineTool ui) where
viewName me = case myDescriptor me of
AnyLinelikeDescriptor descriptor ->
"LineTool(" ++ propertyName (linelikeDescriptor descriptor) ++ ")"
viewCtrl = myUi
viewState = myViewState
viewUpdate = const $ return ()
instance UiCtrl go ui => UiTool go ui (LineTool ui) where
toolState = myToolState
toolGobanClickComplete me (Just from) (Just to) | from /= to = case myDescriptor me of
AnyLinelikeDescriptor linelike ->
doUiGo (myUi me) $
modifyPropertyList (linelikeDescriptor linelike) $
toggleInList $ linelikeLift linelike (from, to)
toolGobanClickComplete _ _ _ = return ()
toolGobanRenderGetBoard me cursor = do
state <- toolGetGobanState me
case state of
ToolGobanDragging _ (Just startCoord) (Just endCoord) | startCoord /= endCoord ->
case myDescriptor me of
AnyLinelikeDescriptor linelike ->
return $ cursorBoard $ flip execGo cursor $
modifyPropertyList (linelikeDescriptor linelike) $
toggleInList $ linelikeLift linelike (startCoord, endCoord)
_ -> return $ cursorBoard cursor
-- | Creates a 'LineTool' that will toggle a line-like property between pairs of
-- points on the board.
create :: UiCtrl go ui => ui -> AnyLinelikeDescriptor -> ToolState -> IO (LineTool ui)
create ui descriptor toolState = do
viewState <- viewStateNew
return LineTool
{ myUi = ui
, myViewState = viewState
, myToolState = toolState
, myDescriptor = descriptor
}
-- | Toggles the presense of an item in a list.
toggleInList :: Eq a => a -> [a] -> [a]
toggleInList x xs = (if x `elem` xs then delete else (:)) x xs