<html>
  <head>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
  </head>
  <body>
    <p><br>
    </p>
    <div class="moz-cite-prefix">On 18/10/2023 22:49, Andy Goryachev
      wrote:<br>
    </div>
    <blockquote type="cite"
cite="mid:MWHPR1001MB21734C91DCC8C7860F6607B3E5D5A@MWHPR1001MB2173.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:Calibri;
        panose-1:2 15 5 2 2 2 4 3 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:"Iosevka Fixed SS16 ";
        panose-1:2 0 5 9 3 0 0 0 0 4;}p.MsoNormal, li.MsoNormal, div.MsoNormal
        {margin:0in;
        font-size:10.0pt;
        font-family:"Calibri",sans-serif;}a:link, span.MsoHyperlink
        {mso-style-priority:99;
        color:blue;
        text-decoration:underline;}span.EmailStyle20
        {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"">Dear John, thank you for clarifications.  Sorry
            for my delayed response.<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"">I think we need more meat for question #1 - it
            is not yet clear.  All event handlers end up in the
            control’s list, and we know that the ordering may be
            undetermined (or, rather, depend on whether it’s the first
            skin, or the second one).<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"">I agree with Michael’s observation that my
            addHandlerLast() is a bit of a hack.  At least in Swing one
            can get all the listeners, move them all to a temporary
            list, insert the handler than needs to go off first, then
            add the old listeners back.  Or, sorry for repeating myself,
            use event filter on a control.  Or add explicit priority
            value to addEventHandler(Filter?)?</span></p>
      </div>
    </blockquote>
    <p>Okay, so to clarify question #1, my problem with how FX currently
      deals with event handlers is different from how it deals with
      properties and listeners.</p>
    <p>Listeners getting mixed up has almost no impact as all listeners
      always get called and nothing gets consumed.  The user listeners
      being "last" therefore is usually not a problem (I say usually,
      because sometimes it still can be a source of frustation that a
      Skin reacts to something before a listener installed by the user
      that may want to veto something).</p>
    <p>Properties also don't have this problem as Skins are careful to
      not to overwrite properties, and CSS respects values directly set
      on controls and prevents CSS from changing them.</p>
    <p>EventHandlers however pass along a stateful modifiable object
      (the Event).  Only one handler is supposed to act on and consume
      the event.  When it comes to users installing an event handler
      directly on a control, users IMHO rightfully expect that their
      event handler will be the ultimate authority and will see any
      event that gets passed to the control first.</p>
    <p>The handlers that FX installs are more of a fallback; they handle
      default processing of events the control needs, but it should be a
      hidden implementation detail; except it isn't very well hidden
      currently as they SHARE the same event handler lists that users
      are using.  Again, this is normally not a big issue, but for event
      handlers, because Events are stateful, not being the first in line
      to process an event means you are simply too late and out of luck.</p>
    <p>Skins/Behaviors and CSS should be completely transparent to the
      user of the Control, and for the most part they are, except for
      EventHandlers stealing events before the user can get at them.</p>
    <p>So what does all that mean?</p>
    <p>I don't think we need to expose an elaborate ordering system or
      priority system for event handlers, because I don't think the user
      should be seeing event handlers from FX in the first place.  They
      should be hidden and only trigger if nothing else was interested
      in the event -- this means there is nothing to order.  User event
      handlers are first (in the order they were added by the user which
      they have control over) and FX handlers are last (regardless of
      when they were "installed").</p>
    <p>So while we may need priorities, separate lists or an
      "addHandlerLast" type function **internally** to ensure FX
      handlers are called last, users don't need this and shouldn't need
      to care about ordering in the first place.<br>
    </p>
    <blockquote type="cite"
cite="mid:MWHPR1001MB21734C91DCC8C7860F6607B3E5D5A@MWHPR1001MB2173.namprd10.prod.outlook.com">
      <div class="WordSection1">
        <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>
        <p class="MsoNormal"><span
            style="font-size:11.0pt;font-family:"Iosevka Fixed
            SS16"">#2.  May be I should ask this question - could
            you give an example where a user event handler is added
            which is supposed to replace the handler in the skin?</span></p>
      </div>
    </blockquote>
    <p>I'm gonna assume you said "Behavior" here instead of "Skin", but
      I'm not entirely sure I'm answering your question here though...</p>
    <p>When a Behavior installs a KEY_PRESSED handler, and it happens to
      be the first handler, currently the user has no options to prevent
      that handler from consuming the event.  Sure, we could filter it,
      but what if we want it to bubble up without the behavior acting on
      it?  In order to have any kind of control here, the user event
      handler (when it gets added) should run first.  This way it can
      intercept a KEY_PRESSED event for say one of the navigation keys
      and handle it differently.  Without being first, there is just no
      way to change a behavior as the behavior handler will already have
      seen the key, acted on it and marked it consumed.</p>
    <blockquote type="cite"
cite="mid:MWHPR1001MB21734C91DCC8C7860F6607B3E5D5A@MWHPR1001MB2173.namprd10.prod.outlook.com">
      <div class="WordSection1">
        <p class="MsoNormal"><span
            style="font-size:11.0pt;font-family:"Iosevka Fixed
            SS16""><o:p><br>
            </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"">#3.  Your proposal (yet to see the details, but
            judging by the fact that you refer to event handlers in the
            context of key bindings) seems to be more complicated than
            one suggested in the input map proposal.  In fact, most of
            the added value there comes from flexibility manipulating
            key bindings.  Could we have the same level of functionality
            from the alternative proposal?</span></p>
      </div>
    </blockquote>
    <p>I think so, although I would propose offering remapping/changing
      the input map by creating a new Behavior instead.</p>
    <p>So, you could break up my proposal in a few parts:</p>
    <p>Part 1. Ensure FX event handlers don't consume events before the
      user has a chance to be the first</p>
    <p>This gives the ability to change anything you want, but at a very
      low level.  Useful to change for example how navigation works, and
      some basic blocking or adding of key bindings to trigger some
      action (including for keys that are normally claimed by
      behaviors).  One could build their own Behavior system with such
      low level access (and the guarantee that you will be able to
      intercept anything).<br>
    </p>
    <p>Part 2. Use custom events for indirecting low level events
      (key/mouse) instead of FunctionTags</p>
    <p>This exposes for the user a higher level mechanism to influence
      controls and behaviors. This is somewhat more useful as events
      have already been interpreted and so the user doesn't have to know
      the platform specifics of what certain mouse and key pressed
      mean.  The user is given a choice to react differently to such
      events, to block them, or to trigger their own high level events.<br>
    </p>
    <p>Part 3. Allow customizing existing behaviors (including their
      input map) by subclassing or composing the behavior</p>
    <p>This is the level I think you are trying to achieve right now,
      customizing behaviors and then specifically their input map.  In
      my proposal I want to make it trivial to subclass and/or compose a
      behavior.  Once your own behavior is created, you can have the
      default behavior install its mappings, after which the user has
      the opportunity to change anything they wish.  I already had a
      hint of an idea here by providing a `BehaviorContext` class on
      which keybindings can be installed; think of this class an
      `InputMap` but not strictly limited to only dealing with this one
      aspect of a behavior.  The `BehaviorContext` may offer key
      remapping functions directly or just delegate it to another object
      that you can get at via this context.<br>
    </p>
    <blockquote type="cite"
