Dear Martin:

This basically is the minimal API surface as far as InputMap is concerned.  
There are probably some methods still missing, such as ...

Say I want Ctrl-J to be Copy instead of whatever it’s default binding is.


InputMap.unbind(FunctionTag.COPY); • missing method.  Or we could add 
InputMap.getKeyBindingfor(FunctionTag)

followed by

InputMap.registerKey(KeyBinding.ctrl(KeyCode.J), COPY);

So, basically, one or two methods are missing!



Any control will need to ensure that it ignore tags it doesn’t understand. Who 
cares if Ctrl-A maps to SELECT_ALL for a button? It will just ignore it.
But I do get your point. If we ask a Control to map an event to an operation we 
should ensure that the control actually supports that operation. So we don’t 
need multiple SELECT_ALL tags, just a verification step so we don’t return 
bogus tags.

Well, if we try to think of a union of all possible functions, it is just not 
right.  The functions have different semantics for different controls, even 
SELECT_ALL would be different, or there will be multiple flavors of SELECT_ALL 
or COPY.  I just don’t think it’s necessary.

Each control declares a bunch of public methods specific to that control, and 
also declares a method identifiers corresponding to these methods (that’s 
FunctionTags).  If we try to add a key binding to a button passing a function 
tag from TextArea it will essentially be ignored because Button does not have 
the corresponding method.

I don’t think there are methods that are common for *every* control.  So we 
have control-specific tags that might be in the control or its base class such 
as TextInputControl.

-andy

P.S. thank you for uncovering a gap in the API!




From: Martin Fox <mar...@martinfox.com>
Date: Tuesday, October 31, 2023 at 16:21
To: Andy Goryachev <andy.goryac...@oracle.com>
Cc: Kevin Rushforth <kevin.rushfo...@oracle.com>, openjfx-dev 
<openjfx-dev@openjdk.org>
Subject: Re: [External] : Re: [Request for Comments] Behavior / InputMap
Andy,

I should have been clearer on why I wrote this up. I think once you’ve 
identified the minimum API surface that’s probably all you should implement.

More important to me is whether reducing the API to a bunch of function tags 
and two API calls does everything that needs to be done. For example, that 
reduction means you can’t enumerate the list of function tags a control 
supports or the full set of key bindings. Is that an issue? Is there a use case 
for these enumerations?


3) Provide an API that asks a control to map an Event to a FunctionTag. This 
enables blocking existing mappings; if a user wants to block the default 
mappings for, say, COPY they can simply discard/consume any events that the 
control would map to COPY.

Supported via InputMap.registerFunction(FunctionTag, Runnable).  Just do 
registerFunction(COPY, () -> { }).

Sorry I didn’t make myself clear. Say I want Ctrl-J to be Copy instead of 
whatever it’s default binding is. The flow would be:

if the event is Ctrl-J
ask the control to perform the COPY operation
else if the control maps this event to COPY
discard the event (it’s the default binding)

They are not.  There is no SELECT_ALL in Button control, for example.  Where 
the hierarchy exists, so does the hierarchy of tags, for example 
TextInputControl.SELECT_ALL which is applicable/used in TextField and TextArea. 
 But we can’t extend it to TableView, for example, as there is no common 
ancestor - unless we invent one (an interface).

Any control will need to ensure that it ignore tags it doesn’t understand. Who 
cares if Ctrl-A maps to SELECT_ALL for a button? It will just ignore it.

But I do get your point. If we ask a Control to map an event to an operation we 
should ensure that the control actually supports that operation. So we don’t 
need multiple SELECT_ALL tags, just a verification step so we don’t return 
bogus tags.



What do you think?

Thank you
-andy



From: Martin Fox <mar...@martinfox.com>
Date: Monday, October 30, 2023 at 17:24
To: Andy Goryachev <andy.goryac...@oracle.com>
Cc: Kevin Rushforth <kevin.rushfo...@oracle.com>, openjfx-dev 
<openjfx-dev@openjdk.org>
Subject: [External] : Re: [Request for Comments] Behavior / InputMap
I was looking over the InputMap proposal with an eye toward paring it down to 
the bare minimum.

From the perspective of a user who wants to manipulate a control without 
subclassing it I think there are only a few essential components.

1) Ensure the user gets events before the control does. That’s a topic for a 
different thread.

2) Provide an API that asks a control to perform the operation identified by a 
FunctionTag. This is the only way to access operations like COPY and MOVE_RIGHT 
that are implemented behind the scenes.

