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