Files
paseo/packages/desktop/src-tauri/src/lib.rs
T

140 lines
5.6 KiB
Rust

use std::sync::atomic::{AtomicU64, Ordering};
use tauri::menu::{Menu, MenuItemBuilder, MenuItemKind, PredefinedMenuItem, Submenu};
#[cfg(target_os = "macos")]
use tauri::menu::AboutMetadata;
use tauri::Manager;
use tauri::WebviewWindow;
// Store zoom as u64 bits (f64 * 100 as integer for atomic ops)
static ZOOM_LEVEL: AtomicU64 = AtomicU64::new(100);
fn get_zoom_factor() -> f64 {
ZOOM_LEVEL.load(Ordering::Relaxed) as f64 / 100.0
}
fn set_zoom_factor(webview: &WebviewWindow, factor: f64) {
let clamped = factor.clamp(0.5, 3.0);
ZOOM_LEVEL.store((clamped * 100.0) as u64, Ordering::Relaxed);
let _ = webview.set_zoom(clamped);
}
#[cfg_attr(mobile, tauri::mobile_entry_point)]
pub fn run() {
tauri::Builder::default()
.plugin(tauri_plugin_dialog::init())
.plugin(tauri_plugin_notification::init())
.plugin(tauri_plugin_opener::init())
.plugin(tauri_plugin_websocket::init())
.setup(|app| {
if cfg!(debug_assertions) {
app.handle().plugin(
tauri_plugin_log::Builder::default()
.level(log::LevelFilter::Info)
.build(),
)?;
}
// Start from Tauri's default menu so macOS standard shortcuts (Cmd+A/C/V/etc)
// keep working. Then inject our zoom controls into a View menu.
//
// On macOS in particular, a custom menu that omits Edit items can break
// responder-chain shortcuts across the whole app.
let menu = Menu::default(app.handle())?;
#[cfg(target_os = "macos")]
{
let app_menu = menu.items()?.into_iter().find_map(|item| match item {
MenuItemKind::Submenu(submenu) => Some(submenu),
_ => None,
});
if let Some(submenu) = app_menu {
// Tauri's default about item sets only `version`, which macOS renders as
// "Version <plist short> (<version>)". Set only `short_version` instead.
let about_metadata = AboutMetadata {
name: Some(app.package_info().name.clone()),
short_version: Some(app.package_info().version.to_string()),
copyright: app.config().bundle.copyright.clone(),
..Default::default()
};
let about = PredefinedMenuItem::about(app.handle(), None, Some(about_metadata))?;
if submenu.remove_at(0)?.is_some() {
submenu.insert(&about, 0)?;
}
}
}
let zoom_in = MenuItemBuilder::with_id("zoom_in", "Zoom In")
.accelerator("CmdOrCtrl+=")
.build(app)?;
let zoom_out = MenuItemBuilder::with_id("zoom_out", "Zoom Out")
.accelerator("CmdOrCtrl+-")
.build(app)?;
let zoom_reset = MenuItemBuilder::with_id("zoom_reset", "Actual Size")
.accelerator("CmdOrCtrl+0")
.build(app)?;
let separator = PredefinedMenuItem::separator(app.handle())?;
// On macOS, Tauri's default menu already has a "View" submenu (with Fullscreen).
// Insert our zoom items at the top so we don't duplicate the submenu.
#[cfg(target_os = "macos")]
{
let mut view_submenu: Option<Submenu<_>> = None;
for item in menu.items()? {
if let MenuItemKind::Submenu(submenu) = item {
if submenu.text()? == "View" {
view_submenu = Some(submenu);
break;
}
}
}
if let Some(view) = view_submenu {
// Zoom controls first, then keep existing items (e.g. Fullscreen).
view.insert_items(&[&zoom_in, &zoom_out, &zoom_reset, &separator], 0)?;
} else {
// Fallback: if the default menu ever changes, create a View menu.
let view_menu = Submenu::with_items(
app,
"View",
true,
&[&zoom_in, &zoom_out, &zoom_reset, &separator],
)?;
menu.append(&view_menu)?;
}
}
// Non-macOS: default menu doesn't include a View menu, so add it.
#[cfg(not(target_os = "macos"))]
{
let view_menu =
Submenu::with_items(app, "View", true, &[&zoom_in, &zoom_out, &zoom_reset])?;
menu.append(&view_menu)?;
}
app.set_menu(menu)?;
let window = app.get_webview_window("main").unwrap();
let window_clone = window.clone();
app.on_menu_event(move |_app, event| {
let id = event.id().as_ref();
if id == "zoom_in" {
let current = get_zoom_factor();
set_zoom_factor(&window_clone, current + 0.1);
} else if id == "zoom_out" {
let current = get_zoom_factor();
set_zoom_factor(&window_clone, current - 0.1);
} else if id == "zoom_reset" {
set_zoom_factor(&window_clone, 1.0);
}
});
Ok(())
})
.run(tauri::generate_context!())
.expect("error while running tauri application");
}