3) Provide an API that asks a control to map an Event to a FunctionTag. This 
enables blocking existing mappings; if a user wants to block the default 
mappings for, say, COPY they can simply discard/consume any events that the 
control would map to COPY.

If a user wants to subclass an existing control they could also use these API’s 
to do full customization but only if they can guarantee that their subclass 
will process events before the superclass. That, too, might be a separate 
discussion.

I would like to discuss these API’s without getting too deep into 
implementation details. With that said, I do have one implementation 
suggestion: since most of the event => FunctionTag mappings are common 
(SELECT_ALL is always Shortcut+A) there should be an internal shared object 
containing the common mappings.

Martin



On Oct 30, 2023, at 3:11 PM, Andy Goryachev <andy.goryac...@oracle.com> wrote:

Dear Kevin:

Thank you for providing a summary to our (lively) discussion.  Even though I 
think I answered these concerns, I don’t mind to have another go at it.

Please find the updated proposal here (same link):

https://gist.github.com/andy-goryachev-oracle/294d8e4b3094fe16f8d55f6dd8b21c09<https://urldefense.com/v3/__https:/gist.github.com/andy-goryachev-oracle/294d8e4b3094fe16f8d55f6dd8b21c09__;!!ACWV5N9M2RV99hQ!MAhFywXruyvFlvk6whGVWBb9fTI-f1D-16YuJbRGdJe52rX503CFBK8S6IamyzPVzQBcJZmg6c_Jh1CfsDxVFw$>

Let me first define what I mean by “behavior” in the context of this proposal.  
A behavior is a translation layer between input events - coming either from the 
control, or from some nodes contained in the skin, or from the platform itself 
- into some actions.  These translation mappings are maintained by a new 
property in Control - the InputMap.  The InputMap has two sides - one for the 
user application, and another - for the skins/behaviors.  Both are “public 
APIs” but the latter is represented as protected methods of BehaviorBase class 
which forms a foundation of the behavior part of the skins that want to use the 
InputMap paradigm.

Back to individual concerns.

* We should not make anything related to Behaviors public without a full design 
of how Behaviors should work, what their responsibilities are, how they 
interact with Skins



And we don’t.  We recommend to use BehaviorBase, but it’s still possible to use 
event handlers or any other home-grown mechanism to implement skins/behaviors 
and suffer from the lack of functionality as a result.  If BehaviorBase is not 
the right name, we can call it InputMapAccessorForSkinUse any other name.

* This proposal doesn't solve the coupling of Skins and behaviors

The skins and behaviors are tightly coupled in some cases.  It is possible that 
a simple control such as Button does not require tight coupling, but a complex 
control such as TextArea does (see TextAreaSkin:1214).

With the InputMap, we now can separate user mappings from skin mappings and 
handlers.  Changing a skin will unregister all of the handlers added by the 
associated behavior, leaving the user mappings intact.

