mirror of
https://github.com/storytold/filmcraft.git
synced 2026-10-24 10:10:05 -06:00
Merge pull request #2481 from Felix-Helleckes/fix/2253-reversible-ui-zoom
#2253: Ctrl+Plus no longer scales the interface one way only; View > Reset Interface Zoom
This commit is contained in:
@@ -3610,3 +3610,5 @@
|
||||
Shows the version, community links and credits in a FilmCraft window. Muestra la versión, los enlaces de la comunidad y los créditos en una ventana de FilmCraft.
|
||||
Couldn't open your web browser No se pudo abrir el navegador web
|
||||
Open this address in your browser yourself: Abre esta dirección tú mismo en el navegador:
|
||||
# View ▸ Reset Interface Zoom (#2253).
|
||||
Reset Interface Zoom Restablecer zoom de la interfaz
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 3 and column 95.
|
@@ -3577,3 +3577,5 @@
|
||||
Export the labels to a preset file… Exporter les étiquettes dans un fichier de paramètre prédéfini…
|
||||
Show the presets folder Afficher le dossier des paramètres prédéfinis
|
||||
Delete this preset Supprimer ce paramètre prédéfini
|
||||
# View ▸ Reset Interface Zoom (#2253).
|
||||
Reset Interface Zoom Réinitialiser le zoom de l'interface
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 5 and column 83.
|
@@ -3575,3 +3575,5 @@
|
||||
Appearance Settings… Pengaturan Tampilan…
|
||||
Add to favorites Tambahkan ke favorit
|
||||
Remove from favorites Hapus dari favorit
|
||||
# View ▸ Reset Interface Zoom (#2253).
|
||||
Reset Interface Zoom Atur Ulang Zoom Antarmuka
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 6 and column 14.
|
@@ -3601,3 +3601,5 @@
|
||||
Shows the version, community links and credits in a FilmCraft window. Mostra la versione, i link della community e i riconoscimenti in una finestra di FilmCraft.
|
||||
Couldn't open your web browser Impossibile aprire il browser web
|
||||
Open this address in your browser yourself: Apri tu questo indirizzo nel browser:
|
||||
# View ▸ Reset Interface Zoom (#2253).
|
||||
Reset Interface Zoom Reimposta zoom dell'interfaccia
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 3 and column 95.
|
@@ -3609,3 +3609,5 @@
|
||||
Shows the version, community links and credits in a FilmCraft window. バージョン、コミュニティへのリンク、クレジットを FilmCraft のウィンドウに表示します。
|
||||
Couldn't open your web browser ウェブブラウザーを開けませんでした
|
||||
Open this address in your browser yourself: このアドレスをご自身でブラウザーで開いてください:
|
||||
# View ▸ Reset Interface Zoom (#2253).
|
||||
Reset Interface Zoom インターフェイスのズームをリセット
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 11 and column 59.
|
@@ -3596,3 +3596,5 @@
|
||||
Shows the version, community links and credits in a FilmCraft window. FilmCraft 창에 버전, 커뮤니티 링크, 제작진을 보여 줍니다.
|
||||
Couldn't open your web browser 웹 브라우저를 열 수 없습니다
|
||||
Open this address in your browser yourself: 이 주소를 브라우저에서 직접 여세요:
|
||||
# View ▸ Reset Interface Zoom (#2253).
|
||||
Reset Interface Zoom 인터페이스 확대/축소 재설정
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 2814 and column 7.
|
@@ -3578,3 +3578,5 @@
|
||||
|
||||
# The native macOS application menu (Settings…).
|
||||
Settings Preferências
|
||||
# View ▸ Reset Interface Zoom (#2253).
|
||||
Reset Interface Zoom Redefinir zoom da interface
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 6 and column 4.
|
@@ -3585,3 +3585,5 @@
|
||||
Shows the version, community links and credits in a FilmCraft window. 在 FilmCraft 窗口中显示版本、社区链接和致谢。
|
||||
Couldn't open your web browser 无法打开网页浏览器
|
||||
Open this address in your browser yourself: 请自行在浏览器中打开此地址:
|
||||
# View ▸ Reset Interface Zoom (#2253).
|
||||
Reset Interface Zoom 重置界面缩放
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 3 and column 95.
|
@@ -685,6 +685,16 @@ impl FilmcraftApp {
|
||||
}
|
||||
}
|
||||
|
||||
/// View ▸ Reset Interface Zoom: the scale Settings ▸ Appearance ▸ UI Scale asks for (the
|
||||
/// system's with Auto), undoing any session zoom (#2253).
|
||||
/// Returns the zoom factor set (egui reports it from the next pass on).
|
||||
pub(crate) fn reset_ui_zoom(&mut self, ctx: &egui::Context) -> f32 {
|
||||
let native = ctx.native_pixels_per_point().filter(|v| v.is_finite() && *v > 0.0).unwrap_or(1.0);
|
||||
let zoom = self.session.prefs.appearance.ui_scale_factor().map_or(1.0, |scale| scale / native);
|
||||
ctx.set_zoom_factor(zoom);
|
||||
zoom
|
||||
}
|
||||
|
||||
/// Make the UI follow the settings after they change (theme, tooltips, frame cache budget,
|
||||
/// play after rendering, audio device).
|
||||
pub fn apply_prefs(&mut self, ctx: &egui::Context) {
|
||||
|
||||
@@ -53,6 +53,7 @@ pub const UI_COMMANDS: &[UiCommand] = &[
|
||||
uic!("view.zoomIn", "Zoom In", ["View"], Some("=")),
|
||||
uic!("view.zoomOut", "Zoom Out", ["View"], Some("-")),
|
||||
uic!("view.zoomToSequence", "Zoom to Sequence", ["View"], Some("\\")),
|
||||
uic!("view.resetInterfaceZoom", "Reset Interface Zoom", ["View"], None),
|
||||
uic!("view.playbackRes.full", "Full", ["View", "Playback Resolution"], None),
|
||||
uic!("view.playbackRes.half", "1/2", ["View", "Playback Resolution"], None),
|
||||
uic!("view.playbackRes.quarter", "1/4", ["View", "Playback Resolution"], None),
|
||||
@@ -417,6 +418,12 @@ pub fn invoke(app: &mut FilmcraftApp, ctx: &egui::Context, id: &str, mut params:
|
||||
app.ui.timeline.fit_pending = true;
|
||||
return Ok(Value::Null);
|
||||
}
|
||||
// the whole interface back to Settings ▸ Appearance ▸ UI Scale, after Ctrl+Plus or a mouse
|
||||
// mapped to page zoom scaled it (#2253)
|
||||
"view.resetInterfaceZoom" => {
|
||||
let zoom = app.reset_ui_zoom(ctx);
|
||||
return Ok(json!({"zoom": zoom}));
|
||||
}
|
||||
"mode.import" => {
|
||||
app.ui.mode = Mode::Import;
|
||||
return Ok(Value::Null);
|
||||
@@ -842,6 +849,16 @@ pub fn bindings(app: &FilmcraftApp) -> Vec<KeyBinding> {
|
||||
let shifted: Vec<KeyBinding> =
|
||||
v.iter().filter(|b| b.0.shift).filter_map(|(m, k, id, p)| shifted_key(*k).map(|k2| (*m, k2, id.clone(), p.clone()))).collect();
|
||||
v.extend(shifted);
|
||||
// `+` is the `=` key with Shift on US layouts and its own key on others and the keypad: a chord
|
||||
// on `=` takes it too, unless something is bound to `+` itself. Otherwise Ctrl+Plus fell
|
||||
// through to egui's interface zoom while Ctrl+- and Ctrl+0 were taken by FilmCraft
|
||||
// shortcuts, so the interface grew and could not shrink back (#2253).
|
||||
let plus: Vec<KeyBinding> = v
|
||||
.iter()
|
||||
.filter(|(m, k, _, p)| *k == egui::Key::Equals && !v.iter().any(|(m2, k2, _, p2)| *k2 == egui::Key::Plus && m2 == m && p2 == p))
|
||||
.map(|(m, _, id, p)| (*m, egui::Key::Plus, id.clone(), p.clone()))
|
||||
.collect();
|
||||
v.extend(plus);
|
||||
v.sort_by_key(|(m, ..)| std::cmp::Reverse(specificity(*m)));
|
||||
v
|
||||
}
|
||||
|
||||
@@ -0,0 +1,96 @@
|
||||
//! Headless UI tests of the interface zoom (#2253).
|
||||
|
||||
use std::sync::mpsc::{Sender, channel};
|
||||
|
||||
use egui_kittest::Harness;
|
||||
use filmcraft_engine::Session;
|
||||
use filmcraft_ui_egui::FilmcraftApp;
|
||||
use filmcraft_ui_egui::control::ControlRequest;
|
||||
use serde_json::{Value, json};
|
||||
|
||||
struct Driver {
|
||||
harness: Harness<'static, FilmcraftApp>,
|
||||
tx: Sender<ControlRequest>,
|
||||
}
|
||||
|
||||
impl Driver {
|
||||
fn demo() -> Self {
|
||||
let mut session = Session::default();
|
||||
session.execute("file.openDemoProject", json!({})).expect("demo project");
|
||||
let (tx, rx) = channel();
|
||||
let app = FilmcraftApp::new(session).with_control(rx);
|
||||
let harness = Harness::builder().with_size(egui::vec2(1600.0, 980.0)).with_step_dt(1.0 / 60.0).with_max_steps(10_000).build_eframe(move |_cc| app);
|
||||
let mut d = Driver { harness, tx };
|
||||
d.frames(4);
|
||||
d
|
||||
}
|
||||
|
||||
fn frames(&mut self, n: usize) {
|
||||
for _ in 0..n {
|
||||
let ctx = self.harness.ctx.clone();
|
||||
let mut raw = std::mem::take(self.harness.input_mut());
|
||||
eframe::App::raw_input_hook(self.harness.state_mut(), &ctx, &mut raw);
|
||||
*self.harness.input_mut() = raw;
|
||||
self.harness.step();
|
||||
}
|
||||
}
|
||||
|
||||
fn ok(&mut self, method: &str, params: Value) -> Value {
|
||||
let (req, reply) = ControlRequest::new(method, params.clone());
|
||||
self.tx.send(req).unwrap();
|
||||
for _ in 0..600 {
|
||||
self.frames(1);
|
||||
if let Ok(v) = reply.try_recv() {
|
||||
assert_eq!(v["ok"], json!(true), "{method} {params} failed: {v}");
|
||||
return v["result"].clone();
|
||||
}
|
||||
}
|
||||
panic!("no reply to {method} {params}");
|
||||
}
|
||||
|
||||
fn click(&mut self, id: &str) {
|
||||
self.ok("ui.click", json!({"id": id}));
|
||||
self.frames(2);
|
||||
}
|
||||
|
||||
fn app(&mut self) -> &mut FilmcraftApp {
|
||||
self.harness.state_mut()
|
||||
}
|
||||
|
||||
/// One key press with `modifiers`, as the window reports it.
|
||||
fn press(&mut self, key: egui::Key, modifiers: egui::Modifiers) {
|
||||
let events = &mut self.harness.input_mut().events;
|
||||
events.push(egui::Event::ModifiersChanged(modifiers));
|
||||
for pressed in [true, false] {
|
||||
events.push(egui::Event::Key { key, physical_key: None, pressed, repeat: false, modifiers });
|
||||
}
|
||||
events.push(egui::Event::ModifiersChanged(egui::Modifiers::NONE));
|
||||
self.frames(3);
|
||||
}
|
||||
}
|
||||
|
||||
/// #2253: with the Timeline focused, Ctrl+= and Ctrl+- are its track-height keys, but Ctrl+Plus
|
||||
/// (the `+` key, or Shift+=) fell through to egui and scaled the whole interface, which the taken
|
||||
/// Ctrl+- and Ctrl+0 could not undo. `+` now goes where `=` goes, and View ▸ Reset Interface Zoom
|
||||
/// gives the configured scale back.
|
||||
#[test]
|
||||
fn ctrl_plus_does_what_ctrl_equals_does_and_the_interface_zoom_can_be_reset() {
|
||||
let mut d = Driver::demo();
|
||||
let clip = d.app().session.active_sequence().unwrap().video_tracks[0].items[0].id.0;
|
||||
d.click(&format!("timeline.clip.{clip}"));
|
||||
assert_eq!(d.app().ui.focused, filmcraft_ui_egui::dock::PanelKind::Timeline);
|
||||
let zoom = d.harness.ctx.zoom_factor();
|
||||
let height = d.app().ui.timeline.video_track_h;
|
||||
d.press(egui::Key::Plus, egui::Modifiers::COMMAND);
|
||||
assert_eq!(d.harness.ctx.zoom_factor(), zoom, "the interface keeps its scale");
|
||||
assert!(d.app().ui.timeline.video_track_h > height, "Ctrl+Plus makes the video tracks taller, as Ctrl+= does");
|
||||
|
||||
// however it got scaled, View ▸ Reset Interface Zoom brings it back
|
||||
d.harness.ctx.set_zoom_factor(1.75);
|
||||
d.frames(2);
|
||||
assert_eq!(d.harness.ctx.zoom_factor(), 1.75);
|
||||
let r = d.ok("ui.menu.invoke", json!({"id": "view.resetInterfaceZoom"}));
|
||||
assert_eq!(r["zoom"], json!(1.0), "the reply says the zoom it set: {r}");
|
||||
d.frames(2);
|
||||
assert_eq!(d.harness.ctx.zoom_factor(), 1.0);
|
||||
}
|
||||
Reference in New Issue
Block a user