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