Skip to content

Commit

Permalink
🔖 Update and release components and core modules
Browse files Browse the repository at this point in the history
⬆️ Upgrade Gradle to v8.2.1

Components Module
💥 Checkboxes have been reworked
✅ Added tests for the reworked Checkboxes

Core Module
♻️ SelectionProperty: reviewed invalidation logic. The core part has been moved to the invalidated() method, this allows bindings to work, as well as simplifying the process
♻️ SelectionGroup: reviewed for the above changes
🐛 SelectionGroup: fixed MultipleSelectionHandler logic

Signed-off-by: palexdev <alessandro.parisi406@gmail.com>
  • Loading branch information
palexdev committed Aug 24, 2023
1 parent 82dd321 commit b8b4b47
Show file tree
Hide file tree
Showing 26 changed files with 1,266 additions and 697 deletions.
66 changes: 65 additions & 1 deletion .idea/inspectionProfiles/Project_Default.xml

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion .idea/misc.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 6 additions & 0 deletions .idea/vcs.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion gradle/wrapper/gradle-wrapper.properties
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-8.1.1-bin.zip
distributionUrl=https\://services.gradle.org/distributions/gradle-8.2.1-bin.zip
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
12 changes: 11 additions & 1 deletion modules/components/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,16 @@ to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

