Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add layer transforms, interaction in layer #3906

Merged
merged 39 commits into from
Feb 17, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
39 commits
Select commit Hold shift + click to select a range
24143f4
add scaling layers, interaction with scaled items
Jan 27, 2024
0f6f82c
fix style
Tweoss Jan 27, 2024
141433d
add pan_zoom demo
Tweoss Jan 29, 2024
c001c5a
add pan_zoom demo
Tweoss Jan 29, 2024
085c593
fix warnings
Tweoss Jan 29, 2024
af79f81
Merge branch 'master' into transform-layer
Tweoss Jan 29, 2024
9fc5b71
Merge branch 'master' into transform-layer
Tweoss Jan 29, 2024
264726b
clean up
Tweoss Jan 29, 2024
17bb75e
port TSTransform to emath, make transform persist
Tweoss Feb 1, 2024
b2342dc
use smooth scrolling in demo
Tweoss Feb 1, 2024
ac2ae96
update docstring in layers.rs
Tweoss Feb 1, 2024
998a6e6
fix cranky, style
Tweoss Feb 1, 2024
b0d73d0
Update crates/egui/src/context.rs doc comment
Tweoss Feb 1, 2024
18347d3
add TSTransform doctests, switch transform order
Tweoss Feb 1, 2024
e593bbf
minor refactoring
Tweoss Feb 1, 2024
227bd6a
add invert method for TSTransform
Tweoss Feb 1, 2024
5902ffd
add back translate for mesh.
Tweoss Feb 1, 2024
635fc2f
Merge branch 'master' into transform-layer
Tweoss Feb 1, 2024
9090324
Update docstring crates/emath/src/ts_transform.rs
Tweoss Feb 10, 2024
6178cd8
simplify pan_zoom logic, multiply TSTransforms
Tweoss Feb 10, 2024
f1df40a
fix TSTransform doc comments
Tweoss Feb 10, 2024
05ba7c8
optimize arcs in transforming galley
Tweoss Feb 10, 2024
be325f0
scale thickness of strokes when transforming
Tweoss Feb 10, 2024
0b892d7
clarify paintcallback scaling comment
Tweoss Feb 10, 2024
2526e5b
fix cranky
Tweoss Feb 10, 2024
5b33246
Merge branch 'master' into transform-layer
Tweoss Feb 10, 2024
f70293a
Merge branch 'master' into transform-layer
Tweoss Feb 15, 2024
663a1b3
fix drag ratio
Tweoss Feb 16, 2024
09c4a50
apply transform to mouse input positions
Tweoss Feb 16, 2024
edafee5
add drag_value example
Tweoss Feb 16, 2024
7fd7e7c
fix formatting
Tweoss Feb 16, 2024
499492e
fix area: use response (not ctx) pointer delta
Tweoss Feb 16, 2024
3c27b3b
refactor hover_pos transform in response.rs
Tweoss Feb 16, 2024
bd46536
add label and link to pan_zoom demo
Tweoss Feb 16, 2024
b0afe90
add tracking inner contents to outer window
Tweoss Feb 16, 2024
c6ca843
fix text inner bounds
Tweoss Feb 17, 2024
f6851ab
add painter example
Tweoss Feb 17, 2024
f4ed104
fix pointer interaction for transforms in SidePanel
Tweoss Feb 17, 2024
b109093
fix topbottom panel pointer position
Tweoss Feb 17, 2024
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
2 changes: 1 addition & 1 deletion crates/egui/src/containers/area.rs
Original file line number Diff line number Diff line change
Expand Up @@ -331,7 +331,7 @@ impl Area {
);

if movable && move_response.dragged() {
state.pivot_pos += ctx.input(|i| i.pointer.delta());
state.pivot_pos += move_response.drag_delta();
}

