diff --git a/Cargo.toml b/Cargo.toml index 5b03934fb..0f31803b2 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -119,12 +119,10 @@ understory_event_state = { git = "https://github.com/jrmoulton/understory", rev understory_index = { git = "https://github.com/jrmoulton/understory", rev = "2c2abb8c4bd9", package = "understory_index" } understory_focus = { git = "https://github.com/jrmoulton/understory", rev = "2c2abb8c4bd9", package = "understory_focus" } understory_virtual_list = { git = "https://github.com/jrmoulton/understory", rev = "2c2abb8c4bd9", package = "understory_virtual_list" } - -[target.'cfg(any(target_os = "windows", target_os = "macos"))'.dependencies] -muda = { workspace = true } +muda = { workspace = true, optional = true } [target.'cfg(any(target_os = "linux"))'.dependencies] -muda = { workspace = true, default-features = false, features = ["gtk"] } +muda = { workspace = true, default-features = false, features = ["gtk"], optional = true } [target.'cfg(target_arch = "wasm32")'.dependencies] wasm-bindgen-futures = { version = "0.4" } @@ -145,7 +143,7 @@ objc2-app-kit = { version = "0.3", features = [ dispatch2 = {version = "0.3.0"} [features] -default = ["editor", "default-image-formats", "vger", "serde"] +default = ["editor", "default-image-formats", "vger", "serde", "menus"] skia = ["dep:floem_skia_renderer"] vello = ["dep:floem_vello_renderer"] vger = ["dep:floem_vger_renderer"] @@ -182,6 +180,7 @@ image-qoi = ["image/qoi"] image-tga = ["image/tga"] image-tiff = ["image/tiff"] image-webp = ["image/webp"] +menus = ["dep:muda"] tokio = ["dep:tokio"] # rfd (file dialog) async runtime crossbeam = ["dep:crossbeam", "floem_renderer/crossbeam"] diff --git a/src/action.rs b/src/action.rs index 920bb2bf8..72f1070d7 100644 --- a/src/action.rs +++ b/src/action.rs @@ -13,13 +13,14 @@ use peniko::kurbo::{Point, Size, Vec2}; use winit::window::WindowId; use winit::window::{ResizeDirection, Theme}; -use crate::IntoView; use crate::platform::{Duration, Instant}; +use crate::IntoView; +#[cfg(feature = "menus")] +use crate::platform::menu::Menu; use crate::{ - app::{AppUpdateEvent, add_app_update_event}, - message::{UPDATE_MESSAGES, UpdateMessage}, - platform::menu::Menu, + app::{add_app_update_event, AppUpdateEvent}, + message::{UpdateMessage, UPDATE_MESSAGES}, view::View, view::ViewId, views::Decorators, @@ -260,6 +261,7 @@ where /// - Windows: Yes /// - macOS: Yes /// - Linux: Uses a custom Floem View +#[cfg(feature = "menus")] pub fn show_context_menu(menu: Menu, pos: Option) { add_update_message(UpdateMessage::ShowContextMenu { menu, pos }); } @@ -271,7 +273,7 @@ pub fn show_context_menu(menu: Menu, pos: Option) { /// - macOS: Yes /// - Linux: No /// - wasm32: No -#[cfg(not(target_arch = "wasm32"))] +#[cfg(all(feature = "menus", not(target_arch = "wasm32")))] pub fn set_window_menu(menu: Menu) { add_update_message(UpdateMessage::WindowMenu { menu }); } diff --git a/src/app/handle.rs b/src/app/handle.rs index 04e78bdcc..609f07f01 100644 --- a/src/app/handle.rs +++ b/src/app/handle.rs @@ -36,6 +36,7 @@ use crate::{ window::{WindowConfig, handle::WindowHandle, id::process_window_updates}, }; +#[cfg(feature = "menus")] struct PendingContextMenu { window_id: WindowId, menu: super::MenuWrapper, @@ -46,6 +47,7 @@ pub(crate) struct ApplicationHandle { window_handles: HashMap, timers: HashMap, animating_windows: std::collections::HashSet, + #[cfg(feature = "menus")] pending_context_menus: Vec, pub(crate) event_listener: Option>, pub(crate) gpu_resources: Option, @@ -60,6 +62,7 @@ impl ApplicationHandle { window_handles: HashMap::new(), timers: HashMap::new(), animating_windows: std::collections::HashSet::new(), + #[cfg(feature = "menus")] pending_context_menus: Vec::new(), event_listener: None, gpu_resources: None, @@ -114,6 +117,7 @@ impl ApplicationHandle { panic!("Sent a gpu resource update after it had already been initialized"); } } + #[cfg(feature = "menus")] UserEvent::ShowContextMenu { window_id, menu, @@ -197,7 +201,7 @@ impl ApplicationHandle { } } } - #[cfg(not(target_arch = "wasm32"))] + #[cfg(all(feature = "menus", not(target_arch = "wasm32")))] AppUpdateEvent::MenuAction { action_id } => { for (_, handle) in self.window_handles.iter_mut() { if handle.window_state.context_menu.contains_key(&action_id) @@ -208,7 +212,7 @@ impl ApplicationHandle { } } } - #[cfg(target_arch = "wasm32")] + #[cfg(all(feature = "menus", target_arch = "wasm32"))] AppUpdateEvent::MenuAction { action_id } => { for (_, handle) in self.window_handles.iter_mut() { if handle.window_state.context_menu.contains_key(&action_id) { @@ -824,10 +828,13 @@ impl ApplicationHandle { } pub(crate) fn flush_deferred_context_menus(&mut self) { - let pending = std::mem::take(&mut self.pending_context_menus); - for item in pending { - if let Some(handle) = self.window_handles.get_mut(&item.window_id) { - handle.show_context_menu(item.menu.0, item.pos); + #[cfg(feature = "menus")] + { + let pending = std::mem::take(&mut self.pending_context_menus); + for item in pending { + if let Some(handle) = self.window_handles.get_mut(&item.window_id) { + handle.show_context_menu(item.menu.0, item.pos); + } } } } diff --git a/src/app/mod.rs b/src/app/mod.rs index f21c58df8..bec417874 100644 --- a/src/app/mod.rs +++ b/src/app/mod.rs @@ -8,9 +8,11 @@ use std::{ sync::atomic::{AtomicBool, Ordering}, }; +#[cfg(feature = "menus")] use crate::platform::menu_types::MenuId; #[cfg(feature = "crossbeam")] use crossbeam::channel::{Receiver, Sender, unbounded as channel}; +#[cfg(feature = "menus")] use peniko::kurbo::Point; #[cfg(not(feature = "crossbeam"))] use std::sync::mpsc::{Receiver, Sender, channel}; @@ -107,13 +109,16 @@ pub enum AppEvent { Reopen { has_visible_windows: bool }, } +#[cfg(feature = "menus")] pub(crate) struct MenuWrapper(pub(crate) muda::Menu); // SAFETY: these unsafe wappers are needed so that we can send the muda memu. // The muda menu internally uses RC on a String ID and it's Vec of children. // This unsafe wrapper is memory safe but the race condition could potentially (unlikely) // lead to bad reference counts and leaked memory. // I think this is fine for this case. +#[cfg(feature = "menus")] unsafe impl Send for MenuWrapper {} +#[cfg(feature = "menus")] unsafe impl Sync for MenuWrapper {} pub(crate) enum UserEvent { @@ -128,6 +133,7 @@ pub(crate) enum UserEvent { GpuResourcesUpdate { window_id: WindowId, }, + #[cfg(feature = "menus")] ShowContextMenu { window_id: WindowId, menu: MenuWrapper, @@ -164,6 +170,7 @@ pub(crate) enum AppUpdateEvent { CancelTimer { timer: TimerToken, }, + #[cfg(feature = "menus")] MenuAction { action_id: MenuId, }, @@ -282,7 +289,7 @@ impl Application { } let handle = ApplicationHandle::new(config); - #[cfg(any(target_os = "windows", target_os = "macos"))] + #[cfg(all(feature = "menus", any(target_os = "windows", target_os = "macos")))] muda::MenuEvent::set_event_handler(Some(move |event: muda::MenuEvent| { add_app_update_event(AppUpdateEvent::MenuAction { action_id: event.id, diff --git a/src/context.rs b/src/context.rs index 95e231023..6fa8b45e7 100644 --- a/src/context.rs +++ b/src/context.rs @@ -2,16 +2,19 @@ use peniko::kurbo::{Affine, Point, Rect}; use smallvec::SmallVec; use std::{cell::RefCell, rc::Rc}; +#[cfg(feature = "menus")] +use crate::platform::menu::Menu; use crate::{ - ElementId, custom_event, + custom_event, event::{EventPropagation, Phase}, - platform::menu::Menu, style::recalc::StyleReason, view::ViewId, + ElementId, }; pub type EventCallback = dyn FnMut(&mut EventCx) -> EventPropagation; pub type ResizeCallback = dyn Fn(Rect); +#[cfg(feature = "menus")] pub type MenuCallback = dyn Fn() -> Menu; bitflags::bitflags! { diff --git a/src/event/dispatch.rs b/src/event/dispatch.rs index 243c999bb..a956ed302 100644 --- a/src/event/dispatch.rs +++ b/src/event/dispatch.rs @@ -17,9 +17,10 @@ use understory_focus::{ }; use winit::keyboard::KeyCode; +#[cfg(feature = "menus")] +use crate::action::show_context_menu; use crate::{ BoxTree, ElementId, ElementMeta, ViewId, - action::show_context_menu, context::Phases, event::{ DragEvent, DragToken, Event, FocusEvent, InteractionEvent, Phase, PointerCaptureEvent, @@ -1195,13 +1196,16 @@ impl RouteCx<'_, '_> { } // Context / popout menus (platform-specific timing). - let pbe = match &self.event { - Event::Pointer(PointerEvent::Down(pbe)) if cfg!(target_os = "macos") => Some(pbe), - Event::Pointer(PointerEvent::Up(pbe)) if !cfg!(target_os = "macos") => Some(pbe), - _ => None, - }; - if let Some(pbe) = pbe { - self.handle_menu_events(&pbe.clone()); + #[cfg(feature = "menus")] + { + let pbe = match &self.event { + Event::Pointer(PointerEvent::Down(pbe)) if cfg!(target_os = "macos") => Some(pbe), + Event::Pointer(PointerEvent::Up(pbe)) if !cfg!(target_os = "macos") => Some(pbe), + _ => None, + }; + if let Some(pbe) = pbe { + self.handle_menu_events(&pbe.clone()); + } } // Window close — close the window if not prevented. @@ -1243,6 +1247,7 @@ impl RouteCx<'_, '_> { } } + #[cfg(feature = "menus")] fn handle_menu_events(&mut self, pbe: &PointerButtonEvent) { let Some(button) = pbe.button else { return }; let Some(hit) = self diff --git a/src/lib.rs b/src/lib.rs index 87cd5c435..8a4ae732f 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -198,6 +198,7 @@ pub use layout::responsive; /// Re-export file module from platform for backward compatibility. pub use platform::file; /// Re-export menu module from platform for backward compatibility. +#[cfg(feature = "menus")] pub use platform::menu; /// Re-export view_tuple module from view for backward compatibility. pub use view::tuple as view_tuple; @@ -230,7 +231,7 @@ pub use floem_renderer::Svg as RendererSvg; pub use floem_renderer::gpu_resources::GpuResources; pub use imbl; pub use layout::ScreenLayout; -#[cfg(not(target_arch = "wasm32"))] +#[cfg(all(feature = "menus", not(target_arch = "wasm32")))] pub use muda; pub use peniko; pub use peniko::kurbo; @@ -239,6 +240,7 @@ pub use platform::open_file; #[cfg(not(target_arch = "wasm32"))] pub use platform::save_as; pub use platform::{Clipboard, ClipboardError, FileDialogOptions, FileInfo, FileSpec}; +#[cfg(feature = "menus")] pub use platform::{Menu, SubMenu}; pub use taffy; pub use ui_events; diff --git a/src/message.rs b/src/message.rs index 494ed3edf..3e45e2c60 100644 --- a/src/message.rs +++ b/src/message.rs @@ -5,13 +5,14 @@ use peniko::kurbo::{Point, Rect, Size, Vec2}; use ui_events::pointer::PointerId; use winit::window::{ResizeDirection, Theme}; +#[cfg(feature = "menus")] +use crate::platform::menu::Menu; use crate::{ - ElementId, - event::{Event, RouteKind, listener}, - platform::menu::Menu, + event::{listener, Event, RouteKind}, style::recalc::StyleReason, view::{AnyView, View, ViewId}, window::state::WindowState, + ElementId, }; thread_local! { @@ -84,11 +85,12 @@ pub enum UpdateMessage { DragWindow, DragResizeWindow(ResizeDirection), SetWindowDelta(Vec2), + #[cfg(feature = "menus")] ShowContextMenu { menu: Menu, pos: Option, }, - #[cfg(not(target_arch = "wasm32"))] + #[cfg(all(feature = "menus", not(target_arch = "wasm32")))] WindowMenu { menu: Menu, }, diff --git a/src/platform/context_menu.rs b/src/platform/context_menu.rs index a30b935f9..d055cecbf 100644 --- a/src/platform/context_menu.rs +++ b/src/platform/context_menu.rs @@ -4,9 +4,9 @@ //! native context menus aren't fully supported by the muda crate. use floem_reactive::{Effect, RwSignal, Scope, SignalGet, SignalUpdate, SignalWith}; -use peniko::Color; use peniko::color::palette; use peniko::kurbo::{Point, Size}; +use peniko::Color; use ui_events::keyboard::{Key, NamedKey}; use crate::context::VisualChangedListener; @@ -17,7 +17,7 @@ use crate::style::CursorStyle; use crate::platform::menu_types; use crate::unit::UnitExt; use crate::view::{IntoView, View}; -use crate::views::{Container, Decorators, Label, Stack, svg}; +use crate::views::{svg, Container, Decorators, Label, Stack}; #[derive(Clone, PartialEq, Eq, Hash)] enum MenuDisplay { @@ -105,7 +105,7 @@ pub(crate) fn context_menu_view( window_size: RwSignal, ) -> impl IntoView { use crate::{ - app::{AppUpdateEvent, add_app_update_event}, + app::{add_app_update_event, AppUpdateEvent}, views::dyn_stack, }; diff --git a/src/platform/menu_types.rs b/src/platform/menu_types.rs index 9b6fc2c63..3e70c6047 100644 --- a/src/platform/menu_types.rs +++ b/src/platform/menu_types.rs @@ -5,8 +5,8 @@ #[cfg(not(target_arch = "wasm32"))] pub use muda::{ - CheckMenuItem, Icon, IconMenuItem, IsMenuItem, Menu, MenuId, MenuItem, NativeIcon, - PredefinedMenuItem, Submenu, accelerator::Accelerator, + accelerator::Accelerator, CheckMenuItem, Icon, IconMenuItem, IsMenuItem, Menu, MenuId, + MenuItem, NativeIcon, PredefinedMenuItem, Submenu, }; // MenuItemKind is only used in context_menu.rs, which is only compiled on Linux/FreeBSD/wasm32 diff --git a/src/platform/mod.rs b/src/platform/mod.rs index 09551d1c9..6fcbce97a 100644 --- a/src/platform/mod.rs +++ b/src/platform/mod.rs @@ -4,12 +4,17 @@ //! features like clipboard access, native menus, and file dialogs. pub(crate) mod clipboard; -#[cfg(any(target_os = "linux", target_os = "freebsd", target_arch = "wasm32"))] +#[cfg(all( + feature = "menus", + any(target_os = "linux", target_os = "freebsd", target_arch = "wasm32") +))] pub(crate) mod context_menu; pub mod file; #[cfg(not(target_arch = "wasm32"))] pub mod file_action; +#[cfg(feature = "menus")] pub mod menu; +#[cfg(feature = "menus")] pub(crate) mod menu_types; pub(crate) mod time; #[cfg(target_arch = "wasm32")] @@ -19,5 +24,6 @@ pub use clipboard::{Clipboard, ClipboardError}; pub use file::{FileDialogOptions, FileInfo, FileSpec}; #[cfg(not(target_arch = "wasm32"))] pub use file_action::{open_file, save_as}; +#[cfg(feature = "menus")] pub use menu::{Menu, SubMenu}; pub(crate) use time::{Duration, Instant}; diff --git a/src/view/id.rs b/src/view/id.rs index 05206842a..23b52060a 100644 --- a/src/view/id.rs +++ b/src/view/id.rs @@ -37,10 +37,11 @@ use crate::{ CENTRAL_DEFERRED_UPDATE_MESSAGES, CENTRAL_UPDATE_MESSAGES, DeferredChild, DeferredChildren, DeferredReactiveSetup, UpdateMessage, }, - platform::menu::Menu, style::{Focusable, PointerEvents, Style, StyleClassRef, StyleSelector}, window::tracking::window_id_for_root, }; +#[cfg(feature = "menus")] +use crate::platform::menu::Menu; use super::AnyView; @@ -908,6 +909,7 @@ impl ViewId { } /// Set the system context menu that should be shown when this view is right-clicked + #[cfg(feature = "menus")] pub fn update_context_menu(&self, menu: impl Fn() -> Menu + 'static) { self.state().borrow_mut().context_menu = Some(Rc::new(menu)); } @@ -915,6 +917,7 @@ impl ViewId { /// Set the system popout menu that should be shown when this view is clicked /// /// Adds a primary-click context menu, which opens below the view. + #[cfg(feature = "menus")] pub fn update_popout_menu(&self, menu: impl Fn() -> Menu + 'static) { self.state().borrow_mut().popout_menu = Some(Rc::new(menu)); } diff --git a/src/view/state.rs b/src/view/state.rs index 09915aacf..397a8cc3a 100644 --- a/src/view/state.rs +++ b/src/view/state.rs @@ -1,20 +1,24 @@ +#[cfg(feature = "menus")] +use crate::context::MenuCallback; use crate::{ - ViewId, action::add_update_message, animate::Animation, context::{ CleanupListeners, EventCallback, EventCallbackConfig, EventListenerVec, LayoutChanged, - MenuCallback, VisualChanged, + VisualChanged, }, + ViewId, +}; +use crate::{ event::listener::{self, EventListenerKey}, message::UpdateMessage, prop_extractor, style::{ - Background, BorderBottomColor, BorderBottomLeftRadius, BorderBottomRightRadius, - BorderLeftColor, BorderRightColor, BorderTopColor, BorderTopLeftRadius, - BorderTopRightRadius, BoxShadowProp, CursorStyle, InheritedInteractionCx, LayoutProps, - Outline, OutlineColor, Style, StyleClassRef, StyleSelectors, TransformProps, - recalc::StyleReason, + recalc::StyleReason, Background, BorderBottomColor, BorderBottomLeftRadius, + BorderBottomRightRadius, BorderLeftColor, BorderRightColor, BorderTopColor, + BorderTopLeftRadius, BorderTopRightRadius, BoxShadowProp, CursorStyle, + InheritedInteractionCx, LayoutProps, Outline, OutlineColor, Style, StyleClassRef, + StyleSelectors, TransformProps, }, view::LayoutTree, }; @@ -393,7 +397,9 @@ pub struct ViewState { pub(crate) registered_listener_keys: SmallVec<[listener::EventListenerKey; 2]>, pub(crate) layout: Option, pub(crate) visual_change: Option, + #[cfg(feature = "menus")] pub(crate) context_menu: Option>, + #[cfg(feature = "menus")] pub(crate) popout_menu: Option>, pub(crate) cleanup_listeners: Rc>, pub(crate) num_waiting_animations: u16, @@ -451,7 +457,9 @@ impl ViewState { registered_listener_keys: SmallVec::new(), layout: None, visual_change: None, + #[cfg(feature = "menus")] context_menu: None, + #[cfg(feature = "menus")] popout_menu: None, child_translation: Vec2::ZERO, cleanup_listeners: Default::default(), diff --git a/src/views/decorator.rs b/src/views/decorator.rs index d866afd4c..85a234495 100644 --- a/src/views/decorator.rs +++ b/src/views/decorator.rs @@ -14,10 +14,11 @@ use crate::{ animate::Animation, context::EventCallbackConfig, event::{EventCx, EventPropagation, listener}, - platform::menu::Menu, style::{Style, StyleClass}, view::{HasViewId, IntoView}, }; +#[cfg(feature = "menus")] +use crate::platform::menu::Menu; /// A trait that extends the appearance and functionality of Views through styling and event handling. /// @@ -610,7 +611,7 @@ pub trait Decorators: IntoView { /// /// # Reactivity /// The menu function is reactive and will rereun in response to any signal changes in the function. - #[cfg(not(target_arch = "wasm32"))] + #[cfg(all(feature = "menus", not(target_arch = "wasm32")))] fn window_menu(self, menu_fn: impl Fn() -> Menu + 'static) -> Self::Intermediate { let intermediate = self.into_intermediate(); Effect::new(move |_| { @@ -624,6 +625,7 @@ pub trait Decorators: IntoView { /// /// # Reactivity /// The menu function is not reactive and will not rerun automatically in response to signal changes while the menu is showing and will only update the menu items each time that it is created + #[cfg(feature = "menus")] fn context_menu(self, menu: impl Fn() -> Menu + 'static) -> Self::Intermediate { let intermediate = self.into_intermediate(); let id = intermediate.view_id(); @@ -635,6 +637,7 @@ pub trait Decorators: IntoView { /// /// # Reactivity /// The menu function is not reactive and will not rerun automatically in response to signal changes while the menu is showing and will only update the menu items each time that it is created + #[cfg(feature = "menus")] fn popout_menu(self, menu: impl Fn() -> Menu + 'static) -> Self::Intermediate { let intermediate = self.into_intermediate(); let id = intermediate.view_id(); diff --git a/src/window/handle.rs b/src/window/handle.rs index de5a87e4c..652e10b1a 100644 --- a/src/window/handle.rs +++ b/src/window/handle.rs @@ -1,4 +1,4 @@ -#[cfg(not(target_arch = "wasm32"))] +#[cfg(all(feature = "menus", not(target_arch = "wasm32")))] use std::collections::HashMap; use std::{cell::RefCell, mem, rc::Rc, sync::Arc}; @@ -8,10 +8,11 @@ use crossbeam::channel::bounded as sync_channel; use std::sync::mpsc::sync_channel; use crate::event::{CustomEvent, RouteKind, ScrollTo, UpdatePhaseEvent}; +#[cfg(feature = "menus")] use crate::platform::menu_types::{Menu as MudaMenu, MenuId}; use crate::style::recalc::StyleReason; use crate::style::{StyleSelector, StyleSelectors}; -#[cfg(target_os = "windows")] +#[cfg(all(feature = "menus", target_os = "windows"))] use muda::MenuTheme as MudaMenuTheme; use crate::platform::{Duration, Instant}; @@ -37,15 +38,29 @@ use winit::{ use super::state::WindowState; use super::tracking::{remove_window_id_mapping, store_window_id_mapping}; -use crate::app::{MenuWrapper, add_app_update_event}; -#[cfg(any(target_os = "linux", target_os = "freebsd", target_arch = "wasm32"))] +#[cfg(feature = "menus")] +use crate::app::MenuWrapper; +use crate::app::add_app_update_event; +#[cfg(all( + feature = "menus", + any(target_os = "linux", target_os = "freebsd", target_arch = "wasm32") +))] use crate::platform::context_menu::context_menu_view; -#[cfg(any(target_os = "linux", target_os = "freebsd", target_arch = "wasm32"))] +#[cfg(all( + feature = "menus", + any(target_os = "linux", target_os = "freebsd", target_arch = "wasm32") +))] use crate::reactive::SignalWith; -#[cfg(any(target_os = "linux", target_os = "freebsd", target_arch = "wasm32"))] +#[cfg(all( + feature = "menus", + any(target_os = "linux", target_os = "freebsd", target_arch = "wasm32") +))] use crate::unit::UnitExt; use crate::view::{LayoutTree, VIEW_STORAGE}; -#[cfg(any(target_os = "linux", target_os = "freebsd", target_arch = "wasm32"))] +#[cfg(all( + feature = "menus", + any(target_os = "linux", target_os = "freebsd", target_arch = "wasm32") +))] use crate::views::{Container, Decorators, Stack}; use crate::{ Application, @@ -87,11 +102,14 @@ pub(crate) struct WindowHandle { transparent: bool, pub(crate) modifiers: Modifiers, pub(crate) window_position: Point, - #[cfg(any(target_os = "linux", target_os = "freebsd", target_arch = "wasm32"))] + #[cfg(all( + feature = "menus", + any(target_os = "linux", target_os = "freebsd", target_arch = "wasm32") + ))] pub(crate) context_menu: RwSignal>, - #[cfg(not(target_arch = "wasm32"))] + #[cfg(all(feature = "menus", not(target_arch = "wasm32")))] pub(crate) window_menu_actions: HashMap>, - #[cfg(not(target_arch = "wasm32"))] + #[cfg(all(feature = "menus", not(target_arch = "wasm32")))] pub(crate) window_menu: Option, pub(crate) event_reducer: WindowEventReducer, pub(crate) gpu_resources: Option, @@ -135,13 +153,22 @@ impl WindowHandle { set_current_view(id); - #[cfg(any(target_os = "linux", target_os = "freebsd", target_arch = "wasm32"))] + #[cfg(all( + feature = "menus", + any(target_os = "linux", target_os = "freebsd", target_arch = "wasm32") + ))] let context_menu = scope.create_rw_signal(None); - #[cfg(not(any(target_os = "linux", target_os = "freebsd", target_arch = "wasm32")))] + #[cfg(not(all( + feature = "menus", + any(target_os = "linux", target_os = "freebsd", target_arch = "wasm32") + )))] let view = scope.enter(move || view_fn(window_id)); - #[cfg(any(target_os = "linux", target_os = "freebsd", target_arch = "wasm32"))] + #[cfg(all( + feature = "menus", + any(target_os = "linux", target_os = "freebsd", target_arch = "wasm32") + ))] let view = scope.enter(move || { let main_view = view_fn(window_id); Stack::new(( @@ -191,11 +218,14 @@ impl WindowHandle { profile: None, modifiers: Modifiers::default(), window_position: Point::ZERO, - #[cfg(any(target_os = "linux", target_os = "freebsd", target_arch = "wasm32"))] + #[cfg(all( + feature = "menus", + any(target_os = "linux", target_os = "freebsd", target_arch = "wasm32") + ))] context_menu, - #[cfg(not(target_arch = "wasm32"))] + #[cfg(all(feature = "menus", not(target_arch = "wasm32")))] window_menu_actions: HashMap::new(), - #[cfg(not(target_arch = "wasm32"))] + #[cfg(all(feature = "menus", not(target_arch = "wasm32")))] window_menu: None, event_reducer: WindowEventReducer::default(), gpu_resources, @@ -337,11 +367,14 @@ impl WindowHandle { profile: None, modifiers: Modifiers::default(), window_position: Point::ZERO, - #[cfg(any(target_os = "linux", target_os = "freebsd", target_arch = "wasm32"))] + #[cfg(all( + feature = "menus", + any(target_os = "linux", target_os = "freebsd", target_arch = "wasm32") + ))] context_menu: scope.create_rw_signal(None), - #[cfg(not(target_arch = "wasm32"))] + #[cfg(all(feature = "menus", not(target_arch = "wasm32")))] window_menu_actions: HashMap::new(), - #[cfg(not(target_arch = "wasm32"))] + #[cfg(all(feature = "menus", not(target_arch = "wasm32")))] window_menu: None, event_reducer: WindowEventReducer::default(), gpu_resources: None, @@ -392,16 +425,25 @@ impl WindowHandle { set_current_view(self.id.root()); // Check event type for platform-specific context menu handling - #[cfg(any(target_os = "linux", target_os = "freebsd", target_arch = "wasm32"))] + #[cfg(all( + feature = "menus", + any(target_os = "linux", target_os = "freebsd", target_arch = "wasm32") + ))] let is_pointer_down = matches!(&event, Event::Pointer(PointerEvent::Down { .. })); - #[cfg(any(target_os = "linux", target_os = "freebsd", target_arch = "wasm32"))] + #[cfg(all( + feature = "menus", + any(target_os = "linux", target_os = "freebsd", target_arch = "wasm32") + ))] let is_pointer_up = matches!(&event, Event::Pointer(PointerEvent::Up { .. })); let root_element_id = self.window_state.root_view_id.get_element_id(); GlobalEventCx::new(&mut self.window_state, root_element_id, event).route_window_event(); // Platform-specific context menu handling - #[cfg(any(target_os = "linux", target_os = "freebsd", target_arch = "wasm32"))] + #[cfg(all( + feature = "menus", + any(target_os = "linux", target_os = "freebsd", target_arch = "wasm32") + ))] { if is_pointer_down && self.context_menu.with_untracked(|c| { @@ -457,7 +499,7 @@ impl WindowHandle { if !change_from_os { self.window_state.theme_overriden = true } - #[cfg(target_os = "windows")] + #[cfg(all(feature = "menus", target_os = "windows"))] { self.set_menu_theme_for_windows(theme); } @@ -580,7 +622,7 @@ impl WindowHandle { pub(crate) fn focused(&mut self, focused: bool) { if focused { - #[cfg(target_os = "macos")] + #[cfg(all(feature = "menus", target_os = "macos"))] if let Some(window_menu) = &self.window_menu { window_menu.init_for_nsapp(); } @@ -1216,6 +1258,7 @@ impl WindowHandle { let scale = cx.window_state.effective_scale(); self.paint_state.set_scale(scale); } + #[cfg(feature = "menus")] UpdateMessage::ShowContextMenu { menu, pos } => { let (menu, registry) = menu.build(); cx.window_state.context_menu.clear(); @@ -1228,6 +1271,7 @@ impl WindowHandle { pos, }); } + #[cfg(all(feature = "menus", not(target_arch = "wasm32")))] UpdateMessage::WindowMenu { menu } => { self.window_menu_actions.clear(); let (menu, registry) = menu.build(); @@ -1327,7 +1371,7 @@ impl WindowHandle { UpdateMessage::SetTheme(theme) => { self.set_theme(theme, false); - #[cfg(target_os = "windows")] + #[cfg(all(feature = "menus", target_os = "windows"))] if let Some(new) = theme { self.set_menu_theme_for_windows(new); } @@ -1478,7 +1522,7 @@ impl WindowHandle { remove_window_id_mapping(&self.id, &self.window_id); } - #[cfg(target_os = "macos")] + #[cfg(all(feature = "menus", target_os = "macos"))] pub(crate) fn show_context_menu(&self, menu: MudaMenu, pos: Option) { use dispatch2::DispatchQueue; use muda::{ @@ -1516,7 +1560,7 @@ impl WindowHandle { } } - #[cfg(target_os = "windows")] + #[cfg(all(feature = "menus", target_os = "windows"))] pub(crate) fn show_context_menu(&self, menu: MudaMenu, pos: Option) { use muda::{ ContextMenu, @@ -1540,7 +1584,7 @@ impl WindowHandle { } } - #[cfg(target_os = "windows")] + #[cfg(all(feature = "menus", target_os = "windows"))] fn init_menu_for_windows(&self, menu: &MudaMenu) { use raw_window_handle::{HasWindowHandle, RawWindowHandle}; @@ -1561,7 +1605,7 @@ impl WindowHandle { } } - #[cfg(target_os = "windows")] + #[cfg(all(feature = "menus", target_os = "windows"))] pub(crate) fn set_menu_theme_for_windows(&self, theme: winit::window::Theme) { use raw_window_handle::{HasWindowHandle, RawWindowHandle}; @@ -1578,7 +1622,10 @@ impl WindowHandle { } } - #[cfg(any(target_os = "linux", target_os = "freebsd", target_arch = "wasm32"))] + #[cfg(all( + feature = "menus", + any(target_os = "linux", target_os = "freebsd", target_arch = "wasm32") + ))] pub(crate) fn show_context_menu(&self, menu: MudaMenu, pos: Option) { let pos = pos.unwrap_or(self.window_state.last_pointer.0); let pos = Point::new( @@ -1588,7 +1635,7 @@ impl WindowHandle { self.context_menu.set(Some((menu, pos, false))); } - #[cfg(target_arch = "wasm32")] + #[cfg(all(feature = "menus", target_arch = "wasm32"))] pub(crate) fn menu_action(&mut self, id: &MenuId) { set_current_view(self.id); if let Some(action) = self.window_state.context_menu.get(id) { @@ -1597,7 +1644,7 @@ impl WindowHandle { } } - #[cfg(not(target_arch = "wasm32"))] + #[cfg(all(feature = "menus", not(target_arch = "wasm32")))] pub(crate) fn menu_action(&mut self, id: &MenuId) { set_current_view(self.id); if let Some(action) = self.window_state.context_menu.get(id) { diff --git a/src/window/state.rs b/src/window/state.rs index bb95030b3..feca5cade 100644 --- a/src/window/state.rs +++ b/src/window/state.rs @@ -1,12 +1,15 @@ -use std::{cell::RefCell, collections::HashMap, time::Instant}; +use std::{cell::RefCell, time::Instant}; +#[cfg(feature = "menus")] +use std::collections::HashMap; use crate::{ action::exec_after_animation_frame, inspector::CaptureState, - platform::menu_types::MenuId, style::{StyleCache, StyleSelectors, recalc::StyleReason}, view::ViewStorage, }; +#[cfg(feature = "menus")] +use crate::platform::menu_types::MenuId; use peniko::kurbo::{Affine, Point, Rect, RoundedRect, Size, Vec2}; use rustc_hash::{FxHashMap, FxHashSet}; @@ -163,6 +166,7 @@ pub struct WindowState { pub(crate) last_cursor_icon: CursorIcon, pub(crate) last_pointer: (Point, PointerInfo), pub(crate) keyboard_navigation: bool, + #[cfg(feature = "menus")] pub(crate) context_menu: HashMap>, /// This is set if we're currently capturing the window for the inspector. @@ -245,6 +249,7 @@ impl WindowState { ), keyboard_navigation: false, grid_bps: GridBreakpoints::default(), + #[cfg(feature = "menus")] context_menu: HashMap::new(), capture: None, style_cache: StyleCache::new(), @@ -1322,6 +1327,7 @@ impl WindowState { } } + #[cfg(feature = "menus")] pub(crate) fn update_context_menu( &mut self, actions: HashMap>,