Move ncurses related files to curses directory
[ncmpcpp.git] / src / sel_items_adder.cpp
blob54532ee394ce38e23f0f6db5283b57e28ac3283a
1 /***************************************************************************
2 * Copyright (C) 2008-2016 by Andrzej Rybczak *
3 * electricityispower@gmail.com *
4 * *
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. *
9 * *
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. *
14 * *
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 ***************************************************************************/
21 #include <algorithm>
23 #include "curses/menu_impl.h"
24 #include "browser.h"
25 #include "global.h"
26 #include "helpers.h"
27 #include "mpdpp.h"
28 #include "playlist.h"
29 #include "sel_items_adder.h"
30 #include "settings.h"
31 #include "statusbar.h"
32 #include "utility/comparators.h"
33 #include "screen_switcher.h"
34 #include "charset.h"
36 SelectedItemsAdder *mySelectedItemsAdder;
38 namespace {
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);
49 else
50 return false;
55 SelectedItemsAdder::SelectedItemsAdder()
57 using Global::MainHeight;
58 using Global::MainStartY;
59 setDimensions();
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...",
67 Config.main_color,
68 Config.window_border
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,
80 "Where?",
81 Config.main_color,
82 Config.window_border
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)
91 ));
92 m_position_selector.addItem(Entry("At the beginning of playlist",
93 std::bind(&Self::addAtTheBeginningOfPlaylist, this)
94 ));
95 m_position_selector.addItem(Entry("After current song",
96 std::bind(&Self::addAfterCurrentSong, this)
97 ));
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);
117 if (!hs)
118 return;
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");
125 return;
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;
137 setDimensions();
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();
153 hasToBeResized = 0;
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())
175 return;
176 if (me.bstate & (BUTTON1_PRESSED | BUTTON3_PRESSED))
178 w->Goto(me.y);
179 if (me.bstate & BUTTON3_PRESSED)
180 runAction();
182 else
183 Screen<WindowType>::mouseButtonPressed(me);
186 /***********************************************************************/
188 bool SelectedItemsAdder::actionRunnable()
190 return !w->empty();
193 void SelectedItemsAdder::runAction()
195 w->current()->value().run();
198 /***********************************************************************/
200 bool SelectedItemsAdder::allowsSearching()
202 return true;
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>(
213 constraint,
214 Config.regex_type,
215 EntryMatcher);
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)
308 return;
309 size_t pos = Status::State::currentSongPosition();
310 ++pos;
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)
318 return;
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)
323 ++pos;
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();
331 ++pos;
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);