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