2022-08-19 15:59:36 +02:00
|
|
|
// Copyright (C) 2020 The Qt Company Ltd.
|
2022-12-21 10:12:09 +01:00
|
|
|
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
|
2020-02-11 11:33:25 +02:00
|
|
|
|
|
|
|
|
#include "edit3dcanvas.h"
|
|
|
|
|
#include "edit3dview.h"
|
|
|
|
|
#include "edit3dwidget.h"
|
|
|
|
|
|
2022-03-18 17:28:28 +02:00
|
|
|
#include <bindingproperty.h>
|
|
|
|
|
#include <nodemetainfo.h>
|
|
|
|
|
#include <nodelistproperty.h>
|
|
|
|
|
#include <variantproperty.h>
|
|
|
|
|
|
2022-02-09 18:49:40 +01:00
|
|
|
#include <utils/qtcassert.h>
|
|
|
|
|
|
|
|
|
|
#include <coreplugin/icore.h>
|
|
|
|
|
|
2020-11-20 12:24:58 +01:00
|
|
|
#include <qmldesignerplugin.h>
|
|
|
|
|
#include <qmldesignerconstants.h>
|
|
|
|
|
|
2024-03-01 15:41:19 +02:00
|
|
|
#include <QApplication>
|
|
|
|
|
#include <QDateTime>
|
2022-02-09 18:49:40 +01:00
|
|
|
#include <QFileInfo>
|
2020-02-11 11:33:25 +02:00
|
|
|
#include <QPainter>
|
2022-02-09 18:49:40 +01:00
|
|
|
#include <QQuickWidget>
|
|
|
|
|
#include <QtCore/qmimedata.h>
|
2020-02-11 11:33:25 +02:00
|
|
|
|
|
|
|
|
namespace QmlDesigner {
|
|
|
|
|
|
2022-02-09 18:49:40 +01:00
|
|
|
static QQuickWidget *createBusyIndicator(QWidget *p)
|
|
|
|
|
{
|
|
|
|
|
auto widget = new QQuickWidget(p);
|
|
|
|
|
|
|
|
|
|
const QString source = Core::ICore::resourcePath("qmldesigner/misc/BusyIndicator.qml").toString();
|
|
|
|
|
QTC_ASSERT(QFileInfo::exists(source), return widget);
|
|
|
|
|
widget->setSource(QUrl::fromLocalFile(source));
|
|
|
|
|
widget->setFixedSize(64, 64);
|
|
|
|
|
widget->setAttribute(Qt::WA_AlwaysStackOnTop);
|
|
|
|
|
widget->setClearColor(Qt::transparent);
|
|
|
|
|
widget->setResizeMode(QQuickWidget::SizeRootObjectToView);
|
2023-02-03 10:36:14 +01:00
|
|
|
widget->setObjectName(Constants::OBJECT_NAME_BUSY_INDICATOR);
|
|
|
|
|
|
2022-02-09 18:49:40 +01:00
|
|
|
return widget;
|
|
|
|
|
}
|
|
|
|
|
|
2020-02-11 11:33:25 +02:00
|
|
|
Edit3DCanvas::Edit3DCanvas(Edit3DWidget *parent)
|
2022-02-09 18:49:40 +01:00
|
|
|
: QWidget(parent)
|
|
|
|
|
, m_parent(parent)
|
|
|
|
|
, m_busyIndicator(createBusyIndicator(this))
|
2020-02-11 11:33:25 +02:00
|
|
|
{
|
|
|
|
|
setMouseTracking(true);
|
|
|
|
|
setAcceptDrops(true);
|
2020-12-10 10:57:37 +01:00
|
|
|
setFocusPolicy(Qt::ClickFocus);
|
2022-02-09 18:49:40 +01:00
|
|
|
m_busyIndicator->show();
|
2020-02-11 11:33:25 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void Edit3DCanvas::updateRenderImage(const QImage &img)
|
|
|
|
|
{
|
|
|
|
|
m_image = img;
|
|
|
|
|
update();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void Edit3DCanvas::updateActiveScene(qint32 activeScene)
|
|
|
|
|
{
|
|
|
|
|
m_activeScene = activeScene;
|
|
|
|
|
}
|
|
|
|
|
|
2022-02-09 18:49:40 +01:00
|
|
|
QImage QmlDesigner::Edit3DCanvas::renderImage() const
|
|
|
|
|
{
|
|
|
|
|
return m_image;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void Edit3DCanvas::setOpacity(qreal opacity)
|
|
|
|
|
{
|
|
|
|
|
m_opacity = opacity;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
QWidget *Edit3DCanvas::busyIndicator() const
|
|
|
|
|
{
|
|
|
|
|
return m_busyIndicator;
|
|
|
|
|
}
|
|
|
|
|
|
2024-03-01 15:41:19 +02:00
|
|
|
void Edit3DCanvas::setFlyMode(bool enabled, const QPoint &pos)
|
|
|
|
|
{
|
|
|
|
|
if (m_flyMode == enabled)
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
m_flyMode = enabled;
|
|
|
|
|
|
|
|
|
|
if (enabled) {
|
|
|
|
|
m_flyModeStartTime = QDateTime::currentMSecsSinceEpoch();
|
|
|
|
|
|
|
|
|
|
// Mouse cursor will be hidden in the flight mode
|
|
|
|
|
QApplication::setOverrideCursor(QCursor(Qt::BlankCursor));
|
|
|
|
|
|
|
|
|
|
m_flyModeStartCursorPos = pos;
|
|
|
|
|
m_flyModeFirstUpdate = true;
|
|
|
|
|
|
|
|
|
|
// Hide cursor on the middle of the active split to make the wheel work during flight mode.
|
|
|
|
|
// We can't rely on current activeSplit value, as mouse press to enter flight mode can change the
|
|
|
|
|
// active split, so hide the cursor based on its current location.
|
|
|
|
|
QPoint center = mapToGlobal(QPoint(width() / 2, height() / 2));
|
|
|
|
|
if (m_parent->view()->isSplitView()) {
|
|
|
|
|
if (pos.x() <= center.x()) {
|
|
|
|
|
if (pos.y() <= center.y())
|
|
|
|
|
m_hiddenCursorPos = mapToGlobal(QPoint(width() / 4, height() / 4));
|
|
|
|
|
else
|
|
|
|
|
m_hiddenCursorPos = mapToGlobal(QPoint(width() / 4, (height() / 4) * 3));
|
|
|
|
|
} else {
|
|
|
|
|
if (pos.y() <= center.y())
|
|
|
|
|
m_hiddenCursorPos = mapToGlobal(QPoint((width() / 4) * 3, height() / 4));
|
|
|
|
|
else
|
|
|
|
|
m_hiddenCursorPos = mapToGlobal(QPoint((width() / 4) * 3, (height() / 4) * 3));
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
m_hiddenCursorPos = center;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
QCursor::setPos(m_hiddenCursorPos);
|
|
|
|
|
} else {
|
|
|
|
|
QCursor::setPos(m_flyModeStartCursorPos);
|
|
|
|
|
|
|
|
|
|
if (QApplication::overrideCursor())
|
|
|
|
|
QApplication::restoreOverrideCursor();
|
|
|
|
|
|
|
|
|
|
if (m_contextMenuPending && (QDateTime::currentMSecsSinceEpoch() - m_flyModeStartTime) < 500)
|
|
|
|
|
m_parent->view()->showContextMenu();
|
|
|
|
|
|
|
|
|
|
m_contextMenuPending = false;
|
|
|
|
|
m_flyModeStartTime = 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
m_parent->view()->setFlyMode(enabled);
|
|
|
|
|
}
|
|
|
|
|
|
2020-02-11 11:33:25 +02:00
|
|
|
void Edit3DCanvas::mousePressEvent(QMouseEvent *e)
|
|
|
|
|
{
|
2024-03-01 15:41:19 +02:00
|
|
|
m_contextMenuPending = false;
|
|
|
|
|
if (!m_flyMode && e->modifiers() == Qt::NoModifier && e->buttons() == Qt::RightButton) {
|
|
|
|
|
setFlyMode(true, e->globalPos());
|
2022-08-19 13:04:26 +03:00
|
|
|
m_parent->view()->startContextMenu(e->pos());
|
2024-03-01 15:41:19 +02:00
|
|
|
m_contextMenuPending = true;
|
|
|
|
|
}
|
2022-08-19 13:04:26 +03:00
|
|
|
|
2020-02-11 11:33:25 +02:00
|
|
|
m_parent->view()->sendInputEvent(e);
|
|
|
|
|
QWidget::mousePressEvent(e);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void Edit3DCanvas::mouseReleaseEvent(QMouseEvent *e)
|
|
|
|
|
{
|
2024-03-01 15:41:19 +02:00
|
|
|
if ((e->buttons() & Qt::RightButton) == Qt::NoButton)
|
|
|
|
|
setFlyMode(false);
|
2020-02-11 11:33:25 +02:00
|
|
|
m_parent->view()->sendInputEvent(e);
|
|
|
|
|
QWidget::mouseReleaseEvent(e);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void Edit3DCanvas::mouseDoubleClickEvent(QMouseEvent *e)
|
|
|
|
|
{
|
|
|
|
|
m_parent->view()->sendInputEvent(e);
|
|
|
|
|
QWidget::mouseDoubleClickEvent(e);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void Edit3DCanvas::mouseMoveEvent(QMouseEvent *e)
|
|
|
|
|
{
|
2024-03-01 15:41:19 +02:00
|
|
|
if (!m_flyMode)
|
|
|
|
|
m_parent->view()->sendInputEvent(e);
|
|
|
|
|
|
2020-02-11 11:33:25 +02:00
|
|
|
QWidget::mouseMoveEvent(e);
|
2024-03-01 15:41:19 +02:00
|
|
|
|
|
|
|
|
if (m_flyMode && e->globalPos() != m_hiddenCursorPos) {
|
|
|
|
|
if (!m_flyModeFirstUpdate) {
|
|
|
|
|
// We notify explicit camera rotation need for puppet rather than rely in mouse events,
|
|
|
|
|
// as mouse isn't grabbed on puppet side and can't handle fast movements that go out of
|
|
|
|
|
// edit camera mouse area. This also simplifies split view handling.
|
|
|
|
|
QPointF diff = m_hiddenCursorPos - e->globalPos();
|
|
|
|
|
if (e->buttons() == (Qt::LeftButton | Qt::RightButton)) {
|
|
|
|
|
m_parent->view()->emitView3DAction(View3DActionType::EditCameraMove,
|
|
|
|
|
QVector3D{float(-diff.x()), float(-diff.y()), 0.f});
|
|
|
|
|
} else {
|
|
|
|
|
m_parent->view()->emitView3DAction(View3DActionType::EditCameraRotation, diff / 6.);
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
// Skip first move to avoid undesirable jump occasionally when initiating flight mode
|
|
|
|
|
m_flyModeFirstUpdate = false;
|
|
|
|
|
}
|
|
|
|
|
QCursor::setPos(m_hiddenCursorPos);
|
|
|
|
|
}
|
2020-02-11 11:33:25 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void Edit3DCanvas::wheelEvent(QWheelEvent *e)
|
|
|
|
|
{
|
|
|
|
|
m_parent->view()->sendInputEvent(e);
|
|
|
|
|
QWidget::wheelEvent(e);
|
|
|
|
|
}
|
|
|
|
|
|
2022-01-10 16:40:35 +02:00
|
|
|
void Edit3DCanvas::keyPressEvent(QKeyEvent *e)
|
|
|
|
|
{
|
2024-03-01 15:41:19 +02:00
|
|
|
if (!e->isAutoRepeat())
|
|
|
|
|
m_parent->view()->sendInputEvent(e);
|
2022-01-10 16:40:35 +02:00
|
|
|
QWidget::keyPressEvent(e);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void Edit3DCanvas::keyReleaseEvent(QKeyEvent *e)
|
|
|
|
|
{
|
2024-03-01 15:41:19 +02:00
|
|
|
if (!e->isAutoRepeat())
|
|
|
|
|
m_parent->view()->sendInputEvent(e);
|
2022-01-10 16:40:35 +02:00
|
|
|
QWidget::keyReleaseEvent(e);
|
|
|
|
|
}
|
|
|
|
|
|
2022-07-07 18:04:18 +02:00
|
|
|
void Edit3DCanvas::paintEvent([[maybe_unused]] QPaintEvent *e)
|
2020-02-11 11:33:25 +02:00
|
|
|
{
|
|
|
|
|
QWidget::paintEvent(e);
|
|
|
|
|
|
|
|
|
|
QPainter painter(this);
|
|
|
|
|
|
2022-02-09 18:49:40 +01:00
|
|
|
if (m_opacity < 1.0) {
|
|
|
|
|
painter.fillRect(rect(), Qt::black);
|
|
|
|
|
painter.setOpacity(m_opacity);
|
|
|
|
|
}
|
|
|
|
|
|
2020-10-08 10:50:15 +03:00
|
|
|
painter.drawImage(rect(), m_image, QRect(0, 0, m_image.width(), m_image.height()));
|
2020-02-11 11:33:25 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void Edit3DCanvas::resizeEvent(QResizeEvent *e)
|
|
|
|
|
{
|
2022-02-09 18:49:40 +01:00
|
|
|
positionBusyInidicator();
|
2020-02-11 11:33:25 +02:00
|
|
|
m_parent->view()->edit3DViewResized(e->size());
|
|
|
|
|
}
|
|
|
|
|
|
2020-11-20 12:24:58 +01:00
|
|
|
void Edit3DCanvas::focusOutEvent(QFocusEvent *focusEvent)
|
|
|
|
|
{
|
|
|
|
|
QmlDesignerPlugin::emitUsageStatisticsTime(Constants::EVENT_3DEDITOR_TIME,
|
|
|
|
|
m_usageTimer.elapsed());
|
2024-03-01 15:41:19 +02:00
|
|
|
|
|
|
|
|
setFlyMode(false);
|
|
|
|
|
m_parent->view()->emitView3DAction(View3DActionType::EditCameraStopAllMoves, {});
|
|
|
|
|
|
2020-11-20 12:24:58 +01:00
|
|
|
QWidget::focusOutEvent(focusEvent);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void Edit3DCanvas::focusInEvent(QFocusEvent *focusEvent)
|
|
|
|
|
{
|
|
|
|
|
m_usageTimer.restart();
|
|
|
|
|
QWidget::focusInEvent(focusEvent);
|
|
|
|
|
}
|
|
|
|
|
|
2023-10-06 17:46:25 +03:00
|
|
|
void Edit3DCanvas::enterEvent(QEnterEvent *e)
|
|
|
|
|
{
|
|
|
|
|
m_parent->view()->sendInputEvent(e);
|
|
|
|
|
QWidget::enterEvent(e);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void Edit3DCanvas::leaveEvent(QEvent *e)
|
|
|
|
|
{
|
|
|
|
|
m_parent->view()->sendInputEvent(e);
|
|
|
|
|
QWidget::leaveEvent(e);
|
|
|
|
|
}
|
|
|
|
|
|
2022-02-09 18:49:40 +01:00
|
|
|
void Edit3DCanvas::positionBusyInidicator()
|
|
|
|
|
{
|
|
|
|
|
m_busyIndicator->move(width() / 2 - 32, height() / 2 - 32);
|
|
|
|
|
}
|
|
|
|
|
|
2020-02-11 11:33:25 +02:00
|
|
|
}
|