if (move_response.dragged() || move_response.clicked())
Expand Down
16 changes: 16 additions & 0 deletions crates/egui/src/containers/panel.rs
Original file line number Diff line number Diff line change
Expand Up @@ -247,6 +247,14 @@ impl SidePanel {
.ctx()
.layer_id_at(pointer)
.map_or(true, |top_layer_id| top_layer_id == ui.layer_id());
let pointer = if let Some(transform) = ui
.ctx()
.memory(|m| m.layer_transforms.get(&ui.layer_id()).cloned())
{
transform.inverse() * pointer
} else {
pointer
};

let resize_x = side.opposite().side_x(panel_rect);
let mouse_over_resize_line = we_are_on_top
Expand Down Expand Up @@ -708,6 +716,14 @@ impl TopBottomPanel {
.ctx()
.layer_id_at(pointer)
.map_or(true, |top_layer_id| top_layer_id == ui.layer_id());
let pointer = if let Some(transform) = ui
.ctx()
.memory(|m| m.layer_transforms.get(&ui.layer_id()).cloned())
{
transform.inverse() * pointer
} else {
pointer
};

let resize_y = side.opposite().side_y(panel_rect);
let mouse_over_resize_line = we_are_on_top
Expand Down
46 changes: 38 additions & 8 deletions crates/egui/src/context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,9 @@
use std::{borrow::Cow, cell::RefCell, panic::Location, sync::Arc, time::Duration};

use ahash::HashMap;
use epaint::{mutex::*, stats::*, text::Fonts, util::OrderedFloat, TessellationOptions, *};
use epaint::{
emath::TSTransform, mutex::*, stats::*, text::Fonts, util::OrderedFloat, TessellationOptions, *,
};

use crate::{
animation_manager::AnimationManager,
Expand Down Expand Up @@ -1245,6 +1247,12 @@ impl Context {
let is_interacted_with = res.is_pointer_button_down_on || clicked || res.drag_released;
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),
&mut res.interact_pointer_pos,
) {
*pos = transform.inverse() * *pos;
}
}

if input.pointer.any_down() && !res.is_pointer_button_down_on {
Expand Down Expand Up @@ -1958,7 +1966,9 @@ impl ContextImpl {
}
}

let shapes = viewport.graphics.drain(self.memory.areas().order());
let shapes = viewport
.graphics
.drain(self.memory.areas().order(), &self.memory.layer_transforms);

let mut repaint_needed = false;

Expand Down Expand Up @@ -2265,13 +2275,19 @@ impl Context {
}

impl Context {
/// Move all the graphics at the given layer.
/// Transform the graphics of the given layer.
///
/// Can be used to implement drag-and-drop (see relevant demo).
pub fn translate_layer(&self, layer_id: LayerId, delta: Vec2) {
if delta != Vec2::ZERO {
self.graphics_mut(|g| g.entry(layer_id).translate(delta));
}
/// This is a sticky setting, remembered from one frame to the next.
///
/// Can be used to implement pan and zoom (see relevant demo).
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)
} else {
m.layer_transforms.insert(layer_id, transform)
}
});
}

