1 /****************************************************************************
3 ** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies).
4 ** Contact: http://www.qt-project.org/legal
6 ** This file is part of the QtQml module of the Qt Toolkit.
8 ** $QT_BEGIN_LICENSE:LGPL$
9 ** Commercial License Usage
10 ** Licensees holding valid commercial Qt licenses may use this file in
11 ** accordance with the commercial license agreement provided with the
12 ** Software or, alternatively, in accordance with the terms contained in
13 ** a written agreement between you and Digia. For licensing terms and
14 ** conditions see http://qt.digia.com/licensing. For further information
15 ** use the contact form at http://qt.digia.com/contact-us.
17 ** GNU Lesser General Public License Usage
18 ** Alternatively, this file may be used under the terms of the GNU Lesser
19 ** General Public License version 2.1 as published by the Free Software
20 ** Foundation and appearing in the file LICENSE.LGPL included in the
21 ** packaging of this file. Please review the following information to
22 ** ensure the GNU Lesser General Public License version 2.1 requirements
23 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
25 ** In addition, as a special exception, Digia gives you certain additional
26 ** rights. These rights are described in the Digia Qt LGPL Exception
27 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
29 ** GNU General Public License Usage
30 ** Alternatively, this file may be used under the terms of the GNU
31 ** General Public License version 3.0 as published by the Free Software
32 ** Foundation and appearing in the file LICENSE.GPL included in the
33 ** packaging of this file. Please review the following information to
34 ** ensure the GNU General Public License version 3.0 requirements will be
35 ** met: http://www.gnu.org/copyleft/gpl.html.
40 ****************************************************************************/
42 #include "inspecttool.h"
44 #include "highlight.h"
45 #include "qquickviewinspector.h"
47 #include <QtCore/QLineF>
49 #include <QtGui/QMouseEvent>
50 #include <QtGui/QWheelEvent>
51 #include <QtGui/QTouchEvent>
52 #include <QtGui/QKeyEvent>
53 #include <QtGui/QGuiApplication>
54 #include <QtGui/QStyleHints>
56 #include <QtQuick/QQuickView>
57 #include <QtQuick/QQuickItem>
59 namespace QmlJSDebugger {
62 InspectTool::InspectTool(QQuickViewInspector *inspector, QQuickView *view) :
63 AbstractTool(inspector),
64 m_originalSmooth(view->rootItem()->smooth()),
66 m_pinchStarted(false),
67 m_didPressAndHold(false),
69 m_rootItem(view->rootItem()),
70 m_originalPosition(view->rootItem()->pos()),
71 m_smoothScaleFactor(Constants::ZoomSnapDelta),
74 m_originalScale(view->rootItem()->scale()),
76 m_hoverHighlight(new HoverHighlight(inspector->overlay())),
80 //Press and Hold Timer
81 m_pressAndHoldTimer.setSingleShot(true);
82 m_pressAndHoldTimer.setInterval(Constants::PressAndHoldTimeout);
83 connect(&m_pressAndHoldTimer, SIGNAL(timeout()), SLOT(zoomTo100()));
84 //Timer to display selected item's name
85 m_nameDisplayTimer.setSingleShot(true);
86 m_nameDisplayTimer.setInterval(qApp->styleHints()->mouseDoubleClickInterval());
87 connect(&m_nameDisplayTimer, SIGNAL(timeout()), SLOT(showSelectedItemName()));
91 InspectTool::~InspectTool()
96 void InspectTool::enable(bool enable)
99 inspector()->setSelectedItems(QList<QQuickItem*>());
100 // restoring the original states.
102 m_rootItem->setScale(m_originalScale);
103 m_rootItem->setPos(m_originalPosition);
104 m_rootItem->setSmooth(m_originalSmooth);
108 m_originalSmooth = m_rootItem->smooth();
109 m_originalScale = m_rootItem->scale();
110 m_originalPosition = m_rootItem->pos();
111 m_rootItem->setSmooth(true);
116 void InspectTool::leaveEvent(QEvent *)
118 m_hoverHighlight->setVisible(false);
121 void InspectTool::mousePressEvent(QMouseEvent *event)
123 m_mousePosition = event->localPos();
124 if (event->button() == Qt::LeftButton) {
125 m_pressAndHoldTimer.start();
126 initializeDrag(event->localPos());
130 void InspectTool::mouseReleaseEvent(QMouseEvent *event)
132 m_mousePosition = event->localPos();
133 m_pressAndHoldTimer.stop();
134 if (event->button() == Qt::LeftButton && !m_dragStarted) {
136 m_hoverHighlight->setVisible(false);
140 void InspectTool::mouseDoubleClickEvent(QMouseEvent *event)
142 m_mousePosition = event->localPos();
143 m_pressAndHoldTimer.stop();
144 if (event->button() == Qt::LeftButton) {
146 m_hoverHighlight->setVisible(false);
150 void InspectTool::mouseMoveEvent(QMouseEvent *event)
152 m_mousePosition = event->localPos();
153 moveItem(event->buttons() & Qt::LeftButton);
156 void InspectTool::hoverMoveEvent(QMouseEvent *event)
158 m_mousePosition = event->localPos();
159 m_pressAndHoldTimer.stop();
160 QQuickItem *item = inspector()->topVisibleItemAt(event->pos());
161 if (!item || item == m_lastClickedItem) {
162 m_hoverHighlight->setVisible(false);
164 m_hoverHighlight->setItem(item);
165 m_hoverHighlight->setVisible(true);
169 void InspectTool::wheelEvent(QWheelEvent *event)
171 if (event->orientation() != Qt::Vertical)
174 Qt::KeyboardModifier smoothZoomModifier = Qt::ControlModifier;
175 if (event->modifiers() & smoothZoomModifier) {
176 int numDegrees = event->delta() / 8;
177 qreal newScale = m_rootItem->scale() + m_smoothScaleFactor * (numDegrees / 15.0f);
178 scaleView(newScale / m_rootItem->scale(), m_mousePosition, m_mousePosition);
179 } else if (!event->modifiers()) {
180 if (event->delta() > 0) {
182 } else if (event->delta() < 0) {
188 void InspectTool::keyReleaseEvent(QKeyEvent *event)
190 switch (event->key()) {
206 qreal newScale = ((event->key() - Qt::Key_0) * 1.0f);
207 scaleView(newScale / m_rootItem->scale(), m_mousePosition, m_mousePosition);
215 void InspectTool::touchEvent(QTouchEvent *event)
217 QList<QTouchEvent::TouchPoint> touchPoints = event->touchPoints();
219 switch (event->type()) {
220 case QEvent::TouchBegin:
221 if (touchPoints.count() == 1 && (event->touchPointStates() & Qt::TouchPointPressed)) {
222 if (!m_pressAndHoldTimer.isActive())
223 m_pressAndHoldTimer.start();
224 m_mousePosition = touchPoints.first().pos();
225 initializeDrag(touchPoints.first().pos());
231 case QEvent::TouchUpdate: {
232 if (touchPoints.count() > 1)
234 if ((touchPoints.count() == 1)
235 && (event->touchPointStates() & Qt::TouchPointMoved)) {
236 m_mousePosition = touchPoints.first().pos();
238 } else if ((touchPoints.count() == 2)
239 && (!(event->touchPointStates() & Qt::TouchPointReleased))) {
240 // determine scale factor
241 const QTouchEvent::TouchPoint &touchPoint0 = touchPoints.first();
242 const QTouchEvent::TouchPoint &touchPoint1 = touchPoints.last();
244 qreal touchScaleFactor =
245 QLineF(touchPoint0.pos(), touchPoint1.pos()).length()
246 / QLineF(touchPoint0.lastPos(), touchPoint1.lastPos()).length();
248 QPointF oldcenter = (touchPoint0.lastPos() + touchPoint1.lastPos()) / 2;
249 QPointF newcenter = (touchPoint0.pos() + touchPoint1.pos()) / 2;
251 m_pinchStarted = true;
252 scaleView(touchScaleFactor, newcenter, oldcenter);
256 case QEvent::TouchEnd: {
257 m_pressAndHoldTimer.stop();
258 if (m_pinchStarted) {
259 m_pinchStarted = false;
261 if (touchPoints.count() == 1 && !m_dragStarted &&
262 !m_didPressAndHold && m_tapEvent) {
264 bool doubleTap = event->timestamp() - m_touchTimestamp
265 < static_cast<ulong>(qApp->styleHints()->mouseDoubleClickInterval());
267 m_nameDisplayTimer.stop();
273 m_touchTimestamp = event->timestamp();
275 m_didPressAndHold = false;
283 void InspectTool::scaleView(const qreal &factor, const QPointF &newcenter, const QPointF &oldcenter)
285 m_pressAndHoldTimer.stop();
286 if (((m_rootItem->scale() * factor) > m_maxScale)
287 || ((m_rootItem->scale() * factor) < m_minScale)) {
290 //New position = new center + scalefactor * (oldposition - oldcenter)
291 QPointF newPosition = newcenter + (factor * (m_rootItem->pos() - oldcenter));
292 m_rootItem->setScale(m_rootItem->scale() * factor);
293 m_rootItem->setPos(newPosition);
296 void InspectTool::zoomIn()
298 qreal newScale = nextZoomScale(ZoomIn);
299 scaleView(newScale / m_rootItem->scale(), m_mousePosition, m_mousePosition);
302 void InspectTool::zoomOut()
304 qreal newScale = nextZoomScale(ZoomOut);
305 scaleView(newScale / m_rootItem->scale(), m_mousePosition, m_mousePosition);
308 void InspectTool::zoomTo100()
310 m_didPressAndHold = true;
312 m_rootItem->setPos(QPointF(0, 0));
313 m_rootItem->setScale(1.0);
316 qreal InspectTool::nextZoomScale(ZoomDirection direction)
318 static QList<qreal> zoomScales =
339 if (direction == ZoomIn) {
340 for (int i = 0; i < zoomScales.length(); ++i) {
341 if (zoomScales[i] > m_rootItem->scale())
342 return zoomScales[i];
344 return zoomScales.last();
346 for (int i = zoomScales.length() - 1; i >= 0; --i) {
347 if (zoomScales[i] < m_rootItem->scale())
348 return zoomScales[i];
350 return zoomScales.first();
356 void InspectTool::initializeDrag(const QPointF &pos)
358 m_dragStartPosition = pos;
359 m_dragStarted = false;
362 void InspectTool::dragItemToPosition()
364 QPointF newPosition = m_rootItem->pos() + m_mousePosition - m_dragStartPosition;
365 m_dragStartPosition = m_mousePosition;
366 m_rootItem->setPos(newPosition);
369 void InspectTool::moveItem(bool valid)
376 && ((m_dragStartPosition - m_mousePosition).manhattanLength()
377 > qApp->styleHints()->startDragDistance())) {
378 m_pressAndHoldTimer.stop();
379 m_dragStarted = true;
382 dragItemToPosition();
385 void InspectTool::selectNextItem()
387 if (m_lastClickedItem != inspector()->topVisibleItemAt(m_mousePosition))
389 QList<QQuickItem*> items = inspector()->itemsAt(m_mousePosition);
390 for (int i = 0; i < items.count(); i++) {
391 if (m_lastItem == items[i]) {
392 if (i + 1 < items.count())
393 m_lastItem = items[i+1];
395 m_lastItem = items[0];
396 inspector()->setSelectedItems(QList<QQuickItem*>() << m_lastItem);
397 showSelectedItemName();
403 void InspectTool::selectItem()
405 if (!inspector()->topVisibleItemAt(m_mousePosition))
407 if (m_lastClickedItem == inspector()->topVisibleItemAt(m_mousePosition)) {
408 m_nameDisplayTimer.start();
411 m_lastClickedItem = inspector()->topVisibleItemAt(m_mousePosition);
412 m_lastItem = m_lastClickedItem;
413 inspector()->setSelectedItems(QList<QQuickItem*>() << m_lastClickedItem);
414 showSelectedItemName();
417 QQuickViewInspector *InspectTool::inspector() const
419 return static_cast<QQuickViewInspector*>(AbstractTool::inspector());
422 void InspectTool::showSelectedItemName()
424 inspector()->showSelectedItemName(m_lastItem, m_mousePosition);
427 } // namespace QtQuick2
428 } // namespace QmlJSDebugger