cite="mid:MWHPR1001MB21734C91DCC8C7860F6607B3E5D5A@MWHPR1001MB2173.namprd10.prod.outlook.com">
      <div class="WordSection1">
        <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>
        <p class="MsoNormal"><span
            style="font-size:11.0pt;font-family:"Iosevka Fixed
            SS16"">#4.  All this code looks like overcomplication
            to me.  And look, you’ve invented some kind of
            BehaviorContext, acknowledging the reality that behaviors
            are stateful. 
          </span></p>
      </div>
    </blockquote>
    <p>It really is not an over complication, but instead separating of
      the different concerns.</p>
    <p>- Behavior interface for easy re-use: Behavior definitions that
      can be created by users or reused as needed<br>
      - BehaviorContext for failsafe install/uninstall: Tracking the
      changes behaviors make to the Control, and being able to undo
      those<br>
      - An internal class for Behavior state tracking, containing per
      control state the Behavior needs to do its work<br>
    </p>
    <p>Behavior definitions are simply instances of Behavior; these
      usually won't need any state, and are therefore easy to subclass
      and compose. In theory they could hold some state and such
      behaviors could be installed on multiple controls at once -- this
      would allow things like behaviors that work accross controls (not
      a concern now, but it would be possible).<br>
    </p>
    <p>The second is the BehaviorContext. Think of it as an indirection
      to functions the Control provides so the control can see
      **exactly** what changes a Behavior made to it, and how to undo
      them when the time comes.  It's a bit like your ListenerHelper,
      except formalized as an API and more specific to the task at hand.
      The Control is completely in charge of the lifecycle of these.  It
      creates them when needed, and destroys them when no longer
      required.  This interface provides methods to talk to the Control,
      but indirectly so everything a behavior does to the control can be
      tracked.  It has methods to install event handlers (indirectly),
      allowing the control not only to know which ones need to removed
      later, but also to treat these handlers differently (it can give
      them the lowest priority).  No co-operation from the Behavior is
      needed to **uninstall** a Behavior; this for example means that a
      Behavior can't "forget" to uninstall something (just like
      ListenerHelper does).<br>
    </p>
    <p>Finally there is state the Behavior may need to track on a per
      control basis; this previously also included all the handlers it
      installed, but this has been nicely separated out as that should
      be the Control's concern.  The state I'm talking about here is
      more about previously seen events, and how they might influence
      future events.  The `keyDown` field in `ButtonBehavior` is a good
      example.  How this state is tracked is completely up to the
      Behavior implementation, and there are no formal classes or
      interface specified here.</p>
    <blockquote type="cite"
