Skip to content

Commit

Permalink
Add Ui::with_transform, making it possible to transform widgets witho…
Browse files Browse the repository at this point in the history
…ut creating a new layer
  • Loading branch information
lucasmerlin committed Sep 1, 2024
1 parent edea5a4 commit 0d30ec7
Show file tree
Hide file tree
Showing 2 changed files with 41 additions and 1 deletion.
14 changes: 13 additions & 1 deletion crates/egui/src/layers.rs
Original file line number Diff line number Diff line change
Expand Up @@ -124,10 +124,14 @@ impl PaintList {
self.0.is_empty()
}

pub fn next_idx(&self) -> ShapeIdx {
ShapeIdx(self.0.len())
}

/// Returns the index of the new [`Shape`] that can be used with `PaintList::set`.
#[inline(always)]
pub fn add(&mut self, clip_rect: Rect, shape: Shape) -> ShapeIdx {
let idx = ShapeIdx(self.0.len());
let idx = self.next_idx();
self.0.push(ClippedShape { clip_rect, shape });
idx
}
Expand Down Expand Up @@ -171,6 +175,14 @@ impl PaintList {
}
}

/// Transform each [`Shape`] and clip rectangle in range by this much, in-place
pub fn transform_range(&mut self, start: ShapeIdx, end: ShapeIdx, transform: TSTransform) {
for ClippedShape { clip_rect, shape } in &mut self.0[start.0..end.0] {
*clip_rect = transform.mul_rect(*clip_rect);
shape.transform(transform);
}
}

/// Read-only access to all held shapes.
pub fn all_entries(&self) -> impl ExactSizeIterator<Item = &ClippedShape> {
self.0.iter()
Expand Down
28 changes: 28 additions & 0 deletions crates/egui/src/ui.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2685,6 +2685,34 @@ impl Ui {

(InnerResponse { inner, response }, payload)
}

/// Create a new Scope and transform its contents via a [`TSTransform`].
/// This only affects visuals, inputs will not be transformed. So this is mostly useful
/// to create visual effects on interactions, e.g. scaling a button on hover / click.
///
/// Check out [`Context::set_transform_layer`] for a persistent transform that also affects
/// inputs.
pub fn with_transform<R>(
&mut self,
transform: emath::TSTransform,
add_contents: impl FnOnce(&mut Self) -> R,
) -> InnerResponse<R> {
let start_idx = self.ctx().graphics(|gx| {
gx.get(self.layer_id())
.map(|l| l.next_idx())
.unwrap_or(crate::layers::ShapeIdx(0))
});

let r = self.scope_dyn(UiBuilder::new(), Box::new(add_contents));

self.ctx().graphics_mut(|g| {
let list = g.entry(self.layer_id());
let end_idx = list.next_idx();
list.transform_range(start_idx, end_idx, transform)
});

r
}
}

/// # Menus
Expand Down

0 comments on commit 0d30ec7

Please sign in to comment.