BasicColors: add `noexcept`
[ncmpc-debian.git] / src / screen.cxx
1 /* ncmpc (Ncurses MPD Client)
2  * (c) 2004-2019 The Music Player Daemon Project
3  * Project homepage: http://musicpd.org
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 along
16  * with this program; if not, write to the Free Software Foundation, Inc.,
17  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18  */
19
20 #include "screen.hxx"
21 #include "PageMeta.hxx"
22 #include "screen_list.hxx"
23 #include "screen_status.hxx"
24 #include "Page.hxx"
25 #include "Command.hxx"
26 #include "config.h"
27 #include "i18n.h"
28 #include "mpdclient.hxx"
29 #include "Options.hxx"
30 #include "DelayedSeek.hxx"
31 #include "player_command.hxx"
32 #include "SongPage.hxx"
33 #include "LyricsPage.hxx"
34
35 #include <mpd/client.h>
36
37 #include <string.h>
38
39 ScreenManager::PageMap::iterator
40 ScreenManager::MakePage(const PageMeta &sf) noexcept
41 {
42         auto i = pages.find(&sf);
43         if (i != pages.end())
44                 return i;
45
46         auto j = pages.emplace(&sf,
47                                sf.init(*this, main_window.w,
48                                        main_window.size));
49         assert(j.second);
50         return j.first;
51 }
52
53 void
54 ScreenManager::Switch(const PageMeta &sf, struct mpdclient &c) noexcept
55 {
56         if (&sf == current_page->first)
57                 return;
58
59         auto page = MakePage(sf);
60
61         mode_fn_prev = &*current_page->first;
62
63         /* close the old mode */
64         current_page->second->OnClose();
65
66         /* get functions for the new mode */
67         current_page = page;
68
69         /* open the new mode */
70         auto &p = *page->second;
71         p.OnOpen(c);
72         p.Resize(main_window.size);
73         p.Update(c);
74         p.SetDirty();
75 }
76
77 void
78 ScreenManager::Swap(struct mpdclient &c, const struct mpd_song *song) noexcept
79 {
80         if (song != nullptr)
81         {
82                 if (false)
83                         { /* just a hack to make the ifdefs less ugly */ }
84 #ifdef ENABLE_SONG_SCREEN
85                 if (mode_fn_prev == &screen_song)
86                         screen_song_switch(*this, c, *song);
87 #endif
88 #ifdef ENABLE_LYRICS_SCREEN
89                 else if (mode_fn_prev == &screen_lyrics)
90                         screen_lyrics_switch(*this, c, *song, true);
91 #endif
92                 else
93                         Switch(*mode_fn_prev, c);
94         }
95         else
96                 Switch(*mode_fn_prev, c);
97 }
98
99 gcc_pure
100 static int
101 find_configured_screen(const char *name) noexcept
102 {
103         unsigned i;
104
105         for (i = 0; i < options.screen_list.size(); ++i)
106                 if (strcmp(options.screen_list[i].c_str(), name) == 0)
107                         return i;
108
109         return -1;
110 }
111
112 void
113 ScreenManager::NextMode(struct mpdclient &c, int offset) noexcept
114 {
115         int max = options.screen_list.size();
116
117         /* find current screen */
118         int current = find_configured_screen(current_page->first->name);
119         int next = current + offset;
120         if (next<0)
121                 next = max-1;
122         else if (next>=max)
123                 next = 0;
124
125         const PageMeta *sf =
126                 screen_lookup_name(options.screen_list[next].c_str());
127         if (sf != nullptr)
128                 Switch(*sf, c);
129 }
130
131 void
132 ScreenManager::Update(struct mpdclient &c, const DelayedSeek &seek) noexcept
133 {
134         const unsigned events = c.events;
135
136 #ifndef NCMPC_MINI
137         static bool was_connected;
138         static bool initialized = false;
139         static bool repeat;
140         static bool random_enabled;
141         static bool single;
142         static bool consume;
143         static unsigned crossfade;
144
145         /* print a message if mpd status has changed */
146         if ((events & MPD_IDLE_OPTIONS) && c.status != nullptr) {
147                 if (!initialized) {
148                         repeat = mpd_status_get_repeat(c.status);
149                         random_enabled = mpd_status_get_random(c.status);
150                         single = mpd_status_get_single(c.status);
151                         consume = mpd_status_get_consume(c.status);
152                         crossfade = mpd_status_get_crossfade(c.status);
153                         initialized = true;
154                 }
155
156                 if (repeat != mpd_status_get_repeat(c.status))
157                         screen_status_message(mpd_status_get_repeat(c.status) ?
158                                               _("Repeat mode is on") :
159                                               _("Repeat mode is off"));
160
161                 if (random_enabled != mpd_status_get_random(c.status))
162                         screen_status_message(mpd_status_get_random(c.status) ?
163                                               _("Random mode is on") :
164                                               _("Random mode is off"));
165
166                 if (single != mpd_status_get_single(c.status))
167                         screen_status_message(mpd_status_get_single(c.status) ?
168                                               /* "single" mode means
169                                                  that MPD will
170                                                  automatically stop
171                                                  after playing one
172                                                  single song */
173                                               _("Single mode is on") :
174                                               _("Single mode is off"));
175
176                 if (consume != mpd_status_get_consume(c.status))
177                         screen_status_message(mpd_status_get_consume(c.status) ?
178                                               /* "consume" mode means
179                                                  that MPD removes each
180                                                  song which has
181                                                  finished playing */
182                                               _("Consume mode is on") :
183                                               _("Consume mode is off"));
184
185                 if (crossfade != mpd_status_get_crossfade(c.status))
186                         screen_status_printf(_("Crossfade %d seconds"),
187                                              mpd_status_get_crossfade(c.status));
188
189                 repeat = mpd_status_get_repeat(c.status);
190                 random_enabled = mpd_status_get_random(c.status);
191                 single = mpd_status_get_single(c.status);
192                 consume = mpd_status_get_consume(c.status);
193                 crossfade = mpd_status_get_crossfade(c.status);
194         }
195
196         if ((events & MPD_IDLE_DATABASE) != 0 && was_connected &&
197             c.IsConnected())
198                 screen_status_message(_("Database updated"));
199         was_connected = c.IsConnected();
200 #endif
201
202         title_bar.Update(c.status);
203
204         unsigned elapsed;
205         if (c.status == nullptr)
206                 elapsed = 0;
207         else if (seek.IsSeeking(mpd_status_get_song_id(c.status)))
208                 elapsed = seek.GetTime();
209         else
210                 elapsed = mpd_status_get_elapsed_time(c.status);
211
212         unsigned duration = c.playing_or_paused
213                 ? mpd_status_get_total_time(c.status)
214                 : 0;
215
216         progress_bar.Set(elapsed, duration);
217
218         status_bar.Update(c.status, c.GetCurrentSong(), seek);
219
220         for (auto &i : pages)
221                 i.second->AddPendingEvents(events);
222
223         /* update the main window */
224         current_page->second->Update(c);
225
226         Paint(current_page->second->IsDirty());
227 }
228
229 void
230 ScreenManager::OnCommand(struct mpdclient &c, DelayedSeek &seek, Command cmd)
231 {
232         if (current_page->second->OnCommand(c, cmd))
233                 return;
234
235         if (handle_player_command(c, seek, cmd))
236                 return;
237
238         const auto *new_page = PageByCommand(cmd);
239         if (new_page != nullptr) {
240                 Switch(*new_page, c);
241                 return;
242         }
243
244         switch(cmd) {
245         case Command::TOGGLE_FIND_WRAP:
246                 options.find_wrap = !options.find_wrap;
247                 screen_status_message(options.find_wrap ?
248                                       _("Find mode: Wrapped") :
249                                       _("Find mode: Normal"));
250                 break;
251         case Command::TOGGLE_AUTOCENTER:
252                 options.auto_center = !options.auto_center;
253                 screen_status_message(options.auto_center ?
254                                       _("Auto center mode: On") :
255                                       _("Auto center mode: Off"));
256                 break;
257         case Command::SCREEN_UPDATE:
258                 current_page->second->SetDirty();
259                 break;
260         case Command::SCREEN_PREVIOUS:
261                 NextMode(c, -1);
262                 break;
263         case Command::SCREEN_NEXT:
264                 NextMode(c, 1);
265                 break;
266         case Command::SCREEN_SWAP:
267                 Swap(c, nullptr);
268                 break;
269
270         default:
271                 break;
272         }
273 }
274
275 #ifdef HAVE_GETMOUSE
276
277 bool
278 ScreenManager::OnMouse(struct mpdclient &c, DelayedSeek &seek,
279                        Point p, mmask_t bstate)
280 {
281         if (current_page->second->OnMouse(c, p - GetMainPosition(),
282                                           bstate))
283                 return true;
284
285         /* if button 2 was pressed switch screen */
286         if (bstate & BUTTON2_CLICKED) {
287                 OnCommand(c, seek, Command::SCREEN_NEXT);
288                 return true;
289         }
290
291         return false;
292 }
293
294 #endif