using (and corrected) refined button handler invocation

TODO: "old" camera handler interferes with left mouse clicks/drags
This commit is contained in:
tpajenka
2014-05-15 22:08:43 +02:00
parent c17852d8e1
commit 271497be81
3 changed files with 146 additions and 82 deletions

View File

@ -2,6 +2,8 @@ module UI.UIOperations where
import Control.Lens ((^.))
import Control.Monad (liftM)
--import Control.Monad.IO.Class (liftIO)
import Control.Monad.RWS.Strict (get)
import qualified Data.HashMap.Strict as Map
import Data.Maybe
@ -19,6 +21,14 @@ toGUIAnys m = mapMaybe (`Map.lookup` m)
{-# INLINABLE toGUIAnys #-}
-- TODO: check for missing components?
-- | Tests whether a point is inside a widget by testing its bounding box first.
isInsideFast :: Monad m => GUIWidget m
-> Pixel -- ^ local coordinates
-> m Bool
isInsideFast wg px = do
(_, _, w, h) <- wg ^. baseProperties.boundary
liftM (isInsideExtent (w, h) px &&) $ (wg ^. baseProperties.isInside) wg px
-- |The function 'getInsideId' returns child widgets that overlap with a
-- specific screen position and the pixel's local coordinates.
@ -27,27 +37,49 @@ toGUIAnys m = mapMaybe (`Map.lookup` m)
-- considered part of the component. The function returns all hit widgets that
-- have no hit children, which may be the input widget itself,
-- or @[]@ if the point does not hit the widget.
getInsideId :: Map.HashMap UIId (GUIWidget Pioneers) -- ^map containing ui widgets
-> Pixel -- ^screen position
getInsideId :: Pixel -- ^parents local coordinates
-> UIId -- ^the parent widget
-> Pioneers [(UIId, Pixel)]
getInsideId hMap px uid = do
let wg = toGUIAny hMap uid
bnd@(bX, bY, _, _) <- wg ^. baseProperties.boundary
getInsideId px uid = do
state <- get
let wg = toGUIAny (state ^. ui.uiMap) uid
(bX, bY, _, _) <- wg ^. baseProperties.boundary
let px' = px -: (bX, bY)
inside <- liftM (isInsideRect bnd px &&) $ (wg ^. baseProperties.isInside) wg px'
inside <- isInsideFast wg px'
if inside -- test inside parent's bounding box
then do
childrenIds <- wg ^. baseProperties.children
hitChildren <- liftM concat $ mapM (getInsideId hMap px') childrenIds
hitChildren <- liftM concat $ mapM (getInsideId px') childrenIds
case hitChildren of
[] -> return [(uid, px')]
_ -> return hitChildren
else return []
--TODO: Priority queue?
--TODO: only needs to return single target if non-overlapping-child convention applies
-- TODO not needed if non-overlapping-child convention applies
getLeadingWidget :: [(UIId, Pixel)] -- ^widgets and their screen positions
-> Pioneers (Maybe (UIId, Pixel)) -- ^the leading widget
getLeadingWidget [] = return Nothing
getLeadingWidget (x:_) = return $ Just x
-- |The function 'isHittingChild' tests if a pixel is hitting a child of the given widget.
--
-- @'Left' 'False'@ is returned if the point is outside the widget,
-- @'Left' 'True'@ is returned if the point is inside the widget and hits no child and
-- 'Right' in combination with both the innermost hit child and the positions local coordinates
-- is returned otherwise.
isHittingChild :: Pixel -- ^parents local coordinates
-> GUIWidget Pioneers -- ^parent widget
-> Pioneers (Either Bool (UIId, Pixel))
isHittingChild px wg = do
isIn <- isInsideFast wg px
if isIn
then do
chld <- wg ^. baseProperties.children
hitChld <- liftM concat $ mapM (getInsideId px) chld
hitLead <- getLeadingWidget hitChld
case hitLead of
Nothing -> return $ Left True
Just h -> return $ Right h
else return $ Left False