1 /***************************************************************************
2  *   Copyright (C) 2006-2021 by Ilya Kotov                                 *
3  *   forkotov02@ya.ru                                                      *
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 Street, Fifth Floor, Boston, MA  02110-1301, USA.         *
19  ***************************************************************************/
20 
21 #include <QApplication>
22 #include <QSettings>
23 #include <QMenu>
24 #include <qmmp/soundcore.h>
25 #include <qmmpui/mediaplayer.h>
26 #include <qmmpui/playlistmanager.h>
27 #include <qmmpui/qmmpuisettings.h>
28 #include "skin.h"
29 #include "mainvisual.h"
30 #include "button.h"
31 #include "titlebar.h"
32 #include "positionbar.h"
33 #include "number.h"
34 #include "togglebutton.h"
35 #include "symboldisplay.h"
36 #include "textscroller.h"
37 #include "monostereo.h"
38 #include "playstatus.h"
39 #include "volumebar.h"
40 #include "balancebar.h"
41 #include "mainwindow.h"
42 #include "timeindicator.h"
43 #include "actionmanager.h"
44 #include "display.h"
45 
MainDisplay(MainWindow * parent)46 MainDisplay::MainDisplay (MainWindow *parent)
47         : PixmapWidget (parent)
48 {
49     m_skin = Skin::instance();
50     setPixmap (m_skin->getMain());
51     setCursor(m_skin->getCursor(Skin::CUR_NORMAL));
52     m_mw = parent;
53 
54     m_timeIndicatorModel = new TimeIndicatorModel(this);
55     m_titlebar = new TitleBar(m_timeIndicatorModel, this);
56     m_titlebar->move(0,0);
57     m_titlebar->setActive(true);
58     m_previous = new Button (this, Skin::BT_PREVIOUS_N, Skin::BT_PREVIOUS_P, Skin::CUR_NORMAL);
59     m_previous->setToolTip(tr("Previous"));
60     connect (m_previous, SIGNAL (clicked()), parent, SLOT (previous()));
61 
62     m_play = new Button (this, Skin::BT_PLAY_N, Skin::BT_PLAY_P, Skin::CUR_NORMAL);
63     m_play->setToolTip(tr("Play"));
64     connect (m_play, SIGNAL (clicked()),parent,SLOT (play()));
65     m_pause = new Button (this, Skin::BT_PAUSE_N,Skin::BT_PAUSE_P, Skin::CUR_NORMAL);
66     m_pause->setToolTip(tr("Pause"));
67     connect (m_pause,SIGNAL (clicked()),parent,SLOT (pause()));
68     m_stop = new Button (this, Skin::BT_STOP_N,Skin::BT_STOP_P, Skin::CUR_NORMAL);
69     m_stop->setToolTip(tr("Stop"));
70     connect (m_stop,SIGNAL (clicked()),parent,SLOT (stop()));
71     m_next = new Button (this, Skin::BT_NEXT_N,Skin::BT_NEXT_P, Skin::CUR_NORMAL);
72     m_next->setToolTip(tr("Next"));
73     connect (m_next,SIGNAL (clicked()),parent,SLOT (next()));
74     m_eject = new Button (this, Skin::BT_EJECT_N,Skin::BT_EJECT_P, Skin::CUR_NORMAL);
75     m_eject->setToolTip(tr("Play files"));
76     connect (m_eject,SIGNAL (clicked()),parent, SLOT(playFiles()));
77     connect (m_skin, SIGNAL (skinChanged()), this, SLOT (updateSkin()));
78     m_vis = new MainVisual (this);
79 
80     m_eqButton = new ToggleButton (this,Skin::BT_EQ_ON_N,Skin::BT_EQ_ON_P,
81                                    Skin::BT_EQ_OFF_N,Skin::BT_EQ_OFF_P);
82     m_eqButton->setToolTip(tr("Equalizer"));
83     m_plButton = new ToggleButton (this,Skin::BT_PL_ON_N,Skin::BT_PL_ON_P,
84                                    Skin::BT_PL_OFF_N,Skin::BT_PL_OFF_P);
85     m_plButton->setToolTip(tr("Playlist"));
86 
87     m_repeatButton = new ToggleButton (this,Skin::REPEAT_ON_N,Skin::REPEAT_ON_P,
88                                        Skin::REPEAT_OFF_N,Skin::REPEAT_OFF_P);
89     connect(m_repeatButton,SIGNAL(clicked(bool)),this,SIGNAL(repeatableToggled(bool)));
90     m_repeatButton->setToolTip(tr("Repeat playlist"));
91     m_shuffleButton = new ToggleButton (this,Skin::SHUFFLE_ON_N,Skin::SHUFFLE_ON_P,
92                                         Skin::SHUFFLE_OFF_N,Skin::SHUFFLE_OFF_P);
93     m_shuffleButton->setToolTip(tr("Shuffle"));
94     connect(m_shuffleButton,SIGNAL(clicked(bool)),this,SIGNAL(shuffleToggled(bool)));
95 
96     m_kbps = new SymbolDisplay(this,3);
97     m_freq = new SymbolDisplay(this,2);
98     m_text = new TextScroller (this);
99     m_monoster = new MonoStereo (this);
100     m_playstatus = new PlayStatus(this);
101 
102     m_volumeBar = new VolumeBar(this);
103     m_volumeBar->setToolTip(tr("Volume"));
104     connect(m_volumeBar, SIGNAL(sliderMoved(int)),SLOT(displayVolume()));
105     connect(m_volumeBar, SIGNAL(sliderPressed()),SLOT(displayVolume()));
106     connect(m_volumeBar, SIGNAL(sliderReleased()),m_text,SLOT(clear()));
107 
108     m_balanceBar = new BalanceBar(this);
109     m_balanceBar->setToolTip(tr("Balance"));
110     connect(m_balanceBar, SIGNAL(sliderMoved(int)),SLOT(displayVolume()));
111     connect(m_balanceBar, SIGNAL(sliderPressed()),SLOT(displayVolume()));
112     connect(m_balanceBar, SIGNAL(sliderReleased()),m_text,SLOT(clear()));
113 
114     m_posbar = new PositionBar(this);
115     connect(m_posbar, SIGNAL(sliderPressed()),SLOT(showPosition()));
116     connect(m_posbar, SIGNAL(sliderMoved(qint64)),SLOT(showPosition()));
117     connect(m_posbar, SIGNAL(sliderReleased()),SLOT(updatePosition()));
118 
119     m_timeIndicator = new TimeIndicator(m_timeIndicatorModel, this);
120     m_aboutWidget = new QWidget(this);
121     m_core = SoundCore::instance();
122     connect(m_core, SIGNAL(elapsedChanged(qint64)), SLOT(setTime(qint64)));
123     connect(m_core, SIGNAL(bitrateChanged(int)), m_kbps, SLOT(display(int)));
124     connect(m_core, SIGNAL(audioParametersChanged(AudioParameters)), SLOT(onAudioPatametersChanged(AudioParameters)));
125     connect(m_core, SIGNAL(stateChanged(Qmmp::State)), SLOT(setState(Qmmp::State)));
126     connect(m_core, SIGNAL(volumeChanged(int)), m_volumeBar, SLOT(setValue(int)));
127     connect(m_core, SIGNAL(balanceChanged(int)), m_balanceBar, SLOT(setValue(int)));
128     connect(m_balanceBar, SIGNAL(sliderMoved(int)), m_core, SLOT(setBalance(int)));
129     connect(m_volumeBar, SIGNAL(sliderMoved(int)), m_core, SLOT(setVolume(int)));
130     m_volumeBar->setValue(m_core->volume());
131     m_balanceBar->setValue(m_core->balance());
132 
133     QmmpUiSettings *ui_settings = QmmpUiSettings::instance();
134     connect(ui_settings, SIGNAL(repeatableListChanged(bool)), m_repeatButton, SLOT(setChecked(bool)));
135     connect(ui_settings, SIGNAL(shuffleChanged(bool)), m_shuffleButton, SLOT(setChecked(bool)));
136     updatePositions();
137     updateMask();
138 }
139 
~MainDisplay()140 MainDisplay::~MainDisplay()
141 {
142     QSettings settings (Qmmp::configFile(), QSettings::IniFormat);
143     settings.setValue ("Skinned/pl_visible",m_plButton->isChecked());
144     settings.setValue ("Skinned/eq_visible",m_eqButton->isChecked());
145 }
146 
updatePositions()147 void MainDisplay::updatePositions()
148 {
149     int r = m_skin->ratio();
150     m_previous->move (r*16, r*88);
151     m_play->move (r*39,  r*88);
152     m_pause->move (r*62,  r*88);
153     m_vis->move(r*24,  r*43);
154     m_stop->move (r*85,  r*88);
155     m_next->move (r*108, r*88);
156     m_eject->move (r*136, r*89);
157     m_posbar->move (r*16, r*72);
158     m_eqButton->move (r*219, r*58);
159     m_plButton->move (r*241, r*58);
160     m_repeatButton->move (r*210, r*89);
161     m_shuffleButton->move (r*164, r*89);
162     m_kbps->move (r*111, r*43);
163     m_freq->move (r*156, r*43);
164     m_text->resize (r*154, r*16);
165     m_text->move (r*109, r*23);
166     m_monoster->move (r*212, r*41);
167     m_playstatus->move(r*24, r*28);
168     m_volumeBar->move(r*107, r*57);
169     m_balanceBar->move(r*177, r*57);
170     m_timeIndicator->move(r*34, r*26);
171     m_aboutWidget->setGeometry(r*247,r*83,r*20,r*25);
172 }
173 
setTime(qint64 t)174 void MainDisplay::setTime (qint64 t)
175 {
176     m_posbar->setValue (t);
177     m_timeIndicatorModel->setPosition(t/1000);
178 }
setDuration(qint64 t)179 void MainDisplay::setDuration(qint64 t)
180 {
181     m_posbar->setMaximum (t);
182     m_timeIndicatorModel->setDuration(t/1000);
183 }
184 
setState(Qmmp::State state)185 void MainDisplay::setState(Qmmp::State state)
186 {
187     switch ((int) state)
188     {
189     case Qmmp::Playing:
190         m_playstatus->setStatus(PlayStatus::PLAY);
191         m_timeIndicatorModel->setVisible(true);
192         setDuration(m_core->duration());
193         break;
194     case Qmmp::Paused:
195         m_playstatus->setStatus(PlayStatus::PAUSE);
196         break;
197     case Qmmp::Stopped:
198         m_playstatus->setStatus(PlayStatus::STOP);
199         m_monoster->setChannels (0);
200         m_timeIndicatorModel->setVisible(false);
201         m_posbar->setValue (0);
202         m_posbar->setMaximum (0);
203     }
204 }
205 
onAudioPatametersChanged(const AudioParameters & p)206 void MainDisplay::onAudioPatametersChanged(const AudioParameters &p)
207 {
208     m_monoster->setChannels(p.channels());
209     m_freq->display(int(p.sampleRate()) / 1000);
210 }
211 
updateSkin()212 void MainDisplay::updateSkin()
213 {
214     setPixmap (m_skin->getMain());
215     m_mw->resize(size());
216     setCursor(m_skin->getCursor(Skin::CUR_NORMAL));
217     setMinimalMode(m_shaded);
218     updatePositions();
219 }
220 
updateMask()221 void MainDisplay::updateMask()
222 {
223     m_mw->clearMask();
224     m_mw->setMask(QRegion(0,0,m_mw->width(),m_mw->height()));
225     QRegion region = m_skin->getRegion(m_shaded? Skin::WINDOW_SHADE : Skin::NORMAL);
226     if (!region.isEmpty())
227         m_mw->setMask(region);
228 }
229 
setMinimalMode(bool b)230 void MainDisplay::setMinimalMode(bool b)
231 {
232     m_shaded = b;
233     int r = m_skin->ratio();
234 
235     if(m_shaded)
236          m_mw->setFixedSize(r*275,r*14);
237     else
238          m_mw->setFixedSize(r*275,r*116);
239     updateMask();
240 }
241 
setActive(bool b)242 void MainDisplay::setActive(bool b)
243 {
244     m_titlebar->setActive(b);
245 }
246 
247 //TODO optimize this connections
setEQ(QWidget * w)248 void MainDisplay::setEQ (QWidget* w)
249 {
250     m_equlizer = w;
251     m_eqButton->setChecked (m_equlizer->isVisible());
252     ACTION(ActionManager::SHOW_EQUALIZER)->setChecked(m_equlizer->isVisible());
253 
254     connect (ACTION(ActionManager::SHOW_EQUALIZER), SIGNAL(triggered(bool)),
255              m_equlizer, SLOT (setVisible (bool)));
256     connect (ACTION(ActionManager::SHOW_EQUALIZER), SIGNAL(triggered(bool)),
257              m_eqButton, SLOT (setChecked (bool)));
258 
259     connect (m_eqButton, SIGNAL(clicked(bool)),
260              ACTION(ActionManager::SHOW_EQUALIZER), SLOT(setChecked (bool)));
261     connect (m_eqButton, SIGNAL(clicked(bool)), m_equlizer, SLOT (setVisible (bool)));
262     connect (m_equlizer, SIGNAL(closed ()), m_eqButton, SLOT (click()));
263 }
264 
setPL(QWidget * w)265 void MainDisplay::setPL (QWidget* w)
266 {
267     m_playlist = w;
268     m_plButton->setChecked (m_playlist->isVisible());
269     ACTION(ActionManager::SHOW_PLAYLIST)->setChecked(m_playlist->isVisible());
270 
271     connect (ACTION(ActionManager::SHOW_PLAYLIST), SIGNAL(triggered(bool)),
272              m_playlist, SLOT (setVisible (bool)));
273     connect (ACTION(ActionManager::SHOW_PLAYLIST), SIGNAL(triggered(bool)),
274              m_plButton, SLOT (setChecked (bool)));
275 
276     connect (m_plButton, SIGNAL(clicked(bool)),
277              ACTION(ActionManager::SHOW_PLAYLIST), SLOT(setChecked (bool)));
278     connect (m_plButton, SIGNAL (clicked (bool)), m_playlist, SLOT (setVisible (bool)));
279     connect (m_playlist, SIGNAL (closed ()), m_plButton, SLOT (click()));
280 }
281 
isPlaylistVisible() const282 bool MainDisplay::isPlaylistVisible() const
283 {
284     return m_plButton->isChecked();
285 }
286 
isEqualizerVisible() const287 bool MainDisplay::isEqualizerVisible() const
288 {
289     return m_eqButton->isChecked();
290 }
291 
displayVolume()292 void MainDisplay::displayVolume()
293 {
294     if(sender() == m_volumeBar)
295         m_text->setText(tr("Volume: %1%").arg(m_volumeBar->value()));
296     if(sender() == m_balanceBar)
297     {
298         if(m_balanceBar->value() > 0)
299             m_text->setText(tr("Balance: %1% right").arg(m_balanceBar->value()));
300         else if(m_balanceBar->value() < 0)
301             m_text->setText(tr("Balance: %1% left").arg(-m_balanceBar->value()));
302         else
303             m_text->setText(tr("Balance: center"));
304     }
305 }
306 
showPosition()307 void MainDisplay::showPosition()
308 {
309     m_text->setText(tr("Seek to: %1").arg(MetaDataFormatter::formatDuration(m_posbar->value(), false)));
310 }
311 
updatePosition()312 void MainDisplay::updatePosition()
313 {
314     m_text->clear();
315     m_core->seek(m_posbar->value());
316 }
317 
wheelEvent(QWheelEvent * e)318 void MainDisplay::wheelEvent (QWheelEvent *e)
319 {
320     m_core->changeVolume(e->delta()/10);
321 }
322 
isRepeatable() const323 bool MainDisplay::isRepeatable() const
324 {
325     return m_repeatButton->isChecked();
326 }
327 
isShuffle() const328 bool MainDisplay::isShuffle() const
329 {
330     return m_shuffleButton->isChecked();
331 }
332 
setIsRepeatable(bool yes)333 void MainDisplay::setIsRepeatable(bool yes)
334 {
335     m_repeatButton->setChecked(yes);
336 }
337 
setIsShuffle(bool yes)338 void MainDisplay::setIsShuffle(bool yes)
339 {
340     m_shuffleButton->setChecked(yes);
341 }
342 
mousePressEvent(QMouseEvent * e)343 void MainDisplay::mousePressEvent(QMouseEvent *e)
344 {
345     if (e->button() == Qt::RightButton)
346         m_mw->menu()->exec(e->globalPos());
347     else if(e->button() == Qt::LeftButton && m_aboutWidget->underMouse())
348         m_mw->about();
349     PixmapWidget::mousePressEvent(e);
350 }
351