Skip to content

Commit

Permalink
Simplify zoom-and-pan area (#8390)
Browse files Browse the repository at this point in the history
* Simplify the zoom-pan-view
* Fix the zoom-pan-view eating the viewport highlight rectangle

---------

Co-authored-by: Jochen Görtler <me@jgoertler.com>
  • Loading branch information
emilk and grtlr authored Dec 11, 2024
1 parent 89851ee commit 91256d7
Show file tree
Hide file tree
Showing 3 changed files with 42 additions and 38 deletions.
2 changes: 1 addition & 1 deletion crates/store/re_chunk_store/src/writes.rs
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ impl ChunkStore {
for (component_name, per_desc) in chunk.components().iter() {
assert!(
per_desc.len() <= 1,
"Insert Chunk with multiple values for component named `{component_name}`: this is currently UB",
"[DEBUG ONLY] Insert Chunk with multiple values for component named `{component_name}`: this is currently UB",
);
}
}
Expand Down
67 changes: 32 additions & 35 deletions crates/viewer/re_ui/src/zoom_pan_area.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
//! * `view`-space: The space where the pan-and-zoom area is drawn.
//! * `scene`-space: The space where the actual content is drawn.
use egui::{emath::TSTransform, Area, Order, Rect, Response, Ui, UiKind};
use egui::{emath::TSTransform, Rect, Response, Ui, UiBuilder};

/// Helper function to handle pan and zoom interactions on a response.
fn register_pan_and_zoom(ui: &Ui, resp: &Response, ui_from_scene: &mut TSTransform) {
Expand Down Expand Up @@ -58,45 +58,42 @@ pub fn fit_to_rect_in_scene(rect_in_ui: Rect, rect_in_scene: Rect) -> TSTransfor

/// Provides a zoom-pan area for a given view.
pub fn zoom_pan_area(
ui: &Ui,
ui: &mut Ui,
view_bounds_in_ui: Rect,
ui_from_scene: &mut TSTransform,
draw_contents: impl FnOnce(&mut Ui),
) -> Response {
let area_resp = Area::new(ui.id().with("zoom_pan_area"))
.constrain_to(view_bounds_in_ui)
.order(Order::Middle)
.kind(UiKind::GenericArea)
.show(ui.ctx(), |ui| {
// Transform to the scene space:
let visible_rect_in_scene = ui_from_scene.inverse() * view_bounds_in_ui;

// set proper clip-rect so we can interact with the background.
ui.set_clip_rect(visible_rect_in_scene);

// A Ui for sensing drag-to-pan, scroll-to-zoom, etc
let mut drag_sense_ui = ui.new_child(
egui::UiBuilder::new()
.sense(egui::Sense::click_and_drag())
.max_rect(visible_rect_in_scene),
);
drag_sense_ui.set_min_size(visible_rect_in_scene.size());
let pan_response = drag_sense_ui.response();

// Update the transform based on the interactions:
register_pan_and_zoom(ui, &pan_response, ui_from_scene);

// Update the clip-rect with the new transform, to avoid frame-delays
ui.set_clip_rect(ui_from_scene.inverse() * view_bounds_in_ui);

// Add the actual contents to the area:
draw_contents(ui);

pan_response
});
let zoom_pan_layer_id = egui::LayerId::new(ui.layer_id().order, ui.id().with("zoom_pan_area"));

// Put the layer directly on-top of the main layer of the ui:
ui.ctx().set_sublayer(ui.layer_id(), zoom_pan_layer_id);

let mut ui = ui.new_child(
UiBuilder::new()
.layer_id(zoom_pan_layer_id)
.max_rect(view_bounds_in_ui)
.sense(egui::Sense::click_and_drag()),
);

// Transform to the scene space:
let visible_rect_in_scene = ui_from_scene.inverse() * view_bounds_in_ui;

// set proper clip-rect so we can interact with the background:
ui.set_clip_rect(visible_rect_in_scene);

let pan_response = ui.response();

// Update the transform based on the interactions:
register_pan_and_zoom(&ui, &pan_response, ui_from_scene);

// Update the clip-rect with the new transform, to avoid frame-delays
ui.set_clip_rect(ui_from_scene.inverse() * view_bounds_in_ui);

// Add the actual contents to the area:
draw_contents(&mut ui);

ui.ctx()
.set_transform_layer(area_resp.response.layer_id, *ui_from_scene);
.set_transform_layer(zoom_pan_layer_id, *ui_from_scene);

area_resp.inner
pan_response
}
11 changes: 9 additions & 2 deletions crates/viewer/re_viewport/src/viewport_ui.rs
Original file line number Diff line number Diff line change
Expand Up @@ -125,8 +125,15 @@ impl ViewportUi {
continue;
};

ui.painter()
.rect_stroke(rect.shrink(stroke.width / 2.0), 0.0, stroke);
// We want the rectangle to be on top of everything in the viewport,
// including stuff in "zoom-pan areas", like we use in the graph view.
let top_layer_id = egui::LayerId::new(ui.layer_id().order, ui.id().with("child_id"));
ui.ctx().set_sublayer(ui.layer_id(), top_layer_id); // Make sure it is directly on top of the ui layer

// We need to shrink a bit so the panel-resize lines don't cover the highlight rectangle.
// This is hacky.
ui.painter().clone().with_layer_id(top_layer_id)
.rect_stroke(rect.shrink(stroke.width), 0.0, stroke);
}
}

Expand Down

0 comments on commit 91256d7

Please sign in to comment.