Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Initial work on playback controls bar #144

Merged
merged 3 commits into from
Feb 18, 2024
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
31 changes: 28 additions & 3 deletions neothesia-core/src/render/text/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -30,9 +30,12 @@ pub struct TextRenderer {

impl TextRenderer {
pub fn new(gpu: &Gpu) -> Self {
let font_system = glyphon::FontSystem::new_with_fonts([glyphon::fontdb::Source::Binary(
Arc::new(include_bytes!("./Roboto-Regular.ttf")),
)]);
let font_system = glyphon::FontSystem::new_with_fonts([
glyphon::fontdb::Source::Binary(Arc::new(include_bytes!("./Roboto-Regular.ttf"))),
glyphon::fontdb::Source::Binary(Arc::new(include_bytes!(
"../../../../neothesia/src/iced_utils/bootstrap-icons.ttf"
))),
]);

let cache = glyphon::SwashCache::new();
let mut atlas = glyphon::TextAtlas::new(&gpu.device, &gpu.queue, gpu.texture_format);
Expand Down Expand Up @@ -91,6 +94,28 @@ impl TextRenderer {
});
}

pub fn queue_icon(&mut self, x: f32, y: f32, size: f32, icon: &str) {
let mut buffer =
glyphon::Buffer::new(&mut self.font_system, glyphon::Metrics::new(size, size));
buffer.set_size(&mut self.font_system, f32::MAX, f32::MAX);
buffer.set_text(
&mut self.font_system,
icon,
glyphon::Attrs::new().family(glyphon::Family::Name("bootstrap-icons")),
glyphon::Shaping::Basic,
);
buffer.shape_until_scroll(&mut self.font_system);

self.queue(TextArea {
buffer,
left: x,
top: y,
scale: 1.0,
bounds: glyphon::TextBounds::default(),
default_color: glyphon::Color::rgb(255, 255, 255),
});
}

pub fn queue_fps(&mut self, fps: f64) {
let text = format!("FPS: {}", fps.round() as u32);
let mut buffer =
Expand Down
Binary file modified neothesia/src/iced_utils/bootstrap-icons.ttf
Binary file not shown.
4 changes: 2 additions & 2 deletions neothesia/src/scene/menu_scene/icons.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,11 @@ use super::Renderer;
static ICONS: iced_core::Font = iced_core::Font::with_name("bootstrap-icons");

pub fn play_icon<'a>() -> iced_widget::Text<'a, Theme, Renderer> {
iced_widget::text('\u{f49d}').font(ICONS)
iced_widget::text('\u{f4f4}').font(ICONS)
}

pub fn note_list_icon<'a>() -> iced_widget::Text<'a, Theme, Renderer> {
iced_widget::text('\u{f451}').font(ICONS)
iced_widget::text('\u{f49f}').font(ICONS)
}

pub fn left_arrow_icon<'a>() -> iced_widget::Text<'a, Theme, Renderer> {
Expand Down
18 changes: 14 additions & 4 deletions neothesia/src/scene/playing_scene/midi_player.rs
Original file line number Diff line number Diff line change
Expand Up @@ -117,7 +117,7 @@ impl MidiPlayer {
}
}

fn set_time(&mut self, time: Duration) {
pub fn set_time(&mut self, time: Duration) {
self.playback.set_time(time);

// Discard all of the events till that point
Expand All @@ -142,10 +142,16 @@ impl MidiPlayer {
self.set_time(time);
}

pub fn percentage_to_time(&self, p: f32) -> Duration {
Duration::from_secs_f32((p * self.playback.lenght().as_secs_f32()).max(0.0))
}

pub fn time_to_percentage(&self, time: &Duration) -> f32 {
time.as_secs_f32() / self.playback.lenght().as_secs_f32()
}

pub fn set_percentage_time(&mut self, p: f32) {
self.set_time(Duration::from_secs_f32(
(p * self.playback.lenght().as_secs_f32()).max(0.0),
));
self.set_time(self.percentage_to_time(p));
}

pub fn leed_in(&self) -> &Duration {
Expand All @@ -160,6 +166,10 @@ impl MidiPlayer {
self.playback.percentage()
}

pub fn time(&self) -> Duration {
self.playback.time()
}

pub fn time_without_lead_in(&self) -> f32 {
self.playback.time().as_secs_f32() - self.playback.leed_in().as_secs_f32()
}
Expand Down
16 changes: 14 additions & 2 deletions neothesia/src/scene/playing_scene/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,9 @@ use toast_manager::ToastManager;
mod animation;
mod top_bar;

const EVENT_CAPTURED: bool = true;
const EVENT_IGNORED: bool = false;

pub struct PlayingScene {
keyboard: Keyboard,
waterfall: WaterfallRenderer,
Expand Down Expand Up @@ -89,11 +92,16 @@ impl PlayingScene {
bg_quad_pipeline: QuadPipeline::new(&target.gpu, &target.transform),
fg_quad_pipeline: QuadPipeline::new(&target.gpu, &target.transform),
toast_manager: ToastManager::default(),
top_bar: TopBar::default(),
top_bar: TopBar::new(),
}
}

fn update_midi_player(&mut self, target: &Target, delta: Duration) -> f32 {
if self.top_bar.loop_active && self.player.time() > self.top_bar.loop_end {
self.player.set_time(self.top_bar.loop_start);
self.keyboard.reset_notes();
}

if self.player.play_along().are_required_keys_pressed() {
let delta = (delta / 10) * (target.config.speed_multiplier * 10.0) as u32;
let midi_events = self.player.update(delta);
Expand Down Expand Up @@ -135,7 +143,7 @@ impl Scene for PlayingScene {
self.keyboard
.update(&mut self.fg_quad_pipeline, &mut target.text_renderer);

TopBar::update(self, &target.window_state);
TopBar::update(self, &target.window_state, &mut target.text_renderer);

self.bg_quad_pipeline.prepare(&target.gpu.queue);
self.fg_quad_pipeline.prepare(&target.gpu.queue);
Expand All @@ -152,6 +160,10 @@ impl Scene for PlayingScene {
}

fn window_event(&mut self, target: &mut Target, event: &WindowEvent) {
if TopBar::handle_window_event(self, target, event) {
return;
}

self.rewind_controler
.handle_window_event(target, event, &mut self.player);

Expand Down
40 changes: 3 additions & 37 deletions neothesia/src/scene/playing_scene/rewind_controller.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use winit::{
dpi::PhysicalPosition,
event::{ElementState, MouseButton, WindowEvent},
event::{ElementState, WindowEvent},
};

use super::MidiPlayer;
Expand All @@ -21,7 +21,7 @@ impl RewindController {
!matches!(self, RewindController::None)
}

fn start_mouse_rewind(&mut self, player: &mut MidiPlayer) {
pub fn start_mouse_rewind(&mut self, player: &mut MidiPlayer) {
let was_paused = player.is_paused();
self.start_rewind(player, RewindController::Mouse { was_paused });
}
Expand All @@ -36,7 +36,7 @@ impl RewindController {
*self = controller;
}

fn stop_rewind(&mut self, player: &mut MidiPlayer) {
pub fn stop_rewind(&mut self, player: &mut MidiPlayer) {
let controller = std::mem::replace(self, RewindController::None);

let was_paused = match controller {
Expand Down Expand Up @@ -72,9 +72,6 @@ impl RewindController {
WindowEvent::KeyboardInput { event, .. } => {
self.handle_keyboard_input(player, event);
}
WindowEvent::MouseInput { state, button, .. } => {
self.handle_mouse_input(player, &target.window_state, state, button);
}
WindowEvent::CursorMoved { position, .. } => {
self.handle_cursor_moved(player, &target.window_state, position);
}
Expand Down Expand Up @@ -118,37 +115,6 @@ impl RewindController {
}
}

fn handle_mouse_input(
&mut self,
player: &mut MidiPlayer,
window_state: &WindowState,
state: &ElementState,
button: &MouseButton,
) {
match (state, button) {
(ElementState::Pressed, MouseButton::Left) => {
let pos = &window_state.cursor_logical_position;

if pos.y < 45.0 && !self.is_rewinding() {
self.start_mouse_rewind(player);

let x = window_state.cursor_logical_position.x;
let w = window_state.logical_size.width;

let p = x / w;
log::debug!("Progressbar: x:{},p:{}", x, p);
player.set_percentage_time(p);
}
}
(ElementState::Released, MouseButton::Left) => {
if let RewindController::Mouse { .. } = self {
self.stop_rewind(player);
}
}
_ => {}
}
}

fn handle_cursor_moved(
&mut self,
player: &mut MidiPlayer,
Expand Down
Loading
Loading