Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

8314968: Public InputMap (v3) #1495

Draft
wants to merge 53 commits into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
53 commits
Select commit Hold shift + click to select a range
616c3a4
8314968: Public InputMap
andy-goryachev-oracle Mar 8, 2024
bee6240
whitespace
andy-goryachev-oracle Mar 8, 2024
dea7531
Merge remote-tracking branch 'origin/master' into 8314968.input.map.v2
andy-goryachev-oracle Apr 2, 2024
ddd1cc0
override
andy-goryachev-oracle Apr 2, 2024
6b35e84
Merge branch 'master' into 8314968.input.map.v2
andy-goryachev-oracle Apr 15, 2024
eb4465a
convenience methods
andy-goryachev-oracle Apr 15, 2024
616c0e6
Merge remote-tracking branch 'origin/master' into 8314968.input.map.v2
andy-goryachev-oracle Apr 18, 2024
b112b9b
focus traversal
andy-goryachev-oracle Apr 18, 2024
7eb90d8
whitespace
andy-goryachev-oracle Apr 18, 2024
134cc5d
Merge remote-tracking branch 'origin/master' into 8314968.input.map.v2
andy-goryachev-oracle Apr 19, 2024
9e455e2
shift shortcut
andy-goryachev-oracle Apr 19, 2024
2fe5dd7
shift option
andy-goryachev-oracle Apr 22, 2024
fc214a4
Merge branch 'master' into 8314968.input.map.v2
andy-goryachev-oracle May 9, 2024
8e6dac7
Merge branch 'master' into 8314968.input.map.v2
andy-goryachev-oracle Jun 6, 2024
a32a87e
stateless skin input map
andy-goryachev-oracle Jun 10, 2024
6347e33
Merge remote-tracking branch 'origin/master' into 8314968.input.map.v3
andy-goryachev-oracle Jun 10, 2024
23baf8e
cleanup
andy-goryachev-oracle Jun 10, 2024
ddd256a
links
andy-goryachev-oracle Jun 10, 2024
d5a0fb0
final methods
andy-goryachev-oracle Jun 11, 2024
9bd6a40
whitespace
andy-goryachev-oracle Jun 14, 2024
dbfeced
Merge branch 'master' into 8314968.input.map.v3
andy-goryachev-oracle Jul 5, 2024
2cb9cc0
Merge branch 'master' into 8314968.input.map.v3
andy-goryachev-oracle Sep 3, 2024
626743c
Merge remote-tracking branch 'origin/master' into 8314968.input.map.v3
andy-goryachev-oracle Sep 24, 2024
3be3465
Merge remote-tracking branch 'origin/master' into 8314968.input.map.v3
andy-goryachev-oracle Oct 22, 2024
e23fa81
Merge remote-tracking branch 'origin/master' into 8314968.input.map.v3
andy-goryachev-oracle Nov 1, 2024
4550a71
sync up with rich text area
andy-goryachev-oracle Nov 1, 2024
96b5018
link
andy-goryachev-oracle Nov 1, 2024
a8ffa3e
Merge remote-tracking branch 'origin/master' into 8314968.input.map.v3
andy-goryachev-oracle Nov 7, 2024
12d06a8
rta
andy-goryachev-oracle Nov 7, 2024
2e7210d
comment
andy-goryachev-oracle Nov 7, 2024
a6acd80
Merge remote-tracking branch 'origin/master' into 8314968.input.map.v3
andy-goryachev-oracle Nov 13, 2024
6ed3642
add handler last
andy-goryachev-oracle Nov 13, 2024
bbd262f
Merge remote-tracking branch 'origin/master' into 8314968.input.map.v3
andy-goryachev-oracle Nov 13, 2024
45402ec
unnecessary add handler last
andy-goryachev-oracle Nov 13, 2024
92f1261
Merge remote-tracking branch 'origin/master' into 8314968.input.map.v3
andy-goryachev-oracle Nov 14, 2024
c13e3ee
doc
andy-goryachev-oracle Nov 14, 2024
c85e648
removed function handler
andy-goryachev-oracle Nov 14, 2024
a14450b
cleanup
andy-goryachev-oracle Nov 14, 2024
f01fc8c
Merge remote-tracking branch 'origin/master' into 8314968.input.map.v3
andy-goryachev-oracle Nov 15, 2024
06a3a5d
review comments
andy-goryachev-oracle Nov 21, 2024
2930824
Merge remote-tracking branch 'origin/master' into 8314968.input.map.v3
andy-goryachev-oracle Nov 21, 2024
a90c9e0
Merge branch 'master' into 8314968.input.map.v3
andy-goryachev-oracle Dec 3, 2024
7f569a9
review comments
andy-goryachev-oracle Dec 3, 2024
b25e367
Merge remote-tracking branch 'origin/master' into 8314968.input.map.v3
andy-goryachev-oracle Dec 9, 2024
5e7b8b7
add handler
andy-goryachev-oracle Dec 10, 2024
039b7bc
Merge remote-tracking branch 'origin/master' into 8314968.input.map.v3
andy-goryachev-oracle Dec 10, 2024
a5c318e
javadoc
andy-goryachev-oracle Dec 10, 2024
0fe4936
sync with rta
andy-goryachev-oracle Dec 10, 2024
765cabb
Merge remote-tracking branch 'origin/master' into 8314968.input.map.v3
andy-goryachev-oracle Dec 12, 2024
38fc815
Merge remote-tracking branch 'origin/master' into 8314968.input.map.v3
andy-goryachev-oracle Dec 17, 2024
8baa0fa
review comments
andy-goryachev-oracle Dec 17, 2024
dfed2b7
Merge branch 'master' into 8314968.input.map.v3
andy-goryachev-oracle Jan 6, 2025
8cee511
Merge remote-tracking branch 'origin/master' into 8314968.input.map.v3
andy-goryachev-oracle Jan 8, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,6 @@

