]> git.sesse.net Git - kdenlive/blob - src/monitorscene.cpp
- Add controls to zoom monitor scene
[kdenlive] / src / monitorscene.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
21 #include "monitorscene.h"
22 #include "renderer.h"
23 #include "kdenlivesettings.h"
24
25 #include <QGraphicsView>
26 #include <QGraphicsPixmapItem>
27 #include <QGraphicsSceneMouseEvent>
28
29 MonitorScene::MonitorScene(Render *renderer, QObject* parent) :
30         QGraphicsScene(parent),
31         m_renderer(renderer),
32         m_view(NULL),
33         m_selectedItem(NULL),
34         m_resizeMode(NoResize),
35         m_clickPoint(0, 0),
36         m_backgroundImage(QImage()),
37         m_enabled(true),
38         m_modified(false),
39         m_zoom(1.0)
40 {
41     setBackgroundBrush(QBrush(QColor(KdenliveSettings::window_background().name())));
42
43     QPen framepen(Qt::SolidLine);
44     framepen.setColor(Qt::red);
45
46     m_frameBorder = new QGraphicsRectItem(QRectF(0, 0, m_renderer->renderWidth(), m_renderer->renderHeight()));
47     m_frameBorder->setPen(framepen);
48     m_frameBorder->setZValue(-2);
49     m_frameBorder->setBrush(Qt::transparent);
50     m_frameBorder->setFlags(0);
51     addItem(m_frameBorder);
52
53     m_lastUpdate.start();
54     m_background = new QGraphicsPixmapItem();
55     m_background->setZValue(-1);
56     m_background->setFlags(0);
57     m_background->setShapeMode(QGraphicsPixmapItem::BoundingRectShape);
58     m_background->setTransformationMode(Qt::FastTransformation);
59     QPixmap bg(m_renderer->renderWidth(), m_renderer->renderHeight());
60     bg.fill();
61     m_background->setPixmap(bg);
62     addItem(m_background);
63
64     //connect(m_renderer, SIGNAL(rendererPosition(int)), this, SLOT(slotUpdateBackground()));
65     connect(m_renderer, SIGNAL(frameUpdated(QImage)), this, SLOT(slotSetBackgroundImage(QImage)));
66 }
67
68 void MonitorScene::setUp()
69 {
70     if (views().count() > 0)
71         m_view = views().at(0);
72     else
73         m_view = NULL;
74
75     m_view->setViewportUpdateMode(QGraphicsView::FullViewportUpdate);
76
77     slotUpdateBackground(true);
78 }
79
80 void MonitorScene::resetProfile()
81 {
82     const QRectF border(0, 0, m_renderer->renderWidth(), m_renderer->renderHeight());
83     m_frameBorder->setRect(border);
84 }
85
86 void MonitorScene::setEnabled(bool enabled)
87 {
88     m_enabled = enabled;
89 }
90
91 void MonitorScene::slotUpdateBackground(bool fit)
92 {
93     if (m_view && m_view->isVisible()) {
94         if (m_lastUpdate.elapsed() > 200) {
95             m_background->setPixmap(QPixmap::fromImage(m_backgroundImage, Qt::ThresholdDither));
96             if (fit)
97                 slotZoomFit();
98             m_lastUpdate.start();
99         }
100     }
101 }
102
103 void MonitorScene::slotSetDirectUpdate(bool directUpdate)
104 {
105     KdenliveSettings::setMonitorscene_directupdate(directUpdate);
106 }
107
108 void MonitorScene::slotSetBackgroundImage(const QImage &image)
109 {
110     m_backgroundImage = image;
111     slotUpdateBackground();
112 }
113
114
115 void MonitorScene::slotZoom(int value)
116 {
117     if (m_view) {
118         m_zoom = value / 100.0;
119         m_view->resetTransform();
120         m_view->scale(m_zoom, m_zoom);
121         emit zoomChanged(value);
122     }
123 }
124
125 void MonitorScene::slotZoomFit()
126 {
127     if (m_view) {
128         m_view->fitInView(m_frameBorder, Qt::KeepAspectRatio);
129         m_view->centerOn(m_frameBorder);
130         m_zoom = m_view->matrix().m11();
131         emit zoomChanged((int)(m_zoom * 100));
132     }
133 }
134
135 void MonitorScene::slotZoomOriginal()
136 {
137     slotZoom(100);
138     if (m_view)
139         m_view->centerOn(m_frameBorder);
140 }
141
142 void MonitorScene::slotZoomOut()
143 {
144     slotZoom(qMax(0, (int)(m_zoom * 100 - 1)));
145 }
146
147 void MonitorScene::slotZoomIn()
148 {
149     slotZoom(qMin(300, (int)(m_zoom * 100 + 1)));
150 }
151
152
153 resizeModes MonitorScene::getResizeMode(QGraphicsRectItem *item, QPoint pos)
154 {
155     if (!m_view)
156         return NoResize;
157
158     QRectF rect = item->rect().normalized();
159     // Item mapped coordinates
160     QPolygon pol = item->deviceTransform(m_view->viewportTransform()).map(rect).toPolygon();
161     QPainterPath top(pol.point(0));
162     top.lineTo(pol.point(1));
163     QPainterPath bottom(pol.point(2));
164     bottom.lineTo(pol.point(3));
165     QPainterPath left(pol.point(0));
166     left.lineTo(pol.point(3));
167     QPainterPath right(pol.point(1));
168     right.lineTo(pol.point(2));
169
170     QPainterPath mouseArea;
171     mouseArea.addRect(pos.x() - 4, pos.y() - 4, 8, 8);
172
173     // Check for collisions between the mouse and the borders
174     if (mouseArea.contains(pol.point(0)))
175         return TopLeft;
176     else if (mouseArea.contains(pol.point(2)))
177         return BottomRight;
178     else if (mouseArea.contains(pol.point(1)))
179         return TopRight;
180     else if (mouseArea.contains(pol.point(3)))
181         return BottomLeft;
182     else if (top.intersects(mouseArea))
183         return Top;
184     else if (bottom.intersects(mouseArea))
185         return Bottom;
186     else if (right.intersects(mouseArea))
187         return Right;
188     else if (left.intersects(mouseArea))
189         return Left;
190     else
191         return NoResize;
192 }
193
194 void MonitorScene::mousePressEvent(QGraphicsSceneMouseEvent *event)
195 {
196     if (!m_enabled)
197         return;
198
199     m_resizeMode = NoResize;
200     m_selectedItem = NULL;
201
202     m_clickPoint = event->scenePos();
203     QList<QGraphicsItem *> itemList = items(QRectF(m_clickPoint - QPoint(4, 4), QSizeF(4, 4)).toRect());
204
205     for (int i = 0; i < itemList.count(); ++i) {
206         if (itemList.at(i)->zValue() >= 0 && itemList.at(i)->flags() & QGraphicsItem::ItemIsMovable) {
207             m_selectedItem = itemList.at(i);
208             // Rect
209             if (itemList.at(i)->type() == 3) {
210                 m_resizeMode = getResizeMode((QGraphicsRectItem*)m_selectedItem, m_view->mapFromScene(m_clickPoint));
211                 break;
212             }
213         }
214     }
215
216     QGraphicsScene::mousePressEvent(event);
217 }
218
219 void MonitorScene::mouseMoveEvent(QGraphicsSceneMouseEvent *event)
220 {
221     if (!m_enabled)
222         return;
223
224     QPointF mousePos = event->scenePos();
225
226     if (m_selectedItem && event->buttons() & Qt::LeftButton) {
227         // Rect
228         if (m_selectedItem->type() == 3) {
229             QGraphicsRectItem *item = static_cast <QGraphicsRectItem *>(m_selectedItem);
230             QRectF rect = item->rect().normalized();
231             QPointF pos = item->pos();
232             QPointF mousePosInRect = item->mapFromScene(mousePos);
233             switch (m_resizeMode) {
234             case TopLeft:
235                 if (mousePos.x() < pos.x() + rect.height() && mousePos.y() < pos.y() + rect.height()) {
236                     item->setRect(rect.adjusted(0, 0, -mousePosInRect.x(), -mousePosInRect.y()));
237                     item->setPos(mousePos);
238                     m_modified = true;
239                 }
240                 break;
241             case Top:
242                 if (mousePos.y() < pos.y() + rect.height()) {
243                     rect.setBottom(rect.height() - mousePosInRect.y());
244                     item->setRect(rect);
245                     item->setPos(QPointF(pos.x(), mousePos.y()));
246                     m_modified = true;
247                 }
248                 break;
249             case TopRight:
250                 if (mousePos.x() > pos.x() && mousePos.y() < pos.y() + rect.height()) {
251                     rect.setBottomRight(QPointF(mousePosInRect.x(), rect.bottom() - mousePosInRect.y()));
252                     item->setRect(rect);
253                     item->setPos(QPointF(pos.x(), mousePos.y()));
254                     m_modified = true;
255                 }
256                 break;
257             case Left:
258                 if (mousePos.x() < pos.x() + rect.width()) {
259                     rect.setRight(rect.width() - mousePosInRect.x());
260                     item->setRect(rect);
261                     item->setPos(QPointF(mousePos.x(), pos.y()));
262                     m_modified = true;
263                 }
264                 break;
265             case Right:
266                 if (mousePos.x() > pos.x()) {
267                     rect.setRight(mousePosInRect.x());
268                     item->setRect(rect);
269                     m_modified = true;
270                 }
271                 break;
272             case BottomLeft:
273                 if (mousePos.x() < pos.x() + rect.width() && mousePos.y() > pos.y()) {
274                     rect.setBottomRight(QPointF(rect.width() - mousePosInRect.x(), mousePosInRect.y()));
275                     item->setRect(rect);
276                     item->setPos(QPointF(mousePos.x(), pos.y()));
277                     m_modified = true;
278                 }
279                 break;
280             case Bottom:
281                 if (mousePos.y() > pos.y()) {
282                     rect.setBottom(mousePosInRect.y());
283                     item->setRect(rect);
284                     m_modified = true;
285                 }
286                 break;
287             case BottomRight:
288                 if (mousePos.x() > pos.x() && mousePos.y() > pos.y()) {
289                     rect.setBottomRight(mousePosInRect);
290                     item->setRect(rect);
291                     m_modified = true;
292                 }
293                 break;
294             default:
295                 QPointF diff = mousePos - m_clickPoint;
296                 m_clickPoint = mousePos;
297                 item->moveBy(diff.x(), diff.y());
298                 m_modified = true;
299                 break;
300             }
301         }
302     } else {
303         mousePos -= QPoint(4, 4);
304         bool itemFound = false;
305         QList<QGraphicsItem *> itemList = items(QRectF(mousePos, QSizeF(4, 4)).toRect());
306
307         foreach(const QGraphicsItem* item, itemList) {
308             if (item->zValue() >= 0 && item->flags() &QGraphicsItem::ItemIsMovable) {
309                 // Rect
310                 if (item->type() == 3) {
311                     if (m_view == NULL)
312                         continue;
313
314                     itemFound = true;
315
316                     switch (getResizeMode((QGraphicsRectItem*)item, m_view->mapFromScene(event->scenePos()))) {
317                     case TopLeft:
318                     case BottomRight:
319                         m_view->setCursor(Qt::SizeFDiagCursor);
320                         break;
321                     case TopRight:
322                     case BottomLeft:
323                         m_view->setCursor(Qt::SizeBDiagCursor);
324                         break;
325                     case Top:
326                     case Bottom:
327                         m_view->setCursor(Qt::SizeVerCursor);
328                         break;
329                     case Left:
330                     case Right:
331                         m_view->setCursor(Qt::SizeHorCursor);
332                         break;
333                     default:
334                         m_view->setCursor(Qt::OpenHandCursor);
335                     }
336                     break;
337                 }
338             }
339         }
340
341         if (!itemFound && m_view)
342             m_view->setCursor(Qt::ArrowCursor);
343
344         QGraphicsScene::mouseMoveEvent(event);
345     }
346     if (m_modified && KdenliveSettings::monitorscene_directupdate()) {
347         emit actionFinished();
348         m_modified = false;
349     }
350 }
351
352 void MonitorScene::mouseReleaseEvent(QGraphicsSceneMouseEvent *event)
353 {
354     if (!m_enabled)
355         return;
356
357     QGraphicsScene::mouseReleaseEvent(event);
358     if (m_modified) {
359         m_modified = false;
360         emit actionFinished();
361     }
362 }
363
364 #include "monitorscene.moc"