1
2 /* Copyright (C) 2011-2020 Michael Lugmair (Lucio Carreras)
3 *
4 * This file is part of sayonara player
5 *
6 * This program is free software: you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation, either version 3 of the License, or
9 * (at your option) any later version.
10
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15
16 * You should have received a copy of the GNU General Public License
17 * along with this program. If not, see <http://www.gnu.org/licenses/>.
18 */
19
20 #include "PlaylistBottomBar.h"
21 #include "PlaylistBottomBarButton.h"
22 #include "PlaylistActionMenu.h"
23
24 #include "Gui/Plugins/PlayerPluginHandler.h"
25 #include "Gui/Utils/Icons.h"
26 #include "Gui/Utils/GuiUtils.h"
27
28 #include "Interfaces/DynamicPlayback.h"
29
30 #include "Utils/Macros.h"
31 #include "Utils/Message/Message.h"
32 #include "Utils/Playlist/PlaylistMode.h"
33 #include "Utils/Settings/Settings.h"
34 #include "Utils/Language/Language.h"
35
36 #ifdef SAYONARA_WITH_SHUTDOWN
37
38 #include "Gui/Shutdown/GUI_Shutdown.h"
39
40 #endif
41
42 #include <QFile>
43 #include <QHBoxLayout>
44 #include <QPushButton>
45 #include <QSpacerItem>
46
47 namespace Pl = ::Playlist;
48 using Pl::BottomBarButton;
49 using Pl::BottomBar;
50
51 struct BottomBar::Private
52 {
53 Playlist::Mode plm;
54
55 DynamicPlaybackChecker* dynamicPlaybackChecker;
56
57 #ifdef SAYONARA_WITH_SHUTDOWN
58 GUI_Shutdown* uiShutdown = nullptr;
59 Shutdown* shutdown = nullptr;
60 #endif
61
62 BottomBarButton* btnRep1 = nullptr;
63 BottomBarButton* btnAppend = nullptr;
64 BottomBarButton* btnRepall = nullptr;
65 BottomBarButton* btnDynamic = nullptr;
66 BottomBarButton* btnShuffle = nullptr;
67 BottomBarButton* btnGapless = nullptr;
68 BottomBarButton* btnShutdown = nullptr;
69
PrivateBottomBar::Private70 Private(DynamicPlaybackChecker* dynamicPlaybackChecker) :
71 dynamicPlaybackChecker {dynamicPlaybackChecker},
72 shutdown {Shutdown::instance()} {}
73
buttonsBottomBar::Private74 QList<BottomBarButton*> buttons()
75 {
76 return {
77 btnRep1,
78 btnAppend,
79 btnRepall,
80 btnDynamic,
81 btnShuffle,
82 btnGapless,
83 btnShutdown
84 };
85 }
86 };
87
BottomBar(QWidget * parent)88 BottomBar::BottomBar(QWidget* parent) :
89 Widget(parent)
90 {}
91
92 BottomBar::~BottomBar() = default;
93
init(DynamicPlaybackChecker * dynamicPlaybackChecker)94 void BottomBar::init(DynamicPlaybackChecker* dynamicPlaybackChecker)
95 {
96 m = Pimpl::make<Private>(dynamicPlaybackChecker);
97
98 using namespace Gui;
99 m->btnRep1 = new BottomBarButton(Icons::icon(Icons::Repeat1, Icons::ForceSayonaraIcon), this);
100 m->btnRepall = new BottomBarButton(Icons::icon(Icons::RepeatAll, Icons::ForceSayonaraIcon), this);
101 m->btnAppend = new BottomBarButton(Icons::icon(Icons::Append, Icons::ForceSayonaraIcon), this);
102 m->btnDynamic = new BottomBarButton(Icons::icon(Icons::Dynamic, Icons::ForceSayonaraIcon), this);
103 m->btnShuffle = new BottomBarButton(Icons::icon(Icons::Shuffle, Icons::ForceSayonaraIcon), this);
104 m->btnGapless = new BottomBarButton(Icons::icon(Icons::Gapless, Icons::ForceSayonaraIcon), this);
105 m->btnShutdown = new BottomBarButton(Icons::icon(Icons::Shutdown), this);
106
107 QLayout* layout = new QHBoxLayout(this);
108 this->setLayout(layout);
109
110 layout->addWidget(m->btnRep1);
111 layout->addWidget(m->btnRepall);
112 layout->addWidget(m->btnShuffle);
113 layout->addWidget(m->btnDynamic);
114 layout->addWidget(m->btnAppend);
115 layout->addWidget(m->btnGapless);
116 layout->addItem(new QSpacerItem(1, 1, QSizePolicy::MinimumExpanding));
117 layout->addWidget(m->btnShutdown);
118
119 layout->setContentsMargins(3, 2, 3, 5);
120 layout->setSpacing(5);
121
122 const auto buttons = m->buttons();
123 for(auto* button : buttons)
124 {
125 button->setCheckable(true);
126 button->setFlat(false);
127 button->setFocusPolicy(Qt::NoFocus);
128 }
129
130 m->btnGapless->setCheckable(false);
131
132 #ifdef SAYONARA_WITH_SHUTDOWN
133 m->uiShutdown = new GUI_Shutdown(this);
134 #endif
135
136 m->plm = GetSetting(Set::PL_Mode);
137
138 m->btnRep1->setChecked(Playlist::Mode::isActive(m->plm.rep1()));
139 m->btnRepall->setChecked(Playlist::Mode::isActive(m->plm.repAll()));
140 m->btnAppend->setChecked(Playlist::Mode::isActive(m->plm.append()));
141 m->btnDynamic->setChecked(Playlist::Mode::isActive(m->plm.dynamic()));
142 m->btnShuffle->setChecked(Playlist::Mode::isActive(m->plm.shuffle()));
143 m->btnShutdown->setVisible(false);
144
145 connect(m->btnRep1, &QPushButton::clicked, this, &BottomBar::rep1Checked);
146 connect(m->btnRepall, &QPushButton::clicked, this, &BottomBar::repAllChecked);
147 connect(m->btnAppend, &QPushButton::released, this, &BottomBar::changePlaylistMode);
148 connect(m->btnShuffle, &QPushButton::clicked, this, &BottomBar::shuffleChecked);
149 connect(m->btnDynamic, &QPushButton::released, this, &BottomBar::changePlaylistMode);
150 connect(m->btnGapless, &QPushButton::clicked, this, &BottomBar::gaplessClicked);
151
152 connect(m->btnShutdown, &QPushButton::clicked, this, &BottomBar::shutdownClicked);
153 connect(m->shutdown, &Shutdown::sigStarted, this, &BottomBar::shutdownStarted);
154 connect(m->shutdown, &Shutdown::sigStopped, this, &BottomBar::shutdownClosed);
155
156 ListenSetting(Set::PL_Mode, BottomBar::playlistModeSettingChanged);
157 }
158
rep1Checked(bool checked)159 void BottomBar::rep1Checked(bool checked)
160 {
161 if(checked)
162 {
163 m->btnRepall->setChecked(false);
164 m->btnShuffle->setChecked(false);
165 }
166
167 changePlaylistMode();
168 }
169
repAllChecked(bool checked)170 void BottomBar::repAllChecked(bool checked)
171 {
172 if(checked)
173 {
174 m->btnRep1->setChecked(false);
175 }
176
177 changePlaylistMode();
178 }
179
shuffleChecked(bool checked)180 void BottomBar::shuffleChecked(bool checked)
181 {
182 if(checked)
183 {
184 m->btnRep1->setChecked(false);
185 }
186
187 changePlaylistMode();
188 }
189
190 // internal gui slot
changePlaylistMode()191 void BottomBar::changePlaylistMode()
192 {
193 parentWidget()->setFocus();
194
195 Playlist::Mode plm;
196
197 plm.setAppend(m->btnAppend->isChecked(), m->btnAppend->isEnabled());
198 plm.setRep1(m->btnRep1->isChecked(), m->btnRep1->isEnabled());
199 plm.setRepAll(m->btnRepall->isChecked(), m->btnRepall->isEnabled());
200 plm.setShuffle(m->btnShuffle->isChecked(), m->btnShuffle->isEnabled());
201 plm.setDynamic(m->btnDynamic->isChecked(), m->btnDynamic->isEnabled());
202
203 if(plm == m->plm)
204 {
205 return;
206 }
207
208 m->plm = plm;
209
210 SetSetting(Set::PL_Mode, m->plm);
211 }
212
gaplessClicked()213 void BottomBar::gaplessClicked()
214 {
215 PlayerPlugin::Handler::instance()->showPlugin("Crossfader");
216 }
217
218 // setting slot
playlistModeSettingChanged()219 void BottomBar::playlistModeSettingChanged()
220 {
221 Playlist::Mode plm = GetSetting(Set::PL_Mode);
222
223 if(plm == m->plm)
224 {
225 return;
226 }
227
228 m->plm = plm;
229
230 m->btnAppend->setChecked(Playlist::Mode::isActive(m->plm.append()));
231 m->btnRep1->setChecked(Playlist::Mode::isActive(m->plm.rep1()));
232 m->btnRepall->setChecked(Playlist::Mode::isActive(m->plm.repAll()));
233 m->btnShuffle->setChecked(Playlist::Mode::isActive(m->plm.shuffle()));
234 m->btnDynamic->setChecked(Playlist::Mode::isActive(m->plm.dynamic()));
235
236 m->btnRep1->setEnabled(Playlist::Mode::isEnabled(m->plm.rep1()));
237 m->btnAppend->setEnabled(Playlist::Mode::isEnabled(m->plm.append()));
238 m->btnRepall->setEnabled(Playlist::Mode::isEnabled(m->plm.repAll()));
239 m->btnDynamic->setEnabled(Playlist::Mode::isEnabled(m->plm.dynamic()));
240 m->btnShuffle->setEnabled(Playlist::Mode::isEnabled(m->plm.shuffle()));
241 m->btnGapless->setEnabled(Playlist::Mode::isEnabled(m->plm.gapless()));
242
243 checkDynamicPlayButton();
244 }
245
checkDynamicPlayButton()246 void BottomBar::checkDynamicPlayButton()
247 {
248 if(m->dynamicPlaybackChecker->isDynamicPlaybackPossible())
249 {
250 m->btnDynamic->setToolTip(tr("Please set library path first"));
251 }
252
253 else
254 {
255 m->btnDynamic->setToolTip(Lang::get(Lang::DynamicPlayback));
256 }
257 }
258
languageChanged()259 void BottomBar::languageChanged()
260 {
261 m->btnAppend->setToolTip(Lang::get(Lang::Append));
262 m->btnDynamic->setToolTip(Lang::get(Lang::DynamicPlayback));
263 m->btnGapless->setToolTip(Lang::get(Lang::GaplessPlayback));
264 m->btnRep1->setToolTip(Lang::get(Lang::Repeat1));
265 m->btnRepall->setToolTip(Lang::get(Lang::RepeatAll));
266 m->btnShuffle->setToolTip(Lang::get(Lang::Shuffle));
267 m->btnShutdown->setToolTip(Lang::get(Lang::Shutdown) + ": " + Lang::get(Lang::Cancel));
268
269 checkDynamicPlayButton();
270 }
271
skinChanged()272 void BottomBar::skinChanged()
273 {
274 const auto fm = this->fontMetrics();
275 auto width = (Gui::Util::textWidth(fm, "m") * 250) / 100;
276 width = std::max(29, width);
277
278 const auto buttons = m->buttons();
279 for(auto* button : buttons)
280 {
281 button->setFixedSize(QSize{width, width});
282 }
283 }
284
showEvent(QShowEvent * e)285 void BottomBar::showEvent(QShowEvent* e)
286 {
287 Gui::Widget::showEvent(e);
288 skinChanged();
289 }
290
resizeEvent(QResizeEvent * e)291 void BottomBar::resizeEvent(QResizeEvent* e)
292 {
293 Gui::Widget::resizeEvent(e);
294 skinChanged();
295 }
296
297 #ifdef SAYONARA_WITH_SHUTDOWN
298
shutdownClicked()299 void BottomBar::shutdownClicked()
300 {
301 const auto answer = Message::question_yn(tr("Cancel shutdown?"));
302 if(answer == Message::Answer::Yes)
303 {
304 Shutdown::instance()->stop();
305 }
306 }
307
shutdownStarted(MilliSeconds time2go)308 void BottomBar::shutdownStarted(MilliSeconds time2go)
309 {
310 Q_UNUSED(time2go)
311
312 const auto b = Shutdown::instance()->is_running();
313 m->btnShutdown->setVisible(b);
314 m->btnShutdown->setChecked(b);
315 }
316
shutdownClosed()317 void BottomBar::shutdownClosed()
318 {
319 const auto b = Shutdown::instance()->is_running();
320 m->btnShutdown->setVisible(b);
321 m->btnShutdown->setChecked(b);
322 }
323
324 #endif
325