Hi John, I like that you clearly define the terms Control, Skin and Behavior, as well as their roles within the control architecture.
However, I don't see how your proposal scales to non-trivial controls, and I agree with Andy that the Button example doesn't help (because a Button lacks substructure and provides only a single interaction). I'm missing your previous idea of using the event system for higher-level semantic events, because I think they're required to make this work. Here's how I see these parts working together: 1) A control is an opaque node in the scene graph, which defines the API for a particular interactive element. It also defines the interactions afforded by its implementation. For example, a Spinner will usually consist of a text field and two buttons, but a skin might choose to implement these components differently. The interactions afforded by a control are exposed as semantic events: class SpinnerEvent extends Event { static EventType<SpinnerEvent> COMMIT_TEXT; static EventType<SpinnerEvent> START_INCREMENT; static EventType<SpinnerEvent> STOP_INCREMENT; static EventType<SpinnerEvent> START_DECREMENT; static EventType<SpinnerEvent> STOP_DECREMENT; } 2) Skins are responsible for generating semantic events, and sending those events to the control. Since we don't need those events to have a tunneling/bubbling behavior, we could have a flag on the event that indicates a "direct event", one that is dispatched directly to its target. 3) Behaviors listen for semantic events on the control, and convert these events into state changes of the control. This part would probably be quite similar to some of the things that have already been proposed. In this way, controls, skins, and behaviors would end up as loosely coupled parts. In particular, I don't see the value in making behaviors public API if they are so tightly coupled to skins that they end up as being basically implementation details. Andy: > Imagine a specific skin that has a Node that accepts a user input. A scroll > bar, a button, or a region with a some function. Unless this element is > proclaimed as must-have for any skin and codified via some new public API > (MySkin.getSomeElement()), it is specific to that particular skin and that > particular behavior. I think that's a very important observation. A skin can't just be anything it wants to be, it must be suitable for its control. So we need a place where we define the API and the interactions afforded by that control. In my opinion, this place is the Control. Its functionality is exposed via properties and methods, and its interactions are specified using semantic events. Now skins are free to be implemented in any imaginable way, provided that they interact with the control using semantic events. This gives us very straightforward restrictions: * A skin can never add interactions that the control didn't specify. * If additional interactions are required, the control must be subclassed and the interactions must be specified by the control. Additionally, the behavior must be extended to account for the additional interactions. On Mon, Nov 6, 2023 at 4:50 AM John Hendrikx <john.hendr...@gmail.com> wrote: > > As promised, a public Behavior API proposal. > > Summary: > > Introduce a new Behavior interface that can be set on a control to replace > its current behavior. The new behavior can be fully custom or composed (or > later subclassed) from a default behavior. Some default behaviors will be > provided as part of this proposal, but not all. > > See here: https://gist.github.com/hjohn/293f3b0ec98562547d49832a2ce56fe7 > > --John