Skip to content

Commit

Permalink
Nicer (& fixed up) help texts for space views (#2070)
Browse files Browse the repository at this point in the history
* Nicer (& fixed) help texts for space views

* centralize constants for space view controls

* fix calling primary mouse button right
"primary" would be more correct, but that's a mouth full

* update egui for modifiers.contains support

* formatting
  • Loading branch information
Wumpf authored May 15, 2023
1 parent ad4c38c commit 86adc26
Showing 15 changed files with 342 additions and 71 deletions.
18 changes: 9 additions & 9 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

14 changes: 7 additions & 7 deletions Cargo.toml
Original file line number Diff line number Diff line change
@@ -125,13 +125,13 @@ debug = true
# ALWAYS document what PR the commit hash is part of, or when it was merged into the upstream trunk.

# TODO(andreas/emilk): Update to a stable egui version
# wgpu 0.16 support, device configuration dependent on adapter, and some additions to help egui_tiles
ecolor = { git = "https://github.com/emilk/egui", rev = "e9fa6c8ff68a0257ce0f2801446ba701917b7ae9" }
eframe = { git = "https://github.com/emilk/egui", rev = "e9fa6c8ff68a0257ce0f2801446ba701917b7ae9" }
egui = { git = "https://github.com/emilk/egui", rev = "e9fa6c8ff68a0257ce0f2801446ba701917b7ae9" }
egui-wgpu = { git = "https://github.com/emilk/egui", rev = "e9fa6c8ff68a0257ce0f2801446ba701917b7ae9" }
egui_extras = { git = "https://github.com/emilk/egui", rev = "e9fa6c8ff68a0257ce0f2801446ba701917b7ae9" }
emath = { git = "https://github.com/emilk/egui", rev = "e9fa6c8ff68a0257ce0f2801446ba701917b7ae9" }
# wgpu 0.16 support, device configuration dependent on adapter, and some additions to help egui_tiles, egui::Modifiers::contains
ecolor = { git = "https://github.com/emilk/egui", rev = "ff8e482" }
eframe = { git = "https://github.com/emilk/egui", rev = "ff8e482" }
egui = { git = "https://github.com/emilk/egui", rev = "ff8e482" }
egui-wgpu = { git = "https://github.com/emilk/egui", rev = "ff8e482" }
egui_extras = { git = "https://github.com/emilk/egui", rev = "ff8e482" }
emath = { git = "https://github.com/emilk/egui", rev = "ff8e482" }

# TODO(andreas): Either work around this issue in wgpu-egui (never discard command buffers) or wait for wgpu patch release.
# Fix for command buffer dropping crash https://github.com/gfx-rs/wgpu/pull/3726
97 changes: 97 additions & 0 deletions crates/re_ui/src/layout_job_builder.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
/// Utility for building layout jobs.
pub struct LayoutJobBuilder<'a> {
pub layout_job: egui::text::LayoutJob,
pub re_ui: &'a crate::ReUi,
}

impl<'a> LayoutJobBuilder<'a> {
pub fn new(re_ui: &'a crate::ReUi) -> Self {
Self {
layout_job: egui::text::LayoutJob::default(),
re_ui,
}
}

/// Append a generic text block.
pub fn add<'b, T: Into<LayoutJobBuilderBuildingBlock<'b>>>(&mut self, text_block: T) {
let text_block: LayoutJobBuilderBuildingBlock<'_> = text_block.into();
match text_block {
LayoutJobBuilderBuildingBlock::Body(text) => self.add_body(text),
LayoutJobBuilderBuildingBlock::Key(key) => self.add_key(key),
LayoutJobBuilderBuildingBlock::Modifier(modifier) => self.add_modifier(modifier),
LayoutJobBuilderBuildingBlock::MouseButton(button) => self.add_mouse_button(button),
};
}

/// Append body text.
pub fn add_body(&mut self, text: &str) {
self.layout_job
.append(text, 0.0, self.re_ui.text_format_body());
}

/// Append text that has special formatting for a button.
pub fn add_button_text(&mut self, text: &str) {
self.layout_job
.append(&text.to_lowercase(), 0.0, self.re_ui.text_format_key());
}

/// Append text for a keyboard key.
pub fn add_key(&mut self, key: egui::Key) {
self.add_button_text(key.name());
}

/// Append text for one or more modifier keys.
pub fn add_modifier(&mut self, modifier: egui::Modifiers) {
let is_mac = matches!(
self.re_ui.egui_ctx.os(),
egui::os::OperatingSystem::Mac | egui::os::OperatingSystem::IOS
);
let text = egui::ModifierNames::NAMES.format(&modifier, is_mac);
self.add_button_text(&text);
}

/// Append text for a mouse button.
pub fn add_mouse_button(&mut self, button: egui::PointerButton) {
self.add_button_text(match button {
egui::PointerButton::Primary => "left mouse button",
egui::PointerButton::Secondary => "right mouse button",
egui::PointerButton::Middle => "middle mouse button",
egui::PointerButton::Extra1 => "extra mouse button 1",
egui::PointerButton::Extra2 => "extra mouse button 2",
});
}
}

