QmlDesigner: Implement spotlight drag handles

Inner cone visualization for spotlight was added, as well as drag
handles to adjust inner and outer cone angles and fade.

Fade handle adjusts fades in order: quadratic, linear, constant.
If a specific fade value is zero, the next one in list is chosen
for adjustment.

Change-Id: I921936d9782de511558bc6c24cfa0953cce494f0
Fixes: QDS-2038
Reviewed-by: Thomas Hartmann <thomas.hartmann@qt.io>
This commit is contained in:
Miikka Heikkinen
2020-05-11 17:25:31 +03:00
parent 387657b83a
commit e4b2e45ea6
7 changed files with 286 additions and 52 deletions

View File

@@ -31,15 +31,14 @@ Node {
id: overlayNode
property View3D view3D
property Node target: parent
property bool autoScale: true
property Camera camera: view3D.camera
property bool active: true
// Read-only
property real relativeScale: 1
onActiveChanged: updateScale()
onSceneTransformChanged: updateScale()
onAutoScaleChanged: updateScale()
// Trigger delayed update on camera change to ensure camera values are correct
onCameraChanged: _generalHelper.requestOverlayUpdate();
@@ -61,11 +60,10 @@ Node {
function updateScale()
{
if (!autoScale) {
target.scale = Qt.vector3d(1, 1, 1);
} else {
if (active)
relativeScale = helper.getRelativeScale(overlayNode);
}
else
relativeScale = 1;
}
MouseArea3D {

View File

@@ -38,6 +38,7 @@ Model {
property MouseArea3D dragHelper: null
property alias material: material
property real length: 12
property real offset: 0
readonly property bool hovering: mouseAreaYZ.hovering || mouseAreaXZ.hovering
@@ -95,7 +96,7 @@ Model {
MouseArea3D {
id: mouseAreaYZ
view3D: rootModel.view3D
x: 0
x: rootModel.offset
y: -1.5
width: rootModel.length
height: 3
@@ -112,7 +113,7 @@ Model {
MouseArea3D {
id: mouseAreaXZ
view3D: rootModel.view3D
x: 0
x: rootModel.offset
y: -1.5
width: rootModel.length
height: 3

View File

@@ -457,8 +457,8 @@ Item {
view3D: overlayView
dragHelper: gizmoDragHelper
onBrightnessCommit: viewRoot.commitObjectProperty(viewRoot.selectedNode, "brightness")
onBrightnessChange: viewRoot.changeObjectProperty(viewRoot.selectedNode, "brightness")
onPropertyValueCommit: viewRoot.commitObjectProperty(targetNode, propName)
onPropertyValueChange: viewRoot.changeObjectProperty(targetNode, propName)
}
AutoScaleHelper {

View File

@@ -0,0 +1,127 @@
/****************************************************************************
**
** Copyright (C) 2020 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3 as published by the Free Software
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
**
****************************************************************************/
import QtQuick 2.0
import QtQuick3D 1.15
DirectionalDraggable {
id: handleRoot
property string currentLabel
property point currentMousePos
property real fadeScale
property real baseScale: 5
scale: autoScaler.getScale(Qt.vector3d(baseScale, baseScale, baseScale))
length: 3
offset: -1.5
Model {
id: handle
source: "#Sphere"
materials: [ handleRoot.material ]
scale: Qt.vector3d(0.02, 0.02, 0.02)
}
AutoScaleHelper {
id: autoScaler
active: handleRoot.active
view3D: handleRoot.view3D
}
property real _q // quadratic fade
property real _l // linear fade
property real _c // constant fade
property real _d: 20 // Divisor from fadeScale calc in lightGizmo
property real _startScale
property real _startFadeScale
property string _currentProp
signal valueCommit(string propName)
signal valueChange(string propName)
function updateFade(relativeDistance, screenPos)
{
// Solved from fadeScale equation in LightGizmo
var newValue = 0;
var _x = Math.max(0, (_startFadeScale - (relativeDistance * _startScale)) / 100);
// Fades capped to range 0-10 because property editor caps them to that range
if (_currentProp === "quadraticFade") {
if (_x === 0)
newValue = 10;
else
newValue = Math.max(0, Math.min(10, -(_c - _d + (_l * _x)) / (_x * _x)));
if (newValue < 0.01)
newValue = 0; // To avoid having tiny positive value when UI shows 0.00
targetNode.quadraticFade = newValue;
} else if (_currentProp === "linearFade") {
if (_x === 0)
newValue = 10;
else
newValue = Math.max(0, Math.min(10, -(_c - _d) / _x));
if (newValue < 0.01)
newValue = 0; // To avoid having tiny positive value when UI shows 0.00
targetNode.linearFade = newValue;
} else {
// Since pure constant fade equates to infinitely long cone, fadeScale calc assumes
// linear fade of one in this case.
newValue = Math.max(0, Math.min(10, _d - _x));
targetNode.constantFade = newValue;
}
var l = Qt.locale();
handleRoot.currentLabel = _currentProp + qsTr(": ") + Number(newValue).toLocaleString(l, 'f', 2);
handleRoot.currentMousePos = screenPos;
}
onPressed: {
_startScale = autoScaler.relativeScale * baseScale * 2;
_startFadeScale = fadeScale;
_l = targetNode.linearFade;
_c = targetNode.constantFade;
_q = targetNode.quadraticFade;
if (targetNode.quadraticFade === 0) {
if (targetNode.linearFade === 0) {
_currentProp = "constantFade";
} else {
_currentProp = "linearFade";
}
} else {
_currentProp = "quadraticFade";
}
updateFade(0, screenPos);
}
onDragged: {
updateFade(relativeDistance, screenPos);
handleRoot.valueChange(_currentProp);
}
onReleased: {
updateFade(relativeDistance, screenPos);
handleRoot.valueCommit(_currentProp);
}
}

View File

@@ -44,7 +44,7 @@ Node {
var c = targetNode.constantFade;
var d = 20; // divisor to target intensity value. E.g. 20 = 1/20 = 5%
if (l === 0 && q === 0)
l = 1;
l = 1; // For pure constant fade, cone would be infinite, so pretend we have linear fade
// Solved from equation in shader:
// 1 / d = 1 / (c + (l + q * dist) * dist);
if (q === 0)
@@ -56,11 +56,14 @@ Node {
}
}
readonly property bool dragging: primaryArrow.dragging
|| spotLightHandle.dragging
|| spotLightInnerHandle.dragging
|| spotLightFadeHandle.dragging
property point currentMousePos
property string currentLabel
signal brightnessCommit()
signal brightnessChange()
signal propertyValueCommit(string propName)
signal propertyValueChange(string propName)
position: targetNode ? targetNode.scenePosition : Qt.vector3d(0, 0, 0)
visible: lightGizmo.targetNode instanceof SpotLight
@@ -69,7 +72,7 @@ Node {
|| lightGizmo.targetNode instanceof PointLight
AutoScaleHelper {
id: autoScale
id: autoScaler
view3D: lightGizmo.view3D
}
@@ -89,44 +92,111 @@ Node {
rotation: !lightGizmo.targetNode ? Qt.quaternion(1, 0, 0, 0)
: lightGizmo.targetNode.sceneRotation
LightModel {
id: spotModel
property real coneScale: visible
? lightGizmo.fadeScale * Math.tan(Math.PI * targetNode.coneAngle / 180)
: 1
geometryName: "Edit 3D SpotLight"
geometryType: LightGeometry.Spot
material: lightMaterial
visible: lightGizmo.targetNode instanceof SpotLight
scale: Qt.vector3d(coneScale, coneScale, lightGizmo.fadeScale)
}
Node {
id: spotParts
visible: lightGizmo.targetNode instanceof SpotLight
SpotLightHandle {
id: sphereHandle1
view3D: lightGizmo.view3D
LightModel {
id: spotModel
property real coneXYScale: spotParts.visible && lightGizmo.targetNode
? lightGizmo.fadeScale * Math.tan(Math.PI * lightGizmo.targetNode.coneAngle / 180)
: 1
geometryName: "Edit 3D SpotLight Cone"
geometryType: LightGeometry.Spot
material: lightMaterial
position: Qt.vector3d(0, spotModel.scale.y, -spotModel.scale.z)
scale: Qt.vector3d(coneXYScale, coneXYScale,
spotParts.visible && lightGizmo.targetNode && lightGizmo.targetNode.coneAngle > 90
? -lightGizmo.fadeScale : lightGizmo.fadeScale)
}
SpotLightHandle {
id: sphereHandle2
view3D: lightGizmo.view3D
LightModel {
id: spotInnerModel
property real coneXYScale: spotParts.visible && lightGizmo.targetNode
? lightGizmo.fadeScale * Math.tan(Math.PI * lightGizmo.targetNode.innerConeAngle / 180)
: 1
geometryName: "Edit 3D SpotLight Inner Cone"
geometryType: LightGeometry.Spot
material: lightMaterial
position: Qt.vector3d(spotModel.scale.x, 0, -spotModel.scale.z)
scale: Qt.vector3d(coneXYScale, coneXYScale,
spotParts.visible && lightGizmo.targetNode && lightGizmo.targetNode.innerConeAngle > 90
? -lightGizmo.fadeScale : lightGizmo.fadeScale)
}
SpotLightHandle {
id: sphereHandle3
id: spotLightHandle
view3D: lightGizmo.view3D
material: lightMaterial
position: Qt.vector3d(0, -spotModel.scale.y, -spotModel.scale.z)
color: (hovering || dragging) ? Qt.rgba(1, 1, 1, 1) : lightGizmo.color
position: lightGizmo.targetNode instanceof SpotLight ? Qt.vector3d(0, spotModel.scale.y, -spotModel.scale.z)
: Qt.vector3d(0, 0, 0)
targetNode: lightGizmo.targetNode instanceof SpotLight ? lightGizmo.targetNode : null
active: lightGizmo.targetNode instanceof SpotLight
dragHelper: lightGizmo.dragHelper
propName: "coneAngle"
propValue: lightGizmo.targetNode instanceof SpotLight ? targetNode.coneAngle : 0
onNewValueChanged: targetNode.coneAngle = newValue
onCurrentMousePosChanged: {
lightGizmo.currentMousePos = currentMousePos;
lightGizmo.currentLabel = currentLabel;
}
onValueChange: lightGizmo.propertyValueChange(propName)
onValueCommit: {
if (targetNode.innerConeAngle > targetNode.coneAngle)
targetNode.innerConeAngle = targetNode.coneAngle;
lightGizmo.propertyValueCommit(propName)
lightGizmo.propertyValueCommit(spotLightInnerHandle.propName);
}
}
SpotLightHandle {
id: sphereHandle4
id: spotLightInnerHandle
view3D: lightGizmo.view3D
material: lightMaterial
position: Qt.vector3d(-spotModel.scale.x, 0, -spotModel.scale.z)
color: (hovering || dragging) ? Qt.rgba(1, 1, 1, 1) : lightGizmo.color
position: lightGizmo.targetNode instanceof SpotLight ? Qt.vector3d(0, -spotInnerModel.scale.y, -spotInnerModel.scale.z)
: Qt.vector3d(0, 0, 0)
eulerRotation: Qt.vector3d(180, 0, 0)
targetNode: lightGizmo.targetNode instanceof SpotLight ? lightGizmo.targetNode : null
active: lightGizmo.targetNode instanceof SpotLight
dragHelper: lightGizmo.dragHelper
propName: "innerConeAngle"
propValue: lightGizmo.targetNode instanceof SpotLight ? targetNode.innerConeAngle : 0
onNewValueChanged: targetNode.innerConeAngle = newValue
onCurrentMousePosChanged: {
lightGizmo.currentMousePos = currentMousePos;
lightGizmo.currentLabel = currentLabel;
}
onValueChange: lightGizmo.propertyValueChange(propName)
onValueCommit: {
if (targetNode.coneAngle < targetNode.innerConeAngle)
targetNode.coneAngle = targetNode.innerConeAngle;
lightGizmo.propertyValueCommit(propName)
lightGizmo.propertyValueCommit(spotLightHandle.propName);
}
}
FadeHandle {
id: spotLightFadeHandle
view3D: lightGizmo.view3D
color: (hovering || dragging) ? Qt.rgba(1, 1, 1, 1) : lightGizmo.color
position: lightGizmo.targetNode instanceof SpotLight ? Qt.vector3d(spotModel.scale.x / 2, 0, -spotInnerModel.scale.z / 2)
: Qt.vector3d(0, 0, 0)
eulerRotation: Qt.vector3d(90, 0, 0)
targetNode: lightGizmo.targetNode instanceof SpotLight ? lightGizmo.targetNode : null
active: lightGizmo.targetNode instanceof SpotLight
dragHelper: lightGizmo.dragHelper
fadeScale: lightGizmo.fadeScale
onCurrentMousePosChanged: {
lightGizmo.currentMousePos = currentMousePos;
lightGizmo.currentLabel = currentLabel;
}
onValueChange: lightGizmo.propertyValueChange(propName)
onValueCommit: lightGizmo.propertyValueCommit(propName)
}
}
@@ -148,7 +218,7 @@ Node {
geometryType: LightGeometry.Directional
material: lightMaterial
visible: lightGizmo.targetNode instanceof DirectionalLight
scale: autoScale.getScale(Qt.vector3d(50, 50, 50))
scale: autoScaler.getScale(Qt.vector3d(50, 50, 50))
}
LightModel {
@@ -168,7 +238,7 @@ Node {
view3D: lightGizmo.view3D
active: lightGizmo.visible
dragHelper: lightGizmo.dragHelper
scale: autoScale.getScale(Qt.vector3d(5, 5, 5))
scale: autoScaler.getScale(Qt.vector3d(5, 5, 5))
length: (lightGizmo.brightnessScale / 10) + 3
property real _startBrightness
@@ -177,7 +247,7 @@ Node {
{
var currentValue = Math.round(Math.max(0, _startBrightness + relativeDistance * 10));
var l = Qt.locale();
lightGizmo.currentLabel = qsTr("brightness: ") + Number(currentValue).toLocaleString(l, 'f', 0);
lightGizmo.currentLabel = "brightness" + qsTr(": ") + Number(currentValue).toLocaleString(l, 'f', 0);
lightGizmo.currentMousePos = screenPos;
targetNode.brightness = currentValue;
}
@@ -189,12 +259,12 @@ Node {
onDragged: {
updateBrightness(relativeDistance, screenPos);
lightGizmo.brightnessChange();
lightGizmo.propertyValueChange("brightness");
}
onReleased: {
updateBrightness(relativeDistance, screenPos);
lightGizmo.brightnessCommit();
lightGizmo.propertyValueCommit("brightness");
}
}

View File

@@ -26,20 +26,57 @@
import QtQuick 2.0
import QtQuick3D 1.15
Node {
DirectionalDraggable {
id: handleRoot
property DefaultMaterial material
property View3D view3D
property string currentLabel
property point currentMousePos
property string propName
property real propValue: 0
property real newValue: 0
scale: autoScaler.getScale(Qt.vector3d(5, 5, 5))
length: 3
offset: -1.5
Model {
scale: autoScale.getScale(Qt.vector3d(0.1, 0.1, 0.1))
id: handle
source: "#Sphere"
materials: [ handleRoot.material ]
scale: Qt.vector3d(0.02, 0.02, 0.02)
}
AutoScaleHelper {
id: autoScale
id: autoScaler
active: handleRoot.active
view3D: handleRoot.view3D
}
property real _startAngle
signal valueCommit()
signal valueChange()
function updateAngle(relativeDistance, screenPos)
{
handleRoot.newValue = Math.round(Math.min(180, Math.max(0, _startAngle + relativeDistance)));
var l = Qt.locale();
handleRoot.currentLabel = propName + qsTr(": ") + Number(newValue).toLocaleString(l, 'f', 0);
handleRoot.currentMousePos = screenPos;
}
onPressed: {
_startAngle = propValue;
updateAngle(0, screenPos);
}
onDragged: {
updateAngle(relativeDistance, screenPos);
handleRoot.valueChange();
}
onReleased: {
updateAngle(relativeDistance, screenPos);
handleRoot.valueCommit();
}
}

View File

@@ -53,5 +53,6 @@
<file>mockfiles/images/point@2x.png</file>
<file>mockfiles/images/spot.png</file>
<file>mockfiles/images/spot@2x.png</file>
<file>mockfiles/FadeHandle.qml</file>
</qresource>
</RCC>