<html xmlns:o="urn:schemas-microsoft-com:office:office" xmlns:w="urn:schemas-microsoft-com:office:word" xmlns:m="http://schemas.microsoft.com/office/2004/12/omml" xmlns="http://www.w3.org/TR/REC-html40">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<meta name="Generator" content="Microsoft Word 15 (filtered medium)">
<style><!--
/* Font Definitions */
@font-face
        {font-family:"Cambria Math";
        panose-1:2 4 5 3 5 4 6 3 2 4;}
@font-face
        {font-family:"Yu Gothic";
        panose-1:2 11 4 0 0 0 0 0 0 0;}
@font-face
        {font-family:Aptos;
        panose-1:2 11 0 4 2 2 2 2 2 4;}
@font-face
        {font-family:"Iosevka Fixed SS16";
        panose-1:2 0 5 9 3 0 0 0 0 4;}
@font-face
        {font-family:"Times New Roman \(Body CS\)";
        panose-1:2 11 6 4 2 2 2 2 2 4;}
@font-face
        {font-family:"\@Yu Gothic";
        panose-1:2 11 4 0 0 0 0 0 0 0;}
@font-face
        {font-family:Optima-Regular;
        panose-1:2 0 5 3 6 0 0 2 0 4;}
/* Style Definitions */
p.MsoNormal, li.MsoNormal, div.MsoNormal
        {margin:0in;
        font-size:10.0pt;
        font-family:"Aptos",sans-serif;}
a:link, span.MsoHyperlink
        {mso-style-priority:99;
        color:blue;
        text-decoration:underline;}
span.apple-converted-space
        {mso-style-name:apple-converted-space;}
span.outlook-search-highlight
        {mso-style-name:outlook-search-highlight;}
span.EmailStyle21
        {mso-style-type:personal-reply;
        font-family:"Iosevka Fixed SS16";
        color:windowtext;}
.MsoChpDefault
        {mso-style-type:export-only;
        font-size:10.0pt;
        mso-ligatures:none;}
@page WordSection1
        {size:8.5in 11.0in;
        margin:1.0in 1.0in 1.0in 1.0in;}
div.WordSection1
        {page:WordSection1;}
--></style>
</head>
<body lang="EN-US" link="blue" vlink="purple" style="word-wrap:break-word;line-break:after-white-space">
<div class="WordSection1">
<p class="MsoNormal"><span style="font-size:11.0pt;font-family:"Iosevka Fixed SS16"">I fully agree with Martin here.<o:p></o:p></span></p>
<p class="MsoNormal"><span style="font-size:11.0pt;font-family:"Iosevka Fixed SS16""><o:p> </o:p></span></p>
<p class="MsoNormal"><span style="font-size:11.0pt;font-family:"Iosevka Fixed SS16"">-andy<o:p></o:p></span></p>
<p class="MsoNormal"><span style="font-size:11.0pt;font-family:"Iosevka Fixed SS16""><o:p> </o:p></span></p>
<div id="mail-editor-reference-message-container">
<div>
<div>
<div style="border:none;border-top:solid #B5C4DF 1.0pt;padding:3.0pt 0in 0in 0in">
<p class="MsoNormal" style="margin-bottom:12.0pt"><b><span style="font-size:12.0pt;color:black">From:
</span></b><span style="font-size:12.0pt;color:black">Martin Fox <martin@martinfox.com><br>
<b>Date: </b>Wednesday, September 18, 2024 at 11:49<br>
<b>To: </b>John Hendrikx <john.hendrikx@gmail.com><br>
<b>Cc: </b>Andy Goryachev <andy.goryachev@oracle.com>, OpenJFX <openjfx-dev@openjdk.org><br>
<b>Subject: </b>Re: [External] : Re: Proposal: Focus Traversal API<o:p></o:p></span></p>
</div>
<p class="MsoNormal"><span style="font-size:12.0pt">John,<o:p></o:p></span></p>
<div>
<p class="MsoNormal"><span style="font-size:12.0pt"><o:p> </o:p></span></p>
</div>
<div>
<p class="MsoNormal"><span style="font-size:12.0pt">Sorry I didn’t respond to this thread earlier. I’ve been looking at the code and bug database trying to work backward to a problem statement. The bug reports cited in the PR are light on details so I’m trying
 to come up with a more concrete set of use cases to consider.<o:p></o:p></span></p>
</div>
<div>
<p class="MsoNormal"><span style="font-size:12.0pt"><o:p> </o:p></span></p>
</div>
<div>
<p class="MsoNormal"><span style="font-size:12.0pt">Currently I’m failing to see the benefit of a traversal event model.<o:p></o:p></span></p>
<div>
<p class="MsoNormal"><span style="font-size:12.0pt"><o:p> </o:p></span></p>
</div>
<div>
<blockquote style="margin-top:5.0pt;margin-bottom:5.0pt">
<div>
<div id="mail-editor-reference-message-container">
<blockquote style="margin-top:5.0pt;margin-bottom:5.0pt">
<div id="mail-editor-reference-message-container">
<p><span style="font-family:Optima-Regular">- 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...). <o:p></o:p></span></p>
</div>
</blockquote>
</div>
</div>
</blockquote>
<div>
<p class="MsoNormal"><span style="font-size:12.0pt">It doesn’t really matter whether the control is capturing the key event and invoking the traversal engine directly or firing off a TraversalEvent. The problem is that the control is processing the key event
 in the first place. You’re talking about something that happens before traversal is even initiated.<o:p></o:p></span></p>
</div>
<div>
<p class="MsoNormal"><span style="font-size:12.0pt"><o:p> </o:p></span></p>
</div>
<div>
<p class="MsoNormal"><span style="font-size:12.0pt">It’s unfortunate that the code snippet in the proposal shows a control doing a direct mapping from KeyCodes to traversal calls. That’s not how the current system is intended to work. There’s already a dispatcher
 at the Scene level that processes KeyEvents and invokes the traversal machinery so controls should just let the traversal keys bubble up. There are exceptions to this throughout the code which I would like to get a better handle on since I can’t tell if they’re
 bugs or truly necessary exceptions.<o:p></o:p></span></p>
</div>
<div>
<p class="MsoNormal"><span style="font-size:12.0pt"><o:p> </o:p></span></p>
</div>
<div>
<p class="MsoNormal"><span style="font-size:12.0pt">Once the system has determined that it’s time for traversal it needs to map from a KeyEvent to a direction and type. I can see where providing a centralized API for doing this could be of benefit but I’m not
 sure that has anything to do with this PR or the concept of TraversalEvents. This is also a decision made before traversal is initiated.<o:p></o:p></span></p>
</div>
<div>
<p class="MsoNormal"><span style="font-size:12.0pt"><o:p> </o:p></span></p>
</div>
<div>
<p class="MsoNormal"><span style="font-size:12.0pt">You give some examples of customizing traversal in various ways. From what I can tell all of them can be accomplished using this PR with maybe one exception that I’ll get to when I respond to Andy’s proposal.
 In other cases I can’t tell if a TraversalEvent would provide a cleaner implementation because I don’t understand how they would work. For example, one could imagine a system where a TraversalEvent is fired by the Scene and expected to bubble back up to the
 Scene which will then utilize the existing centralized engines to actually perform the traversal. But one could also imagine a system where the Scene fires a TraversalEvent and the nodes act on them directly as it bubbles up. I’m not sure what you have in
 mind. It would be nice to see some examples of how a TraversalEvent would move through the system in various scenarios particularly when traversing laterally.<o:p></o:p></span></p>
