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 'v' => Some(SpaceAction::CycleTheme),
36 'n' => Some(SpaceAction::NewTrack),
37 'h' => {
38 self.space_menu.open = true;
39 self.space_menu.section = SpaceMenuSection::Help;
40 self.space_menu.cursor = 0;
41 None
42 }
43 _ => None,
44 }
45 }
46
47 pub fn focus_pane(&mut self, pane: Pane) {
53 if self.focused_pane == Pane::Tracks { self.track_selected = false; self.clip_locked = false; }
54 self.focused_pane = pane;
55 tracing::debug!("focused pane: {:?}", pane);
56 }
57
58
59 pub fn focus_next_pane(&mut self) {
60 self.focus_pane(self.focused_pane.next());
61 }
62
63 pub fn move_up(&mut self) {
69 if self.instrument_modal.open { self.instrument_modal.move_up(); return; }
70 if self.space_menu.open { self.space_menu.move_up(); return; }
71 if self.fx_menu.open { self.fx_menu.move_up(); return; }
72 match self.focused_pane {
73 Pane::Transport => {} Pane::Tracks if !self.track_selected => {
75 if self.track_cursor > 0 {
76 self.track_cursor -= 1;
77 if self.track_cursor < self.track_scroll {
78 self.track_scroll = self.track_cursor;
79 }
80 }
81 }
82 Pane::Tracks => {
83 }
86 Pane::ClipView => {
87 match self.clip_view.focus {
88 ClipViewFocus::PianoRoll if self.clip_view.clip_tab == ClipTab::InstConfig => {
89 if self.clip_view.inst_config_cursor > 0 {
90 self.clip_view.inst_config_cursor -= 1;
91 }
92 }
93 ClipViewFocus::PianoRoll if self.clip_view.clip_tab == ClipTab::Settings => {
94 if self.clip_view.piano_roll.settings_cursor > 0 {
95 self.clip_view.piano_roll.settings_cursor -= 1;
96 }
97 }
98 ClipViewFocus::PianoRoll => self.clip_view.piano_roll.move_up(),
99 ClipViewFocus::FxPanel => {
100 if self.clip_view.fx_panel_tab == FxPanelTab::Synth {
101 if self.clip_view.synth_param_cursor > 0 {
102 self.clip_view.synth_param_cursor -= 1;
103 }
104 } else if self.clip_view.fx_cursor > 0 {
105 self.clip_view.fx_cursor -= 1;
106 }
107 }
108 }
109 }
110 }
111 }
112
113
114 pub fn move_down(&mut self) {
115 if self.instrument_modal.open { self.instrument_modal.move_down(); return; }
116 if self.space_menu.open { self.space_menu.move_down(); return; }
117 if self.fx_menu.open { self.fx_menu.move_down(); return; }
118 match self.focused_pane {
119 Pane::Transport => {}
120 Pane::Tracks if !self.track_selected => {
121 if self.track_cursor + 1 < self.tracks.len() {
122 self.track_cursor += 1;
123 if self.track_cursor >= self.track_scroll + MAX_VISIBLE_TRACKS {
124 self.track_scroll = self.track_cursor + 1 - MAX_VISIBLE_TRACKS;
125 }
126 }
127 }
128 Pane::Tracks => {
129 }
131 Pane::ClipView => {
132 match self.clip_view.focus {
133 ClipViewFocus::PianoRoll if self.clip_view.clip_tab == ClipTab::InstConfig => {
134 if self.clip_view.inst_config_cursor + 1 < INST_CONFIG_PARAM_COUNT {
135 self.clip_view.inst_config_cursor += 1;
136 }
137 }
138 ClipViewFocus::PianoRoll if self.clip_view.clip_tab == ClipTab::Settings => {
139 const SETTINGS_COUNT: usize = 3; if self.clip_view.piano_roll.settings_cursor + 1 < SETTINGS_COUNT {
141 self.clip_view.piano_roll.settings_cursor += 1;
142 }
143 }
144 ClipViewFocus::PianoRoll => self.clip_view.piano_roll.move_down(),
145 ClipViewFocus::FxPanel => {
146 if self.clip_view.fx_panel_tab == FxPanelTab::Synth {
147 let max = self.current_track().map(|t| t.synth_params.len()).unwrap_or(0);
148 if self.clip_view.synth_param_cursor + 1 < max {
149 self.clip_view.synth_param_cursor += 1;
150 }
151 } else {
152 let max = self.active_fx_chain_len();
153 if self.clip_view.fx_cursor + 1 < max {
154 self.clip_view.fx_cursor += 1;
155 }
156 }
157 }
158 }
159 }
160 }
161 }
162
163
164 pub fn move_left(&mut self) {
165 if self.focused_pane == Pane::Tracks && self.track_selected {
166 self.track_element = self.track_element.move_left();
167 if let TrackElement::Clip(idx) = self.track_element {
169 self.open_clip_view(self.track_cursor, idx);
170 }
171 } else if self.focused_pane == Pane::ClipView {
172 match self.clip_view.focus {
173 ClipViewFocus::PianoRoll if self.clip_view.clip_tab == ClipTab::InstConfig => {
174 }
176 ClipViewFocus::PianoRoll if self.clip_view.clip_tab == ClipTab::Settings => {
177 self.adjust_setting(-1);
179 }
180 ClipViewFocus::PianoRoll => {
181 self.clip_view.focus = ClipViewFocus::FxPanel;
182 }
183 ClipViewFocus::FxPanel if self.clip_view.fx_panel_tab == FxPanelTab::Synth => {
184 self.adjust_synth_param(-0.05);
186 }
187 _ => {}
188 }
189 }
190 }
191
192
193 pub fn move_right(&mut self) {
194 if self.focused_pane == Pane::Tracks && self.track_selected {
195 let num_clips = self.current_track().map(|t| t.clips.len()).unwrap_or(0);
196 self.track_element = self.track_element.move_right(num_clips);
197 if let TrackElement::Clip(idx) = self.track_element {
199 self.open_clip_view(self.track_cursor, idx);
200 }
201 } else if self.focused_pane == Pane::ClipView {
202 match self.clip_view.focus {
203 ClipViewFocus::PianoRoll if self.clip_view.clip_tab == ClipTab::InstConfig => {
204 }
206 ClipViewFocus::PianoRoll if self.clip_view.clip_tab == ClipTab::Settings => {
207 self.adjust_setting(1);
209 }
210 ClipViewFocus::FxPanel if self.clip_view.fx_panel_tab == FxPanelTab::Synth => {
211 self.adjust_synth_param(0.05);
213 }
214 ClipViewFocus::FxPanel => {
215 self.clip_view.focus = ClipViewFocus::PianoRoll;
216 }
217 _ => {}
218 }
219 }
220 }
221
222 pub fn adjust_setting(&mut self, direction: i32) {
224 match self.clip_view.piano_roll.settings_cursor {
225 0 => {
226 if direction > 0 {
228 self.clip_view.piano_roll.grid = self.clip_view.piano_roll.grid.next();
229 } else {
230 self.clip_view.piano_roll.grid = self.clip_view.piano_roll.grid.prev();
231 }
232 }
233 1 => {
234 self.clip_view.piano_roll.snap_enabled = !self.clip_view.piano_roll.snap_enabled;
236 }
237 2 => {
238 let v = self.clip_view.piano_roll.default_velocity as i32 + direction * 5;
240 self.clip_view.piano_roll.default_velocity = v.clamp(1, 127) as u8;
241 }
242 _ => {}
243 }
244 }
245
246 pub fn enter(&mut self) -> Option<SpaceAction> {
250 if self.space_menu.open {
252 match self.space_menu.section {
253 SpaceMenuSection::Actions => {
254 if let Some((key, _, _)) = SPACE_ACTIONS.get(self.space_menu.cursor) {
255 if let Some(ch) = key.strip_prefix("spc+").and_then(|s| s.chars().next()) {
257 return self.space_menu_handle(ch);
258 }
259 }
260 self.space_menu.open = false;
261 return None;
262 }
263 SpaceMenuSection::Help => {
264 return None;
266 }
267 }
268 }
269 if self.fx_menu.open {
271 self.fx_menu_select();
272 return None;
273 }
274
275 match self.focused_pane {
276 Pane::Transport => {} Pane::Tracks => {
278 if !self.track_selected {
279 self.track_selected = true;
280 self.track_element = TrackElement::Label;
281 self.show_current_track_controls();
282 } else {
283 self.activate_element();
284 }
285 }
286 Pane::ClipView => {}
287 }
288 None
289 }
290
291
292 pub fn escape(&mut self) {
293 if self.instrument_modal.open {
294 self.instrument_modal.open = false;
295 return;
296 }
297 if self.space_menu.open {
298 self.space_menu.open = false;
299 return;
300 }
301 if self.fx_menu.open {
302 self.fx_menu.open = false;
303 return;
304 }
305 match self.focused_pane {
306 Pane::Transport => {} Pane::Tracks => {
308 if self.clip_locked {
309 self.clip_locked = false;
311 } else if self.track_selected {
312 self.track_selected = false;
313 self.clip_locked = false;
314 self.track_element = TrackElement::Label;
315 self.clip_view_visible = false;
316 self.clip_view_target = None;
317 }
318 }
319 Pane::ClipView => self.focus_pane(Pane::Tracks),
320 }
321 }
322
323 pub fn cycle_tab(&mut self) {
329 if self.focused_pane != Pane::ClipView { return; }
330
331 match (self.clip_view.focus, self.clip_view.fx_panel_tab, self.clip_view.clip_tab) {
332 (ClipViewFocus::FxPanel, FxPanelTab::TrackFx, _) => {
334 self.clip_view.fx_panel_tab = FxPanelTab::Synth;
335 }
336 (ClipViewFocus::FxPanel, FxPanelTab::Synth, _) => {
338 self.clip_view.focus = ClipViewFocus::PianoRoll;
339 self.clip_view.clip_tab = ClipTab::InstConfig;
340 self.clip_view.inst_config_cursor = 0;
341 }
342 (ClipViewFocus::PianoRoll, _, ClipTab::InstConfig) => {
344 self.clip_view.clip_tab = ClipTab::PianoRoll;
345 self.clip_view.piano_roll.focus = PianoRollFocus::Navigation;
346 self.clip_view.piano_roll.column = 0;
347 }
348 (ClipViewFocus::PianoRoll, _, ClipTab::PianoRoll) => {
350 self.clip_view.clip_tab = ClipTab::Settings;
351 }
352 (ClipViewFocus::PianoRoll, _, ClipTab::Settings) => {
354 self.clip_view.focus = ClipViewFocus::FxPanel;
355 self.clip_view.fx_panel_tab = FxPanelTab::TrackFx;
356 self.clip_view.fx_cursor = 0;
357 }
358 }
359 }
360
361}