cite="mid:MWHPR1001MB21734C91DCC8C7860F6607B3E5D5A@MWHPR1001MB2173.namprd10.prod.outlook.com">
      <div class="WordSection1">
        <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>
        <p class="MsoNormal"><span
            style="font-size:11.0pt;font-family:"Iosevka Fixed
            SS16"">Control.setBehavior() is a red flag to me.  As I
            tried to explain before, behaviors is tightly coupled with
            the skin.  One skin may have nodes not present in an
            alternative skin, it might be pointless to design for all
            this variability.  Your Carousel no doubt looks very
            different from TreeTableViewSkin, so all this talk about
            separate behaviors seems like a no-go from the start.</span></p>
      </div>
    </blockquote>
    <p>Then let's drop the pretense here and remove the concept of
      "Behavior" from JavaFX completely.<br>
    </p>
    <p>If we can't make the effort to separate Behavior (which as I said
      before is just a translation of events to higher level events)
      then there is no point in pretending this concept exists at all. 
      Just extend Skin/SkinBase with access to the InputMap and be done
      with it.</p>
    <p>If you however want to make Behaviors into a useful concept, then
      they must be separate from Skins.<br>
    </p>
    <blockquote type="cite"
cite="mid:MWHPR1001MB21734C91DCC8C7860F6607B3E5D5A@MWHPR1001MB2173.namprd10.prod.outlook.com">
      <div class="WordSection1">
        <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>
        <p class="MsoNormal"><span
            style="font-size:11.0pt;font-family:"Iosevka Fixed
            SS16"">Lastly, using event system for skins seems like
            overkill to me.  If applications wants to use that, they can
            do it now (as you undoubtedly know), but adding this whole
            machinery and associated overhead for the sake of skins is,
            in my opinion, unnecessary.<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>
    </blockquote>
    In what way is reusing an existing mechanism to do the indirection
    from events to functions overkill?  It's a known, well tested, and
    currently available system, that is in fact already used for similar
    purposes.<br>
    <blockquote type="cite"
