Skip to content

Commit

Permalink
Add containerCreateContainerFromModel to workaround issue when updati…
Browse files Browse the repository at this point in the history
…ng offset during merge
  • Loading branch information
fjvallarino committed Oct 25, 2021
1 parent b219be4 commit 7b397a5
Show file tree
Hide file tree
Showing 3 changed files with 52 additions and 6 deletions.
5 changes: 2 additions & 3 deletions ChangeLog.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,11 @@

- Add `customModelBuilder` in Composite, for custom models support. These can consume information
from the parent model.
- Add `OverlayWrapper` widget.
- Add `ColorPopup` widget. Besides being useful on its own, it serves as an `OverlayWrapper` example.

### Fixed

- Keep old Composite root if model has not changed. This did not affect previous code,
it was only relevant with new features.
it is only relevant with new features.

### Changed

Expand All @@ -19,6 +17,7 @@
- ZStack's `onlyTopActive` now follows the same pattern as other boolean combinators.
- Shortened labels for `ColorPicker`.
- Changed `_weFindByPath` to `_weFindBranchByPath`, now returning the complete branch up to the given path.
- Add `containerCreateContainerFromModel` to workaround issue when updating offset during merge.

## 1.1.1.0

Expand Down
43 changes: 41 additions & 2 deletions src/Monomer/Widgets/Container.hs
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,32 @@ type ContainerGetCurrentStyle s e
-> WidgetNode s e -- ^ The widget node.
-> StyleState -- ^ The active style for the node.

{-|
Returns an updated version of the Container instance. Currently only used
during merge. Not needed in general, except for widgets that modify offset
or layout direction.
An example can be found in "Monomer.Widgets.Containers.Scroll".
Note:
Some widgets, scroll for example, provide offset/layout direction to the
Container instance; this information is passed down to children widgets in all
the lifecycle methods. During merge a problem arises: the new node has not yet
processed the old state and, since it is the Container whose merge function is
being invoked, it is not able to provide the correct offset/layout direction.
It is also not possible to directly extract this information from the old node,
because we have a Widget instance and not its Container instance. This function
provides a workaround for this.
This is a hacky solution; a more flexible dispatcher for Composite could avoid it.
-}
type ContainerCreateContainerFromModel s e a
= WidgetEnv s e -- ^ The widget environment.
-> WidgetNode s e -- ^ The widget node.
-> a -- ^ The previous model.
-> Maybe (Container s e a) -- ^ An updated Container instance.

{-|
Updates the widget environment before passing it down to children. This function
is called during the execution of all the widget functions. Useful for
Expand Down Expand Up @@ -353,6 +379,8 @@ data Container s e a = Container {
containerUseScissor :: Bool,
-- | Returns the base style for this type of widget.
containerGetBaseStyle :: ContainerGetBaseStyle s e,
-- | Returns an updated version of the Container instance.
containerCreateContainerFromModel :: ContainerCreateContainerFromModel s e a,
-- | Returns the current style, depending on the status of the widget.
containerGetCurrentStyle :: ContainerGetCurrentStyle s e,
-- | Updates the widget environment before passing it down to children.
Expand Down Expand Up @@ -403,6 +431,7 @@ instance Default (Container s e a) where
containerUseScissor = False,
containerGetBaseStyle = defaultGetBaseStyle,
containerGetCurrentStyle = defaultGetCurrentStyle,
containerCreateContainerFromModel = defaultCreateContainerFromModel,
containerUpdateCWenv = defaultUpdateCWenv,
containerInit = defaultInit,
containerInitPost = defaultInitPost,
Expand Down Expand Up @@ -461,6 +490,9 @@ defaultGetBaseStyle wenv node = Nothing
defaultGetCurrentStyle :: ContainerGetCurrentStyle s e
defaultGetCurrentStyle wenv node = currentStyle wenv node

defaultCreateContainerFromModel :: ContainerCreateContainerFromModel s e a
defaultCreateContainerFromModel wenv node state = Nothing

defaultUpdateCWenv :: ContainerUpdateCWenvHandler s e
defaultUpdateCWenv wenv node cnode cidx = wenv

Expand Down Expand Up @@ -571,7 +603,8 @@ mergeWrapper
-> WidgetResult s e
mergeWrapper container wenv newNode oldNode = newResult where
getBaseStyle = containerGetBaseStyle container
updateCWenv = getUpdateCWenv container
createContainerFromModel = containerCreateContainerFromModel container

mergeRequiredHandler = containerMergeChildrenReq container
mergeHandler = containerMerge container
mergePostHandler = containerMergePost container
Expand All @@ -582,8 +615,14 @@ mergeWrapper container wenv newNode oldNode = newResult where
Nothing -> True

styledNode = initNodeStyle getBaseStyle wenv newNode

-- Check if an updated container can be used for offset/layout direction.
pNode = pResult ^. L.node
updateCWenv = case useState oldState >>= createContainerFromModel wenv pNode of
Just newContainer -> getUpdateCWenv newContainer
_ -> getUpdateCWenv container
cWenvHelper idx child = cwenv where
cwenv = updateCWenv wenv (pResult ^. L.node) child idx
cwenv = updateCWenv wenv pNode child idx

pResult = mergeParent mergeHandler wenv styledNode oldNode oldState
cResult = mergeChildren cWenvHelper wenv newNode oldNode pResult
Expand Down
10 changes: 9 additions & 1 deletion src/Monomer/Widgets/Containers/Scroll.hs
Original file line number Diff line number Diff line change
Expand Up @@ -344,12 +344,13 @@ makeNode widget managedWidget = defaultWidgetNode "scroll" widget

makeScroll :: ScrollCfg s e -> ScrollState -> Widget s e
makeScroll config state = widget where
widget = createContainer state def {
container = def {
containerChildrenOffset = Just offset,
containerChildrenScissor = Just (_sstScissor state),
containerLayoutDirection = layoutDirection,
containerGetBaseStyle = getBaseStyle,
containerGetCurrentStyle = scrollCurrentStyle,
containerCreateContainerFromModel = createContainerFromModel,
containerUpdateCWenv = updateCWenv,
containerInit = init,
containerMerge = merge,
Expand All @@ -360,6 +361,7 @@ makeScroll config state = widget where
containerResize = resize,
containerRenderAfter = renderAfter
}
widget = createContainer state container

ScrollState dragging dx dy _ _ _ = state
Size childWidth childHeight = _sstChildSize state
Expand All @@ -386,6 +388,12 @@ makeScroll config state = widget where
& L.children . ix 0 . L.info . L.style .~ childStyle
| otherwise = node

createContainerFromModel wenv node state = Just newContainer where
offset = Point (_sstDeltaX state) (_sstDeltaX state)
newContainer = container {
containerChildrenOffset = Just offset
}

-- This is overriden to account for space used by scroll bars
updateCWenv wenv node cnode cidx = newWenv where
theme = currentTheme wenv node
Expand Down

0 comments on commit 7b397a5

Please sign in to comment.