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