Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 16 additions & 0 deletions neothesia/src/scene/menu_scene/iced_menu/exit.rs
Original file line number Diff line number Diff line change
Expand Up @@ -47,4 +47,20 @@ impl Page for ExitPage {

center_x(controls).center_y().into()
}

fn keyboard_input(event: &iced_runtime::keyboard::Event, _ctx: &Context) -> Option<Message> {
use iced_runtime::keyboard::{key::Named, Event, Key};

match event {
Event::KeyPressed {
key: Key::Named(key),
..
} => match key {
Named::Enter => Some(Message::ExitApp),
Named::Escape => Some(Message::GoBack),
_ => None,
},
_ => None,
}
}
}
214 changes: 214 additions & 0 deletions neothesia/src/scene/menu_scene/iced_menu/main.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,214 @@
use std::path::PathBuf;

use iced_core::{
alignment::{Horizontal, Vertical},
Alignment, Length, Padding,
};
use iced_runtime::Command;
use iced_widget::{column, container, image, row, text};
use neothesia_iced_widgets::{BarLayout, Layout, NeoBtn};

use crate::{context::Context, scene::menu_scene::icons, song::Song};

use super::{page::Page, top_padded, Data, Message, Step};

#[derive(Debug, Clone)]
pub enum Event {
Play,
GoToPage(Step),
MidiFilePicker(MidiFilePickerMessage),
}

pub struct MainPage;

impl Page for MainPage {
type Event = Event;

fn update(data: &mut Data, msg: Self::Event, ctx: &mut Context) -> Command<Message> {
let msg = match msg {
Event::Play => Message::Play,
Event::GoToPage(step) => Message::GoToPage(step),
Event::MidiFilePicker(msg) => return midi_file_picker_update(data, msg, ctx),
};

Command::perform(async {}, move |_| msg)
}

fn view<'a>(data: &'a Data, ctx: &Context) -> neothesia_iced_widgets::Element<'a, Self::Event> {
let buttons = column![
NeoBtn::new_with_label("Select File")
.on_press(Event::MidiFilePicker(MidiFilePickerMessage::open()))
.width(Length::Fill)
.height(Length::Fixed(80.0)),
NeoBtn::new_with_label("Settings")
.on_press(Event::GoToPage(Step::Settings))
.width(Length::Fill)
.height(Length::Fixed(80.0)),
NeoBtn::new_with_label("Exit")
.on_press(Event::GoToPage(Step::Exit))
.width(Length::Fill)
.height(Length::Fixed(80.0)),
]
.width(Length::Fixed(450.0))
.spacing(10);

let column = column![image(data.logo_handle.clone()), buttons]
.spacing(40)
.align_items(Alignment::Center);

let mut layout = Layout::new().body(top_padded(column));

if let Some(song) = ctx.song.as_ref() {
let tracks = NeoBtn::new(
icons::note_list_icon()
.size(30.0)
.vertical_alignment(Vertical::Center)
.horizontal_alignment(Horizontal::Center),
)
.height(Length::Fixed(60.0))
.min_width(80.0)
.on_press(Event::GoToPage(Step::TrackSelection));

let play = NeoBtn::new(
icons::play_icon()
.size(30.0)
.vertical_alignment(Vertical::Center)
.horizontal_alignment(Horizontal::Center),
)
.height(Length::Fixed(60.0))
.min_width(80.0)
.on_press(Event::Play);

let row = row![tracks, play]
.spacing(10)
.align_items(Alignment::Center);

let container = container(row)
.width(Length::Fill)
.align_x(Horizontal::Right)
.padding(Padding {
top: 0.0,
right: 10.0,
bottom: 10.0,
left: 0.0,
});

layout = layout.bottom(
BarLayout::new()
.center(
text(&song.file.name)
.width(Length::Fill)
.vertical_alignment(Vertical::Center)
.horizontal_alignment(Horizontal::Center),
)
.right(container),
);
}

layout.into()
}

fn keyboard_input(event: &iced_runtime::keyboard::Event, _ctx: &Context) -> Option<Message> {
use iced_runtime::keyboard::{key::Named, Event, Key};

match event {
Event::KeyPressed {
key: Key::Named(key),
..
} => match key {
Named::Tab => Some(MidiFilePickerMessage::open().into()),
Named::Enter => Some(Message::Play),
Named::Escape => Some(Message::GoBack),
_ => None,
},
Event::KeyPressed {
key: Key::Character(ch),
..
} => match ch.as_ref() {
"s" => Some(Message::GoToPage(Step::Settings)),
"t" => Some(Message::GoToPage(Step::TrackSelection)),
_ => None,
},
_ => None,
}
}
}

#[derive(Debug, Clone)]
pub enum MidiFilePickerMessage {
OpenMidiFilePicker,
MidiFileLoaded(Option<(midi_file::MidiFile, PathBuf)>),
}

impl MidiFilePickerMessage {
pub(super) fn open() -> Self {
Self::OpenMidiFilePicker
}
}

impl From<MidiFilePickerMessage> for Message {
fn from(msg: MidiFilePickerMessage) -> Self {
Message::MainPage(super::main::Event::MidiFilePicker(msg))
}
}

fn midi_file_picker_update(
data: &mut Data,
msg: MidiFilePickerMessage,
ctx: &mut Context,
) -> Command<Message> {
match msg {
MidiFilePickerMessage::OpenMidiFilePicker => {
data.is_loading = true;
return open_midi_file_picker(|v| MidiFilePickerMessage::MidiFileLoaded(v).into());
}
MidiFilePickerMessage::MidiFileLoaded(midi) => {
if let Some((midi, path)) = midi {
ctx.config.last_opened_song = Some(path);
ctx.song = Some(Song::new(midi));
}
data.is_loading = false;
}
}

Command::none()
}

fn open_midi_file_picker(
f: impl FnOnce(Option<(midi_file::MidiFile, PathBuf)>) -> Message + 'static + Send,
) -> Command<Message> {
Command::perform(
async {
let file = rfd::AsyncFileDialog::new()
.add_filter("midi", &["mid", "midi"])
.pick_file()
.await;

if let Some(file) = file {
log::info!("File path = {:?}", file.path());

let thread = async_thread::Builder::new()
.name("midi-loader".into())
.spawn(move || {
let midi = midi_file::MidiFile::new(file.path());

if let Err(e) = &midi {
log::error!("{}", e);
}

midi.map(|midi| (midi, file.path().to_path_buf())).ok()
});

if let Ok(thread) = thread {
thread.join().await.ok().flatten()
} else {
None
}
} else {
log::info!("User canceled dialog");
None
}
},
f,
)
}
84 changes: 0 additions & 84 deletions neothesia/src/scene/menu_scene/iced_menu/midi_file_picker.rs

This file was deleted.

Loading