<!DOCTYPE html>
<html>
  <head>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
  </head>
  <body>
    <p>My apologies then, I was a bit impatient.  Good luck with the
      test sprint then!<br>
    </p>
    <p>--John<br>
    </p>
    <div class="moz-cite-prefix">On 18/09/2024 17:13, Andy Goryachev
      wrote:<br>
    </div>
    <blockquote type="cite"
cite="mid:BL3PR10MB61853160A21E2EC5F535B0B2E5622@BL3PR10MB6185.namprd10.prod.outlook.com">
      <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
      <meta name="Generator"
        content="Microsoft Word 15 (filtered medium)">
      <style>@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;}p.MsoNormal, li.MsoNormal, div.MsoNormal
        {margin:0in;
        font-size:12.0pt;
        font-family:"Aptos",sans-serif;}a:link, span.MsoHyperlink
        {mso-style-priority:99;
        color:#467886;
        text-decoration:underline;}p.p1, li.p1, div.p1
        {mso-style-name:p1;
        mso-margin-top-alt:auto;
        margin-right:0in;
        mso-margin-bottom-alt:auto;
        margin-left:0in;
        font-size:12.0pt;
        font-family:"Aptos",sans-serif;}span.outlook-search-highlight
        {mso-style-name:outlook-search-highlight;}span.EmailStyle230
        {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;}div.WordSection1
        {page:WordSection1;}</style>
      <div class="WordSection1">
        <p class="MsoNormal"><span
style="font-size:11.0pt;font-family:"Iosevka Fixed SS16"">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.<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>
        <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="color:black">From:
                    </span></b><span style="color:black">John Hendrikx
                    <a class="moz-txt-link-rfc2396E" href="mailto:john.hendrikx@gmail.com"><john.hendrikx@gmail.com></a><br>
                    <b>Date: </b>Tuesday, September 17, 2024 at 23:05<br>
                    <b>To: </b>Andy Goryachev
                    <a class="moz-txt-link-rfc2396E" href="mailto:andy.goryachev@oracle.com"><andy.goryachev@oracle.com></a>,
                    <a class="moz-txt-link-abbreviated" href="mailto:openjfx-dev@openjdk.org">openjfx-dev@openjdk.org</a>
                    <a class="moz-txt-link-rfc2396E" href="mailto:openjfx-dev@openjdk.org"><openjfx-dev@openjdk.org></a><br>
                    <b>Subject: </b>Re: [External] : Re: Proposal:
                    Focus Traversal API<o:p></o:p></span></p>
              </div>
              <p>Andy,<o:p></o:p></p>
              <p>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></p>
              <p>--John<o:p></o:p></p>
              <div>
                <p class="MsoNormal">On 18/09/2024 01:09, Andy Goryachev
                  wrote:<o:p></o:p></p>
              </div>
              <blockquote style="margin-top:5.0pt;margin-bottom:5.0pt">
                <div>
                  <p class="MsoNormal"><span
style="font-size:11.0pt;font-family:"Iosevka Fixed SS16"">Dear
                      John:</span><o:p></o:p></p>
                  <p class="MsoNormal"><span
style="font-size:11.0pt;font-family:"Iosevka Fixed SS16""> </span><o:p></o:p></p>
                  <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><o:p></o:p></p>
                  <p class="MsoNormal"><span
style="font-size:11.0pt;font-family:"Iosevka Fixed SS16""> </span><o:p></o:p></p>
                  <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><o:p></o:p></p>
                  <p class="MsoNormal"><span
style="font-size:11.0pt;font-family:"Iosevka Fixed SS16""> </span><o:p></o:p></p>
                  <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><o:p></o:p></p>
                  <p class="MsoNormal"><span
style="font-size:11.0pt;font-family:"Iosevka Fixed SS16""> </span><o:p></o:p></p>
                  <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><o:p></o:p></p>
                  <p class="MsoNormal"><span
style="font-size:11.0pt;font-family:"Iosevka Fixed SS16""> </span><o:p></o:p></p>
                  <p class="MsoNormal"><span
style="font-size:11.0pt;font-family:"Iosevka Fixed SS16"">Thank
                      you
                    </span><o:p></o:p></p>
                  <p class="MsoNormal"><span
style="font-size:11.0pt;font-family:"Iosevka Fixed SS16"">-andy</span><o:p></o:p></p>
                  <p class="MsoNormal"><span
style="font-size:11.0pt;font-family:"Iosevka Fixed SS16""> </span><o:p></o:p></p>
                  <p class="MsoNormal"><span