/// Top-most layer at the given position.
Expand Down Expand Up @@ -2301,6 +2317,12 @@ 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).cloned()) {
transform * rect
} else {
rect
};
if !rect.is_positive() {
return false;
}
Expand Down Expand Up @@ -2347,6 +2369,12 @@ impl Context {
let mut blocking_widget = None;

self.write(|ctx| {
let transform = ctx
.memory
.layer_transforms
.get(&layer_id)
.cloned()
.unwrap_or_default();
let viewport = ctx.viewport();

// We add all widgets here, even non-interactive ones,
Expand All @@ -2366,6 +2394,8 @@ impl Context {
if contains_pointer {
let pointer_pos = viewport.input.pointer.interact_pos();
if let Some(pointer_pos) = pointer_pos {
// Apply the inverse transformation of this layer to the pointer pos.
let pointer_pos = transform.inverse() * pointer_pos;
if let Some(rects) = viewport.layer_rects_prev_frame.by_layer.get(&layer_id) {
// Iterate backwards, i.e. topmost widgets first.
for blocking in rects.iter().rev() {
Expand Down
22 changes: 16 additions & 6 deletions crates/egui/src/layers.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
//! are sometimes painted behind or in front of other things.

use crate::{Id, *};
use epaint::{ClippedShape, Shape};
use epaint::{emath::TSTransform, ClippedShape, Shape};

/// Different layer categories
#[derive(Clone, Copy, Debug, Hash, Eq, PartialEq, Ord, PartialOrd)]
Expand Down Expand Up @@ -158,11 +158,11 @@ impl PaintList {
self.0[idx.0].shape = Shape::Noop;
}

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

Expand Down Expand Up @@ -194,7 +194,11 @@ impl GraphicLayers {
self.0[layer_id.order as usize].get_mut(&layer_id.id)
}

pub fn drain(&mut self, area_order: &[LayerId]) -> Vec<ClippedShape> {
pub fn drain(
&mut self,
area_order: &[LayerId],
transforms: &ahash::HashMap<LayerId, TSTransform>,
) -> Vec<ClippedShape> {
crate::profile_function!();

let mut all_shapes: Vec<_> = Default::default();
Expand All @@ -211,6 +215,12 @@ 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) {
for clipped_shape in &mut list.0 {
clipped_shape.clip_rect = *transform * clipped_shape.clip_rect;
clipped_shape.shape.transform(*transform);
}
}
all_shapes.append(&mut list.0);
}
}
Expand Down
21 changes: 19 additions & 2 deletions crates/egui/src/memory.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
#![warn(missing_docs)] // Let's keep this file well-documented.` to memory.rs

use ahash::HashMap;
use epaint::emath::TSTransform;

use crate::{
area, vec2,
window::{self, WindowInteraction},
Expand Down Expand Up @@ -85,6 +88,9 @@ pub struct Memory {
#[cfg_attr(feature = "persistence", serde(skip))]
everything_is_visible: bool,

/// Transforms per layer
pub layer_transforms: HashMap<LayerId, TSTransform>,

// -------------------------------------------------
// Per-viewport:
areas: ViewportIdMap<Areas>,
Expand All @@ -107,6 +113,7 @@ impl Default for Memory {
viewport_id: Default::default(),
window_interactions: Default::default(),
areas: Default::default(),
layer_transforms: Default::default(),
popup: Default::default(),
everything_is_visible: Default::default(),
};
Expand Down Expand Up @@ -672,7 +679,8 @@ impl Memory {

/// Top-most layer at the given position.
pub fn layer_id_at(&self, pos: Pos2, resize_interact_radius_side: f32) -> Option<LayerId> {
self.areas().layer_id_at(pos, resize_interact_radius_side)
self.areas()
.layer_id_at(pos, resize_interact_radius_side, &self.layer_transforms)
}

/// An iterator over all layers. Back-to-front. Top is last.
Expand Down Expand Up @@ -948,7 +956,12 @@ impl Areas {
}

/// Top-most layer at the given position.
pub fn layer_id_at(&self, pos: Pos2, resize_interact_radius_side: f32) -> Option<LayerId> {
pub fn layer_id_at(
&self,
pos: Pos2,
resize_interact_radius_side: f32,
layer_transforms: &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) {
Expand All @@ -959,6 +972,10 @@ impl Areas {
rect = rect.expand(resize_interact_radius_side);
}

if let Some(transform) = layer_transforms.get(layer) {
rect = *transform * rect;
}

if rect.contains(pos) {
return Some(*layer);
}
Expand Down
18 changes: 16 additions & 2 deletions crates/egui/src/response.rs
Original file line number Diff line number Diff line change
Expand Up @@ -330,7 +330,14 @@ impl Response {
#[inline]
pub fn drag_delta(&self) -> Vec2 {
if self.dragged() {
self.ctx.input(|i| i.pointer.delta())
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;
}
delta
} else {
Vec2::ZERO
}
Expand Down Expand Up @@ -395,7 +402,14 @@ impl Response {
#[inline]
pub fn hover_pos(&self) -> Option<Pos2> {
if self.hovered() {
self.ctx.input(|i| i.pointer.hover_pos())
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).cloned())
{
pos = transform * pos;
}
Some(pos)
} else {
None
}
Expand Down
3 changes: 2 additions & 1 deletion crates/egui/src/ui.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2156,7 +2156,8 @@ impl Ui {

if let Some(pointer_pos) = self.ctx().pointer_interact_pos() {
let delta = pointer_pos - response.rect.center();
self.ctx().translate_layer(layer_id, delta);
self.ctx()
.set_transform_layer(layer_id, emath::TSTransform::from_translation(delta));
}

InnerResponse::new(inner, response)
Expand Down
1 change: 1 addition & 0 deletions crates/egui_demo_lib/src/demo/demo_app_windows.rs
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ impl Default for Demos {
Box::<super::MiscDemoWindow>::default(),
Box::<super::multi_touch::MultiTouch>::default(),
Box::<super::painting::Painting>::default(),
Box::<super::pan_zoom::PanZoom>::default(),
Box::<super::panels::Panels>::default(),
Box::<super::plot_demo::PlotDemo>::default(),
Box::<super::scrolling::Scrolling>::default(),
Expand Down
1 change: 1 addition & 0 deletions crates/egui_demo_lib/src/demo/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ pub mod misc_demo_window;
pub mod multi_touch;
pub mod paint_bezier;
pub mod painting;
pub mod pan_zoom;
pub mod panels;
pub mod password;
pub mod plot_demo;
Expand Down
Loading
Loading