Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Focus model of Red is too complicated #172

Open
hiiamboris opened this issue Dec 11, 2024 · 0 comments
Open

Focus model of Red is too complicated #172

hiiamboris opened this issue Dec 11, 2024 · 0 comments

Comments

@hiiamboris
Copy link

hiiamboris commented Dec 11, 2024

Currently in Red there's a mix of three focus models:

  1. Single per-OS focused face

    This is the model closest to the actual UX: there is at any point in time only one focused (receiving keyboard events) widget in the OS. Presence of this model is evidenced by the fact that (at least on Windows) set-focus on any face activates (brings to top) its parent window.

  2. Per-window focused face

    Presence of this model is evidenced by the fact that each window face has a /selected facet, and that to move the focus it suffices to set this facet (as done by the set-focus function).

  3. A tree of /selected faces

    Presence of this model is evidenced by other (than window) container face types having a /selected facet - e.g. panel, tab-panel, group-box.

As a result of this mix-up we're having numerous focus-related issues and total inability to reliably tell programmatically (on Red level) where the focus currently is (e.g. in a multi-window program we can't tell which window is in focus).

UX requirements for the focus model as I see are as follows:

  1. Only one widget in the OS has focus at any moment in time
  2. Parents of a focused widget are aware of the focus and may also alter their appearance (e.g. active window's title bar)
  3. When some container widgets (window, tab) are activated, focus may go directly into one of their children. They can be nested, so activation of an outer container may trigger activation of an inner container, which in turn may trigger activation of its child

To satisfy these requirements with minimal complexity I propose adopting the following focus implementation based on model (1):

  1. A global per-interpreter setting holds the currently focused widget (e.g. system/view/focus):

    • it should equal none when focus is in another program, and when set to none, currently active window should be deactivated
    • it should be set to the currently focused face when it is the target of keyboard events in the currently active window; setting it should focus the face and bring window to top
    • it should be set to the currently active window when no face has focus, or when window menu is interacted with (as it has no equivalent face in Red)
    • ideally it should be assumed that objects other than face can be assigned to it (e.g. space objects); in this case a helper function should be exposed to connect that space object to the actual parent base face focusing procedure in the OS

    Each face's or space's location on the widgets tree is known from the chain of its and its ancestors' /parent facets, so having a global setting holding the widget is enough, and there's no need in a separate "focus tree" formed by /selected facets or anything else.

  2. Focus events are captured/bubbled (as they currently are).

  3. Some widgets (e.g. window and tab-panel faces) should remember their last focused child and restore focus to this child on window activation or when switching between tabs (e.g. the same /selected but with a note that it's not the same as focused)

    Normally for this to work, on-focus event should be captured by each container face before it reaches the child. Since Red View UI is powered by the OS, actual capture will be hidden in the R/S part. But I think it still must follow the event capturing phase so that Red-level on-detect event coincides with the actual memorization of the child.

I also suggest that whenever container has scrollbars, once focus is set to its (probably deep) child, it should scroll itself to make that child visible. Other cases where such "bringing widget to focus" should be performed is when widget content is changed - usually as a result of keystroke input, but there may be other cases (like input simulation or interactive UI tutorials), where it may be useful, so it would be best to make this functionality available to the programmer. Ideally, the procedure should be "deep" in a sense that it should bubble through all the ascendants and scroll them to render the altered UI region visible.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant