214 lines
7.0 KiB
Haskell
214 lines
7.0 KiB
Haskell
module Dodge.SelectionSections (
|
|
scrollSelectionSections,
|
|
nextInSectionSS,
|
|
ssLookupDown,
|
|
ssSetCursor,
|
|
selSecYint,
|
|
selSecSelSize,
|
|
inverseSelSecYint,
|
|
posSelSecYint,
|
|
inverseSelNumPos,
|
|
) where
|
|
|
|
import Control.Applicative
|
|
import qualified Control.Foldl as L
|
|
import Control.Lens
|
|
import Control.Monad
|
|
import Data.Foldable
|
|
import qualified Data.IntMap.Strict as IM
|
|
import qualified Data.IntSet as IS
|
|
import Data.Maybe
|
|
import Dodge.Data.CardinalPoint
|
|
import Dodge.Data.Config
|
|
import Dodge.Data.HUD
|
|
import Dodge.Data.SelectionList
|
|
import Dodge.ScreenPos
|
|
import Geometry.Data
|
|
|
|
scrollSelectionSections :: Int -> IMSS a -> Maybe Selection -> Maybe Selection
|
|
scrollSelectionSections yi sss msel
|
|
| yi == 0 = msel
|
|
| yi > 0 = foldl' (&) msel $ replicate yi (ssScrollUsing ssLookupUp sss)
|
|
| otherwise = foldl' (&) msel $ replicate (negate yi) (ssScrollUsing ssLookupDown sss)
|
|
|
|
nextInSectionSS :: IMSS a -> Maybe Selection -> Maybe Selection
|
|
nextInSectionSS = ssScrollUsing ssLookupNextMax
|
|
|
|
ssScrollUsing ::
|
|
(Int -> Int -> IMSS a -> Maybe (Int, Int, SelectionItem a)) ->
|
|
IMSS a ->
|
|
Maybe Selection ->
|
|
Maybe Selection
|
|
ssScrollUsing g = ssScrollMinOnFail g . fmap (ssItems %~ IM.filter _siIsSelectable)
|
|
|
|
--
|
|
ssScrollMinOnFail ::
|
|
(Int -> Int -> IMSS a -> Maybe (Int, Int, SelectionItem a)) ->
|
|
IMSS a ->
|
|
Maybe Selection ->
|
|
Maybe Selection
|
|
ssScrollMinOnFail f sss msel = fmap (\(i, j, _) -> Sel i j q) $ l <|> ssLookupMin sss
|
|
where
|
|
q = fold (msel ^? _Just . slSet)
|
|
l = do
|
|
Sel i j _ <- msel
|
|
f i j sss
|
|
|
|
---- this version removes the selected set when scrolling outside it
|
|
--ssScrollMinOnFail' ::
|
|
-- (Int -> Int -> IMSS a -> Maybe (Int, Int, SelectionItem a)) ->
|
|
-- IMSS a ->
|
|
-- Maybe Selection ->
|
|
-- Maybe Selection
|
|
--ssScrollMinOnFail' f sss msel = fmap (\(i, j, _) -> Sel i j (q i j)) $ l <|> ssLookupMin sss
|
|
-- where
|
|
-- q i j = fromMaybe mempty $ do
|
|
-- Sel k _ xs <- msel ^? _Just
|
|
-- guard $ j `IS.member` xs && i == k
|
|
-- return xs
|
|
-- l = do
|
|
-- Sel i j _ <- msel
|
|
-- f i j sss
|
|
|
|
ssSetCursor ::
|
|
(IMSS a -> Maybe (Int, Int, SelectionItem a)) ->
|
|
IMSS a ->
|
|
Maybe Selection ->
|
|
Maybe Selection
|
|
ssSetCursor f sss msel = fromMaybe msel $ do
|
|
(i, j, _) <- f sss
|
|
let newxs = fromMaybe mempty $ do
|
|
Sel k _ xs <- msel
|
|
guard $ k == i && j `IS.member` xs
|
|
return xs
|
|
return $ Just (Sel i j newxs)
|
|
|
|
ssLookupMax :: IMSS a -> Maybe (Int, Int, SelectionItem a)
|
|
ssLookupMax sss = do
|
|
(i, _) <- IM.lookupMax sss
|
|
ssLookupLE' i sss
|
|
|
|
ssLookupUp :: Int -> Int -> IMSS a -> Maybe (Int, Int, SelectionItem a)
|
|
ssLookupUp i j sss = case ssLookupLT i j sss of
|
|
Nothing -> ssLookupMax sss
|
|
x -> x
|
|
|
|
ssLookupDown :: Int -> Int -> IMSS a -> Maybe (Int, Int, SelectionItem a)
|
|
ssLookupDown i j sss = case ssLookupGT i j sss of
|
|
Nothing -> ssLookupMin sss
|
|
x -> x
|
|
|
|
ssLookupNextMax :: Int -> Int -> IMSS a -> Maybe (Int, Int, SelectionItem a)
|
|
ssLookupNextMax i j sss = case ssLookupGT i j sss of
|
|
Just x@(i', j', _) | i' == i && j' > j -> Just x
|
|
_ -> ssLookupMaxInSection i sss <|> ssLookupDown i j sss
|
|
|
|
ssLookupMaxInSection :: Int -> IMSS a -> Maybe (Int, Int, SelectionItem a)
|
|
ssLookupMaxInSection i sss = do
|
|
ss <- sss ^? ix i . ssItems
|
|
(j, s) <- IM.lookupMax ss
|
|
return (i, j, s)
|
|
|
|
ssLookupLT :: Int -> Int -> IMSS a -> Maybe (Int, Int, SelectionItem a)
|
|
ssLookupLT i j sss = fromMaybe (ssLookupLT' i sss) $ do
|
|
ss <- sss ^? ix i
|
|
(j', si) <- IM.lookupLT j (ss ^. ssItems)
|
|
return $ Just (i, j', si)
|
|
|
|
ssLookupLT' :: Int -> IMSS a -> Maybe (Int, Int, SelectionItem a)
|
|
ssLookupLT' i sss = do
|
|
(i', ss) <- IM.lookupLT i sss
|
|
case IM.lookupMax (ss ^. ssItems) of
|
|
Just (j', si) -> return (i', j', si)
|
|
Nothing -> ssLookupLT' i' sss
|
|
|
|
ssLookupLE' :: Int -> IMSS a -> Maybe (Int, Int, SelectionItem a)
|
|
ssLookupLE' i sss = do
|
|
(i', ss) <- IM.lookupLE i sss
|
|
case IM.lookupMax (ss ^. ssItems) of
|
|
Just (j', si) -> return (i', j', si)
|
|
Nothing -> ssLookupLT' i' sss
|
|
|
|
ssLookupMin :: IMSS a -> Maybe (Int, Int, SelectionItem a)
|
|
ssLookupMin sss = do
|
|
(i, _) <- IM.lookupMin sss
|
|
ssLookupGE' i sss
|
|
|
|
ssLookupGT :: Int -> Int -> IMSS a -> Maybe (Int, Int, SelectionItem a)
|
|
ssLookupGT i j sss = fromMaybe (ssLookupGT' i sss) $ do
|
|
ss <- sss ^? ix i
|
|
(j', si) <- IM.lookupGT j (ss ^. ssItems)
|
|
return $ Just (i, j', si)
|
|
|
|
ssLookupGT' :: Int -> IMSS a -> Maybe (Int, Int, SelectionItem a)
|
|
ssLookupGT' i sss = do
|
|
(i', ss) <- IM.lookupGT i sss
|
|
case IM.lookupMin (ss ^. ssItems) of
|
|
Just (j', si) -> return (i', j', si)
|
|
Nothing -> ssLookupGT' i' sss
|
|
|
|
ssLookupGE' :: Int -> IMSS a -> Maybe (Int, Int, SelectionItem a)
|
|
ssLookupGE' i sss = do
|
|
(i', ss) <- IM.lookupGE i sss
|
|
case IM.lookupMin (ss ^. ssItems) of
|
|
Just (j', si) -> return (i', j', si)
|
|
Nothing -> ssLookupGT' i' sss
|
|
|
|
selSecSelSize :: Int -> Int -> IMSS a -> Maybe Int
|
|
selSecSelSize i j = (^? ix i . ssItems . ix j . siHeight)
|
|
|
|
-- need to check that the vertical gap is correctly put in here
|
|
posSelSecYint :: Config -> LDParams -> Float -> Int
|
|
posSelSecYint cfig ldp y = floor $ (y0 - y) / (20 / ldp ^. ldpScale + ldp ^. ldpVerticalGap)
|
|
where
|
|
V2 _ y0 = screenPosAbs cfig (ldp ^. ldpPos)
|
|
|
|
selSecYint :: Int -> Int -> IMSS a -> Maybe Int
|
|
selSecYint i j sss = do
|
|
ss <- sss ^? ix i
|
|
return
|
|
. (secpos +)
|
|
. subtract (ss ^. ssOffset)
|
|
. sum
|
|
. fmap _siHeight
|
|
. fst
|
|
$ IM.split j (ss ^. ssItems)
|
|
where
|
|
secpos = sum . fmap _ssShownLength . fst $ IM.split i sss
|
|
|
|
inverseSelSecYint :: Int -> IMSS a -> XInfinity (Int, Int)
|
|
inverseSelSecYint yint sss
|
|
| yint < 0 = NegInf
|
|
| otherwise = fromMaybe PosInf $ do
|
|
((i, ss), othersss) <- IM.minViewWithKey sss
|
|
let l = _ssShownLength ss
|
|
if l <= yint
|
|
then return $ inverseSelSecYint (yint - l) othersss
|
|
else do
|
|
let ls = L.postscan (L.premap _siHeight L.sum) (_ssItems ss)
|
|
(j, _) <- L.fold (L.find (\(_, x) -> x - _ssOffset ss > yint)) $ IM.toList ls
|
|
return $ NonInf (i, j)
|
|
|
|
inverseSelSecYintXPosCheck ::
|
|
Config -> LDParams -> Float -> Int -> IMSS a -> Maybe (XInfinity (Int, Int))
|
|
inverseSelSecYintXPosCheck cfig ldp x yint sss = do
|
|
let sel = inverseSelSecYint yint sss
|
|
(i,j) <- case sel of
|
|
NonInf v -> Just v
|
|
NegInf -> do
|
|
(i',j',_) <- ssLookupMin sss
|
|
return (i',j')
|
|
PosInf -> do
|
|
(i',j',_) <- ssLookupMax sss
|
|
return (i',j')
|
|
let V2 x0 _ = screenPosAbs cfig (ldp ^. ldpPos)
|
|
sindent <- sss ^? ix i . ssIndent
|
|
itindent <- sss ^? ix i . ssItems . ix j . siOffX
|
|
let x1 = x0 + _ldpScale ldp * 10 * (fromIntegral (sindent + itindent) - 0.5)
|
|
guard $ x - x1 < 160 && x > x1
|
|
return sel
|
|
|
|
inverseSelNumPos :: Config -> LDParams -> Point2 -> IMSS a -> Maybe (XInfinity (Int, Int))
|
|
inverseSelNumPos cfig ldp (V2 x y) =
|
|
inverseSelSecYintXPosCheck cfig ldp x (posSelSecYint cfig ldp y)
|