1 /* smplayer, GUI front-end for mplayer.
2 Copyright (C) 2006-2021 Ricardo Villalba <ricardo@smplayer.info>
3
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2 of the License, or
7 (at your option) any later version.
8
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
13
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17 */
18
19 #include "mplayerwindow.h"
20 #include "global.h"
21 #include "desktopinfo.h"
22 #include "colorutils.h"
23 #include "screenhelper.h"
24
25 #ifndef MINILIB
26 #include "images.h"
27 #endif
28
29 #include <QLabel>
30 #include <QTimer>
31 #include <QCursor>
32 #include <QEvent>
33 #include <QLayout>
34 #include <QPixmap>
35 #include <QPainter>
36 #include <QApplication>
37 #include <QTimer>
38 #include <QDebug>
39
40 #if LOGO_ANIMATION
41 #include <QPropertyAnimation>
42 #endif
43
44 //#define HANDLE_GESTURES
45
46 #ifdef HANDLE_GESTURES
47 #include <QGestureEvent>
48 #include <QTapGesture>
49 #endif
50
51 #if defined(USE_SHM) || defined(USE_COREVIDEO_BUFFER)
52 #include "videolayerrender.h"
53 #endif
54
MplayerWindow(QWidget * parent,Qt::WindowFlags f)55 MplayerWindow::MplayerWindow(QWidget* parent, Qt::WindowFlags f)
56 : QWidget(parent, f)
57 , video_width(0)
58 , video_height(0)
59 , aspect((double) 4/3)
60 , monitoraspect(0)
61 , logo(0)
62 , videolayer(0)
63 , offset_x(0)
64 , offset_y(0)
65 , zoom_factor(1.0)
66 , orig_x(0)
67 , orig_y(0)
68 , orig_width(0)
69 , orig_height(0)
70 , allow_video_movement(false)
71 #if DELAYED_RESIZE
72 , resize_timer(0)
73 #endif
74 , delay_left_click(false)
75 , left_click_timer(0)
76 , double_clicked(false)
77 #if LOGO_ANIMATION
78 , animated_logo(false)
79 #endif
80 , corner_widget(0)
81 , drag_state(NOT_DRAGGING)
82 , start_drag(QPoint(0,0))
83 , mouse_drag_tracking(false)
84 {
85 helper = new ScreenHelper(this);
86 connect(helper, SIGNAL(mouseMoved(QPoint)), this, SIGNAL(mouseMoved(QPoint)));
87
88 #if defined(USE_SHM) || defined(USE_COREVIDEO_BUFFER)
89 videolayer = new VideoLayerRender(this);
90 #else
91 videolayer = new VideoLayer(this);
92 #endif
93
94 logo = new QLabel( this );
95 logo->setObjectName("mplayerwindowlogo");
96
97 // Set colors
98 #ifdef CHANGE_WIDGET_COLOR
99 setAutoFillBackground(true);
100 ColorUtils::setBackgroundColor( this, QColor(0,0,0) );
101 videolayer->setAutoFillBackground(true);
102 logo->setAutoFillBackground(true);
103 ColorUtils::setBackgroundColor( logo, QColor(0,0,0) );
104 #else
105 setStyleSheet("MplayerWindow { background-color: black;}");
106 videolayer->setStyleSheet("background-color: black;");
107 #endif
108
109 QVBoxLayout * videolayerLayout = new QVBoxLayout( this );
110 videolayerLayout->addWidget( logo, 0, Qt::AlignHCenter | Qt::AlignVCenter );
111
112 setSizePolicy( QSizePolicy::Expanding , QSizePolicy::Expanding );
113 setFocusPolicy( Qt::StrongFocus );
114
115 //#ifdef HANDLE_GESTURES
116 grabGesture(Qt::TapGesture);
117 //#endif
118
119 installEventFilter(this);
120 //videolayer->installEventFilter(this);
121 //logo->installEventFilter(this);
122
123 #if DELAYED_RESIZE
124 resize_timer = new QTimer(this);
125 resize_timer->setSingleShot(true);
126 resize_timer->setInterval(50);
127 connect( resize_timer, SIGNAL(timeout()), this, SLOT(resizeLater()) );
128 #endif
129
130 left_click_timer = new QTimer(this);
131 left_click_timer->setSingleShot(true);
132 left_click_timer->setInterval(qApp->doubleClickInterval()+10);
133 connect(left_click_timer, SIGNAL(timeout()), this, SIGNAL(leftClicked()));
134
135 retranslateStrings();
136 }
137
~MplayerWindow()138 MplayerWindow::~MplayerWindow() {
139 }
140
setCornerWidget(QWidget * w)141 void MplayerWindow::setCornerWidget(QWidget * w) {
142 corner_widget = w;
143
144 QHBoxLayout * blayout = new QHBoxLayout;
145 blayout->addSpacerItem(new QSpacerItem(20, 20, QSizePolicy::Expanding));
146 blayout->addWidget(corner_widget);
147
148 QVBoxLayout * layout = new QVBoxLayout(this);
149 layout->addSpacerItem(new QSpacerItem(20, 20, QSizePolicy::Expanding, QSizePolicy::Expanding));
150 layout->addLayout(blayout);
151 }
152
153 #if USE_COLORKEY
setColorKey(QColor c)154 void MplayerWindow::setColorKey( QColor c ) {
155 #ifdef CHANGE_WIDGET_COLOR
156 ColorUtils::setBackgroundColor( videolayer, c );
157 #endif
158 }
159 #endif
160
retranslateStrings()161 void MplayerWindow::retranslateStrings() {
162 //qDebug("MplayerWindow::retranslateStrings");
163 #ifndef MINILIB
164 logo->setPixmap( Images::icon("background") );
165 #endif
166 }
167
playingStarted()168 void MplayerWindow::playingStarted() {
169 helper->playingStarted();
170 videolayer->playingStarted();
171 }
172
playingStopped()173 void MplayerWindow::playingStopped() {
174 helper->playingStopped();
175 videolayer->playingStopped();
176 }
177
gotVO(QString vo)178 void MplayerWindow::gotVO(QString vo) {
179 videolayer->gotVO(vo);
180 }
181
182 #if REPAINT_BACKGROUND_OPTION
setRepaintBackground(bool b)183 void MplayerWindow::setRepaintBackground(bool b) {
184 repaint_background = b;
185 videolayer->setRepaintBackground(b);
186 }
187 #endif
188
setLogoVisible(bool b)189 void MplayerWindow::setLogoVisible( bool b) {
190 qDebug() << "MplayerWindow::setLogoVisible:" << b;
191
192 #if REPAINT_BACKGROUND_OPTION
193 if (b) videolayer->setUpdatesEnabled(true);
194 #endif
195
196 if (corner_widget) {
197 corner_widget->setVisible(b);
198 }
199
200 #if !LOGO_ANIMATION
201 logo->setVisible(b);
202 #else
203 if (!animated_logo) {
204 logo->setVisible(b);
205 } else {
206 if (b) {
207 logo->show();
208 QPropertyAnimation * animation = new QPropertyAnimation(logo, "pos");
209 animation->setDuration(200);
210 animation->setEasingCurve(QEasingCurve::OutBounce);
211 animation->setStartValue(QPoint(logo->x(), 0 - logo->y()));
212 animation->setEndValue(logo->pos());
213 animation->start();
214 } else {
215 QPropertyAnimation * animation = new QPropertyAnimation(logo, "pos");
216 animation->setDuration(200);
217 animation->setEasingCurve(QEasingCurve::OutBounce);
218 animation->setEndValue(QPoint(width(), logo->y()));
219 animation->setStartValue(logo->pos());
220 animation->start();
221 connect(animation, SIGNAL(finished()), logo, SLOT(hide()));
222 //logo->hide();
223 }
224 }
225 #endif
226 }
227
228 /*
229 void MplayerWindow::changePolicy() {
230 setSizePolicy( QSizePolicy::Preferred , QSizePolicy::Preferred );
231 }
232 */
233
setResolution(int w,int h)234 void MplayerWindow::setResolution( int w, int h)
235 {
236 video_width = w;
237 video_height = h;
238
239 //videolayer->move(1,1);
240 updateVideoWindow();
241 }
242
243
resizeEvent(QResizeEvent *)244 void MplayerWindow::resizeEvent( QResizeEvent * /* e */)
245 {
246 /*qDebug("MplayerWindow::resizeEvent: %d, %d",
247 e->size().width(), e->size().height() );*/
248
249 #if !DELAYED_RESIZE
250 offset_x = 0;
251 offset_y = 0;
252
253 updateVideoWindow();
254 setZoom(zoom_factor);
255 #else
256 resize_timer->start();
257 #endif
258 }
259
260 #if DELAYED_RESIZE
resizeLater()261 void MplayerWindow::resizeLater() {
262 offset_x = 0;
263 offset_y = 0;
264
265 updateVideoWindow();
266 setZoom(zoom_factor);
267 }
268 #endif
269
setMonitorAspect(double asp)270 void MplayerWindow::setMonitorAspect(double asp) {
271 monitoraspect = asp;
272 }
273
setAspect(double asp)274 void MplayerWindow::setAspect( double asp) {
275 aspect = asp;
276 if (monitoraspect!=0) {
277 aspect = aspect / monitoraspect * DesktopInfo::desktop_aspectRatio(this);
278 }
279 updateVideoWindow();
280 }
281
282
updateVideoWindow()283 void MplayerWindow::updateVideoWindow()
284 {
285 //qDebug("MplayerWindow::updateVideoWindow");
286
287 //qDebug("aspect= %f", aspect);
288
289 int w_width = size().width();
290 int w_height = size().height();
291
292 int w = w_width;
293 int h = w_height;
294 int x = 0;
295 int y = 0;
296
297 if (aspect != 0) {
298 int pos1_w = w_width;
299 int pos1_h = w_width / aspect + 0.5;
300
301 int pos2_h = w_height;
302 int pos2_w = w_height * aspect + 0.5;
303
304 //qDebug("pos1_w: %d, pos1_h: %d", pos1_w, pos1_h);
305 //qDebug("pos2_w: %d, pos2_h: %d", pos2_w, pos2_h);
306
307 if (pos1_h <= w_height) {
308 //qDebug("Pos1!");
309 w = pos1_w;
310 h = pos1_h;
311
312 y = (w_height - h) /2;
313 } else {
314 //qDebug("Pos2!");
315 w = pos2_w;
316 h = pos2_h;
317
318 x = (w_width - w) /2;
319 }
320 }
321
322 videolayer->move(x,y);
323 videolayer->resize(w, h);
324
325 orig_x = x;
326 orig_y = y;
327 orig_width = w;
328 orig_height = h;
329
330 //qDebug( "w_width: %d, w_height: %d", w_width, w_height);
331 //qDebug("w: %d, h: %d", w,h);
332 }
333
334
mouseReleaseEvent(QMouseEvent * e)335 void MplayerWindow::mouseReleaseEvent( QMouseEvent * e) {
336 qDebug( "MplayerWindow::mouseReleaseEvent" );
337
338 if (e->button() == Qt::LeftButton) {
339 e->accept();
340 if (delay_left_click) {
341 if (!double_clicked) left_click_timer->start();
342 double_clicked = false;
343 } else {
344 emit leftClicked();
345 }
346 }
347 else
348 if (e->button() == Qt::MiddleButton) {
349 e->accept();
350 emit middleClicked();
351 }
352 else
353 if (e->button() == Qt::XButton1) {
354 e->accept();
355 emit xbutton1Clicked();
356 }
357 else
358 if (e->button() == Qt::XButton2) {
359 e->accept();
360 emit xbutton2Clicked();
361 }
362 else
363 if (e->button() == Qt::RightButton) {
364 e->accept();
365 //emit rightButtonReleased( e->globalPos() );
366 emit rightClicked();
367 }
368 else {
369 e->ignore();
370 }
371 }
372
mouseDoubleClickEvent(QMouseEvent * e)373 void MplayerWindow::mouseDoubleClickEvent( QMouseEvent * e ) {
374 if (e->button() == Qt::LeftButton) {
375 e->accept();
376 if (delay_left_click) {
377 left_click_timer->stop();
378 double_clicked = true;
379 }
380 emit doubleClicked();
381 } else {
382 e->ignore();
383 }
384 }
385
wheelEvent(QWheelEvent * e)386 void MplayerWindow::wheelEvent( QWheelEvent * e ) {
387 #if (QT_VERSION >= QT_VERSION_CHECK(5, 12, 0))
388 qDebug("MplayerWindow::wheelEvent: delta: %d", e->angleDelta().y());
389 e->accept();
390 if (e->angleDelta().y() >= 0) emit wheelUp(); else emit wheelDown();
391 #else
392 qDebug("MplayerWindow::wheelEvent: delta: %d", e->delta());
393 e->accept();
394 if (e->orientation() == Qt::Vertical) {
395 if (e->delta() >= 0) emit wheelUp(); else emit wheelDown();
396 }
397 #endif
398 }
399
eventFilter(QObject * object,QEvent * event)400 bool MplayerWindow::eventFilter( QObject * object, QEvent * event ) {
401 Q_UNUSED(object);
402
403 #ifdef HANDLE_GESTURES
404 if (event->type() == QEvent::Gesture) {
405 qDebug() << "MplayerWindow::eventFilter: event:" << event;
406 QGestureEvent * ge = static_cast<QGestureEvent*>(event);
407 qDebug() << "MplayerWindow::eventFilter: ge:" << ge;
408 if (QGesture * tap = ge->gesture(Qt::TapGesture)) {
409 QTapGesture * tg = static_cast<QTapGesture *>(tap);
410 qDebug() << "MplayerWindow::eventFilter: tg:" << tg;
411 event->setAccepted(true);
412 return false;
413 }
414 }
415 #endif
416
417 if (!mouse_drag_tracking)
418 return false;
419
420 QEvent::Type type = event->type();
421 if (type != QEvent::MouseButtonPress
422 && type != QEvent::MouseButtonRelease
423 && type != QEvent::MouseMove)
424 return false;
425
426 QMouseEvent *mouseEvent = dynamic_cast<QMouseEvent*>(event);
427 if (!mouseEvent)
428 return false;
429
430 if (mouseEvent->modifiers() != Qt::NoModifier) {
431 drag_state = NOT_DRAGGING;
432 return false;
433 }
434
435 if (type == QEvent::MouseButtonPress) {
436 if (mouseEvent->button() != Qt::LeftButton) {
437 drag_state = NOT_DRAGGING;
438 return false;
439 }
440
441 drag_state = START_DRAGGING;
442 start_drag = mouseEvent->globalPos();
443 // Don't filter, so others can have a look at it too
444 return false;
445 }
446
447 if (type == QEvent::MouseButtonRelease) {
448 if (drag_state != DRAGGING || mouseEvent->button() != Qt::LeftButton) {
449 drag_state = NOT_DRAGGING;
450 return false;
451 }
452
453 // Stop dragging and eat event
454 drag_state = NOT_DRAGGING;
455 event->accept();
456 return true;
457 }
458
459 // type == QEvent::MouseMove
460 if (drag_state == NOT_DRAGGING)
461 return false;
462
463 // buttons() note the s
464 if (mouseEvent->buttons() != Qt::LeftButton) {
465 drag_state = NOT_DRAGGING;
466 return false;
467 }
468
469 QPoint pos = mouseEvent->globalPos();
470 QPoint diff = pos - start_drag;
471 if (drag_state == START_DRAGGING) {
472 // Don't start dragging before moving at least DRAG_THRESHOLD pixels
473 if (abs(diff.x()) < DRAG_THRESHOLD && abs(diff.y()) < DRAG_THRESHOLD)
474 return false;
475
476 drag_state = DRAGGING;
477 }
478
479 emit mouseMovedDiff(diff);
480 start_drag = pos;
481 event->accept();
482 return true;
483 }
484
sizeHint() const485 QSize MplayerWindow::sizeHint() const {
486 //qDebug("MplayerWindow::sizeHint");
487 return QSize( video_width, video_height );
488 }
489
minimumSizeHint() const490 QSize MplayerWindow::minimumSizeHint () const {
491 return QSize(0,0);
492 }
493
setOffsetX(int d)494 void MplayerWindow::setOffsetX( int d) {
495 offset_x = d;
496 videolayer->move( orig_x + offset_x, videolayer->y() );
497 }
498
offsetX()499 int MplayerWindow::offsetX() { return offset_x; }
500
setOffsetY(int d)501 void MplayerWindow::setOffsetY( int d) {
502 offset_y = d;
503 videolayer->move( videolayer->x(), orig_y + offset_y );
504 }
505
offsetY()506 int MplayerWindow::offsetY() { return offset_y; }
507
setZoom(double d)508 void MplayerWindow::setZoom( double d) {
509 zoom_factor = d;
510 offset_x = 0;
511 offset_y = 0;
512
513 int x = orig_x;
514 int y = orig_y;
515 int w = orig_width;
516 int h = orig_height;
517
518 if (zoom_factor != 1.0) {
519 w = w * zoom_factor;
520 h = h * zoom_factor;
521
522 // Center
523 x = (width() - w) / 2;
524 y = (height() -h) / 2;
525 }
526
527 videolayer->move(x,y);
528 videolayer->resize(w,h);
529 }
530
zoom()531 double MplayerWindow::zoom() { return zoom_factor; }
532
moveLayer(int offset_x,int offset_y)533 void MplayerWindow::moveLayer( int offset_x, int offset_y ) {
534 int x = videolayer->x();
535 int y = videolayer->y();
536
537 videolayer->move( x + offset_x, y + offset_y );
538 }
539
moveLeft()540 void MplayerWindow::moveLeft() {
541 if ((allow_video_movement) || (videolayer->x()+videolayer->width() > width() ))
542 moveLayer( -16, 0 );
543 }
544
moveRight()545 void MplayerWindow::moveRight() {
546 if ((allow_video_movement) || ( videolayer->x() < 0 ))
547 moveLayer( +16, 0 );
548 }
549
moveUp()550 void MplayerWindow::moveUp() {
551 if ((allow_video_movement) || (videolayer->y()+videolayer->height() > height() ))
552 moveLayer( 0, -16 );
553 }
554
moveDown()555 void MplayerWindow::moveDown() {
556 if ((allow_video_movement) || ( videolayer->y() < 0 ))
557 moveLayer( 0, +16 );
558 }
559
incZoom()560 void MplayerWindow::incZoom() {
561 setZoom( zoom_factor + ZOOM_STEP );
562 }
563
decZoom()564 void MplayerWindow::decZoom() {
565 double zoom = zoom_factor - ZOOM_STEP;
566 if (zoom < ZOOM_MIN) zoom = ZOOM_MIN;
567 setZoom( zoom );
568 }
569
570 // Language change stuff
changeEvent(QEvent * e)571 void MplayerWindow::changeEvent(QEvent *e) {
572 if (e->type() == QEvent::LanguageChange) {
573 retranslateStrings();
574 } else {
575 QWidget::changeEvent(e);
576 }
577 }
578
579 #include "moc_mplayerwindow.cpp"
580