]> git.sesse.net Git - kdenlive/blob - src/onmonitoritems/onmonitorcornersitem.cpp
on monitor corners item: make additional control optional
[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
30 OnMonitorCornersItem::OnMonitorCornersItem(MonitorScene* scene, QGraphicsItem* parent) :
31         AbstractOnMonitorItem(scene),
32         QGraphicsPolygonItem(parent)
33 {
34     setFlags(QGraphicsItem::ItemIsMovable | QGraphicsItem::ItemIsSelectable);
35
36     QPen framepen(Qt::SolidLine);
37     framepen.setColor(Qt::yellow);
38     setPen(framepen);
39     setBrush(Qt::NoBrush);
40 }
41
42 OnMonitorCornersItem::cornersActions OnMonitorCornersItem::getMode(QPointF pos)
43 {
44     QPainterPath mouseArea;
45     pos = mapFromScene(pos);
46     mouseArea.addRect(pos.x() - 6, pos.y() - 6, 12, 12);
47     if (mouseArea.contains(polygon().at(0)))
48         return Corner1;
49     else if (mouseArea.contains(polygon().at(1)))
50         return Corner2;
51     else if (mouseArea.contains(polygon().at(2)))
52         return Corner3;
53     else if (mouseArea.contains(polygon().at(3)))
54         return Corner4;
55     else if (KdenliveSettings::onmonitoreffects_cornersshowcontrols() && mouseArea.contains(getCentroid()))
56         return Move;
57     else
58         return NoAction;
59 }
60
61 void OnMonitorCornersItem::slotMousePressed(QGraphicsSceneMouseEvent* event)
62 {
63     event->accept();
64
65     if (!isEnabled())
66         return;
67
68     m_mode = getMode(event->scenePos());
69     m_lastPoint = event->scenePos();
70 }
71
72 void OnMonitorCornersItem::slotMouseMoved(QGraphicsSceneMouseEvent* event)
73 {
74     event->accept();
75
76     if (!isEnabled()) {
77         emit requestCursor(QCursor(Qt::ArrowCursor));
78         return;
79     }
80
81     /*if (event->buttons() != Qt::NoButton && (event->screenPos() - m_screenClickPoint).manhattanLength() < QApplication::startDragDistance()) {
82      *   event->accept();
83      *   return;
84     }*/
85
86     if (event->buttons() & Qt::LeftButton) {
87         QPointF mousePos = mapFromScene(event->scenePos());
88         QPolygonF p = polygon();
89         switch (m_mode) {
90         case Corner1:
91             p.replace(0, mousePos);
92             m_modified = true;
93             break;
94         case Corner2:
95             p.replace(1, mousePos);
96             m_modified = true;
97             break;
98         case Corner3:
99             p.replace(2, mousePos);
100             m_modified = true;
101             break;
102         case Corner4:
103             p.replace(3, mousePos);
104             m_modified = true;
105             break;
106         case Move:
107             p.translate(mousePos - m_lastPoint);
108             m_modified = true;
109             break;
110         default:
111             break;
112         }
113         m_lastPoint = mousePos;
114         setPolygon(p);
115     } else {
116         switch (getMode(event->scenePos())) {
117         case NoAction:
118             emit requestCursor(QCursor(Qt::ArrowCursor));
119             break;
120         case Move:
121             emit requestCursor(QCursor(Qt::SizeAllCursor));
122             break;
123         default:
124             emit requestCursor(QCursor(Qt::OpenHandCursor));
125             break;
126         }
127     }
128     if (m_modified && KdenliveSettings::monitorscene_directupdate()) {
129         emit actionFinished();
130         m_modified = false;
131     }
132 }
133
134 void OnMonitorCornersItem::paint(QPainter* painter, const QStyleOptionGraphicsItem* option, QWidget* widget)
135 {
136     painter->setPen(QPen(Qt::yellow, 1, Qt::SolidLine));
137
138     if (KdenliveSettings::onmonitoreffects_cornersshowlines())
139         QGraphicsPolygonItem::paint(painter, option, widget);
140
141     painter->setRenderHint(QPainter::Antialiasing);
142     painter->setBrush(QBrush(Qt::yellow));
143     double handleSize = 4 / painter->matrix().m11();
144     painter->drawEllipse(polygon().at(0), handleSize, handleSize);
145     painter->drawEllipse(polygon().at(1), handleSize, handleSize);
146     painter->drawEllipse(polygon().at(2), handleSize, handleSize);
147     painter->drawEllipse(polygon().at(3), handleSize, handleSize);
148
149     if (KdenliveSettings::onmonitoreffects_cornersshowcontrols()) {
150         painter->setPen(QPen(Qt::red, 2, Qt::SolidLine));
151         QPointF c = getCentroid();
152         handleSize *= 1.5;
153         painter->drawLine(QLineF(c - QPointF(handleSize, handleSize), c + QPointF(handleSize, handleSize)));
154         painter->drawLine(QLineF(c - QPointF(-handleSize, handleSize), c + QPointF(-handleSize, handleSize)));
155     }
156 }
157
158 QPointF OnMonitorCornersItem::getCentroid()
159 {
160     QList <QPointF> p = sortedClockwise();
161
162     /*
163      * See: http://local.wasp.uwa.edu.au/~pbourke/geometry/polyarea/
164      */
165
166     double A = 0;
167     int i, j;
168     for (i = 0; i < 4; ++i) {
169         j = (i + 1) % 4;
170         A += p[j].x() * p[i].y() - p[i].x() * p[j].y();
171     }
172     A /= 2.;
173     A = qAbs(A);
174
175     double x = 0, y = 0, f;
176     for (i = 0; i < 4; ++i) {
177         j = (i + 1) % 4;
178         f = (p[i].x() * p[j].y() - p[j].x() * p[i].y());
179         x += f * (p[i].x() + p[j].x());
180         y += f * (p[i].y() + p[j].y());
181     }
182     x /= 6*A;
183     y /= 6*A;
184     return QPointF(x, y);
185 }
186
187 QList <QPointF> OnMonitorCornersItem::sortedClockwise()
188 {
189     QList <QPointF> points = polygon().toList();
190     QPointF& a = points[0];
191     QPointF& b = points[1];
192     QPointF& c = points[2];
193     QPointF& d = points[3];
194
195     /*
196      * http://stackoverflow.com/questions/242404/sort-four-points-in-clockwise-order
197      */
198
199     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();
200     if (abc > 0) {
201         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();
202         if (acd > 0) {
203             ;
204         } else {
205             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();
206             if (abd > 0) {
207                 std::swap(d, c);
208             } else{
209                 std::swap(a, d);
210             }
211         }
212     } else {
213         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();
214         if (acd > 0) {
215             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();
216             if (abd > 0) {
217                 std::swap(b, c);
218             } else {
219                 std::swap(a, b);
220             }
221         } else {
222             std::swap(a, c);
223         }
224     }
225     return points;
226 }
227
228 #include "onmonitorcornersitem.moc"