</div>
<div>
<div>
<p><span style="font-family:Optima-Regular">Martin<o:p></o:p></span></p>
</div>
</div>
<blockquote style="margin-top:5.0pt;margin-bottom:5.0pt">
<div>
<p class="MsoNormal"><span style="font-size:12.0pt">On Sep 17, 2024, at 11:05</span><span style="font-size:12.0pt;font-family:"Arial",sans-serif"> </span><span style="font-size:12.0pt">PM, John Hendrikx <john.hendrikx@gmail.com> wrote:<o:p></o:p></span></p>
</div>
<p class="MsoNormal"><span style="font-size:12.0pt"><o:p> </o:p></span></p>
<div>
<p style="font-variant-caps:normal;text-align:start;word-spacing:0px"><span style="font-size:10.5pt;font-family:Optima-Regular">Andy,<o:p></o:p></span></p>
<p style="font-variant-caps:normal;text-align:start;word-spacing:0px"><span style="font-size:10.5pt;font-family:Optima-Regular">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.<o:p></o:p></span></p>
<p style="font-variant-caps:normal;text-align:start;word-spacing:0px"><span style="font-size:10.5pt;font-family:Optima-Regular">--John<o:p></o:p></span></p>
<div>
<p class="MsoNormal"><span style="font-size:10.5pt;font-family:Optima-Regular">On 18/09/2024 01:09, Andy Goryachev wrote:<o:p></o:p></span></p>
</div>
<blockquote style="margin-top:5.0pt;margin-bottom:5.0pt;font-variant-caps:normal;orphans:auto;text-align:start;widows:auto;word-spacing:0px">
<div>
<div>
<p class="MsoNormal"><span style="font-size:11.0pt;font-family:"Iosevka Fixed SS16"">Dear John:</span><span style="font-size:12.0pt"><o:p></o:p></span></p>
</div>
<div>
<p class="MsoNormal"><span style="font-size:11.0pt;font-family:"Iosevka Fixed SS16""> </span><span style="font-size:12.0pt"><o:p></o:p></span></p>
</div>
<div>
<p class="MsoNormal"><span style="font-size:11.0pt;font-family:"Iosevka Fixed SS16"">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:</span><span style="font-size:12.0pt"><o:p></o:p></span></p>
</div>
<div>
<p class="MsoNormal"><span style="font-size:11.0pt;font-family:"Iosevka Fixed SS16""> </span><span style="font-size:12.0pt"><o:p></o:p></span></p>
</div>
<div>
<p class="MsoNormal"><span style="font-size:11.0pt;font-family:"Iosevka Fixed SS16"">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.</span><span style="font-size:12.0pt"><o:p></o:p></span></p>
</div>
<div>
<p class="MsoNormal"><span style="font-size:11.0pt;font-family:"Iosevka Fixed SS16""> </span><span style="font-size:12.0pt"><o:p></o:p></span></p>
</div>
<div>
<p class="MsoNormal"><span style="font-size:11.0pt;font-family:"Iosevka Fixed SS16"">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.</span><span style="font-size:12.0pt"><o:p></o:p></span></p>
</div>
<div>
<p class="MsoNormal"><span style="font-size:11.0pt;font-family:"Iosevka Fixed SS16""> </span><span style="font-size:12.0pt"><o:p></o:p></span></p>
</div>
<div>
<p class="MsoNormal"><span style="font-size:11.0pt;font-family:"Iosevka Fixed SS16"">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.</span><span style="font-size:12.0pt"><o:p></o:p></span></p>
</div>
<div>
<p class="MsoNormal"><span style="font-size:11.0pt;font-family:"Iosevka Fixed SS16""> </span><span style="font-size:12.0pt"><o:p></o:p></span></p>
</div>
<div>
<p class="MsoNormal"><span style="font-size:11.0pt;font-family:"Iosevka Fixed SS16"">Thank you</span><span style="font-size:12.0pt"><o:p></o:p></span></p>
</div>
<div>
<p class="MsoNormal"><span style="font-size:11.0pt;font-family:"Iosevka Fixed SS16"">-andy</span><span style="font-size:12.0pt"><o:p></o:p></span></p>
</div>
<div>
<p class="MsoNormal"><span style="font-size:11.0pt;font-family:"Iosevka Fixed SS16""> </span><span style="font-size:12.0pt"><o:p></o:p></span></p>
</div>
<div>
<p class="MsoNormal"><span style="font-size:11.0pt;font-family:"Iosevka Fixed SS16""> </span><span style="font-size:12.0pt"><o:p></o:p></span></p>
</div>
<div id="mail-editor-reference-message-container">
<div>
<div>
<div style="border:none;border-top:solid windowtext 1.0pt;padding:3.0pt 0in 0in 0in;border-color:currentcolor currentcolor">
<p class="MsoNormal" style="margin-bottom:12.0pt"><b><span style="font-size:12.0pt">From:<span class="apple-converted-space"> </span></span></b><span style="font-size:12.0pt">John Hendrikx<span class="apple-converted-space"> </span><a href="mailto:john.hendrikx@gmail.com"><span style="color:#467886"><john.hendrikx@gmail.com></span></a><br>
<b>Date:<span class="apple-converted-space"> </span></b>Saturday, September 14, 2024 at 09:41<br>
<b>To:<span class="apple-converted-space"> </span></b>Andy Goryachev<span class="apple-converted-space"> </span><a href="mailto:andy.goryachev@oracle.com"><span style="color:#467886"><andy.goryachev@oracle.com></span></a>,<span class="apple-converted-space"> </span><a href="mailto:openjfx-dev@openjdk.org"><span style="color:#467886">openjfx-dev@openjdk.org</span></a><span class="apple-converted-space"> </span><a href="mailto:openjfx-dev@openjdk.org"><span style="color:#467886"><openjfx-dev@openjdk.org></span></a><br>
<b>Subject:<span class="apple-converted-space"> </span></b>[External] : Re: Proposal: Focus Traversal API<o:p></o:p></span></p>
</div>
<p><span style="font-size:10.5pt;font-family:Optima-Regular">Hi Andy,<o:p></o:p></span></p>
<p><span style="font-size:10.5pt;font-family:Optima-Regular">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.<o:p></o:p></span></p>
<p><span style="font-size:10.5pt;font-family:Optima-Regular">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.<o:p></o:p></span></p>
<p><span style="font-size:10.5pt;font-family:Optima-Regular">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.<o:p></o:p></span></p>
<div>
<div>
<p class="MsoNormal"><span style="font-size:12.0pt">On 14/09/2024 00:17, Andy Goryachev wrote:<o:p></o:p></span></p>
</div>
</div>
<blockquote style="margin-top:5.0pt;margin-bottom:5.0pt">
<div>
<div>
<p class="MsoNormal"><span style="font-size:11.0pt;font-family:"Iosevka Fixed SS16"">Dear John, Everyone:</span><span style="font-size:12.0pt"><o:p></o:p></span></p>
</div>
<div>
<p class="MsoNormal"><span style="font-size:11.0pt;font-family:"Iosevka Fixed SS16""> </span><span style="font-size:12.0pt"><o:p></o:p></span></p>
</div>
<div>
<p class="MsoNormal"><span style="font-size:11.0pt;font-family:"Iosevka Fixed SS16"">Thank you for a thoughtful response!  Some of the ideas you described definitely deserve further consideration.  If I were to summarize:</span><span style="font-size:12.0pt"><o:p></o:p></span></p>
</div>
<div>
<p class="MsoNormal"><span style="font-size:11.0pt;font-family:"Iosevka Fixed SS16""> </span><span style="font-size:12.0pt"><o:p></o:p></span></p>
</div>
<div>
<p class="MsoNormal"><span style="font-size:11.0pt;font-family:"Iosevka Fixed SS16"">1. move the focus traversal logic away from the components and into the Scene</span><span style="font-size:12.0pt"><o:p></o:p></span></p>
</div>
<div>
<p class="MsoNormal"><span style="font-size:11.0pt;font-family:"Iosevka Fixed SS16"">2. re-implement focus traversal through TraversalEvents rather than responding directly to KeyEvents</span><span style="font-size:12.0pt"><o:p></o:p></span></p>
</div>
<div>
<p class="MsoNormal"><span style="font-size:11.0pt;font-family:"Iosevka Fixed SS16"">3. (more) standard policies</span><span style="font-size:12.0pt"><o:p></o:p></span></p>
</div>
<div>
<p class="MsoNormal"><span style="font-size:11.0pt;font-family:"Iosevka Fixed SS16"">4. using CSS</span><span style="font-size:12.0pt"><o:p></o:p></span></p>
</div>
<div>
<p class="MsoNormal"><span style="font-size:11.0pt;font-family:"Iosevka Fixed SS16""> </span><span style="font-size:12.0pt"><o:p></o:p></span></p>
</div>
<div>
<p class="MsoNormal"><span style="font-size:11.0pt;font-family:"Iosevka Fixed SS16"">(there is of course more topics in your response, but let me start with the 4 above)</span><span style="font-size:12.0pt"><o:p></o:p></span></p>
</div>
<div>
<p class="MsoNormal"><span style="font-size:11.0pt;font-family:"Iosevka Fixed SS16""> </span><span style="font-size:12.0pt"><o:p></o:p></span></p>
</div>
<div>
<p class="MsoNormal"><span style="font-size:11.0pt;font-family:"Iosevka Fixed SS16"">#1</span><span style="font-size:12.0pt"><o:p></o:p></span></p>
</div>
<div>
<p class="MsoNormal"><span style="font-size:11.0pt;font-family:"Iosevka Fixed SS16""> </span><span style="font-size:12.0pt"><o:p></o:p></span></p>
</div>
<div>
<p class="MsoNormal"><span style="font-size:11.0pt;font-family:"Iosevka Fixed SS16"">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?</span><span style="font-size:12.0pt"><o:p></o:p></span></p>
</div>
</div>
</blockquote>
<p><span style="font-size:10.5pt;font-family:Optima-Regular">There's two things here.<o:p></o:p></span></p>
<p><span style="font-size:10.5pt;font-family:Optima-Regular">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).<o:p></o:p></span></p>
<p><span style="font-size:10.5pt;font-family:Optima-Regular">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.<o:p></o:p></span></p>
<p><span style="font-size:10.5pt;font-family:Optima-Regular">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.<o:p></o:p></span></p>
<div>
<p class="MsoNormal" style="margin-bottom:12.0pt"><span style="font-size:12.0pt">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.<o:p></o:p></span></p>
</div>
<blockquote style="margin-top:5.0pt;margin-bottom:5.0pt">
<div>
<div>
<p class="MsoNormal"><span style="font-size:11.0pt;font-family:"Iosevka Fixed SS16""> </span><span style="font-size:12.0pt"><o:p></o:p></span></p>
</div>
<div>
<p class="MsoNormal"><span style="font-size:11.0pt;font-family:"Iosevka Fixed SS16"">#2</span><span style="font-size:12.0pt"><o:p></o:p></span></p>
</div>
<div>
<p class="MsoNormal"><span style="font-size:11.0pt;font-family:"Iosevka Fixed SS16""> </span><span style="font-size:12.0pt"><o:p></o:p></span></p>
</div>
<div>
<p class="MsoNormal"><span style="font-size:11.0pt;font-family:"Iosevka Fixed SS16"">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.</span><span style="font-size:12.0pt"><o:p></o:p></span></p>
</div>
</div>
</blockquote>
<div>
<p class="MsoNormal" style="margin-bottom:12.0pt"><span style="font-size:12.0pt">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?<o:p></o:p></span></p>
</div>
<blockquote style="margin-top:5.0pt;margin-bottom:5.0pt">
<div>
<div>
<p class="MsoNormal"><span style="font-size:11.0pt;font-family:"Iosevka Fixed SS16""> </span><span style="font-size:12.0pt"><o:p></o:p></span></p>
</div>
<div>
<p class="MsoNormal"><span style="font-size:11.0pt;font-family:"Iosevka Fixed SS16"">#3</span><span style="font-size:12.0pt"><o:p></o:p></span></p>
</div>
<div>
<p class="MsoNormal"><span style="font-size:11.0pt;font-family:"Iosevka Fixed SS16""> </span><span style="font-size:12.0pt"><o:p></o:p></span></p>
</div>
<div>
<p class="MsoNormal"><span style="font-size:11.0pt;font-family:"Iosevka Fixed SS16"">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.</span><span style="font-size:12.0pt"><o:p></o:p></span></p>
</div>
</div>
</blockquote>
<p><span style="font-size:10.5pt;font-family:Optima-Regular">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.<o:p></o:p></span></p>
<p><span style="font-size:10.5pt;font-family:Optima-Regular">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).<o:p></o:p></span></p>
<blockquote style="margin-top:5.0pt;margin-bottom:5.0pt">
<div>
<div>
<p class="MsoNormal"><span style="font-size:11.0pt;font-family:"Iosevka Fixed SS16""> </span><span style="font-size:12.0pt"><o:p></o:p></span></p>
</div>
<div>
<p class="MsoNormal"><span style="font-size:11.0pt;font-family:"Iosevka Fixed SS16"">#4</span><span style="font-size:12.0pt"><o:p></o:p></span></p>
</div>
<div>
<p class="MsoNormal"><span style="font-size:11.0pt;font-family:"Iosevka Fixed SS16""> </span><span style="font-size:12.0pt"><o:p></o:p></span></p>
</div>
<div>
<p class="MsoNormal"><span style="font-size:11.0pt;font-family:"Iosevka Fixed SS16"">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.</span><span style="font-size:12.0pt"><o:p></o:p></span></p>
</div>
</div>
</blockquote>
<p><span style="font-size:10.5pt;font-family:Optima-Regular">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.<o:p></o:p></span></p>
<p><span style="font-size:10.5pt;font-family:Optima-Regular">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:<o:p></o:p></span></p>
<p><span style="font-size:10.5pt;font-family:Optima-Regular">- I define the container hierarchy (VBox, HBox, which children go where)<br>
- I set a style name<br>
- 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).<o:p></o:p></span></p>
<p><span style="font-size:10.5pt;font-family:Optima-Regular">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?<o:p></o:p></span></p>
<blockquote style="margin-top:5.0pt;margin-bottom:5.0pt">
<div>
<div>
<p class="MsoNormal"><span style="font-size:11.0pt;font-family:"Iosevka Fixed SS16"">--</span><span style="font-size:12.0pt"><o:p></o:p></span></p>
</div>
<div>
<p class="MsoNormal"><span style="font-size:11.0pt;font-family:"Iosevka Fixed SS16""> </span><span style="font-size:12.0pt"><o:p></o:p></span></p>
</div>
<div>
<p class="MsoNormal"><span style="font-size:11.0pt;font-family:"Iosevka Fixed SS16"">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<span class="apple-converted-space"> </span><i>probability</i><span class="apple-converted-space"> </span>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.</span><span style="font-size:12.0pt"><o:p></o:p></span></p>
</div>
</div>
</blockquote>
<p><span style="font-size:10.5pt;font-family:Optima-Regular">"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.  <o:p></o:p></span></p>
<p><span style="font-size:10.5pt;font-family:Optima-Regular">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.<o:p></o:p></span></p>
<p><span style="font-size:10.5pt;font-family:Optima-Regular">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.<o:p></o:p></span></p>
<p><span style="font-size:10.5pt;font-family:Optima-Regular">Also I think this can be implemented gradually.  Here's a potential plan:<o:p></o:p></span></p>
<p><span style="font-size:10.5pt;font-family:Optima-Regular">1. Have Scene listen to unused KeyEvents and translate them to TraversalEvents<o:p></o:p></span></p>
<p><span style="font-size:10.5pt;font-family:Optima-Regular">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...<o:p></o:p></span></p>
<p><span style="font-size:10.5pt;font-family:Optima-Regular">Public API: Limited to a new Event<o:p></o:p></span></p>
<p><span style="font-size:10.5pt;font-family:Optima-Regular">2. Start converting existing controls to listen to TraversalEvent instead of KeyEvent<br>
<br>
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.<o:p></o:p></span></p>
<p><span style="font-size:10.5pt;font-family:Optima-Regular">Benefit: for each control converted, user can now programmatically trigger focus changes, and by overriding things at Scene level can completely change navigation keys<o:p></o:p></span></p>
<p><span style="font-size:10.5pt;font-family:Optima-Regular">Public API: none<o:p></o:p></span></p>
<p><span style="font-size:10.5pt;font-family:Optima-Regular">3. Implement a number of standard policies internally (OPEN, CONFINED, CYCLIC, IGNORED)<o:p></o:p></span></p>
<p><span style="font-size:10.5pt;font-family:Optima-Regular">Convert any controls that could use these as their default, removing any custom logic if it happens to match one of the defaults.<o:p></o:p></span></p>
<p><span style="font-size:10.5pt;font-family:Optima-Regular">Benefit: less code to maintain and debug, gives us experience with which policies make sense and where the gaps are<o:p></o:p></span></p>
<p><span style="font-size:10.5pt;font-family:Optima-Regular">Public API: none<o:p></o:p></span></p>
<p><span style="font-size:10.5pt;font-family:Optima-Regular">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.<o:p></o:p></span></p>
<p><span style="font-size:10.5pt;font-family:Optima-Regular">4. Expose policy property/properties on Parent<o:p></o:p></span></p>
<p><span style="font-size:10.5pt;font-family:Optima-Regular">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.<o:p></o:p></span></p>
<p><span style="font-size:10.5pt;font-family:Optima-Regular">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.<o:p></o:p></span></p>
<div>
<p class="MsoNormal"><span style="font-size:12.0pt">Public API: new properties on Parent<o:p></o:p></span></p>
</div>
<p><span style="font-size:10.5pt;font-family:Optima-Regular">5. Perhaps expose some helpful tools to calculate the "next" Node for a given traversal option.<br>
<br>
This can be done at any stage, and can be considered completely separate.  It is IMHO a relatively low priority need.<br>
<br>
Benefit: less work for control implementors (although they could just "copy" said code)<br>
<br>
Public API: Maybe some methods in Node, or some kind of static helper.<o:p></o:p></span></p>
<p><span style="font-size:10.5pt;font-family:Optima-Regular">6. CSS styleable properties<o:p></o:p></span></p>
<p><span style="font-size:10.5pt;font-family:Optima-Regular">If we really want to give power to our users, and impress them with a flexible focus traversal API, then make these properties styleable.<o:p></o:p></span></p>
<p><span style="font-size:10.5pt;font-family:Optima-Regular">Benefit: allow users to pick any control, and set is policy globally or within a subset of controls (ie. dialogs, popups, etc).<o:p></o:p></span></p>
<p><span style="font-size:10.5pt;font-family:Optima-Regular">Public API: Nothing in Java, but document as CSS properties<o:p></o:p></span></p>
<p><span style="font-size:10.5pt;font-family:Optima-Regular">--John<o:p></o:p></span></p>
<blockquote style="margin-top:5.0pt;margin-bottom:5.0pt">
<div>
<div>
<p class="MsoNormal"><span style="font-size:11.0pt;font-family:"Iosevka Fixed SS16""> </span><span style="font-size:12.0pt"><o:p></o:p></span></p>
</div>
<div>
<p class="MsoNormal"><span style="font-size:11.0pt;font-family:"Iosevka Fixed SS16"">Thank you,</span><span style="font-size:12.0pt"><o:p></o:p></span></p>
</div>
<div>
<p class="MsoNormal"><span style="font-size:11.0pt;font-family:"Iosevka Fixed SS16"">-andy</span><span style="font-size:12.0pt"><o:p></o:p></span></p>
</div>
<div>
<p class="MsoNormal"><span style="font-size:11.0pt;font-family:"Iosevka Fixed SS16""> </span><span style="font-size:12.0pt"><o:p></o:p></span></p>
</div>
<div>
<p class="MsoNormal"><span style="font-size:11.0pt;font-family:"Iosevka Fixed SS16""> </span><span style="font-size:12.0pt"><o:p></o:p></span></p>
</div>
<div>
<p class="MsoNormal"><span style="font-size:11.0pt;font-family:"Iosevka Fixed SS16""> </span><span style="font-size:12.0pt"><o:p></o:p></span></p>
</div>
<div>
<p class="MsoNormal"><span style="font-size:11.0pt;font-family:"Iosevka Fixed SS16""> </span><span style="font-size:12.0pt"><o:p></o:p></span></p>
</div>
<div id="mail-editor-reference-message-container">
<div>
<div>
<div style="border:none;border-top:solid windowtext 1.0pt;padding:3.0pt 0in 0in 0in;border-color:currentcolor currentcolor">
<p class="MsoNormal" style="margin-bottom:12.0pt"><b><span style="font-size:12.0pt">From:<span class="apple-converted-space"> </span></span></b><span style="font-size:12.0pt">openjfx-dev<span class="apple-converted-space"> </span><a href="mailto:openjfx-dev-retn@openjdk.org"><span style="color:#467886"><openjfx-dev-retn@openjdk.org></span></a><span class="apple-converted-space"> </span>on
 behalf of John Hendrikx<span class="apple-converted-space"> </span><a href="mailto:john.hendrikx@gmail.com"><span style="color:#467886"><john.hendrikx@gmail.com></span></a><br>
<b>Date:<span class="apple-converted-space"> </span></b>Wednesday, September 11, 2024 at 19:05<br>
<b>To:<span class="apple-converted-space"> </span></b><a href="mailto:openjfx-dev@openjdk.org"><span style="color:#467886">openjfx-dev@openjdk.org</span></a><span class="apple-converted-space"> </span><a href="mailto:openjfx-dev@openjdk.org"><span style="color:#467886"><openjfx-dev@openjdk.org></span></a><br>
<b>Subject:<span class="apple-converted-space"> </span></b>Re: Proposal: Focus Traversal API<o:p></o:p></span></p>
</div>
<p><span style="font-size:10.5pt;font-family:Optima-Regular">Hi Andy / List,<o:p></o:p></span></p>
<p><span style="font-size:10.5pt;font-family:Optima-Regular">I've given this some thought first, without looking too much at the proposal.<o:p></o:p></span></p>
<p><span style="font-size:10.5pt;font-family:Optima-Regular">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).<br>
<br>
## KeyEvent and TraversalEvent separation<o:p></o:p></span></p>
<p><span style="font-size:10.5pt;font-family:Optima-Regular">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.<o:p></o:p></span></p>
<p><span style="font-size:10.5pt;font-family:Optima-Regular">This separation of KeyEvents into TraversalEvents achieves the following:<o:p></o:p></span></p>
<p><span style="font-size:10.5pt;font-family:Optima-Regular">- 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.<br>
<br>
- 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.<br>
<br>
- 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.<o:p></o:p></span></p>
<p><span style="font-size:10.5pt;font-family:Optima-Regular">## Traversal Policy Properties on Parent<br>
<br>
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.<o:p></o:p></span></p>
<p><span style="font-size:10.5pt;font-family:Optima-Regular">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).<o:p></o:p></span></p>
<p><span style="font-size:10.5pt;font-family:Optima-Regular">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).<o:p></o:p></span></p>
<p><span style="font-size:10.5pt;font-family:Optima-Regular">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).<o:p></o:p></span></p>
<p><span style="font-size:10.5pt;font-family:Optima-Regular">- logicalTraversalPolicy<br>
- directionalTraversalPolicy<o:p></o:p></span></p>
<p><span style="font-size:10.5pt;font-family:Optima-Regular">The properties can be set with a value from a TraversalPolicy enum.  I would suggest the following options:<o:p></o:p></span></p>
<p><span style="font-size:10.5pt;font-family:Optima-Regular">- OPEN<o:p></o:p></span></p>
<p><span style="font-size:10.5pt;font-family:Optima-Regular">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.<o:p></o:p></span></p>
<p><span style="font-size:10.5pt;font-family:Optima-Regular">- CONFINED<o:p></o:p></span></p>
<p><span style="font-size:10.5pt;font-family:Optima-Regular">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.<o:p></o:p></span></p>
<p><span style="font-size:10.5pt;font-family:Optima-Regular">- CYCLIC<o:p></o:p></span></p>
<p><span style="font-size:10.5pt;font-family:Optima-Regular">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.<br>
<br>
- IGNORED<o:p></o:p></span></p>
<p><span style="font-size:10.5pt;font-family:Optima-Regular">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.<o:p></o:p></span></p>
<p><span style="font-size:10.5pt;font-family:Optima-Regular">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.<o:p></o:p></span></p>
<p><span style="font-size:10.5pt;font-family:Optima-Regular">## Use Cases<o:p></o:p></span></p>
<div>
<p class="MsoNormal"><span style="font-size:12.0pt">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)<o:p></o:p></span></p>
</div>
<p><span style="font-size:10.5pt;font-family:Optima-Regular">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.<o:p></o:p></span></p>
<p><span style="font-size:10.5pt;font-family:Optima-Regular">2) User wants to act on Traversal events that the standard policy leaves to bubble up<o:p></o:p></span></p>
<p><span style="font-size:10.5pt;font-family:Optima-Regular">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).<o:p></o:p></span></p>
<p><span style="font-size:10.5pt;font-family:Optima-Regular">3) User wants to do crazy custom navigation<o:p></o:p></span></p>
<p><span style="font-size:10.5pt;font-family:Optima-Regular">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.<o:p></o:p></span></p>
<p><span style="font-size:10.5pt;font-family:Optima-Regular">4) User wants to change what keys are considered navigation keys<o:p></o:p></span></p>
<p><span style="font-size:10.5pt;font-family:Optima-Regular">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<o:p></o:p></span></p>
<p><span style="font-size:10.5pt;font-family:Optima-Regular">5) User wants to use keys that are considered navigation keys for their own purposes<o:p></o:p></span></p>
<p><span style="font-size:10.5pt;font-family:Optima-Regular">Just install a KeyEvent handler as usual, without having to worry that Skins/Controls eat these events before you can get to them<br>
<br>
6) User wants to stop a control from reacting to traversal events, without filtering navigation keys completely<o:p></o:p></span></p>
<p><span style="font-size:10.5pt;font-family:Optima-Regular">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.<o:p></o:p></span></p>
<p><span style="font-size:10.5pt;font-family:Optima-Regular">-----<o:p></o:p></span></p>
<p><span style="font-size:10.5pt;font-family:Optima-Regular">About the Proposal:<o:p></o:p></span></p>
<p><span style="font-size:10.5pt;font-family:Optima-Regular">I think the Goals are fine as stated, although I think we differ on what the Traversal events signify.<o:p></o:p></span></p>
<p><span style="font-size:10.5pt;font-family:Optima-Regular">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.<o:p></o:p></span></p>
<p><span style="font-size:10.5pt;font-family:Optima-Regular">Motivation looks okay.<o:p></o:p></span></p>
<p><span style="font-size:10.5pt;font-family:Optima-Regular">> The focus traversal is provided by the FocusTraversal class which offers static methods for traversing focus in various directions, determined by the TraversalDirection enum.<o:p></o:p></span></p>
<p><span style="font-size:10.5pt;font-family:Optima-Regular">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.<o:p></o:p></span></p>
<p><span style="font-size:10.5pt;font-family:Optima-Regular">About your typical example:<o:p></o:p></span></p>
<p><span style="font-size:10.5pt;font-family:Optima-Regular">   <span class="apple-converted-space"> </span>Node from = ...<br>
   <span class="apple-converted-space"> </span>switch (((KeyEvent)event).getCode()) {<br>
   <span class="apple-converted-space"> </span>case UP:<br>
       <span class="apple-converted-space"> </span>FocusTraversal.traverse(from, TraversalDirection.UP, TraversalMethod.KEY);<br>
       <span class="apple-converted-space"> </span>event.consume();<br>
       <span class="apple-converted-space"> </span>break;<br>
   <span class="apple-converted-space"> </span>case DOWN:<br>
       <span class="apple-converted-space"> </span>// or use the convenience method<br>
       <span class="apple-converted-space"> </span>FocusTraversal.traverseDown(from);<br>
       <span class="apple-converted-space"> </span>event.consume();<br>
       <span class="apple-converted-space"> </span>break;<br>
   <span class="apple-converted-space"> </span>}<o:p></o:p></span></p>
<p><span style="font-size:10.5pt;font-family:Optima-Regular">I think this is not a good way to deal with events.<o:p></o:p></span></p>
<p><span style="font-size:10.5pt;font-family:Optima-Regular">1) The event is consumed regardless of the outcome of traverse.  What if focus did not change?  Should the event be consumed?<o:p></o:p></span></p>
<p><span style="font-size:10.5pt;font-family:Optima-Regular">2) This is consuming KeyEvents directly, robbing the user of the opportunity to act on keys considered "special" by FX.<o:p></o:p></span></p>
<p><span style="font-size:10.5pt;font-family:Optima-Regular">3) This code is not only consuming KeyEvents directly, but also deciding what keys are navigation keys.<o:p></o:p></span></p>
<p><span style="font-size:10.5pt;font-family:Optima-Regular">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:<o:p></o:p></span></p>
<p><span style="font-size:10.5pt;font-family:Optima-Regular">   <span class="apple-converted-space"> </span>Node from = ...<br>
<br>
   <span class="apple-converted-space"> </span>Node result = switch(traversalEvent.getEventType()) {<br>
     <span class="apple-converted-space"> </span>case TraversalEvent.UP -> FocusTraversals.findUp(from);<br>
     <span class="apple-converted-space"> </span>case TraversalEvent.DOWN -> FocusTraversals.findDown(from);<br>
     <span class="apple-converted-space"> </span>// etc<br>
  <span class="apple-converted-space"> </span>}<br>
