1 // Copyright 2005-2019 The Mumble Developers. All rights reserved.
2 // Use of this source code is governed by a BSD-style license
3 // that can be found in the LICENSE file at the root of the
4 // Mumble source tree or at <https://www.mumble.info/LICENSE>.
5 
6 #include "mumble_pch.hpp"
7 
8 #include "OverlayPositionableItem.h"
9 
OverlayPositionableItem(QRectF * posPtr,const bool isPositionable)10 OverlayPositionableItem::OverlayPositionableItem(QRectF *posPtr, const bool isPositionable)
11 	: m_position(posPtr)
12 	, m_isPositionEditable(isPositionable)
13 	, m_qgeiHandle(NULL) {
14 }
15 
~OverlayPositionableItem()16 OverlayPositionableItem::~OverlayPositionableItem() {
17 	delete m_qgeiHandle;
18 	m_qgeiHandle = NULL;
19 }
20 
createPositioningHandle()21 void OverlayPositionableItem::createPositioningHandle() {
22 	m_qgeiHandle = new QGraphicsEllipseItem(QRectF(-4.0f, -4.0f, 8.0f, 8.0f));
23 	m_qgeiHandle->setPen(QPen(Qt::darkRed, 0.0f));
24 	m_qgeiHandle->setBrush(Qt::red);
25 	m_qgeiHandle->setZValue(0.5f);
26 	m_qgeiHandle->setFlag(QGraphicsItem::ItemIsMovable);
27 	m_qgeiHandle->setFlag(QGraphicsItem::ItemIsSelectable);
28 	scene()->addItem(m_qgeiHandle);
29 	m_qgeiHandle->installSceneEventFilter(this);
30 }
31 
sceneEventFilter(QGraphicsItem * watched,QEvent * e)32 bool OverlayPositionableItem::sceneEventFilter(QGraphicsItem *watched, QEvent *e) {
33 	switch (e->type()) {
34 		case QEvent::GraphicsSceneMouseMove:
35 		case QEvent::GraphicsSceneMouseRelease:
36 			QMetaObject::invokeMethod(this, "onMove", Qt::QueuedConnection);
37 			break;
38 		default:
39 			break;
40 	}
41 	return QGraphicsItem::sceneEventFilter(watched, e);
42 }
43 
onMove()44 void OverlayPositionableItem::onMove() {
45 	if (m_qgeiHandle == NULL) {
46 		return;
47 	}
48 
49 	const QRectF &sr = scene()->sceneRect();
50 	const QPointF &p = m_qgeiHandle->pos();
51 
52 	m_position->setX(qBound<qreal>(0.0f, p.x() / sr.width(), 1.0f));
53 	m_position->setY(qBound<qreal>(0.0f, p.y() / sr.height(), 1.0f));
54 
55 	m_qgeiHandle->setPos(m_position->x() * sr.width(), m_position->y() * sr.height());
56 
57 	updateRender();
58 }
59 
updateRender()60 void OverlayPositionableItem::updateRender() {
61 	const QRectF &sr = scene()->sceneRect();
62 	// Translate the 0..1 float position to the real scene coordinates (relative to absolute position)
63 	QPoint absPos(iroundf(sr.width() * m_position->x() + 0.5f), iroundf(sr.height() * m_position->y() + 0.5f));
64 
65 	if (m_isPositionEditable) {
66 		if (m_qgeiHandle == NULL) {
67 			createPositioningHandle();
68 		}
69 		m_qgeiHandle->setPos(absPos.x(), absPos.y());
70 	}
71 
72 	QRectF br = boundingRect();
73 	// Limit the position by the elements width (to make sure it is right-/bottom-bound rather than outside of the scene
74 	QPoint maxPos(iroundf(sr.width() - br.width() + 0.5f), iroundf(sr.height() - br.height() + 0.5f));
75 	int basex = qBound<int>(0, absPos.x(), maxPos.x());
76 	int basey = qBound<int>(0, absPos.y(), maxPos.y());
77 	setPos(basex, basey);
78 }
79 
setItemVisible(const bool & visible)80 void OverlayPositionableItem::setItemVisible(const bool &visible) {
81 	setVisible(visible);
82 	if (m_qgeiHandle != NULL) {
83 		m_qgeiHandle->setVisible(visible);
84 	}
85 }
86