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 <[email protected]>
> Date: Monday, October 30, 2023 at 17:24
> To: Andy Goryachev <[email protected]>
> Cc: Kevin Rushforth <[email protected]>, openjfx-dev
> <[email protected]>
> 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 <[email protected]> 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 <[email protected]> on behalf of Kevin Rushforth
> <[email protected]>
> Date: Friday, October 27, 2023 at 16:34
> To: openjfx-dev <[email protected]>
> 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