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

Simplify zoom-and-pan area #8390

Merged
merged 4 commits into from
Dec 11, 2024
Merged
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
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
Loading