Skip to content

Commit

Permalink
Add a new CLI option / spawn options to hide the welcome screen (#6262)
Browse files Browse the repository at this point in the history
### What
- Partially addresses: #6140

We still need to also tackle
#6263 since the place-holder UI
isn't great.

![image](https://github.com/rerun-io/rerun/assets/3312232/736a42fb-a29e-48e2-8316-9dc790f1e3ad)

### Details
Handling this via blueprint is awkward since the welcome screen
presentation happens without respect to any given blueprint, or in cases
when all the recordings and their blueprints have been closed.

I decided adding this as a spawn option makes the most sense, since this
is the context where someone knows how they are embedding Rerun in
another application.

### 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)
* [x] I've included a screenshot or gif (if applicable)
* [x] I have tested the web demo (if applicable):
* Using examples from latest `main` build:
[rerun.io/viewer](https://rerun.io/viewer/pr/6262?manifest_url=https://app.rerun.io/version/main/examples_manifest.json)
* Using full set of examples from `nightly` build:
[rerun.io/viewer](https://rerun.io/viewer/pr/6262?manifest_url=https://app.rerun.io/version/nightly/examples_manifest.json)
* [x] The PR title and labels are set such as to maximize their
usefulness for the next release's CHANGELOG
* [x] If applicable, add a new check to the [release
checklist](https://github.com/rerun-io/rerun/blob/main/tests/python/release_checklist)!

- [PR Build Summary](https://build.rerun.io/pr/6262)
- [Recent benchmark results](https://build.rerun.io/graphs/crates.html)
- [Wasm size tracking](https://build.rerun.io/graphs/sizes.html)

To run all checks from `main`, comment on the PR with `@rerun-bot
full-check`.
  • Loading branch information
jleibs committed May 10, 2024
1 parent a37c0c2 commit 7c767ab
Show file tree
Hide file tree
Showing 20 changed files with 148 additions and 27 deletions.
13 changes: 11 additions & 2 deletions crates/re_sdk/src/spawn.rs
Expand Up @@ -44,6 +44,9 @@ pub struct SpawnOptions {

/// Extra arguments that will be passed as-is to the Rerun Viewer process.
pub extra_args: Vec<String>,

/// Hide the welcome screen.
pub hide_welcome_screen: bool,
}

// NOTE: No need for .exe extension on windows.
Expand All @@ -58,6 +61,7 @@ impl Default for SpawnOptions {
executable_name: RERUN_BINARY.into(),
executable_path: None,
extra_args: Vec::new(),
hide_welcome_screen: false,
}
}
}
Expand Down Expand Up @@ -257,8 +261,13 @@ pub fn spawn(opts: &SpawnOptions) -> Result<(), SpawnError> {
.stdin(std::process::Stdio::null())
.arg(format!("--port={port}"))
.arg(format!("--memory-limit={memory_limit}"))
.arg("--expect-data-soon")
.args(opts.extra_args.clone());
.arg("--expect-data-soon");

if opts.hide_welcome_screen {
rerun_bin.arg("--hide-welcome-screen");
}

rerun_bin.args(opts.extra_args.clone());

// SAFETY: This code is only run in the child fork, we are not modifying any memory
// that is shared with the parent process.
Expand Down
15 changes: 13 additions & 2 deletions crates/re_viewer/src/app.rs
Expand Up @@ -12,7 +12,10 @@ use re_viewer_context::{
SystemCommandSender,
};

use crate::{app_blueprint::AppBlueprint, background_tasks::BackgroundTasks, AppState};
use crate::{
app_blueprint::AppBlueprint, app_state::WelcomeScreenState, background_tasks::BackgroundTasks,
AppState,
};

// ----------------------------------------------------------------------------

Expand Down Expand Up @@ -47,6 +50,9 @@ pub struct StartupOptions {
#[cfg(not(target_arch = "wasm32"))]
pub screenshot_to_path_then_quit: Option<std::path::PathBuf>,

/// A user has specifically requested the welcome screen be hidden.
pub hide_welcome_screen: bool,

/// Set the screen resolution in logical points.
#[cfg(not(target_arch = "wasm32"))]
pub resolution_in_points: Option<[f32; 2]>,
Expand Down Expand Up @@ -77,6 +83,8 @@ impl Default for StartupOptions {
#[cfg(not(target_arch = "wasm32"))]
screenshot_to_path_then_quit: None,

hide_welcome_screen: false,

#[cfg(not(target_arch = "wasm32"))]
resolution_in_points: None,

Expand Down Expand Up @@ -916,7 +924,10 @@ impl App {
&self.space_view_class_registry,
&self.rx,
&self.command_sender,
self.welcome_screen_opacity(egui_ctx),
&WelcomeScreenState {
hide: self.startup_options.hide_welcome_screen,
opacity: self.welcome_screen_opacity(egui_ctx),
},
);
}
render_ctx.before_submit();
Expand Down
14 changes: 11 additions & 3 deletions crates/re_viewer/src/app_state.rs
Expand Up @@ -72,6 +72,14 @@ impl Default for AppState {
}
}

pub(crate) struct WelcomeScreenState {
/// The normal welcome screen should be hidden. Show a fallback "no data ui" instead.
pub hide: bool,

/// The opacity of the welcome screen during fade-in.
pub opacity: f32,
}

impl AppState {
pub fn set_examples_manifest_url(&mut self, egui_ctx: &egui::Context, url: String) {
self.welcome_screen.set_examples_manifest_url(egui_ctx, url);
Expand Down Expand Up @@ -114,7 +122,7 @@ impl AppState {
space_view_class_registry: &SpaceViewClassRegistry,
rx: &ReceiveSet<LogMsg>,
command_sender: &CommandSender,
welcome_screen_opacity: f32,
welcome_screen_state: &WelcomeScreenState,
) {
re_tracing::profile_function!();

Expand Down Expand Up @@ -384,7 +392,7 @@ impl AppState {
ui.spacing_mut().item_spacing.y = 0.0;

let pre_cursor = ui.cursor();
recordings_panel_ui(&ctx, rx, ui);
recordings_panel_ui(&ctx, rx, ui, welcome_screen_state);
let any_recording_shows = pre_cursor == ui.cursor();

if any_recording_shows {
Expand All @@ -411,7 +419,7 @@ impl AppState {
.frame(viewport_frame)
.show_inside(ui, |ui| {
if show_welcome {
welcome_screen.ui(ui, re_ui, command_sender, welcome_screen_opacity);
welcome_screen.ui(ui, re_ui, command_sender, welcome_screen_state);
} else {
viewport.viewport_ui(ui, &ctx);
}
Expand Down
5 changes: 3 additions & 2 deletions crates/re_viewer/src/ui/mod.rs
@@ -1,5 +1,6 @@
mod blueprint_panel;
mod mobile_warning_ui;
mod no_data_ui;
mod override_ui;
mod recordings_panel;
mod rerun_menu;
Expand All @@ -17,6 +18,6 @@ pub use recordings_panel::recordings_panel_ui;
// ----

pub(crate) use {
self::mobile_warning_ui::mobile_warning_ui, self::top_panel::top_panel,
self::welcome_screen::WelcomeScreen,
self::mobile_warning_ui::mobile_warning_ui, self::no_data_ui::no_data_ui,
self::top_panel::top_panel, self::welcome_screen::WelcomeScreen,
};
20 changes: 20 additions & 0 deletions crates/re_viewer/src/ui/no_data_ui.rs
@@ -0,0 +1,20 @@
/// Show a minimal welcome section.
pub fn no_data_ui(ui: &mut egui::Ui) {
ui.vertical(|ui| {
let (style, line_height) = if ui.available_width() > 400.0 {
(re_ui::ReUi::welcome_screen_h1(), 50.0)
} else {
(re_ui::ReUi::welcome_screen_h2(), 36.0)
};

ui.add(
egui::Label::new(
egui::RichText::new("No Data Loaded")
.strong()
.line_height(Some(line_height))
.text_style(style),
)
.wrap(true),
);
});
}
18 changes: 15 additions & 3 deletions crates/re_viewer/src/ui/recordings_panel.rs
Expand Up @@ -9,9 +9,16 @@ use re_viewer_context::{
Item, StoreHub, SystemCommand, SystemCommandSender, UiVerbosity, ViewerContext,
};

use crate::app_state::WelcomeScreenState;

/// Show the currently open Recordings in a selectable list.
/// Also shows the currently loading receivers.
pub fn recordings_panel_ui(ctx: &ViewerContext<'_>, rx: &ReceiveSet<LogMsg>, ui: &mut egui::Ui) {
pub fn recordings_panel_ui(
ctx: &ViewerContext<'_>,
rx: &ReceiveSet<LogMsg>,
ui: &mut egui::Ui,
welcome_screen_state: &WelcomeScreenState,
) {
ctx.re_ui.panel_content(ui, |re_ui, ui| {
re_ui.panel_title_bar_with_buttons(
ui,
Expand All @@ -31,7 +38,7 @@ pub fn recordings_panel_ui(ctx: &ViewerContext<'_>, rx: &ReceiveSet<LogMsg>, ui:
.max_height(300.)
.show(ui, |ui| {
ctx.re_ui.panel_content(ui, |_re_ui, ui| {
recording_list_ui(ctx, ui);
recording_list_ui(ctx, ui, welcome_screen_state);

// Show currently loading things after.
// They will likely end up here as recordings soon.
Expand Down Expand Up @@ -91,7 +98,11 @@ fn loading_receivers_ui(ctx: &ViewerContext<'_>, rx: &ReceiveSet<LogMsg>, ui: &m
}

/// Draw the recording list.
fn recording_list_ui(ctx: &ViewerContext<'_>, ui: &mut egui::Ui) {
fn recording_list_ui(
ctx: &ViewerContext<'_>,
ui: &mut egui::Ui,
welcome_screen_state: &WelcomeScreenState,
) {
let mut entity_dbs_map: BTreeMap<ApplicationId, Vec<&EntityDb>> = BTreeMap::new();

// Always have a place for the welcome screen, even if there is no recordings or blueprints associated with it:
Expand All @@ -116,6 +127,7 @@ fn recording_list_ui(ctx: &ViewerContext<'_>, ui: &mut egui::Ui) {
if ctx
.app_options
.include_welcome_screen_button_in_recordings_panel
&& !welcome_screen_state.hide
{
debug_assert!(
entity_dbs.is_empty(),
Expand Down
20 changes: 14 additions & 6 deletions crates/re_viewer/src/ui/welcome_screen/mod.rs
Expand Up @@ -4,6 +4,10 @@ mod welcome_section;
use example_section::{ExampleSection, MIN_COLUMN_WIDTH};
use welcome_section::welcome_section_ui;

use crate::app_state::WelcomeScreenState;

use super::no_data_ui;

#[derive(Default)]
pub struct WelcomeScreen {
example_page: ExampleSection,
Expand All @@ -20,9 +24,9 @@ impl WelcomeScreen {
ui: &mut egui::Ui,
re_ui: &re_ui::ReUi,
command_sender: &re_viewer_context::CommandSender,
welcome_screen_opacity: f32,
welcome_screen_state: &WelcomeScreenState,
) {
if welcome_screen_opacity <= 0.0 {
if welcome_screen_state.opacity <= 0.0 {
return;
}

Expand All @@ -46,13 +50,17 @@ impl WelcomeScreen {
..Default::default()
}
.show(ui, |ui| {
self.example_page
.ui(ui, re_ui, command_sender, &welcome_section_ui);
if welcome_screen_state.hide {
no_data_ui(ui);
} else {
self.example_page
.ui(ui, re_ui, command_sender, &welcome_section_ui);
}
});
});

if welcome_screen_opacity < 1.0 {
let cover_opacity = 1.0 - welcome_screen_opacity;
if welcome_screen_state.opacity < 1.0 {
let cover_opacity = 1.0 - welcome_screen_state.opacity;
let fill_color = ui.visuals().panel_fill.gamma_multiply(cover_opacity);
ui.painter()
.rect_filled(response.inner_rect, 0.0, fill_color);
Expand Down
10 changes: 9 additions & 1 deletion crates/re_viewer/src/web.rs
Expand Up @@ -49,6 +49,7 @@ impl WebHandle {
url: Option<String>,
manifest_url: Option<String>,
force_wgpu_backend: Option<String>,
hide_welcome_screen: Option<bool>,
) -> Result<(), wasm_bindgen::JsValue> {
let web_options = eframe::WebOptions {
follow_system_theme: false,
Expand All @@ -63,7 +64,12 @@ impl WebHandle {
canvas_id,
web_options,
Box::new(move |cc| {
let app = create_app(cc, &url, &manifest_url);
let app = create_app(
cc,
&url,
&manifest_url,
hide_welcome_screen.unwrap_or(false),
);
Box::new(app)
}),
)
Expand Down Expand Up @@ -213,6 +219,7 @@ fn create_app(
cc: &eframe::CreationContext<'_>,
url: &Option<String>,
manifest_url: &Option<String>,
hide_welcome_screen: bool,
) -> crate::App {
let build_info = re_build_info::build_info!();
let app_env = crate::AppEnvironment::Web {
Expand All @@ -228,6 +235,7 @@ fn create_app(
is_in_notebook: is_in_notebook(&cc.integration_info),
expect_data_soon: None,
force_wgpu_backend: None,
hide_welcome_screen: hide_welcome_screen,
};
let re_ui = crate::customize_eframe_and_setup_renderer(cc);

Expand Down
5 changes: 5 additions & 0 deletions crates/rerun/src/run.rs
Expand Up @@ -191,6 +191,10 @@ If no arguments are given, a server will be hosted which a Rerun SDK can connect
#[clap(long, default_value_t = Default::default())]
web_viewer_port: WebViewerServerPort,

/// Hide the normal Rerun welcome screen.
#[clap(long)]
hide_welcome_screen: bool,

/// Set the screen resolution (in logical points), e.g. "1920x1080".
/// Useful together with `--screenshot-to`.
#[clap(long)]
Expand Down Expand Up @@ -606,6 +610,7 @@ fn run_impl(
let startup_options = {
re_tracing::profile_scope!("StartupOptions");
re_viewer::StartupOptions {
hide_welcome_screen: args.hide_welcome_screen,
memory_limit: re_memory::MemoryLimit::parse(&args.memory_limit)
.map_err(|err| anyhow::format_err!("Bad --memory-limit: {err}"))?,
persist_state: args.persist_state,
Expand Down
3 changes: 3 additions & 0 deletions crates/rerun_c/src/lib.rs
Expand Up @@ -85,6 +85,7 @@ pub const RR_COMPONENT_TYPE_HANDLE_INVALID: CComponentTypeHandle = 0xFFFFFFFF;
pub struct CSpawnOptions {
pub port: u16,
pub memory_limit: CStringView,
pub hide_welcome_screen: bool,
pub executable_name: CStringView,
pub executable_path: CStringView,
}
Expand All @@ -104,6 +105,8 @@ impl CSpawnOptions {
spawn_opts.memory_limit = self.memory_limit.as_str("memory_limit")?.to_owned();
}

spawn_opts.hide_welcome_screen = self.hide_welcome_screen;

if !self.executable_name.is_empty() {
spawn_opts.executable_name = self.executable_name.as_str("executable_name")?.to_owned();
}
Expand Down
3 changes: 3 additions & 0 deletions crates/rerun_c/src/rerun.h
Expand Up @@ -127,6 +127,9 @@ typedef struct rr_spawn_options {
/// Defaults to `75%` if null.
rr_string memory_limit;

/// Hide the normal Rerun welcome screen.
bool hide_welcome_screen;

/// Specifies the name of the Rerun executable.
///
/// You can omit the `.exe` suffix on Windows.
Expand Down
3 changes: 3 additions & 0 deletions rerun_cpp/src/rerun/c/rerun.h

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

1 change: 1 addition & 0 deletions rerun_cpp/src/rerun/spawn_options.cpp
Expand Up @@ -6,6 +6,7 @@ namespace rerun {
void SpawnOptions::fill_rerun_c_struct(rr_spawn_options& spawn_opts) const {
spawn_opts.port = port;
spawn_opts.memory_limit = detail::to_rr_string(memory_limit);
spawn_opts.hide_welcome_screen = hide_welcome_screen;
spawn_opts.executable_name = detail::to_rr_string(executable_name);
spawn_opts.executable_path = detail::to_rr_string(executable_path);
}
Expand Down
5 changes: 5 additions & 0 deletions rerun_cpp/src/rerun/spawn_options.hpp
Expand Up @@ -26,6 +26,11 @@ namespace rerun {
/// Defaults to `75%` if unset.
std::string_view memory_limit = "75%";

/// Hide the normal Rerun welcome screen.
///
/// Defaults to `false` if unset.
bool hide_welcome_screen = false;

/// Specifies the name of the Rerun executable.
///
/// You can omit the `.exe` suffix on Windows.
Expand Down
7 changes: 6 additions & 1 deletion rerun_js/web-viewer-react/index.js
Expand Up @@ -8,6 +8,7 @@ import * as rerun from "@rerun-io/web-viewer";
* and close any URLs which are not present.
* @property {string} [width] CSS width of the viewer's parent div
* @property {string} [height] CSS height of the viewer's parent div
* @property {boolean} [hide_welcome_screen] Whether to hide the welcome screen. Default is `false`.
*/

/**
Expand All @@ -27,17 +28,21 @@ export default class WebViewer extends React.Component {
/** @type {string[]} */
#recordings = [];

/** @type {boolean} */
#hide_welcome_screen = false;

/** @param {Props} props */
constructor(props) {
super(props);

this.#handle = new rerun.WebViewer();
this.#recordings = toArray(props.rrd);
this.#hide_welcome_screen = props.hide_welcome_screen ?? false;
}

componentDidMount() {
const current = /** @type {HTMLDivElement} */ (this.#parent.current);
this.#handle.start(this.#recordings, current);
this.#handle.start(this.#recordings, current, this.#hide_welcome_screen);
}

componentDidUpdate(/** @type {Props} */ prevProps) {
Expand Down

0 comments on commit 7c767ab

Please sign in to comment.