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

Adapt UI for smaller screens #1608

Merged
merged 13 commits into from
Mar 20, 2023
5 changes: 5 additions & 0 deletions crates/re_ui/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -683,3 +683,8 @@ pub fn native_window_buttons_ui(frame: &mut eframe::Frame, ui: &mut egui::Ui) {
frame.set_minimized(true);
}
}

/// Is this a small-screen device?
pub fn is_mobile(ctx: &egui::Context) -> bool {
ctx.screen_rect().width() < 500.0
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For the moment the definition of is_mobile isn't great here and used only as "is this a narrow screen"... which completely ignores using mobile in landscape which can be very wide!
This opens up the question what the semantics of this really are. It is used for "this is a narrow screen", but one would expect is_mobile to be also about different controls, bigger buttons etc.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah I agree, it was badly named. I removed it.

It makes sense to have different limits for different parts of the UI anyway. We need to support a range of devices, not just "mobile" and "desktop".

}
168 changes: 112 additions & 56 deletions crates/re_viewer/src/app.rs
Original file line number Diff line number Diff line change
Expand Up @@ -279,13 +279,25 @@ impl App {
self.memory_panel_open ^= true;
}
Command::ToggleBlueprintPanel => {
self.blueprint_mut().blueprint_panel_expanded ^= true;
let blueprint = self.blueprint_mut(egui_ctx);
blueprint.blueprint_panel_expanded ^= true;

// Only one of blueprint or selection panel can be open at a time on mobile:
if re_ui::is_mobile(egui_ctx) && blueprint.blueprint_panel_expanded {
blueprint.selection_panel_expanded = false;
}
}
Command::ToggleSelectionPanel => {
self.blueprint_mut().selection_panel_expanded ^= true;
let blueprint = self.blueprint_mut(egui_ctx);
blueprint.selection_panel_expanded ^= true;

// Only one of blueprint or selection panel can be open at a time on mobile:
if re_ui::is_mobile(egui_ctx) && blueprint.selection_panel_expanded {
blueprint.blueprint_panel_expanded = false;
}
}
Command::ToggleTimePanel => {
self.blueprint_mut().time_panel_expanded ^= true;
self.blueprint_mut(egui_ctx).time_panel_expanded ^= true;
}

#[cfg(not(target_arch = "wasm32"))]
Expand Down Expand Up @@ -366,9 +378,12 @@ impl App {
}
}