cite="mid:MWHPR1001MB21734C91DCC8C7860F6607B3E5D5A@MWHPR1001MB2173.namprd10.prod.outlook.com">
      <div class="WordSection1">
        <p class="MsoNormal"><span
            style="font-size:11.0pt;font-family:"Iosevka Fixed
            SS16"">Last question: could you give me an example of
            the problem what currently cannot be solved using existing
            mechanisms, or by the input map proposal, but can be solved
            by the alternative proposal?</span></p>
      </div>
    </blockquote>
    <p>I never said your proposal wouldn't get you where you wanted. 
      I'm only saying that JavaFX already could have this (in a lower
      level form) if Behavior event handlers didn't monopolize events. 
      Introducing a new mechanism to solve what IMHO is a fixable flaw
      therefore does not seem like the right approach.</p>
    <p>That said, my proposal does allow for much more than just
      changing the InputMap.  It improves event handling in several ways
      (more events with more meaning, and more guarantees), it provides
      a clear definition of what Behaviors are (they're not a Controller
      in the MVC sense; MVC does not really apply well to the
      Control/Skin/Behavior relationship), and it provides a route to
      allow user Behaviors and customizing FX provided Behaviors.</p>
    <p>Your proposal seems to want to jump straight to that third point
      (customizing Behaviors, albeit only their InputMap), while (as far
      as I can see) not considering all the roads that you will be
      closing off forever by doing so.</p>
    <p>--John<br>
    </p>
    <blockquote type="cite"
