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

Add fullscreen mode to web viewer #6461

Merged
merged 23 commits into from
May 31, 2024
Merged
Show file tree
Hide file tree
Changes from 20 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ impl PanelState {
self == &Self::Expanded
}

/// Returns `true` if self is [`PanelState::Expanded`]
/// Returns `true` if self is [`PanelState::Hidden`]
#[inline]
pub fn is_hidden(&self) -> bool {
self == &Self::Hidden
Expand Down
12 changes: 11 additions & 1 deletion crates/re_ui/src/command.rs
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,6 @@ pub enum UICommand {
#[cfg(debug_assertions)]
ToggleEguiDebugPanel,

#[cfg(not(target_arch = "wasm32"))]
ToggleFullscreen,
#[cfg(not(target_arch = "wasm32"))]
ZoomIn,
Expand Down Expand Up @@ -171,6 +170,12 @@ impl UICommand {
"Toggle between windowed and fullscreen viewer",
),

#[cfg(target_arch = "wasm32")]
Self::ToggleFullscreen => (
"Toggle fullscreen",
"Toggle between full viewport dimensions and initial dimensions"
),

#[cfg(not(target_arch = "wasm32"))]
Self::ZoomIn => ("Zoom in", "Increases the UI zoom level"),
#[cfg(not(target_arch = "wasm32"))]
Expand Down Expand Up @@ -300,6 +305,8 @@ impl UICommand {

#[cfg(not(target_arch = "wasm32"))]
Self::ToggleFullscreen => Some(key(Key::F11)),
#[cfg(target_arch = "wasm32")]
Self::ToggleFullscreen => None,

#[cfg(not(target_arch = "wasm32"))]
Self::ZoomIn => Some(egui::gui_zoom::kb_shortcuts::ZOOM_IN),
Expand Down Expand Up @@ -336,6 +343,9 @@ impl UICommand {
Self::RestartWithWebGl => None,
#[cfg(target_arch = "wasm32")]
Self::RestartWithWebGpu => None,

#[cfg(target_arch = "wasm32 ")]
Self::ViewportMode(_) => None,
}
}

Expand Down
65 changes: 62 additions & 3 deletions crates/re_viewer/src/app.rs
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,14 @@ pub struct StartupOptions {
/// Forces wgpu backend to use the specified graphics API.
pub force_wgpu_backend: Option<String>,

/// Fullscreen is handled by JS on web.
///
/// This holds some callbacks which we use to communicate
/// about fullscreen state to JS.
#[cfg(target_arch = "wasm32")]
pub fullscreen_options: Option<crate::web::FullscreenOptions>,

/// Default overrides for state of top/side/bottom panels.
pub panel_state_overrides: PanelStateOverrides,
}

Expand All @@ -95,6 +103,9 @@ impl Default for StartupOptions {
expect_data_soon: None,
force_wgpu_backend: None,

#[cfg(target_arch = "wasm32")]
fullscreen_options: Default::default(),

panel_state_overrides: Default::default(),
}
}
Expand Down Expand Up @@ -638,10 +649,8 @@ impl App {
self.egui_debug_panel_open ^= true;
}

#[cfg(not(target_arch = "wasm32"))]
UICommand::ToggleFullscreen => {
let fullscreen = egui_ctx.input(|i| i.viewport().fullscreen.unwrap_or(false));
egui_ctx.send_viewport_cmd(egui::ViewportCommand::Fullscreen(!fullscreen));
self.toggle_fullscreen();
}

#[cfg(not(target_arch = "wasm32"))]
Expand Down Expand Up @@ -1325,6 +1334,56 @@ impl App {
1.0
}
}

#[allow(dead_code)] // only used in web
jprochazk marked this conversation as resolved.
Show resolved Hide resolved
pub(crate) fn toggle_fullscreen(&self) {
#[cfg(not(target_arch = "wasm32"))]
{
let egui_ctx = &self.re_ui.egui_ctx;
let fullscreen = egui_ctx.input(|i| i.viewport().fullscreen.unwrap_or(false));
egui_ctx.send_viewport_cmd(egui::ViewportCommand::Fullscreen(!fullscreen));
}

#[cfg(target_arch = "wasm32")]
{
if let Some(options) = &self.startup_options.fullscreen_options {
// Tell JS to toggle fullscreen.
options.on_toggle.call().unwrap();
jprochazk marked this conversation as resolved.
Show resolved Hide resolved
}
}
}

#[allow(dead_code, clippy::unused_self)] // only used on web
pub(crate) fn is_fullscreen_allowed(&self) -> bool {
#[cfg(not(target_arch = "wasm32"))]
{
true
}

#[cfg(target_arch = "wasm32")]
{
self.startup_options.fullscreen_options.is_some()
}
}

#[allow(dead_code)] // only used on web
pub(crate) fn is_fullscreen_mode(&self) -> bool {
#[cfg(not(target_arch = "wasm32"))]
{
let egui_ctx = &self.re_ui.egui_ctx;
return egui_ctx.input(|i| i.viewport().fullscreen.unwrap_or(false));
}

#[cfg(target_arch = "wasm32")]
{
if let Some(options) = &self.startup_options.fullscreen_options {
// Ask JS if fullscreen is on or not.
return options.get_state.call().unwrap().is_truthy();
jprochazk marked this conversation as resolved.
Show resolved Hide resolved
}

false
}
}
}

#[cfg(target_arch = "wasm32")]
Expand Down
19 changes: 19 additions & 0 deletions crates/re_viewer/src/ui/top_panel.rs
Original file line number Diff line number Diff line change
Expand Up @@ -241,6 +241,25 @@ fn connection_status_ui(ui: &mut egui::Ui, rx: &ReceiveSet<re_log_types::LogMsg>

/// Lay out the panel button right-to-left
fn panel_buttons_r2l(app: &App, app_blueprint: &AppBlueprint<'_>, ui: &mut egui::Ui) {
#[cfg(target_arch = "wasm32")]
if app.is_fullscreen_allowed() {
let mut is_fullscreen = app.is_fullscreen_mode();
let icon = if is_fullscreen {
&re_ui::icons::MINIMIZE
} else {
&re_ui::icons::MAXIMIZE
};

if app
.re_ui()
.medium_icon_toggle_button(ui, icon, &mut is_fullscreen)
.on_hover_text("Toggle fullscreen")
.clicked()
{
app.toggle_fullscreen();
}
}

// selection panel
if app
.re_ui()
Expand Down
20 changes: 19 additions & 1 deletion crates/re_viewer/src/web.rs
Original file line number Diff line number Diff line change
Expand Up @@ -296,6 +296,17 @@ pub struct AppOptions {
render_backend: Option<String>,
hide_welcome_screen: Option<bool>,
panel_state_overrides: Option<PanelStateOverrides>,
fullscreen: Option<FullscreenOptions>,
}

// Keep in sync with the `FullscreenOptions` typedef in `rerun_js/web-viewer/index.js`
#[derive(Clone, Deserialize)]
pub struct FullscreenOptions {
/// This returns the current fullscreen state, which is a boolean representing on/off.
pub get_state: Callback,

/// This calls the JS version of "toggle fullscreen".
pub on_toggle: Callback,
}

#[derive(Clone, Default, Deserialize)]
Expand All @@ -320,7 +331,13 @@ impl From<PanelStateOverrides> for crate::app_blueprint::PanelStateOverrides {
// Can't deserialize `Option<js_sys::Function>` directly, so newtype it is.
#[derive(Clone, Deserialize)]
#[repr(transparent)]
struct Callback(#[serde(with = "serde_wasm_bindgen::preserve")] js_sys::Function);
pub struct Callback(#[serde(with = "serde_wasm_bindgen::preserve")] js_sys::Function);

impl Callback {
pub fn call(&self) -> Result<JsValue, JsValue> {
self.0.call0(&web_sys::window().unwrap())
}
}

fn create_app(
cc: &eframe::CreationContext<'_>,
Expand All @@ -341,6 +358,7 @@ fn create_app(
expect_data_soon: None,
force_wgpu_backend: None,
hide_welcome_screen: app_options.hide_welcome_screen.unwrap_or(false),
fullscreen_options: app_options.fullscreen.clone(),
panel_state_overrides: app_options.panel_state_overrides.unwrap_or_default().into(),
};
let re_ui = crate::customize_eframe_and_setup_renderer(cc)?;
Expand Down
Loading
Loading