]> git.sesse.net Git - kdenlive/blob - src/onmonitoritems/onmonitorcornersitem.cpp
Integrate with the required MLT hooks for getting Movit to work.
[kdenlive] / src / onmonitoritems / onmonitorcornersitem.cpp
1 /***************************************************************************
2  *   Copyright (C) 2010 by Till Theato (root@ttill.de)                     *
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                         *
16  *   Free Software Foundation, Inc.,                                       *
17  *   51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA          *
18  ***************************************************************************/
19
20 #include "onmonitorcornersitem.h"
21 #include "kdenlivesettings.h"
22
23 #include <algorithm>
24
25 #include <QGraphicsSceneMouseEvent>
26 #include <QPainter>
27 #include <QStyleOptionGraphicsItem>
28 #include <QCursor>
29 #include <QGraphicsView>
30
31 OnMonitorCornersItem::OnMonitorCornersItem(QGraphicsItem* parent) :
32     QGraphicsPolygonItem(parent)
33   , m_mode(NoAction)
34   , m_selectedCorner(-1)
35   , m_modified(false)
36   , m_view(NULL)
37 {
38     setFlags(QGraphicsItem::ItemIsMovable | QGraphicsItem::ItemIsSelectable);
39
40     QPen framepen(Qt::SolidLine);
41     framepen.setColor(Qt::yellow);
42     setPen(framepen);
43     setBrush(Qt::NoBrush);
44     setAcceptHoverEvents(true);
45 }
46
47 OnMonitorCornersItem::cornersActions OnMonitorCornersItem::getMode(const QPointF &pos, int *corner)
48 {
49     *corner = -1;
50     if (polygon().count() != 4)
51         return NoAction;
52
53     QPainterPath mouseArea;
54     qreal size = 12;
55     if (getView())
56         size /= m_view->matrix().m11();
57     mouseArea.addRect(pos.x() - size / 2, pos.y() - size / 2, size, size);
58     for (int i = 0; i < 4; ++i) {
59         if (mouseArea.contains(polygon().at(i))) {
60             *corner = i;
61             return Corner;
62         }
63     }
64     if (KdenliveSettings::onmonitoreffects_cornersshowcontrols()) {
65         if (mouseArea.contains(getCentroid()))
66             return Move;
67
68         int j;
69         for (int i = 0; i < 4; ++i) {
70             j = (i + 1) % 4;
71             if (mouseArea.contains(QLineF(polygon().at(i), polygon().at(j)).pointAt(.5))) {
72                 *corner = i;
73                 return MoveSide;
74             }
75         }
76     }
77
78     return NoAction;
79 }
80
81 void OnMonitorCornersItem::mousePressEvent(QGraphicsSceneMouseEvent* event)
82 {
83     m_mode = getMode(event->pos(), &m_selectedCorner);
84     m_lastPoint = event->scenePos();
85
86     if (m_mode == NoAction)
87         event->ignore();
88 }
89
90 void OnMonitorCornersItem::mouseMoveEvent(QGraphicsSceneMouseEvent* event)
91 {
92     /*if (event->buttons() != Qt::NoButton && (event->screenPos() - m_screenClickPoint).manhattanLength() < QApplication::startDragDistance()) {
93      *   event->accept();
94      *   return;
95     }*/
96
97     if (event->buttons() & Qt::LeftButton) {
98         QPointF mousePos = mapFromScene(event->scenePos());
99         QPolygonF p = polygon();
100         switch (m_mode) {
101         case Corner:
102             p.replace(m_selectedCorner, mousePos);
103             m_modified = true;
104             break;
105         case Move:
106             p.translate(mousePos - m_lastPoint);
107             m_modified = true;
108             break;
109         case MoveSide:
110             p[m_selectedCorner] += mousePos - m_lastPoint;
111             p[(m_selectedCorner + 1) % 4] += mousePos - m_lastPoint;
112             m_modified = true;
113             break;
114         default:
115             break;
116         }
117         m_lastPoint = mousePos;
118         setPolygon(p);
119     }
120
121     if (m_modified) {
122         event->accept();
123         if (KdenliveSettings::monitorscene_directupdate()) {
124             emit changed();
125             m_modified = false;
126         }
127     } else {
128         event->ignore();
129     }
130 }
131
132 void OnMonitorCornersItem::mouseReleaseEvent(QGraphicsSceneMouseEvent* event)
133 {
134     if (m_modified) {
135         m_modified = false;
136         emit changed();
137     }
138     event->accept();
139 }
140
141 void OnMonitorCornersItem::hoverMoveEvent(QGraphicsSceneHoverEvent* event)
142 {
143     int corner;
144     switch (getMode(event->pos(), &corner)) {
145     case NoAction:
146         unsetCursor();
147         break;
148     case Move:
149         setCursor(QCursor(Qt::SizeAllCursor));
150         break;
151     default:
152         setCursor(QCursor(Qt::OpenHandCursor));
153         break;
154     }
155 }
156
157 void OnMonitorCornersItem::paint(QPainter* painter, const QStyleOptionGraphicsItem* option, QWidget* widget)
158 {
159     painter->setPen(QPen(Qt::yellow, 1, Qt::SolidLine));
160
161     if (KdenliveSettings::onmonitoreffects_cornersshowlines())
162         QGraphicsPolygonItem::paint(painter, option, widget);
163
164     if (polygon().count() != 4)
165         return;
166
167     double baseSize = 1 / painter->worldTransform().m11();
168     painter->setRenderHint(QPainter::Antialiasing);
169     painter->setBrush(QBrush(isEnabled() ? Qt::yellow : Qt::red));
170     double handleSize = 4  * baseSize;
171     for (int i = 0; i < 4; ++i)
172         painter->drawEllipse(polygon().at(i), handleSize, handleSize);
173
174     if (KdenliveSettings::onmonitoreffects_cornersshowcontrols() && isEnabled()) {
175         painter->setPen(QPen(Qt::red, 2, Qt::SolidLine));
176         double toolSize = 6 * baseSize;
177         // move tool
178         QPointF c = getCentroid();
179         painter->drawLine(QLineF(c - QPointF(toolSize, toolSize), c + QPointF(toolSize, toolSize)));
180         painter->drawLine(QLineF(c - QPointF(-toolSize, toolSize), c + QPointF(-toolSize, toolSize)));
181
182         // move side tools (2 corners at once)
183         int j;
184         for (int i = 0; i < 4; ++i) {
185             j = (i + 1) % 4;
186             QPointF m = QLineF(polygon().at(i), polygon().at(j)).pointAt(.5);
187             painter->drawRect(QRectF(-toolSize / 2., -toolSize / 2., toolSize, toolSize).translated(m));
188         }
189     }
190 }
191
192 QPointF OnMonitorCornersItem::getCentroid()
193 {
194     QList <QPointF> p = sortedClockwise();
195
196     /*
197      * See: http://local.wasp.uwa.edu.au/~pbourke/geometry/polyarea/
198      */
199
200     double A = 0;
201     int i, j;
202     for (i = 0; i < 4; ++i) {
203         j = (i + 1) % 4;
204         A += p[j].x() * p[i].y() - p[i].x() * p[j].y();
205     }
206     A /= 2.;
207     A = qAbs(A);
208
209     double x = 0, y = 0, f;
210     for (i = 0; i < 4; ++i) {
211         j = (i + 1) % 4;
212         f = (p[i].x() * p[j].y() - p[j].x() * p[i].y());
213         x += f * (p[i].x() + p[j].x());
214         y += f * (p[i].y() + p[j].y());
215     }
216     x /= 6*A;
217     y /= 6*A;
218     return QPointF(x, y);
219 }
220
221 QList <QPointF> OnMonitorCornersItem::sortedClockwise()
222 {
223     QList <QPointF> points = polygon().toList();
224     QPointF& a = points[0];
225     QPointF& b = points[1];
226     QPointF& c = points[2];
227     QPointF& d = points[3];
228
229     /*
230      * http://stackoverflow.com/questions/242404/sort-four-points-in-clockwise-order
231      */
232
233     double abc = a.x() * b.y() - a.y() * b.x() + b.x() * c.y() - b.y() * c.x() + c.x() * a.y() - c.y() * a.x();
234     if (abc > 0) {
235         double acd = a.x() * c.y() - a.y() * c.x() + c.x() * d.y() - c.y() * d.x() + d.x() * a.y() - d.y() * a.x();
236         if (acd > 0) {
237             ;
238         } else {
239             double abd = a.x() * b.y() - a.y() * b.x() + b.x() * d.y() - b.y() * d.x() + d.x() * a.y() - d.y() * a.x();
240             if (abd > 0) {
241                 std::swap(d, c);
242             } else{
243                 std::swap(a, d);
244             }
245         }
246     } else {
247         double acd = a.x() * c.y() - a.y() * c.x() + c.x() * d.y() - c.y() * d.x() + d.x() * a.y() - d.y() * a.x();
248         if (acd > 0) {
249             double abd = a.x() * b.y() - a.y() * b.x() + b.x() * d.y() - b.y() * d.x() + d.x() * a.y() - d.y() * a.x();
250             if (abd > 0) {
251                 std::swap(b, c);
252             } else {
253                 std::swap(a, b);
254             }
255         } else {
256             std::swap(a, c);
257         }
258     }
259     return points;
260 }
261
262 bool OnMonitorCornersItem::getView()
263 {
264     if (m_view)
265         return true;
266
267     if (scene() && !scene()->views().isEmpty()) {
268         m_view = scene()->views().first();
269         return true;
270     } else {
271         return false;
272     }
273 }
274
275 #include "onmonitorcornersitem.moc"