Skip to content

Commit

Permalink
🔖 Version 21.3.0
Browse files Browse the repository at this point in the history
Base Package
:sparkles: Defined public API for virtualized containers (wip) and paginated variants

List Package
:boom: Implemented paginated variant of VFXList
:recycle: Make VFXList implement VFXContainer
:recycle: VFXList: move default helper factory to separate method, so that subclasses can easily change it
:recycle: VFXListHelper: do not compute the range if the width/height is 0. Also, for some reason, the binding was not invalidating when the estimatedLength was invalid, as a workaround replace it with all its dependencies
:recycle: VFXListManager: do not compute a new state for a position change if the old and new ranges aren't of the same size. If that is the case, then probably another type of change has occurred and this was triggered as the result of an invalidation
:recycle: VFXListManager: when the orientation changes, now the default behavior is to reset both positions
:recycle: VFXListManager: rename the moveOrCreate algorithm to moveReuseCreate, it has been reworked to reuse as much as possible before creating new cells. If the old state is not empty, then those cells will be used
:recycle: VFXListSkin: invoke onOrientationChanged() from the orientation listener instead

Utils Package
:sparkles: StateMap: add poll method

Tests
:recycle: Minor refactors/changes to ListTests
:white_check_mark: Add tests for VFXPaginatedList
:truck: Rename JMH tests class, and exclude them from the test task

Signed-off-by: palexdev <alessandro.parisi406@gmail.com>
  • Loading branch information
palexdev committed Jan 1, 2024
1 parent 1626d8f commit 3b28c4c
Show file tree
Hide file tree
Showing 20 changed files with 1,976 additions and 175 deletions.
7 changes: 4 additions & 3 deletions TODO.md
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
## General

- [x] Review names
- [ ] Rework pos listener/bindings and move it to manager (on init and 'orientation change' switch function)
- [ ] Review APIs (classes, simplify as much as possible/re-organize at least)
- [ ] Maybe define a common Interface for Virtualized containers
- [x] Maybe define a common Interface for Virtualized containers

## VirtualFlow
## List

