QmlDesigner: Add scale and rotation snapping to 3D view

Fixes: QDS-10464
Change-Id: I9b327b21a3e09313664b2b4b47772e3cb4244327
Reviewed-by: Qt CI Patch Build Bot <ci_patchbuild_bot@qt.io>
Reviewed-by: Mahmoud Badri <mahmoud.badri@qt.io>
This commit is contained in:
Miikka Heikkinen
2023-08-25 14:23:28 +03:00
parent 8af0528893
commit 84e537f313
15 changed files with 350 additions and 53 deletions

View File

@@ -23,16 +23,18 @@ Rectangle {
Rectangle {
id: ctrlRect
width: root.width - 16
height: posIntValue.height + 16
height: posIntValue.height + rotIntValue.height + scaleIntValue.height + 32
color: StudioTheme.Values.themePanelBackground
border.color: StudioTheme.Values.themeControlOutline
border.width: StudioTheme.Values.border
Column {
padding: 8
spacing: 8
Row {
x: 8
y: 8
width: posIntLabel.width + posIntValue.width + StudioTheme.Values.sectionRowSpacing
height: posIntValue.height
width: parent.width - 16
spacing: StudioTheme.Values.sectionRowSpacing
Text {
@@ -45,13 +47,18 @@ Rectangle {
height: posIntValue.height
}
Item { // Spacer
width: Math.max(ctrlRect.width - posIntLabel.width - posIntValue.width - 32, 1)
height: 1
}
StudioControls.RealSpinBox {
id: posIntValue
realFrom: 1
realTo: 100000
realValue: rootView.posInt
realStepSize: 1
width: ctrlRect.width - 24 - posIntLabel.width
width: 80
actionIndicatorVisible: false
hoverEnabled: true
@@ -62,10 +69,86 @@ Rectangle {
onRealValueChanged: rootView.posInt = realValue
}
}
Row {
height: rotIntValue.height
width: parent.width - 16
spacing: StudioTheme.Values.sectionRowSpacing
Text {
id: rotIntLabel
text: qsTr("Rotation Snap Interval:")
color: enabled ? StudioTheme.Values.themeTextColor
: StudioTheme.Values.themeTextColorDisabled
verticalAlignment: Qt.AlignVCenter
horizontalAlignment: Qt.AlignRight
height: rotIntValue.height
}
Item {
id: spacer
Item { // Spacer
width: Math.max(ctrlRect.width - rotIntLabel.width - rotIntValue.width - 32, 1)
height: 1
}
StudioControls.RealSpinBox {
id: rotIntValue
realFrom: 1
realTo: 360
realValue: rootView.rotInt
realStepSize: 1
width: 80
actionIndicatorVisible: false
hoverEnabled: true
ToolTip.visible: hovered
ToolTip.text: qsTr("Snap interval in degrees for rotation gizmo.")
ToolTip.delay: root.toolTipDelay
onRealValueChanged: rootView.rotInt = realValue
}
}
Row {
height: scaleIntValue.height
width: parent.width - 16
spacing: StudioTheme.Values.sectionRowSpacing
Text {
id: scaleIntLabel
text: qsTr("Scale Snap Interval (%):")
color: enabled ? StudioTheme.Values.themeTextColor
: StudioTheme.Values.themeTextColorDisabled
verticalAlignment: Qt.AlignVCenter
horizontalAlignment: Qt.AlignRight
height: scaleIntValue.height
}
Item { // Spacer
width: Math.max(ctrlRect.width - scaleIntLabel.width - scaleIntValue.width - 32, 1)
height: 1
}
StudioControls.RealSpinBox {
id: scaleIntValue
realFrom: 1
realTo: 100000
realValue: rootView.scaleInt
realStepSize: 1
width: 80
actionIndicatorVisible: false
hoverEnabled: true
ToolTip.visible: hovered
ToolTip.text: qsTr("Snap interval for scale gizmo in percentage of original scale.")
ToolTip.delay: root.toolTipDelay
onRealValueChanged: rootView.scaleInt = realValue
}
}
}
}
Item { // Spacer
width: 1
height: Math.max(root.height - buttons.height - ctrlRect.height - 16, 2)
}

View File

@@ -201,9 +201,15 @@ void Edit3DView::modelAttached(Model *model)
AbstractView::modelAttached(model);
rootModelNode().setAuxiliaryData(edit3dSnapPosProperty, m_snapPositionAction->action()->isChecked());
rootModelNode().setAuxiliaryData(edit3dSnapRotProperty, m_snapRotationAction->action()->isChecked());
rootModelNode().setAuxiliaryData(edit3dSnapScaleProperty, m_snapScaleAction->action()->isChecked());
rootModelNode().setAuxiliaryData(edit3dSnapAbsProperty, m_snapAbsoluteAction->action()->isChecked());
rootModelNode().setAuxiliaryData(edit3dSnapPosIntProperty,
Edit3DViewConfig::load(DesignerSettingsKey::EDIT3DVIEW_SNAP_POSITION_INTERVAL));
rootModelNode().setAuxiliaryData(edit3dSnapRotIntProperty,
Edit3DViewConfig::load(DesignerSettingsKey::EDIT3DVIEW_SNAP_ROTATION_INTERVAL));
rootModelNode().setAuxiliaryData(edit3dSnapScaleIntProperty,
Edit3DViewConfig::load(DesignerSettingsKey::EDIT3DVIEW_SNAP_SCALE_INTERVAL));
checkImports();
auto cachedImage = m_canvasCache.take(model);
@@ -938,7 +944,7 @@ void Edit3DView::createEdit3DActions()
QmlDesigner::Constants::EDIT3D_SNAP_POSITION,
View3DActionType::Empty,
QCoreApplication::translate("SnapPositionAction", "Snap Position"),
QKeySequence(Qt::SHIFT | Qt::Key_Tab),
QKeySequence(Qt::SHIFT | Qt::Key_W),
true,
Edit3DViewConfig::load(settingKeyForAction(QmlDesigner::Constants::EDIT3D_SNAP_POSITION), false).toBool(),
QIcon(),
@@ -946,6 +952,40 @@ void Edit3DView::createEdit3DActions()
snapPositionTrigger,
QCoreApplication::translate("SnapPositionAction", "Toggle position snapping during node drag."));
SelectionContextOperation snapRotationTrigger = [this](const SelectionContext &) {
if (model())
rootModelNode().setAuxiliaryData(edit3dSnapRotProperty, m_snapRotationAction->action()->isChecked());
};
m_snapRotationAction = std::make_unique<Edit3DAction>(
QmlDesigner::Constants::EDIT3D_SNAP_ROTATION,
View3DActionType::Empty,
QCoreApplication::translate("SnapRotationAction", "Snap Rotation"),
QKeySequence(Qt::SHIFT | Qt::Key_E),
true,
Edit3DViewConfig::load(settingKeyForAction(QmlDesigner::Constants::EDIT3D_SNAP_ROTATION), false).toBool(),
QIcon(),
this,
snapRotationTrigger,
QCoreApplication::translate("SnapRotationAction", "Toggle rotation snapping during node drag."));
SelectionContextOperation snapScaleTrigger = [this](const SelectionContext &) {
if (model())
rootModelNode().setAuxiliaryData(edit3dSnapScaleProperty, m_snapScaleAction->action()->isChecked());
};
m_snapScaleAction = std::make_unique<Edit3DAction>(
QmlDesigner::Constants::EDIT3D_SNAP_SCALE,
View3DActionType::Empty,
QCoreApplication::translate("SnapScaleAction", "Snap Scale"),
QKeySequence(Qt::SHIFT | Qt::Key_R),
true,
Edit3DViewConfig::load(settingKeyForAction(QmlDesigner::Constants::EDIT3D_SNAP_SCALE), false).toBool(),
QIcon(),
this,
snapScaleTrigger,
QCoreApplication::translate("SnapScaleAction", "Toggle scale snapping during node drag."));
SelectionContextOperation snapAbsoluteTrigger = [this](const SelectionContext &) {
if (model())
rootModelNode().setAuxiliaryData(edit3dSnapAbsProperty, m_snapAbsoluteAction->action()->isChecked());
@@ -954,14 +994,14 @@ void Edit3DView::createEdit3DActions()
m_snapAbsoluteAction = std::make_unique<Edit3DAction>(
QmlDesigner::Constants::EDIT3D_SNAP_ABSOLUTE,
View3DActionType::Empty,
QCoreApplication::translate("SnapAbsoluteAction", "Absolute Snap"),
QKeySequence(Qt::SHIFT | Qt::Key_W),
QCoreApplication::translate("SnapAbsoluteAction", "Absolute Position Snap"),
QKeySequence(Qt::SHIFT | Qt::Key_A),
true,
Edit3DViewConfig::load(settingKeyForAction(QmlDesigner::Constants::EDIT3D_SNAP_ABSOLUTE), true).toBool(),
QIcon(),
this,
snapAbsoluteTrigger,
QCoreApplication::translate("SnapAbsoluteAction", "If enabled, snapping uses scene origin as origin point.\nOtherwise snapping uses drag start point as origin point."));
QCoreApplication::translate("SnapAbsoluteAction", "If enabled, position snapping uses scene origin as origin point.\nOtherwise snapping uses drag start point as origin point."));
m_leftActions << m_selectionModeAction.get();
m_leftActions << nullptr; // Null indicates separator
@@ -1010,6 +1050,8 @@ void Edit3DView::createEdit3DActions()
m_snapActions << m_snapConfigAction.get();
m_snapActions << m_snapPositionAction.get();
m_snapActions << m_snapRotationAction.get();
m_snapActions << m_snapScaleAction.get();
m_snapActions << m_snapAbsoluteAction.get();
}
@@ -1123,6 +1165,10 @@ const char *Edit3DView::settingKeyForAction(const QByteArray &actionId)
{
if (actionId == Constants::EDIT3D_SNAP_POSITION)
return DesignerSettingsKey::EDIT3DVIEW_SNAP_POSITION;
if (actionId == Constants::EDIT3D_SNAP_ROTATION)
return DesignerSettingsKey::EDIT3DVIEW_SNAP_ROTATION;
if (actionId == Constants::EDIT3D_SNAP_SCALE)
return DesignerSettingsKey::EDIT3DVIEW_SNAP_SCALE;
if (actionId == Constants::EDIT3D_SNAP_ABSOLUTE)
return DesignerSettingsKey::EDIT3DVIEW_SNAP_ABSOLUTE;
return "";

View File

@@ -147,6 +147,8 @@ private:
std::unique_ptr<Edit3DAction> m_snapMenuAction;
std::unique_ptr<Edit3DAction> m_snapConfigAction;
std::unique_ptr<Edit3DAction> m_snapPositionAction;
std::unique_ptr<Edit3DAction> m_snapRotationAction;
std::unique_ptr<Edit3DAction> m_snapScaleAction;
std::unique_ptr<Edit3DAction> m_snapAbsoluteAction;
std::unique_ptr<Edit3DBakeLightsAction> m_bakeLightsAction;

View File

@@ -54,14 +54,26 @@ void SnapConfiguration::apply()
{
Edit3DViewConfig::save(DesignerSettingsKey::EDIT3DVIEW_SNAP_POSITION_INTERVAL,
m_positionInterval);
Edit3DViewConfig::save(DesignerSettingsKey::EDIT3DVIEW_SNAP_ROTATION_INTERVAL,
m_rotationInterval);
Edit3DViewConfig::save(DesignerSettingsKey::EDIT3DVIEW_SNAP_SCALE_INTERVAL,
m_scaleInterval);
m_view->rootModelNode().setAuxiliaryData(edit3dSnapPosIntProperty, m_positionInterval);
m_view->rootModelNode().setAuxiliaryData(edit3dSnapRotIntProperty, m_rotationInterval);
m_view->rootModelNode().setAuxiliaryData(edit3dSnapScaleIntProperty, m_scaleInterval);
}
void SnapConfiguration::showConfigDialog(const QPoint &pos)
{
double posInt = Edit3DViewConfig::load(
DesignerSettingsKey::EDIT3DVIEW_SNAP_POSITION_INTERVAL, 10.).toDouble();
double rotInt = Edit3DViewConfig::load(
DesignerSettingsKey::EDIT3DVIEW_SNAP_ROTATION_INTERVAL, 15.).toDouble();
double scaleInt = Edit3DViewConfig::load(
DesignerSettingsKey::EDIT3DVIEW_SNAP_SCALE_INTERVAL, 10.).toDouble();
setPosInt(posInt);
setRotInt(rotInt);
setScaleInt(scaleInt);
if (!m_configDialog) {
// Show non-modal progress dialog with cancel button
@@ -73,7 +85,7 @@ void SnapConfiguration::showConfigDialog(const QPoint &pos)
m_configDialog->setFlags(Qt::Dialog);
m_configDialog->setModality(Qt::ApplicationModal);
m_configDialog->engine()->addImportPath(propertyEditorResourcesPath() + "/imports");
m_configDialog->setMinimumSize({250, 100});
m_configDialog->setMinimumSize({280, 170});
m_configDialog->rootContext()->setContextProperties({
{"rootView", QVariant::fromValue(this)}
@@ -98,6 +110,22 @@ void SnapConfiguration::setPosInt(double value)
}
}
void SnapConfiguration::setRotInt(double value)
{
if (value != m_rotationInterval) {
m_rotationInterval = value;
emit rotIntChanged();
}
}
void SnapConfiguration::setScaleInt(double value)
{
if (value != m_scaleInterval) {
m_scaleInterval = value;
emit scaleIntChanged();
}
}
void SnapConfiguration::cleanup()
{
delete m_configDialog;

View File

@@ -22,11 +22,21 @@ inline constexpr AuxiliaryDataKeyView edit3dSnapPosIntProperty{AuxiliaryDataType
"snapPosInt3d"};
inline constexpr AuxiliaryDataKeyView edit3dSnapAbsProperty{AuxiliaryDataType::NodeInstanceAuxiliary,
"snapAbs3d"};
inline constexpr AuxiliaryDataKeyView edit3dSnapRotProperty{AuxiliaryDataType::NodeInstanceAuxiliary,
"snapRot3d"};
inline constexpr AuxiliaryDataKeyView edit3dSnapRotIntProperty{AuxiliaryDataType::NodeInstanceAuxiliary,
"snapRotInt3d"};
inline constexpr AuxiliaryDataKeyView edit3dSnapScaleProperty{AuxiliaryDataType::NodeInstanceAuxiliary,
"snapScale3d"};
inline constexpr AuxiliaryDataKeyView edit3dSnapScaleIntProperty{AuxiliaryDataType::NodeInstanceAuxiliary,
"snapScaleInt3d"};
class SnapConfiguration : public QObject
{
Q_OBJECT
Q_PROPERTY(double posInt READ posInt WRITE setPosInt NOTIFY posIntChanged)
Q_PROPERTY(double rotInt READ rotInt WRITE setRotInt NOTIFY rotIntChanged)
Q_PROPERTY(double scaleInt READ scaleInt WRITE setScaleInt NOTIFY scaleIntChanged)
public:
SnapConfiguration(AbstractView *view);
@@ -39,9 +49,15 @@ public:
void setPosInt(double value);
double posInt() const { return m_positionInterval; }
void setRotInt(double value);
double rotInt() const { return m_rotationInterval; }
void setScaleInt(double value);
double scaleInt() const { return m_scaleInterval; }
signals:
void posIntChanged();
void rotIntChanged();
void scaleIntChanged();
protected:
bool eventFilter(QObject *obj, QEvent *event) override;
@@ -51,7 +67,9 @@ private:
QPointer<QQuickView> m_configDialog;
QPointer<AbstractView> m_view;
double m_positionInterval = 11.;
double m_positionInterval = 10.;
double m_rotationInterval = 15.;
double m_scaleInterval = 10.;
};
} // namespace QmlDesigner

View File

@@ -66,6 +66,8 @@ const char EDIT3D_BACKGROUND_COLOR_ACTIONS[] = "QmlDesigner.Editor3D.BackgroundC
const char EDIT3D_BAKE_LIGHTS[] = "QmlDesigner.Editor3D.BakeLights";
const char EDIT3D_SNAP_MENU[] = "QmlDesigner.Editor3D.SnapMenu";
const char EDIT3D_SNAP_POSITION[] = "QmlDesigner.Editor3D.SnapPosition";
const char EDIT3D_SNAP_ROTATION[] = "QmlDesigner.Editor3D.SnapRotation";
const char EDIT3D_SNAP_SCALE[] = "QmlDesigner.Editor3D.SnapScale";
const char EDIT3D_SNAP_CONFIG[] = "QmlDesigner.Editor3D.SnapConfig";
const char EDIT3D_SNAP_ABSOLUTE[] = "QmlDesigner.Editor3D.SnapToGrid";

View File

@@ -86,6 +86,10 @@ void DesignerSettings::fromSettings(QSettings *settings)
restoreValue(settings, DesignerSettingsKey::EDIT3DVIEW_SNAP_ABSOLUTE, true);
restoreValue(settings, DesignerSettingsKey::EDIT3DVIEW_SNAP_POSITION, false);
restoreValue(settings, DesignerSettingsKey::EDIT3DVIEW_SNAP_POSITION_INTERVAL, 10.);
restoreValue(settings, DesignerSettingsKey::EDIT3DVIEW_SNAP_ROTATION, false);
restoreValue(settings, DesignerSettingsKey::EDIT3DVIEW_SNAP_ROTATION_INTERVAL, 15.);
restoreValue(settings, DesignerSettingsKey::EDIT3DVIEW_SNAP_SCALE, false);
restoreValue(settings, DesignerSettingsKey::EDIT3DVIEW_SNAP_SCALE_INTERVAL, 10.);
restoreValue(settings, DesignerSettingsKey::SMOOTH_RENDERING, false);
restoreValue(settings, DesignerSettingsKey::SHOW_DEBUG_SETTINGS, false);
restoreValue(settings, DesignerSettingsKey::EDITOR_ZOOM_FACTOR, 1.0);

View File

@@ -35,6 +35,10 @@ inline constexpr char EDIT3DVIEW_GRID_COLOR[] = "Edit3DViewGridLineColor";
inline constexpr char EDIT3DVIEW_SNAP_ABSOLUTE[] = "Edit3DViewSnapAbsolute";
inline constexpr char EDIT3DVIEW_SNAP_POSITION[] = "Edit3DViewSnapPosition";
inline constexpr char EDIT3DVIEW_SNAP_POSITION_INTERVAL[] = "Edit3DViewSnapPositionInterval";
inline constexpr char EDIT3DVIEW_SNAP_ROTATION[] = "Edit3DViewSnapRotation";
inline constexpr char EDIT3DVIEW_SNAP_ROTATION_INTERVAL[] = "Edit3DViewSnapRotationInterval";
inline constexpr char EDIT3DVIEW_SNAP_SCALE[] = "Edit3DViewSnapScale";
inline constexpr char EDIT3DVIEW_SNAP_SCALE_INTERVAL[] = "Edit3DViewSnapScaleInterval";
inline constexpr char ALWAYS_SAVE_IN_CRUMBLEBAR[] = "AlwaysSaveInCrumbleBar";
inline constexpr char USE_DEFAULT_PUPPET[] = "UseDefaultQml2Puppet";
inline constexpr char PUPPET_TOPLEVEL_BUILD_DIRECTORY[] = "PuppetToplevelBuildDirectory";

View File

@@ -49,6 +49,7 @@ Model {
currentAngle = mouseAreaMain.dragHelper.getNewRotationAngle(
targetNode, _pointerPosPressed, Qt.vector3d(screenPos.x, screenPos.y, 0),
_targetPosOnScreen, currentAngle, _trackBall);
currentAngle = _generalHelper.adjustRotationForSnap(currentAngle);
mouseAreaMain.dragHelper.applyRotationAngleToNode(targetNode, _startRotation, currentAngle);
}

View File

@@ -180,6 +180,7 @@ Node {
var scaler = 1.0 + (yDelta * 0.025);
if (scaler === 0)
scaler = 0.0001;
scaler = _generalHelper.adjustScalerForSnap(scaler);
return Qt.vector3d(scaler * _startScale.x,
scaler * _startScale.y,
scaler * _startScale.z);

View File

@@ -771,6 +771,27 @@ bool GeneralHelper::isRotationBlocked(QQuick3DNode *node) const
return m_rotationBlockedNodes.contains(node);
}
// false is returned when keyboard modifiers result in no snapping.
// increment is adjusted according to keyboard modifiers
static bool queryKeyboardForSnapping(bool enabled, double &increment)
{
if (increment <= 0.)
return false;
// Need to do a hard query for key mods as puppet is not handling real events
Qt::KeyboardModifiers mods = QGuiApplication::queryKeyboardModifiers();
const bool shiftMod = mods & Qt::ShiftModifier;
const bool ctrlMod = mods & Qt::ControlModifier;
if ((!ctrlMod && !enabled) || (ctrlMod && enabled))
return false;
if (shiftMod)
increment *= 0.1;
return true;
}
QVector3D GeneralHelper::adjustTranslationForSnap(const QVector3D &newPos,
const QVector3D &startPos,
const QVector3D &snapAxes,
@@ -781,19 +802,10 @@ QVector3D GeneralHelper::adjustTranslationForSnap(const QVector3D &newPos,
bool snapAbs = m_snapAbsolute;
double increment = m_snapPositionInterval;
if (!node || increment == 0. || snapAxes.isNull() || qFuzzyIsNull((newPos - startPos).length()))
if (!node || snapAxes.isNull() || qFuzzyIsNull((newPos - startPos).length())
|| !queryKeyboardForSnapping(snapPos, increment)) {
return newPos;
// Need to do a hard query for key mods as puppet is not handling real events
Qt::KeyboardModifiers mods = QGuiApplication::queryKeyboardModifiers();
const bool shiftMod = mods & Qt::ShiftModifier;
const bool ctrlMod = mods & Qt::ControlModifier;
if ((!ctrlMod && !snapPos) || (ctrlMod && snapPos))
return newPos;
if (shiftMod)
increment *= 0.1;
}
// The node is aligned if there is only 0/90/180/270 degree sceneRotation on the node
// on the drag axis, or the drag plane normal for plane drags
@@ -884,6 +896,63 @@ QVector3D GeneralHelper::adjustTranslationForSnap(const QVector3D &newPos,
return newPos;
}
// newAngle and return are radians
double GeneralHelper::adjustRotationForSnap(double newAngle)
{
bool snapRot = m_snapRotation;
double increment = m_snapRotationInterval;
if (qFuzzyIsNull(newAngle) || !queryKeyboardForSnapping(snapRot, increment))
return newAngle;
double angleDeg = qRadiansToDegrees(newAngle);
double comp1 = double(int(angleDeg / increment)) * increment;
double comp2 = angleDeg > 0 ? comp1 + increment : comp1 - increment;
return qAbs(angleDeg - comp1) > qAbs(angleDeg - comp2) ?
qDegreesToRadians(comp2) : qDegreesToRadians(comp1);
}
static double adjustScaler(double newScale, double increment)
{
double absScale = qAbs(newScale);
double comp1 = 1. + double(int((absScale / increment) - (1. / increment))) * increment;
double comp2 = comp1 + increment;
double retVal = absScale - comp1 > comp2 - absScale ? comp2 : comp1;
if (newScale < 0)
retVal *= -1.;
return retVal;
}
double GeneralHelper::adjustScalerForSnap(double newScale)
{
bool snapScale = m_snapScale;
double increment = m_snapScaleInterval;
if (qFuzzyIsNull(newScale) || !queryKeyboardForSnapping(snapScale, increment))
return newScale;
return adjustScaler(newScale, increment);
}
QVector3D GeneralHelper::adjustScaleForSnap(const QVector3D &newScale)
{
bool snapScale = m_snapScale;
double increment = m_snapScaleInterval;
if (qFuzzyIsNull(newScale.length()) || !queryKeyboardForSnapping(snapScale, increment))
return newScale;
QVector3D adjScale = newScale;
for (int i = 0; i < 3; ++i) {
if (!qFuzzyCompare(newScale[i], 1.f))
adjScale[i] = adjustScaler(newScale[i], increment);
}
return adjScale;
}
void GeneralHelper::handlePendingToolStateUpdate()
{
m_toolStateUpdateTimer.stop();

View File

@@ -106,9 +106,17 @@ public:
const QVector3D &snapAxes,
bool globalOrientation,
QQuick3DNode *node);
void setSnapPosition(bool enable) { m_snapPosition = enable; }
Q_INVOKABLE double adjustRotationForSnap(double newAngle);
Q_INVOKABLE double adjustScalerForSnap(double newScale);
QVector3D adjustScaleForSnap(const QVector3D &newScale);
void setSnapAbsolute(bool enable) { m_snapAbsolute = enable; }
void setSnapPosition(bool enable) { m_snapPosition = enable; }
void setSnapRotation(bool enable) { m_snapRotation = enable; }
void setSnapScale(bool enable) { m_snapScale = enable; }
void setSnapPositionInterval(double interval) { m_snapPositionInterval = interval; }
void setSnapRotationInterval(double interval) { m_snapRotationInterval = interval; }
void setSnapScaleInterval(double interval) { m_snapScaleInterval = interval / 100.; }
signals:
void overlayUpdateNeeded();
@@ -146,7 +154,11 @@ private:
bool m_snapAbsolute = true;
bool m_snapPosition = false;
bool m_snapRotation = false;
bool m_snapScale = false;
double m_snapPositionInterval = 10.;
double m_snapRotationInterval = 15.;
double m_snapScaleInterval = .1;
};
}

View File

@@ -5,6 +5,8 @@
#include "mousearea3d.h"
#include "generalhelper.h"
#include <QtGui/qguiapplication.h>
#include <QtQml/qqmlinfo.h>
#include <QtQuick3D/private/qquick3dcamera_p.h>
@@ -16,6 +18,8 @@
namespace QmlDesigner {
namespace Internal {
static GeneralHelper *s_generalHelper = nullptr;
// Double precision vector for cases where float calculations can suffer from rounding errors
class DoubleVec3D {
public:
@@ -632,6 +636,10 @@ QVector3D MouseArea3D::getNewScale(const QVector3D &startScale, const QVector2D
yScaler += axisY * relativeDistance.y() * distanceFactor;
scaleVec *= xScaler;
scaleVec *= yScaler;
if (s_generalHelper)
scaleVec = s_generalHelper->adjustScaleForSnap(scaleVec);
return startScale * scaleVec;
}
@@ -713,12 +721,14 @@ void MouseArea3D::applyFreeRotation(QQuick3DNode *node, const QVector3D &startRo
QVector3D yAxis = QVector3D(dataPtr[4], dataPtr[5], dataPtr[6]).normalized();
QVector3D finalAxis = (dragVector.x() * yAxis + dragVector.y() * xAxis);
qreal degrees = qRadiansToDegrees(qreal(finalAxis.length()) * mouseDragMultiplier());
qreal radians = qreal(finalAxis.length()) * mouseDragMultiplier();
if (s_generalHelper)
radians = s_generalHelper->adjustRotationForSnap(radians);
finalAxis.normalize();
node->setEulerRotation(startRotation);
node->rotate(degrees, finalAxis, QQuick3DNode::SceneSpace);
node->rotate(qRadiansToDegrees(radians), finalAxis, QQuick3DNode::SceneSpace);
}
// Calculate scene position of the node's pivot point, which in practice is just the position
@@ -818,6 +828,11 @@ QVector3D MouseArea3D::getMousePosInPlane(const MouseArea3D *helper,
return sceneTrans.inverted().transform(intersectGlobalPos).toVec3();
}
void QmlDesigner::Internal::MouseArea3D::setGeneralHelper(GeneralHelper *helper)
{
s_generalHelper = helper;
}
static QPoint getPosFromMoveEvent(QEvent *event)
{
switch (event->type()) {

View File

@@ -19,6 +19,8 @@
namespace QmlDesigner {
namespace Internal {
class GeneralHelper;
class MouseArea3D : public QQuick3DNode
{
Q_OBJECT
@@ -62,6 +64,7 @@ public:
QVector3D getMousePosInPlane(const MouseArea3D *helper, const QPointF &mousePosInView) const;
static qreal mouseDragMultiplier() { return .02; }
static void setGeneralHelper(GeneralHelper *helper);
Q_INVOKABLE QVector3D rayIntersectsPlane(const QVector3D &rayPos0,
const QVector3D &rayPos1,

View File

@@ -376,10 +376,18 @@ void Qt5InformationNodeInstanceServer::updateSnapSettings(const QVector<Property
for (const auto &container : valueChanges) {
if (container.name() == "snapPos3d")
helper->setSnapPosition(container.value().toBool());
else if (container.name() == "snapAbs3d")
helper->setSnapAbsolute(container.value().toBool());
else if (container.name() == "snapPosInt3d")
helper->setSnapPositionInterval(container.value().toDouble());
else if (container.name() == "snapRot3d")
helper->setSnapRotation(container.value().toBool());
else if (container.name() == "snapRotInt3d")
helper->setSnapRotationInterval(container.value().toDouble());
else if (container.name() == "snapScale3d")
helper->setSnapScale(container.value().toBool());
else if (container.name() == "snapScaleInt3d")
helper->setSnapScaleInterval(container.value().toDouble());
else if (container.name() == "snapAbs3d")
helper->setSnapAbsolute(container.value().toBool());
}
}
#endif
@@ -482,6 +490,7 @@ void Qt5InformationNodeInstanceServer::createEditView3D()
engine()->addImageProvider(QLatin1String("IconGizmoImageProvider"),
new QmlDesigner::Internal::IconGizmoImageProvider);
m_3dHelper = helper;
Internal::MouseArea3D::setGeneralHelper(helper);
#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
createAuxiliaryQuickView(QUrl("qrc:/qtquickplugin/mockfiles/qt6/EditView3D.qml"), m_editView3DData);