<br>
   <span class="apple-converted-space"> </span>if (result != null) {<br>
        <span class="apple-converted-space"> </span>result.requestFocus();<br>
        <span class="apple-converted-space"> </span>traversalEvent.consume();<br>
   <span class="apple-converted-space"> </span>}<o:p></o:p></span></p>
<p><span style="font-size:10.5pt;font-family:Optima-Regular">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.  <o:p></o:p></span></p>
<p><span style="font-size:10.5pt;font-family:Optima-Regular">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.<o:p></o:p></span></p>
<p><span style="font-size:10.5pt;font-family:Optima-Regular">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)<o:p></o:p></span></p>
<p><span style="font-size:10.5pt;font-family:Optima-Regular">> 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.<o:p></o:p></span></p>
<p><span style="font-size:10.5pt;font-family:Optima-Regular">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.<o:p></o:p></span></p>
<p><span style="font-size:10.5pt;font-family:Optima-Regular">--John<o:p></o:p></span></p>
<p><span style="font-size:10.5pt;font-family:Optima-Regular"> <o:p></o:p></span></p>
<p><span style="font-size:10.5pt;font-family:Optima-Regular"> <o:p></o:p></span></p>
<p class="MsoNormal" style="margin-bottom:12.0pt"><span style="font-size:12.0pt">On 03/09/2024 21:33, Andy Goryachev wrote:<o:p></o:p></span></p>
<blockquote style="margin-top:5.0pt;margin-bottom:5.0pt">
<div>
<div>
<p class="MsoNormal"><span style="font-size:11.0pt;font-family:"Iosevka Fixed SS16";color:#212121">Dear fellow developers:</span><span style="font-size:12.0pt"><o:p></o:p></span></p>
</div>
<div>
<p class="MsoNormal"><span style="font-size:11.0pt;font-family:"Iosevka Fixed SS16";color:#212121"> </span><span style="font-size:12.0pt"><o:p></o:p></span></p>
</div>
<div>
<p class="MsoNormal"><span style="font-size:11.0pt;font-family:"Iosevka Fixed SS16";color:#212121">I'd like to propose the public focus traversal API:</span><span style="font-size:12.0pt"><o:p></o:p></span></p>
</div>
<div>
<p class="MsoNormal"><span style="font-size:11.0pt;font-family:"Iosevka Fixed SS16";color:#212121"> </span><span style="font-size:12.0pt"><o:p></o:p></span></p>
</div>
<div>
<p class="MsoNormal"><span style="font-size:11.0pt;font-family:"Iosevka Fixed SS16";color:#212121"><a href="https://urldefense.com/v3/__https:/github.com/andy-goryachev-oracle/Test/blob/main/doc/FocusTraversal/FocusTraversal.md__;!!ACWV5N9M2RV99hQ!LnjDXwUbbEymf9b1gkZFia8vuewsVJy6_49It-IKw66U9mS78PjdIPotBpc7AXlSfY7N5xcRXsmcPQhOzavk4z9VkPv-$" title="https://github.com/andy-goryachev-oracle/Test/blob/main/doc/FocusTraversal/FocusTraversal.md"><span style="color:#0078D7">https://github.com/andy-goryachev-oracle/Test/blob/main/doc/<span class="outlook-search-highlight">Focus</span>Traversal/<span class="outlook-search-highlight">Focus</span>Traversal.md</span></a></span><span style="font-size:12.0pt"><o:p></o:p></span></p>
</div>
<div>
<p class="MsoNormal"><span style="font-size:11.0pt;font-family:"Iosevka Fixed SS16";color:#212121"> </span><span style="font-size:12.0pt"><o:p></o:p></span></p>
</div>
<div>
<p class="MsoNormal"><span style="font-size:11.0pt;font-family:"Iosevka Fixed SS16";color:#212121">Draft PR:</span><span style="font-size:12.0pt"><o:p></o:p></span></p>
</div>
<div>
<p class="MsoNormal"><span style="font-size:11.0pt;font-family:"Iosevka Fixed SS16";color:#212121"> </span><span style="font-size:12.0pt"><o:p></o:p></span></p>
</div>
<div>
<p class="MsoNormal"><span style="font-size:11.0pt;font-family:"Iosevka Fixed SS16";color:#212121"><a href="https://urldefense.com/v3/__https:/github.com/openjdk/jfx/pull/1555__;!!ACWV5N9M2RV99hQ!LnjDXwUbbEymf9b1gkZFia8vuewsVJy6_49It-IKw66U9mS78PjdIPotBpc7AXlSfY7N5xcRXsmcPQhOzavk49fH_P2p$"><span style="color:#467886">https://github.com/openjdk/jfx/pull/1555</span></a></span><span style="font-size:12.0pt"><o:p></o:p></span></p>
</div>
<div>
<p class="MsoNormal"><span style="font-size:11.0pt;font-family:"Iosevka Fixed SS16";color:#212121"> </span><span style="font-size:12.0pt"><o:p></o:p></span></p>
</div>
<div>
<p class="MsoNormal"><span style="font-size:11.0pt;font-family:"Iosevka Fixed SS16";color:#212121">Your comments and suggestions will be warmly accepted and appreciated.</span><span style="font-size:12.0pt"><o:p></o:p></span></p>
</div>
<div>
<p class="MsoNormal"><span style="font-size:11.0pt;font-family:"Iosevka Fixed SS16";color:#212121"> </span><span style="font-size:12.0pt"><o:p></o:p></span></p>
</div>
<div>
<p class="MsoNormal"><span style="font-size:11.0pt;font-family:"Iosevka Fixed SS16";color:#212121">Thank you</span><span style="font-size:12.0pt"><o:p></o:p></span></p>
</div>
<div>
<p class="MsoNormal"><span style="font-size:11.0pt;font-family:"Iosevka Fixed SS16";color:#212121"> </span><span style="font-size:12.0pt"><o:p></o:p></span></p>
</div>
<div>
<p class="MsoNormal"><span style="font-size:11.0pt;font-family:"Iosevka Fixed SS16";color:#212121">-andy</span><span style="font-size:12.0pt"><o:p></o:p></span></p>
</div>
</div>
</blockquote>
</div>
</div>
</div>
</div>
</blockquote>
</div>
</div>
</div>
</div>
</blockquote>
</div>
</blockquote>
</div>
<p class="MsoNormal"><span style="font-size:12.0pt"><o:p> </o:p></span></p>
</div>
</div>
</div>
</div>
</div>
</body>
</html>