- [x] Items changed (property)
- [x] Items changed (inside list)
Expand All @@ -17,4 +18,4 @@
- [x] Caching mechanism
- [x] Orientation change
- [x] Introduce spacing feature
- [ ] Implement paginated variant
- [x] Implement paginated variant
3 changes: 3 additions & 0 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,9 @@ java {

test {
useJUnitPlatform()
filter {
excludeTestsMatching "JMH*"
}
}

javafx {
Expand Down
4 changes: 2 additions & 2 deletions gradle.properties
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
#--------------------------------------#
GROUP=io.github.palexdev
POM_ARTIFACT_ID=virtualizedfx
VERSION_NAME=21.2.0
VERSION_NAME=21.3.0
POM_NAME=virtualizedfx
POM_DESCRIPTION=Alternative VirtualFlows for JavaFX
POM_INCEPTION_YEAR=2021
Expand All @@ -19,7 +19,7 @@ POM_PACKAGING=jar
#--------------------------------------#
# Versions #
#--------------------------------------#
vfx=21.2.0
vfx=21.3.0
jdk=21
# Plugins
jfxPlugin=0.1.0
Expand Down
80 changes: 80 additions & 0 deletions src/main/java/io/github/palexdev/virtualizedfx/base/Paginated.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
package io.github.palexdev.virtualizedfx.base;

import javafx.beans.property.IntegerProperty;
import javafx.beans.property.ReadOnlyIntegerProperty;

/**
* Defines the common API for every paginated virtualized container offered by VirtualizedFX. Extends {@link VFXContainer}.
*/
public interface Paginated extends VFXContainer {
int getPage();

/**
* Specifies the page at which the container is.
*/
IntegerProperty pageProperty();

void setPage(int page);

int getMaxPage();

/**
* Specifies the maximum page index at which the container can go.
*/
ReadOnlyIntegerProperty maxPageProperty();

int getCellsPerPage();

/**
* Specifies the number of cells/items to show per each page.
*/
IntegerProperty cellsPerPageProperty();

void setCellsPerPage(int cellsPerPage);

/**
* Goes to the next page if possible.
*/
default void next() {
setPage(getPage() + 1);
}

/**
* Goes to the previous page if possible.
*/
default void previous() {
setPage(getPage() - 1);
}

/**
* Changes the page by the given delta.
*/
default void moveBy(int delta) {
setPage(getPage() + delta);
}

/**
* Given an index, returns the page at which it would be displayed by the container.
* <p></p>
* Note that this will never generate an exception, rather acts as follows for edge cases:
* <p> - empty list or max page is 0 or index < 0: returns 0
* <p> - index > size: returns max page
*/
default int findPageByIndex(int index) {
if (isEmpty() || getMaxPage() == 0 || index < 0) return 0;
if (index > size() - 1) return getMaxPage();
return index / getCellsPerPage();
}

/**
* Computes the maximum page index reachable by the container. This depends on the number of items and the number
* of cells/items per page.
* <p>
* The exact formula is as follows: {@code Math.max(0, ((int) Math.ceil(items / (double) cpp)) - 1)}
*/
default int computeMaxPage() {
int items = size();
int cpp = getCellsPerPage();
return Math.max(0, ((int) Math.ceil(items / (double) cpp)) - 1);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
package io.github.palexdev.virtualizedfx.base;

import javafx.beans.property.ReadOnlyBooleanProperty;
import javafx.beans.property.ReadOnlyIntegerProperty;

/**
* Defines the common API for every virtualized container offered by VirtualizedFX.
*/
public interface VFXContainer {
// TODO maybe more methods can be added here, do it once all containers are implemented
int size();

/**
* Specifies the number of items in the data structure.
*/
ReadOnlyIntegerProperty sizeProperty();

boolean isEmpty();

/**
* Specifies whether the data set is empty.
*/
ReadOnlyBooleanProperty emptyProperty();
}
26 changes: 18 additions & 8 deletions src/main/java/io/github/palexdev/virtualizedfx/list/VFXList.java
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
import io.github.palexdev.mfxcore.controls.SkinBase;
import io.github.palexdev.mfxcore.utils.fx.PropUtils;
import io.github.palexdev.mfxcore.utils.fx.StyleUtils;
import io.github.palexdev.virtualizedfx.base.VFXContainer;
import io.github.palexdev.virtualizedfx.cells.Cell;
import io.github.palexdev.virtualizedfx.enums.BufferSize;
import io.github.palexdev.virtualizedfx.list.VFXListHelper.HorizontalHelper;
Expand All @@ -35,8 +36,8 @@
* Implementation of a virtualized container to show a list of items either vertically or horizontally.
* The default style class is: '.virtualized-list'.
* <p>
* Extends {@link Control}, has its own skin implementation {@link VFXListSkin} and behavior {@link VFXListManager}.
* Uses cells of type {@link Cell}.
* Extends {@link Control}, implements {@link VFXContainer}, has its own skin implementation {@link VFXListSkin}
* and behavior {@link VFXListManager}. Uses cells of type {@link Cell}.
* <p>
* This is a stateful component, meaning that every meaningful variable (position, size, cell size, etc.) will produce a new
* {@link VFXListState}. The state determines which and how items are displayed in the container.
Expand Down Expand Up @@ -86,7 +87,7 @@
* @param <C> the type of cells used by the container to visualize the items
*/
@SuppressWarnings({"rawtypes", "unchecked"})
public class VFXList<T, C extends Cell<T>> extends Control<VFXListManager<T, C>> {
public class VFXList<T, C extends Cell<T>> extends Control<VFXListManager<T, C>> implements VFXContainer {
//================================================================================
// Properties
//================================================================================
Expand All @@ -109,11 +110,7 @@ public void set(VFXListHelper<T, C> newValue) {
super.set(newValue);
}
};
private final FunctionProperty<Orientation, VFXListHelper<T, C>> helperFactory = new FunctionProperty<>(o ->
(o == Orientation.VERTICAL) ?
new VerticalHelper<>(VFXList.this) :
new HorizontalHelper<>(VFXList.this)
) {
private final FunctionProperty<Orientation, VFXListHelper<T, C>> helperFactory = new FunctionProperty<>(defaultHelperFactory()) {
@Override
public void set(Function<Orientation, VFXListHelper<T, C>> newValue) {
if (newValue == null)
Expand Down Expand Up @@ -187,6 +184,15 @@ protected void update(VFXListState<T, C> state) {
setState(state);
}

/**
* @return the default function used to produce a {@link VFXListHelper} according to the container's orientation.
*/
protected Function<Orientation, VFXListHelper<T, C>> defaultHelperFactory() {
return o -> (o == Orientation.VERTICAL) ?
new VerticalHelper<>(this) :
new HorizontalHelper<>(this);
}

/**
* Setter for the {@link #needsViewportLayoutProperty()}.
* This sets the property to true, causing the default skin to recompute the cells' layout.
Expand Down Expand Up @@ -215,27 +221,31 @@ public Supplier<VFXListManager<T, C>> defaultBehaviorProvider() {
/**
* Delegate for {@link ListProperty#size()}.
*/
@Override
public int size() {
return getItems().size();
}

/**
* Delegate for {@link ListProperty#sizeProperty()}.
*/
@Override
public ReadOnlyIntegerProperty sizeProperty() {
return items.sizeProperty();
}

/**
* Delegate for {@link ListProperty#isEmpty()}.
*/
@Override
public boolean isEmpty() {
return getItems().isEmpty();
}

/**
* Delegate for {@link ListProperty#emptyProperty()}
*/
@Override
public ReadOnlyBooleanProperty emptyProperty() {
return items.emptyProperty();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -260,6 +260,7 @@ public VerticalHelper(VFXList<T, C> list) {
super(list);
range.bind(ObjectBindingBuilder.<IntegerRange>build()
.setMapper(() -> {
if (list.getHeight() <= 0) return Utils.INVALID_RANGE;
int needed = totalNum();
if (needed == 0) return Utils.INVALID_RANGE;

Expand All @@ -268,9 +269,10 @@ public VerticalHelper(VFXList<T, C> list) {
if (end - start + 1 < needed) start = Math.max(0, end - needed + 1);
return IntegerRange.of(start, end);
})
.addSources(list.heightProperty(), estimatedLengthProperty())
.addSources(list.heightProperty())
.addSources(list.bufferSizeProperty())
.addSources(list.vPosProperty())
.addSources(list.sizeProperty(), list.cellSizeProperty(), list.spacingProperty())
.get()
);
viewportPosition.bind(ObjectBindingBuilder.<Position>build()
Expand Down Expand Up @@ -437,6 +439,7 @@ public HorizontalHelper(VFXList<T, C> list) {
super(list);
range.bind(ObjectBindingBuilder.<IntegerRange>build()
.setMapper(() -> {
if (list.getWidth() <= 0) return Utils.INVALID_RANGE;
int needed = totalNum();
if (needed == 0) return Utils.INVALID_RANGE;

Expand All @@ -445,9 +448,10 @@ public HorizontalHelper(VFXList<T, C> list) {
if (end - start + 1 < needed) start = Math.max(0, end - needed + 1);
return IntegerRange.of(start, end);
})
.addSources(list.widthProperty(), estimatedLengthProperty())
.addSources(list.widthProperty())
.addSources(list.bufferSizeProperty())
.addSources(list.hPosProperty())
.addSources(list.sizeProperty(), list.cellSizeProperty(), list.spacingProperty())
.get()
);
viewportPosition.bind(ObjectBindingBuilder.<Position>build()
Expand Down

0 comments on commit 3b28c4c

Please sign in to comment.