1
0
Fork 0
mirror of https://github.com/Zedfrigg/ironbar.git synced 2025-07-01 10:41:03 +02:00

feat(music): support for using images in name_map, additional icon options

This commit is contained in:
Jake Stanger 2023-01-29 22:49:22 +00:00
parent b054c17d14
commit 96141d4990
No known key found for this signature in database
GPG key ID: C51FC8F9CB0BEA61
3 changed files with 158 additions and 79 deletions

View file

@ -8,12 +8,34 @@ pub struct Icons {
/// Icon to display when playing.
#[serde(default = "default_icon_play")]
pub(crate) play: String,
/// Icon to display when paused.
#[serde(default = "default_icon_pause")]
pub(crate) pause: String,
/// Icon to display for previous button.
#[serde(default = "default_icon_prev")]
pub(crate) prev: String,
/// Icon to display for next button.
#[serde(default = "default_icon_next")]
pub(crate) next: String,
/// Icon to display under volume slider
#[serde(default = "default_icon_volume")]
pub(crate) volume: String,
/// Icon to display nex to track title
#[serde(default = "default_icon_track")]
pub(crate) track: String,
/// Icon to display nex to album name
#[serde(default = "default_icon_album")]
pub(crate) album: String,
/// Icon to display nex to artist name
#[serde(default = "default_icon_artist")]
pub(crate) artist: String,
}
impl Default for Icons {
@ -21,7 +43,12 @@ impl Default for Icons {
Self {
pause: default_icon_pause(),
play: default_icon_play(),
prev: default_icon_prev(),
next: default_icon_next(),
volume: default_icon_volume(),
track: default_icon_track(),
album: default_icon_album(),
artist: default_icon_artist(),
}
}
}
@ -73,7 +100,7 @@ fn default_socket() -> String {
}
fn default_format() -> String {
String::from("{icon} {title} / {artist}")
String::from("{title} / {artist}")
}
fn default_icon_play() -> String {
@ -84,10 +111,30 @@ fn default_icon_pause() -> String {
String::from("")
}
fn default_icon_prev() -> String {
String::from("\u{f9ad}")
}
fn default_icon_next() -> String {
String::from("\u{f9ac}")
}
fn default_icon_volume() -> String {
String::from("")
}
fn default_icon_track() -> String {
String::from("\u{f886}")
}
fn default_icon_album() -> String {
String::from("\u{f524}")
}
fn default_icon_artist() -> String {
String::from("\u{fd01}")
}
fn default_music_dir() -> PathBuf {
audio_dir().unwrap_or_else(|| home_dir().map(|dir| dir.join("Music")).unwrap_or_default())
}

View file

@ -1,7 +1,7 @@
mod config;
use crate::clients::music::{self, MusicClient, PlayerState, PlayerUpdate, Status, Track};
use crate::image::ImageProvider;
use crate::image::{new_icon_button, new_icon_label, ImageProvider};
use crate::modules::{Module, ModuleInfo, ModuleUpdateEvent, ModuleWidget, WidgetContext};
use crate::popup::Popup;
use crate::{send_async, try_send};
@ -18,7 +18,7 @@ use tokio::sync::mpsc::{Receiver, Sender};
use tracing::error;
pub use self::config::MusicModule;
use self::config::{Icons, PlayerType};
use self::config::PlayerType;
#[derive(Debug)]
pub enum PlayerCommand {
@ -80,7 +80,6 @@ impl Module<Button> for MusicModule {
mut rx: Receiver<Self::ReceiveMessage>,
) -> Result<()> {
let format = self.format.clone();
let icons = self.icons.clone();
let re = Regex::new(r"\{([\w-]+)}")?;
let tokens = get_tokens(&re, self.format.as_str());
@ -102,13 +101,8 @@ impl Module<Button> for MusicModule {
match update {
PlayerUpdate::Update(track, status) => match *track {
Some(track) => {
let display_string = replace_tokens(
format.as_str(),
&tokens,
&track,
&status,
&icons,
);
let display_string =
replace_tokens(format.as_str(), &tokens, &track, &status);
let update = SongUpdate {
song: track,
@ -160,15 +154,22 @@ impl Module<Button> for MusicModule {
info: &ModuleInfo,
) -> Result<ModuleWidget<Button>> {
let button = Button::new();
let button_contents = gtk::Box::new(Orientation::Horizontal, 5);
button.add(&button_contents);
let icon_play = new_icon_label(&self.icons.play, info.icon_theme, 24);
let icon_pause = new_icon_label(&self.icons.pause, info.icon_theme, 24);
let label = Label::new(None);
label.set_angle(info.bar_position.get_angle());
if let Some(truncate) = self.truncate {
truncate.truncate_label(&label);
}
button.add(&label);
button_contents.add(&icon_pause);
button_contents.add(&icon_play);
button_contents.add(&label);
let orientation = info.bar_position.get_orientation();
@ -190,6 +191,21 @@ impl Module<Button> for MusicModule {
context.widget_rx.attach(None, move |mut event| {
if let Some(event) = event.take() {
label.set_label(&event.display_string);
match event.status.state {
PlayerState::Playing => {
icon_play.show();
icon_pause.hide();
}
PlayerState::Paused => {
icon_pause.show();
icon_play.hide();
}
PlayerState::Stopped => {
button.hide();
}
}
button.show();
} else {
button.hide();
@ -212,9 +228,9 @@ impl Module<Button> for MusicModule {
self,
tx: Sender<Self::ReceiveMessage>,
rx: glib::Receiver<Self::SendMessage>,
_info: &ModuleInfo,
info: &ModuleInfo,
) -> Option<gtk::Box> {
let icon_theme = IconTheme::new();
let icon_theme = info.icon_theme;
let container = gtk::Box::builder()
.orientation(Orientation::Horizontal)
@ -228,10 +244,12 @@ impl Module<Button> for MusicModule {
.name("album-art")
.build();
let icons = self.icons;
let info_box = gtk::Box::new(Orientation::Vertical, 10);
let title_label = IconLabel::new("\u{f886}", None);
let album_label = IconLabel::new("\u{f524}", None);
let artist_label = IconLabel::new("\u{fd01}", None);
let title_label = IconLabel::new(&icons.track, None, icon_theme);
let album_label = IconLabel::new(&icons.album, None, icon_theme);
let artist_label = IconLabel::new(&icons.artist, None, icon_theme);
title_label.container.set_widget_name("title");
album_label.container.set_widget_name("album");
@ -242,12 +260,22 @@ impl Module<Button> for MusicModule {
info_box.add(&artist_label.container);
let controls_box = gtk::Box::builder().name("controls").build();
let btn_prev = Button::builder().label("\u{f9ad}").name("btn-prev").build();
let btn_play_pause = Button::builder().label("").name("btn-play-pause").build();
let btn_next = Button::builder().label("\u{f9ac}").name("btn-next").build();
let btn_prev = new_icon_button(&icons.prev, icon_theme, 24);
btn_prev.set_widget_name("btn-prev");
let btn_play = new_icon_button(&icons.play, icon_theme, 24);
btn_play.set_widget_name("btn-play");
let btn_pause = new_icon_button(&icons.pause, icon_theme, 24);
btn_pause.set_widget_name("btn-pause");
let btn_next = new_icon_button(&icons.next, icon_theme, 24);
btn_next.set_widget_name("btn-next");
controls_box.add(&btn_prev);
controls_box.add(&btn_play_pause);
controls_box.add(&btn_play);
controls_box.add(&btn_pause);
controls_box.add(&btn_next);
info_box.add(&controls_box);
@ -262,7 +290,7 @@ impl Module<Button> for MusicModule {
volume_slider.set_inverted(true);
volume_slider.set_widget_name("slider");
let volume_icon = Label::new(Some(&self.icons.volume));
let volume_icon = new_icon_label(&icons.volume, icon_theme, 24);
volume_icon.style_context().add_class("icon");
volume_box.pack_start(&volume_slider, true, true, 0);
@ -277,13 +305,14 @@ impl Module<Button> for MusicModule {
try_send!(tx_prev, PlayerCommand::Previous);
});
let tx_toggle = tx.clone();
btn_play_pause.connect_clicked(move |button| {
if button.style_context().has_class("playing") {
try_send!(tx_toggle, PlayerCommand::Pause);
} else {
try_send!(tx_toggle, PlayerCommand::Play);
}
let tx_play = tx.clone();
btn_play.connect_clicked(move |_| {
try_send!(tx_play, PlayerCommand::Play);
});
let tx_pause = tx.clone();
btn_pause.connect_clicked(move |_| {
try_send!(tx_pause, PlayerCommand::Pause);
});
let tx_next = tx.clone();
@ -300,6 +329,8 @@ impl Module<Button> for MusicModule {
container.show_all();
{
let icon_theme = icon_theme.clone();
let mut prev_cover = None;
rx.attach(None, move |update| {
if let Some(update) = update {
@ -308,7 +339,7 @@ impl Module<Button> for MusicModule {
if prev_cover != new_cover {
prev_cover = new_cover.clone();
let res = match new_cover
.map(|cover_path| ImageProvider::parse(cover_path, &icon_theme, 128))
.map(|cover_path| ImageProvider::parse(&cover_path, &icon_theme, 128))
{
Some(Ok(image)) => image.load_into_image(album_image.clone()),
Some(Err(err)) => {
@ -337,23 +368,23 @@ impl Module<Button> for MusicModule {
match update.status.state {
PlayerState::Stopped => {
btn_play_pause.set_sensitive(false);
btn_pause.hide();
btn_play.show();
btn_play.set_sensitive(false);
}
PlayerState::Playing => {
btn_play_pause.set_sensitive(true);
btn_play_pause.set_label(&self.icons.pause);
btn_play.set_sensitive(false);
btn_play.hide();
let style_context = btn_play_pause.style_context();
style_context.add_class("playing");
style_context.remove_class("paused");
btn_pause.set_sensitive(true);
btn_pause.show();
}
PlayerState::Paused => {
btn_play_pause.set_sensitive(true);
btn_play_pause.set_label(&self.icons.play);
btn_pause.set_sensitive(false);
btn_pause.hide();
let style_context = btn_play_pause.style_context();
style_context.add_class("paused");
style_context.remove_class("playing");
btn_play.set_sensitive(true);
btn_play.show();
}
}
@ -383,11 +414,10 @@ fn replace_tokens(
tokens: &Vec<String>,
song: &Track,
status: &Status,
icons: &Icons,
) -> String {
let mut compiled_string = format_string.to_string();
for token in tokens {
let value = get_token_value(song, status, icons, token);
let value = get_token_value(song, status, token);
compiled_string = compiled_string.replace(format!("{{{token}}}").as_str(), value.as_str());
}
compiled_string
@ -395,14 +425,8 @@ fn replace_tokens(
/// Converts a string format token value
/// into its respective value.
fn get_token_value(song: &Track, status: &Status, icons: &Icons, token: &str) -> String {
fn get_token_value(song: &Track, status: &Status, token: &str) -> String {
match token {
"icon" => match status.state {
PlayerState::Stopped => None,
PlayerState::Playing => Some(&icons.play),
PlayerState::Paused => Some(&icons.pause),
}
.map(std::string::ToString::to_string),
"title" => song.title.clone(),
"album" => song.album.clone(),
"artist" => song.artist.clone(),
@ -417,17 +441,17 @@ fn get_token_value(song: &Track, status: &Status, icons: &Icons, token: &str) ->
.unwrap_or_default()
}
#[derive(Clone)]
#[derive(Clone, Debug)]
struct IconLabel {
label: Label,
container: gtk::Box,
}
impl IconLabel {
fn new(icon: &str, label: Option<&str>) -> Self {
fn new(icon_input: &str, label: Option<&str>, icon_theme: &IconTheme) -> Self {
let container = gtk::Box::new(Orientation::Horizontal, 5);
let icon = Label::new(Some(icon));
let icon = new_icon_label(icon_input, icon_theme, 32);
let label = Label::new(label);
icon.style_context().add_class("icon");