[//]: ##[Unreleased]

## [11.22.0] - 24-08-2023

### Added

- Added tests for the reworked CheckBoxes

### Changed

- CheckBoxes have been reworked

## [11.21.0] - 01-06-2023

### Added
Expand All @@ -26,7 +36,7 @@ to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

### Changed

- MFXCheckBox: SceneBuilder integration set text to "CheckBox"
- MFXCheckbox: SceneBuilder integration set text to "Checkbox"
- MFXFabBase; SceneBuilder integration set text to "Floating Action Button"
- UserAgentBuilder: Implemented code to resolve @import statements and 'local' URL resources. These features will work
only if the Theme deploys the needed assets on the disk first
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,11 @@

package io.github.palexdev.mfxcomponents.behaviors;

import io.github.palexdev.mfxcomponents.controls.checkbox.MFXCheckBox;
import io.github.palexdev.mfxcomponents.skins.MFXCheckBoxSkin;
import io.github.palexdev.mfxcomponents.controls.checkbox.MFXCheckbox;
import io.github.palexdev.mfxcomponents.skins.MFXCheckboxSkin;
import io.github.palexdev.mfxcore.selection.SelectionProperty;
import io.github.palexdev.mfxresources.fonts.MFXIconWrapper;
import javafx.event.ActionEvent;
import javafx.geometry.Bounds;
import javafx.scene.Node;
import javafx.scene.control.Skin;
Expand All @@ -31,17 +33,17 @@
import java.util.Optional;

/**
* This is the default behavior used by all {@link MFXCheckBox} components.
* This is the default behavior used by all {@link MFXCheckbox} components.
* <p>
* Extends {@link MFXSelectableBehaviorBase} since most of the API is the same, but the {@link #handleSelection()} method
* is overridden to also take into account the special {@code indeterminate} state of checkboxes.
* <p>
* The {@link #keyPressed(KeyEvent)} method has been overridden too, to correctly handle the ripple effect.
* As also explained by {@link MFXCheckBoxSkin}, the effect is generated on the node containing the box and the check
* As also explained by {@link MFXCheckboxSkin}, the effect is generated on the node containing the box and the check
* mark. When we click outside the container, or press ENTER, the effect should be generated at the center of the container
* (as if it was a 'fallback'). For this reason, there's also a mechanism to retrieve the container, see {@link #getIcon()}.
*/
public class MFXCheckBoxBehavior extends MFXSelectableBehaviorBase<MFXCheckBox> {
public class MFXCheckboxBehavior extends MFXSelectableBehaviorBase<MFXCheckbox> {
//================================================================================
// Properties
//================================================================================
Expand All @@ -50,7 +52,7 @@ public class MFXCheckBoxBehavior extends MFXSelectableBehaviorBase<MFXCheckBox>
//================================================================================
// Constructors
//================================================================================
public MFXCheckBoxBehavior(MFXCheckBox button) {
public MFXCheckboxBehavior(MFXCheckbox button) {
super(button);
}

Expand All @@ -77,43 +79,38 @@ public void keyPressed(KeyEvent ke) {
/**
* {@inheritDoc}
* <p></p>
* For checkboxes, the mechanism is even more complex since they also have the {@code 'indeterminate'} state.
* For checkboxes, the mechanism is even more complex since they also have the {@code indeterminate} state.
* <p>
* Here's all the possible cases:
* <p> 1) The checkbox doesn't allow the {@code indeterminate} state, this is the simplest case. The selection state
* is flipped
* <p> 2) The checkbox is not selected and neither {@code indeterminate}, sets the {@code indeterminate} state to true
* <p> 3) The checkbox is selected and not {@code indeterminate}, sets the selection state to false
* <p> 4) The checkbox is not selected but {@code indeterminate}, sets the selection state to true and the
* {@code indeterminate} state to false
* is flipped (see {@link MFXCheckbox#allowIndeterminateProperty()})
* <p> 2) The checkbox is {@code indeterminate}, sets the state to {@code selected}
* <p> 3) The checkbox is not selected, sets the state to {@code indeterminate}
* <p>
* In short, the cycle is: UNSELECTED -> INDETERMINATE (if allowed) -> SELECTED
* <p></p>
* Last but not least, if either the selection or {@code indeterminate} states have changed,
* triggers {@link MFXCheckBox#fire()}.
* <b>Note:</b> this method will not invoke {@link MFXCheckbox#fire()}, as it is handled by the checkbox' {@link SelectionProperty},
* this is done to make {@link ActionEvent}s work also when the property is bound. I've not yet decided if this will
* be the final behavior, if you have issues/opinions on this please let me know.
*/
@Override
protected void handleSelection() {
MFXCheckBox checkBox = getNode();
boolean oldIndeterminate = checkBox.isIndeterminate();
boolean oldState = checkBox.isSelected();
MFXCheckbox checkBox = getNode();
if (checkBox.stateProperty().isBound()) return;

MFXCheckbox.TriState oldState = checkBox.getState();
if (checkBox.isAllowIndeterminate()) {
if (!oldState && !oldIndeterminate) {
checkBox.setIndeterminate(true);
} else if (oldState && !oldIndeterminate) {
checkBox.setSelected(false);
} else {
checkBox.setSelected(true);
checkBox.setIndeterminate(false);
if (oldState == MFXCheckbox.TriState.INDETERMINATE) {
checkBox.setState(MFXCheckbox.TriState.SELECTED);
return;
}
if (oldState == MFXCheckbox.TriState.UNSELECTED) {
checkBox.setState(MFXCheckbox.TriState.INDETERMINATE);
return;
}
} else {
checkBox.setSelected(!oldState);
}

// This is needed since the new state may not necessarily be the one above
// For example if in a group and cannot be selected/deselected...
if (checkBox.isSelected() != oldState ||
checkBox.isIndeterminate() != oldIndeterminate)
checkBox.fire();
checkBox.setState(oldState == MFXCheckbox.TriState.UNSELECTED ? MFXCheckbox.TriState.SELECTED : MFXCheckbox.TriState.UNSELECTED);
// fire() is handled by the state property, to make bindings work too
}

@Override
Expand Down Expand Up @@ -147,7 +144,7 @@ public void dispose() {
*/
protected Optional<Node> getIcon() {
if (icon == null) {
MFXCheckBox checkBox = getNode();
MFXCheckbox checkBox = getNode();
Skin<?> skin = checkBox.getSkin();
if (skin == null) return Optional.empty();
Optional<Node> opt = checkBox.getChildrenUnmodifiable().stream()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,9 +33,9 @@ public MFXSelectableBehaviorBase(S button) {
* Responsible for switching the selection state of the component.
* <p>
* It's worth specifying that the change is not as simple as just flipping the boolean value. Those who implement
* the {@link Selectable} API may be in a {@link SelectionGroup} or, in case of {@link MFXSelectable} components, they
* may have the {@link MFXSelectable#changeSelection(boolean)} method overridden. Which means that at the end the new
* state depends on those two factors. After requesting the new state with {@link MFXSelectable#setSelected(boolean)},
* the {@link Selectable} API may be in a {@link SelectionGroup}.
* <p>
* After requesting the new state with {@link Selectable#setSelected(boolean)},
* we must check if the state was effectively changed, and only if so also trigger {@link MFXSelectable#fire()}.
*/
protected void handleSelection() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,6 @@
* <p></p>
* Implements the selection API/Behavior through the {@link Selectable} interface.
* Expects behaviors of type {@link MFXSelectableBehaviorBase}.
* <p></p>
* Implementations of this may need to control the way selection works, for this reason there are two methods that are basically
* hooks for pre/post selection change, see {@link #changeSelection(boolean)} and {@link #onSelectionChanged(boolean)}.
*
* @see SelectionProperty
* @see SelectionGroupProperty
Expand All @@ -30,14 +27,9 @@ public abstract class MFXSelectable<B extends MFXSelectableBehaviorBase<?>> exte
//================================================================================
private final SelectionGroupProperty selectionGroup = new SelectionGroupProperty(this);
private final SelectionProperty selected = new SelectionProperty(this) {
@Override
public void set(boolean newValue) {
boolean state = changeSelection(newValue);
super.set(state);
}

@Override
protected void invalidated() {
super.invalidated();
onSelectionChanged(get());
}
};
Expand All @@ -60,21 +52,6 @@ public MFXSelectable(String text, Node graphic) {
// Methods
//================================================================================

/**
* This is automatically called by the {@link #selectedProperty()} when selection is about to change.
* <p>
* The given parameter is the new requested selection state.
* <p></p>
* One can alter the return value according to its needs.
* By default, does not alter the requested state.
* <p></p>
* BEWARE! Disabling these components when in a {@link SelectionGroup} may produce unexpected results,
* especially when using the {@link SelectionGroup#atLeastOneSelectedProperty()} mode.
*/
protected boolean changeSelection(boolean selected) {
return selected;
}

/**
* This is automatically called by {@link #selectedProperty()} after the selection has changed and has become invalid.
* <p></p>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -95,17 +95,14 @@ public MFXIconButton outlined() {
private void initialize() {
graphicProperty().bind(iconProperty());
setSelectable(false);
selectionGroupProperty().addListener(i -> {
if (getSelectionGroup() != null) asToggle();
});
}

//================================================================================
// Overridden Methods
//================================================================================
@Override
protected boolean changeSelection(boolean selected) {
if (!isSelectable()) return false;
return super.changeSelection(selected);
}

@Override
protected MFXSkinBase<?, ?> buildSkin() {
return new MFXIconButtonSkin(this);
Expand Down

0 comments on commit b8b4b47

Please sign in to comment.