-
Notifications
You must be signed in to change notification settings - Fork 565
Add shortcuts to switch between recordings #11637
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
base: main
Are you sure you want to change the base?
Changes from 1 commit
a1ab26f
43ef515
c34408f
79324ba
65e9d89
9fae174
281121a
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,88 @@ | ||
| use crate::data::RecordingPanelData; | ||
| use egui::Id; | ||
| use itertools::Itertools; | ||
| use re_redap_browser::RedapServers; | ||
| use re_viewer_context::{DisplayMode, SystemCommand, SystemCommandSender, ViewerContext}; | ||
|
|
||
| /// Commands that need to be handled in the context of the recording panel UI. | ||
| /// | ||
| /// Why do we need another command kind? | ||
| /// So the Next / Previous recording action should be a `UiCommand` (for discoverability). | ||
| /// The order of recordings is defined by the recording panel, and the order of the next / previous | ||
| /// commands should match that. There is the nice [`RecordingPanelData`] struct that we can use | ||
| /// to iterate over the recordings in the same display order as the panel UI. | ||
| /// But to construct this, we need a [`ViewerContext`] and the usual `UiCommand` handler doesn't | ||
| /// have access to that, so we need to handle these commands "within" the frame, where we have | ||
| /// access to the context. | ||
| #[derive(Clone, Debug)] | ||
| pub enum RecordingPanelCommand { | ||
| /// Switch to the next recording in the recording panel. | ||
| SelectNextRecording, | ||
|
|
||
| /// Switch to the previous recording in the recording panel. | ||
| SelectPreviousRecording, | ||
| } | ||
|
|
||
| impl RecordingPanelCommand { | ||
| /// Send a command. | ||
| /// | ||
| /// Since the recording panel has no state, commands are stored in egui context. | ||
| pub fn send(self, ctx: &egui::Context) { | ||
| ctx.data_mut(|d| { | ||
| let mut commands: &mut Vec<Self> = d.get_temp_mut_or_default(Id::NULL); | ||
| commands.push(self); | ||
| }) | ||
| } | ||
|
|
||
| /// Read and clear all pending commands. | ||
| fn read(ctx: &egui::Context) -> Vec<Self> { | ||
| ctx.data_mut(|d| d.remove_temp(Id::NULL).unwrap_or_default()) | ||
| } | ||
|
|
||
| /// Handle any pending recording panel commands. | ||
| pub fn handle_recording_panel_commands(ctx: &ViewerContext<'_>, servers: &'_ RedapServers) { | ||
| let commands = RecordingPanelCommand::read(ctx.egui_ctx()); | ||
|
|
||
| let server_data = RecordingPanelData::new(ctx, servers, false); | ||
|
|
||
| for command in commands { | ||
| match command { | ||
| RecordingPanelCommand::SelectNextRecording => { | ||
| Self::shift_through_recordings(ctx, &server_data, 1); | ||
| } | ||
| RecordingPanelCommand::SelectPreviousRecording => { | ||
| Self::shift_through_recordings(ctx, &server_data, -1); | ||
| } | ||
| } | ||
| } | ||
| } | ||
|
|
||
| fn shift_through_recordings( | ||
| ctx: &ViewerContext<'_>, | ||
| server_data: &RecordingPanelData, | ||
| direction: isize, | ||
| ) { | ||
| let recordings = server_data | ||
| .iter_items_in_display_order() | ||
| .filter(|item| DisplayMode::from_item(item).is_some()) | ||
| .collect_vec(); | ||
| let displayed_item = ctx.display_mode().item(); | ||
|
|
||
| if let Some(displayed_item) = displayed_item { | ||
| let current_index = recordings.iter().position(|item| item == &displayed_item); | ||
|
|
||
| let previous_index = match current_index { | ||
| Some(idx) => { | ||
| let len = recordings.len() as isize; | ||
| ((idx as isize + direction + len) % len) as usize | ||
| } | ||
| None => 0, | ||
| }; | ||
|
|
||
| if let Some(previous_item) = recordings.get(previous_index) { | ||
| ctx.command_sender() | ||
| .send_system(SystemCommand::SetSelection(previous_item.clone().into())); | ||
| } | ||
| } | ||
| } | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -27,6 +27,9 @@ pub enum UICommand { | |
| CloseCurrentRecording, | ||
| CloseAllEntries, | ||
|
|
||
| NextRecording, | ||
| PreviousRecording, | ||
|
|
||
| Undo, | ||
| Redo, | ||
|
|
||
|
|
@@ -155,6 +158,12 @@ impl UICommand { | |
| "Close all open current recording (unsaved data will be lost)", | ||
| ), | ||
|
|
||
| UICommand::NextRecording => ("Next recording", "Switch to the next open recording"), | ||
| UICommand::PreviousRecording => ( | ||
| "Previous recording", | ||
| "Switch to the previous open recording", | ||
| ), | ||
|
|
||
| Self::Undo => ( | ||
| "Undo", | ||
| "Undo the last blueprint edit for the open recording", | ||
|
|
@@ -366,6 +375,9 @@ impl UICommand { | |
| Self::CloseCurrentRecording => smallvec![], | ||
| Self::CloseAllEntries => smallvec![], | ||
|
|
||
| Self::NextRecording => smallvec![cmd(Key::CloseBracket)], | ||
| Self::PreviousRecording => smallvec![cmd(Key::OpenBracket)], | ||
|
Comment on lines
+378
to
+379
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. There needs to be some bike shedding on these shortcuts.
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Note: we can support multiple keyboard shortcuts (a primary and a backup; that's why this is a vec). on macOS: on Windows and Linux, I think ctrl+[shift]+tab is the common one for switching between open tabs in an application? Based on this, I suggest ctrl+[shift]+tab as the primary on all platforms, with But I'd like to know where @pweids got
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. ctrl-tab is application switching in Windows, isn't it? I guess we could check what's the browser tab shortcut there. I'm not sure where
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. No, in Windows Alt-Tab is application switching (like cmd-tab in Mac)
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Ah right, my bad! |
||
|
|
||
| Self::Undo => smallvec![cmd(Key::Z)], | ||
| Self::Redo => { | ||
| if os == OperatingSystem::Mac { | ||
|
|
||
Uh oh!
There was an error while loading. Please reload this page.