<html>
  <head>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
  </head>
  <body>
    <p>Hi Andy,<br>
    </p>
    <p>Thanks for the quick response!</p>
    <p>Let me see if I can clarify some of your questions.<br>
    </p>
    <div class="moz-cite-prefix"><br>
    </div>
    <blockquote type="cite"
cite="mid:DM5PR1001MB2172BB7D8C3D8B665859CAB2E5D7A@DM5PR1001MB2172.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: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;}p.MsoNormal, li.MsoNormal, div.MsoNormal
        {margin:0in;
        font-size:10.0pt;
        font-family:"Calibri",sans-serif;}span.EmailStyle19
        {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"">Thank you, John, for a detailed writeup.<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"">Before going into details, I would like to ask
            you to clarify some of the aspects of the alternative
            proposal:<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"">1. What is the API for setting user event
            handlers vs. behavior event handlers?</span></p>
      </div>
    </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.<br>
    </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).</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).<br>
    </p>
    <blockquote type="cite"
cite="mid:DM5PR1001MB2172BB7D8C3D8B665859CAB2E5D7A@DM5PR1001MB2172.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"">2. Is there a way to conditionally invoke the
            default (behavior) event handler if the user event handler
            decides to do so?</span></p>
      </div>
    </blockquote>
    <p>I see two options; <br>
    </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<br>
    </p>
    <blockquote type="cite"
cite="mid:DM5PR1001MB2172BB7D8C3D8B665859CAB2E5D7A@DM5PR1001MB2172.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"">3. How is the key bindings registered /
            unregistered / reverted to default?</span></p>
      </div>
    </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.</p>
    <p>More control can be gained by subclassing or composing an
      existing behavior; see below.<br>
    </p>
    <blockquote type="cite"
cite="mid:DM5PR1001MB2172BB7D8C3D8B665859CAB2E5D7A@DM5PR1001MB2172.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"">4. How is the functions mapped to key bindings
            are registered / unregistered / reverted?</span></p>
      </div>
    </blockquote>
    <p>Functions can be blocked by consuming the relevant ButtonEvent;
      removing that handler will revert it to defaults.</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:</p>
    <p>    interface Behavior<C extends Control> {<br>
              void install(BehaviorContext<C> context);   <br>
          }</p>
    <p>The BehaviorContext has primarily a method to install an event
      handler:</p>
    <p>    <E extends Event> void
      addEventHandler(EventType<E> type, BiConsumer<C, E>
      consumer);<br>
    </p>
    <p>...which is only slightly different from what InputMap offers.</p>
    <p>The context can further have methods that are more convenient:</p>
    <p>    void addKeyMapping(KeyCode keyCode, EventType<KeyEvent>
      type, BiConsumer<C, KeyEvent> consumer);</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.</p>
    <p>It could look something like:</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:</p>
    <p>      control.setBehavior(new MyBehavior());  // can be a
      singleton, but not static as it implements interface</p>
    <p>The `install` method can associate state if needed by associating
      it with the callbacks it installs:</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".<br>
    </p>
    <blockquote type="cite"
cite="mid:DM5PR1001MB2172BB7D8C3D8B665859CAB2E5D7A@DM5PR1001MB2172.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"">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></p>
      </div>
    </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.</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.<br>
    </p>
    <blockquote type="cite"
cite="mid:DM5PR1001MB2172BB7D8C3D8B665859CAB2E5D7A@DM5PR1001MB2172.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"">6. If I read it right, it is impossible to
            redefine the behavior of SomeControl.someFunction() except
            by subclassing, correct?</span></p>
      </div>
    </blockquote>
    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>
    <blockquote type="cite"
cite="mid:DM5PR1001MB2172BB7D8C3D8B665859CAB2E5D7A@DM5PR1001MB2172.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"">7. I wonder if this will require a more drastic
            re-write of all the skins?</span></p>
      </div>
    </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).</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.<br>
    </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.</p>
    <p>Thanks.</p>
    <p>--John<br>
    </p>
    <blockquote type="cite"
cite="mid:DM5PR1001MB2172BB7D8C3D8B665859CAB2E5D7A@DM5PR1001MB2172.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>
        <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 class="moz-txt-link-rfc2396E" href="mailto:openjfx-dev-retn@openjdk.org"><openjfx-dev-retn@openjdk.org></a> on behalf of 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 04:51<br>
                  <b>To: </b><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>Alternative approach for behaviors,
                  leveraging existing event system<o:p></o:p></span></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<o:p></o:p></span></p>
            </div>
          </div>
        </div>
      </div>
    </blockquote>
  </body>
</html>