Skip to content

Focus model of Red is too complicated #172

Open
@hiiamboris

Description

@hiiamboris

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.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions