1 /***************************************************************************
2 * Copyright (C) 2008-2016 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 ***************************************************************************/
23 #include "curses/menu_impl.h"
29 #include "sel_items_adder.h"
31 #include "statusbar.h"
32 #include "utility/comparators.h"
33 #include "screen_switcher.h"
36 SelectedItemsAdder
*mySelectedItemsAdder
;
40 void DisplayComponent(SelectedItemsAdder::Component
&menu
)
42 menu
<< Charset::utf8ToLocale(menu
.drawn()->value().item());
45 bool EntryMatcher(const Regex::Regex
&rx
, const NC::Menu
<SelectedItemsAdder::Entry
>::Item
&item
)
47 if (!item
.isSeparator())
48 return Regex::search(item
.value().item(), rx
);
55 SelectedItemsAdder::SelectedItemsAdder()
57 using Global::MainHeight
;
58 using Global::MainStartY
;
61 m_playlist_selector
= Component(
62 (COLS
-m_playlist_selector_width
)/2,
63 MainStartY
+(MainHeight
-m_playlist_selector_height
)/2,
64 m_playlist_selector_width
,
65 m_playlist_selector_height
,
66 "Add selected item(s) to...",
70 m_playlist_selector
.cyclicScrolling(Config
.use_cyclic_scrolling
);
71 m_playlist_selector
.centeredCursor(Config
.centered_cursor
);
72 m_playlist_selector
.setHighlightColor(Config
.main_highlight_color
);
73 m_playlist_selector
.setItemDisplayer(DisplayComponent
);
75 m_position_selector
= Component(
76 (COLS
-m_position_selector_width
)/2,
77 MainStartY
+(MainHeight
-m_position_selector_height
)/2,
78 m_position_selector_width
,
79 m_position_selector_height
,
84 m_position_selector
.cyclicScrolling(Config
.use_cyclic_scrolling
);
85 m_position_selector
.centeredCursor(Config
.centered_cursor
);
86 m_position_selector
.setHighlightColor(Config
.main_highlight_color
);
87 m_position_selector
.setItemDisplayer(DisplayComponent
);
89 m_position_selector
.addItem(Entry("At the end of playlist",
90 std::bind(&Self::addAtTheEndOfPlaylist
, this)
92 m_position_selector
.addItem(Entry("At the beginning of playlist",
93 std::bind(&Self::addAtTheBeginningOfPlaylist
, this)
95 m_position_selector
.addItem(Entry("After current song",
96 std::bind(&Self::addAfterCurrentSong
, this)
98 m_position_selector
.addItem(Entry("After current album",
99 std::bind(&Self::addAfterCurrentAlbum
, this)
101 m_position_selector
.addItem(Entry("After highlighted item",
102 std::bind(&Self::addAfterHighlightedSong
, this)
104 m_position_selector
.addSeparator();
105 m_position_selector
.addItem(Entry("Cancel",
106 std::bind(&Self::cancel
, this)
109 w
= &m_playlist_selector
;
112 void SelectedItemsAdder::switchTo()
114 using Global::myScreen
;
116 auto hs
= dynamic_cast<HasSongs
*>(myScreen
);
120 Statusbar::print(1, "Fetching selected songs...");
121 m_selected_items
= hs
->getSelectedSongs();
122 if (m_selected_items
.empty())
124 Statusbar::print("No selected songs");
127 populatePlaylistSelector(myScreen
);
128 SwitchTo::execute(this);
129 // default to main window
130 w
= &m_playlist_selector
;
133 void SelectedItemsAdder::resize()
135 using Global::MainHeight
;
136 using Global::MainStartY
;
138 m_playlist_selector
.resize(m_playlist_selector_width
, m_playlist_selector_height
);
139 m_playlist_selector
.moveTo(
140 (COLS
-m_playlist_selector_width
)/2,
141 MainStartY
+(MainHeight
-m_playlist_selector_height
)/2
143 m_position_selector
.resize(m_position_selector_width
, m_position_selector_height
);
144 m_position_selector
.moveTo(
145 (COLS
-m_position_selector_width
)/2,
146 MainStartY
+(MainHeight
-m_position_selector_height
)/2
148 if (previousScreen() && previousScreen()->hasToBeResized
) // resize background window
150 previousScreen()->resize();
151 previousScreen()->refresh();
156 void SelectedItemsAdder::refresh()
158 if (isActiveWindow(m_position_selector
))
160 m_playlist_selector
.display();
161 m_position_selector
.display();
163 else if (isActiveWindow(m_playlist_selector
))
164 m_playlist_selector
.display();
167 std::wstring
SelectedItemsAdder::title()
169 return previousScreen()->title();
172 void SelectedItemsAdder::mouseButtonPressed(MEVENT me
)
174 if (w
->empty() || !w
->hasCoords(me
.x
, me
.y
) || size_t(me
.y
) >= w
->size())
176 if (me
.bstate
& (BUTTON1_PRESSED
| BUTTON3_PRESSED
))
179 if (me
.bstate
& BUTTON3_PRESSED
)
183 Screen
<WindowType
>::mouseButtonPressed(me
);
186 /***********************************************************************/
188 bool SelectedItemsAdder::actionRunnable()
193 void SelectedItemsAdder::runAction()
195 w
->current()->value().run();
198 /***********************************************************************/
200 bool SelectedItemsAdder::allowsSearching()
205 const std::string
&SelectedItemsAdder::searchConstraint()
207 return m_search_predicate
.constraint();
210 void SelectedItemsAdder::setSearchConstraint(const std::string
&constraint
)
212 m_search_predicate
= Regex::ItemFilter
<Entry
>(
218 void SelectedItemsAdder::clearSearchConstraint()
220 m_search_predicate
.clear();
223 bool SelectedItemsAdder::search(SearchDirection direction
, bool wrap
, bool skip_current
)
225 return ::search(*w
, m_search_predicate
, direction
, wrap
, skip_current
);
228 /***********************************************************************/
230 void SelectedItemsAdder::populatePlaylistSelector(BaseScreen
*old_screen
)
232 // stored playlists don't support songs from outside of mpd database
233 bool in_local_browser
= old_screen
== myBrowser
&& myBrowser
->isLocal();
235 m_playlist_selector
.reset();
236 m_playlist_selector
.clear();
237 m_playlist_selector
.addItem(Entry("Current playlist",
238 std::bind(&Self::addToCurrentPlaylist
, this)
240 if (!in_local_browser
)
242 m_playlist_selector
.addItem(Entry("New playlist",
243 std::bind(&Self::addToNewPlaylist
, this)
246 m_playlist_selector
.addSeparator();
247 if (!in_local_browser
)
249 size_t begin
= m_playlist_selector
.size();
250 for (MPD::PlaylistIterator it
= Mpd
.GetPlaylists(), end
; it
!= end
; ++it
)
252 m_playlist_selector
.addItem(Entry(it
->path(),
253 std::bind(&Self::addToExistingPlaylist
, this, it
->path())
256 std::sort(m_playlist_selector
.beginV()+begin
, m_playlist_selector
.endV(),
257 LocaleBasedSorting(std::locale(), Config
.ignore_leading_the
));
258 if (begin
< m_playlist_selector
.size())
259 m_playlist_selector
.addSeparator();
261 m_playlist_selector
.addItem(Entry("Cancel",
262 std::bind(&Self::cancel
, this)
266 void SelectedItemsAdder::addToCurrentPlaylist()
268 w
= &m_position_selector
;
269 m_position_selector
.reset();
272 void SelectedItemsAdder::addToNewPlaylist() const
274 std::string playlist
;
276 Statusbar::ScopedLock slock
;
277 Statusbar::put() << "Save playlist as: ";
278 playlist
= Global::wFooter
->prompt();
280 addToExistingPlaylist(playlist
);
283 void SelectedItemsAdder::addToExistingPlaylist(const std::string
&playlist
) const
285 Mpd
.StartCommandsList();
286 for (auto s
= m_selected_items
.begin(); s
!= m_selected_items
.end(); ++s
)
287 Mpd
.AddToPlaylist(playlist
, *s
);
288 Mpd
.CommitCommandsList();
289 Statusbar::printf("Selected item(s) added to playlist \"%1%\"", playlist
);
290 switchToPreviousScreen();
293 void SelectedItemsAdder::addAtTheEndOfPlaylist() const
295 bool success
= addSongsToPlaylist(m_selected_items
.begin(), m_selected_items
.end(), false, -1);
296 exitSuccessfully(success
);
299 void SelectedItemsAdder::addAtTheBeginningOfPlaylist() const
301 bool success
= addSongsToPlaylist(m_selected_items
.begin(), m_selected_items
.end(), false, 0);
302 exitSuccessfully(success
);
305 void SelectedItemsAdder::addAfterCurrentSong() const
307 if (Status::State::player() == MPD::psStop
)
309 size_t pos
= Status::State::currentSongPosition();
311 bool success
= addSongsToPlaylist(m_selected_items
.begin(), m_selected_items
.end(), false, pos
);
312 exitSuccessfully(success
);
315 void SelectedItemsAdder::addAfterCurrentAlbum() const
317 if (Status::State::player() == MPD::psStop
)
319 auto &pl
= myPlaylist
->main();
320 size_t pos
= Status::State::currentSongPosition();
321 std::string album
= pl
[pos
].value().getAlbum();
322 while (pos
< pl
.size() && pl
[pos
].value().getAlbum() == album
)
324 bool success
= addSongsToPlaylist(m_selected_items
.begin(), m_selected_items
.end(), false, pos
);
325 exitSuccessfully(success
);
328 void SelectedItemsAdder::addAfterHighlightedSong() const
330 size_t pos
= myPlaylist
->main().current()->value().getPosition();
332 bool success
= addSongsToPlaylist(m_selected_items
.begin(), m_selected_items
.end(), false, pos
);
333 exitSuccessfully(success
);
336 void SelectedItemsAdder::cancel()
338 if (isActiveWindow(m_playlist_selector
))
339 switchToPreviousScreen();
340 else if (isActiveWindow(m_position_selector
))
341 w
= &m_playlist_selector
;
344 void SelectedItemsAdder::exitSuccessfully(bool success
) const
346 Statusbar::printf("Selected items added%1%", withErrors(success
));
347 switchToPreviousScreen();
350 void SelectedItemsAdder::setDimensions()
352 using Global::MainHeight
;
354 m_playlist_selector_width
= COLS
*0.6;
355 m_playlist_selector_height
= std::min(MainHeight
, size_t(LINES
*0.66));
357 m_position_selector_width
= std::min(size_t(35), size_t(COLS
));
358 m_position_selector_height
= std::min(size_t(11), MainHeight
);