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 27 commits into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
27 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
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
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2010, 2020, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2010, 2024, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
Expand All @@ -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();
};

// 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),
public ComboBoxBaseBehavior(ComboBoxBase<T> c) {
super(c);
}

new KeyMapping(SPACE, KEY_PRESSED, this::keyPressed),
new KeyMapping(SPACE, KEY_RELEASED, this::keyReleased),
@Override
protected void populateSkinInputMap() {
// ComboBoxBase also cares about focus
getControl().focusedProperty().addListener(focusListener);

enterPressed = new KeyMapping(ENTER, KEY_PRESSED, this::keyPressed),
enterReleased = new KeyMapping(ENTER, 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.
}

// The following keys are forwarded to the parent container
new KeyMapping(ESCAPE, KEY_PRESSED, this::cancelEdit),
new KeyMapping(F10, KEY_PRESSED, this::forwardToParent),
registerFunction(ComboBoxBase.TOGGLE_POPUP, this::togglePopup);

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)
);
registerKey(KeyBinding.with(KeyCode.F4).onKeyReleased().build(), ComboBoxBase.TOGGLE_POPUP);
registerKey(KeyBinding.alt(KeyCode.DOWN), ComboBoxBase.TOGGLE_POPUP);
registerKey(KeyBinding.alt(KeyCode.UP), ComboBoxBase.TOGGLE_POPUP);

// we don't want to consume events on enter press - let them carry on through
enterPressed.setAutoConsume(false);
enterReleased.setAutoConsume(false);
addHandler(KeyBinding.of(KeyCode.SPACE), true, this::keyPressed);
addHandler(KeyBinding.with(KeyCode.SPACE).onKeyReleased().build(), true, this::keyReleased);

// ComboBoxBase also cares about focus
comboBox.focusedProperty().addListener(focusListener);
// these two should not consume the event
addHandler(KeyBinding.of(KeyCode.ENTER), false, this::keyPressed);
addHandler(KeyBinding.with(KeyCode.ENTER).onKeyReleased().build(), false, this::keyReleased);

// 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(KeyBinding.of(KeyCode.ESCAPE), true, this::cancelEdit);
addHandler(KeyBinding.of(KeyCode.F10), true, this::forwardToParent);

@Override public void dispose() {
if (tlFocus != null) tlFocus.dispose();
getNode().focusedProperty().removeListener(focusListener);
super.dispose();
addHandler(MouseEvent.MOUSE_PRESSED, true, this::mousePressed);
addHandler(MouseEvent.MOUSE_RELEASED, true, this::mouseReleased);
addHandler(MouseEvent.MOUSE_ENTERED, true, this::mouseEntered);
addHandler(MouseEvent.MOUSE_EXITED, true, this::mouseExited);
}

@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 Down Expand Up @@ -169,9 +146,9 @@ private void keyPressed(KeyEvent e) {
}
}
else {
if (! getNode().isPressed() && ! getNode().isArmed()) {
if (! getControl().isPressed() && ! getControl().isArmed()) {
keyDown = true;
getNode().arm();
getControl().arm();
}
}
}
Expand All @@ -187,16 +164,16 @@ private void keyReleased(KeyEvent e) {
if (!Utils.isTwoLevelFocus()) {
if (keyDown) {
keyDown = false;
if (getNode().isArmed()) {
getNode().disarm();
if (getControl().isArmed()) {
getControl().disarm();
}
}
}
}

private void forwardToParent(KeyEvent event) {
if (getNode().getParent() != null) {
getNode().getParent().fireEvent(event);
if (getControl().getParent() != null) {
getControl().getParent().fireEvent(event);
}
}

Expand All @@ -205,7 +182,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 Down Expand Up @@ -248,7 +225,7 @@ public void mouseReleased(MouseEvent e) {
}

public void mouseEntered(MouseEvent e) {
if (!getNode().isEditable()) {
if (!getControl().isEditable()) {
mouseInsideButton = true;
} else {
// This is strongly tied to ComboBoxBaseSkin
Expand All @@ -274,23 +251,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 +284,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();
}
}
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2010, 2021, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2010, 2024, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
Expand Down Expand Up @@ -28,10 +28,7 @@
import javafx.scene.control.ComboBox;
import javafx.scene.control.ComboBoxBase;
import javafx.scene.control.SelectionModel;
import com.sun.javafx.scene.control.inputmap.InputMap;

import static javafx.scene.input.KeyCode.DOWN;
import static javafx.scene.input.KeyCode.UP;
import javafx.scene.input.KeyCode;

public class ComboBoxListViewBehavior<T> extends ComboBoxBaseBehavior<T> {

Expand All @@ -44,16 +41,19 @@ public class ComboBoxListViewBehavior<T> extends ComboBoxBaseBehavior<T> {
/**
*
*/
public ComboBoxListViewBehavior(final ComboBox<T> comboBox) {
super(comboBox);
public ComboBoxListViewBehavior(ComboBoxBase<T> c) {
super(c);
}

@Override
protected void populateSkinInputMap() {
super.populateSkinInputMap();

registerFunction(ComboBox.SELECT_PREV, this::selectPrevious);
registerFunction(ComboBox.SELECT_NEXT, this::selectNext);

// Add these bindings as a child input map, so they take precedence
InputMap<ComboBoxBase<T>> comboBoxListViewInputMap = new InputMap<>(comboBox);
comboBoxListViewInputMap.getMappings().addAll(
new InputMap.KeyMapping(UP, e -> selectPrevious()),
new InputMap.KeyMapping(DOWN, e -> selectNext())
);
addDefaultChildMap(getInputMap(), comboBoxListViewInputMap);
registerKey(KeyCode.UP, ComboBox.SELECT_PREV);
registerKey(KeyCode.DOWN, ComboBox.SELECT_NEXT);
}

/***************************************************************************
Expand All @@ -63,7 +63,7 @@ public ComboBoxListViewBehavior(final ComboBox<T> comboBox) {
**************************************************************************/

private ComboBox<T> getComboBox() {
return (ComboBox<T>) getNode();
return (ComboBox<T>) getControl();
}

private void selectPrevious() {
Expand Down
Loading