Fixed `modal` focus.

This commit is contained in:
Samuel Guerra 2022-02-01 01:18:58 -03:00
parent 8547c1dc9b
commit 080461fe60
8 changed files with 38 additions and 18 deletions

3
TODO/Focus.md Normal file
View File

@ -0,0 +1,3 @@
# Focus TODO
* Restore focus from `modal` focus scope to button that opened it.

View File

@ -1,16 +1,11 @@
* Text shaping needs "Language" and "Script".
* Colors don't match other apps, clear_color and background_color also does not match.
* WindowChangedEvent fired on first resize.
* Review `open_widget_display`, needs to be called with widget inner size to calculate default origin (center).
# Interactive Filter
* Integrate `enabled` with new interactive filter.
* Integrate *mouse capture* with new interactive filter.
# Layer
* Continue refactoring layers inside root.
* Opening two modals blocks all interaction.
# Split `inner`

View File

@ -124,11 +124,11 @@ fn functions(window_enabled: RcVar<bool>) -> impl Widget {
window_enabled.set(&ctx, true);
});
},
// Replace Scope
// Overlay Scope
button! {
content = text("Overlay Scope");
on_click = hn!(|ctx, _| {
WindowLayers::insert(ctx, LayerIndex::TOP_MOST, overlay());
WindowLayers::insert(ctx, LayerIndex::TOP_MOST, overlay());
});
}
]
@ -138,10 +138,10 @@ fn overlay() -> impl Widget {
container! {
id = "overlay";
modal = true;
background_color = colors::GRAY.with_alpha(40.pct());
content = container! {
focus_scope = true;
background_color = colors::GRAY.darken(50.pct());
drop_shadow = (0, 0), 4, colors::BLACK;
padding = 2;
content = v_stack! {
items_align = Alignment::RIGHT;

View File

@ -1197,7 +1197,7 @@ pub fn focus_goes_to_parent_after_remove() {
app.take_focus_changed();
app.set_vars(|vars| {
enabled.set(vars, dbg!(false));
enabled.set(vars, false);
});
assert_eq!(Some(parent_id), app.focused());
let evs = app.take_focus_changed();

View File

@ -1009,8 +1009,8 @@ impl Focus {
// move to focusable parent
return self.move_focus(vars, Some(parent.info.path()), self.is_highlighting, FocusChangedCause::Recovery);
} else {
// no focusable parent, is this an error?
return self.move_focus(vars, None, false, FocusChangedCause::Recovery);
// no focusable parent or root
return self.focus_focused_window(vars, windows, self.is_highlighting);
}
}
} else {
@ -1100,12 +1100,11 @@ impl Focus {
fn focus_focused_window(&mut self, vars: &Vars, windows: &Windows, highlight: bool) -> Option<FocusChangedArgs> {
if let Some(info) = windows.focused_info() {
let info = FocusInfoTree::new(info);
let root = info.root();
if root.is_focusable() {
if let Some(root) = info.focusable_root() {
// found focused window and it is focusable.
self.move_focus(vars, Some(root.info.path()), highlight, FocusChangedCause::Recovery)
} else {
// has focused window but it is not focusable
// has focused window but it is not focusable.
self.move_focus(vars, None, false, FocusChangedCause::Recovery)
}
} else {
@ -1555,6 +1554,29 @@ impl<'a> FocusInfoTree<'a> {
WidgetFocusInfo::new(self.tree.root())
}
/// Reference the focusable widget closest to the window root.
///
/// When the window root is not focusable, but a descendant widget is, this method returns
/// the focusable closest to the root counting previous siblings then parents.
pub fn focusable_root(&self) -> Option<WidgetFocusInfo> {
let root = self.root();
if root.is_focusable() {
return Some(root);
}
let mut candidate = None;
let mut candidate_weight = usize::MAX;
for w in root.filter_descendants(|_| DescendantFilter::SkipDescendants) {
let weight = w.info.prev_siblings().count() + w.info.ancestors().count();
if weight < candidate_weight {
candidate = Some(w);
}
}
candidate
}
/// Reference to the widget in the tree, if it is present and is focusable.
#[inline]
pub fn find(&self, widget_id: WidgetId) -> Option<WidgetFocusInfo> {

View File

@ -418,7 +418,7 @@ pub fn enabled(child: impl UiNode, enabled: impl IntoVar<bool>) -> impl UiNode {
impl<C: UiNode> UiNode for EnabledNode<C> {
fn info(&self, ctx: &mut InfoContext, info: &mut WidgetInfoBuilder) {
if !IsEnabled::get(ctx) {
info.meta().set(EnabledState, dbg!(false));
info.meta().set(EnabledState, false);
if !ctx.update_state.flag(RegisteredDisabledFilter) {
info.push_interactive_filter(move |args| args.info.is_enabled())

View File

@ -1021,7 +1021,7 @@ impl<'a> WidgetInfo<'a> {
/// Iterator over all widgets contained by this widget filtered by the `filter` closure.
#[inline]
pub fn filter_descendants<F: FnMut(WidgetInfo<'a>) -> DescendantFilter>(self, filter: F) -> FilterDescendants<'a, F> {
pub fn filter_descendants<F>(self, filter: F) -> FilterDescendants<'a, F> where F: FnMut(WidgetInfo<'a>) -> DescendantFilter {
let mut traverse = self.node().traverse();
traverse.next(); // skip self.
FilterDescendants {

View File

@ -785,7 +785,7 @@ impl Window {
self.window.set_maximized(false);
}
}
WindowState::Fullscreen | WindowState::Exclusive => self.window.set_fullscreen(dbg!(None)),
WindowState::Fullscreen | WindowState::Exclusive => self.window.set_fullscreen(None),
}
// set new state.