Add `Context::layer_transform_to_global` & `layer_transform_from_global` (#5465)

This makes it easy to get the current transform of a layer, and uses
consistent naming everywhere.

`Memory::layer_transforms` is now called `Memory::to_global`, because
the old name was ambiguous (transform into what direction?)
This commit is contained in:
Emil Ernerfeldt 2024-12-12 18:29:13 +01:00 committed by GitHub
parent 99c1034cfc
commit de8ac88c0e
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
8 changed files with 75 additions and 56 deletions

View File

@ -93,8 +93,8 @@ pub fn show_tooltip_at_pointer<R>(
pointer_rect.min.x = pointer_pos.x;
// Transform global coords to layer coords:
if let Some(transform) = ctx.memory(|m| m.layer_transforms.get(&parent_layer).copied()) {
pointer_rect = transform.inverse() * pointer_rect;
if let Some(from_global) = ctx.layer_transform_from_global(parent_layer) {
pointer_rect = from_global * pointer_rect;
}
show_tooltip_at_dyn(
@ -162,8 +162,8 @@ fn show_tooltip_at_dyn<'c, R>(
) -> R {
// Transform layer coords to global coords:
let mut widget_rect = *widget_rect;
if let Some(transform) = ctx.memory(|m| m.layer_transforms.get(&parent_layer).copied()) {
widget_rect = transform * widget_rect;
if let Some(to_global) = ctx.layer_transform_to_global(parent_layer) {
widget_rect = to_global * widget_rect;
}
remember_that_tooltip_was_shown(ctx);
@ -404,11 +404,12 @@ pub fn popup_above_or_below_widget<R>(
AboveOrBelow::Above => (widget_response.rect.left_top(), Align2::LEFT_BOTTOM),
AboveOrBelow::Below => (widget_response.rect.left_bottom(), Align2::LEFT_TOP),
};
if let Some(transform) = parent_ui
if let Some(to_global) = parent_ui
.ctx()
.memory(|m| m.layer_transforms.get(&parent_ui.layer_id()).copied())
.layer_transform_to_global(parent_ui.layer_id())
{
pos = transform * pos;
pos = to_global * pos;
}
let frame = Frame::popup(parent_ui.style());

View File

@ -518,7 +518,7 @@ impl ContextImpl {
crate::hit_test::hit_test(
&viewport.prev_pass.widgets,
&layers,
&self.memory.layer_transforms,
&self.memory.to_global,
pos,
interact_radius,
)
@ -1329,11 +1329,11 @@ impl Context {
res.is_pointer_button_down_on || res.long_touched || clicked || res.drag_stopped;
if is_interacted_with {
res.interact_pointer_pos = input.pointer.interact_pos();
if let (Some(transform), Some(pos)) = (
memory.layer_transforms.get(&res.layer_id),
if let (Some(to_global), Some(pos)) = (
memory.to_global.get(&res.layer_id),
&mut res.interact_pointer_pos,
) {
*pos = transform.inverse() * *pos;
*pos = to_global.inverse() * *pos;
}
}
@ -2381,7 +2381,7 @@ impl ContextImpl {
let shapes = viewport
.graphics
.drain(self.memory.areas().order(), &self.memory.layer_transforms);
.drain(self.memory.areas().order(), &self.memory.to_global);
let mut repaint_needed = false;
@ -2697,6 +2697,7 @@ impl Context {
/// Transform the graphics of the given layer.
///
/// This will also affect input.
/// The direction of the given transform is "into the global coordinate system".
///
/// This is a sticky setting, remembered from one frame to the next.
///
@ -2706,13 +2707,28 @@ impl Context {
pub fn set_transform_layer(&self, layer_id: LayerId, transform: TSTransform) {
self.memory_mut(|m| {
if transform == TSTransform::IDENTITY {
m.layer_transforms.remove(&layer_id)
m.to_global.remove(&layer_id)
} else {
m.layer_transforms.insert(layer_id, transform)
m.to_global.insert(layer_id, transform)
}
});
}
/// Return how to transform the graphics of the given layer into the global coordinate system.
///
/// Set this with [`Self::layer_transform_to_global`].
pub fn layer_transform_to_global(&self, layer_id: LayerId) -> Option<TSTransform> {
self.memory(|m| m.to_global.get(&layer_id).copied())
}
/// Return how to transform the graphics of the global coordinate system into the local coordinate system of the given layer.
///
/// This returns the inverse of [`Self::layer_transform_to_global`].
pub fn layer_transform_from_global(&self, layer_id: LayerId) -> Option<TSTransform> {
self.layer_transform_to_global(layer_id)
.map(|t| t.inverse())
}
/// Move all the graphics at the given layer.
///
/// Is used to implement drag-and-drop preview.
@ -2777,12 +2793,11 @@ impl Context {
///
/// See also [`Response::contains_pointer`].
pub fn rect_contains_pointer(&self, layer_id: LayerId, rect: Rect) -> bool {
let rect =
if let Some(transform) = self.memory(|m| m.layer_transforms.get(&layer_id).copied()) {
transform * rect
} else {
rect
};
let rect = if let Some(to_global) = self.layer_transform_to_global(layer_id) {
to_global * rect
} else {
rect
};
if !rect.is_positive() {
return false;
}

View File

@ -35,7 +35,7 @@ pub struct WidgetHits {
pub fn hit_test(
widgets: &WidgetRects,
layer_order: &[LayerId],
layer_transforms: &HashMap<LayerId, TSTransform>,
layer_to_global: &HashMap<LayerId, TSTransform>,
pos: Pos2,
search_radius: f32,
) -> WidgetHits {
@ -44,9 +44,9 @@ pub fn hit_test(
let search_radius_sq = search_radius * search_radius;
// Transform the position into the local coordinate space of each layer:
let pos_in_layers: HashMap<LayerId, Pos2> = layer_transforms
let pos_in_layers: HashMap<LayerId, Pos2> = layer_to_global
.iter()
.map(|(layer_id, t)| (*layer_id, t.inverse() * pos))
.map(|(layer_id, to_global)| (*layer_id, to_global.inverse() * pos))
.collect();
let mut closest_dist_sq = f32::INFINITY;

View File

@ -213,7 +213,7 @@ impl GraphicLayers {
pub fn drain(
&mut self,
area_order: &[LayerId],
transforms: &ahash::HashMap<LayerId, TSTransform>,
to_global: &ahash::HashMap<LayerId, TSTransform>,
) -> Vec<ClippedShape> {
crate::profile_function!();
@ -231,10 +231,10 @@ impl GraphicLayers {
for layer_id in area_order {
if layer_id.order == order {
if let Some(list) = order_map.get_mut(&layer_id.id) {
if let Some(transform) = transforms.get(layer_id) {
if let Some(to_global) = to_global.get(layer_id) {
for clipped_shape in &mut list.0 {
clipped_shape.clip_rect = *transform * clipped_shape.clip_rect;
clipped_shape.shape.transform(*transform);
clipped_shape.clip_rect = *to_global * clipped_shape.clip_rect;
clipped_shape.shape.transform(*to_global);
}
}
all_shapes.append(&mut list.0);
@ -246,10 +246,10 @@ impl GraphicLayers {
for (id, list) in order_map {
let layer_id = LayerId::new(order, *id);
if let Some(transform) = transforms.get(&layer_id) {
if let Some(to_global) = to_global.get(&layer_id) {
for clipped_shape in &mut list.0 {
clipped_shape.clip_rect = *transform * clipped_shape.clip_rect;
clipped_shape.shape.transform(*transform);
clipped_shape.clip_rect = *to_global * clipped_shape.clip_rect;
clipped_shape.shape.transform(*to_global);
}
}

View File

@ -95,8 +95,13 @@ pub struct Memory {
#[cfg_attr(feature = "persistence", serde(skip))]
everything_is_visible: bool,
/// Transforms per layer
pub layer_transforms: HashMap<LayerId, TSTransform>,
/// Transforms per layer.
///
/// Instead of using this directly, use:
/// * [`crate::Context::set_transform_layer`]
/// * [`crate::Context::layer_transform_to_global`]
/// * [`crate::Context::layer_transform_from_global`]
pub to_global: HashMap<LayerId, TSTransform>,
// -------------------------------------------------
// Per-viewport:
@ -120,7 +125,7 @@ impl Default for Memory {
focus: Default::default(),
viewport_id: Default::default(),
areas: Default::default(),
layer_transforms: Default::default(),
to_global: Default::default(),
popup: Default::default(),
everything_is_visible: Default::default(),
add_fonts: Default::default(),
@ -819,7 +824,7 @@ impl Memory {
/// Top-most layer at the given position.
pub fn layer_id_at(&self, pos: Pos2) -> Option<LayerId> {
self.areas()
.layer_id_at(pos, &self.layer_transforms)
.layer_id_at(pos, &self.to_global)
.and_then(|layer_id| {
if self.is_above_modal_layer(layer_id) {
Some(layer_id)
@ -829,6 +834,12 @@ impl Memory {
})
}
/// The currently set transform of a layer.
#[deprecated = "Use `Context::layer_transform_to_global` instead"]
pub fn layer_transforms(&self, layer_id: LayerId) -> Option<TSTransform> {
self.to_global.get(&layer_id).copied()
}
/// An iterator over all layers. Back-to-front, top is last.
pub fn layer_ids(&self) -> impl ExactSizeIterator<Item = LayerId> + '_ {
self.areas().order().iter().copied()
@ -1194,15 +1205,15 @@ impl Areas {
pub fn layer_id_at(
&self,
pos: Pos2,
layer_transforms: &HashMap<LayerId, TSTransform>,
layer_to_global: &HashMap<LayerId, TSTransform>,
) -> Option<LayerId> {
for layer in self.order.iter().rev() {
if self.is_visible(layer) {
if let Some(state) = self.areas.get(&layer.id) {
let mut rect = state.rect();
if state.interactable {
if let Some(transform) = layer_transforms.get(layer) {
rect = *transform * rect;
if let Some(to_global) = layer_to_global.get(layer) {
rect = *to_global * rect;
}
if rect.contains(pos) {

View File

@ -406,11 +406,8 @@ impl MenuRoot {
}
}
if let Some(transform) = button
.ctx
.memory(|m| m.layer_transforms.get(&button.layer_id).copied())
{
pos = transform * pos;
if let Some(to_global) = button.ctx.layer_transform_to_global(button.layer_id) {
pos = to_global * pos;
}
return MenuResponse::Create(pos, id);

View File

@ -392,11 +392,8 @@ impl Response {
pub fn drag_delta(&self) -> Vec2 {
if self.dragged() {
let mut delta = self.ctx.input(|i| i.pointer.delta());
if let Some(scaling) = self
.ctx
.memory(|m| m.layer_transforms.get(&self.layer_id).map(|t| t.scaling))
{
delta /= scaling;
if let Some(from_global) = self.ctx.layer_transform_from_global(self.layer_id) {
delta *= from_global.scaling;
}
delta
} else {
@ -478,11 +475,8 @@ impl Response {
pub fn hover_pos(&self) -> Option<Pos2> {
if self.hovered() {
let mut pos = self.ctx.input(|i| i.pointer.hover_pos())?;
if let Some(transform) = self
.ctx
.memory(|m| m.layer_transforms.get(&self.layer_id).copied())
{
pos = transform.inverse() * pos;
if let Some(from_global) = self.ctx.layer_transform_from_global(self.layer_id) {
pos = from_global * pos;
}
Some(pos)
} else {

View File

@ -766,14 +766,15 @@ impl<'t> TextEdit<'t> {
}
// Set IME output (in screen coords) when text is editable and visible
let transform = ui
.memory(|m| m.layer_transforms.get(&ui.layer_id()).copied())
let to_global = ui
.ctx()
.layer_transform_to_global(ui.layer_id())
.unwrap_or_default();
ui.ctx().output_mut(|o| {
o.ime = Some(crate::output::IMEOutput {
rect: transform * rect,
cursor_rect: transform * primary_cursor_rect,
rect: to_global * rect,
cursor_rect: to_global * primary_cursor_rect,
});
});
}