/// Generic building block that the layout job builder can consume.
///
/// Not meant to be used directly, use [`LayoutJobBuilder::add`] instead.
pub enum LayoutJobBuilderBuildingBlock<'a> {
Body(&'a str),
Key(egui::Key),
Modifier(egui::Modifiers),
MouseButton(egui::PointerButton),
}

impl<'a> From<&'a str> for LayoutJobBuilderBuildingBlock<'a> {
fn from(text: &'a str) -> Self {
Self::Body(text)
}
}

impl From<egui::Key> for LayoutJobBuilderBuildingBlock<'_> {
fn from(key: egui::Key) -> Self {
Self::Key(key)
}
}

impl From<egui::Modifiers> for LayoutJobBuilderBuildingBlock<'_> {
fn from(modifier: egui::Modifiers) -> Self {
Self::Modifier(modifier)
}
}

impl From<egui::PointerButton> for LayoutJobBuilderBuildingBlock<'_> {
fn from(button: egui::PointerButton) -> Self {
Self::MouseButton(button)
}
}
20 changes: 20 additions & 0 deletions crates/re_ui/src/lib.rs
Original file line number Diff line number Diff line change
@@ -5,6 +5,7 @@ mod command_palette;
mod design_tokens;
pub mod egui_helpers;
pub mod icons;
mod layout_job_builder;
mod static_image_cache;
pub mod toasts;
mod toggle_switch;
@@ -13,6 +14,7 @@ pub use command::Command;
pub use command_palette::CommandPalette;
pub use design_tokens::DesignTokens;
pub use icons::Icon;
pub use layout_job_builder::LayoutJobBuilder;
pub use static_image_cache::StaticImageCache;
pub use toggle_switch::toggle_switch;

@@ -606,6 +608,24 @@ impl ReUi {

response
}

/// Text format used for regular body.
pub fn text_format_body(&self) -> egui::TextFormat {
egui::TextFormat::simple(
egui::TextStyle::Body.resolve(&self.egui_ctx.style()),
self.egui_ctx.style().visuals.text_color(),
)
}

/// Text format used for labels referring to keys and buttons.
pub fn text_format_key(&self) -> egui::TextFormat {
let mut style = egui::TextFormat::simple(
egui::TextStyle::Monospace.resolve(&self.egui_ctx.style()),
self.egui_ctx.style().visuals.text_color(),
);
style.background = self.egui_ctx.style().visuals.widgets.noninteractive.bg_fill;
style
}
}

// ----------------------------------------------------------------------------
1 change: 1 addition & 0 deletions crates/re_viewer/src/ui/mod.rs
Original file line number Diff line number Diff line change
@@ -5,6 +5,7 @@ mod selection_history_ui;
mod space_view;
mod space_view_entity_picker;
mod space_view_heuristics;
mod spaceview_controls;
mod view_bar_chart;
mod view_category;
mod view_tensor;
41 changes: 41 additions & 0 deletions crates/re_viewer/src/ui/spaceview_controls.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
/// Modifier to press for scroll to zoom.
pub const ZOOM_SCROLL_MODIFIER: egui::Modifiers = egui::Modifiers::COMMAND;

/// Modifier to press for scroll to pan horizontally.
pub const HORIZONTAL_SCROLL_MODIFIER: egui::Modifiers = egui::Modifiers::SHIFT;

/// Which mouse button to drag for panning a 2D view.
pub const DRAG_PAN2D_BUTTON: egui::PointerButton = egui::PointerButton::Primary;

/// Rectangles drawn with this mouse button zoom in 2D views.
pub const SELECTION_RECT_ZOOM_BUTTON: egui::PointerButton = egui::PointerButton::Secondary;

/// Clicking this button moves the timeline to where the cursor is.
pub const MOVE_TIME_CURSOR_BUTTON: egui::PointerButton = egui::PointerButton::Secondary;

/// Which mouse button to drag for panning a 2D view.
pub const DRAG_PAN3D_BUTTON: egui::PointerButton = egui::PointerButton::Secondary;

/// Which mouse button to drag for rotating a 3D view.
pub const ROTATE3D_BUTTON: egui::PointerButton = egui::PointerButton::Primary;

/// Which mouse button rolls the camera.
pub const ROLL_MOUSE: egui::PointerButton = egui::PointerButton::Middle;

/// Which mouse button rolls the camera if the roll modifier is pressed.
pub const ROLL_MOUSE_ALT: egui::PointerButton = egui::PointerButton::Primary;

/// See [`ROLL_MOUSE_ALT`].
pub const ROLL_MOUSE_MODIFIER: egui::Modifiers = egui::Modifiers::ALT;

/// Which modifier speeds up the 3D camera movement.
pub const SPEED_UP_3D_MODIFIER: egui::Modifiers = egui::Modifiers::SHIFT;

/// Which modifier slows down the 3D camera movement.
pub const SLOW_DOWN_3D_MODIFIER: egui::Modifiers = egui::Modifiers::CTRL;

