add play/pause/stop button to status bar and idle display

This commit is contained in:
Mark 2023-11-25 17:02:35 +01:00
parent 3e86ba921e
commit 168f51a5fc
5 changed files with 241 additions and 10 deletions

View File

@ -31,11 +31,8 @@ font = ''
status_bar = '''\t status_bar = '''\t
\s0.5;?\A#\c505050by \c593D6E\A##?\a#?\A# ##\c505050on \c264524\a##\c808080?%>Year=%# (%>Year=%)## | \d''' \s0.5;?\A#\c505050by \c593D6E\A##?\a#?\A# ##\c505050on \c264524\a##\c808080?%>Year=%# (%>Year=%)## | \d'''
idle_top = '\t' idle_top = '''\t \s0.5;\c505050(\d?%>Genre=%#, %>Genre=%##)
?\A#\c505050by \c593D6E\A##?\a#?\A# ##\c505050on \c264524\a##\c808080?%>Year=%# (%>Year=%)##'''
idle_side1 = '''?\A#\c505050by \c593D6E\A## idle_side1 = ''
?\a#\c505050on \c264524\a##''' idle_side2 = ''
idle_side2 = '''
\c505050\d
%>Year=%
%>Genre=% '''

View File

@ -8,6 +8,7 @@ use crate::{
gui_anim::AnimationController, gui_anim::AnimationController,
gui_base::Button, gui_base::Button,
gui_playback::{get_right_x, image_display, CurrentInfo}, gui_playback::{get_right_x, image_display, CurrentInfo},
gui_playpause::PlayPause,
gui_text::{AdvancedLabel, Label}, gui_text::{AdvancedLabel, Label},
}; };
@ -20,6 +21,7 @@ pub struct IdleDisplay {
c_top_label: AdvancedLabel, c_top_label: AdvancedLabel,
c_side1_label: AdvancedLabel, c_side1_label: AdvancedLabel,
c_side2_label: AdvancedLabel, c_side2_label: AdvancedLabel,
c_buttons: PlayPause,
cover_aspect_ratio: AnimationController<f32>, cover_aspect_ratio: AnimationController<f32>,
artist_image_aspect_ratio: AnimationController<f32>, artist_image_aspect_ratio: AnimationController<f32>,
cover_left: f32, cover_left: f32,
@ -33,6 +35,7 @@ pub struct IdleDisplay {
impl IdleDisplay { impl IdleDisplay {
pub fn new(config: GuiElemCfg) -> Self { pub fn new(config: GuiElemCfg) -> Self {
let cover_bottom = 0.79;
Self { Self {
config, config,
idle_mode: 0.0, idle_mode: 0.0,
@ -56,6 +59,7 @@ impl IdleDisplay {
), ),
c_side1_label: AdvancedLabel::new(GuiElemCfg::default(), Vec2::new(0.0, 0.5), vec![]), c_side1_label: AdvancedLabel::new(GuiElemCfg::default(), Vec2::new(0.0, 0.5), vec![]),
c_side2_label: AdvancedLabel::new(GuiElemCfg::default(), Vec2::new(0.0, 0.5), vec![]), c_side2_label: AdvancedLabel::new(GuiElemCfg::default(), Vec2::new(0.0, 0.5), vec![]),
c_buttons: PlayPause::new(GuiElemCfg::default()),
cover_aspect_ratio: AnimationController::new( cover_aspect_ratio: AnimationController::new(
1.0, 1.0,
1.0, 1.0,
@ -76,7 +80,7 @@ impl IdleDisplay {
), ),
cover_left: 0.01, cover_left: 0.01,
cover_top: 0.21, cover_top: 0.21,
cover_bottom: 0.79, cover_bottom,
artist_image_top: 0.5, artist_image_top: 0.5,
artist_image_to_cover_margin: 0.01, artist_image_to_cover_margin: 0.01,
} }
@ -91,6 +95,7 @@ impl GuiElem for IdleDisplay {
self.c_top_label.elem_mut(), self.c_top_label.elem_mut(),
self.c_side1_label.elem_mut(), self.c_side1_label.elem_mut(),
self.c_side2_label.elem_mut(), self.c_side2_label.elem_mut(),
self.c_buttons.elem_mut(),
] ]
.into_iter(), .into_iter(),
) )
@ -256,6 +261,14 @@ impl GuiElem for IdleDisplay {
); );
self.c_side2_label.config_mut().pos = self.c_side2_label.config_mut().pos =
Rectangle::from_tuples((left, ai_top), (max_right, bottom)); Rectangle::from_tuples((left, ai_top), (max_right, bottom));
// limit width of c_buttons
let buttons_right_pos = 0.99;
let buttons_width_max = info.pos.height() * 0.08 / 0.3 / info.pos.width();
let buttons_width = buttons_width_max.min(0.2);
self.c_buttons.config_mut().pos = Rectangle::from_tuples(
(buttons_right_pos - buttons_width, 0.86),
(buttons_right_pos, 0.94),
);
} }
} }
fn config(&self) -> &GuiElemCfg { fn config(&self) -> &GuiElemCfg {

View File

@ -0,0 +1,207 @@
use musicdb_lib::server::Command;
use speedy2d::{color::Color, dimen::Vec2, shape::Rectangle, Graphics2D};
use crate::{
gui::{DrawInfo, GuiAction, GuiElem, GuiElemCfg},
gui_base::{Button, Panel},
};
pub struct PlayPause {
config: GuiElemCfg,
to_zero: Button<[Panel<()>; 1]>,
play_pause: Button<[PlayPauseDisplay; 1]>,
to_end: Button<[NextSongShape; 1]>,
}
impl PlayPause {
pub fn new(config: GuiElemCfg) -> Self {
Self {
config,
to_zero: Button::new(
GuiElemCfg::at(Rectangle::from_tuples((0.0, 0.0), (0.3, 1.0))),
|_| vec![GuiAction::SendToServer(Command::Stop)],
[Panel::with_background(
GuiElemCfg::at(Rectangle::from_tuples((0.2, 0.2), (0.8, 0.8))),
(),
Color::MAGENTA,
)],
),
play_pause: Button::new(
GuiElemCfg::at(Rectangle::from_tuples((0.35, 0.0), (0.65, 1.0))),
|btn| {
vec![GuiAction::SendToServer(if btn.children[0].is_playing {
Command::Pause
} else {
Command::Resume
})]
},
[PlayPauseDisplay::new(GuiElemCfg::at(
Rectangle::from_tuples((0.2, 0.2), (0.8, 0.8)),
))],
),
to_end: Button::new(
GuiElemCfg::at(Rectangle::from_tuples((0.7, 0.0), (1.0, 1.0))),
|_| vec![GuiAction::SendToServer(Command::NextSong)],
[NextSongShape::new(GuiElemCfg::at(Rectangle::from_tuples(
(0.2, 0.2),
(0.8, 0.8),
)))],
),
}
}
}
struct PlayPauseDisplay {
config: GuiElemCfg,
is_playing: bool,
}
impl PlayPauseDisplay {
pub fn new(config: GuiElemCfg) -> Self {
Self {
config,
is_playing: false,
}
}
}
impl GuiElem for PlayPauseDisplay {
fn draw(&mut self, info: &mut DrawInfo, g: &mut Graphics2D) {
self.is_playing = info.database.playing;
if info.database.playing {
g.draw_rectangle(
Rectangle::from_tuples(
(
info.pos.top_left().x + info.pos.width() * 0.2,
info.pos.top_left().y,
),
(
info.pos.top_left().x + info.pos.width() * 0.4,
info.pos.bottom_right().y,
),
),
Color::BLUE,
);
g.draw_rectangle(
Rectangle::from_tuples(
(
info.pos.bottom_right().x - info.pos.width() * 0.4,
info.pos.top_left().y,
),
(
info.pos.bottom_right().x - info.pos.width() * 0.2,
info.pos.bottom_right().y,
),
),
Color::BLUE,
);
} else {
g.draw_triangle(
[
*info.pos.top_left(),
Vec2::new(
info.pos.bottom_right().x,
(info.pos.top_left().y + info.pos.bottom_right().y) / 2.0,
),
info.pos.bottom_left(),
],
Color::GREEN,
);
}
}
fn config(&self) -> &GuiElemCfg {
&self.config
}
fn config_mut(&mut self) -> &mut GuiElemCfg {
&mut self.config
}
fn children(&mut self) -> Box<dyn Iterator<Item = &mut dyn GuiElem> + '_> {
Box::new([].into_iter())
}
fn any(&self) -> &dyn std::any::Any {
self
}
fn any_mut(&mut self) -> &mut dyn std::any::Any {
self
}
fn elem(&self) -> &dyn GuiElem {
self
}
fn elem_mut(&mut self) -> &mut dyn GuiElem {
self
}
}
struct NextSongShape {
config: GuiElemCfg,
}
impl NextSongShape {
pub fn new(config: GuiElemCfg) -> Self {
Self { config }
}
}
impl GuiElem for NextSongShape {
fn draw(&mut self, info: &mut DrawInfo, g: &mut Graphics2D) {
let top = *info.pos.top_left();
let bottom = info.pos.bottom_left();
let right = Vec2::new(info.pos.bottom_right().x, (top.y + bottom.y) / 2.0);
g.draw_triangle([top, right, bottom], Color::CYAN);
let half_width = info.pos.width() * 0.04;
let top_right = Vec2::new(info.pos.top_right().x - half_width, info.pos.top_left().y);
let bottom_right = Vec2::new(
info.pos.top_right().x - half_width,
info.pos.bottom_right().y,
);
g.draw_line(top_right, bottom_right, 2.0 * half_width, Color::CYAN);
}
fn config(&self) -> &GuiElemCfg {
&self.config
}
fn config_mut(&mut self) -> &mut GuiElemCfg {
&mut self.config
}
fn children(&mut self) -> Box<dyn Iterator<Item = &mut dyn GuiElem> + '_> {
Box::new([].into_iter())
}
fn any(&self) -> &dyn std::any::Any {
self
}
fn any_mut(&mut self) -> &mut dyn std::any::Any {
self
}
fn elem(&self) -> &dyn GuiElem {
self
}
fn elem_mut(&mut self) -> &mut dyn GuiElem {
self
}
}
impl GuiElem for PlayPause {
fn config(&self) -> &GuiElemCfg {
&self.config
}
fn config_mut(&mut self) -> &mut GuiElemCfg {
&mut self.config
}
fn children(&mut self) -> Box<dyn Iterator<Item = &mut dyn GuiElem> + '_> {
Box::new(
[
self.to_zero.elem_mut(),
self.play_pause.elem_mut(),
self.to_end.elem_mut(),
]
.into_iter(),
)
}
fn any(&self) -> &dyn std::any::Any {
self
}
fn any_mut(&mut self) -> &mut dyn std::any::Any {
self
}
fn elem(&self) -> &dyn GuiElem {
self
}
fn elem_mut(&mut self) -> &mut dyn GuiElem {
self
}
}

