Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ You can find its changes [documented below](#070---2021-01-01).
- Add #[data(eq)] shorthand attribute for Data derive macro ([#1884] by [@Maan2003])
- X11: detect keyboard layout ([#1779] by [@Maan2003])
- WindowDesc::with_config ([#1929] by [@Maan2003])
- `UpdateCtx::request_focus`, `UpdateCtx::resign_focus`, `UpdateCtx::focus_next`, `UpdateCtx::focus_prev`, `UpdateCtx::set_focus` ([#1960] by [@xarvic])

### Changed

Expand Down Expand Up @@ -784,6 +785,8 @@ Last release without a changelog :(
[#1886]: https://github.com/linebender/druid/pull/1886
[#1907]: https://github.com/linebender/druid/pull/1907
[#1929]: https://github.com/linebender/druid/pull/1929
[#1960]: https://github.com/linebender/druid/pull/1960


[Unreleased]: https://github.com/linebender/druid/compare/v0.7.0...master
[0.7.0]: https://github.com/linebender/druid/compare/v0.6.0...v0.7.0
Expand Down
174 changes: 87 additions & 87 deletions druid/src/contexts.rs
Original file line number Diff line number Diff line change
Expand Up @@ -338,6 +338,93 @@ impl_context_method!(EventCtx<'_, '_>, UpdateCtx<'_, '_>, {
trace!("clear_cursor");
self.widget_state.cursor_change = CursorChange::Default;
}

/// Request keyboard focus.
///
/// Because only one widget can be focused at a time, multiple focus requests
/// from different widgets during a single event cycle means that the last
/// widget that requests focus will override the previous requests.
///
/// See [`is_focused`] for more information about focus.
///
/// [`is_focused`]: struct.EventCtx.html#method.is_focused
pub fn request_focus(&mut self) {
trace!("request_focus");
// We need to send the request even if we're currently focused,
// because we may have a sibling widget that already requested focus
// and we have no way of knowing that yet. We need to override that
// to deliver on the "last focus request wins" promise.
let id = self.widget_id();
self.widget_state.request_focus = Some(FocusChange::Focus(id));
}

/// Transfer focus to the widget with the given `WidgetId`.
///
/// See [`is_focused`] for more information about focus.
///
/// [`is_focused`]: struct.EventCtx.html#method.is_focused
pub fn set_focus(&mut self, target: WidgetId) {
trace!("set_focus target={:?}", target);
self.widget_state.request_focus = Some(FocusChange::Focus(target));
}

/// Transfer focus to the next focusable widget.
///
/// This should only be called by a widget that currently has focus.
///
/// See [`is_focused`] for more information about focus.
///
/// [`is_focused`]: struct.EventCtx.html#method.is_focused
pub fn focus_next(&mut self) {
trace!("focus_next");
if self.has_focus() {
self.widget_state.request_focus = Some(FocusChange::Next);
} else {
warn!(
"focus_next can only be called by the currently \
focused widget or one of its ancestors."
);
}
}

/// Transfer focus to the previous focusable widget.
///
/// This should only be called by a widget that currently has focus.
///
/// See [`is_focused`] for more information about focus.
///
/// [`is_focused`]: struct.EventCtx.html#method.is_focused
pub fn focus_prev(&mut self) {
trace!("focus_prev");
if self.has_focus() {
self.widget_state.request_focus = Some(FocusChange::Previous);
} else {
warn!(
"focus_prev can only be called by the currently \
focused widget or one of its ancestors."
);
}
}

/// Give up focus.
///
/// This should only be called by a widget that currently has focus.
///
/// See [`is_focused`] for more information about focus.
///
/// [`is_focused`]: struct.EventCtx.html#method.is_focused
pub fn resign_focus(&mut self) {
trace!("resign_focus");
if self.has_focus() {
self.widget_state.request_focus = Some(FocusChange::Resign);
} else {
warn!(
"resign_focus can only be called by the currently focused widget \
or one of its ancestors. ({:?})",
self.widget_id()
);
}
}
});

// methods on event, update, and lifecycle
Expand Down Expand Up @@ -586,93 +673,6 @@ impl EventCtx<'_, '_> {
self.is_handled
}

/// Request keyboard focus.
///
/// Because only one widget can be focused at a time, multiple focus requests
/// from different widgets during a single event cycle means that the last
/// widget that requests focus will override the previous requests.
///
/// See [`is_focused`] for more information about focus.
///
/// [`is_focused`]: struct.EventCtx.html#method.is_focused
pub fn request_focus(&mut self) {
trace!("request_focus");
// We need to send the request even if we're currently focused,
// because we may have a sibling widget that already requested focus
// and we have no way of knowing that yet. We need to override that
// to deliver on the "last focus request wins" promise.
let id = self.widget_id();
self.widget_state.request_focus = Some(FocusChange::Focus(id));
}

/// Transfer focus to the widget with the given `WidgetId`.
///
/// See [`is_focused`] for more information about focus.
///
/// [`is_focused`]: struct.EventCtx.html#method.is_focused
pub fn set_focus(&mut self, target: WidgetId) {
trace!("set_focus target={:?}", target);
self.widget_state.request_focus = Some(FocusChange::Focus(target));
}

/// Transfer focus to the next focusable widget.
///
/// This should only be called by a widget that currently has focus.
///
/// See [`is_focused`] for more information about focus.
///
/// [`is_focused`]: struct.EventCtx.html#method.is_focused
pub fn focus_next(&mut self) {
trace!("focus_next");
if self.has_focus() {
self.widget_state.request_focus = Some(FocusChange::Next);
} else {
warn!(
"focus_next can only be called by the currently \
focused widget or one of its ancestors."
);
}
}

/// Transfer focus to the previous focusable widget.
///
/// This should only be called by a widget that currently has focus.
///
/// See [`is_focused`] for more information about focus.
///
/// [`is_focused`]: struct.EventCtx.html#method.is_focused
pub fn focus_prev(&mut self) {
trace!("focus_prev");
if self.has_focus() {
self.widget_state.request_focus = Some(FocusChange::Previous);
} else {
warn!(
"focus_prev can only be called by the currently \
focused widget or one of its ancestors."
);
}
}

/// Give up focus.
///
/// This should only be called by a widget that currently has focus.
///
/// See [`is_focused`] for more information about focus.
///
/// [`is_focused`]: struct.EventCtx.html#method.is_focused
pub fn resign_focus(&mut self) {
trace!("resign_focus");
if self.has_focus() {
self.widget_state.request_focus = Some(FocusChange::Resign);
} else {
warn!(
"resign_focus can only be called by the currently focused widget \
or one of its ancestors. ({:?})",
self.widget_id()
);
}
}

/// Request an update cycle.
///
/// After this, `update` will be called on the widget in the next update cycle, even
Expand Down