Features
New Constraint Layout Fully Adopted
The new layout system was introduced in 0.8.2 alongside the former approach is now fully adopted and the old system has been removed. You can get more details on how the new system works in the previous release notes. This release does bring a few additional changes as well. The main difference is that parent constraints are now "constant" by default. This means constraints like the following will NOT modify the parent bounds:
constraint(view) {
it.width eq parent.width - 10 // parent.width is treated like a simple number and is not updated to meet the constraints
}However, you can still make parent properties writable by being explicit as follows:
constraint(view) {
it.width eq parent.width.writable - 10 // now parent.width could be modified if needed to meet the constraints
}There were also some improvements to this new layout engine. Constraints now default all parent properties to read-only. This means it is no longer possible to use the readOnly field on parent properties. Instead, each can be turned into a "writable" value using the new writable field on each.
Revamped Animation APIs
The Animation APIs have been updated to make them more powerful and easier to use. You can now animate a lot more data types, with built-in support for common ones like (Int, Float, Double, Size, Position, Rectangle, Color, and Measure). It is also easy to add new types when they can be converted to a numeric representation. The animation APIs also let you create animatable properties, and provides a few different types of animations, including tweens, key-frames, and repetition.
New Diff API for ObservableList
A new list diff algorithm (based on Google's diff-match-patch) was introduced internally in 0.8.2 to support the new constraint system. It has now been adopted as the mechanism for notifying about changes to ObservableList and related types (i.e. FilteredList). This algorithm scales better and more intuitive than what was in place before. But the APIs are very different.
Old
observableList.changed += { list, removed: Map<Int, T>, added: Map<Int, T>, moved: Map<Int, Pair<Int, T>> ->
}New
observableList.changed += { list, changes: Differences<T> ->
}The new API indicates changes via the Differences interface. This interface lets you iterate over a series of Difference<T> instances that indicate what change was applied to the list at a given index.
observableList.changed += { list, changes: Differences<T> ->
changes.forEach { difference ->
when (difference) {
is Delete -> {}
is Insert -> {}
else -> {} // Equal
}
}
}Differences also let you compute moves optionally in case they matter to your handling of changes.
diffs.computeMoves().forEach {
when (it) {
is Insert -> {
it.items.forEach { item ->
if (it.origin(of = item) == null) {
// not a move
}
}
}
is Delete -> {
it.items.forEach { item ->
when (val destination = it.destination(of = item)) {
null -> {
// not a move
}
else -> {
// move
}
}
}
}
else -> {}
}
}Improved Tables and TreeTables
- Table/TreeTable now support footers
- Table/TreeTable now allow changing the visibility of their header (and footer)
- Tables and their related types now handle being added to a
ScrollPanel. In this case they will BasicMutableTableBehaviornow shows sort order via an icon- New
EqualSizePolicyandProportionalSizePolicytypes to support different table header sizing strategies - New way to specify the stickiness of headers and footers within tables and their derivatives
- New
KeyValueTableto simplify showing Maps in tabular form - Table and its derivatives no longer prevent their first column from resizing
BasicTreeTableBehaviornow takes aniconFactoryinstead of an icon colorTreeTablenow scales the contents of its internal ScrollPanel likeTabledoesTableHeaderCell(used for basic table behaviors) now repaints when disabled/enabled to update colors correctly.TableHeaderCellno longer changes color on pointer pressed if its column is not movableTableHeaderCellno longer uses theGrabbingicon when draggingBasicMutableTableBehaviornow reflects initial sorting of its table.- Ideal size for Table (and derivatives)
- TableBehavior moveColumn now provides the distance it will move. This allows for constant velocity animations
New FileSelector Control
Form Controls
- New
slider,rangeSlider,circularSliderandcircularRangeSlidercontrols - New
fileandfilescontrols
APIs
- Replaced
constrain(videw: View, within: Rectangle)method with faster<T: Positionable> Iterable<T>.constrain(using: ConstraintDslContext.(Bounds) -> Unit, within: (Int, T) -> Rectangle) - new
ifNullutility function - ScrollPanel now exposes scrollbar dimensions and notifies listeners when they change.
- CheckBoxRadioButtonBehavior now takes an
iconInsetwhich indicates the padding around the icon (does not apply to icon-text spacing gap). - BasicMutableTableBehavior now takes a footerColor
- New
simpleTableCellEditorfunction for creatingTableEditors that modify a single cell at a time. - New
ConvexPolygon.mapfunction to create a new polygon by transforming another - New DSL to use an ItemVisualizer of a different time after mapping its inputs:
ItemVisualizer<R, C>.after(mapper: (T) -> R): ItemVisualizer<T, C> - New
ExpandableIteminterface for use with Tree and related views. - [API] MutableTreeNode's children is now a MutableList
- Updated
path(data: String)function, so it can returnnull - New
cancelabledelegate
Performance
- General
- Minor change to AffineTransformImpl to support single Point invocations without converting to array/list
- RenderManagerImpl now uses View.generationNumber instead of an ancestor comparison for layout order
- ConstraintLayoutImpl handles changes in constant parts of constraints more efficiently. This makes
readOnlyusage faster.
- Browser
- Now using native JS Set/Map in some performance critical areas
- TreeSetJs no longer uses recursion
Fixes | Improvements
- General
- Bug in
HorizontalFlowLayoutwhen container is empty - typo in ScrollPanelConstraintDslContext property
optionalRadioListnow allows deselection of its items- Layout of some Form list items
- SplitPanel constraints no longer modify parent
- ScrollPanel how ignores layout when its content scrolls
- ListItem no longer replaces layout if children remain the same
- Bug in
Tablethat could lead to an incorrect index being used when generating a row - Bug in
TreeTablethat could lead to an incorrect index being used when generating a row - Bug in basic list positioning for cases when the list has now width or height
- Bug in
FilteredListwhen filter isnull - Improved how Table and TreeTable handle visible scrollbars. They both now avoid showing horizontal bars and adjust their headers accordingly if the vertical bar is visible.
- Bug in TreeColumns where items weren't being recycled
- Bug in View.generationNumber updating
- Issue in CheckBoxRadioButtonBehavior where icon inset was not being included in the button's idealSize.
MutableTablekeeps itself sorted when its model changes.- Bug in ListItem that caused default
cellAlignmentto be ignored - No longer doing layout in
TreeTablewhencolumnSizePolicychanged before it has abehavior View.scrollTonow handles nestedScrollPanels- List now checks the point that is 1 pixel up and left from its display rect bottom-right corner when updating visible cells. This avoids accidentally including cells that are hidden.
- Bug in Tree that rendered rows incorrectly in some cases
- ScrollPanel now matches content ideal size right away
- Bug in
- Browser
- Minor icon alignment issue in native button behavior
- Native button behavior now properly updates button
idealSize - Bug in native Slider snapping Behavior for some values of ticks
- Default Key event behavior now prevented when event consumed.
- Desktop
- Bug in desktop DragManagerImpl where unsupported MimeTypes were not properly handled
Dependencies
- Kotlin -> 1.7.21
- Kodein -> 7.16.0
- Skiko -> 0.7.40
- Kover -> 0.6.1
- Dokka -> 1.7.20
- Measured -> 0.3.2