mirror of
https://git.planet-casio.com/Lephenixnoir/JustUI.git
synced 2024-12-28 20:43:40 +01:00
add notes about keyboard focus system
This commit is contained in:
parent
f28d7a9cb8
commit
7a5101360a
1 changed files with 104 additions and 1 deletions
105
doc/scene.md
105
doc/scene.md
|
@ -1,3 +1,106 @@
|
||||||
# JustUI: Scenes and events
|
# JustUI: Scenes, events and keyboard focus
|
||||||
|
|
||||||
|
## Introduction
|
||||||
|
|
||||||
|
The _scene_ in JustUI is the component sitting at the root of the widget hierarchy. It handles all the dynamic aspects of the UI, including distributing/propagating events and managing keyboard focus among the widgets.
|
||||||
|
|
||||||
|
Ideas...
|
||||||
|
|
||||||
|
New keyboard focus system.
|
||||||
|
1. Principle and conforming states
|
||||||
|
a. Widgets have a focus policy of FOCUS_ACCEPT, FOCUS_SCOPE or FOCUS_REJECT,
|
||||||
|
and two status flags FOCUSED and ACTIVE_FOCUSED whose valid combinations
|
||||||
|
describe 3 focus levels: *no focus* (F=0), *inactive focus* (F=1, AF=0),
|
||||||
|
and *active focus* (F=1, AF=1).
|
||||||
|
b. Each focus scope defines a region consisting of its subtree but excluding
|
||||||
|
itself and any children of other focus scopes. Up to one widget of policy
|
||||||
|
FOCUS_ACCEPT or FOCUS_SCOPE in the region may have its FOCUSED flag set,
|
||||||
|
called the *focus target* of the scope. The ACTIVE_FOCUSED flag of the
|
||||||
|
target is equal to the scope's.
|
||||||
|
c. Every focus scope fs induces a *focus chain* fc(fs), where
|
||||||
|
fc(w) = [] if w is FOCUS_ACCEPT or w is FOCUS_SCOPE with no target;
|
||||||
|
fc(w) = fc(target) + [target] if w is a scope with the named target.
|
||||||
|
Note that as a result of 1.b all elements of the chain have their FOCUSED
|
||||||
|
flag set and their ACTIVE_FOCUSED flags equal to that of fs.
|
||||||
|
d. jscene is a focus scope defined to have its ACTIVE_FOCUSED always set,
|
||||||
|
the only such widget that doesn't inherit this flag from a scope parent.
|
||||||
|
As such, the ACTIVE_FOCUSED flag identifies the focus chain of the scene.
|
||||||
|
jscene offers keyboard events to its focus chain, propagating rejected
|
||||||
|
events in list order.
|
||||||
|
X. The first (deepest) widget in the scene's focus chain is said to have
|
||||||
|
*strong focus*. Other widgets this chain are said to have *weak focus*.
|
||||||
|
-> TODO: Strong/weak focus is an informal substate of active focus and
|
||||||
|
may not be kept in the future.
|
||||||
|
2. Operations
|
||||||
|
a. The core operation is a changing the target of a scope, which can be
|
||||||
|
initiated by any widget in the region through a widget-context call. The
|
||||||
|
consequences of this operation are as follow:
|
||||||
|
- The old target, if any, loses its FOCUSED and ACTIVE_FOCUSED flags. If
|
||||||
|
it's a scope and it had active focus, all widgets in its focus chain
|
||||||
|
also lose active focus.
|
||||||
|
- The new target, if any, gets its FOCUSED flag and the scope's value for
|
||||||
|
the ACTIVE_FOCUSED flag. If it's a focus scope and it gets active
|
||||||
|
focus, then its focus chain also gets active focus.
|
||||||
|
All widgets affected receive a FOCUS_CHANGED event and the scope itself
|
||||||
|
receives a FOCUS_TARGET_CHANGED event.
|
||||||
|
b. There is a widget-scene call to give a widget active focus. If the widget
|
||||||
|
has policy FOCUS_ACCEPT or FOCUS_SCOPE, this call walks up the scope
|
||||||
|
chain and assigns new targets until it reaches the scene. If the widget
|
||||||
|
has policy FOCUS_NONE, this call just removes the surrounding scope's
|
||||||
|
target.
|
||||||
|
X. There is a widget-context call to relinquish one's own focus within the
|
||||||
|
parent scope. This is intended to differ from 2.b in that scopes might
|
||||||
|
implement special logic for moving focus to a nearby widget.
|
||||||
|
-> TODO: Left unresolved for later
|
||||||
|
3. Key-listener pattern
|
||||||
|
a. The operations described in 2.a and 2.b allow a "key-listener" pattern
|
||||||
|
where a widget "klw" (not the scene) receives keyboard events from its
|
||||||
|
potentially-focused descendants (i.e. inserts itself in the focus chain)
|
||||||
|
without impacting the focus mechanics of its surrounding scope "ssw".
|
||||||
|
b. The pattern consists of making klw a focus scope, and whenever it
|
||||||
|
receives a FOCUS_TARGET_CHANGED event that assigns a target, make klw
|
||||||
|
grab focus within ssw. This way, with regards to ssw, when focus moves:
|
||||||
|
- From within klw to within klw:
|
||||||
|
the grab is a no-op: OK.
|
||||||
|
- From within klw to outside it:
|
||||||
|
outside widget gets focus within ssw and klw does nothing: OK.
|
||||||
|
- From outside klw to within it:
|
||||||
|
inside widget gets focus in klw, klw gets focus in ssw: OK.
|
||||||
|
- From outside klw to outside it:
|
||||||
|
normal retargeting within ssw.
|
||||||
|
X. Should this be a built-in behavior?
|
||||||
|
|
||||||
|
4. Behavior of built-in widgets
|
||||||
|
a. `jfileselect`, `jinput`, `jlist` have policy FOCUS_ACCEPT
|
||||||
|
b. `jscene` has policy FOCUS_SCOPE
|
||||||
|
TODO: What about jframe?
|
||||||
|
c. `jfkeys` has policy `FOCUS_REJECT` and must be given events manually
|
||||||
|
d. Widgets with a stack layout will try and give focus (within their
|
||||||
|
surrounding scope) to the current element. If the element is complex, it
|
||||||
|
should be a focus scope. Similarly, widgets with invisible children will
|
||||||
|
move focus around to their direct children as needed to make sure focus
|
||||||
|
remains on a visible child.
|
||||||
|
|
||||||
|
5. Implementation
|
||||||
|
a. Events are `FOCUS_CHANGED` when own FOCUSED and ACTIVE_FOCUSED flags have
|
||||||
|
changed, and `FOCUS_TARGET_CHANGED` for scopes when the target changes.
|
||||||
|
|
||||||
|
NOTES:
|
||||||
|
- Focus events don't propagate but are replicated, which adds some complexity
|
||||||
|
- Focus scopes could have background focus for jfkeys (left for later). Hard
|
||||||
|
part is this isn't specified by jfkeys.
|
||||||
|
Could tell users to add this to their main loop, or follow gscreen:
|
||||||
|
jevent e = jscene_run();
|
||||||
|
if(jwidget_event(fkeys, e)) continue;
|
||||||
|
- Is there any sensible definition to "relinquishing" focus? In gintctl if e.g.
|
||||||
|
an jinput validates we want to take its focus away and put it back somewhere
|
||||||
|
sensible (i.e. the gscreen, not NULL, otherwise we don't have F-keys anymore)
|
||||||
|
- Some functions from <jwidget-api.h> should go to <jwidget.h>
|
||||||
|
- Functions from <jwidget.h> that require context or operate on the whole tree
|
||||||
|
should **really** be identified clearly. Everything by default should just
|
||||||
|
treat the widget as a box in a void.
|
||||||
|
-> Previously this was in jscene. Why not keep it that way?
|
||||||
|
|
||||||
|
## Keyboard focus and event propagation
|
||||||
|
|
||||||
TODO.
|
TODO.
|
||||||
|
|
Loading…
Reference in a new issue