From 3c3894f19b0239446bdcdae3bbdbac0c7a97cf4a Mon Sep 17 00:00:00 2001 From: Kamil Jarosz Date: Mon, 8 Jul 2024 13:17:09 +0200 Subject: [PATCH] desktop: Add View menu --- core/src/avm1/globals/stage.rs | 2 +- core/src/avm2/globals/flash/display/stage.rs | 2 +- core/src/display_object/stage.rs | 15 ++- core/src/player.rs | 26 ++++- desktop/assets/texts/en-US/main_menu.ftl | 2 + desktop/assets/texts/en-US/settings.ftl | 8 +- desktop/src/gui/menu_bar.rs | 108 ++++++++++++++++++- 7 files changed, 151 insertions(+), 12 deletions(-) diff --git a/core/src/avm1/globals/stage.rs b/core/src/avm1/globals/stage.rs index 1e290a9e2a7e3..7ad7b682198a6 100644 --- a/core/src/avm1/globals/stage.rs +++ b/core/src/avm1/globals/stage.rs @@ -113,7 +113,7 @@ fn set_scale_mode<'gc>( activation .context .stage - .set_scale_mode(&mut activation.context, scale_mode); + .set_scale_mode(&mut activation.context, scale_mode, true); Ok(Value::Undefined) } diff --git a/core/src/avm2/globals/flash/display/stage.rs b/core/src/avm2/globals/flash/display/stage.rs index 20bb59f19cf7f..ef24099f348d7 100644 --- a/core/src/avm2/globals/flash/display/stage.rs +++ b/core/src/avm2/globals/flash/display/stage.rs @@ -279,7 +279,7 @@ pub fn set_scale_mode<'gc>( activation .context .stage - .set_scale_mode(&mut activation.context, scale_mode); + .set_scale_mode(&mut activation.context, scale_mode, true); } else { return Err(make_error_2008(activation, "scaleMode")); } diff --git a/core/src/display_object/stage.rs b/core/src/display_object/stage.rs index 82beb9b2fc6f7..555a9cef3f247 100644 --- a/core/src/display_object/stage.rs +++ b/core/src/display_object/stage.rs @@ -314,11 +314,18 @@ impl<'gc> Stage<'gc> { } /// Set the stage scale mode. - pub fn set_scale_mode(self, context: &mut UpdateContext<'_, 'gc>, scale_mode: StageScaleMode) { - if !self.forced_scale_mode() { - self.0.write(context.gc_context).scale_mode = scale_mode; - self.build_matrices(context); + pub fn set_scale_mode( + self, + context: &mut UpdateContext<'_, 'gc>, + scale_mode: StageScaleMode, + respect_forced: bool, + ) { + if respect_forced && self.forced_scale_mode() { + return; } + + self.0.write(context.gc_context).scale_mode = scale_mode; + self.build_matrices(context); } /// Get whether movies are prevented from changing the stage scale mode. diff --git a/core/src/player.rs b/core/src/player.rs index e44814623390d..16e722b9b04ee 100644 --- a/core/src/player.rs +++ b/core/src/player.rs @@ -853,6 +853,10 @@ impl Player { }) } + pub fn quality(&mut self) -> StageQuality { + self.mutate_with_update_context(|context| context.stage.quality()) + } + pub fn set_quality(&mut self, quality: StageQuality) { self.mutate_with_update_context(|context| { context.stage.set_quality(context, quality); @@ -868,6 +872,26 @@ impl Player { }) } + pub fn scale_mode(&mut self) -> StageScaleMode { + self.mutate_with_update_context(|context| context.stage.scale_mode()) + } + + pub fn set_scale_mode(&mut self, scale_mode: StageScaleMode) { + self.mutate_with_update_context(|context| { + context.stage.set_scale_mode(context, scale_mode, false); + }) + } + + pub fn forced_scale_mode(&mut self) -> bool { + self.mutate_with_update_context(|context| context.stage.forced_scale_mode()) + } + + pub fn set_forced_scale_mode(&mut self, force: bool) { + self.mutate_with_update_context(|context| { + context.stage.set_forced_scale_mode(context, force); + }) + } + /// Handle an event sent into the player from the external windowing system /// or an HTML element. pub fn handle_event(&mut self, event: PlayerEvent) -> bool { @@ -2832,7 +2856,7 @@ impl PlayerBuilder { let stage = context.stage; stage.set_align(context, self.align); stage.set_forced_align(context, self.forced_align); - stage.set_scale_mode(context, self.scale_mode); + stage.set_scale_mode(context, self.scale_mode, false); stage.set_forced_scale_mode(context, self.forced_scale_mode); stage.set_allow_fullscreen(context, self.allow_fullscreen); stage.post_instantiation(context, None, Instantiator::Movie, false); diff --git a/desktop/assets/texts/en-US/main_menu.ftl b/desktop/assets/texts/en-US/main_menu.ftl index 3dc955f580b74..ae2504ef83aa6 100644 --- a/desktop/assets/texts/en-US/main_menu.ftl +++ b/desktop/assets/texts/en-US/main_menu.ftl @@ -40,3 +40,5 @@ debug-menu-open-movie-list = Show Known Movies debug-menu-open-domain-list = Show Domains debug-menu-search-display-objects = Search Display Objects... +view-menu = View +view-menu-fullscreen = Full Screen diff --git a/desktop/assets/texts/en-US/settings.ftl b/desktop/assets/texts/en-US/settings.ftl index 1ad36f41facc3..14b4f7af625b4 100644 --- a/desktop/assets/texts/en-US/settings.ftl +++ b/desktop/assets/texts/en-US/settings.ftl @@ -58,10 +58,10 @@ align-bottom-right = Bottom-Right align-force = Force scale-mode = Scale Mode -scale-mode-exactfit = Exact Fit -scale-mode-noborder = No Border -scale-mode-noscale = No Scale -scale-mode-showall = Show All +scale-mode-exactfit = Stretch to Fit +scale-mode-noborder = Crop to Fit +scale-mode-noscale = 100% (Unscaled) +scale-mode-showall = Zoom to Fit scale-mode-force = Force player-version = Player Version diff --git a/desktop/src/gui/menu_bar.rs b/desktop/src/gui/menu_bar.rs index 70a2d654b2daa..eefb593f9dd1b 100644 --- a/desktop/src/gui/menu_bar.rs +++ b/desktop/src/gui/menu_bar.rs @@ -4,8 +4,10 @@ use crate::gui::{text, DebugMessage}; use crate::player::LaunchOptions; use crate::preferences::GlobalPreferences; use egui::{menu, Button, Key, KeyboardShortcut, Modifiers, Widget}; -use ruffle_core::Player; +use ruffle_core::config::Letterbox; +use ruffle_core::{Player, StageScaleMode}; use ruffle_frontend_utils::recents::Recent; +use ruffle_render::quality::StageQuality; use unic_langid::LanguageIdentifier; use url::Url; use winit::event_loop::EventLoopProxy; @@ -68,6 +70,7 @@ impl MenuBar { menu::bar(ui, |ui| { self.file_menu(locale, ui, dialogs, player.is_some()); + self.view_menu(locale, ui, &mut player); menu::menu_button(ui, text(locale, "controls-menu"), |ui| { ui.add_enabled_ui(player.is_some(), |ui| { @@ -275,6 +278,109 @@ impl MenuBar { }); } + fn view_menu( + &mut self, + locale: &LanguageIdentifier, + ui: &mut egui::Ui, + player: &mut Option<&mut Player>, + ) { + menu::menu_button(ui, text(locale, "view-menu"), |ui| { + ui.add_enabled_ui(player.is_some(), |ui| { + ui.menu_button(text(locale, "scale-mode"), |ui| { + let items = vec![ + ("scale-mode-noscale", StageScaleMode::NoScale), + ("scale-mode-showall", StageScaleMode::ShowAll), + ("scale-mode-exactfit", StageScaleMode::ExactFit), + ("scale-mode-noborder", StageScaleMode::NoBorder), + ]; + let current_scale_mode = player.as_mut().map(|player| player.scale_mode()); + for (id, scale_mode) in items { + let clicked = if Some(scale_mode) == current_scale_mode { + ui.checkbox(&mut true, text(locale, id)).clicked() + } else { + ui.button(text(locale, id)).clicked() + }; + if clicked { + ui.close_menu(); + if let Some(player) = player { + player.set_scale_mode(scale_mode); + } + } + } + ui.separator(); + + let original_forced_scale_mode = player + .as_mut() + .map(|player| player.forced_scale_mode()) + .unwrap_or_default(); + let mut forced_scale_mode = original_forced_scale_mode; + ui.checkbox( + &mut forced_scale_mode, + text(locale, "scale-mode-force"), + ); + if forced_scale_mode != original_forced_scale_mode { + if let Some(player) = player { + player.set_forced_scale_mode(forced_scale_mode); + } + } + }); + + let original_letterbox = if let Some(player) = player { + player.letterbox() == Letterbox::On + } else { + false + }; + let mut letterbox = original_letterbox; + ui.checkbox(&mut letterbox, text(locale, "letterbox")); + if letterbox != original_letterbox { + if let Some(player) = player { + player.set_letterbox(if letterbox { + Letterbox::On + } else { + Letterbox::Off + }); + } + } + ui.separator(); + + if ui.button(text(locale, "view-menu-fullscreen")).clicked() { + ui.close_menu(); + if let Some(player) = player { + player.set_fullscreen(true); + } + } + ui.separator(); + + ui.menu_button(text(locale, "quality"), |ui| { + let items = vec![ + ("quality-low", StageQuality::Low), + ("quality-medium", StageQuality::Medium), + ("quality-high", StageQuality::High), + ("quality-best", StageQuality::Best), + ("quality-high8x8", StageQuality::High8x8), + ("quality-high8x8linear", StageQuality::High8x8Linear), + ("quality-high16x16", StageQuality::High16x16), + ("quality-high16x16linear", StageQuality::High16x16Linear), + ]; + let current_quality = player.as_mut().map(|player| player.quality()); + for (id, quality) in items { + let clicked = if Some(quality) == current_quality { + ui.checkbox(&mut true, text(locale, id)).clicked() + } else { + ui.button(text(locale, id)).clicked() + }; + if clicked { + ui.close_menu(); + if let Some(player) = player { + player.set_quality(quality); + } + } + } + }); + }); + }); + } + fn open_file(&mut self, ui: &mut egui::Ui) { ui.close_menu();