Refactor node mutation (again)

This commit is contained in:
Matt Campbell 2022-11-30 09:20:12 -06:00
parent 18ccf1fd10
commit 49bbcf9b2e
5 changed files with 32 additions and 42 deletions

View file

@ -158,19 +158,8 @@ impl ContextImpl {
} }
#[cfg(feature = "accesskit")] #[cfg(feature = "accesskit")]
fn mutate_accesskit_node( fn accesskit_node(&mut self, id: Id, parent_id: Option<Id>) -> &mut accesskit::Node {
&mut self, let update = self.output.accesskit_update.as_mut().unwrap();
id: Id,
parent_id: Option<Id>,
f: impl FnOnce(&mut accesskit::Node),
) {
let update = match &mut self.output.accesskit_update {
Some(update) => update,
None => {
return;
}
};
let nodes = &mut update.nodes; let nodes = &mut update.nodes;
let node_map = &mut self.frame_state.accesskit_nodes; let node_map = &mut self.frame_state.accesskit_nodes;
let index = node_map.get(&id).copied().unwrap_or_else(|| { let index = node_map.get(&id).copied().unwrap_or_else(|| {
@ -184,7 +173,7 @@ impl ContextImpl {
parent.children.push(accesskit_id); parent.children.push(accesskit_id);
index index
}); });
f(Arc::get_mut(&mut nodes[index].1).unwrap()); Arc::get_mut(&mut nodes[index].1).unwrap()
} }
} }
@ -495,9 +484,9 @@ impl Context {
// Make sure anything that can receive focus has an AccessKit node. // Make sure anything that can receive focus has an AccessKit node.
// TODO(mwcampbell): For nodes that are filled from widget info, // TODO(mwcampbell): For nodes that are filled from widget info,
// some information is written to the node twice. // some information is written to the node twice.
self.mutate_accesskit_node(id, None, |node| { if let Some(mut node) = self.accesskit_node(id, None) {
response.fill_accesskit_node_common(node); response.fill_accesskit_node_common(&mut node);
}); }
} }
let clicked_elsewhere = response.clicked_elsewhere(); let clicked_elsewhere = response.clicked_elsewhere();
@ -1586,19 +1575,20 @@ impl Context {
/// ## Accessibility /// ## Accessibility
impl Context { impl Context {
/// Create an AccessKit node with the specified ID if one doesn't already /// If AccessKit support is active for the current frame, get or create
/// exist, then call the provided function with a mutable reference /// a node with the specified ID and return a mutable reference to it.
/// to the node. Node that the `parent_id` parameter is ignored if the node /// `parent_id is ignored if the node already exists.
/// already exists. If AccessKit isn't active for this frame, this method
/// does nothing.
#[cfg(feature = "accesskit")] #[cfg(feature = "accesskit")]
pub fn mutate_accesskit_node( pub fn accesskit_node(
&self, &self,
id: Id, id: Id,
parent_id: Option<Id>, parent_id: Option<Id>,
f: impl FnOnce(&mut accesskit::Node), ) -> Option<RwLockWriteGuard<'_, accesskit::Node>> {
) { let ctx = self.write();
self.write().mutate_accesskit_node(id, parent_id, f); ctx.output
.accesskit_update
.is_some()
.then(move || RwLockWriteGuard::map(ctx, |c| c.accesskit_node(id, parent_id)))
} }
/// Returns whether AccessKit is active for the current frame. /// Returns whether AccessKit is active for the current frame.

View file

@ -529,17 +529,17 @@ impl Response {
self.output_event(event); self.output_event(event);
} else { } else {
#[cfg(feature = "accesskit")] #[cfg(feature = "accesskit")]
self.ctx.mutate_accesskit_node(self.id, None, |node| { if let Some(mut node) = self.ctx.accesskit_node(self.id, None) {
self.fill_accesskit_node_from_widget_info(node, make_info()); self.fill_accesskit_node_from_widget_info(&mut node, make_info());
}); }
} }
} }
pub fn output_event(&self, event: crate::output::OutputEvent) { pub fn output_event(&self, event: crate::output::OutputEvent) {
#[cfg(feature = "accesskit")] #[cfg(feature = "accesskit")]
self.ctx.mutate_accesskit_node(self.id, None, |node| { if let Some(mut node) = self.ctx.accesskit_node(self.id, None) {
self.fill_accesskit_node_from_widget_info(node, event.widget_info().clone()); self.fill_accesskit_node_from_widget_info(&mut node, event.widget_info().clone());
}); }
self.ctx.output().events.push(event); self.ctx.output().events.push(event);
} }
@ -606,9 +606,9 @@ impl Response {
/// Associate a label with a control for accessibility. /// Associate a label with a control for accessibility.
pub fn labelled_by(self, id: Id) -> Self { pub fn labelled_by(self, id: Id) -> Self {
#[cfg(feature = "accesskit")] #[cfg(feature = "accesskit")]
self.ctx.mutate_accesskit_node(self.id, None, |node| { if let Some(mut node) = self.ctx.accesskit_node(self.id, None) {
node.labelled_by.push(id.accesskit_id()); node.labelled_by.push(id.accesskit_id());
}); }
#[cfg(not(feature = "accesskit"))] #[cfg(not(feature = "accesskit"))]
{ {
let _ = id; let _ = id;

View file

@ -541,7 +541,7 @@ impl<'a> Widget for DragValue<'a> {
response.widget_info(|| WidgetInfo::drag_value(value)); response.widget_info(|| WidgetInfo::drag_value(value));
#[cfg(feature = "accesskit")] #[cfg(feature = "accesskit")]
ui.ctx().mutate_accesskit_node(response.id, None, |node| { if let Some(mut node) = ui.ctx().accesskit_node(response.id, None) {
use accesskit::Action; use accesskit::Action;
// If either end of the range is unbounded, it's better // If either end of the range is unbounded, it's better
// to leave the corresponding AccessKit field set to None, // to leave the corresponding AccessKit field set to None,
@ -585,7 +585,7 @@ impl<'a> Widget for DragValue<'a> {
let value_text = format!("{}{}{}", prefix, value_text, suffix); let value_text = format!("{}{}{}", prefix, value_text, suffix);
node.value = Some(value_text.into()); node.value = Some(value_text.into());
} }
}); }
response response
} }

View file

@ -740,7 +740,7 @@ impl<'a> Slider<'a> {
response.widget_info(|| WidgetInfo::slider(value, self.text.text())); response.widget_info(|| WidgetInfo::slider(value, self.text.text()));
#[cfg(feature = "accesskit")] #[cfg(feature = "accesskit")]
ui.ctx().mutate_accesskit_node(response.id, None, |node| { if let Some(mut node) = ui.ctx().accesskit_node(response.id, None) {
use accesskit::Action; use accesskit::Action;
node.min_numeric_value = Some(*self.range.start()); node.min_numeric_value = Some(*self.range.start());
node.max_numeric_value = Some(*self.range.end()); node.max_numeric_value = Some(*self.range.end());
@ -753,7 +753,7 @@ impl<'a> Slider<'a> {
if value > *clamp_range.start() { if value > *clamp_range.start() {
node.actions |= Action::Decrement; node.actions |= Action::Decrement;
} }
}); }
let slider_response = response.clone(); let slider_response = response.clone();

View file

@ -665,7 +665,7 @@ impl<'t> TextEdit<'t> {
let parent_id = response.id; let parent_id = response.id;
for (i, row) in galley.rows.iter().enumerate() { for (i, row) in galley.rows.iter().enumerate() {
let id = parent_id.with(i); let id = parent_id.with(i);
ui.ctx().mutate_accesskit_node(id, Some(parent_id), |node| { if let Some(mut node) = ui.ctx().accesskit_node(id, Some(parent_id)) {
node.role = Role::InlineTextBox; node.role = Role::InlineTextBox;
let rect = row.rect.translate(text_draw_pos.to_vec2()); let rect = row.rect.translate(text_draw_pos.to_vec2());
node.bounds = Some(accesskit::kurbo::Rect { node.bounds = Some(accesskit::kurbo::Rect {
@ -717,10 +717,10 @@ impl<'t> TextEdit<'t> {
node.character_positions = Some(character_positions.into()); node.character_positions = Some(character_positions.into());
node.character_widths = Some(character_widths.into()); node.character_widths = Some(character_widths.into());
node.word_lengths = word_lengths.into(); node.word_lengths = word_lengths.into();
}); }
} }
ui.ctx().mutate_accesskit_node(parent_id, None, |node| { if let Some(mut node) = ui.ctx().accesskit_node(parent_id, None) {
if let Some(cursor_range) = &cursor_range { if let Some(cursor_range) = &cursor_range {
let anchor = &cursor_range.secondary.rcursor; let anchor = &cursor_range.secondary.rcursor;
let focus = &cursor_range.primary.rcursor; let focus = &cursor_range.primary.rcursor;
@ -737,7 +737,7 @@ impl<'t> TextEdit<'t> {
} }
node.default_action_verb = Some(accesskit::DefaultActionVerb::Focus); node.default_action_verb = Some(accesskit::DefaultActionVerb::Focus);
}); }
} }
TextEditOutput { TextEditOutput {