Nick
03/10/2023, 4:52 PMPopupManager. Before, you could make custom popups by directly adding items to the Display. This worked in many cases, but had a lot of limitations. For example, Views added this way would be affected by any Layout on the Display, which meant you couldn't control these Popups as easily. Also, new Views added to the Display after a custom popup was shown could overlay the popup. So there was no way to guarantee that a popup remained the top-most View. The new PopupManager fixes these limitations and provides a simple API for showing popups.
Any View Can Be A Popup
The PopupManager's API works with View, so you can make anything a popup. Simply do the following:
popupManager.show(myView) {
it.center eq parent.center
}
// ...
popupManager.hide(myView)
Views that are shown as popups will automatically become top-level (being removed from their existing parent if already displayed) and sit above all other existing Views. Hiding a popup removes it from the Display, but it won't return the View to a previous parent if it had one.
Popup Layouts
Popups are shown with layout information directly. There are two ways to show a popup: relative to the Display, or relative to another View and the Display. There is an API call for each:
Here, myView is positioned with only a "reference" to the Display (parent).
popupManager.show(myView) {
it.center eq parent.center
}
But sometimes a popup needs to be positioned relative to another View. This shows how to place myView so it tracks the bounds of someView. The PopupManager will handle keeping the popup aligned with someView.
// myView is positioned with only a "reference" to the Display (parent)
popupManager.show(myView, relativeTo = someView) { popup, anchor ->
<http://popup.top|popup.top> greaterEq 0 // Popup top-left always visible
popup.left greaterEq 0 // Popup top-left always visible
popup.width.preserve // don't shrink popup
popup.height.preserve // don't shrink popup
(popup.right lessEq parent.right ) .. Strong // stay in parent as long as doesn't compress popup
(popup.bottom lessEq parent.bottom) .. Strong // stay in parent as long as doesn't compress popup
(<http://popup.top|popup.top> eq anchor.bottom + 10) .. Medium // follow anchor, as long as stronger constraints not in conflict
(popup.centerY eq anchor.centerY ) .. Medium // follow anchor, as long as stronger constraints not in conflict
}
More Powerful Text Rendering
Text Alignment
There is a new TextAlignment enum that controls how wrapped text is displayed within its margins. This is a replacement for HorizontalAlignment, which currently uses Left, Right (instead of Start, End) and does not support Justify. You can justify text by doing the following:
canvas.wrapped(
text,
at = Origin,
leftMargin = 0.0,
rightMargin = width,
alignment = TextAlignment.Justify,
fill = Black.paint
)
canvas.wrapped(
styledText,
at = Origin,
leftMargin = 0.0,
rightMargin = width,
alignment = TextAlignment.Justify,
)
Letter, Word, And Line Spacing
You can now control the way letters, words and lines are spaced when rendering text. Letter and words spacing can be provided to the text rendering methods on Canvas using the new TextSpacing class. This information can also be passed to TextMetrics when measuring text. Label also has support for both letter and word spacing.
Line spacing can also be specified whenever you deal with wrapped text.
APIs
• Rectangle.toPath that allows specifying each corner radius
• Exposing insets in simpleTextButtonRenderer function
• repeat and loop animations can now have delays
• Canvas can now render wrapped text with custom line-spacing
• Label now has lineSpacing property which controls how it displays wrapped text
• Animatable Properties are no longer restricted to use within Views
• New method to create Ellipse and Circle by inscribing within Rectangle
• New Circle.diameter property
• New constructor for StyledText that takes a String and Style
Accessibility
• Browser
◦ Button now sets accessibilityLabel to its text if no label is already provided
◦ HyperLink with native behavior will now apply aria-label to the anchor tag using the HyperLink's text when the AccessibilityManager is present
Fixes | Improvements
• General
◦ Bug with empty AnimationBlock when created during active animation
◦ Wrapped text not correctly aligned
◦ Bug in FilteredList iterator.remove
◦ CommonLabelBehavior no longer provides an x offset for wrapped text since the alignment is handled correctly by Canvas
◦ Edge case where layout can hang b/c of double imprecision
◦ Issue where CommonLabelBehavior overrides Label.foregroundColor on uninstall
◦ Bug where incorrect item could be removed from RenderManagerImpl.pendingLayout
◦ Bug where some View properties lost during behavior install
◦ Bug where some views not cleaned up by RenderManager
◦ Bug in pointer handling when Display transformed
◦ ToggleButton no longer relies on being displayed to listen to its model
◦ StyledText.text now returns correct value
• Browser
◦ Misidentifying elements as native scroll panels led to incorrect pointer behavior
◦ Reuse instances for linear/radial gradient paints
◦ Reusing clipped images
◦ Hyperlinks now open in new tab
◦ Shadow render bug when using SVG
◦ Element sometimes not reused when drawing shadow
◦ Remove overflow on element w/ shadow
◦ Fixed wrapped StyledText rendering
◦ Wrapped StyledText now supports text decoration on previously unsupported cases
• Desktop
◦ Fixed SVG image file loading issue
◦ Fixed rendering of images with radius
◦ Issue where font families weren't being properly tracked and therefore incorrectly applied
◦ Incorrect paragraph width measurement