1 /* ============================================================
2  *
3  * This file is a part of digiKam project
4  * https://www.digikam.org
5  *
6  * Date        : 2014-09-18
7  * Description : slideshow OSD widget
8  *
9  * Copyright (C) 2014-2021 by Gilles Caulier <caulier dot gilles at gmail dot com>
10  * Copyright (C) 2019-2020 by Minh Nghia Duong <minhnghiaduong997 at gmail dot com>
11  * Copyright (C)      2021 by Phuoc Khanh Le <phuockhanhnk94 at gmail dot com>
12  *
13  * This program is free software; you can redistribute it
14  * and/or modify it under the terms of the GNU General
15  * Public License as published by the Free Software Foundation;
16  * either version 2, or (at your option)
17  * any later version.
18  *
19  * This program is distributed in the hope that it will be useful,
20  * but WITHOUT ANY WARRANTY; without even the implied warranty of
21  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
22  * GNU General Public License for more details.
23  *
24  * ============================================================ */
25 
26 #include "slideosd.h"
27 
28 // Qt includes
29 
30 #include <QApplication>
31 #include <QProgressBar>
32 #include <QLayout>
33 #include <QTimer>
34 #include <QEvent>
35 #include <QStyle>
36 
37 // Local includes
38 
39 #include "digikam_debug.h"
40 #include "slideshowloader.h"
41 #include "slidetoolbar.h"
42 #include "slideproperties.h"
43 #include "ratingwidget.h"
44 #include "colorlabelwidget.h"
45 #include "picklabelwidget.h"
46 #include "dinfointerface.h"
47 
48 using namespace Digikam;
49 
50 namespace DigikamGenericSlideShowPlugin
51 {
52 
53 class Q_DECL_HIDDEN SlideOSD::Private
54 {
55 public:
56 
Private()57     explicit Private()
58       : paused          (false),
59         video           (false),
60         blink           (false),
61         ready           (false),
62         refresh         (1000),       ///< Progress bar refresh in ms
63         progressBar     (nullptr),
64         progressTimer   (nullptr),
65         labelsBox       (nullptr),
66         progressBox     (nullptr),
67         parent          (nullptr),
68         slideProps      (nullptr),
69         toolBar         (nullptr),
70         ratingWidget    (nullptr),
71         clWidget        (nullptr),
72         plWidget        (nullptr),
73         settings        (nullptr)
74     {
75     }
76 
77     bool                paused;
78     bool                video;
79     bool                blink;
80     bool                ready;
81 
82     int const           refresh;
83 
84     QProgressBar*       progressBar;
85     QTimer*             progressTimer;
86 
87     DHBox*              labelsBox;
88     DHBox*              progressBox;
89 
90     SlideShowLoader*    parent;
91     SlideProperties*    slideProps;
92     SlideToolBar*       toolBar;
93     RatingWidget*       ratingWidget;
94     ColorLabelSelector* clWidget;
95     PickLabelSelector*  plWidget;
96     SlideShowSettings*  settings;
97 };
98 
SlideOSD(SlideShowSettings * const settings,SlideShowLoader * const parent)99 SlideOSD::SlideOSD(SlideShowSettings* const settings, SlideShowLoader* const parent)
100     : QWidget(parent),
101       d      (new Private())
102 {
103     Qt::WindowFlags flags = Qt::FramelessWindowHint  |
104                             Qt::WindowStaysOnTopHint |
105                             Qt::X11BypassWindowManagerHint;
106 
107     setWindowFlags(flags);
108     setAttribute(Qt::WA_TranslucentBackground, true);
109     setAttribute(Qt::WA_ShowWithoutActivating, true);
110     setMouseTracking(true);
111 
112     d->parent       = parent;
113     d->settings     = settings;
114 
115     d->slideProps   = new SlideProperties(d->settings, this);
116     d->slideProps->installEventFilter(d->parent);
117 
118     // ---------------------------------------------------------------
119 
120     d->labelsBox    = new DHBox(this);
121 
122     d->clWidget     = new ColorLabelSelector(d->labelsBox);
123     d->clWidget->installEventFilter(this);
124     d->clWidget->installEventFilter(d->parent);
125     d->clWidget->colorLabelWidget()->installEventFilter(this);
126     d->clWidget->setFocusPolicy(Qt::NoFocus);
127     d->clWidget->setMouseTracking(true);
128 
129     d->plWidget     = new PickLabelSelector(d->labelsBox);
130     d->plWidget->installEventFilter(this);
131     d->plWidget->installEventFilter(d->parent);
132     d->plWidget->setFocusPolicy(Qt::NoFocus);
133     d->plWidget->pickLabelWidget()->installEventFilter(this);
134     d->plWidget->setMouseTracking(true);
135 
136     d->ratingWidget = new RatingWidget(d->labelsBox);
137     d->ratingWidget->setTracking(false);
138     d->ratingWidget->setFading(false);
139     d->ratingWidget->installEventFilter(this);
140     d->ratingWidget->installEventFilter(d->parent);
141     d->ratingWidget->setFocusPolicy(Qt::NoFocus);
142     d->ratingWidget->setMouseTracking(true);
143 
144     d->labelsBox->layout()->setAlignment(d->ratingWidget, Qt::AlignVCenter | Qt::AlignLeft);
145     d->labelsBox->installEventFilter(d->parent);
146     d->labelsBox->setMouseTracking(true);
147 
148     d->labelsBox->setVisible(d->settings->printLabels || d->settings->printRating);
149     d->ratingWidget->setVisible(d->settings->printRating);
150     d->clWidget->setVisible(d->settings->printLabels);
151     d->plWidget->setVisible(d->settings->printLabels);
152 
153     connect(d->ratingWidget, SIGNAL(signalRatingChanged(int)),
154             parent, SLOT(slotAssignRating(int)));
155 
156     connect(d->clWidget, SIGNAL(signalColorLabelChanged(int)),
157             parent, SLOT(slotAssignColorLabel(int)));
158 
159     connect(d->plWidget, SIGNAL(signalPickLabelChanged(int)),
160             parent, SLOT(slotAssignPickLabel(int)));
161 
162     // ---------------------------------------------------------------
163 
164     d->progressBox   = new DHBox(this);
165     d->progressBox->setVisible(d->settings->showProgressIndicator);
166     d->progressBox->installEventFilter(d->parent);
167     d->progressBox->setMouseTracking(true);
168 
169     d->progressBar   = new QProgressBar(d->progressBox);
170     d->progressBar->setMinimum(0);
171     d->progressBar->setMaximum(d->settings->delay);
172     d->progressBar->setFocusPolicy(Qt::NoFocus);
173     d->progressBar->installEventFilter(d->parent);
174     d->progressBar->setMouseTracking(true);
175 
176     d->toolBar       = new SlideToolBar(d->settings, d->progressBox);
177     d->toolBar->installEventFilter(this);
178     d->toolBar->installEventFilter(d->parent);
179 
180     connect(d->toolBar, SIGNAL(signalPause()),
181             d->parent, SLOT(slotPause()));
182 
183     connect(d->toolBar, SIGNAL(signalPlay()),
184             d->parent, SLOT(slotPlay()));
185 
186     connect(d->toolBar, SIGNAL(signalNext()),
187             d->parent, SLOT(slotLoadNextItem()));
188 
189     connect(d->toolBar, SIGNAL(signalPrev()),
190             d->parent, SLOT(slotLoadPrevItem()));
191 
192     connect(d->toolBar, SIGNAL(signalClose()),
193             d->parent, SLOT(close()));
194 
195     connect(d->toolBar, SIGNAL(signalRemoveImageFromList()),
196             d->parent, SLOT(slotRemoveImageFromList()));
197 
198     connect(d->toolBar, SIGNAL(signalUpdateSettings()),
199             this, SLOT(slotUpdateSettings()));
200 
201     connect(d->toolBar, SIGNAL(signalScreenSelected(int)),
202             d->parent, SLOT(slotScreenSelected(int)));
203 
204     // ---------------------------------------------------------------
205 
206     QGridLayout* const grid = new QGridLayout(this);
207     grid->addWidget(d->slideProps,  0, 0, 1, 2);
208     grid->addWidget(d->labelsBox,   1, 0, 1, 1);
209     grid->addWidget(d->progressBox, 2, 0, 1, 1);
210     grid->setRowStretch(0, 10);
211     grid->setColumnStretch(1, 10);
212     grid->setContentsMargins(QMargins());
213     grid->setSpacing(QApplication::style()->pixelMetric(QStyle::PM_DefaultLayoutSpacing));
214 
215     // ---------------------------------------------------------------
216 
217     d->progressTimer = new QTimer(this);
218     d->progressTimer->setSingleShot(false);
219 
220     connect(d->progressTimer, SIGNAL(timeout()),
221             this, SLOT(slotProgressTimer()));
222 
223     QTimer::singleShot(500, this, SLOT(slotStart()));
224 }
225 
~SlideOSD()226 SlideOSD::~SlideOSD()
227 {
228     d->progressTimer->stop();
229 
230     delete d;
231 }
232 
slotStart()233 void SlideOSD::slotStart()
234 {
235     d->settings->suffleImages();
236     d->parent->slotLoadNextItem();
237     d->progressTimer->start(d->refresh);
238     pause(!d->settings->autoPlayEnabled);
239 }
240 
slotUpdateSettings()241 void SlideOSD::slotUpdateSettings()
242 {
243     d->labelsBox->setVisible(d->settings->printLabels || d->settings->printRating);
244     d->progressBox->setVisible(d->settings->showProgressIndicator);
245     d->ratingWidget->setVisible(d->settings->printRating);
246     d->clWidget->setVisible(d->settings->printLabels);
247     d->plWidget->setVisible(d->settings->printLabels);
248     d->progressBar->setMaximum(d->settings->delay);
249     d->settings->suffleImages();
250 }
251 
toolBar() const252 SlideToolBar* SlideOSD::toolBar() const
253 {
254     return d->toolBar;
255 }
256 
setCurrentUrl(const QUrl & url)257 void SlideOSD::setCurrentUrl(const QUrl& url)
258 {
259     DInfoInterface::DInfoMap info = d->settings->iface->itemInfo(url);
260     DItemInfo item(info);
261 
262     // Update info text.
263 
264     d->slideProps->setCurrentUrl(url);
265 
266     // Display Labels.
267 
268     if (d->settings->printLabels)
269     {
270         d->clWidget->blockSignals(true);
271         d->plWidget->blockSignals(true);
272         d->clWidget->setColorLabel((ColorLabel)item.colorLabel());
273         d->plWidget->setPickLabel((PickLabel)item.pickLabel());
274         d->clWidget->blockSignals(false);
275         d->plWidget->blockSignals(false);
276     }
277 
278     if (d->settings->printRating)
279     {
280         d->ratingWidget->blockSignals(true);
281         d->ratingWidget->setRating(item.rating());
282         d->ratingWidget->blockSignals(false);
283     }
284 
285     // Make the OSD the proper size
286 
287     resize(d->parent->width() - 10, d->parent->height());
288     move(10, 0);
289     raise();
290 }
291 
slideShowSize() const292 QSize SlideOSD::slideShowSize() const
293 {
294     return d->parent->size();
295 }
296 
eventFilter(QObject * obj,QEvent * ev)297 bool SlideOSD::eventFilter(QObject* obj, QEvent* ev)
298 {
299     if (
300         (obj == d->labelsBox)                    ||
301         (obj == d->ratingWidget)                 ||
302         (obj == d->clWidget)                     ||
303         (obj == d->plWidget)                     ||
304         (obj == d->clWidget->colorLabelWidget()) ||
305         (obj == d->plWidget->pickLabelWidget())
306        )
307     {
308         if (ev->type() == QEvent::Enter)
309         {
310             d->paused = isPaused();
311             d->parent->slotPause();
312 
313             return false;
314         }
315 
316         if (ev->type() == QEvent::Leave)
317         {
318             if (!d->paused)
319             {
320                 d->parent->slotPlay();
321             }
322 
323             return false;
324         }
325     }
326 
327     // pass the event on to the parent class
328 
329     return QWidget::eventFilter(obj, ev);
330 }
331 
slotProgressTimer()332 void SlideOSD::slotProgressTimer()
333 {
334     QString str = QString::fromUtf8("(%1/%2)")
335                     .arg(QString::number(d->settings->fileList.indexOf(d->parent->currentItem()) + 1))
336                     .arg(QString::number(d->settings->fileList.count()));
337 
338     if      (isPaused())
339     {
340         d->blink = !d->blink;
341 
342         if (d->blink)
343         {
344             str = QString();
345         }
346 
347         d->progressBar->setFormat(str);
348     }
349     else if (d->video)
350     {
351         d->progressBar->setFormat(str);
352         return;
353     }
354     else
355     {
356         d->progressBar->setFormat(str);
357         d->progressBar->setMaximum(d->settings->delay);
358 
359         if (d->progressBar->value() == d->settings->delay)
360         {
361             if (!d->ready)
362             {
363                 return;
364             }
365 
366             d->ready = false;
367             d->parent->slotLoadNextItem();
368         }
369 
370         d->progressBar->setValue(d->progressBar->value()+1);
371     }
372 }
373 
pause(bool b)374 void SlideOSD::pause(bool b)
375 {
376     d->toolBar->pause(b);
377 
378     if (!b)
379     {
380         d->progressBar->setValue(0);
381     }
382 }
383 
video(bool b)384 void SlideOSD::video(bool b)
385 {
386     d->video = b;
387 }
388 
isPaused() const389 bool SlideOSD::isPaused() const
390 {
391     return d->toolBar->isPaused();
392 }
393 
isUnderMouse() const394 bool SlideOSD::isUnderMouse() const
395 {
396     return (
397             d->ratingWidget->underMouse() ||
398             d->progressBar->underMouse()  ||
399             d->clWidget->underMouse()     ||
400             d->plWidget->underMouse()     ||
401             d->toolBar->underMouse()
402            );
403 }
404 
toggleProperties()405 void SlideOSD::toggleProperties()
406 {
407     d->slideProps->togglePaintEnabled();
408 }
409 
setLoadingReady(bool b)410 void SlideOSD::setLoadingReady(bool b)
411 {
412     d->ready = b;
413 }
414 
415 } // namespace DigikamGenericSlideShowPlugin
416