Add in-window menus for Linux and Windows.

This commit is contained in:
2026-08-07 15:23:12 +02:00
parent 3b1a65359c
commit 358648378e
4 changed files with 767 additions and 69 deletions

View File

@@ -95,6 +95,7 @@ enum AutoTranslationTaskEvent {
pub enum Message {
// Menu
MenuEvent(muda::MenuId),
WindowMenu(menu::WindowMenuEvent),
// Navigation
SetActiveView(SidebarView),
@@ -1079,6 +1080,7 @@ pub struct BdsApp {
// Platform
_menu_bar: Option<muda::Menu>,
menu_registry: MenuRegistry,
window_menu: menu::WindowMenuState,
native_edit_commands: native_edit::EditCommandQueue,
#[cfg(target_os = "macos")]
_lifecycle_handler: Option<objc2::rc::Retained<crate::platform::macos::BdsAppleEventHandler>>,
@@ -1291,6 +1293,7 @@ impl BdsApp {
image_drop_import_running: false,
_menu_bar: Some(menu_bar),
menu_registry: registry,
window_menu: menu::WindowMenuState::default(),
native_edit_commands: native_edit::command_queue(),
#[cfg(target_os = "macos")]
_lifecycle_handler: lifecycle_handler,
@@ -1397,6 +1400,7 @@ impl BdsApp {
image_drop_import_running: false,
_menu_bar: None,
menu_registry: MenuRegistry::empty(),
window_menu: menu::WindowMenuState::default(),
native_edit_commands: native_edit::command_queue(),
#[cfg(target_os = "macos")]
_lifecycle_handler: None,
@@ -1465,6 +1469,25 @@ impl BdsApp {
}
Task::none()
}
Message::WindowMenu(event) => {
let has_project = self.active_project.is_some();
let active_tab = self.active_tab_type();
let offline = self.offline_mode;
let interactions_enabled = !self.search_index_rebuild_running;
let connected = self.remote_client.is_some();
let enabled = |action| {
menu::action_enabled(
action,
has_project,
active_tab.as_ref(),
offline,
interactions_enabled,
) && (action != MenuAction::DisconnectServer || connected)
};
self.window_menu
.handle_event(event, enabled)
.map_or_else(Task::none, |action| self.dispatch_menu_action(action))
}
// ── Navigation ──
Message::SetActiveView(view) => {
@@ -3778,74 +3801,84 @@ impl BdsApp {
None
};
native_edit::native_edit(
workspace::view(
self.sidebar_view,
self.sidebar_visible,
self.sidebar_width,
&self.tabs,
self.active_tab.as_deref(),
self.panel_visible,
self.panel_tab,
&self.task_snapshots,
&self.collapsed_task_groups,
&self.output_entries,
&self.sidebar_posts,
&self.sidebar_media,
&self.sidebar_scripts,
&self.sidebar_templates,
&self.sidebar_imports,
&self.chat_conversations,
active_post_filter,
&self.media_filter,
&self.sidebar_media_thumbs,
self.sidebar_posts_has_more,
self.sidebar_media_has_more,
active_name,
&self.projects,
self.active_project.as_ref().map(|p| p.id.as_str()),
self.post_count,
self.media_count,
self.offline_mode,
self.locale_dropdown_open,
self.project_dropdown_open,
&self.theme_badge,
self.ui_locale,
&self.toasts,
self.active_modal.clone(),
self.data_dir.as_deref(),
post_preview_widget,
style_preview_widget,
&self.post_editors,
&self.media_editors,
&self.template_editors,
&self.script_editors,
&self.import_editors,
&self.chat_editors,
self.tags_view_state.as_ref(),
self.settings_state.as_ref(),
self.style_view_state.as_ref(),
self.dashboard_state.as_ref(),
&self.site_validation_state,
&self.duplicates_state,
&self.guide_documentation,
&self.api_documentation,
&self.cli_documentation,
&self.mcp_documentation,
&self.metadata_diff_state,
&self.menu_editor_state,
&self.translation_validation_state,
&self.git_state,
&self.git_diffs,
&self.git_file_history,
),
Arc::clone(&self.native_edit_commands),
)
.into()
let content = workspace::view(
self.sidebar_view,
self.sidebar_visible,
self.sidebar_width,
&self.tabs,
self.active_tab.as_deref(),
self.panel_visible,
self.panel_tab,
&self.task_snapshots,
&self.collapsed_task_groups,
&self.output_entries,
&self.sidebar_posts,
&self.sidebar_media,
&self.sidebar_scripts,
&self.sidebar_templates,
&self.sidebar_imports,
&self.chat_conversations,
active_post_filter,
&self.media_filter,
&self.sidebar_media_thumbs,
self.sidebar_posts_has_more,
self.sidebar_media_has_more,
active_name,
&self.projects,
self.active_project.as_ref().map(|p| p.id.as_str()),
self.post_count,
self.media_count,
self.offline_mode,
self.locale_dropdown_open,
self.project_dropdown_open,
&self.theme_badge,
self.ui_locale,
&self.toasts,
self.active_modal.clone(),
self.data_dir.as_deref(),
post_preview_widget,
style_preview_widget,
&self.post_editors,
&self.media_editors,
&self.template_editors,
&self.script_editors,
&self.import_editors,
&self.chat_editors,
self.tags_view_state.as_ref(),
self.settings_state.as_ref(),
self.style_view_state.as_ref(),
self.dashboard_state.as_ref(),
&self.site_validation_state,
&self.duplicates_state,
&self.guide_documentation,
&self.api_documentation,
&self.cli_documentation,
&self.mcp_documentation,
&self.metadata_diff_state,
&self.menu_editor_state,
&self.translation_validation_state,
&self.git_state,
&self.git_diffs,
&self.git_file_history,
);
#[cfg(not(target_os = "macos"))]
let content =
menu::window_menu_view(content, &self.window_menu, self.ui_locale, |action| {
menu::action_enabled(
action,
self.active_project.is_some(),
self.active_tab_type(),
self.offline_mode,
!self.search_index_rebuild_running,
) && (action != MenuAction::DisconnectServer || self.remote_client.is_some())
});
native_edit::native_edit(content, Arc::clone(&self.native_edit_commands)).into()
}
pub fn subscription(&self) -> Subscription<Message> {
let menu_sub = menu::menu_subscription();
let window_menu_sub = menu::window_menu_subscription();
let task_tick =
iced::time::every(std::time::Duration::from_millis(500)).map(|_| Message::TaskTick);
@@ -3915,6 +3948,7 @@ impl BdsApp {
Subscription::batch([
menu_sub,
window_menu_sub,
task_tick,
domain_event_tick,
toast_tick,