Add sizeReq field to WidgetInstance; update preferredSize/resize to use it

This commit is contained in:
Francisco Vallarino 2020-08-12 15:52:54 -03:00
parent 4ab4b4596b
commit 3398ca332b
17 changed files with 111 additions and 104 deletions

View File

@ -40,6 +40,5 @@ resizeWidget
resizeWidget wenv windowSize widgetRoot = newRoot where
Size w h = windowSize
assigned = Rect 0 0 w h
widget = _wiWidget widgetRoot
preferredSize = widgetPreferredSize widget wenv widgetRoot
newRoot = widgetResize widget wenv assigned assigned preferredSize widgetRoot
instReqs = widgetPreferredSize (_wiWidget widgetRoot) wenv widgetRoot
newRoot = widgetResize (_wiWidget instReqs) wenv assigned assigned instReqs

View File

@ -272,12 +272,11 @@ type ContainerPreferredSizeHandler s e
= WidgetEnv s e
-> WidgetInstance s e
-> Seq (WidgetInstance s e)
-> Seq (Tree SizeReq)
-> Tree SizeReq
-> SizeReq
defaultPreferredSize :: ContainerPreferredSizeHandler s e
defaultPreferredSize wenv widgetInst children reqs = Node current reqs where
current = SizeReq {
defaultPreferredSize wenv inst children = req where
req = SizeReq {
_srSize = Size 0 0,
_srPolicyWidth = FlexibleSize,
_srPolicyHeight = FlexibleSize
@ -287,13 +286,16 @@ containerPreferredSize
:: ContainerPreferredSizeHandler s e
-> WidgetEnv s e
-> WidgetInstance s e
-> Tree SizeReq
containerPreferredSize psHandler wenv widgetInst = preferredSize where
-> WidgetInstance s e
containerPreferredSize psHandler wenv widgetInst = newInst where
children = _wiChildren widgetInst
childrenReqs = fmap updateChild children
updateChild child = Node (updateSizeReq req child) reqs where
Node req reqs = widgetPreferredSize (_wiWidget child) wenv child
preferredSize = psHandler wenv widgetInst children childrenReqs
updateChild child = widgetPreferredSize (_wiWidget child) wenv child
newChildren = fmap updateChild children
sizeReq = psHandler wenv widgetInst newChildren
newInst = widgetInst {
_wiChildren = newChildren,
_wiSizeReq = sizeReq
}
-- | Resize
type ContainerResizeHandler s e
@ -301,13 +303,12 @@ type ContainerResizeHandler s e
-> Rect
-> Rect
-> Seq (WidgetInstance s e)
-> Seq (Tree SizeReq)
-> WidgetInstance s e
-> (WidgetInstance s e, Seq (Rect, Rect))
defaultResize :: ContainerResizeHandler s e
defaultResize wenv viewport renderArea children reqs widgetInst = newSize where
childrenSizes = Seq.replicate (Seq.length reqs) (def, def)
defaultResize wenv viewport renderArea children widgetInst = newSize where
childrenSizes = Seq.replicate (Seq.length children) def
newSize = (widgetInst, childrenSizes)
containerResize
@ -315,19 +316,13 @@ containerResize
-> WidgetEnv s e
-> Rect
-> Rect
-> Tree SizeReq
-> WidgetInstance s e
-> WidgetInstance s e
containerResize handler wenv viewport renderArea reqs widgetInst = newSize where
containerResize handler wenv viewport renderArea widgetInst = newSize where
children = _wiChildren widgetInst
defReqs = Seq.replicate (Seq.length children) (singleNode def)
curReqs = nodeChildren reqs
childrenReqs = if Seq.null curReqs then defReqs else curReqs
(tempInst, assigned) =
handler wenv viewport renderArea children childrenReqs widgetInst
resizeChild (child, req, (viewport, renderArea)) =
widgetResize (_wiWidget child) wenv viewport renderArea req child
newChildren = resizeChild <$> Seq.zip3 children childrenReqs assigned
(tempInst, assigned) = handler wenv viewport renderArea children widgetInst
resize (child, (vp, ra)) = widgetResize (_wiWidget child) wenv vp ra child
newChildren = resize <$> Seq.zip children assigned
newSize = tempInst {
_wiViewport = viewport,
_wiRenderArea = renderArea,

View File

@ -83,21 +83,16 @@ defaultHandleMessage
-> Maybe (WidgetResult s e)
defaultHandleMessage wenv target message widgetInst = Nothing
defaultPreferredSize :: WidgetEnv s e -> WidgetInstance s e -> Tree SizeReq
defaultPreferredSize wenv widgetInst = singleNode SizeReq {
_srSize = Size 0 0,
_srPolicyWidth = FlexibleSize,
_srPolicyHeight = FlexibleSize
}
defaultPreferredSize :: WidgetEnv s e -> WidgetInstance s e -> WidgetInstance s e
defaultPreferredSize wenv widgetInst = widgetInst
defaultResize
:: WidgetEnv s e
-> Rect
-> Rect
-> Tree SizeReq
-> WidgetInstance s e
-> WidgetInstance s e
defaultResize wenv viewport renderArea reqs widgetInst = widgetInst {
defaultResize wenv viewport renderArea widgetInst = widgetInst {
_wiViewport = viewport,
_wiRenderArea = renderArea
}

View File

@ -99,7 +99,7 @@ createComposite comp state = widget where
widgetFind = compositeFind state,
widgetHandleEvent = compositeHandleEvent comp state,
widgetHandleMessage = compositeHandleMessage comp state,
widgetPreferredSize = compositePreferredSize state,
widgetPreferredSize = compositePreferredSize comp state,
widgetResize = compositeResize comp state,
widgetRender = compositeRender comp state
}
@ -228,15 +228,24 @@ compositeHandleMessage comp state@CompositeState{..} wenv target arg widgetComp
-- Preferred size
compositePreferredSize
:: CompositeState s e
:: (Eq s, Typeable s, Typeable e)
=> Composite s e ep
-> CompositeState s e
-> WidgetEnv sp ep
-> WidgetInstance sp ep
-> Tree SizeReq
compositePreferredSize state wenv _ = preferredSize where
-> WidgetInstance sp ep
compositePreferredSize comp state wenv widgetComp = newComp where
CompositeState{..} = state
widget = _wiWidget _cmpRoot
cwenv = convertWidgetEnv wenv _cmpGlobalKeys _cmpModel
preferredSize = widgetPreferredSize widget cwenv _cmpRoot
newRoot = widgetPreferredSize widget cwenv _cmpRoot
newState = state {
_cmpRoot = newRoot
}
newComp = widgetComp {
_wiWidget = createComposite comp newState,
_wiSizeReq = _wiSizeReq newRoot
}
-- Resize
compositeResize
@ -246,14 +255,13 @@ compositeResize
-> WidgetEnv sp ep
-> Rect
-> Rect
-> Tree SizeReq
-> WidgetInstance sp ep
-> WidgetInstance sp ep
compositeResize comp state wenv newView newArea reqs widgetComp = resized where
compositeResize comp state wenv newView newArea widgetComp = resized where
CompositeState{..} = state
widget = _wiWidget _cmpRoot
cwenv = convertWidgetEnv wenv _cmpGlobalKeys _cmpModel
newRoot = widgetResize widget cwenv newView newArea reqs _cmpRoot
newRoot = widgetResize widget cwenv newView newArea _cmpRoot
newState = state {
_cmpRoot = newRoot
}
@ -361,9 +369,8 @@ resizeResult state wenv result widgetComp = resizedResult where
renderArea = _wiRenderArea widgetComp
cwenv = convertWidgetEnv wenv _cmpGlobalKeys _cmpModel
widgetRoot = _wrWidget result
widget = _wiWidget widgetRoot
newReqs = widgetPreferredSize widget cwenv widgetRoot
newRoot = widgetResize widget cwenv viewport renderArea newReqs widgetRoot
tempRoot = widgetPreferredSize (_wiWidget widgetRoot) cwenv widgetRoot
newRoot = widgetResize (_wiWidget tempRoot) cwenv viewport renderArea tempRoot
resizedResult = result {
_wrWidget = newRoot
}

View File

@ -170,10 +170,10 @@ data Widget s e =
-- Renderer (mainly for text sizing functions)
--
-- Returns: the minimum size desired by the widget
widgetPreferredSize
widgetPreferredSize -- -> widgetUpdateSizeReq
:: WidgetEnv s e
-> WidgetInstance s e
-> Tree SizeReq,
-> WidgetInstance s e,
-- | Resizes the children of this widget
--
-- Vieport assigned to the widget
@ -186,7 +186,6 @@ data Widget s e =
:: WidgetEnv s e
-> Rect
-> Rect
-> Tree SizeReq
-> WidgetInstance s e
-> WidgetInstance s e,
-- | Renders the widget
@ -217,6 +216,8 @@ data WidgetInstance s e =
_wiWidget :: Widget s e,
-- | The children widget, if any
_wiChildren :: Seq (WidgetInstance s e),
-- | The preferred size for the widget
_wiSizeReq :: SizeReq,
-- | Indicates if the widget is enabled for user interaction
_wiEnabled :: !Bool,
-- | Indicates if the widget is visible

View File

@ -29,6 +29,7 @@ defaultWidgetInstance widgetType widget = WidgetInstance {
_wiPath = Seq.empty,
_wiWidget = widget,
_wiChildren = Seq.empty,
_wiSizeReq = def,
_wiEnabled = True,
_wiVisible = True,
_wiFocusable = False,
@ -210,12 +211,11 @@ drawWidgetBg renderer wenv inst = drawBg styleState _styleMargin where
drawBg (Just sst) margin = drawStyledBackground renderer renderArea sst margin
resizeInstance :: WidgetEnv s e -> WidgetInstance s e -> WidgetInstance s e
resizeInstance wenv inst = newInstance where
widget = _wiWidget inst
resizeInstance wenv inst = newInst where
viewport = _wiViewport inst
renderArea = _wiRenderArea inst
reqs = widgetPreferredSize widget wenv inst
newInstance = widgetResize widget wenv viewport renderArea reqs inst
instReqs = widgetPreferredSize (_wiWidget inst) wenv inst
newInst = widgetResize (_wiWidget instReqs) wenv viewport renderArea instReqs
isFocusCandidate :: Path -> WidgetInstance s e -> Bool
isFocusCandidate startFrom widgetInst = isValid where

View File

@ -53,10 +53,13 @@ makeButton config = widget where
result = resultReqsEvents requests events widgetInst
_ -> Nothing
preferredSize wenv widgetInst = singleNode sizeReq where
preferredSize wenv widgetInst = newInst where
Style{..} = _wiStyle widgetInst
size = getTextBounds wenv _styleText (_btnLabel config)
sizeReq = SizeReq size FlexibleSize StrictSize
newInst = widgetInst {
_wiSizeReq = sizeReq
}
render renderer wenv widgetInst@WidgetInstance{..} = do
drawWidgetBg renderer wenv widgetInst

View File

@ -55,9 +55,9 @@ makeContainer config = widget where
| otherwise = Nothing
_ -> Nothing
preferredSize wenv widgetInst children reqs = Node sizeReq reqs where
sizeReq = nodeValue $ Seq.index reqs 0
preferredSize wenv widgetInst children = sizeReq where
sizeReq = _wiSizeReq $ Seq.index children 0
resize wenv viewport renderArea children reqs widgetInst = resized where
resize wenv viewport renderArea children widgetInst = resized where
assignedArea = Seq.singleton (viewport, renderArea)
resized = (widgetInst, assignedArea)

View File

@ -164,16 +164,15 @@ makeDropdown config state = widget where
newEvents = Seq.fromList $ fmap ($ item) (_ddOnChange config)
result = WidgetResult (reqs <> newReqs) (events <> newEvents) newInstance
preferredSize wenv widgetInst children reqs = Node sizeReq reqs where
preferredSize wenv widgetInst children = sizeReq where
Style{..} = _wiStyle widgetInst
size = getTextBounds wenv _styleText (dropdownLabel wenv)
sizeReq = SizeReq size FlexibleSize StrictSize
resize wenv viewport renderArea children reqs widgetInst = resized where
childrenReqs = Seq.zip children reqs
area = case Seq.lookup 0 childrenReqs of
Just (child, reqChild) -> (oViewport, oRenderArea) where
reqHeight = _h . _srSize . nodeValue $ reqChild
resize wenv viewport renderArea children widgetInst = resized where
area = case Seq.lookup 0 children of
Just child -> (oViewport, oRenderArea) where
reqHeight = _h . _srSize . _wiSizeReq $ child
maxHeight = min reqHeight 150
oViewport = viewport {
_ry = _ry viewport + _rh viewport,

View File

@ -33,8 +33,9 @@ makeFixedGrid isHorizontal = widget where
widgetResize = containerResize resize
}
preferredSize wenv widgetInst children reqs = Node reqSize reqs where
(vchildren, vreqs) = visibleChildrenReq children reqs
preferredSize wenv widgetInst children = reqSize where
vchildren = Seq.filter _wiVisible children
vreqs = _wiSizeReq <$> vchildren
reqSize = SizeReq (Size width height) FlexibleSize FlexibleSize
width
| Seq.null vchildren = 0
@ -49,7 +50,7 @@ makeFixedGrid isHorizontal = widget where
| isHorizontal = 1
| otherwise = fromIntegral (length vchildren)
resize wenv viewport renderArea children reqs widgetInst = resized where
resize wenv viewport renderArea children widgetInst = resized where
Rect l t w h = renderArea
vchildren = Seq.filter _wiVisible children
cols = if isHorizontal then length vchildren else 1

View File

@ -23,10 +23,13 @@ makeLabel caption = widget where
widgetRender = render
}
preferredSize wenv widgetInst = singleNode sizeReq where
preferredSize wenv widgetInst = newInst where
Style{..} = _wiStyle widgetInst
size = getTextBounds wenv _styleText caption
sizeReq = SizeReq size FlexibleSize StrictSize
newInst = widgetInst {
_wiSizeReq = sizeReq
}
render renderer wenv widgetInst@WidgetInstance{..} = do
drawWidgetBg renderer wenv widgetInst

View File

@ -192,10 +192,10 @@ makeListView config state = widget where
scrollPath = firstChildPath widgetInst
scrollReq rect = SendMessage scrollPath (ScrollTo rect)
preferredSize wenv widgetInst children reqs = Node sizeReq reqs where
sizeReq = nodeValue $ Seq.index reqs 0
preferredSize wenv widgetInst children = sizeReq where
sizeReq = _wiSizeReq $ Seq.index children 0
resize wenv viewport renderArea children reqs widgetInst = resized where
resize wenv viewport renderArea children widgetInst = resized where
assignedArea = Seq.singleton (viewport, renderArea)
resized = (widgetInst, assignedArea)

View File

@ -44,8 +44,7 @@ data ScrollState = ScrollState {
_sstDragging :: Maybe ActiveBar,
_sstDeltaX :: !Double,
_sstDeltaY :: !Double,
_sstChildSize :: Size,
_sstReqSize :: Tree SizeReq
_sstChildSize :: Size
} deriving (Typeable)
newtype ScrollMessage
@ -82,8 +81,7 @@ defaultState = ScrollState {
_sstDragging = Nothing,
_sstDeltaX = 0,
_sstDeltaY = 0,
_sstChildSize = def,
_sstReqSize = singleNode def
_sstChildSize = def
}
scroll :: WidgetInstance s e -> WidgetInstance s e
@ -110,7 +108,7 @@ makeScroll config state = widget where
widgetRender = render
}
ScrollState dragging dx dy cs prevReqs = state
ScrollState dragging dx dy cs = state
Size childWidth childHeight = cs
merge wenv oldState widgetInst = resultWidget newInstance where
@ -151,14 +149,14 @@ makeScroll config state = widget where
| otherwise = Nothing
Move point -> result where
drag bar = updateScrollThumb state bar point viewport sctx
makeWidget state = rebuildWidget wenv state widgetInst prevReqs
makeWidget state = rebuildWidget wenv state widgetInst
makeResult state = resultReqs [IgnoreChildrenEvents] (makeWidget state)
result = fmap (makeResult . drag) dragging
WheelScroll _ (Point wx wy) wheelDirection -> result where
changedX = wx /= 0 && childWidth > vw
changedY = wy /= 0 && childHeight > vh
needsUpdate = changedX || changedY
makeWidget state = rebuildWidget wenv state widgetInst prevReqs
makeWidget state = rebuildWidget wenv state widgetInst
makeResult state = resultReqs [IgnoreChildrenEvents] (makeWidget state)
wheelRate = _scWheelRate config
result
@ -213,7 +211,7 @@ makeScroll config state = widget where
_sstDeltaX = scrollAxis stepX 0 childWidth vw,
_sstDeltaY = scrollAxis stepY 0 childHeight vh
}
newInstance = rebuildWidget wenv newState widgetInst prevReqs
newInstance = rebuildWidget wenv newState widgetInst
updateScrollThumb state activeBar point viewport sctx = newState where
Point px py = point
@ -234,34 +232,33 @@ makeScroll config state = widget where
_sstDeltaY = newDeltaY
}
rebuildWidget wenv newState widgetInst reqs = newInst where
rebuildWidget wenv newState widgetInst = newInst where
newWidget = makeScroll config newState
tempInst = widgetInst { _wiWidget = newWidget }
widget = _wiViewport tempInst
viewport = _wiViewport tempInst
renderArea = _wiRenderArea tempInst
newInst = scrollResize (Just newWidget) wenv widget renderArea reqs tempInst
newInst = scrollResize (Just newWidget) wenv viewport renderArea tempInst
preferredSize wenv widgetInst children reqs = Node sizeReq reqs where
size = _srSize . nodeValue $ Seq.index reqs 0
preferredSize wenv widgetInst children = sizeReq where
size = _srSize $ _wiSizeReq (Seq.index children 0)
sizeReq = SizeReq size FlexibleSize FlexibleSize
scrollResize uWidget wenv viewport renderArea reqs widgetInst = newInst where
scrollResize uWidget wenv viewport renderArea widgetInst = newInst where
Rect l t w h = renderArea
child = Seq.index (_wiChildren widgetInst) 0
childReq = fromMaybe (singleNode def) (Seq.lookup 0 (nodeChildren reqs))
childReq = _wiSizeReq child
Size childWidth2 childHeight2 = _srSize $ nodeValue childReq
Size childWidth2 childHeight2 = _srSize childReq
areaW = max w childWidth2
areaH = max h childHeight2
cRenderArea = Rect (l + dx) (t + dy) areaW areaH
defWidget = makeScroll config $ state {
_sstChildSize = Size areaW areaH,
_sstReqSize = reqs
_sstChildSize = Size areaW areaH
}
newWidget = fromMaybe defWidget uWidget
cWidget = _wiWidget child
newChild = widgetResize cWidget wenv viewport cRenderArea childReq child
newChild = widgetResize cWidget wenv viewport cRenderArea child
newInst = widgetInst {
_wiViewport = viewport,
@ -308,7 +305,7 @@ makeScroll config state = widget where
scrollStatus
:: ScrollConfig -> WidgetEnv s e -> ScrollState -> Rect -> ScrollContext
scrollStatus config wenv scrollState viewport = ScrollContext{..} where
ScrollState _ dx dy (Size childWidth childHeight) _ = scrollState
ScrollState _ dx dy (Size childWidth childHeight) = scrollState
barThickness = _scBarThickness config
mousePos = _ipsMousePos (_weInputStatus wenv)
vpLeft = _rx viewport

View File

@ -21,6 +21,9 @@ makeSpacer = widget where
widgetPreferredSize = preferredSize
}
preferredSize wenv widgetInst = singleNode sizeReq where
preferredSize wenv widgetInst = newInst where
size = Size defaultSpace defaultSpace
sizeReq = SizeReq size RemainderSize RemainderSize
newInst = widgetInst {
_wiSizeReq = sizeReq
}