* Function tags are defined in control class, but don't match the functionality 
of control class
NOTE: this begs the question of whether there should always be a method on 
control for each such function (even if the implementation just delegates to 
the behavior



May be it was not described extensively, but it is being suggested to have one 
public method for each function tag, which does invoke the said tag.  This 
enabled indirection via InputMap which in turn allows the app- or skin- 
developer to redefine the functionality (in effect, allowing for changing the 
behavior without subclassing the behavior).

So, for example, SomeControl.copy() would invoke execute(TAG_COPY), which by 
default would invoke SomeControlBehavior.copy().

This proposal did not make this change for the subset of controls - 
intentionally - because it can be done later in a separate PR.

* An input map should not refer to the node and be stateless and sharable among 
all (or some) instances of the same class; this would mean mapping input events 
to Control::method rather than to instance::method or to some arbitrary lambda
NOTE: this would depend on the previous being resolved

I think we are confusing two things.  The InputMap allows for per-control 
mapping, so it cannot be shareable or static.  Period.

Now, the other thing is a possible requirement to allow for changing the 
mapping on per-control-type basis, to overwrite the behavior for each instance 
of a particular control.  This I did not address because it’s an implementation 
detail for that control type.  I did not want to add child maps, but perhaps we 
could add another API to the skin/behavior side of InputMap to allow for such a 
static map.

Personally, I don’t like the idea as it basically adds nothing: event handlers 
still need to be added to each control and each Node in the skin (if any) and 
there is an extra complexity added.  A better solution would be to subclass the 
control class and add the mappings for each instance just like we do today.

* Arbitrary key mapping seems out of scope for the core of JavaFX; this sort of 
mapping could be done by the application if the event order problem was solved, 
and if we had public API on control for all functions that are called by the 
behavior.

Arbitrary (user) key bindings are enabled by the proposed InputMap.  Any 
alternative proposal, in my opinion, should support this function out of the 
box.

* Should Input map be immutable?

The value of InputMap is ability to change the mapping, so I don’t understand 
where this requirement is coming from.  Perhaps an example or a use case could 
be provided?

* Changes to the Behavior system should focus on replacing complete behaviors, 
and being able to use these by default for a certain subset of controls (like 
-fx-skin provide in CSS)



As I mentioned earlier, the skin and its behavior might be tightly coupled.  So 
if a use case exists for changing the behavior, we already have a solution - a 
custom skin.  May be a use case or an example of why we can’t do that with the 
existing architecture would help here.

And finally, I would like to emphasize that even though the InputMap proposal 
is fairly well developed and validated using a number of non-trivial controls 
and some new controls (RichTextArea 
https://github.com/andy-goryachev-oracle/jfx/pull/1<https://urldefense.com/v3/__https:/github.com/andy-goryachev-oracle/jfx/pull/1__;!!ACWV5N9M2RV99hQ!MAhFywXruyvFlvk6whGVWBb9fTI-f1D-16YuJbRGdJe52rX503CFBK8S6IamyzPVzQBcJZmg6c_Jh1ACM9EGvA$>
 ), I am not against modifying/enhancing it based on the community feedback.  I 
hope we can get to a good solution in a reasonable time frame, or we all would 
have to learn react and program in javascript.

Cheers,
-andy





From: openjfx-dev <openjfx-dev-r...@openjdk.org> on behalf of Kevin Rushforth 
<kevin.rushfo...@oracle.com>
Date: Friday, October 27, 2023 at 16:34
To: openjfx-dev <openjfx-dev@openjdk.org>
Subject: Re: [Request for Comments] Behavior / InputMap
I've mostly caught up on the (lively) discussion surrounding this feature 
request.

It is clear that we do not yet have general agreement on the direction this 
proposal should take, so let's continue to discuss the proposal, its 
shortcomings, and any alternative approaches.

We should start by making sure that the motivation for doing this -- what 
problem is being solved -- is well understood. Andy will rework the initial 
sections of the proposal to make it more clear.

If I can summarize what I see are the main concerns that have been raised:

* We should not make anything related to Behaviors public without a full design 
of how Behaviors should work, what their responsibilities are, how they 
interact with Skins

* This proposal doesn't solve the coupling of Skins and behaviors

* Function tags are defined in control class, but don't match the functionality 
of control class
NOTE: this begs the question of whether there should always be a method on 
control for each such function (even if the implementation just delegates to 
the behavior

* An input map should not refer to the node and be stateless and sharable among 
all (or some) instances of the same class; this would mean mapping input events 
to Control::method rather than to instance::method or to some arbitrary lambda
NOTE: this would depend on the previous being resolved

* Arbitrary key mapping seems out of scope for the core of JavaFX; this sort of 
mapping could be done by the application if the event order problem was solved, 
and if we had public API on control for all functions that are called by the 
behavior.

* Should Input map be immutable?

* Changes to the Behavior system should focus on replacing complete behaviors, 
and being able to use these by default for a certain subset of controls (like 
-fx-skin provide in CSS)

There are probably other concerns as well.

Finally, one of the comments made, which I completely agree with, is that API 
design needs to come first. It needs to be fully fleshed out, and needs to be 
forward-looking. We should only expose as public API what is needed to solve 
the problem and no more.

Let's continue the discussion with this in mind.

-- Kevin



On 9/29/2023 3:44 PM, Andy Goryachev wrote:
Dear fellow JavaFX developers:

For some time now, we’ve been working to identify missing features in JavaFX 
that hinder application development.  We’ve been working on adding some of the 
missing features (for which we’ll have a separate announcement), but I feel 
that engaging wider community is a rather important part of the process.

I would like to share with you one such missing feature - ability to extend 
behavior of the existing components (and make the task of creating new 
components easier) by adding a public InputMap and BehaviorBase.

Please find the actual proposal here
https://gist.github.com/andy-goryachev-oracle/294d8e4b3094fe16f8d55f6dd8b21c09<https://urldefense.com/v3/__https:/gist.github.com/andy-goryachev-oracle/294d8e4b3094fe16f8d55f6dd8b21c09__;!!ACWV5N9M2RV99hQ!MAhFywXruyvFlvk6whGVWBb9fTI-f1D-16YuJbRGdJe52rX503CFBK8S6IamyzPVzQBcJZmg6c_Jh1CfsDxVFw$>

We are very much interested in your feedback.  Thank you in advance.

-andy

Reply via email to