import javafx.scene.control.ColorPicker;
import javafx.scene.control.PopupControl;

import javafx.scene.paint.Color;

public class ColorPickerBehavior extends ComboBoxBaseBehavior<Color> {
Expand All @@ -41,8 +40,8 @@ public class ColorPickerBehavior extends ComboBoxBaseBehavior<Color> {
/**
*
*/
public ColorPickerBehavior(final ColorPicker colorPicker) {
super(colorPicker);
public ColorPickerBehavior(ColorPicker c) {
super(c);
}

/**************************************************************************
Expand All @@ -54,14 +53,14 @@ public ColorPickerBehavior(final ColorPicker colorPicker) {
@Override public void onAutoHide(PopupControl popup) {
// when we click on some non interactive part of the
// Color Palette - we do not want to hide.
if (!popup.isShowing() && getNode().isShowing()) {
if (!popup.isShowing() && getControl().isShowing()) {
// Popup was dismissed. Maybe user clicked outside or typed ESCAPE.
// Make sure DatePicker button is in sync.
getNode().hide();
getControl().hide();
}
// if the ColorPicker is no longer showing, then invoke the super method
// to keep its show/hide state in sync.
if (!getNode().isShowing()) {
if (!getControl().isShowing()) {
super.onAutoHide(popup);
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,30 +25,25 @@

package com.sun.javafx.scene.control.behavior;

import com.sun.javafx.scene.control.inputmap.InputMap;

import javafx.beans.InvalidationListener;
import javafx.beans.Observable;
import javafx.event.EventHandler;
import javafx.event.EventTarget;
import javafx.scene.Node;
import javafx.scene.control.ComboBox;
import javafx.scene.control.ComboBoxBase;
import javafx.scene.control.DatePicker;
import javafx.scene.control.PopupControl;
import javafx.scene.control.TextField;
import javafx.scene.control.input.BehaviorBase;
import javafx.scene.control.input.KeyBinding;
import javafx.scene.input.KeyCode;
import javafx.scene.input.KeyEvent;
import javafx.scene.input.MouseButton;
import javafx.scene.input.MouseEvent;
import com.sun.javafx.scene.control.skin.Utils;
import javafx.scene.input.*;
import com.sun.javafx.scene.control.inputmap.KeyBinding;

import static javafx.scene.input.KeyCode.*;
import static javafx.scene.input.KeyEvent.*;
import static com.sun.javafx.scene.control.inputmap.InputMap.KeyMapping;
import static com.sun.javafx.scene.control.inputmap.InputMap.MouseMapping;

public class ComboBoxBaseBehavior<T> extends BehaviorBase<ComboBoxBase<T>> {

private final InputMap<ComboBoxBase<T>> inputMap;
private InvalidationListener focusListener = this::focusChanged;

/***************************************************************************
Expand All @@ -62,65 +57,47 @@ public class ComboBoxBaseBehavior<T> extends BehaviorBase<ComboBoxBase<T>> {
/**
*
*/
public ComboBoxBaseBehavior(final ComboBoxBase<T> comboBox) {
super(comboBox);

// create a map for comboBox-specific mappings (this reuses the default
// InputMap installed on the control, if it is non-null, allowing us to pick up any user-specified mappings)
inputMap = createInputMap();

final EventHandler<KeyEvent> togglePopup = e -> {
// If popup is shown, KeyEvent causes popup to close
showPopupOnMouseRelease = true;

if (getNode().isShowing()) hide();
else show();
};
public ComboBoxBaseBehavior(ComboBoxBase<T> c) {
super(c);
}

// comboBox-specific mappings for key and mouse input
KeyMapping enterPressed, enterReleased;
addDefaultMapping(inputMap,
new KeyMapping(F4, KEY_RELEASED, togglePopup),
new KeyMapping(new KeyBinding(UP).alt(), togglePopup),
new KeyMapping(new KeyBinding(DOWN).alt(), togglePopup),
@Override
protected void populateSkinInputMap() {
// ComboBoxBase also cares about focus
getControl().focusedProperty().addListener(focusListener);

new KeyMapping(SPACE, KEY_PRESSED, this::keyPressed),
new KeyMapping(SPACE, KEY_RELEASED, this::keyReleased),
// Only add this if we're on an embedded platform that supports 5-button navigation
if (Utils.isTwoLevelFocus()) {
tlFocus = new TwoLevelFocusComboBehavior(getControl()); // needs to be last.
}

enterPressed = new KeyMapping(ENTER, KEY_PRESSED, this::keyPressed),
enterReleased = new KeyMapping(ENTER, KEY_RELEASED, this::keyReleased),
registerFunction(ComboBoxBase.TOGGLE_POPUP, this::togglePopup);

// The following keys are forwarded to the parent container
new KeyMapping(ESCAPE, KEY_PRESSED, this::cancelEdit),
new KeyMapping(F10, KEY_PRESSED, this::forwardToParent),
registerKey(KeyBinding.builder(KeyCode.F4).keyReleased().build(), ComboBoxBase.TOGGLE_POPUP);
registerKey(KeyBinding.alt(KeyCode.DOWN), ComboBoxBase.TOGGLE_POPUP);
registerKey(KeyBinding.alt(KeyCode.UP), ComboBoxBase.TOGGLE_POPUP);

new MouseMapping(MouseEvent.MOUSE_PRESSED, this::mousePressed),
new MouseMapping(MouseEvent.MOUSE_RELEASED, this::mouseReleased),
new MouseMapping(MouseEvent.MOUSE_ENTERED, this::mouseEntered),
new MouseMapping(MouseEvent.MOUSE_EXITED, this::mouseExited)
);
addHandler(KeyBinding.of(KeyCode.SPACE), (ev) -> keyPressed(ev, true));
addHandler(KeyBinding.builder(KeyCode.SPACE).keyReleased().build(), (ev) -> keyReleased(ev, true));

// we don't want to consume events on enter press - let them carry on through
enterPressed.setAutoConsume(false);
enterReleased.setAutoConsume(false);
// these two should not consume the event
addHandler(KeyBinding.of(KeyCode.ENTER), (ev) -> keyPressed(ev, false));
addHandler(KeyBinding.builder(KeyCode.ENTER).keyReleased().build(), (ev) -> keyReleased(ev, false));

// ComboBoxBase also cares about focus
comboBox.focusedProperty().addListener(focusListener);
addHandler(KeyBinding.of(KeyCode.ESCAPE), this::cancelEdit);
addHandler(KeyBinding.of(KeyCode.F10), this::forwardToParent);

// Only add this if we're on an embedded platform that supports 5-button navigation
if (Utils.isTwoLevelFocus()) {
tlFocus = new TwoLevelFocusComboBehavior(comboBox); // needs to be last.
}
addHandler(MouseEvent.MOUSE_PRESSED, this::mousePressed);
addHandler(MouseEvent.MOUSE_RELEASED, this::mouseReleased);
addHandler(MouseEvent.MOUSE_ENTERED, this::mouseEntered);
addHandler(MouseEvent.MOUSE_EXITED, this::mouseExited);
}

@Override public void dispose() {
if (tlFocus != null) tlFocus.dispose();
getNode().focusedProperty().removeListener(focusListener);
super.dispose();
}

@Override public InputMap<ComboBoxBase<T>> getInputMap() {
return inputMap;
public void dispose() {
if (tlFocus != null) {
tlFocus.dispose();
}
getControl().focusedProperty().removeListener(focusListener);
}

/***************************************************************************
Expand All @@ -132,7 +109,7 @@ public ComboBoxBaseBehavior(final ComboBoxBase<T> comboBox) {
protected void focusChanged(Observable o) {
// If we did have the key down, but are now not focused, then we must
// disarm the box.
final ComboBoxBase<T> box = getNode();
final ComboBoxBase<T> box = getControl();
if (keyDown && !box.isFocused()) {
keyDown = false;
box.disarm();
Expand All @@ -158,7 +135,7 @@ protected void focusChanged(Observable o) {
* causes this button to be armed if it is not already armed by a mouse
* press.
*/
private void keyPressed(KeyEvent e) {
private void keyPressed(KeyEvent e, boolean consume) {
// If popup is shown, KeyEvent causes popup to close
showPopupOnMouseRelease = true;

Expand All @@ -169,34 +146,46 @@ private void keyPressed(KeyEvent e) {
}
}
else {
if (! getNode().isPressed() && ! getNode().isArmed()) {
if (! getControl().isPressed() && ! getControl().isArmed()) {
keyDown = true;
getNode().arm();
getControl().arm();
}
}
if (consume) {
e.consume();
}
}

/**
* Invoked when a valid keystroke release occurs which causes the button
* to fire if it was armed by a keyPress.
*/
private void keyReleased(KeyEvent e) {
private void keyReleased(KeyEvent e, boolean consume) {
// If popup is shown, KeyEvent causes popup to close
showPopupOnMouseRelease = true;

if (!Utils.isTwoLevelFocus()) {
if (keyDown) {
keyDown = false;
if (getNode().isArmed()) {
getNode().disarm();
if (getControl().isArmed()) {
getControl().disarm();
}
}
}
if (consume) {
e.consume();
}
}

private void forwardToParent(KeyEvent event) {
if (getNode().getParent() != null) {
getNode().getParent().fireEvent(event);
try {
if (getControl().getParent() != null) {
getControl().getParent().fireEvent(event);
}
} finally {
// TODO original logic is to always consume the event.
// we may want to change that
event.consume();
}
}

Expand All @@ -205,7 +194,7 @@ private void cancelEdit(KeyEvent event) {
* This can be cleaned up if the editor property is moved up
* to ComboBoxBase.
*/
ComboBoxBase comboBoxBase = getNode();
ComboBoxBase comboBoxBase = getControl();
TextField textField = null;
if (comboBoxBase instanceof DatePicker) {
textField = ((DatePicker)comboBoxBase).getEditor();
Expand All @@ -218,6 +207,7 @@ private void cancelEdit(KeyEvent event) {
} else {
forwardToParent(event);
}
event.consume();
}


Expand All @@ -229,6 +219,7 @@ private void cancelEdit(KeyEvent event) {

public void mousePressed(MouseEvent e) {
arm(e);
e.consume();
}

public void mouseReleased(MouseEvent e) {
Expand All @@ -245,22 +236,25 @@ public void mouseReleased(MouseEvent e) {
showPopupOnMouseRelease = true;
hide();
}
e.consume();
}

public void mouseEntered(MouseEvent e) {
if (!getNode().isEditable()) {
if (!getControl().isEditable()) {
mouseInsideButton = true;
} else {
// This is strongly tied to ComboBoxBaseSkin
final EventTarget target = e.getTarget();
mouseInsideButton = (target instanceof Node && "arrow-button".equals(((Node) target).getId()));
}
arm();
e.consume();
}

public void mouseExited(MouseEvent e) {
mouseInsideButton = false;
disarm();
e.consume();
}

// private void getFocus() {
Expand All @@ -274,23 +268,23 @@ private void arm(MouseEvent e) {
! (e.isMiddleButtonDown() || e.isSecondaryButtonDown() ||
e.isShiftDown() || e.isControlDown() || e.isAltDown() || e.isMetaDown()));

if (! getNode().isArmed() && valid) {
getNode().arm();
if (! getControl().isArmed() && valid) {
getControl().arm();
}
}

public void show() {
if (! getNode().isShowing()) {
if (getNode().isFocusTraversable()) {
getNode().requestFocus();
if (! getControl().isShowing()) {
if (getControl().isFocusTraversable()) {
getControl().requestFocus();
}
getNode().show();
getControl().show();
}
}

public void hide() {
if (getNode().isShowing()) {
getNode().hide();
if (getControl().isShowing()) {
getControl().hide();
}
}

Expand All @@ -307,15 +301,25 @@ public void onAutoHide(PopupControl popup) {
}

public void arm() {
if (getNode().isPressed()) {
getNode().arm();
if (getControl().isPressed()) {
getControl().arm();
}
}

public void disarm() {
if (! keyDown && getNode().isArmed()) {
getNode().disarm();
if (! keyDown && getControl().isArmed()) {
getControl().disarm();
}
}

private void togglePopup() {
// If popup is shown, KeyEvent causes popup to close
showPopupOnMouseRelease = true;

if (getControl().isShowing()) {
hide();
} else {
show();
}
}
}
Loading