tinytools-0.1.0.5: src/Potato/Flow/Controller/Manipulator/Layers.hs
{-# OPTIONS_GHC -fno-warn-unused-record-wildcards #-}
{-# LANGUAGE RecordWildCards #-}
module Potato.Flow.Controller.Manipulator.Layers (
LayersHandler(..)
) where
import Relude
import Potato.Flow.Controller.Handler
import Potato.Flow.Controller.Input
import Potato.Flow.Controller.OwlLayers
import Potato.Flow.Controller.Types
import Potato.Flow.Llama
import Potato.Flow.Math
import Potato.Flow.Owl
import Potato.Flow.OwlItem
import Potato.Flow.OwlState
import Potato.Flow.OwlWorkspace
import Potato.Flow.Serialization.Snake
import Potato.Flow.Types
import Potato.Flow.Preview
import Data.Char
import Data.Default
import Data.Dependent.Sum (DSum ((:=>)))
import qualified Data.IntMap as IM
import Data.Sequence ((<|))
import qualified Data.Sequence as Seq
import qualified Data.Text as T
import qualified Potato.Data.Text.Zipper as TZ
data LayerDragState = LDS_None | LDS_Dragging | LDS_Selecting LayerEntryPos | LDS_Option LayerDownType deriving (Show, Eq)
data LayerDownType = LDT_Hide | LDT_Lock | LDT_Collapse | LDT_Normal deriving (Show, Eq)
layersHandlerRenderEntry_selected :: LayersHandlerRenderEntry -> Bool
layersHandlerRenderEntry_selected (LayersHandlerRenderEntryNormal LHRESS_Selected _ _ _) = True
layersHandlerRenderEntry_selected (LayersHandlerRenderEntryNormal LHRESS_InheritSelected _ _ _) = True
layersHandlerRenderEntry_selected _ = False
-- TODO we could probably change this to do a more efficient binary search based on position in hierarchy
doesSelectionContainREltId_linear :: REltId -> Selection -> Bool
doesSelectionContainREltId_linear rid = isJust . find (\sowl -> rid == _superOwl_id sowl) . unSuperOwlParliament
collapseOffset :: Int
collapseOffset = 0
hideOffset :: Int
hideOffset = 1
lockOffset :: Int
lockOffset = 2
titleOffset :: Int
titleOffset = 3
clickLayerNew :: Seq LayerEntry -> XY -> Maybe (SuperOwl, LayerDownType, Int)
clickLayerNew lentries (V2 absx lepos) = case Seq.lookup lepos lentries of
Nothing -> Nothing
Just le -> Just . (,,absx - layerEntry_depth le) sowl $ case () of
() | layerEntry_isFolder le && layerEntry_depth le + collapseOffset == absx -> LDT_Collapse
() | layerEntry_depth le + hideOffset == absx -> LDT_Hide
() | layerEntry_depth le + lockOffset == absx -> LDT_Lock
() -> LDT_Normal
where
sowl = _layerEntry_superOwl le
data LayersHandler = LayersHandler {
_layersHandler_dragState :: LayerDragState
, _layersHandler_cursorPos :: XY
, _layersHandler_dropSpot :: Maybe OwlSpot
}
instance Default LayersHandler where
def = LayersHandler {
_layersHandler_dragState = LDS_None
, _layersHandler_cursorPos = 0
, _layersHandler_dropSpot = Nothing
}
handleScroll :: (PotatoHandler h) => h -> PotatoHandlerInput -> Int -> PotatoHandlerOutput
handleScroll h PotatoHandlerInput {..} scroll = r where
-- TODO share this code with other handler
scrollPos = _layersState_scrollPos _potatoHandlerInput_layersState
maxentries = 10 + (Seq.length $ _layersState_entries _potatoHandlerInput_layersState)
newScrollPos = max 0 (min maxentries (scrollPos + scroll))
r = def {
_potatoHandlerOutput_nextHandler = Just $ SomePotatoHandler h
-- TODO clamp based on number of entries
, _potatoHandlerOutput_action = HOA_Layers (_potatoHandlerInput_layersState { _layersState_scrollPos = newScrollPos}) IM.empty
}
resetLayersHandler :: LayersHandler -> LayersHandler
resetLayersHandler lh = lh {
_layersHandler_dragState = LDS_None
, _layersHandler_dropSpot = Nothing
}
--TODO need to reorder so it becomes undo friendly here I think? (uhh, pretty sure it's ok to delete this TODO? should be ordered by assumption)
-- TODO assert elts are valid
moveEltLlama :: OwlPFState -> (OwlSpot, OwlParliament) -> Llama
moveEltLlama pfs (ospot, op) = makePFCLlama $ OwlPFCMove (ospot, owlParliament_toSuperOwlParliament (_owlPFState_owlTree pfs) op)
-- spot is invalid if it's a descendent of a already selected element
isSpotValidToDrop :: OwlTree -> Selection -> OwlSpot -> Bool
isSpotValidToDrop ot sel spot = not $ owlParliamentSet_descendent ot (_owlSpot_parent spot) (superOwlParliament_toOwlParliamentSet sel)
instance PotatoHandler LayersHandler where
pHandlerName LayersHandler {..} = handlerName_layers <> " " <> show _layersHandler_dragState
-- we incorrectly reuse RelMouseDrag for LayersHandler even though LayersHandler doesn't care about canvas pan coords
-- pan offset should always be set to 0 in RelMouseDrag
pHandleMouse lh@LayersHandler {..} PotatoHandlerInput {..} (RelMouseDrag MouseDrag {..}) = let
selection = _potatoHandlerInput_selection
ls@(LayersState _ lentries scrollPos) = _potatoHandlerInput_layersState
pfs = _potatoHandlerInput_pFState
owltree = (_owlPFState_owlTree pfs)
V2 rawxoffset rawlepos = _mouseDrag_to
leposxy@(V2 _ lepos) = V2 rawxoffset (rawlepos + scrollPos)
in case (_mouseDrag_state, _layersHandler_dragState) of
(MouseDragState_Down, LDS_None) -> r where
shift = elem KeyModifier_Shift _mouseDrag_modifiers
(nextDragState, mNextLayerState, changes) = case clickLayerNew lentries leposxy of
Nothing -> (LDS_None, Nothing, IM.empty)
-- (you can only click + drag selected elements)
Just (downsowl, ldtdown, _) -> case ldtdown of
LDT_Normal -> if shift || (not $ doesSelectionContainREltId_linear (_superOwl_id downsowl) selection)
-- TODO check if element is descendent of selected element and return LDS_None if so
-- if element wasn't selected or shift is held down, enter selection mode
then (LDS_Selecting lepos, Nothing, IM.empty)
else (LDS_Dragging, Nothing, IM.empty)
-- DELETE
-- this variant denies selecting children of selected parents but not the other way around...
-- maybe easier to deny this at a higher level rather than here.
{-
LDT_Normal -> if shift
then if exclusivedescendent
-- element is descendent of selection and therefore do not allow selecting
then (LDS_None, Nothing, IM.empty)
else (LDS_Selecting lepos, Nothing, IM.empty)
else if not isselected
then if exclusivedescendent
-- element is descendent of selection and therefore do not allow selecting (TODO consider alternatively, enter dragging mode)
then (LDS_None, Nothing, IM.empty)
-- enter selection mode
else (LDS_Selecting lepos, Nothing, IM.empty)
-- entry dragging mode
else (LDS_Dragging, Nothing, IM.empty)
where
rid = _superOwl_id downsowl
selectionset = superOwlParliament_toOwlParliamentSet selection
isselected = owlParliamentSet_member rid selectionset
exclusivedescendent = owlParliamentSet_descendent owltree rid selectionset && not isselected
-}
LDT_Hide -> r' where
nextLayersState = toggleLayerEntry pfs ls lepos LHCO_ToggleHide
hideChanges = changesFromToggleHide pfs nextLayersState lepos
r' = (LDS_Option LDT_Hide, Just $ nextLayersState, hideChanges)
LDT_Lock -> (LDS_Option LDT_Lock, Just $ toggleLayerEntry pfs ls lepos LHCO_ToggleLock, IM.empty)
LDT_Collapse -> (LDS_Option LDT_Collapse, Just $ toggleLayerEntry pfs ls lepos LHCO_ToggleCollapse, IM.empty)
r = Just $ def {
_potatoHandlerOutput_nextHandler = Just $ SomePotatoHandler lh {
_layersHandler_dragState = nextDragState
, _layersHandler_cursorPos = _mouseDrag_to
, _layersHandler_dropSpot = Nothing
}
, _potatoHandlerOutput_action = case mNextLayerState of
Nothing -> HOA_Nothing
Just nextLayersState -> HOA_Layers nextLayersState changes
}
(MouseDragState_Down, _) -> error "unexpected, _layersHandler_dragState should have been reset on last mouse up"
(MouseDragState_Dragging, LDS_Dragging) -> r where
-- we will always place between dropSowl and justAboveDropSowl
mDropSowlWithOffset = do
(downsowl, _, offset') <- clickLayerNew lentries leposxy
return (downsowl, offset')
mJustAboveDropSowl = do
lentry <- case mDropSowlWithOffset of
Nothing -> Seq.lookup (Seq.length lentries - 1) lentries
Just _ -> Seq.lookup (lepos-1) lentries
return $ _layerEntry_superOwl lentry
nparentoffset = case mDropSowlWithOffset of
Nothing -> case mJustAboveDropSowl of
Nothing -> error "this should never happen"
-- we are at the very bottom
Just asowl -> rawxoffset - superOwl_depth asowl
Just (dsowl, x) -> case mJustAboveDropSowl of
-- we are at the very top
Nothing -> 0
-- limit how deep in the hierarchy we can move based on what's below the cursor
Just asowl -> max x (superOwl_depth dsowl - superOwl_depth asowl)
nsibling = max 0 (- (min 0 nparentoffset))
targetspot = case mJustAboveDropSowl of
-- we are dropping at the top of our LayerEntries
Nothing -> OwlSpot noOwl Nothing
Just asowl -> if nparentoffset > 0 && hasOwlItem_isFolder asowl
-- drop inside at the top
then OwlSpot (_superOwl_id asowl) Nothing
else case owlTree_findSuperOwl owltree newsiblingid of
Nothing -> OwlSpot noOwl siblingout
Just newsibling -> OwlSpot (superOwl_parentId newsibling) siblingout
where
newsiblingid = owlTree_superOwlNthParentId owltree asowl nsibling
siblingout = case newsiblingid of
x | x == noOwl -> Nothing
x -> Just x
-- check if spot is valid
-- instead we do this check when we drop instead, that behavior "felt" nicer to me even though this is probably more correct
--SuperOwlParliament selectedsowls = _potatoHandlerInput_selection
--isSpotValid = isSpotValidToDrop owltree _potatoHandlerInput_selection spot
isSpotValid = True
r = Just $ def {
_potatoHandlerOutput_nextHandler = Just $ SomePotatoHandler lh {
_layersHandler_cursorPos = _mouseDrag_to
, _layersHandler_dropSpot = if isSpotValid then Just targetspot else Nothing
}
}
-- TODO someday do drag for multi-select here
(MouseDragState_Dragging, _) -> Just $ def {
_potatoHandlerOutput_nextHandler = Just $ SomePotatoHandler lh {
_layersHandler_cursorPos = _mouseDrag_to
, _layersHandler_dropSpot = Nothing
}
}
(MouseDragState_Up, LDS_Selecting leposdown) -> r where
shift = elem KeyModifier_Shift _mouseDrag_modifiers
sowl = _layerEntry_superOwl $ Seq.index lentries leposdown
r = Just $ def {
_potatoHandlerOutput_nextHandler = Just $ SomePotatoHandler (resetLayersHandler lh)
, _potatoHandlerOutput_action = HOA_Select shift (SuperOwlParliament $ Seq.singleton sowl)
}
-- NOTE this will not work on inherit selected children, feature or bug??
-- we clicked and released on a selected element, enter renaming mode
(MouseDragState_Up, LDS_Dragging) | isNothing _layersHandler_dropSpot -> case clickLayerNew lentries leposxy of
Nothing -> error "pretty sure this should never happen "
-- (you can only click + drag selected elements)
Just (downsowl, ldtdown, offset) -> case ldtdown of
LDT_Normal | offset >= titleOffset -> r where
-- TODO great place for TZ.selectAll when you add selection capability into TZ
zipper = TZ.fromText $ hasOwlItem_name downsowl
r = Just $ setHandlerOnly LayersRenameHandler {
_layersRenameHandler_original = resetLayersHandler lh
, _layersRenameHandler_renaming = downsowl
, _layersRenameHandler_index = lepos
, _layersRenameHandler_zipper = zipper
}
_ -> Just $ setHandlerOnly (resetLayersHandler lh)
-- TODO when we have multi-user mode, we'll want to test if the target drop space is still valid
(MouseDragState_Up, LDS_Dragging) -> r where
mllama = do
spot <- _layersHandler_dropSpot
let
isSpotValid = isSpotValidToDrop owltree _potatoHandlerInput_selection spot
-- TODO modify if we drag on top of existing elt... Is there anything to do here? I can't remember why I added this comment. Pretty sure there's nothing to do
modifiedSpot = spot
guard isSpotValid
return $ moveEltLlama pfs (modifiedSpot, superOwlParliament_toOwlParliament selection)
r = Just $ def {
_potatoHandlerOutput_nextHandler = Just $ SomePotatoHandler (resetLayersHandler lh)
, _potatoHandlerOutput_action = maybe HOA_Nothing (HOA_Preview . Preview PO_StartAndCommit) mllama
}
(MouseDragState_Up, LDS_Option _) -> Just $ def {
_potatoHandlerOutput_nextHandler = Just $ SomePotatoHandler (resetLayersHandler lh)
}
(MouseDragState_Up, LDS_None) -> Just $ def {
_potatoHandlerOutput_nextHandler = Just $ SomePotatoHandler (resetLayersHandler lh)
-- deselect everything
, _potatoHandlerOutput_action = HOA_Select False isParliament_empty
}
(MouseDragState_Cancelled, _) -> Just $ setHandlerOnly (resetLayersHandler lh)
pHandleKeyboard lh phi kbd = case kbd of
KeyboardData (KeyboardKey_Scroll scroll) _ -> Just $ handleScroll lh phi scroll
_ -> Nothing
--pRenderHandler lh@LayersHandler {..} PotatoHandlerInput {..} = emptyHandlerRenderOutput
pIsHandlerActive LayersHandler {..} = if _layersHandler_dragState /= LDS_None then HAS_Active_Mouse else HAS_Inactive
-- TODO this is incorrect, we may be in the middle of dragging elements that got deleted
pRefreshHandler h _ = Just $ SomePotatoHandler h
-- TODO generate LHRESS_ChildSelected
pRenderLayersHandler LayersHandler {..} PotatoHandlerInput {..} = LayersViewHandlerRenderOutput newlentries where
selection = _potatoHandlerInput_selection
LayersState _ lentries _ = _potatoHandlerInput_layersState
--pfs = _potatoHandlerInput_pFState
--owltree = (_owlPFState_owlTree pfs)
-- TODO would also be best to cache this in LayerState since it's also used by other operations...
selectionset = superOwlParliament_toOwlParliamentSet selection
isSelected lentry = owlParliamentSet_member (layerEntry_rEltId lentry) selectionset
-- perhaps linear search is faster for smaller sets though
--isSelected lentry = doesSelectionContainREltId_linear (_superOwl_id $ _layerEntry_superOwl lentry) selection
-- update the selected state
mapaccumlfn_forselection mseldepth lentry = case mseldepth of
Nothing -> normalcase
Just x -> if layerEntry_depth lentry > x
then (mseldepth, makelentry LHRESS_InheritSelected)
else normalcase
where
-- dot depth will be filled in later
makelentry x = LayersHandlerRenderEntryNormal x Nothing Nothing lentry
normalcase = if isSelected lentry
then (Just (layerEntry_depth lentry), makelentry LHRESS_Selected)
else (Nothing, makelentry LHRESS_None)
(_,newlentries1) = mapAccumL mapaccumlfn_forselection Nothing lentries
-- next insert the drop spot
newlentries2 = case _layersHandler_dropSpot of
Nothing -> newlentries1
Just ds -> r where
(mleftmost, samelevel) = case _owlSpot_parent ds of
x | x == noOwl -> (maybe Nothing Just (_owlSpot_leftSibling ds), True)
x -> case _owlSpot_leftSibling ds of
Nothing -> (Just x, False)
Just s -> (Just s, True)
r = case mleftmost of
Nothing -> LayersHandlerRenderEntryDummy 0 <| newlentries1
Just leftmostid -> r' where
-- TODO you could probably do this more efficiently with a very bespoke fold but whatever
(index, depth) = case Seq.findIndexL (\lentry -> _superOwl_id (_layerEntry_superOwl lentry) == leftmostid) lentries of
Nothing -> error $ "expected to find id " <> show leftmostid <> " in " <> show lentries
Just x -> (skipped, depth') where
depth' = layerEntry_depth (Seq.index lentries x) + (if samelevel then 0 else 1)
noskiplentries = Seq.drop (x+1) $ lentries
skippedlentries = Seq.takeWhileL (\lentry -> layerEntry_depth lentry > depth') $ noskiplentries
skipped = if samelevel then x + 1 + Seq.length skippedlentries else x+1
r' = Seq.insertAt index (LayersHandlerRenderEntryDummy depth) newlentries1
-- finally add the dots indicating drop spot depth
mapaccumrfn_fordots mdropdepth lhre = case mdropdepth of
Nothing -> case lhre of
LayersHandlerRenderEntryDummy d -> (Just d, lhre)
_ -> (mdropdepth, lhre)
Just x -> case lhre of
LayersHandlerRenderEntryNormal s _ _ lentry -> if layerEntry_depth lentry >= x
then (mdropdepth, LayersHandlerRenderEntryNormal s (Just x) Nothing lentry)
else (Nothing, lhre)
_ -> error "unexpected LayersHandlerRenderEntryDummy"
(_, newlentries3) = mapAccumR mapaccumrfn_fordots Nothing newlentries2
-- determine parents of selection
mapaccumrfn_forchildselected (selstack, lastdepth) lhre = ((newstack, depth), newlhre) where
selected = layersHandlerRenderEntry_selected lhre
depth = layersHandlerRenderEntry_depth lhre
(childSelected, newstack) = if depth > lastdepth
then (False, selected:selstack)
else if selected
then case selstack of
[] -> (False, [True]) -- this happens if on the first element that we mapAccumR on
_:xs -> (False, True:xs)
else if depth < lastdepth
then case selstack of
[] -> error "this should never happen"
x1:xs1 -> case xs1 of
[] -> (x1, [x1])
x2:xs2 -> (x1 && not x2, (x1 || x2) : xs2)
else (False, selstack)
newlhre = if childSelected
then case lhre of
LayersHandlerRenderEntryNormal _ mdots renaming lentry -> LayersHandlerRenderEntryNormal LHRESS_ChildSelected mdots renaming lentry
x -> x
else lhre
(_, newlentries) = mapAccumR mapaccumrfn_forchildselected ([], 0) newlentries3
data LayersRenameHandler = LayersRenameHandler {
_layersRenameHandler_original :: LayersHandler
, _layersRenameHandler_renaming :: SuperOwl
, _layersRenameHandler_index :: Int -- LayerEntries index of what we are renaming
, _layersRenameHandler_zipper :: TZ.TextZipper
}
isValidLayerRenameChar :: Char -> Bool
isValidLayerRenameChar c = case c of
_ | isControl c -> False
' ' -> True -- only allow ' ' for whitespace character
_ | isSpace c -> False
_ -> True
renameTextZipperTransform :: KeyboardKey -> Maybe (TZ.TextZipper -> TZ.TextZipper)
renameTextZipperTransform = \case
KeyboardKey_Space -> Just $ TZ.insertChar ' '
KeyboardKey_Char k | isValidLayerRenameChar k -> Just $ TZ.insertChar k
KeyboardKey_Backspace -> Just $ TZ.deleteLeft
KeyboardKey_Delete -> Just $ TZ.deleteRight
KeyboardKey_Left -> Just $ TZ.left
KeyboardKey_Right -> Just $ TZ.right
KeyboardKey_Home -> Just $ TZ.home
KeyboardKey_End -> Just $ TZ.end
KeyboardKey_Paste t | T.all isValidLayerRenameChar t -> Just $ TZ.insert t
_ -> Nothing
renameToAndReturn :: LayersRenameHandler -> Text -> PotatoHandlerOutput
renameToAndReturn LayersRenameHandler {..} newName = r where
controller = CTagRename :=> (Identity $ CRename {
_cRename_deltaLabel = (hasOwlItem_name _layersRenameHandler_renaming, newName)
})
r = def {
_potatoHandlerOutput_nextHandler = Just $ SomePotatoHandler _layersRenameHandler_original
, _potatoHandlerOutput_action = HOA_Preview $ Preview PO_StartAndCommit $ makePFCLlama . OwlPFCManipulate $ IM.fromList [(_superOwl_id _layersRenameHandler_renaming,controller)]
}
toDisplayLines :: LayersRenameHandler -> TZ.DisplayLines ()
toDisplayLines LayersRenameHandler {..} = TZ.displayLinesWithAlignment TZ.TextAlignment_Left 1000 () () _layersRenameHandler_zipper
-- TODO this should be configurable
-- hardcoded offset to the <elt name> e.g. " ea 𐂂 <elt name>"
layerJunkOffset :: Int
layerJunkOffset = 7
-- TODO confirm/cancel if click off the one we are renaming, cancle handler and pass input onto the replacement (see TODO in GoatWidget)
instance PotatoHandler LayersRenameHandler where
pHandlerName _ = handlerName_layersRename
-- we incorrectly reuse RelMouseDrag for LayersHandler even though LayersHandler doesn't care about canvas pan coords
-- pan offset should always be set to 0 in RelMouseDrag
pHandleMouse lh@LayersRenameHandler {..} phi@PotatoHandlerInput {..} rmd@(RelMouseDrag MouseDrag {..}) = let
LayersState _ lentries scrollPos = _potatoHandlerInput_layersState
V2 rawxoffset rawlepos = _mouseDrag_to
leposxy@(V2 _ lepos) = V2 rawxoffset (rawlepos + scrollPos)
renaminglepos = _layersRenameHandler_index
in case _mouseDrag_state of
MouseDragState_Down | lepos == renaminglepos -> r where
xpos = case clickLayerNew lentries leposxy of
Nothing -> error "this should never happen"
Just (_, _, xoff) -> xoff - layerJunkOffset
dl = toDisplayLines lh
nexttz = TZ.goToDisplayLinePosition xpos 0 dl _layersRenameHandler_zipper
r = Just $ def {
_potatoHandlerOutput_nextHandler = Just $ SomePotatoHandler lh {
_layersRenameHandler_zipper = nexttz
}
}
-- TODO drag + select when it's implemented in TZ
MouseDragState_Dragging -> Just $ setHandlerOnly lh
MouseDragState_Up -> Just $ setHandlerOnly lh
_ -> Just r where
-- we want to pass output to original hanler
mpho' = pHandleMouse _layersRenameHandler_original phi rmd
-- but we also want to return a rename event
pho'' = renameToAndReturn lh (TZ.value _layersRenameHandler_zipper)
-- so just do both and sketch combine the results... probably ok...
r = case mpho' of
Nothing -> error "this should never happen..."
Just pho' -> pho' { _potatoHandlerOutput_action = _potatoHandlerOutput_action pho'' }
pHandleKeyboard lh@LayersRenameHandler {..} phi@PotatoHandlerInput {..} kbd = case kbd of
-- don't allow ctrl shortcuts while renaming
KeyboardData _ [KeyModifier_Ctrl] -> Just $ setHandlerOnly lh
KeyboardData KeyboardKey_Return [] -> Just $ renameToAndReturn lh (TZ.value _layersRenameHandler_zipper)
KeyboardData KeyboardKey_Esc [] -> Just $ setHandlerOnly _layersRenameHandler_original
KeyboardData (KeyboardKey_Scroll scroll) _ -> Just $ handleScroll lh phi scroll
KeyboardData key [] -> case renameTextZipperTransform key of
Nothing -> Nothing
Just f -> r where
nexttz = f _layersRenameHandler_zipper
r = Just $ def {
_potatoHandlerOutput_nextHandler = Just $ SomePotatoHandler lh {
_layersRenameHandler_zipper = nexttz
}
}
_ -> Nothing
-- TODO this is incorrect, we may be in the middle of renaming elements that got deleted
pRefreshHandler h _ = Just $ SomePotatoHandler h
-- TODO render renaming stuff (or do we do this in pRenderLayersHandler?)
--pRenderHandler lh@LayersRenameHandler {..} PotatoHandlerInput {..} = emptyHandlerRenderOutput
pIsHandlerActive LayersRenameHandler {..} = HAS_Active_Keyboard
pRenderLayersHandler LayersRenameHandler {..} phi@PotatoHandlerInput {..} = r where
r' = pRenderLayersHandler _layersRenameHandler_original phi
entries' = _layersViewHandlerRenderOutput_entries r'
-- PROBLEM you want to do some hcropping on the zipper but you don't know how much to crop by because width is unknown
-- solution 1: align right
-- solution 2: take over entire row from very left
-- solution 3: ignore, user may need to resize layers area
-- we will just do solution 3 cuz it's easiest
adjustfn (LayersHandlerRenderEntryNormal lhress dots _ lentry) = LayersHandlerRenderEntryNormal lhress dots (Just _layersRenameHandler_zipper) lentry where
adjustfn (LayersHandlerRenderEntryDummy _) = error "this should never happen"
entries = Seq.adjust' adjustfn _layersRenameHandler_index entries'
r = LayersViewHandlerRenderOutput { _layersViewHandlerRenderOutput_entries = entries }