Skip to content

Commit

Permalink
Viewer's command queue is now a channel, allowing to queue commands w…
Browse files Browse the repository at this point in the history
…ithout mutable access (#2339)

<!--
Open the PR up as a draft until you feel it is ready for a proper
review.

Do not make PR:s from your own `main` branch, as that makes it difficult
for reviewers to add their own fixes.

Add any improvements to the branch as new commits to make it easier for
reviewers to follow the progress. All commits will be squashed to a
single commit once the PR is merged into `main`.

Make sure you mention any issues that this PR closes in the description,
as well as any other related issues.

To get an auto-generated PR description you can put "copilot:summary" or
"copilot:walkthrough" anywhere.
-->

### What

Allows for decoupling a bunch of things!
The good parts from #2333 ;)

### Checklist
* [x] I have read and agree to [Contributor
Guide](https://github.com/rerun-io/rerun/blob/main/CONTRIBUTING.md) and
the [Code of
Conduct](https://github.com/rerun-io/rerun/blob/main/CODE_OF_CONDUCT.md)

<!-- This line will get updated when the PR build summary job finishes.
-->
PR Build Summary: https://build.rerun.io/pr/2339

<!-- pr-link-docs:start -->
Docs preview: https://rerun.io/preview/c58f5af/docs
Examples preview: https://rerun.io/preview/c58f5af/examples
<!-- pr-link-docs:end -->

---------

Co-authored-by: Jeremy Leibs <[email protected]>
  • Loading branch information
Wumpf and jleibs authored Jun 8, 2023
1 parent 141c64d commit 0dc490c
Show file tree
Hide file tree
Showing 8 changed files with 78 additions and 40 deletions.
1 change: 1 addition & 0 deletions Cargo.lock

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

3 changes: 2 additions & 1 deletion crates/re_ui/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -29,8 +29,9 @@ eframe = ["dep:eframe"]


[dependencies]
egui.workspace = true
crossbeam.workspace = true
egui_extras.workspace = true
egui.workspace = true
image = { workspace = true, default-features = false, features = ["png"] }
parking_lot.workspace = true
serde = { version = "1", features = ["derive"] }
Expand Down
28 changes: 16 additions & 12 deletions crates/re_ui/examples/re_ui_example.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use re_ui::{toasts, Command, CommandPalette};
use re_ui::{toasts, Command, CommandPalette, CommandReceiver, CommandSender};

fn main() -> eframe::Result<()> {
re_log::setup_native_logging();
Expand Down Expand Up @@ -49,7 +49,8 @@ pub struct ExampleApp {
cmd_palette: CommandPalette,

/// Commands to run at the end of the frame.
pending_commands: Vec<Command>,
pub command_sender: CommandSender,
command_receiver: CommandReceiver,
latest_cmd: String,
}

Expand All @@ -60,6 +61,8 @@ impl ExampleApp {

let tree = egui_tiles::Tree::new_tabs(vec![1, 2, 3]);

let (command_sender, command_receiver) = re_ui::command_channel();

Self {
re_ui,
toasts: Default::default(),
Expand All @@ -74,7 +77,8 @@ impl ExampleApp {
dummy_bool: true,

cmd_palette: CommandPalette::default(),
pending_commands: Default::default(),
command_sender,
command_receiver,
latest_cmd: Default::default(),
}
}
Expand Down Expand Up @@ -205,13 +209,13 @@ impl eframe::App for ExampleApp {
});

if let Some(cmd) = self.cmd_palette.show(egui_ctx) {
self.pending_commands.push(cmd);
self.command_sender.send(cmd);
}
if let Some(cmd) = re_ui::Command::listen_for_kb_shortcut(egui_ctx) {
self.pending_commands.push(cmd);
self.command_sender.send(cmd);
}

for cmd in self.pending_commands.drain(..) {
while let Some(cmd) = self.command_receiver.recv() {
self.latest_cmd = cmd.text().to_owned();

#[allow(clippy::single_match)]
Expand Down Expand Up @@ -248,7 +252,7 @@ impl ExampleApp {
ui.set_height(top_bar_style.height);
ui.add_space(top_bar_style.indent);

ui.menu_button("File", |ui| file_menu(ui, &mut self.pending_commands));
ui.menu_button("File", |ui| file_menu(ui, &self.command_sender));

self.top_bar_ui(ui, frame);
})
Expand Down Expand Up @@ -297,11 +301,11 @@ impl ExampleApp {
}
}

fn file_menu(ui: &mut egui::Ui, pending_commands: &mut Vec<Command>) {
Command::Save.menu_button_ui(ui, pending_commands);
Command::SaveSelection.menu_button_ui(ui, pending_commands);
Command::Open.menu_button_ui(ui, pending_commands);
Command::Quit.menu_button_ui(ui, pending_commands);
fn file_menu(ui: &mut egui::Ui, command_sender: &CommandSender) {
Command::Save.menu_button_ui(ui, command_sender);
Command::SaveSelection.menu_button_ui(ui, command_sender);
Command::Open.menu_button_ui(ui, command_sender);
Command::Quit.menu_button_ui(ui, command_sender);
}

fn selection_buttons(ui: &mut egui::Ui) {
Expand Down
33 changes: 31 additions & 2 deletions crates/re_ui/src/command.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,34 @@
use egui::{Key, KeyboardShortcut, Modifiers};

/// Sender that queues up the execution of a command.
pub struct CommandSender(crossbeam::channel::Sender<Command>);

impl CommandSender {
/// Send a command to be executed.
pub fn send(&self, command: Command) {
// The only way this can fail is if the receiver has been dropped.
self.0.send(command).ok();
}
}

/// Receiver for the [`CommandSender`]
pub struct CommandReceiver(crossbeam::channel::Receiver<Command>);

impl CommandReceiver {
/// Receive a command to be executed if any is queued.
pub fn recv(&self) -> Option<Command> {
// The only way this can fail (other than being empty)
// is if the sender has been dropped.
self.0.try_recv().ok()
}
}

/// Creates a new command channel.
pub fn command_channel() -> (CommandSender, CommandReceiver) {
let (sender, receiver) = crossbeam::channel::unbounded();
(CommandSender(sender), CommandReceiver(receiver))
}

/// All the commands we support.
///
/// Most are available in the GUI,
Expand Down Expand Up @@ -232,12 +261,12 @@ impl Command {
pub fn menu_button_ui(
self,
ui: &mut egui::Ui,
pending_commands: &mut Vec<Command>,
command_sender: &CommandSender,
) -> egui::Response {
let button = self.menu_button(ui.ctx());
let response = ui.add(button).on_hover_text(self.tooltip());
if response.clicked() {
pending_commands.push(self);
command_sender.send(self);
ui.close_menu();
}
response
Expand Down
2 changes: 1 addition & 1 deletion crates/re_ui/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ mod static_image_cache;
pub mod toasts;
mod toggle_switch;

pub use command::Command;
pub use command::{command_channel, Command, CommandReceiver, CommandSender};
pub use command_palette::CommandPalette;
pub use design_tokens::DesignTokens;
pub use icons::Icon;
Expand Down
19 changes: 11 additions & 8 deletions crates/re_viewer/src/app.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ use re_data_store::store_db::StoreDb;
use re_log_types::{ApplicationId, LogMsg, StoreId, StoreKind};
use re_renderer::WgpuResourcePoolStatistics;
use re_smart_channel::Receiver;
use re_ui::{toasts, Command};
use re_ui::{toasts, Command, CommandReceiver, CommandSender};
use re_viewer_context::{
AppOptions, ComponentUiRegistry, DynSpaceViewClass, PlayState, SpaceViewClassRegistry,
SpaceViewClassRegistryError,
Expand Down Expand Up @@ -108,7 +108,8 @@ pub struct App {
pub(crate) frame_time_history: egui::util::History<f32>,

/// Commands to run at the end of the frame.
pub(crate) pending_commands: Vec<Command>,
pub command_sender: CommandSender,
command_receiver: CommandReceiver,
cmd_palette: re_ui::CommandPalette,

analytics: ViewerAnalytics,
Expand Down Expand Up @@ -164,6 +165,8 @@ impl App {
screenshotter.screenshot_to_path_then_quit(screenshot_path);
}

let (command_sender, command_receiver) = re_ui::command_channel();

Self {
build_info,
startup_options,
Expand All @@ -188,7 +191,8 @@ impl App {

frame_time_history: egui::util::History::new(1..100, 0.5),

pending_commands: Default::default(),
command_sender,
command_receiver,
cmd_palette: Default::default(),

space_view_class_registry,
Expand Down Expand Up @@ -237,9 +241,9 @@ impl App {
self.space_view_class_registry.add::<T>()
}

fn check_keyboard_shortcuts(&mut self, egui_ctx: &egui::Context) {
fn check_keyboard_shortcuts(&self, egui_ctx: &egui::Context) {
if let Some(cmd) = Command::listen_for_kb_shortcut(egui_ctx) {
self.pending_commands.push(cmd);
self.command_sender.send(cmd);
}
}

Expand All @@ -249,8 +253,7 @@ impl App {
egui_ctx: &egui::Context,
frame: &mut eframe::Frame,
) {
let commands = self.pending_commands.drain(..).collect_vec();
for cmd in commands {
while let Some(cmd) = self.command_receiver.recv() {
self.run_command(cmd, blueprint, frame, egui_ctx);
}
}
Expand Down Expand Up @@ -906,7 +909,7 @@ impl eframe::App for App {
}

if let Some(cmd) = self.cmd_palette.show(egui_ctx) {
self.pending_commands.push(cmd);
self.command_sender.send(cmd);
}

self.run_pending_commands(&mut blueprint, egui_ctx, frame);
Expand Down
24 changes: 12 additions & 12 deletions crates/re_viewer/src/ui/rerun_menu.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,13 +26,13 @@ pub fn rerun_menu_button_ui(ui: &mut egui::Ui, frame: &mut eframe::Frame, app: &

ui.add_space(spacing);

Command::ToggleCommandPalette.menu_button_ui(ui, &mut app.pending_commands);
Command::ToggleCommandPalette.menu_button_ui(ui, &app.command_sender);

ui.add_space(spacing);

#[cfg(not(target_arch = "wasm32"))]
{
Command::Open.menu_button_ui(ui, &mut app.pending_commands);
Command::Open.menu_button_ui(ui, &app.command_sender);

save_buttons_ui(ui, app);

Expand All @@ -42,24 +42,24 @@ pub fn rerun_menu_button_ui(ui: &mut egui::Ui, frame: &mut eframe::Frame, app: &
let zoom_factor = app.app_options().zoom_factor;
ui.weak(format!("Zoom {:.0}%", zoom_factor * 100.0))
.on_hover_text("The zoom factor applied on top of the OS scaling factor.");
Command::ZoomIn.menu_button_ui(ui, &mut app.pending_commands);
Command::ZoomOut.menu_button_ui(ui, &mut app.pending_commands);
Command::ZoomIn.menu_button_ui(ui, &app.command_sender);
Command::ZoomOut.menu_button_ui(ui, &app.command_sender);
ui.add_enabled_ui(zoom_factor != 1.0, |ui| {
Command::ZoomReset.menu_button_ui(ui, &mut app.pending_commands)
Command::ZoomReset.menu_button_ui(ui, &app.command_sender)
});

Command::ToggleFullscreen.menu_button_ui(ui, &mut app.pending_commands);
Command::ToggleFullscreen.menu_button_ui(ui, &app.command_sender);

ui.add_space(spacing);
}

{
Command::ResetViewer.menu_button_ui(ui, &mut app.pending_commands);
Command::ResetViewer.menu_button_ui(ui, &app.command_sender);

#[cfg(not(target_arch = "wasm32"))]
Command::OpenProfiler.menu_button_ui(ui, &mut app.pending_commands);
Command::OpenProfiler.menu_button_ui(ui, &app.command_sender);

Command::ToggleMemoryPanel.menu_button_ui(ui, &mut app.pending_commands);
Command::ToggleMemoryPanel.menu_button_ui(ui, &app.command_sender);
}

ui.add_space(spacing);
Expand All @@ -85,7 +85,7 @@ pub fn rerun_menu_button_ui(ui: &mut egui::Ui, frame: &mut eframe::Frame, app: &
#[cfg(not(target_arch = "wasm32"))]
{
ui.add_space(spacing);
Command::Quit.menu_button_ui(ui, &mut app.pending_commands);
Command::Quit.menu_button_ui(ui, &app.command_sender);
}
});
}
Expand Down Expand Up @@ -280,7 +280,7 @@ fn save_buttons_ui(ui: &mut egui::Ui, app: &mut App) {
.clicked()
{
ui.close_menu();
app.pending_commands.push(Command::Save);
app.command_sender.send(Command::Save);
}

// We need to know the loop selection _before_ we can even display the
Expand All @@ -297,7 +297,7 @@ fn save_buttons_ui(ui: &mut egui::Ui, app: &mut App) {
.clicked()
{
ui.close_menu();
app.pending_commands.push(Command::SaveSelection);
app.command_sender.send(Command::SaveSelection);
}
});
}
Expand Down
8 changes: 4 additions & 4 deletions crates/re_viewer/src/ui/top_panel.rs
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,7 @@ fn top_bar_ui(
))
.clicked()
{
app.pending_commands.push(Command::ToggleSelectionPanel);
app.command_sender.send(Command::ToggleSelectionPanel);
}

let mut time_panel_expanded = blueprint.time_panel_expanded;
Expand All @@ -113,7 +113,7 @@ fn top_bar_ui(
))
.clicked()
{
app.pending_commands.push(Command::ToggleTimePanel);
app.command_sender.send(Command::ToggleTimePanel);
}

let mut blueprint_panel_expanded = blueprint.blueprint_panel_expanded;
Expand All @@ -130,7 +130,7 @@ fn top_bar_ui(
))
.clicked()
{
app.pending_commands.push(Command::ToggleBlueprintPanel);
app.command_sender.send(Command::ToggleBlueprintPanel);
}

if cfg!(debug_assertions) && app.app_options().show_metrics {
Expand All @@ -143,7 +143,7 @@ fn top_bar_ui(
});
}

fn frame_time_label_ui(ui: &mut egui::Ui, app: &mut App) {
fn frame_time_label_ui(ui: &mut egui::Ui, app: &App) {
if let Some(frame_time) = app.frame_time_history.average() {
let ms = frame_time * 1e3;

Expand Down

0 comments on commit 0dc490c

Please sign in to comment.