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