forked from qt-creator/qt-creator
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:
@@ -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)
|
||||
}
|
||||
|
@@ -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 "";
|
||||
|
@@ -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;
|
||||
|
||||
|
@@ -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;
|
||||
|
@@ -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
|
||||
|
@@ -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";
|
||||
|
||||
|
@@ -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);
|
||||
|
@@ -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";
|
||||
|
@@ -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);
|
||||
}
|
||||
|
||||
|
@@ -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);
|
||||
|
@@ -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();
|
||||
|
@@ -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;
|
||||
};
|
||||
|
||||
}
|
||||
|
@@ -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()) {
|
||||
|
@@ -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,
|
||||
|
@@ -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);
|
||||
|
Reference in New Issue
Block a user