1 /***************************************************************************
2 * Copyright (C) 2008-2014 by Andrzej Rybczak *
3 * electricityispower@gmail.com *
5 * This program is free software; you can redistribute it and/or modify *
6 * it under the terms of the GNU General Public License as published by *
7 * the Free Software Foundation; either version 2 of the License, or *
8 * (at your option) any later version. *
10 * This program is distributed in the hope that it will be useful, *
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
13 * GNU General Public License for more details. *
15 * You should have received a copy of the GNU General Public License *
16 * along with this program; if not, write to the *
17 * Free Software Foundation, Inc., *
18 * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. *
19 ***************************************************************************/
22 #include <boost/date_time/posix_time/posix_time.hpp>
28 #include "menu_impl.h"
30 #include "screen_switcher.h"
33 #include "statusbar.h"
34 #include "helpers/song_iterator_maker.h"
35 #include "utility/comparators.h"
36 #include "utility/functional.h"
39 using Global::MainHeight
;
40 using Global::MainStartY
;
42 namespace ph
= std::placeholders
;
48 std::string
songToString(const MPD::Song
&s
);
49 bool playlistEntryMatcher(const Regex::Regex
&rx
, const MPD::Song
&s
);
54 : m_total_length(0), m_remaining_time(0), m_scroll_begin(0)
55 , m_timer(boost::posix_time::from_time_t(0))
56 , m_reload_total_length(false), m_reload_remaining(false)
58 w
= NC::Menu
<MPD::Song
>(0, MainStartY
, COLS
, MainHeight
, Config
.playlist_display_mode
== DisplayMode::Columns
&& Config
.titles_visibility
? Display::Columns(COLS
) : "", Config
.main_color
, NC::Border());
59 w
.cyclicScrolling(Config
.use_cyclic_scrolling
);
60 w
.centeredCursor(Config
.centered_cursor
);
61 w
.setHighlightColor(Config
.main_highlight_color
);
62 w
.setSelectedPrefix(Config
.selected_item_prefix
);
63 w
.setSelectedSuffix(Config
.selected_item_suffix
);
64 switch (Config
.playlist_display_mode
)
66 case DisplayMode::Classic
:
67 w
.setItemDisplayer(std::bind(
68 Display::Songs
, ph::_1
, std::cref(w
), std::cref(Config
.song_list_format
)
71 case DisplayMode::Columns
:
72 w
.setItemDisplayer(std::bind(
73 Display::SongsInColumns
, ph::_1
, std::cref(w
)
79 void Playlist::switchTo()
81 SwitchTo::execute(this);
86 void Playlist::resize()
88 size_t x_offset
, width
;
89 getWindowResizeParams(x_offset
, width
);
90 w
.resize(width
, MainHeight
);
91 w
.moveTo(x_offset
, MainStartY
);
93 switch (Config
.playlist_display_mode
)
95 case DisplayMode::Columns
:
96 if (Config
.titles_visibility
)
98 w
.setTitle(Display::Columns(w
.getWidth()));
101 case DisplayMode::Classic
:
108 std::wstring
Playlist::title()
110 std::wstring result
= L
"Playlist ";
111 if (Config
.playlist_show_mpd_host
)
114 result
+= ToWString(Mpd
.GetHostname());
117 if (m_reload_total_length
|| m_reload_remaining
)
118 m_stats
= getTotalLength();
119 result
+= Scroller(ToWString(m_stats
), m_scroll_begin
, COLS
-result
.length()-(Config
.design
== Design::Alternative
? 2 : Global::VolumeState
.length()));
123 void Playlist::update()
125 if (w
.isHighlighted()
126 && Config
.playlist_disable_highlight_delay
.time_duration::seconds() > 0
127 && Global::Timer
- m_timer
> Config
.playlist_disable_highlight_delay
)
129 w
.setHighlighting(false);
134 void Playlist::enterPressed()
137 Mpd
.PlayID(w
.current()->value().getID());
140 void Playlist::mouseButtonPressed(MEVENT me
)
142 if (!w
.empty() && w
.hasCoords(me
.x
, me
.y
))
144 if (size_t(me
.y
) < w
.size() && (me
.bstate
& (BUTTON1_PRESSED
| BUTTON3_PRESSED
)))
147 if (me
.bstate
& BUTTON3_PRESSED
)
151 Screen
<WindowType
>::mouseButtonPressed(me
);
155 /***********************************************************************/
157 bool Playlist::allowsSearching()
162 void Playlist::setSearchConstraint(const std::string
&constraint
)
164 m_search_predicate
= Regex::Filter
<MPD::Song
>(
165 Regex::make(constraint
, Config
.regex_type
), playlistEntryMatcher
169 void Playlist::clearConstraint()
171 m_search_predicate
.clear();
174 bool Playlist::find(SearchDirection direction
, bool wrap
, bool skip_current
)
176 return search(w
, m_search_predicate
, direction
, wrap
, skip_current
);
179 /***********************************************************************/
181 std::vector
<MPD::Song
> Playlist::getSelectedSongs()
183 return w
.getSelectedSongs();
186 /***********************************************************************/
188 MPD::Song
Playlist::nowPlayingSong()
191 if (Status::State::player() != MPD::psUnknown
)
193 auto sp
= Status::State::currentSongPosition();
194 if (sp
>= 0 && size_t(sp
) < w
.size())
195 s
= w
.at(sp
).value();
200 void Playlist::EnableHighlighting()
202 w
.setHighlighting(true);
203 m_timer
= Global::Timer
;
206 std::string
Playlist::getTotalLength()
208 std::ostringstream result
;
210 if (m_reload_total_length
)
213 for (const auto &s
: w
)
214 m_total_length
+= s
.value().getDuration();
215 m_reload_total_length
= false;
217 if (Config
.playlist_show_remaining_time
&& m_reload_remaining
)
219 m_remaining_time
= 0;
220 for (size_t i
= Status::State::currentSongPosition(); i
< w
.size(); ++i
)
221 m_remaining_time
+= w
[i
].value().getDuration();
222 m_reload_remaining
= false;
225 result
<< '(' << w
.size() << (w
.size() == 1 ? " item" : " items");
229 result
<< ", length: ";
230 ShowTime(result
, m_total_length
, Config
.playlist_shorten_total_times
);
232 if (Config
.playlist_show_remaining_time
&& m_remaining_time
&& w
.size() > 1)
234 result
<< " :: remaining: ";
235 ShowTime(result
, m_remaining_time
, Config
.playlist_shorten_total_times
);
241 void Playlist::SetSelectedItemsPriority(int prio
)
243 auto list
= getSelectedOrCurrent(w
.begin(), w
.end(), w
.current());
244 Mpd
.StartCommandsList();
245 for (auto it
= list
.begin(); it
!= list
.end(); ++it
)
246 Mpd
.SetPriority((*it
)->value(), prio
);
247 Mpd
.CommitCommandsList();
248 Statusbar::print("Priority set");
251 bool Playlist::checkForSong(const MPD::Song
&s
)
253 return m_song_refs
.find(s
) != m_song_refs
.end();
256 void Playlist::registerSong(const MPD::Song
&s
)
261 void Playlist::unregisterSong(const MPD::Song
&s
)
263 auto it
= m_song_refs
.find(s
);
264 assert(it
!= m_song_refs
.end());
266 m_song_refs
.erase(it
);
273 std::string
songToString(const MPD::Song
&s
)
276 switch (Config
.playlist_display_mode
)
278 case DisplayMode::Classic
:
279 result
= Format::stringify
<char>(Config
.song_list_format
, &s
);
281 case DisplayMode::Columns
:
282 result
= Format::stringify
<char>(Config
.song_columns_mode_format
, &s
);
287 bool playlistEntryMatcher(const Regex::Regex
&rx
, const MPD::Song
&s
)
289 return Regex::search(songToString(s
), rx
);