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
📝 Update TODO

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 42cd0b7
Show file tree
Hide file tree
Showing 32 changed files with 1,281 additions and 707 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.

10 changes: 5 additions & 5 deletions TODO.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
### Components (from material-web)

- [x] Button
- [ ] Checkbox
- [x] Checkbox
- [ ] Field
- [ ] Radio button
- [ ] Switch
Expand All @@ -28,9 +28,9 @@

### Module: MaterialFX

- [ ] Behavior API
- [ ] Behavior API (Done, Experimental/WIP)
- [x] Buttons
- [ ] Checkboxes
- [x] Checkboxes
- [ ] Radio Buttons
- [ ] Toggles
- [ ] Combo-boxes
Expand All @@ -47,8 +47,8 @@

#### Roadmap

- [ ] Time to make a Demo app (ASAP)
- [ ] Theme API and Dark theme
- [ ] Time to make a Demo app
- [ ] Theme API and Dark theme (Done, Experimental/WIP)
- [ ] ColorPicker
- [ ] TextArea
- [ ] Cards
Expand Down
4 changes: 2 additions & 2 deletions gradle.properties
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,8 @@ jdk=11
testJdk=17

# Modules
mfx=11.21.0
mfxcore=11.6.3
mfx=11.22.0
mfxcore=11.6.4
mfxeffects=11.2.1
mfxlocalization=11.1.0
mfxresources=11.8.0
Expand Down
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
2 changes: 1 addition & 1 deletion modules/components/gradle.properties
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
# Maven #
#--------------------------------------#
POM_ARTIFACT_ID=mfxcomponents
VERSION_NAME=11.21.0
VERSION_NAME=11.22.0

POM_NAME=mfxcomponents
POM_DESCRIPTION=Material Design/Modern components for JavaFX
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
Loading

0 comments on commit 42cd0b7

Please sign in to comment.