phosphor_app/state/
navigation.rs1use super::*;
4
5impl NavState {
6
7 pub fn toggle_space_menu(&mut self) {
11 self.space_menu.toggle();
12 }
13
14 pub fn space_menu_handle(&mut self, ch: char) -> Option<SpaceAction> {
20 self.space_menu.open = false;
21 match ch {
22 '1' => { self.focus_pane(Pane::Transport); None }
23 '2' => { self.focus_pane(Pane::Tracks); None }
24 '3' => { self.focus_pane(Pane::ClipView); None }
25 'p' => Some(SpaceAction::PlayPause),
26 'r' => Some(SpaceAction::ToggleRecord),
27 'l' => Some(SpaceAction::ToggleLoop),
28 'm' => Some(SpaceAction::ToggleMetronome),
29 '!' => Some(SpaceAction::Panic),
30 'a' => Some(SpaceAction::AddInstrument),
31 's' => Some(SpaceAction::Save),
32 'o' => Some(SpaceAction::Open),
33 'd' => Some(SpaceAction::Delete),
34 'e' => Some(SpaceAction::EditMode),
35 'q' => Some(SpaceAction::Quantize),
36 'w' => Some(SpaceAction::Presets),
37 'v' => Some(SpaceAction::CycleTheme),
38 'n' => Some(SpaceAction::NewTrack),
39 'h' => {
40 self.space_menu.open = true;
41 self.space_menu.section = SpaceMenuSection::Help;
42 self.space_menu.cursor = 0;
43 None
44 }
45 _ => None,
46 }
47 }
48
49 pub fn focus_pane(&mut self, pane: Pane) {
55 if self.focused_pane == Pane::Tracks { self.track_selected = false; self.element_locked = false; }
56 self.focused_pane = pane;
57 tracing::debug!("focused pane: {:?}", pane);
58 }
59
60
61 pub fn focus_next_pane(&mut self) {
62 self.focus_pane(self.focused_pane.next());
63 }
64
65 pub fn move_up(&mut self) {
71 if self.instrument_modal.open { self.instrument_modal.move_up(); return; }
72 if self.space_menu.open { self.space_menu.move_up(); return; }
73 if self.fx_menu.open { self.fx_menu.move_up(); return; }
74 match self.focused_pane {
75 Pane::Transport => {} Pane::Tracks if !self.track_selected => {
77 if self.track_cursor > 0 {
78 self.track_cursor -= 1;
79 if self.track_cursor < self.track_scroll {
80 self.track_scroll = self.track_cursor;
81 }
82 }
83 }
84 Pane::Tracks => {
85 }
88 Pane::ClipView => {
89 match self.clip_view.focus {
90 ClipViewFocus::PianoRoll if self.clip_view.clip_tab == ClipTab::InstConfig => {
91 if self.clip_view.inst_config_cursor > 0 {
92 self.clip_view.inst_config_cursor -= 1;
93 }
94 }
95 ClipViewFocus::PianoRoll if self.clip_view.clip_tab == ClipTab::Settings => {
96 if self.clip_view.piano_roll.settings_cursor > 0 {
97 self.clip_view.piano_roll.settings_cursor -= 1;
98 }
99 }
100 ClipViewFocus::PianoRoll => self.clip_view.piano_roll.move_up(),
101 ClipViewFocus::FxPanel => {
102 if self.clip_view.fx_panel_tab == FxPanelTab::Synth {
103 if self.clip_view.synth_param_cursor > 0 {
104 self.clip_view.synth_param_cursor -= 1;
105 }
106 } else if self.clip_view.fx_cursor > 0 {
107 self.clip_view.fx_cursor -= 1;
108 }
109 }
110 }
111 }
112 }
113 }
114
115
116 pub fn move_down(&mut self) {
117 if self.instrument_modal.open { self.instrument_modal.move_down(); return; }
118 if self.space_menu.open { self.space_menu.move_down(); return; }
119 if self.fx_menu.open { self.fx_menu.move_down(); return; }
120 match self.focused_pane {
121 Pane::Transport => {}
122 Pane::Tracks if !self.track_selected => {
123 if self.track_cursor + 1 < self.tracks.len() {
124 self.track_cursor += 1;
125 if self.track_cursor >= self.track_scroll + MAX_VISIBLE_TRACKS {
126 self.track_scroll = self.track_cursor + 1 - MAX_VISIBLE_TRACKS;
127 }
128 }
129 }
130 Pane::Tracks => {
131 }
133 Pane::ClipView => {
134 match self.clip_view.focus {
135 ClipViewFocus::PianoRoll if self.clip_view.clip_tab == ClipTab::InstConfig => {
136 if self.clip_view.inst_config_cursor + 1 < INST_CONFIG_PARAM_COUNT {
137 self.clip_view.inst_config_cursor += 1;
138 }
139 }
140 ClipViewFocus::PianoRoll if self.clip_view.clip_tab == ClipTab::Settings => {
141 const SETTINGS_COUNT: usize = 3; if self.clip_view.piano_roll.settings_cursor + 1 < SETTINGS_COUNT {
143 self.clip_view.piano_roll.settings_cursor += 1;
144 }
145 }
146 ClipViewFocus::PianoRoll => self.clip_view.piano_roll.move_down(),
147 ClipViewFocus::FxPanel => {
148 if self.clip_view.fx_panel_tab == FxPanelTab::Synth {
149 let max = self.current_track().map(|t| t.synth_params.len()).unwrap_or(0);
150 if self.clip_view.synth_param_cursor + 1 < max {
151 self.clip_view.synth_param_cursor += 1;
152 }
153 } else {
154 let max = self.active_fx_chain_len();
155 if self.clip_view.fx_cursor + 1 < max {
156 self.clip_view.fx_cursor += 1;
157 }
158 }
159 }
160 }
161 }
162 }
163 }
164
165
166 pub fn move_left(&mut self) {
167 if self.focused_pane == Pane::Tracks && self.track_selected {
168 self.track_element = self.track_element.move_left();
169 if let TrackElement::Clip(idx) = self.track_element {
171 self.open_clip_view(self.track_cursor, idx);
172 }
173 } else if self.focused_pane == Pane::ClipView {
174 match self.clip_view.focus {
175 ClipViewFocus::PianoRoll if self.clip_view.clip_tab == ClipTab::InstConfig => {
176 }
178 ClipViewFocus::PianoRoll if self.clip_view.clip_tab == ClipTab::Settings => {
179 self.adjust_setting(-1);
181 }
182 ClipViewFocus::PianoRoll => {
183 self.clip_view.focus = ClipViewFocus::FxPanel;
184 }
185 ClipViewFocus::FxPanel if self.clip_view.fx_panel_tab == FxPanelTab::Synth => {
186 self.adjust_synth_param(-0.05);
188 }
189 _ => {}
190 }
191 }
192 }
193
194
195 pub fn move_right(&mut self) {
196 if self.focused_pane == Pane::Tracks && self.track_selected {
197 let num_clips = self.current_track().map(|t| t.clips.len()).unwrap_or(0);
198 self.track_element = self.track_element.move_right(num_clips);
199 if let TrackElement::Clip(idx) = self.track_element {
201 self.open_clip_view(self.track_cursor, idx);
202 }
203 } else if self.focused_pane == Pane::ClipView {
204 match self.clip_view.focus {
205 ClipViewFocus::PianoRoll if self.clip_view.clip_tab == ClipTab::InstConfig => {
206 }
208 ClipViewFocus::PianoRoll if self.clip_view.clip_tab == ClipTab::Settings => {
209 self.adjust_setting(1);
211 }
212 ClipViewFocus::FxPanel if self.clip_view.fx_panel_tab == FxPanelTab::Synth => {
213 self.adjust_synth_param(0.05);
215 }
216 ClipViewFocus::FxPanel => {
217 self.clip_view.focus = ClipViewFocus::PianoRoll;
218 }
219 _ => {}
220 }
221 }
222 }
223
224 pub fn adjust_setting(&mut self, direction: i32) {
226 match self.clip_view.piano_roll.settings_cursor {
227 0 => {
228 if direction > 0 {
230 self.clip_view.piano_roll.grid = self.clip_view.piano_roll.grid.next();
231 } else {
232 self.clip_view.piano_roll.grid = self.clip_view.piano_roll.grid.prev();
233 }
234 self.clip_view.piano_roll.update_column_count();
235 }
236 1 => {
237 self.clip_view.piano_roll.snap_enabled = !self.clip_view.piano_roll.snap_enabled;
239 }
240 2 => {
241 let v = self.clip_view.piano_roll.default_velocity as i32 + direction * 5;
243 self.clip_view.piano_roll.default_velocity = v.clamp(1, 127) as u8;
244 }
245 _ => {}
246 }
247 }
248
249 pub fn enter(&mut self) -> Option<SpaceAction> {
253 if self.space_menu.open {
255 match self.space_menu.section {
256 SpaceMenuSection::Actions => {
257 if let Some((key, _, _)) = SPACE_ACTIONS.get(self.space_menu.cursor) {
258 if let Some(ch) = key.strip_prefix("spc+").and_then(|s| s.chars().next()) {
260 return self.space_menu_handle(ch);
261 }
262 }
263 self.space_menu.open = false;
264 return None;
265 }
266 SpaceMenuSection::Help => {
267 return None;
269 }
270 }
271 }
272 if self.fx_menu.open {
274 self.fx_menu_select();
275 return None;
276 }
277
278 match self.focused_pane {
279 Pane::Transport => {} Pane::Tracks => {
281 if !self.track_selected {
282 self.track_selected = true;
283 self.track_element = TrackElement::Label;
284 self.show_current_track_controls();
285 } else {
286 self.activate_element();
287 }
288 }
289 Pane::ClipView => {}
290 }
291 None
292 }
293
294
295 pub fn escape(&mut self) {
296 if self.instrument_modal.open {
297 self.instrument_modal.open = false;
298 return;
299 }
300 if self.space_menu.open {
301 self.space_menu.open = false;
302 return;
303 }
304 if self.fx_menu.open {
305 self.fx_menu.open = false;
306 return;
307 }
308 match self.focused_pane {
309 Pane::Transport => {} Pane::Tracks => {
311 if self.element_locked {
312 self.element_locked = false;
314 } else if self.track_selected {
315 self.track_selected = false;
316 self.element_locked = false;
317 self.track_element = TrackElement::Label;
318 self.clip_view_visible = false;
319 self.clip_view_target = None;
320 }
321 }
322 Pane::ClipView => self.focus_pane(Pane::Tracks),
323 }
324 }
325
326 pub fn cycle_tab(&mut self) {
332 if self.focused_pane != Pane::ClipView { return; }
333
334 match (self.clip_view.focus, self.clip_view.fx_panel_tab, self.clip_view.clip_tab) {
335 (ClipViewFocus::FxPanel, FxPanelTab::TrackFx, _) => {
337 self.clip_view.fx_panel_tab = FxPanelTab::Synth;
338 }
339 (ClipViewFocus::FxPanel, FxPanelTab::Synth, _) => {
341 self.clip_view.focus = ClipViewFocus::PianoRoll;
342 self.clip_view.clip_tab = ClipTab::InstConfig;
343 self.clip_view.inst_config_cursor = 0;
344 }
345 (ClipViewFocus::PianoRoll, _, ClipTab::InstConfig) => {
347 self.clip_view.clip_tab = ClipTab::PianoRoll;
348 self.clip_view.piano_roll.focus = PianoRollFocus::Navigation;
349 self.clip_view.piano_roll.column = 0;
350 }
351 (ClipViewFocus::PianoRoll, _, ClipTab::PianoRoll) => {
353 self.clip_view.clip_tab = ClipTab::Settings;
354 }
355 (ClipViewFocus::PianoRoll, _, ClipTab::Settings) => {
357 self.clip_view.focus = ClipViewFocus::FxPanel;
358 self.clip_view.fx_panel_tab = FxPanelTab::TrackFx;
359 self.clip_view.fx_cursor = 0;
360 }
361 }
362 }
363
364}