[External] : Re: Proposal: Focus Traversal API
John Hendrikx
john.hendrikx at gmail.com
Tue Sep 24 21:51:14 UTC 2024
On 24/09/2024 20:53, Andy Goryachev wrote:
>
> Dear John:
>
> Now with the test sprint over, let me try to respond to your earlier
> questions (sorry for the delay!).
>
Looks like you guys did a lot of useful work in a short time. It's good
to see many tests being converted.
>
> > What is the point of TraversalEvent.NODE_TRAVERSED?
>
> My understanding it's an alternative to adding a
> TraversalEngine.TraverseListener in the original implementation.
>
> The main purpose, I think, is to notify the control of the fact that
> its child got focus.
>
> You might be right that it might be possible to replace the event by
> adding a listener to Scene.focusOwnerProperty, though it's likely to
> complicate the event handling machinery in the skins.
>
Yeah, I think this should not be part of the public API if it is to
handle some internal Skin problem. Events should be
consumable/filterable to prevent some action from occurring. This Event
would make sense if it initiated traversal, but instead only informs
about it.
>
> > What does it mean if I filter this event? What if I consume it?
>
> Current behavior of Skins that depend on it will break.
>
> Were there other questions? Please let me know.
>
Please have a look at https://bugs.openjdk.org/browse/JDK-8340852 -- I
think this should be fixed sooner rather than later, and will probably
simplify a traversal API implementation.
>
>
> Allow me to summarize various suggestions and ideas floated during the
> discussion:
>
> Additional problems:
>
> * existing problem of consuming events that had no effect on the
> control(s)
>
These should be fixed on a case by case basis yes.
>
> * priority of handling e.g. accelerators vs regular key events
>
Accelerators are handled by Scene with no way to get in between. That
sounds like a different topic altogether, and one I wouldn't be so sure
off you should be allowed to get in between. If there is some kind of
prioritized event handler system, then the user could potentially
intercept these by installing a handler with a higher priority.
Most of the issues I've had with keys being consumed too early is caused
by Controls directly installing navigational keys in their input maps,
instead of leaving them to bubble up to Scene. This is fine for
controls that have specific navigation needs, but currently all controls
do this or they would break when nested inside a ScrollPane (see
https://bugs.openjdk.org/browse/JDK-8340852).
> You proposed an alternative design which consists of
>
> * creating a new hierarchy of TraversalEvents
>
This probably won't work, I was looking for a real purpose for having a
TraversalEvent. I think it would be sufficient to give users tools on
Scene level to do the most common navigation options (ie. directional
and logical). Anything more custom just means that user can implement
this by doing their own node traversal (there is more than sufficient
information there to implement custom traversal strategies, beyond those
that we wish to provide out of the box with a simple
focusNext/Previous/Up/Down/Left/Right API).
I've dumbed down my idea to just fixing ScrollPane, and perhaps adding
some methods to Scene to trigger directional/logical navigation. That
should solve most concerns, with the left over niche cases probably
being so specific that it would require scanning the Scene graph to find
what Node you'd want to focus...
> The benefits of this idea are:
>
> * ability to completely customize traversal ("crazy custom navigation")
>
We don't need this, you can already do whatever crazy custom navigation
you want, we just need the standard navigation to be available easily
(and if ScrollPane bug is solved, then you get that completely free from
Scene for your custom control). More complex navigation can be handled
by calling methods on Scene in handlers. For example, here is a simple
navigation method that you can implement yourself in current FX:
/**
* Focuses the first focusable node under the given node.
*
* @paramnode a {@link Node}or child of the given node to give focus.
* @return<code>true</code>if focus was given, otherwise <code>false</code>
*/
publicstaticbooleanfocus(Node node) {
if(node instanceofParent p) {
for(Node child : p.getChildrenUnmodifiable()) {
if(focus(child)) {
returntrue;
}
}
}
if(node.isFocusTraversable() && !node.isDisabled() && node.isVisible()) {
node.requestFocus();
returntrue;
}
returnfalse;
}
Ideally, you shouldn't need to do yourself. It should be sufficient to
call a `focusNext` type method.
>
> * setting of traversal policies with CSS
>
I think this would be highly useful and so must be considered to be a
possibility. As explained in one of my replies, JavaFX CSS is not
limited to visual policies.
>
> Some additional issues were touched upon during the discussion:
>
> * ScrollPane consuming navigational keys
>
That's the big one IMHO. Fix that, and most problems are already
solved; the traversal API should see how much is still needed **after**
that problem is fixed.
>
> * some (ScrollPane, Spinner, TextField) control needlessly consume
> key events (see also _JDK-8320557)_
>
Yeah, we should just make PR's for those and get them fixed.
>
> * possible accessibility regression with ScrollPane
>
I didn't see this anywhere.
> Is this a complete list? Did I miss anything?
>
Looks pretty complete. Thanks.
--John
> -andy
>
> *From: *John Hendrikx <john.hendrikx at gmail.com>
> *Date: *Thursday, September 19, 2024 at 07:24
> *To: *Andy Goryachev <andy.goryachev at oracle.com>,
> openjfx-dev at openjdk.org <openjfx-dev at openjdk.org>
> *Subject: *Re: [External] : Re: Proposal: Focus Traversal API
>
> My apologies then, I was a bit impatient. Good luck with the test
> sprint then!
>
> --John
>
> On 18/09/2024 17:13, Andy Goryachev wrote:
>
> Oh, sorry, I did not mean to ignore your comments. I should have
> mentioned we are having a bi-annual "test sprint" and work
> exclusively on the test suite. You made a lot of good comments
> that require some thought and careful consideration, for which I
> simply had no spare CPU cycles last week or this week. Sorry,
> will definitely respond in detail early next week.
>
> -andy
>
> *From: *John Hendrikx <john.hendrikx at gmail.com>
> <mailto:john.hendrikx at gmail.com>
> *Date: *Tuesday, September 17, 2024 at 23:05
> *To: *Andy Goryachev <andy.goryachev at oracle.com>
> <mailto:andy.goryachev at oracle.com>, openjfx-dev at openjdk.org
> <openjfx-dev at openjdk.org> <mailto:openjfx-dev at openjdk.org>
> *Subject: *Re: [External] : Re: Proposal: Focus Traversal API
>
> Andy,
>
> As you're not responding to any of the suggestions or any of my
> questions, but are only re-iterating points that I believe are not
> going to be a benefit to the long term viability of FX, I see no
> point in continuing the discussion further.
>
> --John
>
> On 18/09/2024 01:09, Andy Goryachev wrote:
>
> Dear John:
>
> You do bring a lot of good points, no doubt. And I do agree
> with a lot of the suggestion, but I still want to emphasize
> two points:
>
> 1. The backward compatibility should not be dismissed that
> easily. There is a number of existing applications out there
> and we do not want to break them. Whether the behavior is
> specified or not is irrelevant, we do not want to cause mayhem
> from the customers and developers alike whose keyboard
> navigation suddenly changed.
>
> 2. I question the cost benefit analysis of the redesign idea.
> While I agree with you that it might help with some unusual
> cases, the overall benefit is rather limited. The benefit of
> the proposed solution is, in my opinion, far greater: it
> allows for custom traversal policies (a feature that has been
> requested multiple times) and enables focus traversal from
> custom components, something of a lesser value, but still
> important. Exposing the existing APIs is a relatively cheap
> solution that will give us two features at nearly zero cost.
> On the other hand, I doubt that our team, or yourself, are
> willing commit substantial development effort to redesign the
> thing to use events. Which brings me to the choice I
> mentioned earlier: realistically, we have a choice of
> providing two requested features soon, or never.
>
> I would also encourage other members of the development
> community to voice their opinion on the subject, perhaps there
> is something else we can do to move forward.
>
> Thank you
>
> -andy
>
> *From: *John Hendrikx <john.hendrikx at gmail.com>
> <mailto:john.hendrikx at gmail.com>
> *Date: *Saturday, September 14, 2024 at 09:41
> *To: *Andy Goryachev <andy.goryachev at oracle.com>
> <mailto:andy.goryachev at oracle.com>, openjfx-dev at openjdk.org
> <openjfx-dev at openjdk.org> <mailto:openjfx-dev at openjdk.org>
> *Subject: *[External] : Re: Proposal: Focus Traversal API
>
> Hi Andy,
>
> First let me say that when it comes to designing an API, you
> really need to take the time to think the solution through.
> The current internal solution was probably kept internal for
> exactly that reason, insufficient time to work out the kinks
> and look into alternatives.
>
> An API is almost impossible to change later, so the general
> rule is that if you're not sure about an API, then its better
> to have no API. This is why I think it is important that we
> first look for what the API should look like, then worry about
> how this can be fitted onto JavaFX. Making concessions
> related to the current implementation before having a clear
> idea of how the API should preferably work is not part of
> that. You start making concessions only when it turns out the
> preferred design would encounter unresolvable problems in the
> current implementation.
>
> Since I think there is very little public API related to focus
> traversal, nor is there any specification of how it currently
> works, I think we have a lot of room to maneuver. This is why
> I think we should first reach a consensus on the API, then
> look how it can be fitted on top of FX. Sometimes a well
> thought out API also is a natural fit, and may be easier to
> migrate to than you think.
>
> On 14/09/2024 00:17, Andy Goryachev wrote:
>
> Dear John, Everyone:
>
> Thank you for a thoughtful response! Some of the ideas
> you described definitely deserve further consideration.
> If I were to summarize:
>
> 1. move the focus traversal logic away from the components
> and into the Scene
>
> 2. re-implement focus traversal through TraversalEvents
> rather than responding directly to KeyEvents
>
> 3. (more) standard policies
>
> 4. using CSS
>
> (there is of course more topics in your response, but let
> me start with the 4 above)
>
> #1
>
> I generally like this idea. In some sense it is already
> how things work internally, but without the ability to
> customize that (i.e. by introducing custom traversal keys,
> or removing existing ones). The downside is substantial:
> not only we'd need to re-design the whole of the focus
> traversal, but also rework the existing control's
> behaviors. Did I mention the risk of regression, given
> the absence of comprehensive behavioral tests?
>
> There's two things here.
>
> 1. There is no need to re-design the whole focus traversal.
> The old internal system can be gradually replaced (it works by
> directly consuming KeyEvents after all).
>
> 2. Regression. When nothing is specified, and the fact that
> controls **ought** to work like other common controls in
> different UI toolkits, is it a regression when focus traversal
> works the same as those other platforms, even if it may be a
> regression from the point of view of FX? For example, a
> Spinner will currently react to any mouse key, where as other
> common toolkits only react to the left mouse button. Is it a
> regression if FX is adjusted to also only react to the left
> mouse button? It's not specified anywhere.
>
> I think we have sufficient space to maneuver here as long as
> we are not making focus traversal completely different from
> how it commonly works in UI's.
>
> Can there be regressions versus the current (unspecified)
> implementation? Sure, there can be. Is that necessarily
> bad? That depends. If the new focus traversal works like it
> does on all other toolkits, then no, it is more of a bug fix.
> Did we break something with the new implementation? That's
> always possible, but will then be fixed as soon as it is reported.
>
> #2
>
> This may or may not be an integral part of #1.
> Potentially, it allows for injection of events by the
> application code, as well as simplifies creation of
> complex custom controls. The latter becomes possible with
> the original proposal, so net benefit is limited to the
> first part, I think.
>
> I think TraversalEvents are quite central to making this an
> API that will really stand the test of time. It leverages the
> existing event system, giving you all the power that comes
> with it. You did not answer my question about the
> TraversalEvents in your design. Why are the Events when they
> can't be triggered, filtered or consumed?
>
> #3
>
> One obvious possibility is to enable creation of a simple
> policy based on a list of Nodes. I must mention one use
> case that is impossible to cover with pre-defined policy
> is one where navigation depends on some state. Such a
> policy must be implemented programmatically. I think one
> property should be sufficient - I am strongly against
> adding two properties here.
>
> Programmatic escapes can always be achieved by responding
> directly to a TraversalEvent. I think however this should be
> a rare case, and standard policies should really cover almost
> all use cases. It may be a gap that should be investigated,
> and the API adjusted for (usually the "exceptions" are well
> worth looking into to see if with a tweak they can't become
> "standard"). As for being "strongly against" having two
> properties -- that's an odd stance to take without motivating
> it. It could also be rolled into "one" where the Policy is a
> record with the two values, but I think we're getting ahead of
> ourselves here. First the API, then the implementation.
>
> I do think however there is great value in having the Logical
> and Directional navigation split. Often you'll only want to
> replace one of these with a custom policy (or a different
> standard policy), so that the other navigation method can be
> used to escape the control. For example, a Toolbar could be
> tabbed in an out of (using Logical navigation) while the
> Directional navigation is cyclic (and thus can't be used to
> escape the control's context).
>
> #4
>
> The idea of using CSS to specify traversal policy seems
> wrong to me: the CSS defines the presentation aspects
> (styles) rather than behavioral ones. I know it is
> possible to set custom skins and the corresponding
> behavior via CSS, and we know why (skins define the
> appearance), but we should not go beyond that, in my opinion.
>
> I see no problem styling such properties. They're FX
> properties, and it would be very convenient to style them to
> globally alter how focus works, instead of having to rely on,
> say, Builders or Factories for controls where traversal
> policies can be applied. There are also already properties
> that don't only influence the look of controls. "-fx-skin"
> being the most obvious one, but there is also
> "-fx-focus-traversable", "-fx-context-menu-enabled",
> "-fx-block-increment", "-fx-unit-increment", "-fx-pannable",
> "-fx-initial-delay", "-fx-repeat-delay", "-fx-collapsible",
> "-fx-show-delay", "-fx-show-duration", "-fx-hide-delay", and
> probably more. Aside from "-fx-skin" none of these properties
> have a visual impact, but instead alter behavior.
>
> Note: I'm not saying this needs to be there immediately. I
> just want to make sure we're not closing off this direction,
> as again, it would be a huge hassle to do this
> programmatically. In "code" the only things I usually do on
> my controls are the following:
>
> - I define the container hierarchy (VBox, HBox, which children
> go where)
> - I set a style name
> - I set anything that unfortunately cannot be CSS styled
> (things like ALWAYS, SOMETIMES, NEVER grow policies, Grid
> sizes, etc, things that are clearly "visual" but still can't
> be styled).
>
> All the rest I don't touch, or want to touch. Having to
> select a traversal policy for every control of type X I create
> is just cumbersome and unnecessary. There will be a call then
> to set this "globally", and then there will be the question,
> do we make something custom with many limitations because it
> doesn't fit our conceptions of what (FX) CSS is for (ie,
> not style, but only *visual* style) or do we just expose these
> properties as Styleable leveraging an existing powerful system
> with almost zero effort?
>
> --
>
> There is one more aspect of the problem that I think we
> should consider. The current proposal does not change the
> implementation in any material way, nor does it change the
> behavior, thus can be done quickly. The benefit everyone
> gets from it is ability to trigger focus traversal and to
> control it via custom policies. Any other solution will
> require resources and the bandwidth we currently don't
> have, which means the /probability/ of it being added to
> FX is virtually zero. Let me emphasize, I am not against
> attempting to discuss or implement the best possible
> solution, but we should be aware of the limitations of the
> reality we live in.
>
> "Quickly" and API's are incompatible with each other. There
> is nothing worse than exposing an API quickly, which then
> becomes a burden on the system -- I think the current CSS API
> is a prime example of where "quickly" has gone wrong, costing
> us tremendous amounts of effort to make even minor changes to it.
>
> I urge you to ignore the current implementation, think
> thoroughly how (in an ideal world) you would want such an API
> to work (from a user perspective, not from an implementor's
> perspective) and only then see how this could be made to fit
> into JavaFX.
>
> This is exactly what I did. I did not look at the
> implementation, although I'm aware of some of it. I looked at
> how I as a user of FX am building applications, the struggles
> I have with it currently, (with controls for example "eating"
> KeyEvents), and how I would like to be able to adjust focus
> traversal. Do I want to respond to "KeyCode.LEFT" or do I want
> to respond to "TraversalEvent.LEFT"? Do I also need to respond
> to "KeyCode.NUM_PAD_LEFT"? These things should be abstracted,
> and preferably I should just be able to choose from common
> navigation standards. And when I do want to change such a
> standard, in 99% of the cases that will be the case for all
> similar controls in my application. How do I do such things
> currently if I want to change something for all controls in my
> application? I use CSS.
>
> Also I think this can be implemented gradually. Here's a
> potential plan:
>
> 1. Have Scene listen to unused KeyEvents and translate them to
> TraversalEvents
>
> Benefit: gives custom controls a way to respond to keyboard
> based navigation in a platform agnostic way; this probably
> already removes the biggest roadblock for custom controls...
>
> Public API: Limited to a new Event
>
> 2. Start converting existing controls to listen to
> TraversalEvent instead of KeyEvent
>
> This hits a lot of controls, but should be relatively easy to
> do, and it can be all kept internal for now. It can be done
> in a few batches.
>
> Benefit: for each control converted, user can now
> programmatically trigger focus changes, and by overriding
> things at Scene level can completely change navigation keys
>
> Public API: none
>
> 3. Implement a number of standard policies internally (OPEN,
> CONFINED, CYCLIC, IGNORED)
>
> Convert any controls that could use these as their default,
> removing any custom logic if it happens to match one of the
> defaults.
>
> Benefit: less code to maintain and debug, gives us experience
> with which policies make sense and where the gaps are
>
> Public API: none
>
> Order: It is possible to do this before 2, and so some of the
> control conversions could just consist of removing their
> custom logic, and selecting a standard policy.
>
> 4. Expose policy property/properties on Parent
>
> Any controls that are not using a custom policy anymore (of
> type IGNORED) can now be user adjusted. We don't have to
> guarantee that each policy makes sense for each control.
> Changing a default IGNORED policy to a standard one will
> change the behavior (as intended) but it need not be a
> "complete" behavior that users like. This is not FX's
> problem, and can be improved upon later.
>
> Benefit: users can now change policies on any existing
> control, even ones with a custom policy; many of the controls
> may support a switch between OPEN, CONFINED and CYCLIC out of
> the box.
>
> Public API: new properties on Parent
>
> 5. Perhaps expose some helpful tools to calculate the "next"
> Node for a given traversal option.
>
> This can be done at any stage, and can be considered
> completely separate. It is IMHO a relatively low priority need.
>
> Benefit: less work for control implementors (although they
> could just "copy" said code)
>
> Public API: Maybe some methods in Node, or some kind of static
> helper.
>
> 6. CSS styleable properties
>
> If we really want to give power to our users, and impress them
> with a flexible focus traversal API, then make these
> properties styleable.
>
> Benefit: allow users to pick any control, and set is policy
> globally or within a subset of controls (ie. dialogs, popups,
> etc).
>
> Public API: Nothing in Java, but document as CSS properties
>
> --John
>
> Thank you,
>
> -andy
>
> *From: *openjfx-dev <openjfx-dev-retn at openjdk.org>
> <mailto:openjfx-dev-retn at openjdk.org> on behalf of John
> Hendrikx <john.hendrikx at gmail.com>
> <mailto:john.hendrikx at gmail.com>
> *Date: *Wednesday, September 11, 2024 at 19:05
> *To: *openjfx-dev at openjdk.org <openjfx-dev at openjdk.org>
> <mailto:openjfx-dev at openjdk.org>
> *Subject: *Re: Proposal: Focus Traversal API
>
> Hi Andy / List,
>
> I've given this some thought first, without looking too
> much at the proposal.
>
> In my view, focus traversal should be implemented using
> events, and FX should provide standard handling of these
> events controlled with properties (potentially even CSS
> stylable for easy mass changing of the default navigation
> policy).
>
> ## KeyEvent and TraversalEvent separation
>
> I think the cleanest implementation would be to implement
> a KeyEvent listener on Scene that takes any unused
> KeyEvents, checks if they're considered navigation keys,
> and converts these keys to a new type of event, the
> TraversalEvent. The TraversalEvent is then fired at the
> original target. The TraversalEvent is structured into
> Directional and Logical sub types, and has leaf types
> UP/DOWN/LEFT/RIGHT and NEXT/PREVIOUS. Scene is the
> logical place to handle this as without a Scene there is
> no focus owner, and so there is no point in doing focus
> traversal.
>
> This separation of KeyEvents into TraversalEvents achieves
> the following:
>
> - User can decide to act on **any** key, even navigation
> keys, without the system interfering by consuming keys
> early, unexpectedly or even consuming these keys without
> doing anything (sometimes keys get consumed that don't
> actually change focus...). The navigation keys have many
> possible dual purposes, and robbing the user of the
> opportunity to use them due to an overzealous component
> interpreting them as traversal keys is very annoying.
> Dual purposes include for example cursor control in
> TextField/TextArea, Scrollbars, etc. The user should have
> the same control here as these FX controls have.
>
> - Scene is interpreting the KeyEvents, and this
> interpretation is now controllable. If I want a Toolbar
> (or the whole application) to react to WASD navigation
> keys, then installing a KeyEvent handler at Scene level or
> at any intermediate Parent level that converts WASD to
> UP/LEFT/DOWN/RIGHT Traversal events would affect this
> change easily.
>
> - The separation also allows to block Focus Traversal
> only, without blocking the actual Keys involved. If I
> want to stop a Toolbar from reacting to LEFT/RIGHT, but I
> need those keys higher up in the hierarchy, then I'm
> screwed. With the separation, the key events are
> unaffected, and I can block Toolbars from reacting
> specifically to traversal events only.
>
> ## Traversal Policy Properties on Parent
>
> I think FX should provide several policies out of the box,
> based on common navigation patterns. The goal here is to
> have policies in place that cover all use cases in current
> FX provided controls. This will provide a good base that
> will cover probably all realistic work loads that custom
> controls may have. The goal is not to support every
> esoteric form of navigation, instead an escape hatch will
> be provided in the form of disabling the standard navigation.
>
> In order to achieve this, I think Parent should get two
> new properties, which control how it will react to
> Directional and Logical navigation. These will have
> default values that allow navigation to flow from Node to
> Node within a Parent and from Parent to its Parent when
> navigation options in a chosen direction are exhausted
> within a Parent. Custom controls like Combo boxes,
> Toolbars, Button groups, etc, can change the default
> provided by a Parent (similar to how some controls change
> the mouse transparent flag default).
>
> These two properties should cover all realistic needs, and
> IMHO should be considered to be CSS stylable in the future
> to allow easy changing of default policies of controls
> (ie. want all Toolbars to react differently to navigation
> keys, then just style the appropriate property for all
> toolbars in one go).
>
> Parent will use these properties to install an event
> handler that reacts to TraversalEvents (not KeyEvents).
> This handler can be fully disabled, or overridden (using
> setOnTraversalEvent).
>
> - logicalTraversalPolicy
> - directionalTraversalPolicy
>
> The properties can be set with a value from a
> TraversalPolicy enum. I would suggest the following options:
>
> - OPEN
>
> This policy should be the default policy for all Parents.
> It will act and consume a given TraversalEvent only when
> there is a suitable target within its hierarchy. If there
> is no suitable target, or the target would remain
> unchanged, the event is NOT consumed and left to bubble
> up, allowing its parent(s) to act on it instead.
>
> - CONFINED
>
> This policy consumes all TraversalEvents, regardless of
> whether there is something to navigate to or not. This
> policy is suitable for controls that have some kind of
> substructure that we don't want to accidentally exit with
> either Directional or Logical navigation. In most cases,
> you only want to set one of the properties to CONFINED as
> otherwise there would be no keyboard supported way to exit
> your control. This is a suitable policy for say button
> groups, toolbars, comboboxes, etc.
>
> - CYCLIC
>
> Similar to CONFINED but instead of stopping navigation at
> the controls logical boundaries, the navigation wraps
> around to the logical start. For example, when were
> positioned on the right most button in a button group,
> pressing RIGHT again would navigate to the left most button.
>
> - IGNORED
>
> This is similar to the mouseTransparent property, and
> basically leaves the TraversalEvent to bubble up. This
> policy allows you to completely disable directional and/or
> logical navigation for a control. Useful if you want to
> install your own handler (the escape hatch) but still want
> to keep either the default directional or logical navigation.
>
> Possible other options for this enum could include a
> version that consumes all TraversalEvents (BLOCK) but I
> don't see a use for it at the moment. There may also be
> variants of CONFINED and CYCLIC that make an exception for
> cases where there is only a single choice available. A
> ButtonGroup for example may want to react differently
> depending on whether it has 0, 1 or more buttons. Whether
> these should be enshrined with a custom enum value, or
> perhaps a flag, or just left up to a custom implementation
> is something we'd need to decide still.
>
> ## Use Cases
>
> 1) User wants to change the behavior of a control from its
> default to something else (ie. a Control that is CYCLIC
> can be changed to OPEN or CONFINED)
>
> Just call the setters with the appropriate preferred
> policy. This could be done in CSS for maximum convenience
> to enable a global change of all similar controls.
>
> 2) User wants to act on Traversal events that the standard
> policy leaves to bubble up
>
> Just install a Traversal event handler either on the
> control or on its parent (depending on their needs). A
> potential action to an unused Traversal event could be to
> close a Dialog/Toast popup, or a custom behavior like
> selecting the first/last item or next/previous row (ie. if
> I press "RIGHT" and there is no further right item, a user
> could decide to have this select the first item again in
> the current Row or the first item in the **next** Row).
>
> 3) User wants to do crazy custom navigation
>
> Set both policies to IGNORED, then install your own event
> handler (or use the setOnTraversalHandler to completely
> override the handler). Now react on the Traversal events,
> consuming them at will and changing focus to whatever
> control you desire.
>
> 4) User wants to change what keys are considered
> navigation keys
>
> Install event handler on Scene (or any intermediate
> Parent) for KeyEvents, interpret WASD keys as
> UP/LEFT/DOWN/RIGHT and sent out a corresponding Traversal
> event
>
> 5) User wants to use keys that are considered navigation
> keys for their own purposes
>
> Just install a KeyEvent handler as usual, without having
> to worry that Skins/Controls eat these events before you
> can get to them
>
> 6) User wants to stop a control from reacting to traversal
> events, without filtering navigation keys completely
>
> With the separation of unconsumed KeyEvents into
> TraversalEvents, a user can now block only the latter to
> achieve this goal without having to blanket block certain
> KeyEvents.
>
> -----
>
> About the Proposal:
>
> I think the Goals are fine as stated, although I think we
> differ on what the Traversal events signify.
>
> I think CSS support should be considered a possible future
> goal. The proposal should therefore take into account
> that we may want to offer this in the future.
>
> Motivation looks okay.
>
> > The focus traversal is provided by the FocusTraversal
> class which offers static methods for traversing focus in
> various directions, determined by the TraversalDirection enum.
>
> I think these methods don't need to be exposed with a good
> selection of standard TraversalPolicy options. After all,
> there are only so many ways that you can do a sensible
> navigation action without confusing the user, and
> therefore I think these policy options will cover 99% of
> the use cases already. For the left over 1% we could
> **consider** providing these focus traversal functions as
> a separate public API, but I would have them return the
> Node they would suggest, and leave the final decision to
> call requestFocus up to the caller. Initially however I
> think there is already more than enough power for custom
> implementations to listen to Traversal events and do their
> own custom navigation. If it is not similar to one of the
> standard navigation options, the traverseUp/Down functions
> won't be of much use then anyway.
>
> About your typical example:
>
> Node from = ...
> switch (((KeyEvent)event).getCode()) {
> case UP:
> FocusTraversal.traverse(from, TraversalDirection.UP,
> TraversalMethod.KEY);
> event.consume();
> break;
> case DOWN:
> // or use the convenience method
> FocusTraversal.traverseDown(from);
> event.consume();
> break;
> }
>
> I think this is not a good way to deal with events.
>
> 1) The event is consumed regardless of the outcome of
> traverse. What if focus did not change? Should the event
> be consumed?
>
> 2) This is consuming KeyEvents directly, robbing the user
> of the opportunity to act on keys considered "special" by FX.
>
> 3) This code is not only consuming KeyEvents directly, but
> also deciding what keys are navigation keys.
>
> So I think this example code should be different. However,
> first I expect that in most cases, configuring a different
> traversal policy on your Parent subclass will already be
> sufficient in almost all cases (especially if we look at
> FX current controls and see if the suggested policies
> would cover those use cases). So this code will almost
> never be needed. However, in the event that you need
> something even more specific, you may consider handling
> Traversal events directly. In which case the code should
> IMHO look something like this:
>
> Node from = ...
>
> Node result = switch(traversalEvent.getEventType()) {
> case TraversalEvent.UP -> FocusTraversals.findUp(from);
> case TraversalEvent.DOWN ->
> FocusTraversals.findDown(from);
> // etc
> }
>
> if (result != null) {
> result.requestFocus();
> traversalEvent.consume();
> }
>
> Note that the above code leaves the final decision to call
> requestFocus up to the caller. It also allows the caller
> to distinguish between the case where there is no suitable
> Node in the indicated direction and act accordingly.
>
> This allows it to NOT consume the event if it prefers its
> Parent to handle it (if the control doesn't want CYCLIC or
> CONFINED style navigation). It also allows it to further
> scrutinize the suggested Node, and if it decides it does
> not like it (due to some property or CSS style or
> whatever) it may follow up with another findXXX call or
> some other option to pick the Node it wants. It also
> allows (in the case of no Node being found) to pick its
> own preferred Node in those cases. In other words, it is
> just far more flexible.
>
> I'm not sure yet where to place these static helper
> methods (if we decide to expose them at all initially), or
> even if they should be static. Given that its first
> parameter is always a Node, a non-static location for them
> could simply be on Node itself, in which case the calling
> convention would become "Node result =
> from.findTraversableUp()" (suggested name only)
>
> > Focus traversals generate a new type of event,
> encapsulated by the class TraversalEvent which extends
> javafx.event.Event, using the event type
> TraversalEvent.NODE_TRAVERSED.
>
> What is the point of this event? If you want to know that
> focus changed, you can add a listener to
> Scene.focusOwnerProperty. What does it mean if I filter
> this event? What if I consume it? I don't think this
> should be an event at all, unless implemented as I
> suggested above, where consuming/filtering/bubbling can be
> used to control how controls will react to navigation events.
>
> --John
>
> On 03/09/2024 21:33, Andy Goryachev wrote:
>
> Dear fellow developers:
>
> I'd like to propose the public focus traversal API:
>
> https://github.com/andy-goryachev-oracle/Test/blob/main/doc/FocusTraversal/FocusTraversal.md
> <https://urldefense.com/v3/__https:/github.com/andy-goryachev-oracle/Test/blob/main/doc/FocusTraversal/FocusTraversal.md__;!!ACWV5N9M2RV99hQ!LnjDXwUbbEymf9b1gkZFia8vuewsVJy6_49It-IKw66U9mS78PjdIPotBpc7AXlSfY7N5xcRXsmcPQhOzavk4z9VkPv-$>
>
> Draft PR:
>
> https://github.com/openjdk/jfx/pull/1555
> <https://urldefense.com/v3/__https:/github.com/openjdk/jfx/pull/1555__;!!ACWV5N9M2RV99hQ!LnjDXwUbbEymf9b1gkZFia8vuewsVJy6_49It-IKw66U9mS78PjdIPotBpc7AXlSfY7N5xcRXsmcPQhOzavk49fH_P2p$>
>
> Your comments and suggestions will be warmly accepted
> and appreciated.
>
> Thank you
>
> -andy
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://mail.openjdk.org/pipermail/openjfx-dev/attachments/20240924/41bc8d4a/attachment-0001.htm>
More information about the openjfx-dev
mailing list