style="font-size:11.0pt;font-family:"Iosevka Fixed SS16""> </span><o:p></o:p></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="color:black">From:
                              </span></b><span style="color:black">John
                              Hendrikx <a
                                href="mailto:john.hendrikx@gmail.com"
                                moz-do-not-send="true">
                                <john.hendrikx@gmail.com></a><br>
                              <b>Date: </b>Saturday, September 14, 2024
                              at 09:41<br>
                              <b>To: </b>Andy Goryachev <a
                                href="mailto:andy.goryachev@oracle.com"
                                moz-do-not-send="true"><andy.goryachev@oracle.com></a>,
                              <a href="mailto:openjfx-dev@openjdk.org"
                                moz-do-not-send="true"
                                class="moz-txt-link-freetext">openjfx-dev@openjdk.org</a>
                              <a href="mailto:openjfx-dev@openjdk.org"
                                moz-do-not-send="true">
                                <openjfx-dev@openjdk.org></a><br>
                              <b>Subject: </b>[External] : Re:
                              Proposal: Focus Traversal API</span><o:p></o:p></p>
                        </div>
                        <p>Hi Andy,<o:p></o:p></p>
                        <p>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></p>
                        <p>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></p>
                        <p>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></p>
                        <div>
                          <p class="MsoNormal">On 14/09/2024 00:17, Andy
                            Goryachev wrote:<o:p></o:p></p>
                        </div>
                        <blockquote
                          style="margin-top:5.0pt;margin-bottom:5.0pt">
                          <div>
                            <p class="MsoNormal"><span
style="font-size:11.0pt;font-family:"Iosevka Fixed SS16"">Dear
                                John, Everyone:</span><o:p></o:p></p>
                            <p class="MsoNormal"><span
style="font-size:11.0pt;font-family:"Iosevka Fixed SS16""> </span><o:p></o:p></p>
                            <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><o:p></o:p></p>
                            <p class="MsoNormal"><span
style="font-size:11.0pt;font-family:"Iosevka Fixed SS16""> </span><o:p></o:p></p>
                            <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><o:p></o:p></p>
                            <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><o:p></o:p></p>
                            <p class="MsoNormal"><span
style="font-size:11.0pt;font-family:"Iosevka Fixed SS16"">3.
                                (more) standard policies</span><o:p></o:p></p>
                            <p class="MsoNormal"><span
style="font-size:11.0pt;font-family:"Iosevka Fixed SS16"">4.
                                using CSS</span><o:p></o:p></p>
                            <p class="MsoNormal"><span
style="font-size:11.0pt;font-family:"Iosevka Fixed SS16""> </span><o:p></o:p></p>
                            <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><o:p></o:p></p>
                            <p class="MsoNormal"><span
style="font-size:11.0pt;font-family:"Iosevka Fixed SS16""> </span><o:p></o:p></p>
                            <p class="MsoNormal"><span
style="font-size:11.0pt;font-family:"Iosevka Fixed SS16"">#1
                              </span><o:p></o:p></p>
                            <p class="MsoNormal"><span
style="font-size:11.0pt;font-family:"Iosevka Fixed SS16""> </span><o:p></o:p></p>
                            <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><o:p></o:p></p>
                          </div>
                        </blockquote>
                        <p>There's two things here.<o:p></o:p></p>
                        <p>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></p>
                        <p>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></p>
                        <p>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></p>
                        <p class="MsoNormal"
                          style="margin-bottom: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></p>
                        <blockquote
                          style="margin-top:5.0pt;margin-bottom:5.0pt">
                          <div>
                            <p class="MsoNormal"><span
style="font-size:11.0pt;font-family:"Iosevka Fixed SS16""> </span><o:p></o:p></p>
                            <p class="MsoNormal"><span
style="font-size:11.0pt;font-family:"Iosevka Fixed SS16"">#2</span><o:p></o:p></p>
                            <p class="MsoNormal"><span
style="font-size:11.0pt;font-family:"Iosevka Fixed SS16""> </span><o:p></o:p></p>
                            <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><o:p></o:p></p>
                          </div>
                        </blockquote>
                        <p class="MsoNormal"
                          style="margin-bottom: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></p>
                        <blockquote
                          style="margin-top:5.0pt;margin-bottom:5.0pt">
                          <div>
                            <p class="MsoNormal"><span
style="font-size:11.0pt;font-family:"Iosevka Fixed SS16""> </span><o:p></o:p></p>
                            <p class="MsoNormal"><span
style="font-size:11.0pt;font-family:"Iosevka Fixed SS16"">#3</span><o:p></o:p></p>
                            <p class="MsoNormal"><span
