tangled
alpha
login
or
join now
inkreas.ing
/
torque-tracker
1
fork
atom
old school music tracker
1
fork
atom
overview
issues
pulls
pipelines
enable playback control from page menu
inkreas.ing
7 months ago
13268233
1fd0de95
+125
-110
8 changed files
expand all
collapse all
unified
split
src
app.rs
ui
dialog
page_menu.rs
header.rs
pages
order_list.rs
pattern.rs
sample_list.rs
song_directory_config_page.rs
pages.rs
+67
-26
src/app.rs
···
60
60
Header(HeaderEvent),
61
61
/// also closes all dialogs
62
62
GoToPage(PagesEnum),
63
63
+
Playback(PlaybackType),
63
64
CloseRequested,
64
65
CloseApp,
65
66
ConstRedraw,
66
67
}
67
68
69
69
+
impl Clone for GlobalEvent {
70
70
+
fn clone(&self) -> Self {
71
71
+
// TODO: make this really clone, once the Dialogs are an enum instead of Box dyn
72
72
+
match self {
73
73
+
GlobalEvent::OpenDialog(_) => panic!("TODO: don't clone this"),
74
74
+
GlobalEvent::Page(page_event) => GlobalEvent::Page(page_event.clone()),
75
75
+
GlobalEvent::Header(header_event) => GlobalEvent::Header(header_event.clone()),
76
76
+
GlobalEvent::GoToPage(pages_enum) => GlobalEvent::GoToPage(*pages_enum),
77
77
+
GlobalEvent::CloseRequested => GlobalEvent::CloseRequested,
78
78
+
GlobalEvent::CloseApp => GlobalEvent::CloseApp,
79
79
+
GlobalEvent::ConstRedraw => GlobalEvent::ConstRedraw,
80
80
+
GlobalEvent::Playback(playback_type) => GlobalEvent::Playback(*playback_type),
81
81
+
}
82
82
+
}
83
83
+
}
84
84
+
68
85
impl Debug for GlobalEvent {
69
86
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
70
87
let mut debug = f.debug_struct("GlobalEvent");
···
76
93
GlobalEvent::CloseRequested => debug.field("CloseRequested", &""),
77
94
GlobalEvent::CloseApp => debug.field("CloseApp", &""),
78
95
GlobalEvent::ConstRedraw => debug.field("ConstRedraw", &""),
96
96
+
GlobalEvent::Playback(playback_type) => debug.field("Playback", &playback_type),
79
97
};
80
98
debug.finish()
81
99
}
100
100
+
}
101
101
+
102
102
+
#[derive(Clone, Copy, Debug)]
103
103
+
pub enum PlaybackType {
104
104
+
Stop,
105
105
+
Song,
106
106
+
Pattern,
107
107
+
FromOrder,
108
108
+
FromCursor,
82
109
}
83
110
84
111
struct WorkerThreads {
···
253
280
return;
254
281
}
255
282
256
256
-
let message = if event.logical_key == Key::Named(NamedKey::F5) {
257
257
-
// play song from start
258
258
-
Some(ToWorkerMsg::Playback(PlaybackSettings::Order {
259
259
-
idx: 0,
260
260
-
should_loop: true,
261
261
-
}))
283
283
+
if event.logical_key == Key::Named(NamedKey::F5) {
284
284
+
self.event_queue
285
285
+
.push_back(GlobalEvent::Playback(PlaybackType::Song));
262
286
} else if event.logical_key == Key::Named(NamedKey::F6) {
263
263
-
Some(ToWorkerMsg::Playback(if modifiers.state().shift_key() {
264
264
-
// play the current order
265
265
-
self.header.play_current_order()
287
287
+
if modifiers.state().shift_key() {
288
288
+
self.event_queue
289
289
+
.push_back(GlobalEvent::Playback(PlaybackType::FromOrder));
266
290
} else {
267
267
-
// play the current pattern
268
268
-
self.header.play_current_pattern()
269
269
-
}))
291
291
+
self.event_queue
292
292
+
.push_back(GlobalEvent::Playback(PlaybackType::Pattern));
293
293
+
}
270
294
// TODO: add F7 handling
271
295
} else if event.logical_key == Key::Named(NamedKey::F8) {
272
272
-
Some(ToWorkerMsg::StopPlayback)
273
273
-
} else {
274
274
-
None
275
275
-
};
276
276
-
if let Some(msg) = message {
277
277
-
let result = AUDIO.lock_blocking().try_msg_worker(msg);
278
278
-
279
279
-
match result {
280
280
-
SendResult::Success => (),
281
281
-
SendResult::BufferFull => {
282
282
-
panic!("to worker buffer full, probably have to retry somehow")
283
283
-
}
284
284
-
SendResult::AudioInactive => panic!("audio should always be active"),
285
285
-
}
296
296
+
self.event_queue
297
297
+
.push_back(GlobalEvent::Playback(PlaybackType::Stop));
298
298
+
// TODO: allow F5 to also switch to the playback page, once it exists
286
299
} else {
287
300
// key_event didn't start or stop the song, so process normally
288
301
if let Some(dialog) = dialog_manager.active_dialog_mut() {
···
350
363
GlobalEvent::ConstRedraw => {
351
364
self.ui_pages.request_draw_const();
352
365
_ = self.try_request_redraw();
366
366
+
}
367
367
+
GlobalEvent::Playback(playback_type) => {
368
368
+
let msg = match playback_type {
369
369
+
PlaybackType::Song => Some(ToWorkerMsg::Playback(PlaybackSettings::Order {
370
370
+
idx: 0,
371
371
+
should_loop: true,
372
372
+
})),
373
373
+
PlaybackType::Stop => Some(ToWorkerMsg::StopPlayback),
374
374
+
PlaybackType::Pattern => {
375
375
+
Some(ToWorkerMsg::Playback(self.header.play_current_pattern()))
376
376
+
}
377
377
+
PlaybackType::FromOrder => {
378
378
+
Some(ToWorkerMsg::Playback(self.header.play_current_order()))
379
379
+
}
380
380
+
PlaybackType::FromCursor => None,
381
381
+
};
382
382
+
383
383
+
if let Some(msg) = msg {
384
384
+
let result = AUDIO.lock_blocking().try_msg_worker(msg);
385
385
+
386
386
+
match result {
387
387
+
SendResult::Success => (),
388
388
+
SendResult::BufferFull => {
389
389
+
panic!("to worker buffer full, probably have to retry somehow")
390
390
+
}
391
391
+
SendResult::AudioInactive => panic!("audio should always be active"),
392
392
+
}
393
393
+
}
353
394
}
354
395
}
355
396
}
+52
-78
src/ui/dialog/page_menu.rs
···
3
3
use winit::keyboard::{Key, NamedKey};
4
4
5
5
use crate::{
6
6
-
app::GlobalEvent,
6
6
+
app::{GlobalEvent, PlaybackType},
7
7
coordinates::{CharPosition, CharRect, FONT_SIZE, PixelRect},
8
8
draw_buffer::DrawBuffer,
9
9
ui::pages::PagesEnum,
···
11
11
12
12
use super::{Dialog, DialogResponse};
13
13
14
14
-
enum PageOrPageMenu {
14
14
+
enum Action {
15
15
Menu(Menu),
16
16
+
// TODO: maybe fold this into the more general event variant
16
17
Page(PagesEnum),
17
17
-
CloseApp,
18
18
-
// should be removed when possible
18
18
+
Event(GlobalEvent),
19
19
+
// TODO: should be removed when it's all implemented
19
20
NotYetImplemented,
20
21
}
21
22
···
33
34
rect: CharRect,
34
35
selected: usize,
35
36
pressed: bool,
36
36
-
buttons: &'static [(&'static str, PageOrPageMenu)],
37
37
+
buttons: &'static [(&'static str, Action)],
37
38
sub_menu: Option<Box<Self>>,
38
39
}
39
40
···
58
59
Self::BOTRIGHT_COLOR,
59
60
1,
60
61
);
61
61
-
for (num, (name, action)) in self.buttons.iter().enumerate() {
62
62
+
for (num, (name, _)) in self.buttons.iter().enumerate() {
62
63
let text_color = match self.selected == num {
63
64
true => 11,
64
65
false => 0,
···
112
113
} else if self.pressed {
113
114
self.pressed = false;
114
115
match &self.buttons[self.selected].1 {
115
115
-
PageOrPageMenu::Menu(menu) => {
116
116
+
Action::Menu(menu) => {
116
117
let menu = match menu {
117
118
Menu::File => Self::file(),
118
119
Menu::Playback => Self::playback(),
···
123
124
self.sub_menu = Some(Box::new(menu));
124
125
return DialogResponse::RequestRedraw;
125
126
}
126
126
-
PageOrPageMenu::Page(page) => {
127
127
+
Action::Page(page) => {
127
128
event.push_back(GlobalEvent::GoToPage(*page));
128
129
return DialogResponse::Close;
129
130
}
130
130
-
PageOrPageMenu::NotYetImplemented => {
131
131
+
Action::NotYetImplemented => {
131
132
println!("Not yet implementes");
132
133
return DialogResponse::RequestRedraw;
133
134
}
134
134
-
PageOrPageMenu::CloseApp => {
135
135
-
event.push_back(GlobalEvent::CloseRequested);
135
135
+
Action::Event(global_event) => {
136
136
+
event.push_back(global_event.clone());
136
137
return DialogResponse::Close;
137
138
}
138
139
}
···
165
166
name: &'static str,
166
167
pos: CharPosition,
167
168
width: usize,
168
168
-
buttons: &'static [(&'static str, PageOrPageMenu)],
169
169
+
buttons: &'static [(&'static str, Action)],
169
170
) -> Self {
170
171
let rect = CharRect::new(
171
172
pos.y(),
···
208
209
CharPosition::new(6, 11),
209
210
29,
210
211
&[
211
211
-
("File Menu...", PageOrPageMenu::Menu(Menu::File)),
212
212
-
("Playback Menu...", PageOrPageMenu::Menu(Menu::Playback)),
212
212
+
("File Menu...", Action::Menu(Menu::File)),
213
213
+
("Playback Menu...", Action::Menu(Menu::Playback)),
213
214
(
214
215
"View Patterns (F2)",
215
215
-
PageOrPageMenu::Page(PagesEnum::Pattern),
216
216
+
Action::Page(PagesEnum::Pattern),
216
217
),
217
217
-
("Sample Menu...", PageOrPageMenu::Menu(Menu::Sample)),
218
218
-
("Instrument Menu...", PageOrPageMenu::Menu(Menu::Instrument)),
218
218
+
("Sample Menu...", Action::Menu(Menu::Sample)),
219
219
+
("Instrument Menu...", Action::Menu(Menu::Instrument)),
219
220
(
220
221
"View Orders/Panning (F11)",
221
221
-
PageOrPageMenu::Page(PagesEnum::OrderList),
222
222
+
Action::Page(PagesEnum::OrderList),
222
223
),
223
224
(
224
225
"View Variables (F12)",
225
225
-
PageOrPageMenu::Page(PagesEnum::SongDirectoryConfig),
226
226
-
),
227
227
-
(
228
228
-
"Message Editor (Shift-F9)",
229
229
-
PageOrPageMenu::NotYetImplemented,
230
230
-
),
231
231
-
("Settings Menu...", PageOrPageMenu::Menu(Menu::Settings)),
232
232
-
(
233
233
-
"Help! (F1)",
234
234
-
PageOrPageMenu::Page(PagesEnum::Help),
226
226
+
Action::Page(PagesEnum::SongDirectoryConfig),
235
227
),
228
228
+
("Message Editor (Shift-F9)", Action::NotYetImplemented),
229
229
+
("Settings Menu...", Action::Menu(Menu::Settings)),
230
230
+
("Help! (F1)", Action::Page(PagesEnum::Help)),
236
231
],
237
232
)
238
233
}
···
243
238
CharPosition::new(25, 13),
244
239
26,
245
240
&[
246
246
-
("Load... (F9)", PageOrPageMenu::NotYetImplemented),
247
247
-
("New... (Ctrl-N)", PageOrPageMenu::NotYetImplemented),
248
248
-
("Save Current (Ctrl-S)", PageOrPageMenu::NotYetImplemented),
249
249
-
("Save As... (F10)", PageOrPageMenu::NotYetImplemented),
250
250
-
("Export... (Shift-F10)", PageOrPageMenu::NotYetImplemented),
251
251
-
("Message Log (Ctrl-F11)", PageOrPageMenu::NotYetImplemented),
252
252
-
("Quit (Ctrl-Q)", PageOrPageMenu::CloseApp),
241
241
+
("Load... (F9)", Action::NotYetImplemented),
242
242
+
("New... (Ctrl-N)", Action::NotYetImplemented),
243
243
+
("Save Current (Ctrl-S)", Action::NotYetImplemented),
244
244
+
("Save As... (F10)", Action::NotYetImplemented),
245
245
+
("Export... (Shift-F10)", Action::NotYetImplemented),
246
246
+
("Message Log (Ctrl-F11)", Action::NotYetImplemented),
247
247
+
(
248
248
+
"Quit (Ctrl-Q)",
249
249
+
Action::Event(GlobalEvent::CloseRequested),
250
250
+
),
253
251
],
254
252
)
255
253
}
···
260
258
CharPosition::new(25, 13),
261
259
31,
262
260
&[
263
263
-
(
264
264
-
"Show Infopage (F5)",
265
265
-
PageOrPageMenu::NotYetImplemented,
266
266
-
),
261
261
+
("Show Infopage (F5)", Action::NotYetImplemented),
267
262
(
268
263
"Play Song (Ctrl-F5)",
269
269
-
PageOrPageMenu::NotYetImplemented,
264
264
+
Action::Event(GlobalEvent::Playback(PlaybackType::Song)),
270
265
),
271
266
(
272
267
"Play Pattern (F6)",
273
273
-
PageOrPageMenu::NotYetImplemented,
268
268
+
Action::Event(GlobalEvent::Playback(PlaybackType::Pattern)),
274
269
),
275
270
(
276
271
"Play from Order (Shift-F6)",
277
277
-
PageOrPageMenu::NotYetImplemented,
272
272
+
Action::Event(GlobalEvent::Playback(PlaybackType::FromOrder)),
278
273
),
279
279
-
(
280
280
-
"Play from Mark/Cursor (F7)",
281
281
-
PageOrPageMenu::NotYetImplemented,
282
282
-
),
274
274
+
("Play from Mark/Cursor (F7)", Action::NotYetImplemented),
283
275
(
284
276
"Stop (F8)",
285
285
-
PageOrPageMenu::NotYetImplemented,
286
286
-
),
287
287
-
(
288
288
-
"Reinit Soundcard (Ctrl-I)",
289
289
-
PageOrPageMenu::NotYetImplemented,
290
290
-
),
291
291
-
(
292
292
-
"Driver Screen (Shift-F5)",
293
293
-
PageOrPageMenu::NotYetImplemented,
277
277
+
Action::Event(GlobalEvent::Playback(PlaybackType::Stop)),
294
278
),
295
295
-
(
296
296
-
"Calculate Length (Ctrl-P)",
297
297
-
PageOrPageMenu::NotYetImplemented,
298
298
-
),
279
279
+
("Reinit Soundcard (Ctrl-I)", Action::NotYetImplemented),
280
280
+
("Driver Screen (Shift-F5)", Action::NotYetImplemented),
281
281
+
("Calculate Length (Ctrl-P)", Action::NotYetImplemented),
299
282
],
300
283
)
301
284
}
···
308
291
&[
309
292
(
310
293
"Sample List (F3)",
311
311
-
PageOrPageMenu::Page(PagesEnum::SampleList),
312
312
-
),
313
313
-
(
314
314
-
"Sample Library (Ctrl-F3)",
315
315
-
PageOrPageMenu::NotYetImplemented,
294
294
+
Action::Page(PagesEnum::SampleList),
316
295
),
296
296
+
("Sample Library (Ctrl-F3)", Action::NotYetImplemented),
317
297
],
318
298
)
319
299
}
···
324
304
CharPosition::new(20, 23),
325
305
33,
326
306
&[
327
327
-
(
328
328
-
"Instrument List (F4)",
329
329
-
PageOrPageMenu::NotYetImplemented,
330
330
-
),
331
331
-
(
332
332
-
"Instrument Library (Ctrl-F4)",
333
333
-
PageOrPageMenu::NotYetImplemented,
334
334
-
),
307
307
+
("Instrument List (F4)", Action::NotYetImplemented),
308
308
+
("Instrument Library (Ctrl-F4)", Action::NotYetImplemented),
335
309
],
336
310
)
337
311
}
···
344
318
&[
345
319
(
346
320
"Preferences (Shift-F5)",
347
347
-
PageOrPageMenu::NotYetImplemented,
321
321
+
Action::NotYetImplemented,
348
322
),
349
323
(
350
324
"MIDI Configuration (Shift-F1)",
351
351
-
PageOrPageMenu::NotYetImplemented,
325
325
+
Action::NotYetImplemented,
352
326
),
353
327
(
354
328
"System Configuration (Ctrl-F1)",
355
355
-
PageOrPageMenu::NotYetImplemented,
329
329
+
Action::NotYetImplemented,
356
330
),
357
331
(
358
332
"Palette Editor (Ctrl-F12)",
359
359
-
PageOrPageMenu::NotYetImplemented,
333
333
+
Action::NotYetImplemented,
360
334
),
361
335
(
362
336
"Font Editor (Shift-F12)",
363
363
-
PageOrPageMenu::NotYetImplemented,
337
337
+
Action::NotYetImplemented,
364
338
),
365
339
(
366
340
"Toggle Fullscreen (Ctrl-Alt-Enter)",
367
367
-
PageOrPageMenu::NotYetImplemented,
341
341
+
Action::NotYetImplemented,
368
342
),
369
343
],
370
344
)
+1
-1
src/ui/header.rs
···
11
11
draw_buffer::DrawBuffer,
12
12
};
13
13
14
14
-
#[derive(Debug)]
14
14
+
#[derive(Debug, Clone)]
15
15
pub enum HeaderEvent {
16
16
SetCursorRow(u16),
17
17
SetMaxCursorRow(u16),
+1
-1
src/ui/pages.rs
···
126
126
SampleList,
127
127
}
128
128
129
129
-
#[derive(Debug)]
129
129
+
#[derive(Debug, Clone)]
130
130
pub enum PageEvent {
131
131
Sdc(SDCChange),
132
132
Pattern(PatternPageEvent),
+1
-1
src/ui/pages/order_list.rs
···
17
17
18
18
use super::{Page, PageEvent, PageResponse};
19
19
20
20
-
#[derive(Debug)]
20
20
+
#[derive(Debug, Clone)]
21
21
pub enum OrderListPageEvent {
22
22
SetVolumeCurrent(i16),
23
23
SetPanCurrent(i16),
+1
-1
src/ui/pages/pattern.rs
···
103
103
note.and_then(Result::ok)
104
104
}
105
105
106
106
-
#[derive(Debug)]
106
106
+
#[derive(Debug, Clone)]
107
107
pub enum PatternPageEvent {
108
108
Loaded(Pattern, u8),
109
109
SetSampleInstr(u8),
+1
-1
src/ui/pages/sample_list.rs
···
25
25
},
26
26
};
27
27
28
28
-
#[derive(Debug)]
28
28
+
#[derive(Debug, Clone)]
29
29
pub enum SampleListEvent {
30
30
SetSample(u8, String, SampleMetaData),
31
31
SelectSample(u8),
+1
-1
src/ui/pages/song_directory_config_page.rs
···
29
29
// Amiga,
30
30
// }
31
31
32
32
-
#[derive(Debug)]
32
32
+
#[derive(Debug, Clone)]
33
33
pub enum SDCChange {
34
34
SetSongName(String),
35
35
InitialTempo(i16),