Struct FocusManager
pub struct FocusManager(/* private fields */);Expand description
Focus Manager enables you to set and change the key focus between attached nodes. Each domain can have only one instance of a Focus Manager.
§Focusable node
A focusable node is a node that is attached to the scene graph and has the Node::FocusableProperty set to true. Kanzi can set focus only to focusable nodes. When a node has the Node::FocusableProperty set to false, Kanzi excludes that node from the focus management. This is the default setting.
§Key focus node
The key focus node of an application is the node that receives all the key input, and has the read-only Node::FocusedProperty set to true. Kanzi controls the value of the Node::FocusedProperty internally. Changing the value of the property does not set the key focus node. To set the key focus node, use trySetFocus() or tryMoveFocus() or one of its variants.
§Focus chain and focus order
A focus chain is the sequence of nodes that defines the order in which Kanzi applies focus to nodes when the application user moves the focus in a focus scope using the focus chain navigation methods. Each focus scope node has its own focus chain.
To set the order of a node in a focus chain, use the FocusOrderProperty. When you do not set the value of the FocusOrderProperty, the node tree order determines the order of the node in a focus chain.
§Focus scopes
Kanzi organizes nodes in focus scopes. Focus scopes are nodes which assist in focus chain navigation handling. Focus scopes group their child nodes and drive the focus navigation within that group. They also act like a focus proxy, forwarding the focus to one of their focusable child nodes.
When a focus scope receives focus, Kanzi tries to move the focus to the last-focused node of the focus scope. If focus has not yet visited the focus scope, Kanzi tries to focus:
-
The first focusable node of the focus chain, if the reason the focus scope receives the focus is not backward focus chain navigation.
The first focusable node is either the node with the smallest value of the FocusOrderProperty, or the first node in the node tree of the focus scope.
-
The last focusable node of the focus chain, if the focus scope receives the focus because of backward focus chain navigation.
The last focusable node is either the node with the largest value of the FocusOrderProperty, or the last node in the node tree of the focus scope.
When you move the focus away from a focus scope, that scope remembers its last-focused child node.
For more details on focus navigation with scopes, see ScopeFocusNavigation “Setting focus to focus scope nodes and focus navigation in focus scopes”.
§Focus scope types
Kanzi defines these focus scope types:
-
Focus group groups focusable nodes. This is the simplest type of focus scope. You can move the focus to the focus group and out of the focus group.
To make a node a focus group, in that node set the FocusScopeTypeProperty to FocusScopeType::Group.
-
Focus fence keeps the focus navigation inside the scope and does not allow the focus navigation to enter or leave that scope.
To make a node a focus fence, in that node set the FocusScopeTypeProperty to FocusScopeType::Fence.
-
Overlay focus scope types:
-
Modal overlay blocks the key and touch input that originates from outside its boundaries and keeps the focus navigation within the overlay boundaries, just like a focus fence. Every Kanzi application has at least one modal overlay: the Screen node.
To make a node a modal overlay, in that node set the FocusScopeTypeProperty to FocusScopeType::Modal.
-
Modeless overlay propagates the key and touch input that originates from outside its boundaries, but keeps the focus navigation within the focus scope boundaries, just like a modal overlay.
To make a node a modeless overlay, in that node set the FocusScopeTypeProperty to FocusScopeType::Modeless.
-
Auto-closing modal overlay is similar to modal overlay, except that when the overlay is an Activity in a Parallel Activity Host, the Parallel Activity Host deactivates that Activity when user input originates from outside the boundaries of that Activity.
To make a node an auto-closing modal overlay, in that node set the FocusScopeTypeProperty to FocusScopeType::AutoClosingModal.
-
Auto-closing modeless overlay is similar to modeless overlay, except that when the overlay is an Activity in a Parallel Activity Host, the Parallel Activity Host deactivates that Activity when:
- User input originates from outside the boundaries of that Activity.
- Focus moves to an overlay that is behind that Activity.
To make a node an auto-closing modal overlay, in that node set the FocusScopeTypeProperty to FocusScopeType::AutoClosingModeless.
One overlay at a time can be the focused overlay. The focus node of the focused overlay is the key focus node of the application and receives key input.
The focus node of an overlay that is currently not the focused overlay is the logical focus node of that overlay. This node was the key focus node before the overlay lost focus. Once the overlay regains focus, the logical focus node becomes the key focus node of the application.
When user input originates from a node that is outside the node tree of an overlay focus scope, that overlay focus scope sends the InputOutsideOverlayMessage message. A Parallel Activity Host automatically handles the InputOutsideOverlayMessage message sent by an Activity which is an auto-closing overlay. For an overlay focus scope node that is not an Activity you can handle the InputOutsideOverlayMessage message manually. For example, you can make a modeless overlay invisible when user input originates from outside its boundaries.
An overlay focus scope has no parent focus scope.
§Nesting focus scopes
Kanzi organizes nodes in a tree of nodes and organizes focus scopes in the same tree. This enables you to create focus scopes inside focus scopes, that is, nested focus scopes. A nested focus scope behaves the same way as any other focus scope: it forwards and remembers the focus of its child node the same way, regardless of its nested state. When the last-focused node of a focus scope is a nested focus scope, if the nested focus scope is a focus group or a focus fence, Kanzi forwards the focus to the last-focused node of that focus group or focus fence.
Kanzi does not include the nested overlay focus scopes from the focus chain, and does not remember these overlay scope nodes as last-focused nodes. To learn how Kanzi handles these scope types, see OverlayFocusScopeStackAndInputDelivery “Overlay focus scope stack and input delivery”.
§Setting focus
To set focus to a node:
-
In the node set these properties:
- Node::FocusableProperty to true.
- Node::EnabledProperty to true. This is the default value.
- Node::VisibleProperty to true. This is the default value.
-
Attach the node to the node tree of a focus scope that is either the foremost modal overlay in your application or a modeless overlay on top of the foremost modal overlay.
For example, attach the node to the Screen or a Viewport2D node.
Kanzi can set focus to a node that is in the process of being attached to the node tree, but not to a node that is not attached to the node tree.
-
Use one of the trySetFocus() methods to set focus to the node.
To set focus to a node:
§Getting focus
To retrieve the node that has the key focus, use the getFocus() method.
Kanzi uses these properties to indicate if a node is the focus node of an overlay or if a focus scope contains the focus node of an overlay:
-
Node::FocusedProperty reports whether a node has the key focus and receives key input. Only one node in an application can have this property set to true at a time.
-
Node::FocusStateProperty when set to FocusState::LogicalFocus indicates that the node is the logical focus node of an overlay that is currently not the focused overlay. The logical focus node gets the key focus when the overlay, to which the node belongs, regains the focus.
-
Node::FocusStateProperty in a focus scope node can have these values:
- FocusState::NoFocus indicates that none of the nodes in that scope have focus.
- FocusState::LogicalFocus indicates that one of the nodes in that scope is the logical focus node of the overlay to which the scope belongs.
- FocusState::KeyFocus indicates that one of the nodes in that scope is the key focus node of the overlay to which the scope belongs.
For example, you can use the Node::FocusedProperty or Node::FocusStateProperty in a binding or as a controller property in a state manager to change the look and behavior of the node that has the key focus or is the logical focus of an overlay.
§The impact of the Node::VisibleProperty on the focused node
When you hide a node that has focus, by setting the Node::VisibleProperty to false:
- The Focus Manager dispatches the FocusLostMessage with FocusReason::Hidden and the application loses the focus.
- Kanzi clears the last-focused node information of all ascendant focus scopes of the node that you hid.
You cannot set the focus to a hidden node.
§The impact of the Node::EnabledProperty on the focused node
When you disable a node that has focus, by setting the Node::EnabledProperty to false, the Focus Manager keeps the focus on that node and continues to deliver input events to its attached Input Manipulators. UI nodes are responsible for checking their enabled state when receiving input events, and deciding whether to handle those events. You cannot set focus to a disabled node.
§Focus chain navigation
Unless you want to override the default behavior, or you want to provide other triggers to move the focus across the nodes, you do not need to care about the default key navigation. You can override the default key navigation by customizing the FocusNavigationManipulator installed on the focus scope, or setting your own focus navigation manipulator to the focus scope. Other means of focus chain navigation you can use are actions that are triggered by property changes, state changes on nodes, and so on.
The default chain navigation keys are the Tab and BackTab keys. The forward direction navigates the focus from the node with smaller value of the attached FocusOrderProperty to the nodes with higher value of the attached FocusOrderProperty, while backwards direction navigates the focus in the opposite direction.
Kanzi restricts the focus chain navigation to within a specific overlay focus scope and, when performing focus chain navigation, skips the nested focus fences, the focus groups with empty focus chain, and overlay focus scopes.
Kanzi automatically includes in the focus chain all nodes in a focus scope that have the Node::FocusableProperty, Node::EnabledProperty, and Node::VisibleProperty set to true. To move the focus to the next node in the focus chain, call the tryMoveFocus() method or one of its overrides.
When Tab and BackTab keys are functional keys of a node, that node consumes the keys used by the focus chain navigation. When such node receives focus, the Focus Manager is no longer able to move the focus from that node through the key input events. To use keys to move focus from such node, you must install a FocusNavigationManipulator to that node, and set custom keys to move the focus from the node.
To move focus in focus chain from a node that consumes the Tab and BackTab keys:
§Setting focus to focus scope nodes and focus navigation in focus scopes
When you set the focus to a focus scope node, Kanzi tries to restore the focus on the last-focused node of the focus scope.
When you set the focus to a focus scope node using the tryMoveFocusBackward() method, and the focus scope has no last-focused node remembered, Kanzi tries to move the focus to the last focusable node of the focus chain of the focus scope.
When you set the focus to a focus scope node using trySetFocus() or any other variant of the tryMoveFocus() methods, and the focus scope has no last-focused node remembered, Kanzi tries to move the focus to the first focusable node of the focus chain of the focus scope.
To set the focus on the last focusable child node of a scope:
When you move the focus out from a focus scope, the focus scope remembers the focus state of its last-focused node. This way when you return the focus to the focus scope using the trySetFocus() or tryMoveFocus() method, Kanzi restores the focus on this node, unless the last-focused node is detached from the UI scene.
To move the focus back to the last-focused node of a focus scope:
When you set the focus to a focus scope using the focus chain navigation methods, such as tryMoveFocus() and its overrides, the focus scope forwards the focus to its last-focused child node. Further calls on the method move the focus in the direction specified, to the next or previous node in the focus chain, including nested focus scopes.
When a node gets focus, all its ascendant focus scopes get their focus state set to true. The focus scopes keep the focus state as long as the focus node remains in their scope. When you move the focus away from a node, all its ascendant focus scopes get their focus state set to false.
This example shows this scenario:
Kanzi skips focus scopes in the focus chain navigation, because a focus scope does not get focus as long as it has child nodes that can get focus. The child nodes of a focus scope node that is hidden or disabled cannot get focus. You can exclude a focus scope node from the focus chain by setting either the Node::EnabledProperty or the Node::VisibleProperty to false.
You can route the default focus chain navigation in the same way as regular focus nodes. In that case, focus chain navigation follows the routed nodes and focuses the nodes or focus scopes routed when the focus navigation leaves the focus scope:
- In the forward navigation after the last node of the focus chain is visited
- In the backward navigation after the first node of the focus chain is visited
Use a focus fence (FocusScopeType::Fence) when you want to keep the focus chain navigation within the boundaries of a focus scope.
Kanzi keeps the focus chain navigation inside a focus fence and skips fences when the focus chain navigation happens outside of those focus fences. Kanzi also ignores the focus routing to focus fences. You can move the focus from within a focus fence to a node outside of the focus fence, and the other way around, only using the trySetFocus() method.
This example shows the focus fence behavior:
§Overlay focus scope stack and input delivery
By default, Kanzi delivers touch input to all nodes in an overlay focus scope, including the nested focus scopes that are not overlay focus scopes. Kanzi keeps track of the overlay focus scopes of an application that are attached to the node tree, and organizes them in the form of a stack. If the foremost overlay focus scope is a modeless overlay, Kanzi delivers the touch input that occurs outside of the foremost overlay focus scope boundaries to the overlay focus scopes that precede the foremost overlay scope.
When Kanzi detects touch input that originates outside an overlay scope, it sends the InputOutsideOverlayMessage message. To enable Kanzi to detect the origin of the touch input, you must set the Node::HitTestableProperty to true on the overlay scopes.
Kanzi delivers the key input to the foremost overlay scope first. If the foremost overlay scope does not consume the key input, and that scope is a modeless overlay, Kanzi propagates the key input to the overlay scopes that precede the foremost overlay scope. If the key is handled in one of the propagated overlay scopes, and the scope is a modeless overlay, Kanzi sends the InputOutsideOverlayMessage message.
When you attach an overlay scope node to the UI scene, Kanzi inserts that overlay scope to the overlay scope stack according to the rendering order of the nodes in the UI scene. The overlay scope receives:
- OverlayBroughtToFrontMessage when it becomes the foremost overlay scope.
- OverlaySentToBackMessage when it is no longer the foremost overlay scope.
When you hide an overlay scope node by setting Node::VisibleProperty to false on that node, Kanzi removes the overlay focus scope from the focus scope stack. When the overlay scope node is made visible again, Kanzi adds the overlay focus scope back to the focus scope stack.
To create a modal overlay node:
To bring an overlay focus scope to front:
To send an overlay focus scope back:
When you detach an overlay focus scope node from the node tree, Kanzi removes that overlay focus scope from the FocusManager. When Kanzi removes an overlay focus scope from the FocusManager, it marks that focus scope as detached. A detached overlay focus scope remembers its last-focused node.
When you attach a detached overlay focus scope node to the node tree, if that overlay scope becomes the foremost overlay scope, Kanzi restores the focus of that overlay scope.
§Cyclic focus navigation
When you move the focus forward or backward in a focus scope, and the focus reaches the last or first focusable node of the focus scope, Kanzi looks for the sibling of the focus scope to continue the focus chain navigation. When Kanzi cannot find a focus candidate in an overlay focus scope in the navigation direction, Kanzi by default keeps the focus on the last focused node. To enable cyclic focus navigation, attach the CyclicFocusNavigationProperty to the focus scope node, and set the property value to true.
In cyclic focus navigation:
- When during forward focus navigation the focus reaches the last focusable UI element of the focus scope, focus navigation moves from there to the first focusable UI element.
- When during backward focus navigation the focus reaches the first focusable UI element of the focus scope, focus navigation moves from there to the last focusable UI element.
You can enable cyclic focus navigation for any focus scope node. When you enable cyclic focus navigation, the focus chain navigation never leaves the boundaries of the focus scope.
§Focus change notifications
Kanzi uses focus change notification messages to inform UI nodes about changes in the application focus and focus scope type of nodes. The set of messages that Kanzi dispatches depends on which focus action caused the change.
Kanzi dispatches these messages to notify nodes about focus changes:
- AboutToLoseFocusMessage to the node that is about to lose the focus.
- AboutToGainFocusMessage to the node that is about to gain the focus.
- FocusLostMessage to the node that lost the focus.
- FocusGainedMessage to the node that gained the focus.
- FocusEnteredFocusScopeMessage to the focus scope node to which the focus moved.
- FocusLeftFocusScopeMessage to the focus scope node from which the focus left.
- OverlayBroughtToFrontMessage to the overlay focus scope node that moved to the top of the overlay focus scope stack.
- OverlaySentToBackMessage to the focus scope node of the overlay that is no longer the foremost overlay in the overlay focus scope stack.
- OverlayGainedFocusMessage to the focus scope node of the overlay that became the focused overlay scope.
- OverlayLostFocusMessage to the overlay focus scope node of the overlay that previously was the focused overlay scope.
Each message contains an argument that specifies the reason of the focus change.
Kanzi dispatches different sets of messages depending on the type of change:
- Focus scope related messages only when there is a change in the currently focused focus scope.
- Overlay related messages only when there is a change in the currently focused overlay.
- OverlayBroughtToFrontMessage and OverlaySentToBackMessage only when there is a change in the foremost overlay focus scope.
These examples show how to handle the messages that Kanzi dispatches before the focus moves.
The pre-focus message handlers are: To move focus:
When focus is set to a node and the application has no focus:
When focus is removed from the application:
When focus moves to a node in the same focus scope:
When focus moves to a node in a different focus scope because of trySetFocus() or tryMoveFocus() call:
When focus moves from a node in an overlay to a node in another overlay because of trySetFocus() call or because the overlay is detached:
Kanzi dispatches the OverlayGainedFocusMessage, FocusEnteredFocusScopeMessage, FocusLeftFocusScopeMessage, and OverlayLostFocusMessage only if the focused overlay or the focus scope that contains the key focus changes because of a focus change.
When there is a change in the overlay scope stack because a node was detached or attached, or its visibility changed:
-
When an overlay focus scope node, which is behind the currently focused overlay and is invisible, is made visible, Kanzi does not dispatch any focus change notifications.
-
When an overlay focus scope node is attached to be the foremost overlay but there is no application focus, and the attached overlay node has no focusable nodes, Kanzi dispatches only the OverlayBroughtToFrontMessage and OverlaySentToBackMessage.
-
When an overlay focus scope node is attached to be the foremost overlay and there is an existing application focus, Kanzi dispatches all focus change notifications:
-
When the overlay focus scope node of the foremost overlay, which holds the application focus, is detached from the node tree, Kanzi dispatches all focus change notifications:
When the Focus Scope Type of a node changes, Kanzi:
- Removes the application focus.
- Applies the scope type change.
- Tries to restore the focus to the previously focused node if the scope type change itself does not cause Kanzi to restore focus to a node.
The focus scope type change concerns also the case where a new focus scope type is assigned to a node. The focus scope type of a node is expected to change only while using the Kanzi Studio Preview. There should be no need to change the focus scope type of a node dynamically at runtime.
The focus scope type change determines which messages Kanzi dispatches and their order:
-
When there is no application focus and a node, which is eligible to gain focus, is set to be an overlay focus scope:
-
When the application has focus and a node which is set to be an overlay focus scope becomes the foremost overlay:
-
When the focus scope type of the focus scope that contains the focus changes from group to fence:
-
When there is no application focus and focus scope type changes from group to fence, Kanzi does not dispatch any message.
-
When there is no application focus, and focus scope type changes from one overlay type to another, Kanzi does not dispatch any message.
-
When the application focus is in an overlay whose focus scope type changes to an other overlay type:
Trait Implementations§
§impl Clone for FocusManager
impl Clone for FocusManager
§fn clone(&self) -> FocusManager
fn clone(&self) -> FocusManager
1.0.0 · Source§fn clone_from(&mut self, source: &Self)
fn clone_from(&mut self, source: &Self)
source. Read more