style="font-size:11.0pt;font-family:"Iosevka Fixed SS16""> </span><o:p></o:p></p>
                            <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><o:p></o:p></p>
                          </div>
                        </blockquote>
                        <p>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></p>
                        <p>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></p>
                        <blockquote
                          style="margin-top:5.0pt;margin-bottom:5.0pt">
                          <div>
                            <p class="MsoNormal"><span
style="font-size:11.0pt;font-family:"Iosevka Fixed SS16""> </span><o:p></o:p></p>
                            <p class="MsoNormal"><span
style="font-size:11.0pt;font-family:"Iosevka Fixed SS16"">#4</span><o:p></o:p></p>
                            <p class="MsoNormal"><span
style="font-size:11.0pt;font-family:"Iosevka Fixed SS16""> </span><o:p></o:p></p>
                            <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><o:p></o:p></p>
                          </div>
                        </blockquote>
                        <p>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></p>
                        <p>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></p>
                        <p>- 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></p>
                        <p>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></p>
                        <blockquote
                          style="margin-top:5.0pt;margin-bottom:5.0pt">
                          <div>
                            <p class="MsoNormal"><span
style="font-size:11.0pt;font-family:"Iosevka Fixed SS16"">--</span>
                              <o:p></o:p></p>
                            <p class="MsoNormal"><span
style="font-size:11.0pt;font-family:"Iosevka Fixed SS16""> </span><o:p></o:p></p>
                            <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
                                <i>probability</i> 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><o:p></o:p></p>
                          </div>
                        </blockquote>
                        <p>"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></p>
                        <p>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></p>
                        <p>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></p>
                        <p>Also I think this can be implemented
                          gradually.  Here's a potential plan:<o:p></o:p></p>
                        <p>1. Have Scene listen to unused KeyEvents and
                          translate them to TraversalEvents<o:p></o:p></p>
                        <p>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></p>
                        <p>Public API: Limited to a new Event<o:p></o:p></p>
                        <p>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></p>
                        <p>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></p>
                        <p>Public API: none<o:p></o:p></p>
                        <p>3. Implement a number of standard policies
                          internally (OPEN, CONFINED, CYCLIC, IGNORED)<o:p></o:p></p>
                        <p>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></p>
                        <p>Benefit: less code to maintain and debug,
                          gives us experience with which policies make
                          sense and where the gaps are<o:p></o:p></p>
                        <p>Public API: none<o:p></o:p></p>
                        <p>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></p>
                        <p>4. Expose policy property/properties on
                          Parent<o:p></o:p></p>
                        <p>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></p>
                        <p>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></p>
                        <p class="MsoNormal">Public API: new properties
                          on Parent<o:p></o:p></p>
                        <p>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></p>
                        <p>6. CSS styleable properties<o:p></o:p></p>
                        <p>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></p>
                        <p>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></p>
                        <p>Public API: Nothing in Java, but document as
                          CSS properties<o:p></o:p></p>
                        <p>--John<o:p></o:p></p>
                        <blockquote
                          style="margin-top:5.0pt;margin-bottom:5.0pt">
                          <div>
                            <p class="MsoNormal"><span
style="font-size:11.0pt;font-family:"Iosevka Fixed SS16""> </span><o:p></o:p></p>
                            <p class="MsoNormal"><span
style="font-size:11.0pt;font-family:"Iosevka Fixed SS16"">Thank
                                you,</span><o:p></o:p></p>
                            <p class="MsoNormal"><span
style="font-size:11.0pt;font-family:"Iosevka Fixed SS16"">-andy</span><o:p></o:p></p>
                            <p class="MsoNormal"><span
style="font-size:11.0pt;font-family:"Iosevka Fixed SS16""> </span><o:p></o:p></p>
                            <p class="MsoNormal"><span
style="font-size:11.0pt;font-family:"Iosevka Fixed SS16""> </span><o:p></o:p></p>
                            <p class="MsoNormal"><span
style="font-size:11.0pt;font-family:"Iosevka Fixed SS16""> </span><o:p></o:p></p>
                            <p class="MsoNormal"><span
style="font-size:11.0pt;font-family:"Iosevka Fixed SS16""> </span><o:p></o:p></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="color:black">From:
                                        </span></b><span
                                        style="color:black">openjfx-dev
                                        <a
href="mailto:openjfx-dev-retn@openjdk.org" moz-do-not-send="true">
<openjfx-dev-retn@openjdk.org></a> on behalf of John Hendrikx <a
href="mailto:john.hendrikx@gmail.com" moz-do-not-send="true">
<john.hendrikx@gmail.com></a><br>
                                        <b>Date: </b>Wednesday,
                                        September 11, 2024 at 19:05<br>
                                        <b>To: </b><a
