Fixed `modal` focus.
This commit is contained in:
parent
8547c1dc9b
commit
080461fe60
|
@ -0,0 +1,3 @@
|
|||
# Focus TODO
|
||||
|
||||
* Restore focus from `modal` focus scope to button that opened it.
|
|
@ -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`
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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> {
|
||||
|
|
|
@ -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())
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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.
|
||||
|
|
Loading…
Reference in New Issue