cite="mid:MWHPR1001MB21734C91DCC8C7860F6607B3E5D5A@MWHPR1001MB2173.namprd10.prod.outlook.com">
      <div class="WordSection1">
        <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>
        <p class="MsoNormal"><span
            style="font-size:11.0pt;font-family:"Iosevka Fixed
            SS16"">Thank you<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>
        <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 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">John
                  Hendrikx <a class="moz-txt-link-rfc2396E" href="mailto:john.hendrikx@gmail.com"><john.hendrikx@gmail.com></a><br>
                  <b>Date: </b>Monday, October 16, 2023 at 13:10<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>[External] : Re: Alternative approach
                  for behaviors, leveraging existing event system<o:p></o:p></span></p>
            </div>
            <p>Hi Andy,<o:p></o:p></p>
            <p>Thanks for the quick response!<o:p></o:p></p>
            <p>Let me see if I can clarify some of your questions.<o:p></o:p></p>
            <div>
              <p class="MsoNormal"><span style="font-size:11.0pt"><o:p> </o:p></span></p>
            </div>
            <blockquote style="margin-top:5.0pt;margin-bottom:5.0pt">
              <p class="MsoNormal"><span
                  style="font-size:11.0pt;font-family:"Iosevka
                  Fixed SS16 "">Thank you, John, for a detailed
                  writeup.</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 "">Before going into details, I would
                  like to ask you to clarify some of the aspects of the
                  alternative proposal:</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
                  ";background:yellow;mso-highlight:yellow">1. What
                  is the API for setting user event handlers vs.
                  behavior event handlers?</span><o:p></o:p></p>
            </blockquote>
            <p>User handlers stay backwards compatible, so no change
              there, they can be installed as usual.  I only want to
              prevent mixing them up with FX internals, as this makes
              the call order unpredictable depending on when exactly
              your event handler was installed/reinstalled, and what
              type of events it is interested in.<o:p></o:p></p>
            <p>Handlers for behaviors have a lot of freedom of how they
              can be dealt with, as it will all be internal code (when
              users can create behaviors, a small API can be exposed for
              this when installing the behavior).  The event handler
              system could be extended with some kind of priority
              system, or we could create separate lists for behavioral
              handlers (these can use the same EventTypes, but they're
              marked as behavorial -- no need to create new ones, a
              method on EventType to create a behavioral EventType (or
              lower priority type) from the current one should suffice).<o:p></o:p></p>
            <p>The separate list proposal seems easiest; as the event
              system already maintains lists per type, adding new types
              will separate them easily.  The only thing that the event
              system than needs to do is to treat behavioral event
              handlers as lowest priority (either for a complete
              capture/bubble phase or per Node, not sure yet what would
              be best here).<o:p></o:p></p>
            <blockquote style="margin-top:5.0pt;margin-bottom:5.0pt">
              <p class="MsoNormal"><span
                  style="font-size:11.0pt;font-family:"Iosevka
                  Fixed SS16
                  ";background:yellow;mso-highlight:yellow">2. Is
                  there a way to conditionally invoke the default
                  (behavior) event handler if the user event handler
                  decides to do so?</span><o:p></o:p></p>
            </blockquote>
            <p>I see two options; <o:p></o:p></p>
            <p>1. The user handler mimics some behavior and fires the
              same event (ie. control.fireEvent(new
              ButtonEvent(ButtonEvent.BUTTON_FIRE)))<br>
              2. The user can install an event handler/filter to block
              the behavior events when it does not pass a condition<o:p></o:p></p>
            <blockquote style="margin-top:5.0pt;margin-bottom:5.0pt">
              <p class="MsoNormal"><span
                  style="font-size:11.0pt;font-family:"Iosevka
                  Fixed SS16
                  ";background:yellow;mso-highlight:yellow">3. How
                  is the key bindings registered / unregistered /
                  reverted to default?</span><o:p></o:p></p>
            </blockquote>
            <p>Initially, you would do this by registering your own
              event handler that overrides an existing key binding;
              consuming the event will block the default behavior. 
              Removing your event handler will revert it back to
              default.  The only thing that may need additional work is
              when you want to block it from being used by the behavior,
              but still want to let it buble up.  My other post had a
              suggestion to be able to mark the event in some way.<o:p></o:p></p>
            <p>More control can be gained by subclassing or composing an
              existing behavior; see below.<o:p></o:p></p>
            <blockquote style="margin-top:5.0pt;margin-bottom:5.0pt">
              <p class="MsoNormal"><span
                  style="font-size:11.0pt;font-family:"Iosevka
                  Fixed SS16
                  ";background:yellow;mso-highlight:yellow">4. How
                  is the functions mapped to key bindings are registered
                  / unregistered / reverted?</span><o:p></o:p></p>
            </blockquote>
            <p>Functions can be blocked by consuming the relevant
              ButtonEvent; removing that handler will revert it to
              defaults.<o:p></o:p></p>
            <p>Influencing existing behaviors directly I think should be
              done by subclassing the behavior or composing it (if they
              become public).  I have some ideas here, where you are
              passed a Context object:<o:p></o:p></p>
            <p>    interface Behavior<C extends Control> {<br>
                      void install(BehaviorContext<C> context);   <br>
                  }<o:p></o:p></p>
            <p>The BehaviorContext has primarily a method to install an
              event handler:<o:p></o:p></p>
            <p>    <E extends Event> void
              addEventHandler(EventType<E> type, BiConsumer<C,
              E> consumer);<o:p></o:p></p>
            <p>...which is only slightly different from what InputMap
              offers.<o:p></o:p></p>
            <p>The context can further have methods that are more
              convenient:<o:p></o:p></p>
            <p>    void addKeyMapping(KeyCode keyCode,
              EventType<KeyEvent> type, BiConsumer<C,
              KeyEvent> consumer);<o:p></o:p></p>
            <p>The context can also offer methods to remove mappings, so
              subclassed or composed behaviors can remove mappings they
              want to specifically disable.  Other options include
              providing a predicate to make them conditional in a
              subclass/composition.<o:p></o:p></p>
            <p>It could look something like:<o:p></o:p></p>
            <p>      class MyBehavior implements Behavior<Button>
              {<br>
                          public void
              install(BehaviorContext<Button> context) {<br>
                                 // call behavior you wish to base your
              behavior on:<br>
                               
              ButtonBehavior.getInstance().install(context);<br>
              <br>
                                // call methods on context to
              add/remove/remap/conditionalize things that ButtonBehavior
              did<br>
                                // call methods on context to add your
              own custom mappings<br>
                          }<br>
                    }<br>
              <br>
              Installing the custom behavior is then a matter of passing
              it to a Control:<o:p></o:p></p>
            <p>      control.setBehavior(new MyBehavior());  // can be a
              singleton, but not static as it implements interface<o:p></o:p></p>
            <p>The `install` method can associate state if needed by
              associating it with the callbacks it installs:<o:p></o:p></p>
            <p>      State state = new State();<br>
                    BiConsumer<Button, Control> bc = (b, c) ->
              {  // access state here };<br>
              <br>
              Alternatively, the State class can have methods like:<br>
              <br>
                  class State {<br>
                      boolean keyDown;  // some state<br>
              <br>
                      void keyPressed(Button control, KeyEvent event) {<br>
                          if (!control.isPressed() &&
              !control.isArmed()) {<br>
                              keyDown = true;<br>
                              control.fireEvent(new
              ButtonEvent(ButtonEvent.BUTTON_ARM));<br>
                          }<br>
                      }<br>
                  }<br>
              <br>
              And the handler for installing can be referred to with
              "state::keyPressed".<o:p></o:p></p>
            <blockquote style="margin-top:5.0pt;margin-bottom:5.0pt">
              <p class="MsoNormal"><span
                  style="font-size:11.0pt;font-family:"Iosevka
                  Fixed SS16 "">5. Propagating the new events
                  (TextInputControl.SELECT_ALL) up to unsuspecting
                  parents represents a bit of departure, how will that
                  impact all the existing applications?  Probably not
                  much since they will be ignored, with a bit of
                  overhead due to memory allocation, right?</span><o:p></o:p></p>
            </blockquote>
            <p>It's pretty innocuous, the new event types will be
              ignored. There is some overhead associated with using the
              event system for this purpose (although I think it is not
              outside its purpose), but as it is in the context of other
              event processing it's not an order of magnitude
              difference.  Some memory is allocated for the event
              indeed, as it also is already for the events we're
              reacting to.  The event system is I think reasonably
              optimized to skip controls that did not install handlers
              for a given type; most of the time I'd expect say a
              ButtonEvent to travel from the root node immediately to
              the Button control, skipping all parents.<o:p></o:p></p>
            <p>It may also bring some unexpected bonusses as the events
              can be interacted with at higher levels as well (a group
              of Buttons could have handlers that do something with
              ARM/DISARM/FIRE).  It also may enable logging of events
              that are more at a semantic level (button was fired, some
              text was selected), perhaps it may even have applications
              in an undo/redo system.  I for sure see some testing
              applications; behaviors can be tested to send out the
              right events when they're interacted with correctly, while
              controls can use the more semantic events directly for
              testing purposes instead of having to simulate
              clicks/keypresses.<o:p></o:p></p>
            <blockquote style="margin-top:5.0pt;margin-bottom:5.0pt">
              <p class="MsoNormal"><span
                  style="font-size:11.0pt;font-family:"Iosevka
                  Fixed SS16 "">6. If I read it right, it is
                  impossible to redefine the behavior of
                  SomeControl.someFunction() except by subclassing,
                  correct?</span><o:p></o:p></p>
            </blockquote>
            <p class="MsoNormal"><span style="font-size:11.0pt">I'm not
                entirely sure what you mean by that.  Buttons have
                methods like `arm`, `disarm` and `fire`.  Changing how
                those work would require subclassing.<br>
                <br>
                <o:p></o:p></span></p>
            <blockquote style="margin-top:5.0pt;margin-bottom:5.0pt">
              <p class="MsoNormal"><span
                  style="font-size:11.0pt;font-family:"Iosevka
                  Fixed SS16 "">7. I wonder if this will require a
                  more drastic re-write of all the skins?</span><o:p></o:p></p>
            </blockquote>
            <p>If Behaviors become public, I think it would be best that
              Skins are not reliant on them (I think some are?).  As
              long as we're only toying with the event handlers, I think
              Skins are unaffected (unless of course some Skins are
              doing behavioral type stuff that they shouldn't be doing,
              that would be part of a clean up then).<o:p></o:p></p>
            <p>Skins probably shouldn't be accessing the behaviors
              anyway, as I can imagine user controls without skins may
              still want to use behaviors.  In other words, I think
              Skins and Behaviors should be completely separate things
              that don't interact with each other, unless it is via the
              Control.  That will definitely help to keep things
              untangled.<o:p></o:p></p>
            <p>I think it should be possible to do this alternative
              proposal also one control, and one behavior at a time. 
              I've primarily looked at ButtonBehavior so far, and that
              seems pretty trivial to change.<o:p></o:p></p>
            <p>Thanks.<o:p></o:p></p>
            <p>--John<o:p></o:p></p>
            <blockquote style="margin-top:5.0pt;margin-bottom:5.0pt">
              <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 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">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>Monday, October 16, 2023 at 04:51<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>Alternative approach for
                        behaviors, leveraging existing event system</span><o:p></o:p></p>
                  </div>
                  <div>
                    <p class="MsoNormal" style="margin-bottom:12.0pt"><span
                        style="font-size:11.0pt">Hi Andy, hi list,<br>
                        <br>
                        I've had the weekend to think about the proposal
                        made by Andy Goryachev <br>
                        to make some of the API's surrounding InputMap /
                        Behaviors public.<br>
                        <br>
                        I'm having some nagging doubts if that proposal
                        is really the way <br>
                        forward, and I'd like to explore a different
                        approach which leverages <br>
                        more of FX's existing event infrastructure.<br>
                        <br>
                        First, let me repeat an earlier observation; I
                        think event handlers <br>
                        installed by users should always have priority
                        over handlers installed <br>
                        by FX behaviors. The reasoning here is that the
                        user (the developer in <br>
                        this case) should be in control.  Just like CSS
                        will back off when the <br>
                        user changes values directly, so should default
                        behaviors.  For this <br>
                        proposal to have merit, this needs to be
                        addressed.<br>
                        <br>
                        One thing that I think Andy's proposal addresses
                        very nicely is the need <br>
                        for an indirection between low level key and
                        mouse events and their <br>
                        associated behavior. Depending on the platform,
                        or even platform <br>
                        configuration, certain keys and mouse events
                        will result in certain high <br>
                        level actions.  Which keys and mouse events is
                        platform specific.  A <br>
                        user wishing to change this behavior should not
                        need to be aware of how <br>
                        these key and mouse events are mapped to a
                        behavior.<br>
                        <br>
                        I however think this can be addressed in a
                        different way, and I will use <br>
                        the Button control to illustrate this, as it is
                        already doing something <br>
                        similar out of the box.<br>
                        <br>
                        The Button control will trigger itself when a
                        specific combination of <br>
                        key/mouse events occurs.  In theory, a user
                        could install event handlers <br>
                        to check if the mouse was released over the
                        button, and then perform <br>
                        some kind of action that the button is supposed
                        to perform.  In practice <br>
                        however, this is tricky, and would require
                        mimicing the whole process to <br>
                        ensure the mouse was also first **pressed** on
                        that button, if it wasn't <br>
                        moved outside the clickable area, etc.<br>
                        <br>
                        Obviously expecting a user to install the
                        necessary event handlers to <br>
                        detect button presses based on key and mouse
                        events is a ridiculous <br>
                        expectation, and so Button offers a much simpler
                        alternative: the <br>
                        ActionEvent; this is a high level event that
                        encapsulates several other <br>
                        events, and translates it to a new concept.  It
                        is triggered when all <br>
                        the criteria to fire the button have been met
                        without the user needing <br>
                        to be aware of what those are.<br>
                        <br>
                        I think the strategy of translating low level
                        events to high level <br>
                        events, is a really good one, and suitable for
                        reusing for other purposes.<br>
                        <br>
                        One such purpose is converting platform
                        dependent events into platform <br>
                        independent ones. Instead of needing to know the
                        exact key press that <br>
                        would fire a Button, there can be an event that
                        can fire a button.  Such <br>
                        a specific event can be filtered and listened
                        for as usual, it can be <br>
                        redirected, blocked and it can be triggered by
                        anyone for any reason.<br>
                        <br>
                        For a Button, the sequence of events is normally
                        this:<br>
                        <br>
                        - User presses SPACE, resulting in a KeyEvent<br>
                        - Behavior receives KeyEvent and arms the button<br>
                        - User releases SPACE, resulting in a KeyEvent<br>
                        - Behavior receives KeyEvent, disarms and fires
                        the button<br>
                        - Control fires an ActionEvent<br>
                        <br>
                        What I'm proposing is to change it to:<br>
                        <br>
                        - User presses SPACE, resulting in a KeyEvent<br>
                        - Behavior receives KeyEvent, and sends out
                        ButtonEvent.BUTTON_ARM<br>
                        - Control receives BUTTON_ARM, and arms the
                        button<br>
                        - User releases SPACE, resulting in a KeyEvent<br>
                        - Behavior receives KeyEvent and sends out
                        ButtonEvent.BUTTON_FIRE<br>
                        - Control receives BUTTON_FIRE, disarms the
                        button and fires an ActionEvent<br>
                        <br>
                        The above basically adds an event based
                        indirection.  Normally it is <br>
                        KeyEvent -> ActionEvent, but now it would be
                        KeyEvent -> ButtonEvent -> <br>
                        ActionEvent. The user now has the option of
                        hooking into the mechanics <br>
                        of a Button at several different levels:<br>
                        <br>
                        - The "raw" level, listening for raw key/mouse
                        events, useful for <br>
                        creating custom behavior that can be platform
                        specific<br>
                        - The "interpreted" level, listening for things
                        like ARM, DISARM, FIRE, <br>
                        SELECT_NEXT_WORD, SELECT_ALL, etc...; these are
                        platform independent<br>
                        - The "application" level, primarily action type
                        events<br>
                        <br>
                        There is sufficient precedence for such a
                        system.  Action events are a <br>
                        good example, but another example are the DnD
                        events which are created <br>
                        by looking at raw mouse events, effectively
                        interpreting magic mouse <br>
                        movements and presses into more useful DnD
                        events.<br>
                        <br>
                        The event based indirection here is very similar
                        to the FunctionTag <br>
                        indirection in Andy's proposal.  Instead of
                        FunctionTags, there would be <br>
                        new events defined:<br>
                        <br>
                             ButtonEvent {<br>
                                 public static final
                        EventType<ButtonEvent> ANY = ... ;<br>
                                 public static final
                        EventType<ButtonEvent> BUTTON_ARM = ... ;<br>
                                 public static final
                        EventType<ButtonEvent> BUTTON_DISARM = ...
                        ;<br>
                                 public static final
                        EventType<ButtonEvent> BUTTON_FIRE = ... ;<br>
                             }<br>
                        <br>
                             TextFieldEvent {<br>
                                 public static final
                        EventType<TextFieldEvent> ANY = ... ;<br>
                                 public static final
                        EventType<TextFieldEvent> SELECT_ALL = ...
                        ;<br>
                                 public static final
                        EventType<TextFieldEvent> SELECT_NEXT_WORD
                        <br>
                        = ... ;<br>
                             }<br>
                        <br>
                        These events are similarly publically accessible
                        and static as <br>
                        FunctionTags would be.<br>
                        <br>
                        The internal Behavior classes would shift from
                        translating + executing a <br>
                        behavior to only translating it.  The Control
                        would be actually <br>
                        executing the behavior.<br>
                        <br>
                        This also simplifies the role of Behaviors, and
                        maybe even clarifies it; <br>
                        a Behavior's purpose is to translate platform
                        dependent to platform <br>
                        independent events, but not to act on those
                        events.  Acting upon the <br>
                        events will be squarely the domain of the
                        control.  As this pinpoints <br>
                        better what Behavior's purpose it, and as it
                        simplifies their <br>
                        implementation (event translation only) it may
                        be the way that leads to <br>
                        them becoming public as well.<br>
                        <br>
                        ---<br>
                        <br>
                        I've used a similar mechanism as described above
                        in one of my FX <br>
                        Applications; key bindings are defined in a
                        configuration file:<br>
                        <br>
                             BACKSPACE: navigateBack<br>
                             LEFT: player.position:subtract(10000)<br>
                             RIGHT: player.position:add(10000)<br>
                             P: player.paused:toggle<br>
                             SPACE: player.paused:toggle<br>
                             I:<br>
                                 - overlayVisible:toggle<br>
                                 - showInfo:trigger<br>
                        <br>
                        When the right key is pressed (and it is not
                        consumed by anything), it <br>
                        is translated to a new higher level event by a
                        generic key binding <br>
                        system.  This event is fired to the same target
                        (the focused node).  If <br>
                        the high level event is consumed, the action was
                        succesfully triggered; <br>
                        if not, and a key has more than one mapping,
                        another event is sent out <br>
                        that may get consumed or not.  If none of the
                        high level events were <br>
                        consumed, the low level event that triggered it
                        is allowed to propogate <br>
                        as usual.<br>
                        <br>
                        The advantage of this system is obvious; the
                        controls involved can keep <br>
                        the action that needs to be performed separate
                        from the exact key (or <br>
                        something else) that may trigger it.  For
                        "navigateBack" for example, it <br>
                        is also an option to use the mouse; controls
                        need not be aware of this <br>
                        at all.  These events also bubble up; a nested
                        control that has several <br>
                        states may consume "navigateBack" until it has
                        reached its local "top <br>
                        level", and only then let it bubble up for one
                        of its parents to act on.<br>
                        <br>
                        --John</span><o:p></o:p></p>
                  </div>
                </div>
              </div>
            </blockquote>
          </div>
        </div>
      </div>
    </blockquote>
  </body>
</html>