fn blueprint_mut(&mut self) -> &mut Blueprint {
fn blueprint_mut(&mut self, egui_ctx: &egui::Context) -> &mut Blueprint {
let selected_app_id = self.selected_app_id();
self.state.blueprints.entry(selected_app_id).or_default()
self.state
.blueprints
.entry(selected_app_id)
.or_insert_with(|| Blueprint::new(egui_ctx))
}

fn memory_panel_ui(
Expand Down Expand Up @@ -487,7 +502,11 @@ impl eframe::App for App {
.map_or_else(ApplicationId::unknown, |rec_info| {
rec_info.application_id.clone()
});
let blueprint = self.state.blueprints.entry(selected_app_id).or_default();
let blueprint = self
.state
.blueprints
.entry(selected_app_id)
.or_insert_with(|| Blueprint::new(egui_ctx));

recording_config_entry(
&mut self.state.recording_configs,
Expand Down Expand Up @@ -940,7 +959,9 @@ impl AppState {
render_ctx,
};

let blueprint = blueprints.entry(selected_app_id.clone()).or_default();
let blueprint = blueprints
.entry(selected_app_id.clone())
.or_insert_with(|| Blueprint::new(ui.ctx()));
time_panel.show_panel(&mut ctx, blueprint, ui);
selection_panel.show_panel(&mut ctx, ui, blueprint);

Expand All @@ -955,7 +976,7 @@ impl AppState {
.show_inside(ui, |ui| match *panel_selection {
PanelSelection::Viewport => blueprints
.entry(selected_app_id)
.or_default()
.or_insert_with(|| Blueprint::new(ui.ctx()))
.blueprint_panel_and_viewport(&mut ctx, ui),
PanelSelection::EventLog => event_log_view.ui(&mut ctx, ui),
});
Expand Down Expand Up @@ -1039,7 +1060,7 @@ fn top_panel(
});
}

fn rerun_menu_button_ui(ui: &mut egui::Ui, _frame: &mut eframe::Frame, app: &mut App) {
fn rerun_menu_button_ui(ui: &mut egui::Ui, frame: &mut eframe::Frame, app: &mut App) {
// let desired_icon_height = ui.max_rect().height() - 2.0 * ui.spacing_mut().button_padding.y;
let desired_icon_height = ui.max_rect().height() - 4.0; // TODO(emilk): figure out this fudge
let desired_icon_height = desired_icon_height.at_most(28.0); // figma size 2023-02-03
Expand Down Expand Up @@ -1101,7 +1122,7 @@ fn rerun_menu_button_ui(ui: &mut egui::Ui, _frame: &mut eframe::Frame, app: &mut
});

ui.menu_button("Options", |ui| {
options_menu_ui(ui, &mut app.state.app_options);
options_menu_ui(ui, frame, &mut app.state.app_options);
});

ui.add_space(spacing);
Expand Down Expand Up @@ -1180,7 +1201,11 @@ fn top_bar_ui(
rec_info.application_id.clone()
});

let blueprint = app.state.blueprints.entry(selected_app_id).or_default();
let blueprint = app
.state
.blueprints
.entry(selected_app_id)
.or_insert_with(|| Blueprint::new(ui.ctx()));

// From right-to-left:

Expand All @@ -1196,38 +1221,56 @@ fn top_bar_ui(
ui.add_space(extra_margin);
}

app.re_ui
let mut selection_panel_expanded = blueprint.selection_panel_expanded;
if app
.re_ui
.medium_icon_toggle_button(
ui,
&re_ui::icons::RIGHT_PANEL_TOGGLE,
&mut blueprint.selection_panel_expanded,
&mut selection_panel_expanded,
)
.on_hover_text(format!(
"Toggle Selection View{}",
Command::ToggleSelectionPanel.format_shortcut_tooltip_suffix(ui.ctx())
));
))
.clicked()
{
app.pending_commands.push(Command::ToggleSelectionPanel);
}

app.re_ui
let mut time_panel_expanded = blueprint.time_panel_expanded;
if app
.re_ui
.medium_icon_toggle_button(
ui,
&re_ui::icons::BOTTOM_PANEL_TOGGLE,
&mut blueprint.time_panel_expanded,
&mut time_panel_expanded,
)
.on_hover_text(format!(
"Toggle Timeline View{}",
Command::ToggleTimePanel.format_shortcut_tooltip_suffix(ui.ctx())
));
))
.clicked()
{
app.pending_commands.push(Command::ToggleTimePanel);
}

app.re_ui
let mut blueprint_panel_expanded = blueprint.blueprint_panel_expanded;
if app
.re_ui
.medium_icon_toggle_button(
ui,
&re_ui::icons::LEFT_PANEL_TOGGLE,
&mut blueprint.blueprint_panel_expanded,
&mut blueprint_panel_expanded,
)
.on_hover_text(format!(
"Toggle Blueprint View{}",
Command::ToggleBlueprintPanel.format_shortcut_tooltip_suffix(ui.ctx())
));
))
.clicked()
{
app.pending_commands.push(Command::ToggleBlueprintPanel);
}

if cfg!(debug_assertions) && app.state.app_options.show_metrics {
ui.vertical_centered(|ui| {
Expand Down Expand Up @@ -1515,7 +1558,7 @@ fn recordings_menu(ui: &mut egui::Ui, app: &mut App) {
}
}

fn options_menu_ui(ui: &mut egui::Ui, options: &mut AppOptions) {
fn options_menu_ui(ui: &mut egui::Ui, frame: &mut eframe::Frame, options: &mut AppOptions) {
ui.style_mut().wrap = Some(false);

if ui
Expand All @@ -1530,45 +1573,58 @@ fn options_menu_ui(ui: &mut egui::Ui, options: &mut AppOptions) {
{
ui.separator();
ui.label("Debug:");
debug_menu_options_ui(ui);
debug_menu_options_ui(ui, frame);
}
}

#[cfg(debug_assertions)]
fn debug_menu_options_ui(ui: &mut egui::Ui) {
let mut debug = ui.style().debug;
let mut any_clicked = false;

any_clicked |= ui
.checkbox(&mut debug.debug_on_hover, "Ui debug on hover")
.on_hover_text("However over widgets to see their rectangles")
.changed();
any_clicked |= ui
.checkbox(&mut debug.show_expand_width, "Show expand width")
.on_hover_text("Show which widgets make their parent wider")
.changed();
any_clicked |= ui
.checkbox(&mut debug.show_expand_height, "Show expand height")
.on_hover_text("Show which widgets make their parent higher")
.changed();
any_clicked |= ui.checkbox(&mut debug.show_resize, "Show resize").changed();
any_clicked |= ui
.checkbox(
&mut debug.show_interactive_widgets,
"Show interactive widgets",
)
.on_hover_text("Show an overlay on all interactive widgets.")
.changed();
// This option currently causes the viewer to hang.
// any_clicked |= ui
// .checkbox(&mut debug.show_blocking_widget, "Show blocking widgets")
// .on_hover_text("Show what widget blocks the interaction of another widget.")
// .changed();

if any_clicked {
let mut style = (*ui.ctx().style()).clone();
style.debug = debug;
ui.ctx().set_style(style);
fn debug_menu_options_ui(ui: &mut egui::Ui, _frame: &mut eframe::Frame) {
{
let mut debug = ui.style().debug;
let mut any_clicked = false;

any_clicked |= ui
.checkbox(&mut debug.debug_on_hover, "Ui debug on hover")
.on_hover_text("However over widgets to see their rectangles")
.changed();
any_clicked |= ui
.checkbox(&mut debug.show_expand_width, "Show expand width")
.on_hover_text("Show which widgets make their parent wider")
.changed();
any_clicked |= ui
.checkbox(&mut debug.show_expand_height, "Show expand height")
.on_hover_text("Show which widgets make their parent higher")
.changed();
any_clicked |= ui.checkbox(&mut debug.show_resize, "Show resize").changed();
any_clicked |= ui
.checkbox(
&mut debug.show_interactive_widgets,
"Show interactive widgets",
)
.on_hover_text("Show an overlay on all interactive widgets.")
.changed();
// This option currently causes the viewer to hang.
// any_clicked |= ui
// .checkbox(&mut debug.show_blocking_widget, "Show blocking widgets")
// .on_hover_text("Show what widget blocks the interaction of another widget.")
// .changed();

if any_clicked {
let mut style = (*ui.ctx().style()).clone();
style.debug = debug;
ui.ctx().set_style(style);
}
}

#[cfg(not(target_arch = "wasm32"))]
{
ui.separator();
if ui.button("Mobile size").clicked() {
// frame.set_window_size(egui::vec2(375.0, 812.0)); // iPhone 12 mini
_frame.set_window_size(egui::vec2(375.0, 667.0)); // iPhone SE 2nd gen
_frame.set_fullscreen(false);
ui.close_menu();
}
}

ui.separator();
Expand Down
16 changes: 4 additions & 12 deletions crates/re_viewer/src/misc/time_control_ui.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,19 +6,11 @@ use re_log_types::TimeType;
use super::time_control::{Looping, PlayState, TimeControl};

impl TimeControl {
pub fn time_control_ui(
pub fn timeline_selector_ui(
&mut self,
re_ui: &re_ui::ReUi,
times_per_timeline: &TimesPerTimeline,
ui: &mut egui::Ui,
) {
self.play_pause_ui(re_ui, times_per_timeline, ui);
self.timeline_selector_ui(times_per_timeline, ui);
self.playback_speed_ui(ui);
self.fps_ui(ui);
}

fn timeline_selector_ui(&mut self, times_per_timeline: &TimesPerTimeline, ui: &mut egui::Ui) {
self.select_a_valid_timeline(times_per_timeline);

egui::ComboBox::from_id_source("timeline")
Expand All @@ -38,7 +30,7 @@ impl TimeControl {
});
}

fn fps_ui(&mut self, ui: &mut egui::Ui) {
pub fn fps_ui(&mut self, ui: &mut egui::Ui) {
if self.time_type() == TimeType::Sequence {
if let Some(mut fps) = self.fps() {
ui.add(
Expand All @@ -53,7 +45,7 @@ impl TimeControl {
}
}

fn play_pause_ui(
pub fn play_pause_ui(
&mut self,
re_ui: &re_ui::ReUi,
times_per_timeline: &TimesPerTimeline,
Expand Down Expand Up @@ -178,7 +170,7 @@ impl TimeControl {
});
}

fn playback_speed_ui(&mut self, ui: &mut egui::Ui) {
pub fn playback_speed_ui(&mut self, ui: &mut egui::Ui) {
let mut speed = self.speed();
let drag_speed = (speed * 0.02).at_least(0.01);
ui.add(
Expand Down
2 changes: 1 addition & 1 deletion crates/re_viewer/src/native.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ type AppCreator =
pub fn run_native_app(app_creator: AppCreator) -> eframe::Result<()> {
let native_options = eframe::NativeOptions {
initial_window_size: Some([1600.0, 1200.0].into()),
min_window_size: Some([600.0, 450.0].into()), // Should be high enough to fit the rerun menu
min_window_size: Some([320.0, 450.0].into()), // Should be high enough to fit the rerun menu

#[cfg(target_os = "macos")]
fullsize_content: re_ui::FULLSIZE_CONTENT,
Expand Down
20 changes: 11 additions & 9 deletions crates/re_viewer/src/ui/blueprint.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ use crate::misc::{space_info::SpaceInfoCollection, ViewerContext};
use super::viewport::Viewport;

/// Defines the layout of the whole Viewer (or will, eventually).
#[derive(serde::Deserialize, serde::Serialize)]
#[derive(Default, serde::Deserialize, serde::Serialize)]
#[serde(default)]
pub struct Blueprint {
pub blueprint_panel_expanded: bool,
Expand All @@ -13,18 +13,18 @@ pub struct Blueprint {
pub viewport: Viewport,
}

impl Default for Blueprint {
fn default() -> Self {
impl Blueprint {
/// Prefer this to [`Blueprint::default`] to get better defaults based on screen size.
pub fn new(egui_ctx: &egui::Context) -> Self {
let screen_size = egui_ctx.screen_rect().size();
Self {
blueprint_panel_expanded: true,
selection_panel_expanded: true,
time_panel_expanded: true,
blueprint_panel_expanded: screen_size.x > 750.0,
selection_panel_expanded: screen_size.x > 1000.0,
time_panel_expanded: screen_size.y > 600.0,
viewport: Default::default(),
}
}
}

impl Blueprint {
pub fn blueprint_panel_and_viewport(&mut self, ctx: &mut ViewerContext<'_>, ui: &mut egui::Ui) {
crate::profile_function!();

Expand Down Expand Up @@ -52,14 +52,16 @@ impl Blueprint {
ui: &mut egui::Ui,
spaces_info: &SpaceInfoCollection,
) {
let screen_width = ui.ctx().screen_rect().width();

let panel = egui::SidePanel::left("blueprint_panel")
.resizable(true)
.frame(egui::Frame {
fill: ui.visuals().panel_fill,
..Default::default()
})
.min_width(120.0)
.default_width(200.0);
.default_width((0.35 * screen_width).min(200.0).round());

panel.show_animated_inside(ui, self.blueprint_panel_expanded, |ui: &mut egui::Ui| {
self.title_bar_ui(ctx, ui, spaces_info);
Expand Down
Loading