View File

@ -5,7 +5,9 @@ use speedy2d::{color::Color, dimen::Vec2, shape::Rectangle};
use crate::{ use crate::{
gui::{DrawInfo, GuiElem, GuiElemCfg}, gui::{DrawInfo, GuiElem, GuiElemCfg},
gui_anim::AnimationController, gui_anim::AnimationController,
gui_base::Panel,
gui_playback::{image_display, CurrentInfo}, gui_playback::{image_display, CurrentInfo},
gui_playpause::PlayPause,
gui_text::AdvancedLabel, gui_text::AdvancedLabel,
}; };
@ -15,6 +17,7 @@ pub struct StatusBar {
current_info: CurrentInfo, current_info: CurrentInfo,
cover_aspect_ratio: AnimationController<f32>, cover_aspect_ratio: AnimationController<f32>,
c_song_label: AdvancedLabel, c_song_label: AdvancedLabel,
c_buttons: PlayPause,
} }
impl StatusBar { impl StatusBar {
@ -33,13 +36,14 @@ impl StatusBar {
Instant::now(), Instant::now(),
), ),
c_song_label: AdvancedLabel::new(GuiElemCfg::default(), Vec2::new(0.0, 0.5), vec![]), c_song_label: AdvancedLabel::new(GuiElemCfg::default(), Vec2::new(0.0, 0.5), vec![]),
c_buttons: PlayPause::new(GuiElemCfg::default()),
} }
} }
} }
impl GuiElem for StatusBar { impl GuiElem for StatusBar {
fn children(&mut self) -> Box<dyn Iterator<Item = &mut dyn GuiElem> + '_> { fn children(&mut self) -> Box<dyn Iterator<Item = &mut dyn GuiElem> + '_> {
Box::new([self.c_song_label.elem_mut()].into_iter()) Box::new([self.c_song_label.elem_mut(), self.c_buttons.elem_mut()].into_iter())
} }
fn draw(&mut self, info: &mut DrawInfo, g: &mut speedy2d::Graphics2D) { fn draw(&mut self, info: &mut DrawInfo, g: &mut speedy2d::Graphics2D) {
self.current_info.update(info, g); self.current_info.update(info, g);
@ -71,12 +75,20 @@ impl GuiElem for StatusBar {
if let Some(h) = &info.helper { if let Some(h) = &info.helper {
h.request_redraw(); h.request_redraw();
} }
// limit width of c_buttons
let buttons_right_pos = 0.99;
let buttons_width_max = info.pos.height() * 0.7 / 0.3 / info.pos.width();
let buttons_width = buttons_width_max.min(0.2);
self.c_buttons.config_mut().pos = Rectangle::from_tuples(
(buttons_right_pos - buttons_width, 0.15),
(buttons_right_pos, 0.85),
);
self.c_song_label.config_mut().pos = Rectangle::from_tuples( self.c_song_label.config_mut().pos = Rectangle::from_tuples(
( (
self.cover_aspect_ratio.value * info.pos.height() / info.pos.width(), self.cover_aspect_ratio.value * info.pos.height() / info.pos.width(),
0.0, 0.0,
), ),
(1.0, 1.0), (buttons_right_pos - buttons_width, 1.0),
); );
} }
// draw cover // draw cover

View File

@ -34,6 +34,8 @@ mod gui_notif;
#[cfg(feature = "speedy2d")] #[cfg(feature = "speedy2d")]
mod gui_playback; mod gui_playback;
#[cfg(feature = "speedy2d")] #[cfg(feature = "speedy2d")]
mod gui_playpause;
#[cfg(feature = "speedy2d")]
mod gui_queue; mod gui_queue;
#[cfg(feature = "speedy2d")] #[cfg(feature = "speedy2d")]
mod gui_screen; mod gui_screen;