mirror of
				https://github.com/rad4day/Waybar.git
				synced 2025-10-30 23:42:42 +01:00 
			
		
		
		
	mpris: add tooltip and length limits
This commit is contained in:
		| @@ -44,6 +44,11 @@ class Mpris : public AModule { | ||||
|  | ||||
|   auto getPlayerInfo() -> std::optional<PlayerInfo>; | ||||
|   auto getIcon(const Json::Value&, const std::string&) -> std::string; | ||||
|   auto getArtistStr(const PlayerInfo&, bool) -> std::string; | ||||
|   auto getAlbumStr(const PlayerInfo&, bool) -> std::string; | ||||
|   auto getTitleStr(const PlayerInfo&, bool) -> std::string; | ||||
|   auto getLengthStr(const PlayerInfo&, bool) -> std::string; | ||||
|   auto getDynamicStr(const PlayerInfo&, bool, bool) -> std::string; | ||||
|  | ||||
|   Gtk::Box box_; | ||||
|   Gtk::Label label_; | ||||
| @@ -53,6 +58,19 @@ class Mpris : public AModule { | ||||
|   std::string format_playing_; | ||||
|   std::string format_paused_; | ||||
|   std::string format_stopped_; | ||||
|  | ||||
|   std::string tooltip_; | ||||
|   std::string tooltip_playing_; | ||||
|   std::string tooltip_paused_; | ||||
|   std::string tooltip_stopped_; | ||||
|  | ||||
|   int artist_len_; | ||||
|   int album_len_; | ||||
|   int title_len_; | ||||
|   int dynamic_len_; | ||||
|   std::vector<std::string> dynamic_prio_; | ||||
|   bool tooltip_len_limits_; | ||||
|  | ||||
|   std::chrono::seconds interval_; | ||||
|   std::string player_; | ||||
|   std::vector<std::string> ignored_players_; | ||||
|   | ||||
| @@ -74,20 +74,20 @@ Addressed by *mpd* | ||||
| 	Tooltip information displayed when the MPD server can't be reached. | ||||
|  | ||||
| *artist-len*: ++ | ||||
|     typeof: integer ++ | ||||
|     Maximum length of the Artist tag. | ||||
| 	typeof: integer ++ | ||||
| 	Maximum length of the Artist tag. | ||||
|  | ||||
| *album-len*: ++ | ||||
|     typeof: integer ++ | ||||
|     Maximum length of the Album tag. | ||||
| 	typeof: integer ++ | ||||
| 	Maximum length of the Album tag. | ||||
|  | ||||
| *album-artist-len*: ++ | ||||
|     typeof: integer ++ | ||||
|     Maximum length of the Album Artist tag. | ||||
| 	typeof: integer ++ | ||||
| 	Maximum length of the Album Artist tag. | ||||
|  | ||||
| *title-len*: ++ | ||||
|     typeof: integer ++ | ||||
|     Maximum length of the Title tag. | ||||
| 	typeof: integer ++ | ||||
| 	Maximum length of the Title tag. | ||||
|  | ||||
| *rotate*: ++ | ||||
| 	typeof: integer ++ | ||||
| @@ -98,12 +98,12 @@ Addressed by *mpd* | ||||
| 	The maximum length in character the module should display. | ||||
|  | ||||
| *min-length*: ++ | ||||
|     typeof: integer ++ | ||||
|     The minimum length in characters the module should take up. | ||||
| 	typeof: integer ++ | ||||
| 	The minimum length in characters the module should take up. | ||||
|  | ||||
| *align*: ++ | ||||
|     typeof: float ++ | ||||
|     The alignment of the text, where 0 is left-aligned and 1 is right-aligned. If the module is rotated, it will follow the flow of the text. | ||||
| 	typeof: float ++ | ||||
| 	The alignment of the text, where 0 is left-aligned and 1 is right-aligned. If the module is rotated, it will follow the flow of the text. | ||||
|  | ||||
| *on-click*: ++ | ||||
| 	typeof: string ++ | ||||
|   | ||||
| @@ -33,6 +33,48 @@ The *mpris* module displays currently playing media via libplayerctl. | ||||
| 	typeof: string ++ | ||||
| 	The status-specific text format. | ||||
|  | ||||
| *tooltip*: ++ | ||||
| 	typeof: bool ++ | ||||
| 	default: true ++ | ||||
| 	Option to disable tooltip on hover. | ||||
|  | ||||
| *tooltip-format*: ++ | ||||
| 	typeof: string ++ | ||||
| 	default: {player} ({status}) {dynamic} ++ | ||||
| 	The tooltip text format. | ||||
|  | ||||
| *tooltip-format-[status]*: ++ | ||||
| 	typeof: string ++ | ||||
| 	default: "MPD (disconnected)" ++ | ||||
| 	The status-specif tooltip format. | ||||
|  | ||||
| *artist-len*: ++ | ||||
| 	typeof: integer ++ | ||||
| 	Maximum length of the Artist tag. | ||||
|  | ||||
| *album-len*: ++ | ||||
| 	typeof: integer ++ | ||||
| 	Maximum length of the Album tag. | ||||
|  | ||||
| *title-len*: ++ | ||||
| 	typeof: integer ++ | ||||
| 	Maximum length of the Title tag. | ||||
|  | ||||
| *dynamic-len*: ++ | ||||
| 	typeof: integer ++ | ||||
| 	Maximum length of the Dynamic tag. | ||||
|  | ||||
| *dynamic-priority* ++  | ||||
| 	typeof: []string ++ | ||||
| 	default: ["title", "length", "artist", "album"] | ||||
| 	Priority of the tags when truncating the Dynamic tag (absence in this | ||||
| 	list means force inclusion). | ||||
|  | ||||
| *enable-tooltip-len-limits*: ++ | ||||
| 	typeof: bool ++ | ||||
| 	default: false ++ | ||||
| 	Option to enable the limits for the tooltip as well | ||||
|  | ||||
| *on-click*: ++ | ||||
| 	typeof: string ++ | ||||
| 	default: play-pause ++ | ||||
| @@ -83,8 +125,8 @@ The *mpris* module displays currently playing media via libplayerctl. | ||||
|  | ||||
| ``` | ||||
| "mpris": { | ||||
| 	"format": "DEFAULT: {player_icon} {dynamic}", | ||||
| 	"format-paused": "DEFAULT: {status_icon} <i>{dynamic}</i>", | ||||
| 	"format": "{player_icon} {dynamic}", | ||||
| 	"format-paused": "{status_icon} <i>{dynamic}</i>", | ||||
| 	"player-icons": { | ||||
| 		"default": "▶", | ||||
| 		"mpv": "🎵" | ||||
|   | ||||
| @@ -21,6 +21,13 @@ Mpris::Mpris(const std::string& id, const Json::Value& config) | ||||
|       box_(Gtk::ORIENTATION_HORIZONTAL, 0), | ||||
|       label_(), | ||||
|       format_(DEFAULT_FORMAT), | ||||
|       tooltip_(DEFAULT_FORMAT), | ||||
|       artist_len_(-1), | ||||
|       album_len_(-1), | ||||
|       title_len_(-1), | ||||
|       dynamic_len_(-1), | ||||
|       dynamic_prio_({"title", "length", "artist", "album"}), | ||||
|       tooltip_len_limits_(false), | ||||
|       interval_(0), | ||||
|       player_("playerctld"), | ||||
|       manager(), | ||||
| @@ -42,6 +49,46 @@ Mpris::Mpris(const std::string& id, const Json::Value& config) | ||||
|   if (config_["format-stopped"].isString()) { | ||||
|     format_stopped_ = config_["format-stopped"].asString(); | ||||
|   } | ||||
|   if (tooltipEnabled()) { | ||||
|     if (config_["tooltip-format"].isString()) { | ||||
|       tooltip_ = config_["tooltip-format"].asString(); | ||||
|     } | ||||
|     if (config_["tooltip-format-playing"].isString()) { | ||||
|       tooltip_playing_ = config_["tooltip-format-playing"].asString(); | ||||
|     } | ||||
|     if (config_["tooltip-format-paused"].isString()) { | ||||
|       tooltip_paused_ = config_["tooltip-format-paused"].asString(); | ||||
|     } | ||||
|     if (config_["tooltip-format-stopped"].isString()) { | ||||
|       tooltip_stopped_ = config_["tooltip-format-stopped"].asString(); | ||||
|     } | ||||
|     if (config_["enable-tooltip-len-limits"].isBool()) { | ||||
|       tooltip_len_limits_ = config["enable-tooltip-len-limits"].asBool(); | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   if (config["artist-len"].isUInt()) { | ||||
|     artist_len_ = config["artist-len"].asUInt(); | ||||
|   } | ||||
|   if (config["album-len"].isUInt()) { | ||||
|     album_len_ = config["album-len"].asUInt(); | ||||
|   } | ||||
|   if (config["title-len"].isUInt()) { | ||||
|     title_len_ = config["title-len"].asUInt(); | ||||
|   } | ||||
|   if (config["dynamic-len"].isUInt()) { | ||||
|     dynamic_len_ = config["dynamic-len"].asUInt(); | ||||
|   } | ||||
|   if (config_["dynamic-priority"].isArray()) { | ||||
|     dynamic_prio_.clear(); | ||||
|     for (auto it = config_["dynamic-priority"].begin(); it != config_["dynamic-priority"].end(); | ||||
|          ++it) { | ||||
|       if (it->isString()) { | ||||
|         dynamic_prio_.push_back(it->asString()); | ||||
|       } | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   if (config_["interval"].isUInt()) { | ||||
|     interval_ = std::chrono::seconds(config_["interval"].asUInt()); | ||||
|   } | ||||
| @@ -51,7 +98,9 @@ Mpris::Mpris(const std::string& id, const Json::Value& config) | ||||
|   if (config_["ignored-players"].isArray()) { | ||||
|     for (auto it = config_["ignored-players"].begin(); it != config_["ignored-players"].end(); | ||||
|          ++it) { | ||||
|       ignored_players_.push_back(it->asString()); | ||||
|       if (it->isString()) { | ||||
|         ignored_players_.push_back(it->asString()); | ||||
|       } | ||||
|     } | ||||
|   } | ||||
|  | ||||
| @@ -129,6 +178,95 @@ auto Mpris::getIcon(const Json::Value& icons, const std::string& key) -> std::st | ||||
|   return ""; | ||||
| } | ||||
|  | ||||
| auto Mpris::getArtistStr(const PlayerInfo &info, bool truncated) -> std::string { | ||||
|   std::string artist = info.artist.value_or(std::string()); | ||||
|   return (truncated && artist_len_ >= 0) ? artist.substr(0, artist_len_) : artist; | ||||
| } | ||||
|  | ||||
| auto Mpris::getAlbumStr(const PlayerInfo &info, bool truncated) -> std::string { | ||||
|   std::string album = info.album.value_or(std::string()); | ||||
|   return (truncated && album_len_ >= 0) ? album.substr(0, album_len_) : album; | ||||
| } | ||||
|  | ||||
| auto Mpris::getTitleStr(const PlayerInfo &info, bool truncated) -> std::string { | ||||
|   std::string title = info.title.value_or(std::string()); | ||||
|   return (truncated && title_len_ >= 0) ? title.substr(0, title_len_) : title; | ||||
| } | ||||
|  | ||||
| auto Mpris::getLengthStr(const PlayerInfo &info, bool from_dynamic) -> std::string { | ||||
|   if (info.length.has_value()) { | ||||
|     return from_dynamic ? ("[" + info.length.value() + "]") : info.length.value(); | ||||
|   } | ||||
|   return std::string(); | ||||
| } | ||||
|  | ||||
| auto Mpris::getDynamicStr(const PlayerInfo &info, bool truncated, bool html) -> std::string { | ||||
|   std::string artist = getArtistStr(info, truncated); | ||||
|   std::string album = getAlbumStr(info, truncated); | ||||
|   std::string title = getTitleStr(info, truncated); | ||||
|   std::string length = getLengthStr(info, true); | ||||
|  | ||||
|   std::stringstream dynamic; | ||||
|   bool showArtist, showAlbum, showTitle, showLength; | ||||
|   showArtist = artist.length() != 0; | ||||
|   showAlbum = album.length() != 0; | ||||
|   showTitle = title.length() != 0; | ||||
|   showLength = length.length() != 0; | ||||
|  | ||||
|   if (truncated && dynamic_len_ >= 0) { | ||||
|     size_t dynamicLen = dynamic_len_; | ||||
|     size_t artistLen = showArtist ? artist.length() + 3 : 0; | ||||
|     size_t albumLen = showAlbum ? album.length() + 3 : 0; | ||||
|     size_t titleLen = title.length(); | ||||
|     size_t lengthLen = showLength ? length.length() + 1 : 0; | ||||
|  | ||||
|     size_t totalLen = 0; | ||||
|  | ||||
|     for (auto it = dynamic_prio_.begin(); it != dynamic_prio_.end(); ++it) { | ||||
|       if (*it == "artist") { | ||||
|         if (totalLen + artistLen > dynamicLen) { | ||||
|           showArtist = false; | ||||
|         } else { | ||||
|           totalLen += artistLen; | ||||
|         } | ||||
|       } else if (*it == "album") { | ||||
|         if (totalLen + albumLen > dynamicLen) { | ||||
|           showAlbum = false; | ||||
|         } else { | ||||
|           totalLen += albumLen; | ||||
|         } | ||||
|       } else if (*it == "title") { | ||||
|         if (totalLen + titleLen > dynamicLen) { | ||||
|           showTitle = false; | ||||
|         } else { | ||||
|           totalLen += titleLen; | ||||
|         } | ||||
|       } else if (*it == "length") { | ||||
|         if (totalLen + lengthLen > dynamicLen) { | ||||
|           showLength = false; | ||||
|         } else { | ||||
|           totalLen += lengthLen; | ||||
|         } | ||||
|       } | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   if (showArtist) dynamic << artist << " - "; | ||||
|   if (showAlbum) dynamic << album << " - "; | ||||
|   if (showTitle) dynamic << title; | ||||
|   if (showLength) { | ||||
|     dynamic << " "; | ||||
|     if (html) { | ||||
|       dynamic << "<small>"; | ||||
|     } | ||||
|     dynamic << length; | ||||
|     if (html) { | ||||
|       dynamic << "</small>"; | ||||
|     } | ||||
|   } | ||||
|   return dynamic.str(); | ||||
| } | ||||
|  | ||||
| auto Mpris::onPlayerNameAppeared(PlayerctlPlayerManager* manager, PlayerctlPlayerName* player_name, | ||||
|                                  gpointer data) -> void { | ||||
|   Mpris* mpris = static_cast<Mpris*>(data); | ||||
| @@ -335,18 +473,6 @@ auto Mpris::update() -> void { | ||||
|  | ||||
|   spdlog::debug("mpris[{}]: running update", info.name); | ||||
|  | ||||
|   // dynamic is the auto-formatted string containing a nice out-of-the-box | ||||
|   // format text | ||||
|   std::stringstream dynamic; | ||||
|   if (info.artist) dynamic << *info.artist << " - "; | ||||
|   if (info.album) dynamic << *info.album << " - "; | ||||
|   if (info.title) dynamic << *info.title; | ||||
|   if (info.length) | ||||
|     dynamic << " " | ||||
|             << "<small>" | ||||
|             << "[" << *info.length << "]" | ||||
|             << "</small>"; | ||||
|  | ||||
|   // set css class for player status | ||||
|   if (!lastStatus.empty() && box_.get_style_context()->has_class(lastStatus)) { | ||||
|     box_.get_style_context()->remove_class(lastStatus); | ||||
| @@ -366,25 +492,55 @@ auto Mpris::update() -> void { | ||||
|   lastPlayer = info.name; | ||||
|  | ||||
|   auto formatstr = format_; | ||||
|   auto tooltipstr = tooltip_; | ||||
|   switch (info.status) { | ||||
|     case PLAYERCTL_PLAYBACK_STATUS_PLAYING: | ||||
|       if (!format_playing_.empty()) formatstr = format_playing_; | ||||
|       if (!tooltip_playing_.empty()) tooltipstr = tooltip_playing_; | ||||
|       break; | ||||
|     case PLAYERCTL_PLAYBACK_STATUS_PAUSED: | ||||
|       if (!format_paused_.empty()) formatstr = format_paused_; | ||||
|       if (!tooltip_paused_.empty()) tooltipstr = tooltip_paused_; | ||||
|       break; | ||||
|     case PLAYERCTL_PLAYBACK_STATUS_STOPPED: | ||||
|       if (!format_stopped_.empty()) formatstr = format_stopped_; | ||||
|       if (!tooltip_stopped_.empty()) tooltipstr = tooltip_stopped_; | ||||
|       break; | ||||
|   } | ||||
|   auto label_format = | ||||
|       fmt::format(fmt::runtime(formatstr), fmt::arg("player", info.name), | ||||
|                   fmt::arg("status", info.status_string), fmt::arg("artist", *info.artist), | ||||
|                   fmt::arg("title", *info.title), fmt::arg("album", *info.album), | ||||
|                   fmt::arg("length", *info.length), fmt::arg("dynamic", dynamic.str()), | ||||
|                   fmt::arg("player_icon", getIcon(config_["player-icons"], info.name)), | ||||
|                   fmt::arg("status_icon", getIcon(config_["status-icons"], info.status_string))); | ||||
|   label_.set_markup(label_format); | ||||
|  | ||||
|   try { | ||||
|     auto label_format = fmt::format( | ||||
|         fmt::runtime(formatstr), fmt::arg("player", info.name), | ||||
|         fmt::arg("status", info.status_string), fmt::arg("artist", getArtistStr(info, true)), | ||||
|         fmt::arg("title", getTitleStr(info, true)), fmt::arg("album", getAlbumStr(info, true)), | ||||
|         fmt::arg("length", getLengthStr(info, false)), | ||||
|         fmt::arg("dynamic", getDynamicStr(info, true, true)), | ||||
|         fmt::arg("player_icon", getIcon(config_["player-icons"], info.name)), | ||||
|         fmt::arg("status_icon", getIcon(config_["status-icons"], info.status_string))); | ||||
|  | ||||
|     label_.set_markup(label_format); | ||||
|   } catch (fmt::format_error const& e) { | ||||
|     spdlog::warn("mpris: format error: {}", e.what()); | ||||
|   } | ||||
|  | ||||
|   if (tooltipEnabled()) { | ||||
|     try { | ||||
|       auto tooltip_text = fmt::format( | ||||
|           fmt::runtime(tooltipstr), fmt::arg("player", info.name), | ||||
|           fmt::arg("status", info.status_string), | ||||
|           fmt::arg("artist", getArtistStr(info, tooltip_len_limits_)), | ||||
|           fmt::arg("title", getTitleStr(info, tooltip_len_limits_)), | ||||
|           fmt::arg("album", getAlbumStr(info, tooltip_len_limits_)), | ||||
|           fmt::arg("length", getLengthStr(info, false)), | ||||
|           fmt::arg("dynamic", getDynamicStr(info, tooltip_len_limits_, false)), | ||||
|           fmt::arg("player_icon", getIcon(config_["player-icons"], info.name)), | ||||
|           fmt::arg("status_icon", getIcon(config_["status-icons"], info.status_string))); | ||||
|  | ||||
|       label_.set_tooltip_text(tooltip_text); | ||||
|     } catch (fmt::format_error const& e) { | ||||
|       spdlog::warn("mpris: format error (tooltip): {}", e.what()); | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   event_box_.set_visible(true); | ||||
|   // call parent update | ||||
|   | ||||
		Reference in New Issue
	
	Block a user
	 chayleaf
					chayleaf