/*
* Copyright (c) 2013. by Gerrit Grunwald
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package jfx8controls.extendingcontrol;
import com.sun.javafx.scene.control.behavior.BehaviorBase;
import com.sun.javafx.scene.control.behavior.KeyBinding;
import javafx.scene.control.ButtonBase;
import javafx.scene.input.MouseButton;
import javafx.scene.input.MouseEvent;
import java.util.ArrayList;
import java.util.List;
import static javafx.scene.input.KeyCode.SPACE;
import static javafx.scene.input.KeyEvent.KEY_PRESSED;
import static javafx.scene.input.KeyEvent.KEY_RELEASED;
/**
* User: hansolo
* Date: 07.10.13
* Time: 09:21
* To change this template use File | Settings | File Templates.
*/
public class SlideCheckBoxBehavior <C extends ButtonBase> extends BehaviorBase<C> {
/***************************************************************************
* *
* Constructors *
* *
**************************************************************************/
public SlideCheckBoxBehavior(final C button) {
super(button, BUTTON_BINDINGS);
}
public SlideCheckBoxBehavior(final C button, final List<KeyBinding> bindings) {
super(button, bindings);
}
/***************************************************************************
* *
* Focus change handling *
* *
**************************************************************************/
@Override protected void focusChanged() {
// If we did have the key down, but are now not focused, then we must
// disarm the button.
final ButtonBase button = getControl();
if (keyDown && !button.isFocused()) {
keyDown = false;
button.disarm();
}
}
/***************************************************************************
* *
* Key event handling *
* *
**************************************************************************/
/**
* Indicates that a keyboard key has been pressed which represents the
* event (this could be space bar for example). As long as keyDown is true,
* we are also armed, and will ignore mouse events related to arming.
* Note this is made package private solely for the sake of testing.
*/
private boolean keyDown;
private static final String PRESS_ACTION = "Press";
private static final String RELEASE_ACTION = "Release";
protected static final List<KeyBinding> BUTTON_BINDINGS = new ArrayList<KeyBinding>();
static {
BUTTON_BINDINGS.add(new KeyBinding(SPACE, KEY_PRESSED, PRESS_ACTION));
BUTTON_BINDINGS.add(new KeyBinding(SPACE, KEY_RELEASED, RELEASE_ACTION));
}
@Override protected void callAction(String name) {
if (!getControl().isDisabled()) {
if (PRESS_ACTION.equals(name)) {
keyPressed();
} else if (RELEASE_ACTION.equals(name)) {
keyReleased();
} else {
super.callAction(name);
}
}
}
/**
* This function is invoked when an appropriate keystroke occurs which
* causes this button to be armed if it is not already armed by a mouse
* press.
*/
private void keyPressed() {
final ButtonBase button = getControl();
if (!button.isPressed() && !button.isArmed()) {
keyDown = true;
button.arm();
}
}
/**
* Invoked when a valid keystroke release occurs which causes the button
* to fire if it was armed by a keyPress.
*/
private void keyReleased() {
final ButtonBase button = getControl();
if (keyDown) {
keyDown = false;
if (button.isArmed()) {
button.disarm();
button.fire();
}
}
}
/***************************************************************************
* *
* Mouse event handling *
* *
**************************************************************************/
/**
* Invoked when a mouse press has occurred over the button. In addition to
* potentially arming the Button, this will transfer focus to the button
*/
@Override public void mousePressed(MouseEvent e) {
final ButtonBase button = getControl();
super.mousePressed(e);
// if the button is not already focused, then request the focus
if (! button.isFocused() && button.isFocusTraversable()) {
button.requestFocus();
}
// arm the button if it is a valid mouse event
// Note there appears to be a bug where if I press and hold and release
// then there is a clickCount of 0 on the release, whereas a quick click
// has a release clickCount of 1. So here I'll check clickCount <= 1,
// though it should really be == 1 I think.
boolean valid = (e.getButton() == MouseButton.PRIMARY &&
! (e.isMiddleButtonDown() || e.isSecondaryButtonDown() ||
e.isShiftDown() || e.isControlDown() || e.isAltDown() || e.isMetaDown()));
if (! button.isArmed() && valid) {
button.arm();
}
}
/**
* Invoked when a mouse release has occurred. We determine whether this
* was done in a manner that would fire the button's action. This happens
* only if the button was armed by a corresponding mouse press.
*/
@Override public void mouseReleased(MouseEvent e) {
// if armed by a mouse press instead of key press, then fire!
final ButtonBase button = getControl();
if (! keyDown && button.isArmed()) {
button.fire();
button.disarm();
}
}
/**
* Invoked when the mouse enters the Button. If the Button had been armed
* by a mouse press and the mouse is still pressed, then this will cause
* the button to be rearmed.
*/
@Override public void mouseEntered(MouseEvent e) {
// rearm if necessary
final ButtonBase button = getControl();
super.mouseEntered(e);
if (! keyDown && button.isPressed()) {
button.arm();
}
}
/**
* Invoked when the mouse exits the Button. If the Button is armed due to
* a mouse press, then this function will disarm the button upon the mouse
* exiting it.
*/
@Override public void mouseExited(MouseEvent e) {
// Disarm if necessary
final ButtonBase button = getControl();
super.mouseExited(e);
if (! keyDown && button.isArmed()) {
button.disarm();
}
}
}