summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorChristopher Ham <christopher.ham@nokia.com>2012-01-16 19:25:14 +1000
committerQt by Nokia <qt-info@nokia.com>2012-01-23 03:07:17 +0100
commit15f5b3c1f0eb8ffef9d700001e979945aa09fc30 (patch)
tree9d0b4b26962343d379b871648dd63495a5cf0fff
parent5a5714584fa94ca9ff68146aa9f53a274058c979 (diff)
Adding a color picker and material editting to ModelTweaker
The color picker has been added - needs clean up. Picker now updates the model properly. Texture selection is now working. And saving works. Change-Id: I031799eb2fcb5f61d1cf71d6b2d6d6d03907491a Reviewed-by: Christopher Ham <christopher.ham@nokia.com> Reviewed-by: Danny Pope <daniel.pope@nokia.com>
-rw-r--r--util/qt3d/modeltweak/modeltweak.pro7
-rw-r--r--util/qt3d/modeltweak/qml/ButtonBarPane.qml6
-rw-r--r--util/qt3d/modeltweak/qml/CheckBox.qml45
-rw-r--r--util/qt3d/modeltweak/qml/ColorPicker.qml286
-rw-r--r--util/qt3d/modeltweak/qml/ColorUtils.js61
-rw-r--r--util/qt3d/modeltweak/qml/ModelPropertiesPane.qml752
-rw-r--r--util/qt3d/modeltweak/qml/ModelTweak.qml40
-rw-r--r--util/qt3d/modeltweak/qml/ModelViewport.qml1
-rw-r--r--util/qt3d/modeltweak/qml/Widgets/BlenderToggle.qml1
-rw-r--r--util/qt3d/modeltweak/qml/Widgets/Checkered.qml27
-rw-r--r--util/qt3d/modeltweak/qml/Widgets/ColorSelector.qml72
-rw-r--r--util/qt3d/modeltweak/qml/Widgets/ColorWidget.qml37
-rw-r--r--util/qt3d/modeltweak/qml/Widgets/HSVColor.qml15
-rw-r--r--util/qt3d/modeltweak/qml/Widgets/InputBox.qml39
-rw-r--r--util/qt3d/modeltweak/qml/Widgets/SliderHandle.qml76
-rw-r--r--util/qt3d/modeltweak/qml/fileHandling.js26
16 files changed, 1211 insertions, 280 deletions
diff --git a/util/qt3d/modeltweak/modeltweak.pro b/util/qt3d/modeltweak/modeltweak.pro
index d77f4f1e..285927aa 100644
--- a/util/qt3d/modeltweak/modeltweak.pro
+++ b/util/qt3d/modeltweak/modeltweak.pro
@@ -23,10 +23,3 @@ RC_FILE = modeltweak.rc
HEADERS += \
quickfile.h
-
-
-
-
-
-
-
diff --git a/util/qt3d/modeltweak/qml/ButtonBarPane.qml b/util/qt3d/modeltweak/qml/ButtonBarPane.qml
index c366fb0d..c21f16bb 100644
--- a/util/qt3d/modeltweak/qml/ButtonBarPane.qml
+++ b/util/qt3d/modeltweak/qml/ButtonBarPane.qml
@@ -32,8 +32,10 @@ Flow {
{
FileHandler.save_qml(true);
}
-
- quickFile.load()
+ var useEffect = useCustomEffect;
+ useCustomEffect = false;
+ quickFile.load();
+ useCustomEffect = useEffect;
}
buttonText: "Load Asset"
imageSrc: "images/model.png"
diff --git a/util/qt3d/modeltweak/qml/CheckBox.qml b/util/qt3d/modeltweak/qml/CheckBox.qml
new file mode 100644
index 00000000..efadd539
--- /dev/null
+++ b/util/qt3d/modeltweak/qml/CheckBox.qml
@@ -0,0 +1,45 @@
+import QtQuick 1.0
+
+Item {
+ id: checkBox
+ height: Math.max (textBox.height, check.height)
+ width: textBox.width + check.width
+ property alias text: textBox.text
+ property bool checked: false
+ signal clicked(bool checked)
+ property variant color: Qt.rgba(1,1,1,1)
+
+ Text {
+ id: textBox
+ anchors.left: parent.left
+ color: checkBox.color
+ }
+
+ Rectangle {
+ id: check
+ width: 16
+ height: 16
+ anchors.right: parent.right
+
+ border.color: checkBox.color
+ border.width: 1
+ color: Qt.rgba(0,0,0,0)
+
+ Rectangle {
+ anchors.centerIn: parent
+
+ border.color: checkBox.color
+ border.width: 1
+
+ width: parent.width - 6
+ height: parent.height - 6
+ color: checkBox.color
+ opacity: checked
+ }
+ }
+
+ MouseArea {
+ anchors.fill: parent
+ onClicked: { checked = !checked; checkBox.clicked(checked) }
+ }
+}
diff --git a/util/qt3d/modeltweak/qml/ColorPicker.qml b/util/qt3d/modeltweak/qml/ColorPicker.qml
new file mode 100644
index 00000000..641a6acc
--- /dev/null
+++ b/util/qt3d/modeltweak/qml/ColorPicker.qml
@@ -0,0 +1,286 @@
+import QtQuick 1.0
+import "Widgets"
+import "ColorUtils.js" as ColorUtils
+
+Rectangle {
+ id: picker
+ property alias alpha: alphaSlider.value
+ property alias hue: hueSlider.value
+ property alias sat: colorSelector.sat
+ property alias val: colorSelector.val
+ property variant colorSelect: Qt.hsla(hsl_hue, hsl_sat, hsl_lum, alpha)
+ property HSVColor targetColor
+
+ HSVColor { id: oldColor }
+
+ property real hsl_hue: hue
+ property real hsl_sat: sat*val*((hsl_lum <= 2) ? hsl_lum*2 : 2*(1 - hsl_lum))
+ property real hsl_lum: ((2.0 - sat)*val)/2
+
+ property int red: rgb[0]
+ property int green: rgb[1]
+ property int blue: rgb[2]
+
+ property variant rgb: ColorUtils.hsvToRgb(hue, sat, val)
+
+ onRgbChanged: updateTarget()
+ onAlphaChanged: updateTarget()
+
+ anchors.fill: parent
+ property real bgAlpha: 0.5
+ color: Qt.rgba(1,1,1,bgAlpha)
+
+ function apply() {
+ updateTarget();
+ picker.visible = false;
+ }
+
+ function cancel() {
+ resetTarget();
+ picker.visible = false;
+ }
+
+ function setTarget(target) {
+ targetColor = target;
+ hue = target.hue;
+ sat = target.sat;
+ val = target.val;
+ alpha = target.alpha;
+ oldColor.hue = target.hue;
+ oldColor.sat = target.sat;
+ oldColor.val = target.val;
+ oldColor.alpha = target.alpha
+ }
+
+ function updateTarget() {
+ if (targetColor === null || !picker.visible) return;
+ targetColor.hue = hue;
+ targetColor.sat = sat;
+ targetColor.val = val;
+ targetColor.alpha = alpha;
+ }
+
+ function resetTarget() {
+ if (targetColor === null) return;
+ targetColor.hue = oldColor.hue;
+ targetColor.sat = oldColor.sat;
+ targetColor.val = oldColor.val;
+ targetColor.alpha = oldColor.alpha;
+ }
+
+ MouseArea {
+ anchors.fill: parent
+ onClicked: {}
+ }
+
+ Rectangle {
+ width: pickerLayout.implicitWidth+20
+ height: 250
+ anchors.centerIn: parent
+
+ border.width: 2
+ border.color: "white"
+ color: mainwindow.color
+
+ Row {
+ id: pickerLayout
+ anchors {
+ top: parent.top
+ horizontalCenter: parent.horizontalCenter
+ margins: 10
+ }
+ height: 200
+ spacing: 10
+
+ Item {
+ id: colorViewer
+ width: height
+ height: parent.height
+ Rectangle {
+ anchors.fill: parent
+ rotation: -90
+ gradient: Gradient {
+ GradientStop { position: 0.0; color: Qt.hsla(hueSlider.value, 1.0, 1.0) }
+ GradientStop { position: 1.0; color: Qt.hsla(hueSlider.value, 1.0, 0.5) }
+ }
+ }
+ Rectangle {
+ anchors.fill: parent
+ border.color: "lightgray"
+ gradient: Gradient {
+ GradientStop { position: 0.0; color: Qt.rgba(0,0,0,0) }
+ GradientStop { position: 1.0; color: Qt.rgba(0,0,0,1) }
+ }
+ }
+
+ ColorSelector {
+ id: colorSelector
+ anchors.fill: parent
+ }
+ }
+
+ Item {
+ width: 20
+ height: parent.height
+ Rectangle {
+ anchors.fill: parent
+ border.color: "lightgray"
+ gradient: Gradient {
+ GradientStop { position: 1.0; color: Qt.hsla(1.0, 1.0, 0.5) }
+ GradientStop { position: 0.85; color: Qt.hsla(0.85, 1.0, 0.5) }
+ GradientStop { position: 0.76; color: Qt.hsla(0.76, 1.0, 0.5) }
+ GradientStop { position: 0.5; color: Qt.hsla(0.5, 1.0, 0.5) }
+ GradientStop { position: 0.33; color: Qt.hsla(0.33, 1.0, 0.5) }
+ GradientStop { position: 0.16; color: Qt.hsla(0.16, 1.0, 0.5) }
+ GradientStop { position: 0.0; color: Qt.hsla(0.0, 1.0, 0.5) }
+ }
+ }
+
+ SliderHandle {
+ id: hueSlider
+ anchors.fill: parent
+ }
+ }
+
+ Item {
+ width: 20
+ height: parent.height
+
+ Checkered {
+ anchors.fill: parent
+ }
+
+ Rectangle {
+ anchors.fill: parent
+ border.color: "lightgray"
+ gradient: Gradient {
+ GradientStop {
+ position: 0.0;
+ color: Qt.hsla(picker.hsl_hue, picker.hsl_sat, picker.hsl_lum)
+ }
+ GradientStop {
+ position: 1.0;
+ color: Qt.hsla(picker.hsl_hue, picker.hsl_sat, picker.hsl_lum, 0)
+ }
+ }
+ }
+
+ SliderHandle {
+ id: alphaSlider
+ anchors.fill: parent
+ inverted: true
+ }
+ }
+
+ Item {
+ width: 60
+ height: parent.height
+
+ Item {
+ id: preview
+ width: parent.width; height: 40
+ Checkered {
+ anchors.fill: parent
+ }
+ Rectangle {
+ anchors.fill: parent
+ border.color: "lightgray"
+ color: picker.colorSelect
+ }
+ }
+
+ Column {
+ anchors.top: preview.bottom
+ anchors.topMargin: 5
+ spacing: 3
+ width: parent.width
+
+ InputBox {
+ id: redIn
+ width: parent.width; height: 20
+ label: "R:"
+ }
+
+ InputBox {
+ id: greenIn
+ width: parent.width; height: 20
+ label: "G:"
+ }
+
+ InputBox {
+ id: blueIn
+ width: parent.width; height: 20
+ label: "B:"
+ }
+
+ Binding {
+ target: redIn.input; property: "text"
+ value: Math.round(rgb[0])
+ }
+ Binding {
+ target: greenIn.input; property: "text"
+ value: Math.round(rgb[1])
+ }
+ Binding {
+ target: blueIn.input; property: "text"
+ value: Math.round(rgb[2])
+ }
+
+ Item {
+ width: 5; height: 5
+ }
+
+ InputBox {
+ id: hueIn
+ width: parent.width; height: 20
+ label: "H:"
+ }
+
+ InputBox {
+ id: satIn
+ width: parent.width; height: 20
+ label: "S:"
+ }
+
+ InputBox {
+ id: valIn
+ width: parent.width; height: 20
+ label: "V:"
+ }
+
+ Binding {
+ target: hueIn.input; property: "text"
+ value: Math.round(picker.hue*100)/100
+ }
+ Binding {
+ target: satIn.input; property: "text"
+ value: Math.round(picker.sat*100)/100
+ }
+ Binding {
+ target: valIn.input; property: "text"
+ value: Math.round(picker.val*100)/100
+ }
+ }
+ }
+ }
+
+ Row {
+ anchors {
+ margins: 5
+ top: pickerLayout.bottom
+ horizontalCenter: parent.horizontalCenter
+ }
+ spacing: 10
+ BlenderToggle {
+ width: 80
+ buttonText: "Apply"
+ onClicked: picker.apply()
+ }
+ BlenderToggle {
+ width: 80
+ buttonText: "Cancel"
+ onClicked: picker.cancel()
+ }
+ }
+ }
+}
diff --git a/util/qt3d/modeltweak/qml/ColorUtils.js b/util/qt3d/modeltweak/qml/ColorUtils.js
new file mode 100644
index 00000000..5addf394
--- /dev/null
+++ b/util/qt3d/modeltweak/qml/ColorUtils.js
@@ -0,0 +1,61 @@
+.pragma library
+
+function rgbToHsv(r, g, b) {
+ r = r/255; g = g/255; b = b/255;
+ var max = Math.max(r, g, b), min = Math.min(r, g, b);
+ var h, s, v = max;
+
+ var d = max - min;
+ s = max == 0 ? 0 : d / max;
+
+ if (max == min){
+ h = 0; // achromatic
+ } else {
+ switch (max) {
+ case r: h = (g - b) / d + (g < b ? 6 : 0); break;
+ case g: h = (b - r) / d + 2; break;
+ case b: h = (r - g) / d + 4; break;
+ }
+ h /= 6;
+ }
+
+ return new Array(h, s, v);
+}
+
+function hsvToRgb(h, s, v) {
+ var r, g, b;
+
+ var i = Math.floor(h * 6);
+ var f = h * 6 - i;
+ var p = v * (1 - s);
+ var q = v * (1 - f * s);
+ var t = v * (1 - (1 - f) * s);
+
+ switch (i % 6){
+ case 0: r = v; g = t; b = p; break;
+ case 1: r = q; g = v; b = p; break;
+ case 2: r = p; g = v; b = t; break;
+ case 3: r = p; g = q; b = v; break;
+ case 4: r = t; g = p; b = v; break;
+ case 5: r = v; g = p; b = q; break;
+ }
+
+ return new Array(r * 255, g * 255, b * 255);
+}
+
+function hsvToHsl(h, s, v) {
+ var ss, l;
+
+ l = ((2.0 - s)*v);
+
+ ss = s*v*((l <= 1) ? l : 2 - l);
+
+ l /= 2;
+
+ return new Array(h, ss, l);
+}
+
+function hsvToColor(h, s, v, a) {
+ var hsl = hsvToHsl(h,s,v);
+ return Qt.hsla(hsl[0], hsl[1], hsl[2], a);
+}
diff --git a/util/qt3d/modeltweak/qml/ModelPropertiesPane.qml b/util/qt3d/modeltweak/qml/ModelPropertiesPane.qml
index 7325402b..b83d92d4 100644
--- a/util/qt3d/modeltweak/qml/ModelPropertiesPane.qml
+++ b/util/qt3d/modeltweak/qml/ModelPropertiesPane.qml
@@ -1,310 +1,520 @@
import QtQuick 1.0
import Qt3D 1.0
import ModelTweak 1.0
+import "Widgets"
+import "ColorUtils.js" as ColorUtils
-Column {
+Row {
id: properties
- width: posX.width
- height: parent.height
- spacing: 4
-
+ spacing: 30
property alias rotateLocked: imageR.isLocked
property alias scaleLocked: imageS.isLocked
property alias translateLocked: imageP.isLocked;
signal changed;
+ Column {
+ width: posX.width
+ height: parent.height
+ spacing: 4
- // POSITION
- Item {
- id: positionPanel
- width: parent.width
- height: imageP.height
-
- Text {
- anchors.left: parent.left
- anchors.leftMargin: 8
- text: "Position";
- color: "#FFFFFF"
- }
- Image {
- id: imageP
- anchors.right: parent.right
- anchors.rightMargin: 8
-
- //Animation to pulse the lock icon if attempting to modify while locked.
- property bool bounce: false
-
- SequentialAnimation on scale{
- running: imageP.bounce
- NumberAnimation { to : 2.0; duration: 150; easing.type: "OutQuad" }
- NumberAnimation { to : 1.0; duration: 150; easing.type: "OutQuad" }
- NumberAnimation { to : 2.0; duration: 150; easing.type: "OutQuad" }
- NumberAnimation { to : 1.0; duration: 150; easing.type: "OutQuad" }
- onCompleted: imageP.bounce = false
+ // POSITION
+ Item {
+ id: positionPanel
+ width: parent.width
+ height: imageP.height
+
+ Text {
+ anchors.left: parent.left
+ anchors.leftMargin: 8
+ text: "Position";
+ color: "#FFFFFF"
}
+ Image {
+ id: imageP
+ anchors.right: parent.right
+ anchors.rightMargin: 8
- //Manage locked/unlocked state
- state: "UNLOCKED"
- property bool isLocked: false
-
- states: [
- State {
- name: "UNLOCKED"
- PropertyChanges { target: imageP; source: "images/unlock.png"}
- PropertyChanges { target: imageP; isLocked: false;}
- },
- State {
- name: "LOCKED"
- PropertyChanges { target: imageP; source: "images/lock.png"}
- PropertyChanges { target: imageP; isLocked: true;}
+ //Animation to pulse the lock icon if attempting to modify while locked.
+ property bool bounce: false
+
+ SequentialAnimation on scale{
+ running: imageP.bounce
+ NumberAnimation { to : 2.0; duration: 150; easing.type: "OutQuad" }
+ NumberAnimation { to : 1.0; duration: 150; easing.type: "OutQuad" }
+ NumberAnimation { to : 2.0; duration: 150; easing.type: "OutQuad" }
+ NumberAnimation { to : 1.0; duration: 150; easing.type: "OutQuad" }
+ onCompleted: imageP.bounce = false
}
- ]
-
- MouseArea {
- anchors.fill: parent
- onDoubleClicked: {
- if (parent.state=="LOCKED")
- parent.state="UNLOCKED"
- else
- parent.state="LOCKED"
+
+ //Manage locked/unlocked state
+ state: "UNLOCKED"
+ property bool isLocked: false
+
+ states: [
+ State {
+ name: "UNLOCKED"
+ PropertyChanges { target: imageP; source: "images/unlock.png"}
+ PropertyChanges { target: imageP; isLocked: false;}
+ },
+ State {
+ name: "LOCKED"
+ PropertyChanges { target: imageP; source: "images/lock.png"}
+ PropertyChanges { target: imageP; isLocked: true;}
+ }
+ ]
+
+ MouseArea {
+ anchors.fill: parent
+ onDoubleClicked: {
+ if (parent.state=="LOCKED")
+ parent.state="UNLOCKED"
+ else
+ parent.state="LOCKED"
+ }
}
}
}
- }
- BlenderValueSlider {
- focus: true
- id: posX
- label: "X:"
- locked: imageP.isLocked
- value: transformTranslate.translate.x.toFixed(3)
- function update (f) {
- transformTranslate.translate = Qt.vector3d(f, transformTranslate.translate.y, transformTranslate.translate.z);
+ BlenderValueSlider {
+ focus: true
+ id: posX
+ label: "X:"
+ locked: imageP.isLocked
+ value: transformTranslate.translate.x.toFixed(3)
+ function update (f) {
+ transformTranslate.translate = Qt.vector3d(f, transformTranslate.translate.y, transformTranslate.translate.z);
+ }
+ onNext: { updateMe(); focus = false; posY.focus = true; }
+ onPrev: { updateMe(); focus = false; scaleZ.focus = true; }
+ onFail: { imageP.bounce=true; }
+ onChanged: { properties.changed(); }
}
- onNext: { updateMe(); focus = false; posY.focus = true; }
- onPrev: { updateMe(); focus = false; scaleZ.focus = true; }
- onFail: { imageP.bounce=true; }
- onChanged: { properties.changed(); }
- }
- BlenderValueSlider {
- id: posY
- label: "Y:"
- locked: imageP.isLocked
- value: transformTranslate.translate.y.toFixed(3)
- function update (f) {
- transformTranslate.translate = Qt.vector3d(transformTranslate.translate.x, f, transformTranslate.translate.z);
+ BlenderValueSlider {
+ id: posY
+ label: "Y:"
+ locked: imageP.isLocked
+ value: transformTranslate.translate.y.toFixed(3)
+ function update (f) {
+ transformTranslate.translate = Qt.vector3d(transformTranslate.translate.x, f, transformTranslate.translate.z);
+ }
+ onNext: { updateMe(); focus = false; posZ.focus = true; }
+ onPrev: { updateMe(); focus = false; posX.focus = true; }
+ onFail: { imageP.bounce=true; }
+ onChanged: { properties.changed(); }
}
- onNext: { updateMe(); focus = false; posZ.focus = true; }
- onPrev: { updateMe(); focus = false; posX.focus = true; }
- onFail: { imageP.bounce=true; }
- onChanged: { properties.changed(); }
- }
- BlenderValueSlider {
- id: posZ
- label: "Z:"
- locked: imageP.isLocked
- value: transformTranslate.translate.z.toFixed(3)
- function update (f) {
- transformTranslate.translate = Qt.vector3d(transformTranslate.translate.x, transformTranslate.translate.y, f);
+ BlenderValueSlider {
+ id: posZ
+ label: "Z:"
+ locked: imageP.isLocked
+ value: transformTranslate.translate.z.toFixed(3)
+ function update (f) {
+ transformTranslate.translate = Qt.vector3d(transformTranslate.translate.x, transformTranslate.translate.y, f);
+ }
+ onNext: { updateMe(); focus = false; rotX.focus = true; }
+ onPrev: { updateMe(); focus = false; posY.focus = true; }
+ onFail: { imageP.bounce=true; }
+ onChanged: { properties.changed(); }
}
- onNext: { updateMe(); focus = false; rotX.focus = true; }
- onPrev: { updateMe(); focus = false; posY.focus = true; }
- onFail: { imageP.bounce=true; }
- onChanged: { properties.changed(); }
- }
- // ROTATE
- Item {
- id: rotationPanel
- width: parent.width
- height: imageR.height
- property bool dirty: false
-
- Text {
- anchors.left: parent.left
- anchors.leftMargin: 8
- text: "Rotation";
- color: "#FFFFFF"
+ // ROTATE
+ Item {
+ id: rotationPanel
+ width: parent.width
+ height: imageR.height
+ property bool dirty: false
+ Text {
+ anchors.left: parent.left
+ anchors.leftMargin: 8
+ text: "Scale";
+ color: "#FFFFFF"
+ }
+
+ Image {
+ id: imageR
+ anchors.right: parent.right
+ anchors.rightMargin: 8
+
+ //Animation to pulse the lock icon if attempting to modify while locked.
+ property bool bounce: false
+
+ SequentialAnimation on scale{
+ running: imageR.bounce
+ NumberAnimation { to : 2.0; duration: 150; easing.type: "OutQuad" }
+ NumberAnimation { to : 1.0; duration: 150; easing.type: "OutQuad" }
+ NumberAnimation { to : 2.0; duration: 150; easing.type: "OutQuad" }
+ NumberAnimation { to : 1.0; duration: 150; easing.type: "OutQuad" }
+ onCompleted: imageR.bounce = false
+ }
+
+ //Manage locked/unlocked state
+ state: "UNLOCKED"
+ property bool isLocked: false
+
+ states: [
+ State {
+ name: "UNLOCKED"
+ PropertyChanges { target: imageR; source: "images/unlock.png"}
+ PropertyChanges { target: imageR; isLocked: false;}
+ },
+ State {
+ name: "LOCKED"
+ PropertyChanges { target: imageR; source: "images/lock.png"}
+ PropertyChanges { target: imageR; isLocked: true;}
+ }
+ ]
+
+ MouseArea {
+ anchors.fill: parent
+ onDoubleClicked: {
+ if (parent.state=="LOCKED")
+ parent.state="UNLOCKED"
+ else
+ parent.state="LOCKED"
+ }
+ }
+ }
+ }
+ BlenderValueSlider {
+ id: rotX
+ label: "X:"
+ delta: 1
+ locked: imageR.isLocked
+ min: 0; limitMin: true
+ max: 360; limitMax: true
+ value: transformRotateX.angle.toFixed(3)
+ function update (f) { transformRotateX.angle = f }
+ onNext: { updateMe(); focus = false; rotY.focus = true; }
+ onPrev: { updateMe(); focus = false; posZ.focus = true; }
+ onFail: { imageR.bounce=true; }
+ onChanged: { properties.changed(); }
+ }
+ BlenderValueSlider {
+ id: rotY
+ label: "Y:"
+ delta: 1
+ locked: imageR.isLocked
+ min: 0; limitMin: true
+ max: 360; limitMax: true
+ value: transformRotateY.angle.toFixed(3)
+ function update (f) { transformRotateY.angle = f }
+ onNext: { updateMe(); focus = false; rotZ.focus = true; }
+ onPrev: { updateMe(); focus = false; rotX.focus = true; }
+ onFail: { imageR.bounce=true; }
+ onChanged: { properties.changed(); }
}
- Image {
- id: imageR
- anchors.right: parent.right
- anchors.rightMargin: 8
-
- //Animation to pulse the lock icon if attempting to modify while locked.
- property bool bounce: false
-
- SequentialAnimation on scale{
- running: imageR.bounce
- NumberAnimation { to : 2.0; duration: 150; easing.type: "OutQuad" }
- NumberAnimation { to : 1.0; duration: 150; easing.type: "OutQuad" }
- NumberAnimation { to : 2.0; duration: 150; easing.type: "OutQuad" }
- NumberAnimation { to : 1.0; duration: 150; easing.type: "OutQuad" }
- onCompleted: imageR.bounce = false
+ BlenderValueSlider {
+ id: rotZ
+ label: "Z:"
+ delta: 1
+ locked: imageR.isLocked
+ min: 0; limitMin: true
+ max: 360; limitMax: true
+ value: transformRotateZ.angle.toFixed(3)
+ function update (f) { transformRotateZ.angle = f }
+ onNext: { updateMe(); focus = false; scaleX.focus = true; }
+ onPrev: { updateMe(); focus = false; rotY.focus = true; }
+ onFail: { imageR.bounce=true; }
+ onChanged: { properties.changed(); }
+ }
+
+ // SCALE
+ Item {
+ id: scalePanel
+ width: parent.width
+ height: imageS.height
+ property bool dirty: false
+
+ Item {
+ width: parent.width
+ height: effectText.height
+ Text {
+ id: effectText
+ anchors.left: parent.left
+ anchors.leftMargin: 8
+ text: "Effect";
+ color: "#FFFFFF"
+ font.bold: true
+ }
}
- //Manage locked/unlocked state
- state: "UNLOCKED"
- property bool isLocked: false
-
- states: [
- State {
- name: "UNLOCKED"
- PropertyChanges { target: imageR; source: "images/unlock.png"}
- PropertyChanges { target: imageR; isLocked: false;}
- },
- State {
- name: "LOCKED"
- PropertyChanges { target: imageR; source: "images/lock.png"}
- PropertyChanges { target: imageR; isLocked: true;}
+ Image {
+ id: imageS
+ anchors.right: parent.right
+ anchors.rightMargin: 8
+
+ //Animation to pulse the lock icon if attempting to modify while locked.
+ property bool bounce: false
+
+ SequentialAnimation on scale{
+ running: imageS.bounce
+ NumberAnimation { to : 2.0; duration: 150; easing.type: "OutQuad" }
+ NumberAnimation { to : 1.0; duration: 150; easing.type: "OutQuad" }
+ NumberAnimation { to : 2.0; duration: 150; easing.type: "OutQuad" }
+ NumberAnimation { to : 1.0; duration: 150; easing.type: "OutQuad" }
+ onCompleted: imageS.bounce = false
}
- ]
-
- MouseArea {
- anchors.fill: parent
- onDoubleClicked: {
- if (parent.state=="LOCKED")
- parent.state="UNLOCKED"
- else
- parent.state="LOCKED"
+
+ //Manage locked/unlocked state
+ state: "UNLOCKED"
+ property bool isLocked: false
+
+ states: [
+ State {
+ name: "UNLOCKED"
+ PropertyChanges { target: imageS; source: "images/unlock.png"}
+ PropertyChanges { target: imageS; isLocked: false;}
+ },
+ State {
+ name: "LOCKED"
+ PropertyChanges { target: imageS; source: "images/lock.png"}
+ PropertyChanges { target: imageS; isLocked: true;}
+ }
+ ]
+
+ MouseArea {
+ anchors.fill: parent
+ onDoubleClicked: {
+ if (parent.state=="LOCKED")
+ parent.state="UNLOCKED"
+ else
+ parent.state="LOCKED"
+ }
}
}
}
- }
- BlenderValueSlider {
- id: rotX
- label: "X:"
- delta: 1
- locked: imageR.isLocked
- min: 0; limitMin: true
- max: 360; limitMax: true
- value: transformRotateX.angle.toFixed(3)
- function update (f) { transformRotateX.angle = f }
- onNext: { updateMe(); focus = false; rotY.focus = true; }
- onPrev: { updateMe(); focus = false; posZ.focus = true; }
- onFail: { imageR.bounce=true; }
- onChanged: { properties.changed(); }
- }
- BlenderValueSlider {
- id: rotY
- label: "Y:"
- delta: 1
- locked: imageR.isLocked
- min: 0; limitMin: true
- max: 360; limitMax: true
- value: transformRotateY.angle.toFixed(3)
- function update (f) { transformRotateY.angle = f }
- onNext: { updateMe(); focus = false; rotZ.focus = true; }
- onPrev: { updateMe(); focus = false; rotX.focus = true; }
- onFail: { imageR.bounce=true; }
- onChanged: { properties.changed(); }
- }
- BlenderValueSlider {
- id: rotZ
- label: "Z:"
- delta: 1
- locked: imageR.isLocked
- min: 0; limitMin: true
- max: 360; limitMax: true
- value: transformRotateZ.angle.toFixed(3)
- function update (f) { transformRotateZ.angle = f }
- onNext: { updateMe(); focus = false; scaleX.focus = true; }
- onPrev: { updateMe(); focus = false; rotY.focus = true; }
- onFail: { imageR.bounce=true; }
- onChanged: { properties.changed(); }
+ BlenderValueSlider {
+ id: scaleX
+ label: "X:"
+ locked: imageS.isLocked
+ min: 0; limitMin: true
+ value: transformScale.scale.x.toFixed(3)
+ function update (f) { transformScale.scale = Qt.vector3d(f, transformScale.scale.y, transformScale.scale.z); }
+ onNext: { updateMe(); focus = false; scaleY.focus = true; }
+ onPrev: { updateMe(); focus = false; rotZ.focus = true; }
+ onFail: { imageS.bounce=true; }
+ onChanged: { properties.changed(); }
+ }
+ BlenderValueSlider {
+ id: scaleY
+ label: "Y:"
+ locked: imageS.isLocked
+ min: 0; limitMin: true
+ value: transformScale.scale.y.toFixed(3)
+ function update (f) { transformScale.scale = Qt.vector3d(transformScale.scale.x, f, transformScale.scale.z); }
+ onNext: { updateMe(); focus = false; scaleZ.focus = true; }
+ onPrev: { updateMe(); focus = false; scaleX.focus = true; }
+ onFail: { imageS.bounce=true; }
+ onChanged: { properties.changed(); }
+ }
+ BlenderValueSlider {
+ id: scaleZ
+ label: "Z:"
+ locked: imageS.isLocked
+ min: 0; limitMin: true
+ value: transformScale.scale.z.toFixed(3)
+ function update (f) { transformScale.scale = Qt.vector3d(transformScale.scale.x, transformScale.scale.y, f); }
+ onNext: { updateMe(); focus = false; posX.focus = true; }
+ onPrev: { updateMe(); focus = false; scaleY.focus = true; }
+ onFail: { imageS.bounce=true; }
+ onChanged: { properties.changed(); }
+ }
}
- // SCALE
- Item {
- id: scalePanel
- width: parent.width
- height: imageS.height
- property bool dirty: false
-
- Text {
- anchors.left: parent.left
- anchors.leftMargin: 8
- text: "Scale";
- color: "#FFFFFF"
+ // Material, Effect
+ Column {
+ width: 150
+ spacing: 5
+ CheckBox {
+ id: fromMesh
+ width: parent.width
+ text: "From Mesh"
+ checked: true
+ onClicked: {
+ useCustomEffect = !checked;
+ if (checked) {
+ // A horrible hack to reload the default mesh material
+ // TODO: Find a better way of doing this (i.e. no runtime errors)
+ source_mesh.source = "";
+ source_mesh.source = targetMesh;
+ }
+ }
}
- Image {
- id: imageS
- anchors.right: parent.right
- anchors.rightMargin: 8
-
- //Animation to pulse the lock icon if attempting to modify while locked.
- property bool bounce: false
-
- SequentialAnimation on scale{
- running: imageS.bounce
- NumberAnimation { to : 2.0; duration: 150; easing.type: "OutQuad" }
- NumberAnimation { to : 1.0; duration: 150; easing.type: "OutQuad" }
- NumberAnimation { to : 2.0; duration: 150; easing.type: "OutQuad" }
- NumberAnimation { to : 1.0; duration: 150; easing.type: "OutQuad" }
- onCompleted: imageS.bounce = false
+
+ Column {
+ enabled: !fromMesh.checked
+ opacity: enabled ? 1.0: 0.5
+ width: parent.width; spacing: 5
+
+ move: Transition {
+ NumberAnimation {
+ properties: "y"
+ easing.type: Easing.InOutQuad;
+ duration: 150
+ }
+ }
+
+ Behavior on opacity {
+ NumberAnimation { easing.type: Easing.InOutQuad; duration: 100 }
+ }
+
+ CheckBox {
+ width: parent.width
+ text: "Decal"
+ checked: false
+ onClicked: {
+ modelEffect.decal = checked
+ }
+ }
+
+ Item {
+ width: parent.width
+ height: colorText.height
+ Text {
+ id: colorText
+ anchors.left: parent.left
+ anchors.leftMargin: 8
+ text: "Color";
+ color: "#FFFFFF"
+ font.bold: true
+ }
+ }
+
+ CheckBox {
+ id: simpleColor
+ width: parent.width
+ text: "Simple"
+ checked: true
+ onClicked: {
+ useCustomMaterial = !checked;
+ }
+ }
+
+ ColorWidget {
+ id: flat
+ visible: opacity != 0
+ opacity: simpleColor.checked
+ width: parent.width; height: 16
+ targetColor: modelEffect.hsv
+ text: "Flat Color"
+ Behavior on opacity {
+ NumberAnimation { easing.type: Easing.InOutQuad; duration: 100 }
+ }
+ }
+
+ ColorWidget {
+ id: ambient
+ visible: opacity != 0
+ opacity: !flat.visible
+ width: parent.width; height: 16
+ targetColor: modelMaterial.amb_hsv
+ text: "Ambient Color"
+ Behavior on opacity {
+ NumberAnimation { easing.type: Easing.InOutQuad; duration: 100 }
+ }
+ }
+
+ ColorWidget {
+ id: diffuse
+ visible: opacity != 0
+ opacity: !flat.visible
+ width: parent.width; height: 16
+ targetColor: modelMaterial.dif_hsv
+ text: "Diffuse Color"
+ Behavior on opacity {
+ NumberAnimation { easing.type: Easing.InOutQuad; duration: 100 }
+ }
+ }
+
+ ColorWidget {
+ id: specular
+ visible: opacity != 0
+ opacity: !flat.visible
+ width: parent.width; height: 16
+ targetColor: modelMaterial.spec_hsv
+ text: "Specular Color"
+ Behavior on opacity {
+ NumberAnimation { easing.type: Easing.InOutQuad; duration: 100 }
+ }
+ }
+
+ Item { width: parent.width; height: 5 }
+
+ Item {
+ visible: opacity != 0
+ opacity: !flat.visible
+ height: shineText.height + shinyValue.height + 5
+ width: parent.width
+
+ Behavior on opacity {
+ NumberAnimation { easing.type: Easing.InOutQuad; duration: 100 }
+ }
+
+ Text {
+ id: shineText
+ text: "Shininess:"
+ color: "white"
+ }
+ InputBox {
+ anchors.right: parent.right
+ width: parent.width - shineText.width - 5
+ height: shineText.height
+ input.text: modelMaterial.shininess
+ }
+ Rectangle {
+ width: parent.width - 8; height: 1
+ anchors.centerIn: shinyValue
+ color: "gray"
+ }
+
+ SliderHandle {
+ id: shinyValue
+ width: parent.width; height: 10
+ anchors { top: shineText.bottom; topMargin: 5 }
+ horizontal: true
+ onValueChanged: {
+ modelMaterial.shininess = Math.round(value * 128)
+ }
+ }
+ }
+
+ Item { width: parent.width; height: 5 }
+
+ Item {
+ width: parent.width
+ height: textureText.height
+ Text {
+ id: textureText
+ anchors.left: parent.left
+ anchors.leftMargin: 8
+ text: "Texture";
+ color: "#FFFFFF"
+ font.bold: true
+ }
}
- //Manage locked/unlocked state
- state: "UNLOCKED"
- property bool isLocked: false
-
- states: [
- State {
- name: "UNLOCKED"
- PropertyChanges { target: imageS; source: "images/unlock.png"}
- PropertyChanges { target: imageS; isLocked: false;}
- },
- State {
- name: "LOCKED"
- PropertyChanges { target: imageS; source: "images/lock.png"}
- PropertyChanges { target: imageS; isLocked: true;}
+ Item {
+ width: parent.width
+ height: texturePreview.height
+ Image {
+ id: texturePreview
+ width: 60; height: width
+ source: textureFile.filename
}
- ]
-
- MouseArea {
- anchors.fill: parent
- onDoubleClicked: {
- if (parent.state=="LOCKED")
- parent.state="UNLOCKED"
- else
- parent.state="LOCKED"
+ Rectangle {
+ anchors.fill: texturePreview
+ border.color: "white"
+ border.width: 1
+ color: "transparent"
+ }
+
+ BlenderToggle {
+ width: 60; height: 20
+ anchors.right: parent.right
+ buttonText: "Open..."
+ onClicked: {
+ textureFile.load();
+ }
}
}
}
}
- BlenderValueSlider {
- id: scaleX
- label: "X:"
- locked: imageS.isLocked
- min: 0; limitMin: true
- value: transformScale.scale.x.toFixed(3)
- function update (f) { transformScale.scale = Qt.vector3d(f, transformScale.scale.y, transformScale.scale.z); }
- onNext: { updateMe(); focus = false; scaleY.focus = true; }
- onPrev: { updateMe(); focus = false; rotZ.focus = true; }
- onFail: { imageS.bounce=true; }
- onChanged: { properties.changed(); }
- }
- BlenderValueSlider {
- id: scaleY
- label: "Y:"
- locked: imageS.isLocked
- min: 0; limitMin: true
- value: transformScale.scale.y.toFixed(3)
- function update (f) { transformScale.scale = Qt.vector3d(transformScale.scale.x, f, transformScale.scale.z); }
- onNext: { updateMe(); focus = false; scaleZ.focus = true; }
- onPrev: { updateMe(); focus = false; scaleX.focus = true; }
- onFail: { imageS.bounce=true; }
- onChanged: { properties.changed(); }
- }
- BlenderValueSlider {
- id: scaleZ
- label: "Z:"
- locked: imageS.isLocked
- min: 0; limitMin: true
- value: transformScale.scale.z.toFixed(3)
- function update (f) { transformScale.scale = Qt.vector3d(transformScale.scale.x, transformScale.scale.y, f); }
- onNext: { updateMe(); focus = false; posX.focus = true; }
- onPrev: { updateMe(); focus = false; scaleY.focus = true; }
- onFail: { imageS.bounce=true; }
- onChanged: { properties.changed(); }
- }
}
diff --git a/util/qt3d/modeltweak/qml/ModelTweak.qml b/util/qt3d/modeltweak/qml/ModelTweak.qml
index 001ad4a3..57766e86 100644
--- a/util/qt3d/modeltweak/qml/ModelTweak.qml
+++ b/util/qt3d/modeltweak/qml/ModelTweak.qml
@@ -42,11 +42,17 @@ import QtQuick 1.0
import Qt3D 1.0
import ModelTweak 1.0
import "fileHandling.js" as FileHandler
+import "Widgets"
+import "ColorUtils.js" as ColorUtils
Rectangle {
id: outerWindow;
width: 1024
height: 768
+ property alias modelEffect: customEffect
+ property alias modelMaterial: customMaterial
+ property bool useCustomEffect: false
+ property bool useCustomMaterial: false
property bool changed: false
Component.onCompleted: {
@@ -95,6 +101,11 @@ Rectangle {
filename: "meshes/penguin.3ds"
}
+ QuickFile {
+ id: textureFile
+ filename: ""
+ }
+
Mesh {
id: source_mesh
source: quickFile.filename
@@ -106,6 +117,30 @@ Rectangle {
Rotation3D { id: transformRotateZ; axis: Qt.vector3d(0, 0, 1); angle: 0; }
Scale3D { id: transformScale; scale: Qt.vector3d(1, 1, 1); }
+ Effect {
+ id: customEffect;
+ property alias hsv: hsvColor
+ material: useCustomMaterial ? customMaterial : null;
+ color: hsv.color
+ blending: (hsv.alpha < 1.0)
+ || (useCustomMaterial && (hsvAmbColor.alpha*hsvDifColor.alpha*hsvSpecColor.alpha < 1.0))
+ texture: textureFile.filename
+ }
+ Material {
+ id: customMaterial
+ property alias amb_hsv: hsvAmbColor
+ property alias dif_hsv: hsvDifColor
+ property alias spec_hsv: hsvSpecColor
+ ambientColor: hsvAmbColor.color
+ diffuseColor: hsvDifColor.color
+ specularColor: hsvSpecColor.color
+ textureUrl: textureFile.filename
+ }
+ HSVColor { id: hsvColor }
+ HSVColor { id: hsvAmbColor }
+ HSVColor { id: hsvDifColor }
+ HSVColor { id: hsvSpecColor }
+
ModelViewport {
id: mvpZY
x: 0;
@@ -214,6 +249,11 @@ Rectangle {
onChanged: {outerWindow.changed=true}
}
+ ColorPicker {
+ id: colorPicker
+ visible: false
+ }
+
HelpOverlay {
id: helpOverlay
visible: false
diff --git a/util/qt3d/modeltweak/qml/ModelViewport.qml b/util/qt3d/modeltweak/qml/ModelViewport.qml
index c3b7712e..b5188d57 100644
--- a/util/qt3d/modeltweak/qml/ModelViewport.qml
+++ b/util/qt3d/modeltweak/qml/ModelViewport.qml
@@ -80,6 +80,7 @@ Rectangle {
transformRotateZ,
transformTranslate,
]
+ effect: useCustomEffect ? modelEffect : null;
}
Effect {
diff --git a/util/qt3d/modeltweak/qml/Widgets/BlenderToggle.qml b/util/qt3d/modeltweak/qml/Widgets/BlenderToggle.qml
index 7e397636..aa220c36 100644
--- a/util/qt3d/modeltweak/qml/Widgets/BlenderToggle.qml
+++ b/util/qt3d/modeltweak/qml/Widgets/BlenderToggle.qml
@@ -13,6 +13,7 @@ Rectangle {
property alias buttonText: text.text
property alias imageSrc: img.source
+ property alias textColor: text.color
signal clicked
diff --git a/util/qt3d/modeltweak/qml/Widgets/Checkered.qml b/util/qt3d/modeltweak/qml/Widgets/Checkered.qml
new file mode 100644
index 00000000..49bf1d82
--- /dev/null
+++ b/util/qt3d/modeltweak/qml/Widgets/Checkered.qml
@@ -0,0 +1,27 @@
+import QtQuick 1.0
+
+Grid {
+ property variant color1: "#FFFFFF"
+ property variant color2: "#BBBBBB"
+ property variant cellSize: 10
+ width: 20
+ height: parent.height
+ clip: true
+
+ rows: height/cellSize
+ columns: width/cellSize
+ Repeater {
+ model: parent.rows * parent.columns
+ Rectangle {
+ width: cellSize; height: cellSize;
+ color: {
+ var check;
+ if (columns%2) check = index;
+ else check = Math.floor(index/columns)%2 + index;
+
+ if (check%2) return color1;
+ else return color2;
+ }
+ }
+ }
+}
diff --git a/util/qt3d/modeltweak/qml/Widgets/ColorSelector.qml b/util/qt3d/modeltweak/qml/Widgets/ColorSelector.qml
new file mode 100644
index 00000000..a55a743f
--- /dev/null
+++ b/util/qt3d/modeltweak/qml/Widgets/ColorSelector.qml
@@ -0,0 +1,72 @@
+import QtQuick 1.0
+
+Item {
+ id: select
+ property real sat: 1.0
+ property real val: 1.0
+ width: parent.width
+ height: parent.height
+
+ Binding {
+ target: handle; property: "x"
+ value: select.sat * select.width
+ }
+ Binding {
+ target: select; property: "sat"
+ value: handle.x/width
+ }
+
+ Binding {
+ target: handle; property: "y"
+ value: (1.0 - select.val) * select.height
+ }
+ Binding {
+ target: select; property: "val"
+ value: 1.0 - handle.y/height
+ }
+
+ Item {
+ id: handle
+ width: 20
+ height: width
+ x: 0.0; y: 0.0
+
+ Rectangle {
+ x: -width/2
+ y: x
+ width: parent.width-2
+ height: width
+ radius: width/2
+
+ border.color: "white"
+ color: "transparent"
+ }
+ Rectangle {
+ x: -width/2
+ y: x
+ width: parent.width
+ height: width
+ radius: width/2
+
+ border.width: 2
+ border.color: "black"
+ color: "transparent"
+ }
+ }
+
+ MouseArea {
+ anchors.fill: parent
+ function mouseEvent(mouse) {
+ if (mouse.buttons & Qt.LeftButton) {
+ handle.x = Math.max(0, Math.min(height, mouse.x))
+ handle.y = Math.max(0, Math.min(height, mouse.y))
+ }
+ }
+ onPressed: mouseEvent(mouse);
+ onPositionChanged: mouseEvent(mouse);
+ hoverEnabled: true
+ onEntered: handle.opacity = 0.5;
+ onExited: { if (!pressed) handle.opacity = 1.0 }
+ onReleased: { if (!containsMouse) handle.opacity = 1.0 }
+ }
+}
diff --git a/util/qt3d/modeltweak/qml/Widgets/ColorWidget.qml b/util/qt3d/modeltweak/qml/Widgets/ColorWidget.qml
new file mode 100644
index 00000000..f60ff1b0
--- /dev/null
+++ b/util/qt3d/modeltweak/qml/Widgets/ColorWidget.qml
@@ -0,0 +1,37 @@
+import QtQuick 1.0
+
+Item {
+ id: colorWidget
+ width: parent.width; height: 16
+
+ property variant targetColor
+ property alias text: flatText.text
+
+ Rectangle {
+ height: 2
+ anchors {
+ left: parent.left; right: flatSet.right
+ bottom: parent.bottom
+ rightMargin: flatSet.width/2
+ }
+ color: colorWidget.targetColor.color
+ }
+ Text {
+ id: flatText
+ anchors { top: parent.top; left: parent.left }
+ text:"Color"
+ color: "white"
+ }
+ BlenderToggle {
+ id: flatSet
+ width: 32
+ anchors { right: parent.right }
+ height: parent.height
+ buttonText: "Set"
+ radius: 6
+ onClicked: {
+ colorPicker.setTarget(colorWidget.targetColor);
+ colorPicker.visible = true
+ }
+ }
+}
diff --git a/util/qt3d/modeltweak/qml/Widgets/HSVColor.qml b/util/qt3d/modeltweak/qml/Widgets/HSVColor.qml
new file mode 100644
index 00000000..9e137428
--- /dev/null
+++ b/util/qt3d/modeltweak/qml/Widgets/HSVColor.qml
@@ -0,0 +1,15 @@
+import QtQuick 1.0
+import "../ColorUtils.js" as ColorUtils
+
+Item {
+ property real hue: 0.0
+ property real sat: 0.0
+ property real val: 1.0
+ property real alpha: 1.0
+ property color color: ColorUtils.hsvToColor(hue, sat, val, alpha)
+ property int red: rgb[0]
+ property int green: rgb[1]
+ property int blue: rgb[2]
+
+ property variant rgb: ColorUtils.hsvToRgb(hue, sat, val)
+}
diff --git a/util/qt3d/modeltweak/qml/Widgets/InputBox.qml b/util/qt3d/modeltweak/qml/Widgets/InputBox.qml
new file mode 100644
index 00000000..d3d31837
--- /dev/null
+++ b/util/qt3d/modeltweak/qml/Widgets/InputBox.qml
@@ -0,0 +1,39 @@
+import QtQuick 1.0
+
+Item {
+ id: textInput
+ width: 60
+ height: 20
+ property alias label: lbl.text
+ property alias input: inputBox
+
+// Binding {
+// target: textInput; property: "value"
+// value: inputBox.text
+// }
+// Binding {
+// target: inputBox; property: "text"
+// value: { var result = textInput.value*100; return Math.round(result)/100 }
+// }
+
+ Text {
+ id: lbl
+ color: "lightgray"
+ anchors.left: parent.left
+ }
+
+ Rectangle {
+ border.color: "gray"
+ color: "transparent"
+ width: 40
+ height: inputBox.height
+ anchors.right: parent.right
+ TextInput {
+ id: inputBox
+ anchors { fill: parent; leftMargin: 5 }
+ color: "white"
+ text: { var result = textInput.value*100; return Math.round(result)/100 }
+ selectByMouse: true; readOnly: true
+ }
+ }
+}
diff --git a/util/qt3d/modeltweak/qml/Widgets/SliderHandle.qml b/util/qt3d/modeltweak/qml/Widgets/SliderHandle.qml
new file mode 100644
index 00000000..9f72cabc
--- /dev/null
+++ b/util/qt3d/modeltweak/qml/Widgets/SliderHandle.qml
@@ -0,0 +1,76 @@
+import QtQuick 1.0
+
+Item {
+ id: slider
+ width: parent.width
+ height: parent.height
+ property real value: 0.0
+ property bool inverted: false
+ property bool horizontal: false
+
+ signal changed;
+
+ Binding {
+ target: slider; property: "value"
+ value: {
+ var res;
+ var pos = horizontal ? handle.x : handle.y;
+ var delta = horizontal ? width-handle.width : height-handle.height;
+ res = pos/delta;
+ return inverted ? 1-res : res
+ }
+ }
+ Binding {
+ target: handle; property: "y"
+ value: {
+ var res = inverted ? 1 - slider.value : slider.value
+ if (!horizontal) return res*(height-handle.height);
+ }
+ }
+ Binding {
+ target: handle; property: "x"
+ value: {
+ var res = inverted ? 1 - slider.value : slider.value
+ if (horizontal) return res*(width-handle.width);
+ }
+ }
+
+ Rectangle {
+ id: handle
+ width: 8 + (horizontal ? 0 : parent.width)
+ height: 8 + (!horizontal ? 0 : parent.height)
+ anchors.horizontalCenter: horizontal ? undefined : parent.horizontalCenter
+ anchors.verticalCenter: !horizontal ? undefined : parent.verticalCenter
+ radius: 2
+ Behavior on opacity {
+ NumberAnimation { easing.type: Easing.InOutQuad; duration: 80 }
+ }
+ gradient: Gradient {
+ GradientStop { position: 0.0; color: "#FFFFFF" }
+ GradientStop { position: 1.0; color: "#FFFFFF" }
+ }
+ border.width: 1
+ border.color: "darkgray"
+ onXChanged: slider.changed()
+ onYChanged: slider.changed()
+ }
+
+ MouseArea {
+ id: mouseArea
+ anchors.fill: parent
+ function mouseEvent(mouse) {
+ if (mouse.buttons & Qt.LeftButton) {
+ if (horizontal)
+ handle.x = Math.max(0, Math.min(width-handle.width, mouse.x-handle.width/2))
+ else
+ handle.y = Math.max(0, Math.min(height-handle.height, mouse.y-handle.height/2));
+ }
+ }
+ onPressed: mouseEvent(mouse);
+ onPositionChanged: mouseEvent(mouse);
+ hoverEnabled: true
+ onEntered: handle.opacity = 0.5;
+ onExited: { if (!pressed) handle.opacity = 1.0 }
+ onReleased: { if (!containsMouse) handle.opacity = 1.0 }
+ }
+}
diff --git a/util/qt3d/modeltweak/qml/fileHandling.js b/util/qt3d/modeltweak/qml/fileHandling.js
index 9867a90f..3b8b7137 100644
--- a/util/qt3d/modeltweak/qml/fileHandling.js
+++ b/util/qt3d/modeltweak/qml/fileHandling.js
@@ -1,5 +1,30 @@
function save_qml(closePrompt) {
+ var effectData = "";
+ if (useCustomEffect) {
+ effectData +=
+ " effect: Effect {\n" +
+ " decal: " + customEffect.decal + "\n" +
+ " blending: " + customEffect.blending + "\n";
+
+ if (useCustomMaterial) {
+ effectData +=
+ " material: Material {\n" +
+ " ambientColor: \"" + modelMaterial.ambientColor + "\"\n" +
+ " diffuseColor: \"" + modelMaterial.diffuseColor + "\"\n" +
+ " specularColor: \"" + modelMaterial.specularColor + "\"\n" +
+ " shininess: " + modelMaterial.shininess + "\n" +
+ " textureUrl: \"" + modelMaterial.textureUrl + "\"\n" +
+ " }\n"
+ } else {
+ effectData +=
+ " color: \"" + modelEffect.color + "\"\n" +
+ " texture: \"" + modelEffect.texture + "\"\n"
+ }
+
+ effectData += " }\n"
+ }
+
var saveData =
"// --------| WARNING |--------!!\n" +
"// This is a generated file. Modifying the text or layout of \n" +
@@ -58,6 +83,7 @@ function save_qml(closePrompt) {
" transformRotateZ,\n" +
" transformTranslate,\n" +
" ]\n" +
+ effectData +
"}\n";
quickFile.filename = source_mesh.source