View File

@ -34,15 +34,15 @@ makeStack isHorizontal = widget where
widgetResize = containerResize resize
}
preferredSize wenv widgetInst children reqs = Node reqSize reqs where
(_, vreqs) = visibleChildrenReq children reqs
preferredSize wenv widgetInst children = sizeReq where
vreqs = _wiSizeReq <$> Seq.filter _wiVisible children
size = calcPreferredSize vreqs
reqSize = SizeReq size FlexibleSize FlexibleSize
sizeReq = SizeReq size FlexibleSize FlexibleSize
resize wenv viewport renderArea children reqs widgetInst = resized where
resize wenv viewport renderArea children widgetInst = resized where
Rect l t w h = renderArea
childrenPairs = Seq.zip children reqs
(vchildren, vreqs) = visibleChildrenReq children reqs
vchildren = Seq.filter _wiVisible children
vreqs = _wiSizeReq <$> vchildren
mainSize = if isHorizontal then w else h
mainStart = if isHorizontal then l else t
policyFilter policy req = policySelector req == policy
@ -63,17 +63,16 @@ makeStack isHorizontal = widget where
| rExists && (not fExists || fSize <= 0) = rSize / rCount
| otherwise = 0
assignedArea = Seq.zip newViewports newViewports
(newViewports, _) = foldl' foldHelper (Seq.empty, mainStart) childrenPairs
foldHelper (accum, offset) childPair = (newAccum, newOffset) where
newSize = resizeChild renderArea fExtra rUnit offset childPair
(newViewports, _) = foldl' foldHelper (Seq.empty, mainStart) children
foldHelper (accum, offset) child = (newAccum, newOffset) where
newSize = resizeChild renderArea fExtra rUnit offset child
newAccum = accum |> newSize
newOffset = offset + rectSelector newSize
resized = (widgetInst, assignedArea)
resizeChild renderArea fExtra rUnit offset childPair = result where
resizeChild renderArea fExtra rUnit offset child = result where
Rect l t w h = renderArea
childInstance = fst childPair
req = nodeValue $ snd childPair
req = _wiSizeReq child
srSize = _srSize req
emptyRect = Rect l t 0 0
hRect = Rect offset t calcNewSize h
@ -83,7 +82,7 @@ makeStack isHorizontal = widget where
FlexibleSize -> (1 + fExtra) * sizeSelector srSize
RemainderSize -> rUnit
result
| not $ _wiVisible childInstance = emptyRect
| not $ _wiVisible child = emptyRect
| isHorizontal = hRect
| otherwise = vRect

View File

@ -140,10 +140,13 @@ makeTextField config state = widget where
_wiWidget = makeTextField config newState
}
preferredSize wenv widgetInst = singleNode sizeReq where
preferredSize wenv widgetInst = newInst where
Style{..} = _wiStyle widgetInst
size = getTextBounds wenv _styleText currText
sizeReq = SizeReq size FlexibleSize StrictSize
newInst = widgetInst {
_wiSizeReq = sizeReq
}
render renderer wenv widgetInst = do
drawWidgetBg renderer wenv widgetInst

View File

@ -139,6 +139,8 @@
- Pending
- Improve styling options. Handle cases for Normal, Hover, Focused with independent background and border
- Add support for dashed borders
- Make BaseWidget and BaseContainer use a custom type instead of just Widget. Maybe also rename them?
- Fix ListView keyboard navigation
- Create Checkbox
- Create Radio
- Add testing