]> git.sesse.net Git - kdenlive/blob - src/onmonitoritems/onmonitorrectitem.cpp
Merge branch 'master' into feature/pkey
[kdenlive] / src / onmonitoritems / onmonitorrectitem.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 "onmonitorrectitem.h"
21 #include "kdenlivesettings.h"
22
23 #include <QGraphicsSceneMouseEvent>
24 #include <QPainter>
25 #include <QStyleOptionGraphicsItem>
26 #include <QCursor>
27 #include <QGraphicsView>
28
29 OnMonitorRectItem::OnMonitorRectItem(const QRectF &rect, double dar, QGraphicsItem* parent) :
30         QGraphicsRectItem(rect, parent),
31         m_dar(dar),
32         m_modified(false),
33         m_view(NULL)
34 {
35     setFlags(QGraphicsItem::ItemIsMovable | QGraphicsItem::ItemIsSelectable);
36
37     QPen framepen(Qt::SolidLine);
38     framepen.setColor(Qt::yellow);
39     setPen(framepen);
40     setBrush(Qt::transparent);
41     setAcceptHoverEvents(true);
42 }
43
44 rectActions OnMonitorRectItem::getMode(QPointF pos)
45 {
46     // Item mapped coordinates
47     QPolygonF pol(rect().normalized());
48
49     QPainterPath top(pol.at(0));
50     top.lineTo(pol.at(1));
51     QPainterPath bottom(pol.at(2));
52     bottom.lineTo(pol.at(3));
53     QPainterPath left(pol.at(0));
54     left.lineTo(pol.at(3));
55     QPainterPath right(pol.at(1));
56     right.lineTo(pol.at(2));
57
58     QPainterPath mouseArea;
59     qreal xsize = 10;
60     qreal ysize = 10;
61     if (getView()) {
62         xsize /= m_view->matrix().m11();
63         ysize /= m_view->matrix().m22();
64     }
65     mouseArea.addRect(pos.x() - xsize / 2, pos.y() - ysize / 2, xsize, ysize);
66
67     // Check for collisions between the mouse and the borders
68     if (mouseArea.contains(pol.at(0)))
69         return ResizeTopLeft;
70     else if (mouseArea.contains(pol.at(2)))
71         return ResizeBottomRight;
72     else if (mouseArea.contains(pol.at(1)))
73         return ResizeTopRight;
74     else if (mouseArea.contains(pol.at(3)))
75         return ResizeBottomLeft;
76     else if (top.intersects(mouseArea))
77         return ResizeTop;
78     else if (bottom.intersects(mouseArea))
79         return ResizeBottom;
80     else if (right.intersects(mouseArea))
81         return ResizeRight;
82     else if (left.intersects(mouseArea))
83         return ResizeLeft;
84     else if (rect().normalized().contains(pos))
85         return Move;
86     else
87         return NoAction;
88 }
89
90 void OnMonitorRectItem::mousePressEvent(QGraphicsSceneMouseEvent* event)
91 {
92     event->accept();
93
94     m_lastPoint = event->scenePos();
95     m_oldRect = rect().normalized();
96     m_mode = getMode(event->pos());
97 }
98
99 void OnMonitorRectItem::mouseMoveEvent(QGraphicsSceneMouseEvent* event)
100 {
101     /*if (event->buttons() != Qt::NoButton && (event->screenPos() - m_screenClickPoint).manhattanLength() < QApplication::startDragDistance()) {
102      *   event->accept();
103      *   return;
104     }*/
105
106     if (event->buttons() & Qt::LeftButton) {
107         QRectF r = rect().normalized();
108         QPointF p = pos();
109         QPointF mousePos = event->scenePos();
110         QPointF mousePosInRect = event->pos();
111         QPointF diff = mousePos - m_lastPoint;
112         m_lastPoint = mousePos;
113
114         switch (m_mode) {
115         case ResizeTopLeft:
116             if (mousePos.x() < p.x() + r.height() && mousePos.y() < p.y() + r.height()) {
117                 r.adjust(0, 0, -mousePosInRect.x(), -mousePosInRect.y());
118                 setPos(mousePos);
119                 m_modified = true;
120             }
121             break;
122         case ResizeTop:
123             if (mousePos.y() < p.y() + r.height()) {
124                 r.setBottom(r.height() - mousePosInRect.y());
125                 setPos(QPointF(p.x(), mousePos.y()));
126                 m_modified = true;
127             }
128             break;
129         case ResizeTopRight:
130             if (mousePos.x() > p.x() && mousePos.y() < p.y() + r.height()) {
131                 r.setBottomRight(QPointF(mousePosInRect.x(), r.bottom() - mousePosInRect.y()));
132                 setPos(QPointF(p.x(), mousePos.y()));
133                 m_modified = true;
134             }
135             break;
136         case ResizeLeft:
137             if (mousePos.x() < p.x() + r.width()) {
138                 r.setRight(r.width() - mousePosInRect.x());
139                 setPos(QPointF(mousePos.x(), p.y()));
140                 m_modified = true;
141             }
142             break;
143         case ResizeRight:
144             if (mousePos.x() > p.x()) {
145                 r.setRight(mousePosInRect.x());
146                 m_modified = true;
147             }
148             break;
149         case ResizeBottomLeft:
150             if (mousePos.x() < p.x() + r.width() && mousePos.y() > p.y()) {
151                 r.setBottomRight(QPointF(r.width() - mousePosInRect.x(), mousePosInRect.y()));
152                 setPos(QPointF(mousePos.x(), p.y()));
153                 m_modified = true;
154             }
155             break;
156         case ResizeBottom:
157             if (mousePos.y() > p.y()) {
158                 r.setBottom(mousePosInRect.y());
159                 m_modified = true;
160             }
161             break;
162         case ResizeBottomRight:
163             if (mousePos.x() > p.x() && mousePos.y() > p.y()) {
164                 r.setBottomRight(mousePosInRect);
165                 m_modified = true;
166             }
167             break;
168         case Move:
169             moveBy(diff.x(), diff.y());
170             m_modified = true;
171             break;
172         default:
173             break;
174         }
175
176         // Keep aspect ratio
177         if (event->modifiers() == Qt::ControlModifier) {
178             // compare to rect during mouse press: 
179             // if we subtract rect() we'll get a whole lot of flickering
180             // because of diffWidth > diffHeight changing all the time
181             int diffWidth = qAbs(r.width() - m_oldRect.width());
182             int diffHeight = qAbs(r.height() - m_oldRect.height());
183
184             if (diffHeight != 0 || diffWidth != 0) {
185                 if (diffWidth > diffHeight)
186                     r.setBottom(r.width() / m_dar);
187                 else
188                     r.setRight(r.height() * m_dar);
189
190                 // the rect's position changed
191                 if (p - pos() != QPointF()) {
192                     if (diffWidth > diffHeight) {
193                         if (m_mode != ResizeBottomLeft)
194 #if QT_VERSION >= 0x040600
195                             setY(p.y() - r.height() + rect().normalized().height());
196 #else
197                             setPos(x(), p.y() - r.height() + rect().normalized().height());
198 #endif
199                     } else {
200                         if (m_mode != ResizeTopRight)
201 #if QT_VERSION >= 0x040600
202                             setX(p.x() - r.width() + rect().normalized().width());
203 #else
204                             setPos(p.x() - r.width() + rect().normalized().width(), y());
205 #endif
206                     }
207                 }
208             }
209         }
210
211         setRect(r);
212     }
213
214     if (m_modified) {
215         event->accept();
216         if (KdenliveSettings::monitorscene_directupdate()) {
217             emit changed();
218             m_modified = false;
219         }
220     } else {
221         event->ignore();
222     }
223 }
224
225 void OnMonitorRectItem::mouseReleaseEvent(QGraphicsSceneMouseEvent* event)
226 {
227     if (m_modified) {
228         m_modified = false;
229         emit changed();
230     }
231     event->accept();
232 }
233
234 void OnMonitorRectItem::hoverMoveEvent(QGraphicsSceneHoverEvent* event)
235 {
236     switch (getMode(event->pos())) {
237     case ResizeTopLeft:
238     case ResizeBottomRight:
239         setCursor(QCursor(Qt::SizeFDiagCursor));
240         break;
241     case ResizeTopRight:
242     case ResizeBottomLeft:
243         setCursor(QCursor(Qt::SizeBDiagCursor));
244         break;
245     case ResizeTop:
246     case ResizeBottom:
247         setCursor(QCursor(Qt::SizeVerCursor));
248         break;
249     case ResizeLeft:
250     case ResizeRight:
251         setCursor(QCursor(Qt::SizeHorCursor));
252         break;
253     case Move:
254         setCursor(QCursor(Qt::OpenHandCursor));
255         break;
256     default:
257         unsetCursor();
258         break;
259     }
260 }
261
262 void OnMonitorRectItem::paint(QPainter* painter, const QStyleOptionGraphicsItem* option, QWidget* widget)
263 {
264     Q_UNUSED(widget)
265
266     painter->setPen(pen());
267     painter->drawRect(option->rect);
268     const QRectF r = painter->worldTransform().mapRect(option->rect);
269     painter->setWorldMatrixEnabled(false);
270     if (isEnabled()) {
271         QRectF handle(0, 0, 6, 6);
272         handle.moveTopLeft(r.topLeft());
273         painter->fillRect(handle, QColor(Qt::yellow));
274         handle.moveTopRight(r.topRight());
275         painter->fillRect(handle, QColor(Qt::yellow));
276         handle.moveBottomLeft(r.bottomLeft());
277         painter->fillRect(handle, QColor(Qt::yellow));
278         handle.moveBottomRight(r.bottomRight());
279         painter->fillRect(handle, QColor(Qt::yellow));
280     }
281     
282     // Draw cross at center
283     QPointF center = r.center();
284     painter->drawLine(center + QPointF(-6, 0), center + QPointF(6, 0));
285     painter->drawLine(center + QPointF(0, 6), center + QPointF(0, -6));
286 }
287
288 bool OnMonitorRectItem::getView()
289 {
290     if (m_view)
291         return true;
292
293     if (scene() && scene()->views().count()) {
294         m_view = scene()->views()[0];
295         return true;
296     } else {
297         return false;
298     }
299 }
300
301 #include "onmonitorrectitem.moc"