href="mailto:openjfx-dev@openjdk.org" moz-do-not-send="true"
                                          class="moz-txt-link-freetext">openjfx-dev@openjdk.org</a>
                                        <a
href="mailto:openjfx-dev@openjdk.org" moz-do-not-send="true">
<openjfx-dev@openjdk.org></a><br>
                                        <b>Subject: </b>Re: Proposal:
                                        Focus Traversal API</span><o:p></o:p></p>
                                  </div>
                                  <p>Hi Andy / List,<o:p></o:p></p>
                                  <p>I've given this some thought
                                    first, without looking too much at
                                    the proposal.<o:p></o:p></p>
                                  <p>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></p>
                                  <p>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></p>
                                  <p>This separation of KeyEvents into
                                    TraversalEvents achieves the
                                    following:<o:p></o:p></p>
                                  <p>- 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></p>
                                  <p>## 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></p>
                                  <p>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></p>
                                  <p>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></p>
                                  <p>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></p>
                                  <p>- logicalTraversalPolicy<br>
                                    - directionalTraversalPolicy<o:p></o:p></p>
                                  <p>The properties can be set with a
                                    value from a TraversalPolicy enum. 
                                    I would suggest the following
                                    options:<o:p></o:p></p>
                                  <p>- OPEN<o:p></o:p></p>
                                  <p>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></p>
                                  <p>- CONFINED<o:p></o:p></p>
                                  <p>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></p>
                                  <p>- CYCLIC<o:p></o:p></p>
                                  <p>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></p>
                                  <p>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></p>
                                  <p>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></p>
                                  <p>## Use Cases<o:p></o:p></p>
                                  <p class="MsoNormal">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></p>
                                  <p>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></p>
                                  <p>2) User wants to act on Traversal
                                    events that the standard policy
                                    leaves to bubble up<o:p></o:p></p>
                                  <p>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></p>
                                  <p>3) User wants to do crazy custom
                                    navigation<o:p></o:p></p>
                                  <p>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></p>
                                  <p>4) User wants to change what keys
                                    are considered navigation keys<o:p></o:p></p>
                                  <p>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></p>
                                  <p>5) User wants to use keys that are
                                    considered navigation keys for their
                                    own purposes<o:p></o:p></p>
                                  <p>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></p>
                                  <p>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></p>
                                  <p>-----<o:p></o:p></p>
                                  <p>About the Proposal:<o:p></o:p></p>
                                  <p>I think the Goals are fine as
                                    stated, although I think we differ
                                    on what the Traversal events
                                    signify.<o:p></o:p></p>
                                  <p>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></p>
                                  <p>Motivation looks okay.<o:p></o:p></p>
                                  <p>> 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></p>
                                  <p>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></p>
                                  <p>About your typical example:<o:p></o:p></p>
                                  <p>    Node from = ...<br>
                                        switch
                                    (((KeyEvent)event).getCode()) {<br>
                                        case UP:<br>
                                           
                                    FocusTraversal.traverse(from,
                                    TraversalDirection.UP,
                                    TraversalMethod.KEY);<br>
                                            event.consume();<br>
                                            break;<br>
                                        case DOWN:<br>
                                            // or use the convenience
                                    method<br>
                                           
                                    FocusTraversal.traverseDown(from);<br>
                                            event.consume();<br>
                                            break;<br>
                                        }<o:p></o:p></p>
                                  <p>I think this is not a good way to
                                    deal with events.<o:p></o:p></p>
                                  <p>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></p>
                                  <p>2) This is consuming KeyEvents
                                    directly, robbing the user of the
                                    opportunity to act on keys
                                    considered "special" by FX.<o:p></o:p></p>
                                  <p>3) This code is not only consuming
                                    KeyEvents directly, but also
                                    deciding what keys are navigation
                                    keys.<o:p></o:p></p>
                                  <p>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></p>
                                  <p>    Node from = ...<br>
                                    <br>
                                        Node result =
                                    switch(traversalEvent.getEventType())
                                    {<br>
                                          case TraversalEvent.UP ->
                                    FocusTraversals.findUp(from);<br>
                                          case TraversalEvent.DOWN ->
                                    FocusTraversals.findDown(from);<br>
                                          // etc<br>
                                       }<br>
                                    <br>
                                        if (result != null) {<br>
                                             result.requestFocus();<br>
                                             traversalEvent.consume();<br>
                                        }<o:p></o:p></p>
                                  <p>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></p>
                                  <p>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></p>
                                  <p>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></p>
                                  <p>> 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></p>
                                  <p>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></p>
                                  <p>--John<o:p></o:p></p>
                                  <p> <o:p></o:p></p>
                                  <p> <o:p></o:p></p>
                                  <p class="MsoNormal"
                                    style="margin-bottom:12.0pt">On
                                    03/09/2024 21:33, Andy Goryachev
                                    wrote:<o:p></o:p></p>
                                  <blockquote
style="margin-top:5.0pt;margin-bottom:5.0pt">
                                    <div>
                                      <p class="MsoNormal"><span
style="font-size:11.0pt;font-family:"Iosevka Fixed SS16";color:#212121">Dear
                                          fellow developers:</span><o:p></o:p></p>
                                      <p class="MsoNormal"
style="font-variant-caps:normal;orphans:auto;text-align:start;widows:auto;word-spacing:0px">
                                        <span
style="font-size:11.0pt;font-family:"Iosevka Fixed SS16";color:#212121"> </span><o:p></o:p></p>
                                      <p class="MsoNormal"
style="font-variant-caps:normal;orphans:auto;text-align:start;widows:auto;word-spacing:0px">
                                        <span
style="font-size:11.0pt;font-family:"Iosevka Fixed SS16";color:#212121">I'd
                                          like to propose the public
                                          focus traversal API:</span><o:p></o:p></p>
                                      <p class="MsoNormal"
style="font-variant-caps:normal;orphans:auto;text-align:start;widows:auto;word-spacing:0px">
                                        <span
style="font-size:11.0pt;font-family:"Iosevka Fixed SS16";color:#212121"> </span><o:p></o:p></p>
                                      <p class="p1"
style="margin:0in;font-variant-caps:normal;orphans:auto;text-align:start;widows:auto;word-spacing:0px">
                                        <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"
                                            moz-do-not-send="true"><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><o:p></o:p></p>
                                      <p class="MsoNormal"
style="font-variant-caps:normal;orphans:auto;text-align:start;widows:auto;word-spacing:0px">
                                        <span
style="font-size:11.0pt;font-family:"Iosevka Fixed SS16";color:#212121"> </span><o:p></o:p></p>
                                      <p class="MsoNormal"
style="font-variant-caps:normal;orphans:auto;text-align:start;widows:auto;word-spacing:0px">
                                        <span
style="font-size:11.0pt;font-family:"Iosevka Fixed SS16";color:#212121">Draft
                                          PR:</span><o:p></o:p></p>
                                      <p class="MsoNormal"><span
style="font-size:11.0pt;font-family:"Iosevka Fixed SS16";color:#212121"> </span><o:p></o:p></p>
                                      <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$"
                                            moz-do-not-send="true">https://github.com/openjdk/jfx/pull/1555</a></span><o:p></o:p></p>
                                      <p class="MsoNormal"><span
style="font-size:11.0pt;font-family:"Iosevka Fixed SS16";color:#212121"> </span><o:p></o:p></p>
                                      <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><o:p></o:p></p>
                                      <p class="MsoNormal"><span
style="font-size:11.0pt;font-family:"Iosevka Fixed SS16";color:#212121"> </span><o:p></o:p></p>
                                      <p class="MsoNormal"
style="font-variant-caps:normal;orphans:auto;text-align:start;widows:auto;word-spacing:0px">
                                        <span
style="font-size:11.0pt;font-family:"Iosevka Fixed SS16";color:#212121">Thank
                                          you</span><o:p></o:p></p>
                                      <p class="MsoNormal"
style="font-variant-caps:normal;orphans:auto;text-align:start;widows:auto;word-spacing:0px">
                                        <span
style="font-size:11.0pt;font-family:"Iosevka Fixed SS16";color:#212121"> </span><o:p></o:p></p>
                                      <p class="MsoNormal"
style="font-variant-caps:normal;orphans:auto;text-align:start;widows:auto;word-spacing:0px">
                                        <span
style="font-size:11.0pt;font-family:"Iosevka Fixed SS16";color:#212121">-andy</span><o:p></o:p></p>
                                      <p class="MsoNormal"><span
style="font-size:11.0pt;font-family:"Iosevka Fixed SS16""> </span><o:p></o:p></p>
                                    </div>
                                  </blockquote>
                                </div>
                              </div>
                            </div>
                          </div>
                        </blockquote>
                      </div>
                    </div>
                  </div>
                </div>
              </blockquote>
            </div>
          </div>
        </div>
      </div>
    </blockquote>
  </body>
</html>