/// Key to restore the camera.
pub const TRACKED_CAMERA_RESTORE_KEY: egui::Key = egui::Key::Escape;

/// Description text for which action resets a space view.
pub const RESET_VIEW_BUTTON_TEXT: &str = "double click";
2 changes: 1 addition & 1 deletion crates/re_viewer/src/ui/view_bar_chart/mod.rs
Original file line number Diff line number Diff line change
@@ -2,4 +2,4 @@ mod scene;
pub(crate) use self::scene::SceneBarChart;

mod ui;
pub(crate) use self::ui::{view_bar_chart, BarChartState, HELP_TEXT};
pub(crate) use self::ui::{help_text, view_bar_chart, BarChartState};
28 changes: 24 additions & 4 deletions crates/re_viewer/src/ui/view_bar_chart/ui.rs
Original file line number Diff line number Diff line change
@@ -7,14 +7,34 @@ use re_log::warn_once;
use re_log_types::component_types::{self, InstanceKey};
use re_viewer_context::{auto_color, ViewerContext};

use crate::ui::spaceview_controls::{
HORIZONTAL_SCROLL_MODIFIER, SELECTION_RECT_ZOOM_BUTTON, ZOOM_SCROLL_MODIFIER,
};

use super::SceneBarChart;

// ---

pub(crate) const HELP_TEXT: &str = "\
Pan by dragging, or scroll (+ shift = horizontal).\n\
Box zooming: Right click to zoom in and zoom out using a selection.\n\
Reset view with double-click.";
pub fn help_text(re_ui: &re_ui::ReUi) -> egui::WidgetText {
let mut layout = re_ui::LayoutJobBuilder::new(re_ui);

layout.add("Pan by dragging, or scroll (+ ");
layout.add(HORIZONTAL_SCROLL_MODIFIER);
layout.add(" for horizontal).\n");

layout.add("Zoom with pinch gesture or scroll + ");
layout.add(ZOOM_SCROLL_MODIFIER);
layout.add(".\n");

layout.add("Drag ");
layout.add(SELECTION_RECT_ZOOM_BUTTON);
layout.add(" to zoom in/out using a selection.\n\n");

layout.add_button_text("double-click");
layout.add(" to reset the view.");

layout.layout_job.into()
}

#[derive(Clone, Default, serde::Deserialize, serde::Serialize)]
pub struct BarChartState;
29 changes: 22 additions & 7 deletions crates/re_viewer/src/ui/view_spatial/eye.rs
Original file line number Diff line number Diff line change
@@ -2,6 +2,11 @@ use egui::{lerp, NumExt as _, Rect};
use glam::Affine3A;
use macaw::{vec3, IsoTransform, Mat4, Quat, Vec3};

use crate::ui::spaceview_controls::{
DRAG_PAN3D_BUTTON, ROLL_MOUSE, ROLL_MOUSE_ALT, ROLL_MOUSE_MODIFIER, ROTATE3D_BUTTON,
SLOW_DOWN_3D_MODIFIER, SPEED_UP_3D_MODIFIER,
};

use super::SpaceCamera3D;

/// An eye in a 3D view.
@@ -299,18 +304,20 @@ impl OrbitEye {
let mut did_interact = false;

if response.drag_delta().length() > drag_threshold {
if response.dragged_by(egui::PointerButton::Middle)
|| (response.dragged_by(egui::PointerButton::Primary)
&& response.ctx.input(|i| i.modifiers.alt))
if response.dragged_by(ROLL_MOUSE)
|| (response.dragged_by(ROLL_MOUSE_ALT)
&& response
.ctx
.input(|i| i.modifiers.contains(ROLL_MOUSE_MODIFIER)))
{
if let Some(pointer_pos) = response.ctx.pointer_latest_pos() {
self.roll(&response.rect, pointer_pos, response.drag_delta());
did_interact = true;
}
} else if response.dragged_by(egui::PointerButton::Primary) {
} else if response.dragged_by(ROTATE3D_BUTTON) {
self.rotate(response.drag_delta());
did_interact = true;
} else if response.dragged_by(egui::PointerButton::Secondary) {
} else if response.dragged_by(DRAG_PAN3D_BUTTON) {
self.translate(response.drag_delta());
did_interact = true;
}
@@ -379,8 +386,16 @@ impl OrbitEye {
local_movement = local_movement.normalize_or_zero();

let speed = self.orbit_radius
* (if input.modifiers.shift { 10.0 } else { 1.0 })
* (if input.modifiers.ctrl { 0.1 } else { 1.0 });
* (if input.modifiers.contains(SPEED_UP_3D_MODIFIER) {
10.0
} else {
1.0
})
* (if input.modifiers.contains(SLOW_DOWN_3D_MODIFIER) {
0.1
} else {
1.0
});
let world_movement = self.world_from_view_rot * (speed * local_movement);

self.velocity = egui::lerp(
Loading

0 comments on commit 86adc26

Please sign in to comment.