forked from qt-creator/qt-creator
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:
@@ -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 {
|
||||
|
@@ -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
|
||||
|
@@ -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 {
|
||||
|
127
share/qtcreator/qml/qmlpuppet/mockfiles/FadeHandle.qml
Normal file
127
share/qtcreator/qml/qmlpuppet/mockfiles/FadeHandle.qml
Normal 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);
|
||||
}
|
||||
}
|
@@ -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");
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -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();
|
||||
}
|
||||
}
|
||||
|
@@ -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>
|
||||
|
Reference in New Issue
Block a user