io.github.palexdev.mfxcomponents.behaviors.MFXCheckboxBehavior Maven / Gradle / Ivy
Show all versions of materialfx-all Show documentation
/*
* Copyright (C) 2023 Parisi Alessandro - [email protected]
* This file is part of MaterialFX (https://github.com/palexdev/MaterialFX)
*
* MaterialFX is free software: you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public License
* as published by the Free Software Foundation; either version 3 of the License,
* or (at your option) any later version.
*
* MaterialFX is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with MaterialFX. If not, see .
*/
package io.github.palexdev.mfxcomponents.behaviors;
import io.github.palexdev.mfxcomponents.controls.checkbox.MFXCheckbox;
import io.github.palexdev.mfxcomponents.controls.checkbox.TriState;
import io.github.palexdev.mfxcore.selection.SelectionProperty;
import io.github.palexdev.mfxcore.utils.EnumUtils;
import javafx.event.ActionEvent;
import javafx.scene.input.KeyCode;
import javafx.scene.input.KeyEvent;
import javafx.scene.input.MouseButton;
import javafx.scene.input.MouseEvent;
import java.util.function.Consumer;
/**
* This is the default behavior used by all {@link MFXCheckbox} components.
*
* 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.
*/
public class MFXCheckboxBehavior extends MFXSelectableBehaviorBase {
//================================================================================
// Constructors
//================================================================================
public MFXCheckboxBehavior(MFXCheckbox button) {
super(button);
}
//================================================================================
// Overridden Methods
//================================================================================
/**
* {@inheritDoc}
*
* Overridden to not trigger {@link MFXCheckbox#fire()} twice as it is already handled by {@link #handleSelection()}
*/
@Override
public void mouseClicked(MouseEvent me, Consumer callback) {
if (me.getButton() == MouseButton.PRIMARY) handleSelection();
if (callback != null) callback.accept(me);
}
/**
* {@inheritDoc}
*
* Overridden to not trigger {@link MFXCheckbox#fire()} twice as it is already handled by {@link #handleSelection()}
*/
@Override
public void keyPressed(KeyEvent ke, Consumer callback) {
if (ke.getCode() == KeyCode.ENTER) handleSelection();
if (callback != null) callback.accept(ke);
}
/**
* {@inheritDoc}
*
* For checkboxes, the mechanism is even more complex since they also have the {@code indeterminate} state.
*
* Here's all the possible cases:
*
1) The checkbox doesn't allow the {@code indeterminate} state, this is the simplest case. The selection state
* is flipped (see {@link MFXCheckbox#allowIndeterminateProperty()})
*
2) The checkbox is {@code indeterminate}, sets the state to {@code selected}
*
3) The checkbox is not selected, sets the state to {@code indeterminate}
*
* In short, the cycle is: UNSELECTED -> SELECTED -> INDETERMINATE (if allowed)
*
* Note: 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();
if (checkBox.stateProperty().isBound()) return;
TriState oldState = checkBox.getState();
TriState newState = EnumUtils.next(TriState.class, oldState);
if (newState == TriState.INDETERMINATE && !checkBox.isAllowIndeterminate())
newState = EnumUtils.next(TriState.class, newState);
checkBox.setState(newState);
// fire() is handled by the state property, to make bindings work too
}
}