From c6840fe9b3796044d2de1c7538fba6e307e40431 Mon Sep 17 00:00:00 2001 From: jess Date: Tue, 31 Mar 2026 17:57:46 -0700 Subject: [PATCH] =?UTF-8?q?Wire=20settings=20panel,=20keyboard=20triggers,?= =?UTF-8?q?=20native=20menu,=20and=20module=20windows=20=E2=80=94=20elimin?= =?UTF-8?q?ate=2032=20dead-code=20warnings?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- au-o2-gui/src/entry.rs | 178 ++++++++++++++++++++++++++++++++++++++++- 1 file changed, 176 insertions(+), 2 deletions(-) diff --git a/au-o2-gui/src/entry.rs b/au-o2-gui/src/entry.rs index f4bc8a3..ab64862 100644 --- a/au-o2-gui/src/entry.rs +++ b/au-o2-gui/src/entry.rs @@ -1,8 +1,11 @@ use std::path::PathBuf; use chrono::NaiveDateTime; -use iced::{Element, Task}; +use iced::keyboard::{Key, Modifiers}; +use iced::{Element, Subscription, Task}; +use crate::behaviors::Action; +use crate::gui::native_menu::{NativeMenu, NativeMenuAction}; use crate::gui::time_utility; #[derive(Debug, Clone)] @@ -24,6 +27,7 @@ pub enum AppState { ProjectView(ProjectViewState), NewProject(crate::gui::new_project::State), TimeUtility { tapper_state: time_utility::State, return_state: Box }, + Settings { settings_state: crate::gui::settings::State, return_state: Box }, Editor(crate::editor::Editor), } @@ -59,12 +63,22 @@ pub enum Message { TimeUtilityCancel, RunTimeUtilityAnalysis, + OpenSettings, + CloseSettings { save: bool }, + SettingsMessage(crate::gui::settings::Message), + + KeyPressed(Key, Modifiers), + KeyReleased(Key, Modifiers), + WindowClosed(iced::window::Id), + Tick, + EditorMessage(crate::editor::Message), } pub struct App { pub state: AppState, pub global_config: crate::config::AudioOxideConfig, + native_menu: NativeMenu, } impl Default for App { @@ -75,12 +89,17 @@ impl Default for App { } else { AppState::ProjectView(ProjectViewState::Splash) }; - Self { state, global_config: config } + Self { + state, + global_config: config, + native_menu: NativeMenu::init(), + } } } pub fn main() -> iced::Result { iced::application("Audio Oxide", App::update, App::view) + .subscription(App::subscription) .run() } @@ -305,6 +324,80 @@ impl App { } } + Message::OpenSettings => { + if matches!(self.state, AppState::Settings { .. }) { + return Task::none(); + } + let return_state = std::mem::replace( + &mut self.state, + AppState::ProjectView(ProjectViewState::Splash), + ); + let settings_state = crate::gui::settings::State::new(&self.global_config); + self.state = AppState::Settings { + settings_state, + return_state: Box::new(return_state), + }; + } + Message::CloseSettings { save } => { + if save { + if let AppState::Settings { ref settings_state, .. } = self.state { + self.global_config = settings_state.config.clone(); + crate::first_run::save_config(&self.global_config); + } + } + if let Some(rs) = self.take_settings_return() { + self.state = rs; + } else { + self.state = AppState::ProjectView(ProjectViewState::Splash); + } + } + Message::SettingsMessage(settings_msg) => { + if let AppState::Settings { ref mut settings_state, .. } = self.state { + let is_save = matches!(settings_msg, crate::gui::settings::Message::Save); + let is_cancel = matches!(settings_msg, crate::gui::settings::Message::Cancel); + let done = crate::gui::settings::handle_message(settings_state, settings_msg); + if done { + return self.update(Message::CloseSettings { save: is_save && !is_cancel }); + } + } + } + + Message::KeyPressed(key, modifiers) => { + if let Some(action) = crate::triggers::map_key_press_to_action(&self.state, key, modifiers) { + return self.dispatch_action(action); + } + } + Message::KeyReleased(key, modifiers) => { + if let Some(action) = crate::triggers::map_key_release_to_action(&self.state, key, modifiers) { + return self.dispatch_action(action); + } + } + Message::Tick => { + let menu_actions = self.native_menu.poll_events(); + if let Some(first) = menu_actions.into_iter().next() { + match first { + NativeMenuAction::Action(action) => { + return self.dispatch_action(action); + } + NativeMenuAction::ShowNewTrackWizard => { + return self.update(Message::EditorMessage(crate::editor::Message::ShowNewTrackWizard)); + } + } + } + } + + Message::WindowClosed(window_id) => { + if let AppState::Editor(ref mut editor) = self.state { + if editor.module_for_window(window_id).is_some() { + let title = editor.module_window_title(window_id); + let _had_view = editor.module_window_view(window_id).is_some(); + debug_log!("module window closed: {:?} (had_view={})", title, _had_view); + drop(title); + return editor.close_module_window_by_id(window_id).map(Message::EditorMessage); + } + } + } + Message::EditorMessage(editor_msg) => { if let AppState::Editor(ref mut editor) = self.state { return editor.update(editor_msg).map(Message::EditorMessage); @@ -331,12 +424,82 @@ impl App { AppState::TimeUtility { tapper_state, .. } => { time_utility::view(tapper_state) } + AppState::Settings { settings_state, .. } => { + crate::gui::settings::view(settings_state) + .map(Message::SettingsMessage) + } AppState::Editor(editor) => { editor.view().map(Message::EditorMessage) } } } + fn subscription(&self) -> Subscription { + use iced::keyboard; + Subscription::batch([ + keyboard::on_key_press(|key, modifiers| Some(Message::KeyPressed(key, modifiers))), + keyboard::on_key_release(|key, modifiers| Some(Message::KeyReleased(key, modifiers))), + iced::window::close_events().map(Message::WindowClosed), + iced::time::every(std::time::Duration::from_millis(100)).map(|_| Message::Tick), + ]) + } + + fn dispatch_action(&mut self, action: Action) -> Task { + match action { + Action::TimeUtilityTapPressed => self.update(Message::TimeUtilityTapPressed), + Action::TimeUtilityTapReleased => self.update(Message::TimeUtilityTapReleased), + Action::OpenSettings => self.update(Message::OpenSettings), + Action::NewProject => self.update(Message::ViewNewProject), + Action::EditorTogglePlayback => { + self.update(Message::EditorMessage(crate::editor::Message::PlayPressed)) + } + Action::EditorStop => { + self.update(Message::EditorMessage(crate::editor::Message::StopPressed)) + } + Action::EditorToggleRecord => { + self.update(Message::EditorMessage(crate::editor::Message::RecordPressed)) + } + Action::EditorRewind => { + self.update(Message::EditorMessage(crate::editor::Message::RewindPressed)) + } + Action::EditorPlayFromBeginning => { + self.update(Message::EditorMessage(crate::editor::Message::RewindPressed)) + } + Action::EditorToggleInspector => { + self.update(Message::EditorMessage(crate::editor::Message::ToggleInspector)) + } + Action::EditorToggleBottomPanel => { + self.update(Message::EditorMessage(crate::editor::Message::ToggleBottomPanel)) + } + Action::EditorToggleMixer => { + self.update(Message::EditorMessage(crate::editor::Message::SetBottomPanelMode( + crate::editor::BottomPanelMode::Mixer, + ))) + } + Action::EditorToggleCycle => { + self.update(Message::EditorMessage(crate::editor::Message::CycleToggled)) + } + Action::EditorToggleMetronome => { + self.update(Message::EditorMessage(crate::editor::Message::MetronomeToggled)) + } + Action::ZoomInH => { + self.update(Message::EditorMessage(crate::editor::Message::ZoomH(1.25))) + } + Action::ZoomOutH => { + self.update(Message::EditorMessage(crate::editor::Message::ZoomH(0.8))) + } + Action::ZoomInV => { + self.update(Message::EditorMessage(crate::editor::Message::ZoomV(1.25))) + } + Action::ZoomOutV => { + self.update(Message::EditorMessage(crate::editor::Message::ZoomV(0.8))) + } + action => { + self.update(Message::EditorMessage(crate::editor::Message::EditAction(action))) + } + } + } + fn take_time_utility_return(&mut self) -> Option { let placeholder = AppState::ProjectView(ProjectViewState::Splash); let old = std::mem::replace(&mut self.state, placeholder); @@ -347,4 +510,15 @@ impl App { None } } + + fn take_settings_return(&mut self) -> Option { + let placeholder = AppState::ProjectView(ProjectViewState::Splash); + let old = std::mem::replace(&mut self.state, placeholder); + if let AppState::Settings { return_state, .. } = old { + Some(*return_state) + } else { + self.state = old; + None + } + } }