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
6 changes: 5 additions & 1 deletion masonry_core/src/app/render_root.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
// Copyright 2019 the Xilem Authors and the Druid Authors
// SPDX-License-Identifier: Apache-2.0

use std::any::Any;
use std::any::{Any, TypeId};
use std::collections::HashMap;
use std::sync::Arc;

Expand Down Expand Up @@ -144,6 +144,9 @@ pub(crate) struct RenderRootState {

pub(crate) widget_tags: HashMap<WidgetTagInner, WidgetId>,

/// Map of layers attached to widgets, keyed by the attached widget id, then the type of the layer root.
pub(crate) attached_layers: HashMap<WidgetId, HashMap<TypeId, WidgetId>>,

/// Whether data set in the pointer pass has been invalidated.
pub(crate) needs_pointer_pass: bool,

Expand Down Expand Up @@ -355,6 +358,7 @@ impl RenderRoot {
last_sent_ime_area: INVALID_IME_AREA,
scene_cache: HashMap::new(),
widget_tags: HashMap::new(),
attached_layers: HashMap::new(),
needs_pointer_pass: false,
trace: PassTracing::from_env(),
inspector_state: InspectorState {
Expand Down
78 changes: 77 additions & 1 deletion masonry_core/src/core/contexts.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@

//! The context types that are passed into various widget methods.

use std::any::Any;
use std::any::{Any, TypeId};
use std::collections::hash_map::Entry;

use accesskit::{NodeId, TreeUpdate};
Expand Down Expand Up @@ -1501,6 +1501,12 @@ impl_context_method!(MutateCtx<'_>, EventCtx<'_>, UpdateCtx<'_>, RawCtx<'_>, {
}

global_state.scene_cache.remove(&state.id);

if let Some(layers) = global_state.attached_layers.remove(&state.id) {
for (_, layer_id) in layers {
global_state.emit_signal(RenderRootSignal::RemoveLayer(layer_id));
}
}
}

let id = child.id();
Expand Down Expand Up @@ -1804,11 +1810,81 @@ impl_context_method!(
));
}

/// Creates a new [layer] at a specified `position`, and ties it to the current widget.
///
/// The layer will be removed when the current widget is removed from the tree.
/// A widget can only have one layer of any given type `W` at a time: if a widget creates two layers of the same type, the old layer will be removed.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's keep line lengths under 100.

Suggested change
/// A widget can only have one layer of any given type `W` at a time: if a widget creates two layers of the same type, the old layer will be removed.
/// A widget can only have one layer of any given type `W` at a time:
/// if a widget creates two layers of the same type, the old layer will be removed.

///
/// The given `position` must be in the window's coordinate space.
///
/// # Panics
///
/// If [`W::as_layer()`](Widget::as_layer) returns `None`.
///
/// [layer]: crate::doc::masonry_concepts#layers
pub fn create_attached_layer<W: Widget + ?Sized>(
&mut self,
layer_type: LayerType,
mut fallback_widget: NewWidget<W>,
position: Point,
) {
trace!("create_attached_layer");

if fallback_widget.widget.as_layer().is_none() {
debug_panic!(
"cannot create layer of type {} - `Widget::as_layer()` returned None",
fallback_widget.widget.short_type_name()
);
return;
}

// FIXME - Add LayerId type and use that instead.
let layer_id = fallback_widget.id;

let layers = self
.global_state
.attached_layers
.entry(self.widget_id())
.or_default();
if let Some(prev) = layers.insert(TypeId::of::<W>(), layer_id) {
self.global_state
.emit_signal(RenderRootSignal::RemoveLayer(prev));
}
self.global_state.emit_signal(RenderRootSignal::NewLayer(
layer_type,
fallback_widget.erased(),
position,
));
}

/// Returns the attached layer created by this widget with the given type `W`.
///
/// See [`Self::create_attached_layer`] for more details.
pub fn get_attached_layer<W: Widget + ?Sized>(&self) -> Option<WidgetId> {
self.global_state
.attached_layers
.get(&self.widget_id())?
.get(&TypeId::of::<W>())
.copied()
}

/// Removes the layer with the specified widget as root.
pub fn remove_layer(&mut self, root_widget_id: WidgetId) {
trace!("remove_layer");
self.global_state
.emit_signal(RenderRootSignal::RemoveLayer(root_widget_id));

let Some(layers) = self.global_state.attached_layers.get_mut(&self.widget_id()) else {
return;
};

let layer_type_id = layers
.iter()
.find(|(_, id)| **id == root_widget_id)
.map(|(type_id, _)| *type_id);
if let Some(type_id) = layer_type_id {
layers.remove(&type_id);
}
}

/// Repositions the layer with the specified widget as root.
Expand Down
Loading