diff --git a/nymea-app/resources.qrc b/nymea-app/resources.qrc
index 520a053f..2c6da110 100644
--- a/nymea-app/resources.qrc
+++ b/nymea-app/resources.qrc
@@ -21,7 +21,7 @@
ui/connection/wifisetup/BoxInfoPage.qml
ui/components/NymeaHeader.qml
ui/components/HeaderButton.qml
- ui/components/ColorPicker.qml
+ ui/components/ColorPickerPre510.qml
ui/components/ColorIcon.qml
ui/components/ThinDivider.qml
ui/components/ThrottledSlider.qml
@@ -232,5 +232,8 @@
ui/components/NymeaItemDelegate.qml
ui/components/NymeaSwipeDelegate.qml
ui/customviews/GarageController.qml
+ ui/components/ColorPicker.qml
+ ui/utils/ActionQueue.qml
+ ui/components/ColorTemperaturePicker.qml
diff --git a/nymea-app/ui/Nymea.qml b/nymea-app/ui/Nymea.qml
index f016ac9f..f367f90a 100644
--- a/nymea-app/ui/Nymea.qml
+++ b/nymea-app/ui/Nymea.qml
@@ -55,6 +55,9 @@ ApplicationWindow {
property int margins: 16
property int bigMargins: 20
+
+ property int radius: 6
+
property int extraSmallFont: 10
property int smallFont: 13
property int mediumFont: 16
diff --git a/nymea-app/ui/components/BigTile.qml b/nymea-app/ui/components/BigTile.qml
index b66c13d2..4dd81bac 100644
--- a/nymea-app/ui/components/BigTile.qml
+++ b/nymea-app/ui/components/BigTile.qml
@@ -19,6 +19,37 @@ Item {
property alias bottomPadding: content.bottomPadding
signal clicked();
+ signal pressAndHold();
+
+ function wobble() {
+ wobbleAnimation.start();
+ }
+
+ transform: Translate { id: wobbleTransform }
+
+ SequentialAnimation {
+ id: wobbleAnimation
+
+ PropertyAnimation {
+ target: wobbleTransform
+ property: "x"
+ from: 0
+ to: 10
+ duration: 50
+ easing.type: Easing.OutCirc
+ }
+ PropertyAnimation {
+ target: wobbleTransform
+ property: "x"
+ from: 10
+ to: 0
+ duration: 400
+ easing.type: Easing.OutElastic
+ easing.amplitude: 2
+ easing.period: 0.4
+ }
+ }
+
Rectangle {
id: background
@@ -64,6 +95,7 @@ Item {
Layout.fillWidth: true
height: contentItem.implicitHeight
onClicked: root.clicked()
+ onPressAndHold: root.pressAndHold()
}
}
}
diff --git a/nymea-app/ui/components/BrightnessSlider.qml b/nymea-app/ui/components/BrightnessSlider.qml
index c8587ab8..cfc4f009 100644
--- a/nymea-app/ui/components/BrightnessSlider.qml
+++ b/nymea-app/ui/components/BrightnessSlider.qml
@@ -28,89 +28,81 @@
*
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
-import QtQuick 2.3
+import QtQuick 2.9
+import QtGraphicalEffects 1.0
+import Nymea 1.0
+import "../utils"
Item {
id: root
+ implicitWidth: orientation == Qt.Horizontal ? 300 : app.hugeIconSize
+ implicitHeight: orientation == Qt.Horizontal ? app.hugeIconSize : 300
- property int brightness: min
- property int min: 0
- property int max: 100
- property Component touchDelegate: Rectangle { height: root.height; width: 5; color: app.foregroundColor }
+ property Thing thing: null
- property bool active: true
- property bool pressed: mouseArea.pressed
+ readonly property StateType colorTemperatureStateType: root.thing.thingClass.stateTypes.findByName("brightness")
- signal moved(real brightness);
+ property int value: thing.stateByName("brightness").value
+
+ property int orientation: Qt.Horizontal
+
+ ActionQueue {
+ id: actionQueue
+ thing: root.thing
+ stateType: root.colorTemperatureStateType
+ }
Rectangle {
- height: parent.width
- width: parent.height
- anchors.centerIn: parent
- rotation: -90
- border.width: 1
- border.color: app.foregroundColor
+ id: clipRect
+ anchors.fill: parent
+ radius: app.radius
+ color: Qt.tint(app.backgroundColor, Qt.rgba(app.foregroundColor.r, app.foregroundColor.g, app.foregroundColor.b, 0.1))
+ }
+ LinearGradient {
+ anchors.fill: parent
+ anchors.rightMargin: root.orientation == Qt.Horizontal ?
+ parent.width - (dragHandle.x + dragHandle.width / 2)
+ : 0
+ anchors.topMargin: root.orientation == Qt.Vertical ?
+ dragHandle.y + dragHandle.height / 2
+ : 0
+ start: root.orientation == Qt.Horizontal ? Qt.point(0,0) : Qt.point(0, height)
+ end: root.orientation == Qt.Horizontal ? Qt.point(width, 0) : Qt.point(0, 0)
+ source: clipRect
gradient: Gradient {
- GradientStop { position: 0.0; color: Qt.rgba(0, 0, 0, .5) }
- GradientStop { position: 1.0; color: Qt.rgba(1, 1, 1, .5) }
+ GradientStop { position: 0.0; color: "transparent" }
+ GradientStop { position: 1.0; color: "#55ffffff" }
}
}
- Loader {
- id: touchDelegateLoader
- // 0 : width = min : max
- // x = (width * (brightness - min) / (max-min))
- property int position: (root.width * (root.brightness - root.min) / (root.max - root.min));
- x: item ? Math.max(0, Math.min(position - width * .5, parent.width - item.width)) : 0
- sourceComponent: root.touchDelegate
- visible: !mouseArea.pressed && root.active
- Behavior on x {
- enabled: !mouseArea.pressed
- NumberAnimation {}
- }
+ Rectangle {
+ id: dragHandle
+ x: root.orientation === Qt.Horizontal ?
+ (actionQueue.pendingValue || root.value) * (root.width - dragHandle.width) / 100
+ : 0
+ y: root.orientation === Qt.Vertical ?
+ root.height - dragHandle.height - ((actionQueue.pendingValue || root.value) * (root.height - dragHandle.height) / 100)
+ : 0
+ height: root.orientation === Qt.Horizontal ? parent.height : 8
+ width: root.orientation === Qt.Horizontal ? 8 : parent.width
+ radius: 4
+ color: app.foregroundColor
}
MouseArea {
- id: mouseArea
anchors.fill: parent
- preventStealing: true
-
- drag.minimumX: 0
- drag.maximumX: width - dndItem.width
- drag.minimumY: 0
- drag.maximumY: height - dndItem.height
-
- property var lastSentTime: new Date()
-
- onPressed: {
- dndItem.x = Math.min(width - dndItem.width, Math.max(0, mouseX - dndItem.width / 2))
- dndItem.y = 0;
- mouseArea.drag.target = dndItem;
- }
-
onPositionChanged: {
- root.brightness = Math.min(root.max, Math.max(root.min, (mouseX * (root.max - root.min) / width) + root.min))
-
- var currentTime = new Date();
- if (pressed && currentTime - lastSentTime > 200) {
- root.moved(root.brightness)
- lastSentTime = currentTime
+ var minCt = root.colorTemperatureStateType.minValue;
+ var maxCt = root.colorTemperatureStateType.maxValue
+ var ct;
+ if (root.orientation == Qt.Horizontal) {
+ ct = Math.min(maxCt, Math.max(minCt, (mouseX * (maxCt - minCt) / (width - dragHandle.width)) + minCt))
+ } else {
+ ct = Math.min(maxCt, Math.max(minCt, ((height - mouseY) * (maxCt - minCt) / (height - dragHandle.height)) + minCt))
}
+ actionQueue.sendValue(ct);
}
-
- onReleased: {
- root.brightness = Math.min(root.max, Math.max(root.min, (mouseX * (root.max - root.min) / width) + root.min))
- root.moved(root.brightness)
- mouseArea.drag.target = undefined;
- }
-
}
-
- Loader {
- id: dndItem
- sourceComponent: root.touchDelegate
- visible: mouseArea.pressed && root.active
- }
-
}
+
diff --git a/nymea-app/ui/components/ColorPicker.qml b/nymea-app/ui/components/ColorPicker.qml
index 0010dcb9..ebd4bc07 100644
--- a/nymea-app/ui/components/ColorPicker.qml
+++ b/nymea-app/ui/components/ColorPicker.qml
@@ -1,249 +1,126 @@
-/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
-*
-* Copyright 2013 - 2020, nymea GmbH
-* Contact: contact@nymea.io
-*
-* This file is part of nymea.
-* This project including source code and documentation is protected by
-* copyright law, and remains the property of nymea GmbH. All rights, including
-* reproduction, publication, editing and translation, are reserved. The use of
-* this project is subject to the terms of a license agreement to be concluded
-* with nymea GmbH in accordance with the terms of use of nymea GmbH, available
-* under https://nymea.io/license
-*
-* GNU General Public License Usage
-* Alternatively, this project may be redistributed and/or modified under the
-* terms of the GNU General Public License as published by the Free Software
-* Foundation, GNU version 3. This project is distributed in the hope that it
-* will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty
-* of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
-* Public License for more details.
-*
-* You should have received a copy of the GNU General Public License along with
-* this project. If not, see .
-*
-* For any further details and any questions please contact us under
-* contact@nymea.io or see our FAQ/Licensing Information on
-* https://nymea.io/license/faq
-*
-* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
-
-import QtQuick 2.5
+import QtQuick 2.9
+import QtGraphicalEffects 1.0
+import Nymea 1.0
+import "../utils"
Item {
id: root
- property color color: actionState
- property bool pressed: mouseArea.pressed
- property bool hovered: mouseArea.containsMouse
+ property Thing thing: null
- property bool active: true
-
- property Component touchDelegate: Rectangle {
- height: 15
- width: height
- radius: height / 2
- color: app.accentColor
-
-
- Rectangle {
- color: root.hovered || root.pressed ? "#11000000" : "transparent"
- anchors.centerIn: parent
- height: 30
- width: height
- radius: width / 2
- Behavior on color { ColorAnimation { duration: 200 } }
- }
+ ActionQueue {
+ id: actionQueue
+ thing: root.thing
+ stateType: thing.thingClass.stateTypes.findByName("color")
}
- function calculateXy(color) {
- if (!color.hasOwnProperty("r")) {
- // Qt 4.8's color doesn't have r,g,b properties
- var colorString = color.toString();
- color = new Object;
- color.r = 1.0 * parseInt("0x" + colorString.substring(1,3), 16) / 256;
- color.g = 1.0 * parseInt("0x" + colorString.substring(3,5), 16) / 256;
- color.b = 1.0 * parseInt("0x" + colorString.substring(5,7), 16) / 256;
- }
-
- var point = new Object;
- var brightness = Math.min(color.r, color.g, color.b);
- point.y = Math.round(root.height * brightness);
- var newColor = new Object;
- newColor.r = color.r - brightness;
- newColor.g = color.g - brightness;
- newColor.b = color.b - brightness;
-
- var sectionWidth = root.width / 6;
-
- var sections = [true, true, true];
- if (newColor.r > 0) {
- sections[1] = false;
- }
- if (newColor.g > 0) {
- sections[2] = false;
- }
- if (newColor.b > 0) {
- sections[0] = false;
- }
- if (sections[0]) {
- if (newColor.r > newColor.g) {
- point.x = sectionWidth * newColor.g;
- } else if (newColor.r == newColor.g) {
- point.x = sectionWidth
- } else {
- point.x = sectionWidth * 2 - newColor.r * sectionWidth;
- }
- } else if (sections[1]) {
- if (newColor.g > newColor.b) {
- point.x = sectionWidth * 2 + sectionWidth * newColor.b;
- } else if (newColor.g == newColor.b) {
- point.x = sectionWidth * 3;
- } else {
- point.x = sectionWidth * 4 - newColor.g * sectionWidth
- }
- } else {
- if (newColor.b > newColor.r) {
- point.x = sectionWidth * 4 + sectionWidth * newColor.r
- } else if (newColor.b == newColor.r) {
- point.x = sectionWidth * 5;
- } else {
- point.x = sectionWidth * 6 - newColor.b * sectionWidth;
- }
- }
- return point;
- }
-
- function calculateColor(x, y) {
- x = Math.min(Math.max(0, x), width - 1);
- y = Math.min(Math.max(0, y), height - 1);
- var color = root.color;
- var sectionWidth = root.width / 6;
- var section = Math.floor(x / sectionWidth)
- var sectionX = Math.floor(x % (sectionWidth - 0.00001)) // the - 0.00001 is to prevent a mismatch when rounding
- // sectionVal : 1.0 = sectionX : sectionWidth
- var sectionVal = (1.0 * sectionX / sectionWidth)
-
- // brightnessVal : 1.0 = mouseY : height
- var brightness = 1.0 * y / height
-
- switch (section) {
- case 0:
- // GradientStop { position: 0.0; color: "#ff0000" }
- color = Qt.rgba(1, sectionVal + brightness, brightness, 1)
- break;
- case 1:
- // GradientStop { position: 0.17; color: "#ffff00" }
- color = Qt.rgba(1 - sectionVal + brightness, 1, brightness, 1)
- break;
- case 2:
- // GradientStop { position: 0.33; color: "#00ff00" }
- color = Qt.rgba(brightness, 1, sectionVal + brightness, 1)
- break;
- case 3:
- // GradientStop { position: 0.5; color: "#00ffff" }
- color = Qt.rgba(brightness, 1 - sectionVal + brightness, 1, 1)
- break;
- case 4:
- // GradientStop { position: 0.66; color: "#0000ff" }
- color = Qt.rgba(sectionVal + brightness, brightness, 1, 1)
- break;
- case 5:
- // GradientStop { position: 0.83; color: "#ff00ff" }
- color = Qt.rgba(1, brightness, 1 - sectionVal + brightness, 1)
- break;
- }
- // print("got color", color.r, color.g, color.b)
- return color
- }
-
- Rectangle {
- height: parent.width
- width: parent.height
+ ConicalGradient {
+ id: gradient
anchors.centerIn: parent
- rotation: -90
-
- gradient: Gradient {
- GradientStop { position: 0.0; color: "#ff0000" }
- GradientStop { position: 0.17; color: "#ffff00" }
- GradientStop { position: 0.33; color: "#00ff00" }
- GradientStop { position: 0.5; color: "#00ffff" }
- GradientStop { position: 0.66; color: "#0000ff" }
- GradientStop { position: 0.83; color: "#ff00ff" }
- GradientStop { position: 1.0; color: "#ff0000" }
+ width: Math.min(parent.width, parent.height)
+ height: width
+ visible: false
+ gradient: Gradient{
+ id: g
+ GradientStop { position: 0.000; color: Qt.rgba(1, 0, 0, 1) }
+ GradientStop { position: 0.167; color: Qt.rgba(1, 1, 0, 1) }
+ GradientStop { position: 0.333; color: Qt.rgba(0, 1, 0, 1) }
+ GradientStop { position: 0.500; color: Qt.rgba(0, 1, 1, 1) }
+ GradientStop { position: 0.667; color: Qt.rgba(0, 0, 1, 1) }
+ GradientStop { position: 0.833; color: Qt.rgba(1, 0, 1, 1) }
+ GradientStop { position: 1.000; color: Qt.rgba(1, 0, 0, 1) }
}
}
Rectangle {
- anchors.fill: parent
- border.color: app.foregroundColor
- border.width: 1
- gradient: Gradient {
- GradientStop { position: 0.0; color: "transparent" }
- GradientStop { position: 1.0; color: "white" }
+ id: mask
+ anchors.fill: gradient
+ radius: width / 2
+ }
+ OpacityMask {
+ anchors.fill: gradient
+ source: gradient
+ maskSource: mask
+ }
+
+ RadialGradient {
+ anchors.fill: gradient
+ gradient: Gradient{
+ GradientStop { position: 0.05; color: Qt.rgba(1, 1, 1, 1) }
+ GradientStop { position: 0.10; color: Qt.rgba(1, 1, 1, .9) }
+ GradientStop { position: 0.20; color: Qt.rgba(1, 1, 1, .7) }
+ GradientStop { position: 0.30; color: Qt.rgba(1, 1, 1, .5) }
+ GradientStop { position: 0.40; color: Qt.rgba(1, 1, 1, .3) }
+ GradientStop { position: 0.50; color: "transparent" }
}
}
MouseArea {
id: mouseArea
anchors.fill: parent
- preventStealing: true
- hoverEnabled: true
-
- drag.minimumX: 0
- drag.maximumX: width - dndItem.width
- drag.minimumY: 0
- drag.maximumY: height - dndItem.height
-
- property variant draggedItem
- property variant draggedLight
-
- onPressed: {
- mouseArea.drag.target = dndItem;
- dndItem.x = Math.min(width - dndItem.width, Math.max(0, mouseX - dndItem.width / 2))
- dndItem.y = Math.min(height - dndItem.height, Math.max(0, mouseY - dndItem.height / 2))
- mouseArea.draggedItem = touchDelegateLoader;
- }
onPositionChanged: {
- if (mouseArea.draggedItem) {
- root.color = root.calculateColor(mouseX, mouseY);
- if (mouseArea.draggedLight) {
- mouseArea.draggedLight.color = root.calculateColor(mouseX, mouseY);
+
+ var angle = calculateAngle(mouseX, mouseY)
+ var position = angle / 360;
+
+ var stopBefore = null;
+ var stopAfter = null;
+ for (var i = 0; i < g.stops.length; i++) {
+ var stop = g.stops[i];
+ if (stop.position < position) {
+ stopBefore = stop;
+ continue
}
+ stopAfter = stop;
+ break;
}
+
+ var colorBefore = stopBefore.color
+ var colorAfter = stopAfter.color
+ // p : 1 = pis : (a - b)
+ var positionInStop = (position - stopBefore.position) / (stopAfter.position - stopBefore.position);
+
+ var dr = stopAfter.color.r - stopBefore.color.r;
+ var dg = stopAfter.color.g - stopBefore.color.g;
+ var db = stopAfter.color.b - stopBefore.color.b;
+
+ var distanceFromCenter = calculateDistance(mouseX, mouseY)
+
+ // Reduce width a bit to keep outside circle for full color intensity
+ var positionFromCenter = Math.min(distanceFromCenter / (width * 0.9 / 2), 1)
+ // Invert it, The further we're away, the less impact this should have
+ positionFromCenter = 1 - positionFromCenter;
+ print("pos", positionFromCenter)
+
+ var color = Qt.rgba((stopBefore.color.r + dr * positionInStop) + positionFromCenter,
+ (stopBefore.color.g + dg * positionInStop) + positionFromCenter,
+ (stopBefore.color.b + db * positionInStop) + positionFromCenter,
+ 1)
+
+ actionQueue.sendValue(color);
}
- onReleased: {
- if (mouseArea.draggedItem) {
- root.color = root.calculateColor(mouseX, mouseY);
- if (mouseArea.draggedLight) {
- mouseArea.draggedLight.color = root.calculateColor(mouseX, mouseY);
- }
- }
- mouseArea.draggedItem = undefined;
- mouseArea.draggedLight = undefined;
- mouseArea.drag.target = undefined;
+ function calculateAngle(mouseX, mouseY) {
+ // transform coords to center of dial
+ mouseX -= mouseArea.width / 2
+ mouseY -= mouseArea.height / 2
+ var rad = Math.atan(mouseY / mouseX);
+ var angle = rad * 180 / Math.PI
+
+ angle += 90;
+
+ if (mouseX < 0 && mouseY >= 0) angle = 180 + angle;
+ if (mouseX < 0 && mouseY < 0) angle = 180 + angle;
+
+ return angle;
}
- }
+ function calculateDistance(mouseX, mouseY) {
+ mouseX -= mouseArea.width / 2
+ mouseY -= mouseArea.height / 2
- Loader {
- id: touchDelegateLoader
- property variant point: calculateXy(root.color);
- x: item ? Math.max(0, Math.min(point.x - width * .5, parent.width - item.width)) : 0
- y: item ? Math.max(0, Math.min(point.y - height * .5, parent.height - item.height)) : 0
- sourceComponent: root.touchDelegate
- visible: mouseArea.draggedItem !== touchDelegateLoader && root.active
- // Behavior on x {
- // enabled: !mouseArea.pressed
- // NumberAnimation {}
- // }
- }
-
- Loader {
- id: dndItem
- sourceComponent: root.touchDelegate
- visible: mouseArea.draggedItem !== undefined && root.active
+ return Math.abs(Math.sqrt(Math.pow(mouseX, 2) + Math.pow(mouseY, 2)))
+ }
}
}
diff --git a/nymea-app/ui/components/ColorPickerCt.qml b/nymea-app/ui/components/ColorPickerCt.qml
index bdd59609..1f3ea0d9 100644
--- a/nymea-app/ui/components/ColorPickerCt.qml
+++ b/nymea-app/ui/components/ColorPickerCt.qml
@@ -102,5 +102,4 @@ Item {
sourceComponent: root.touchDelegate
visible: mouseArea.pressed && root.active
}
-
}
diff --git a/nymea-app/ui/components/ColorPickerPre510.qml b/nymea-app/ui/components/ColorPickerPre510.qml
new file mode 100644
index 00000000..0010dcb9
--- /dev/null
+++ b/nymea-app/ui/components/ColorPickerPre510.qml
@@ -0,0 +1,249 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+*
+* Copyright 2013 - 2020, nymea GmbH
+* Contact: contact@nymea.io
+*
+* This file is part of nymea.
+* This project including source code and documentation is protected by
+* copyright law, and remains the property of nymea GmbH. All rights, including
+* reproduction, publication, editing and translation, are reserved. The use of
+* this project is subject to the terms of a license agreement to be concluded
+* with nymea GmbH in accordance with the terms of use of nymea GmbH, available
+* under https://nymea.io/license
+*
+* GNU General Public License Usage
+* Alternatively, this project may be redistributed and/or modified under the
+* terms of the GNU General Public License as published by the Free Software
+* Foundation, GNU version 3. This project is distributed in the hope that it
+* will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty
+* of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
+* Public License for more details.
+*
+* You should have received a copy of the GNU General Public License along with
+* this project. If not, see .
+*
+* For any further details and any questions please contact us under
+* contact@nymea.io or see our FAQ/Licensing Information on
+* https://nymea.io/license/faq
+*
+* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+import QtQuick 2.5
+
+Item {
+ id: root
+
+ property color color: actionState
+ property bool pressed: mouseArea.pressed
+ property bool hovered: mouseArea.containsMouse
+
+ property bool active: true
+
+ property Component touchDelegate: Rectangle {
+ height: 15
+ width: height
+ radius: height / 2
+ color: app.accentColor
+
+
+ Rectangle {
+ color: root.hovered || root.pressed ? "#11000000" : "transparent"
+ anchors.centerIn: parent
+ height: 30
+ width: height
+ radius: width / 2
+ Behavior on color { ColorAnimation { duration: 200 } }
+ }
+ }
+
+ function calculateXy(color) {
+ if (!color.hasOwnProperty("r")) {
+ // Qt 4.8's color doesn't have r,g,b properties
+ var colorString = color.toString();
+ color = new Object;
+ color.r = 1.0 * parseInt("0x" + colorString.substring(1,3), 16) / 256;
+ color.g = 1.0 * parseInt("0x" + colorString.substring(3,5), 16) / 256;
+ color.b = 1.0 * parseInt("0x" + colorString.substring(5,7), 16) / 256;
+ }
+
+ var point = new Object;
+ var brightness = Math.min(color.r, color.g, color.b);
+ point.y = Math.round(root.height * brightness);
+ var newColor = new Object;
+ newColor.r = color.r - brightness;
+ newColor.g = color.g - brightness;
+ newColor.b = color.b - brightness;
+
+ var sectionWidth = root.width / 6;
+
+ var sections = [true, true, true];
+ if (newColor.r > 0) {
+ sections[1] = false;
+ }
+ if (newColor.g > 0) {
+ sections[2] = false;
+ }
+ if (newColor.b > 0) {
+ sections[0] = false;
+ }
+ if (sections[0]) {
+ if (newColor.r > newColor.g) {
+ point.x = sectionWidth * newColor.g;
+ } else if (newColor.r == newColor.g) {
+ point.x = sectionWidth
+ } else {
+ point.x = sectionWidth * 2 - newColor.r * sectionWidth;
+ }
+ } else if (sections[1]) {
+ if (newColor.g > newColor.b) {
+ point.x = sectionWidth * 2 + sectionWidth * newColor.b;
+ } else if (newColor.g == newColor.b) {
+ point.x = sectionWidth * 3;
+ } else {
+ point.x = sectionWidth * 4 - newColor.g * sectionWidth
+ }
+ } else {
+ if (newColor.b > newColor.r) {
+ point.x = sectionWidth * 4 + sectionWidth * newColor.r
+ } else if (newColor.b == newColor.r) {
+ point.x = sectionWidth * 5;
+ } else {
+ point.x = sectionWidth * 6 - newColor.b * sectionWidth;
+ }
+ }
+ return point;
+ }
+
+ function calculateColor(x, y) {
+ x = Math.min(Math.max(0, x), width - 1);
+ y = Math.min(Math.max(0, y), height - 1);
+ var color = root.color;
+ var sectionWidth = root.width / 6;
+ var section = Math.floor(x / sectionWidth)
+ var sectionX = Math.floor(x % (sectionWidth - 0.00001)) // the - 0.00001 is to prevent a mismatch when rounding
+ // sectionVal : 1.0 = sectionX : sectionWidth
+ var sectionVal = (1.0 * sectionX / sectionWidth)
+
+ // brightnessVal : 1.0 = mouseY : height
+ var brightness = 1.0 * y / height
+
+ switch (section) {
+ case 0:
+ // GradientStop { position: 0.0; color: "#ff0000" }
+ color = Qt.rgba(1, sectionVal + brightness, brightness, 1)
+ break;
+ case 1:
+ // GradientStop { position: 0.17; color: "#ffff00" }
+ color = Qt.rgba(1 - sectionVal + brightness, 1, brightness, 1)
+ break;
+ case 2:
+ // GradientStop { position: 0.33; color: "#00ff00" }
+ color = Qt.rgba(brightness, 1, sectionVal + brightness, 1)
+ break;
+ case 3:
+ // GradientStop { position: 0.5; color: "#00ffff" }
+ color = Qt.rgba(brightness, 1 - sectionVal + brightness, 1, 1)
+ break;
+ case 4:
+ // GradientStop { position: 0.66; color: "#0000ff" }
+ color = Qt.rgba(sectionVal + brightness, brightness, 1, 1)
+ break;
+ case 5:
+ // GradientStop { position: 0.83; color: "#ff00ff" }
+ color = Qt.rgba(1, brightness, 1 - sectionVal + brightness, 1)
+ break;
+ }
+ // print("got color", color.r, color.g, color.b)
+ return color
+ }
+
+ Rectangle {
+ height: parent.width
+ width: parent.height
+ anchors.centerIn: parent
+ rotation: -90
+
+ gradient: Gradient {
+ GradientStop { position: 0.0; color: "#ff0000" }
+ GradientStop { position: 0.17; color: "#ffff00" }
+ GradientStop { position: 0.33; color: "#00ff00" }
+ GradientStop { position: 0.5; color: "#00ffff" }
+ GradientStop { position: 0.66; color: "#0000ff" }
+ GradientStop { position: 0.83; color: "#ff00ff" }
+ GradientStop { position: 1.0; color: "#ff0000" }
+ }
+ }
+
+ Rectangle {
+ anchors.fill: parent
+ border.color: app.foregroundColor
+ border.width: 1
+ gradient: Gradient {
+ GradientStop { position: 0.0; color: "transparent" }
+ GradientStop { position: 1.0; color: "white" }
+ }
+ }
+
+ MouseArea {
+ id: mouseArea
+ anchors.fill: parent
+ preventStealing: true
+ hoverEnabled: true
+
+ drag.minimumX: 0
+ drag.maximumX: width - dndItem.width
+ drag.minimumY: 0
+ drag.maximumY: height - dndItem.height
+
+ property variant draggedItem
+ property variant draggedLight
+
+ onPressed: {
+ mouseArea.drag.target = dndItem;
+ dndItem.x = Math.min(width - dndItem.width, Math.max(0, mouseX - dndItem.width / 2))
+ dndItem.y = Math.min(height - dndItem.height, Math.max(0, mouseY - dndItem.height / 2))
+ mouseArea.draggedItem = touchDelegateLoader;
+ }
+ onPositionChanged: {
+ if (mouseArea.draggedItem) {
+ root.color = root.calculateColor(mouseX, mouseY);
+ if (mouseArea.draggedLight) {
+ mouseArea.draggedLight.color = root.calculateColor(mouseX, mouseY);
+ }
+ }
+ }
+
+ onReleased: {
+ if (mouseArea.draggedItem) {
+ root.color = root.calculateColor(mouseX, mouseY);
+ if (mouseArea.draggedLight) {
+ mouseArea.draggedLight.color = root.calculateColor(mouseX, mouseY);
+ }
+ }
+ mouseArea.draggedItem = undefined;
+ mouseArea.draggedLight = undefined;
+ mouseArea.drag.target = undefined;
+
+ }
+
+ }
+
+ Loader {
+ id: touchDelegateLoader
+ property variant point: calculateXy(root.color);
+ x: item ? Math.max(0, Math.min(point.x - width * .5, parent.width - item.width)) : 0
+ y: item ? Math.max(0, Math.min(point.y - height * .5, parent.height - item.height)) : 0
+ sourceComponent: root.touchDelegate
+ visible: mouseArea.draggedItem !== touchDelegateLoader && root.active
+ // Behavior on x {
+ // enabled: !mouseArea.pressed
+ // NumberAnimation {}
+ // }
+ }
+
+ Loader {
+ id: dndItem
+ sourceComponent: root.touchDelegate
+ visible: mouseArea.draggedItem !== undefined && root.active
+ }
+}
diff --git a/nymea-app/ui/components/ColorTemperaturePicker.qml b/nymea-app/ui/components/ColorTemperaturePicker.qml
new file mode 100644
index 00000000..ec133b34
--- /dev/null
+++ b/nymea-app/ui/components/ColorTemperaturePicker.qml
@@ -0,0 +1,69 @@
+import QtQuick 2.9
+import QtGraphicalEffects 1.0
+import Nymea 1.0
+import "../utils"
+
+Item {
+ id: root
+ implicitWidth: orientation == Qt.Horizontal ? 300 : app.hugeIconSize
+ implicitHeight: orientation == Qt.Horizontal ? app.hugeIconSize : 300
+
+ property Thing thing: null
+
+ property int orientation: Qt.Horizontal
+
+ readonly property StateType colorTemperatureStateType: root.thing.thingClass.stateTypes.findByName("colorTemperature")
+
+ property int value: thing.stateByName("colorTemperature").value
+
+ ActionQueue {
+ id: actionQueue
+ thing: root.thing
+ stateType: root.colorTemperatureStateType
+ }
+
+ Rectangle {
+ id: clipRect
+ anchors.fill: parent
+ radius: app.radius
+ }
+
+ LinearGradient {
+ anchors.fill: parent
+ start: root.orientation == Qt.Horizontal ? Qt.point(0, 0) : Qt.point(0, height)
+ end: root.orientation == Qt.Horizontal ? Qt.point(width, 0) : Qt.point(0, 0)
+ source: clipRect
+ gradient: Gradient {
+ GradientStop { position: 0.0; color: "#dfffff" }
+ GradientStop { position: 0.5; color: "#ffffea" }
+ GradientStop { position: 1.0; color: "#ffd649" }
+ }
+ }
+
+ Rectangle {
+ id: dragHandle
+ property double valuePercentage: ((actionQueue.pendingValue || root.value) - root.colorTemperatureStateType.minValue) / (root.colorTemperatureStateType.maxValue - root.colorTemperatureStateType.minValue)
+ x: orientation == Qt.Horizontal ? valuePercentage * (root.width - dragHandle.width) : 0
+ y: root.orientation === Qt.Vertical ? root.height - dragHandle.height - (valuePercentage * (root.height - dragHandle.height)) : 0
+ height: root.orientation == Qt.Horizontal ? parent.height : 8
+ width: root.orientation == Qt.Horizontal ? 8 : parent.width
+ radius: 4
+ color: Qt.tint(app.backgroundColor, Qt.rgba(app.foregroundColor.r, app.foregroundColor.g, app.foregroundColor.b, 0.5))
+ }
+
+ MouseArea {
+ anchors.fill: parent
+ onPositionChanged: {
+ var minCt = root.colorTemperatureStateType.minValue;
+ var maxCt = root.colorTemperatureStateType.maxValue
+ var ct;
+ if (root.orientation == Qt.Horizontal) {
+ ct = Math.min(maxCt, Math.max(minCt, (mouseX * (maxCt - minCt) / (width - dragHandle.width)) + minCt))
+ } else {
+ ct = Math.min(maxCt, Math.max(minCt, ((height - mouseY) * (maxCt - minCt) / (height - dragHandle.height)) + minCt))
+ }
+ actionQueue.sendValue(ct);
+ }
+ }
+}
+
diff --git a/nymea-app/ui/delegates/ParamDelegate.qml b/nymea-app/ui/delegates/ParamDelegate.qml
index 5fe0cf74..846a01f9 100644
--- a/nymea-app/ui/delegates/ParamDelegate.qml
+++ b/nymea-app/ui/delegates/ParamDelegate.qml
@@ -280,7 +280,7 @@ ItemDelegate {
Component {
id: colorPickerComponent
- ColorPicker {
+ ColorPickerPre510 {
id: colorPicker
implicitHeight: 200
// color: root.param.value
diff --git a/nymea-app/ui/delegates/statedelegates/ColorDelegate.qml b/nymea-app/ui/delegates/statedelegates/ColorDelegate.qml
index a68e7bf4..010166d2 100644
--- a/nymea-app/ui/delegates/statedelegates/ColorDelegate.qml
+++ b/nymea-app/ui/delegates/statedelegates/ColorDelegate.qml
@@ -81,7 +81,7 @@ Item {
padding: app.margins
property var colorValue
property int preferredY: 0
- contentItem: ColorPicker {
+ contentItem: ColorPickerPre510 {
color: colorPickerDialog.colorValue
property var lastSentTime: new Date()
onColorChanged: {
diff --git a/nymea-app/ui/devicelistpages/LightsDeviceListPage.qml b/nymea-app/ui/devicelistpages/LightsDeviceListPage.qml
index 22ca1f05..397371c6 100644
--- a/nymea-app/ui/devicelistpages/LightsDeviceListPage.qml
+++ b/nymea-app/ui/devicelistpages/LightsDeviceListPage.qml
@@ -29,12 +29,13 @@
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
import QtQuick 2.5
-import QtQuick.Controls 2.1
-import QtQuick.Controls.Material 2.1
+import QtQuick.Controls 2.2
+import QtQuick.Controls.Material 2.2
import QtQuick.Layouts 1.1
import QtGraphicalEffects 1.0
import Nymea 1.0
import "../components"
+import "../utils"
DeviceListPageBase {
id: root
@@ -95,50 +96,37 @@ DeviceListPageBase {
bottomPadding: 0
leftPadding: 0
rightPadding: 0
- enabled: connectedState == null || connectedState.value === true
property State connectedState: thing.stateByName("connected")
property State powerState: thing.stateByName("power")
property State brightnessState: thing.stateByName("brightness")
property State colorState: thing.stateByName("color")
- onClicked: root.enterPage(index)
+ property bool tileColored: enabled && colorState && powerState.value === true
+ property bool colorInverted: tileColored && NymeaUtils.isDark(app.foregroundColor) === NymeaUtils.isDark(colorState.value)
+ property bool isConnected: connectedState && connectedState.value === true
- property int pendingCommand: -1
- property var pendingValue: null
- function adjustBrightness(value) {
- if (pendingCommand != -1) {
- // busy, cache value
- pendingValue = value;
- return;
+ onClicked: {
+ if (isConnected) {
+ root.enterPage(index)
+ } else {
+ itemDelegate.wobble()
}
- pendingCommand = engine.thingManager.executeAction(itemDelegate.thing.id,
- itemDelegate.brightnessState.stateTypeId,
- [{
- paramTypeId: itemDelegate.brightnessState.stateTypeId,
- value: value
- }])
- pendingValue = null;
}
- Connections {
- target: engine.thingManager
- onExecuteActionReply: {
- if (itemDelegate.pendingCommand == commandId) {
- itemDelegate.pendingCommand = -1;
- if (itemDelegate.pendingValue != null) {
- itemDelegate.adjustBrightness(pendingValue)
- }
- }
- }
+ ActionQueue {
+ id: actionQueue
+ thing: itemDelegate.thing
+ stateType: thing.thingClass.stateTypes.findByName("brightness")
}
contentItem: Rectangle {
- color: itemDelegate.powerState.value === true && itemDelegate.colorState ? itemDelegate.colorState.value : "#00000000"
+ color: enabled && itemDelegate.powerState.value === true && itemDelegate.colorState ? itemDelegate.colorState.value : "#00000000"
implicitHeight: contentColumn.implicitHeight
Behavior on implicitHeight { NumberAnimation { duration: 100 } }
radius: 6
+ enabled: itemDelegate.connectedState == null || connectedState.value === true
ColumnLayout {
id: contentColumn
@@ -150,10 +138,17 @@ DeviceListPageBase {
spacing: app.margins
ColorIcon {
+ id: lightIcon
Layout.preferredHeight: app.iconSize
Layout.preferredWidth: app.iconSize
name: itemDelegate.powerState.value === true ? "../images/light-on.svg" : "../images/light-off.svg"
color: itemDelegate.powerState.value === true ? app.accentColor : keyColor
+ Binding {
+ target: lightIcon
+ property: "color"
+ value: itemDelegate.colorInverted ? app.backgroundColor : app.foregroundColor
+ when: itemDelegate.tileColored
+ }
}
Label {
@@ -165,9 +160,8 @@ DeviceListPageBase {
Binding {
target: nameLabel
property: "color"
- value: itemDelegate.colorState && NymeaUtils.isDark(app.foregroundColor) === NymeaUtils.isDark(itemDelegate.colorState.value) ?
- app.backgroundColor : app.foregroundColor
- when: nameLabel.enabled && itemDelegate.colorState !== null && itemDelegate.powerState.value === true
+ value: itemDelegate.colorInverted ? app.backgroundColor : app.foregroundColor
+ when: itemDelegate.tileColored
}
}
@@ -176,6 +170,7 @@ DeviceListPageBase {
}
Switch {
+ id: lightSwitch
checked: itemDelegate.powerState.value === true
onClicked: {
var params = [];
@@ -186,6 +181,76 @@ DeviceListPageBase {
print("executing for thing:", itemDelegate.thing.id)
engine.deviceManager.executeAction(itemDelegate.thing.id, itemDelegate.powerState.stateTypeId, params)
}
+
+ indicator: Item {
+ id: indicator
+ implicitWidth: 38
+ implicitHeight: 32
+ x: lightSwitch.leftPadding + (lightSwitch.availableWidth - width) / 2
+ y: lightSwitch.topPadding + (lightSwitch.availableHeight - height) / 2
+
+ property Item control
+ property alias handle: handle
+
+ Material.elevation: 1
+
+ Rectangle {
+ id: indicatorBackground
+ width: parent.width
+ height: 14
+ radius: height / 2
+ y: parent.height / 2 - height / 2
+ color: lightSwitch.enabled ?
+ (lightSwitch.checked ? lightSwitch.Material.switchCheckedTrackColor : lightSwitch.Material.switchUncheckedTrackColor)
+ : lightSwitch.Material.switchDisabledTrackColor
+
+ Binding {
+ target: indicatorBackground
+ property: "color"
+ value: "#808080"
+ when: itemDelegate.tileColored
+ }
+ }
+
+ Rectangle {
+ id: handle
+ x: Math.max(0, Math.min(parent.width - width, lightSwitch.visualPosition * parent.width - (width / 2)))
+ y: (parent.height - height) / 2
+ width: 20
+ height: 20
+ radius: width / 2
+ color: lightSwitch.enabled ? (lightSwitch.checked ? lightSwitch.Material.switchCheckedHandleColor : lightSwitch.Material.switchUncheckedHandleColor)
+ : lightSwitch.Material.switchDisabledHandleColor
+
+
+ Binding {
+ target: handle
+ property: "color"
+ value: "#f0f0f0"
+ when: itemDelegate.tileColored
+ }
+
+ Behavior on x {
+ enabled: !lightSwitch.pressed
+ SmoothedAnimation {
+ duration: 300
+ }
+ }
+// layer.enabled: indicator.Material.elevation > 0
+// layer.effect: ElevationEffect {
+// elevation: indicator.Material.elevation
+// }
+ }
+ DropShadow {
+ anchors.fill: handle
+ horizontalOffset: 1
+ verticalOffset: 1
+ radius: 4.0
+ samples: 17
+ color: "#80000000"
+ source: handle
+ }
+ }
}
}
@@ -196,21 +261,45 @@ DeviceListPageBase {
radius: 6
color: Qt.tint(app.backgroundColor, Qt.rgba(app.foregroundColor.r, app.foregroundColor.g, app.foregroundColor.b, .1))
+ Rectangle {
+ height: knob.x + knob.width / 2
+ width: parent.height
+ anchors.centerIn: parent
+ anchors.horizontalCenterOffset: -(parent.width - height) / 2
+ rotation: -90
+ gradient: Gradient {
+ GradientStop { position: 0; color: "transparent" }
+ GradientStop { position: 1; color: "#55ffffff" }
+ }
+ }
+
Rectangle {
id: knob
- height: 12
- width: 12
+ height: 14
+ width: 14
radius: 8
- color: app.accentColor
+ color: "#f0f0f0"
anchors.verticalCenter: parent.verticalCenter
- x: itemDelegate.brightnessState ? itemDelegate.brightnessState.value * (parent.width - width) / 100 : 0
+ x: itemDelegate.brightnessState ?
+ (actionQueue.queuedValue || actionQueue.pendingValue || itemDelegate.brightnessState.value) * (parent.width - width) / 100
+ : 0
+ }
+ DropShadow {
+ anchors.fill: knob
+ horizontalOffset: 1
+ verticalOffset: 1
+ radius: 4.0
+ samples: 17
+ color: "#80000000"
+ source: knob
}
MouseArea {
+ id: brightnessMouseArea
anchors.fill: parent
preventStealing: true
onMouseXChanged: {
- itemDelegate.adjustBrightness(Math.max(1, Math.min(100, mouseX / width * 100)))
+ actionQueue.sendValue(Math.max(1, Math.min(100, mouseX / width * 100)))
}
}
}
diff --git a/nymea-app/ui/devicepages/GenericDevicePage.qml b/nymea-app/ui/devicepages/GenericDevicePage.qml
index 4b9a7e0a..90f1a31a 100644
--- a/nymea-app/ui/devicepages/GenericDevicePage.qml
+++ b/nymea-app/ui/devicepages/GenericDevicePage.qml
@@ -239,7 +239,7 @@ DevicePageBase {
}
property int pendingActionId: -1
- property real valueCache: 0
+ property var valueCache: 0
property bool valueCacheDirty: false
function enqueueSetValue(value) {
diff --git a/nymea-app/ui/devicepages/LightDevicePage.qml b/nymea-app/ui/devicepages/LightDevicePage.qml
index 5cea7c52..eeb54373 100644
--- a/nymea-app/ui/devicepages/LightDevicePage.qml
+++ b/nymea-app/ui/devicepages/LightDevicePage.qml
@@ -28,11 +28,12 @@
*
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
-import QtQuick 2.5
+import QtQuick 2.9
import QtQuick.Controls 2.1
import QtQuick.Layouts 1.1
import QtQuick.Controls.Material 2.1
import Nymea 1.0
+import QtGraphicalEffects 1.0
import "../components"
DevicePageBase {
@@ -54,279 +55,139 @@ DevicePageBase {
readonly property var ctState: ctStateType ? device.states.getState(ctStateType.id) : null
readonly property var ctActionType: deviceClass.actionTypes.findByName("colorTemperature")
+ readonly property int statesCount: (powerState !== null ? 1 : 0) +
+ (brightnessState !== null ? 1 : 0) +
+ (ctState !== null ? 1 : 0) +
+ (colorState !== null ? 1 : 0)
GridLayout {
anchors.fill: parent
anchors.margins: app.margins
- columns: app.landscape ? 2 : 1
+ columns: app.landscape ? root.statesCount : 1
rowSpacing: app.margins
columnSpacing: app.margins
Layout.alignment: Qt.AlignCenter
- Dial {
- Layout.minimumWidth: app.landscape ? parent.width / 3 :app.iconSize * 4
- Layout.preferredHeight: width
- Layout.fillWidth: true
- Layout.topMargin: app.margins
- Layout.bottomMargin: app.landscape ? app.margins : 0
- Layout.alignment: Qt.AlignCenter
- Layout.rowSpan: app.landscape ? 3 : 1
+ GridLayout {
Layout.fillHeight: true
- device: root.device
- stateType: root.brightnessStateType
- showValueLabel: false
- }
-
-// Item {
-// Layout.preferredWidth: Math.max(app.iconSize * 4, parent.width / 5)
-// Layout.preferredHeight: width
-// Layout.topMargin: app.margins
-// Layout.bottomMargin: app.landscape ? app.margins : 0
-// Layout.alignment: Qt.AlignCenter
-// Layout.rowSpan: app.landscape ? 4 : 1
-// Layout.fillHeight: true
-
-// AbstractButton {
-// height: Math.min(parent.height, parent.width)
-// width: height
-// anchors.centerIn: parent
-// Rectangle {
-// anchors.fill: parent
-// color: "white"
-// border.color: root.powerState.value === true ? app.accentColor : bulbIcon.keyColor
-// border.width: 4
-// radius: width / 2
-// }
-
-// ColorIcon {
-// id: bulbIcon
-// anchors.fill: parent
-// anchors.margins: app.margins * 1.5
-// name: root.powerState.value === true ? "../images/light-on.svg" : "../images/light-off.svg"
-// color: root.powerState.value === true ? app.accentColor : keyColor
-// }
-// onClicked: {
-// var params = []
-// var param = {}
-// param["paramTypeId"] = root.powerActionType.paramTypes.get(0).id;
-// param["value"] = !root.powerState.value;
-// params.push(param)
-// engine.deviceManager.executeAction(root.device.id, root.powerStateType.id, params);
-// }
-// }
-// }
-
-
- RowLayout {
- Layout.fillHeight: true
- spacing: app.margins
+ Layout.fillWidth: !app.landscape
+ columnSpacing: app.margins
+ rowSpacing: app.margins
Layout.alignment: Qt.AlignHCenter
visible: root.ctStateType !== null
+ columns: app.landscape ? 1 : 4
Repeater {
model: ListModel {
- ListElement { name: "activate"; ct: "0"; bri: 100 }
- ListElement { name: "concentrate"; ct: "23"; bri: 100 }
- ListElement { name: "reading"; ct: "57"; bri: 100 }
- ListElement { name: "relax"; ct: "95" ; bri: 55}
+ ListElement { name: "activate"; ct: "0"; bri: 100; color: "#00c5ff" }
+ ListElement { name: "concentrate"; ct: "23"; bri: 100; color: "#3dddff" }
+ ListElement { name: "reading"; ct: "57"; bri: 100; color: "#f4de00" }
+ ListElement { name: "relax"; ct: "95" ; bri: 55; color: "#ffaf2a"}
}
- delegate: Pane {
+ delegate: Item {
+ Layout.preferredWidth: app.hugeIconSize
+ Layout.preferredHeight: app.hugeIconSize
Layout.fillWidth: true
- Layout.preferredHeight: Math.max(20, width)
- Material.elevation: 1
- // Layout.maximumWidth: app.iconSize * 2
- padding: 0
- Image {
- source: "../images/lighting/" + model.name + ".svg"
- anchors.fill: parent
- ItemDelegate {
- anchors.fill: parent
- onClicked: {
- // Translate from % to absolute value in min/max
- // % : 100 = abs : (max - min)
- print("min,max", root.ctStateType, root.ctStateType.minValue, root.ctStateType.maxValue)
- var absoluteCtValue = (model.ct * (root.ctStateType.maxValue - root.ctStateType.minValue) / 100) + root.ctStateType.minValue
- var params = [];
- var param1 = {};
- param1["paramTypeId"] = root.ctActionType.paramTypes.get(0).id;
- param1["value"] = absoluteCtValue;
- params.push(param1)
- engine.deviceManager.executeAction(root.device.id, root.ctActionType.id, params)
- params = [];
- param1 = {};
- param1["paramTypeId"] = root.brightnessActionType.paramTypes.get(0).id;
- param1["value"] = model.bri;
- params.push(param1)
- engine.deviceManager.executeAction(root.device.id, root.brightnessActionType.id, params)
- }
- }
- }
- }
- }
- }
-
-// Rectangle {
-// color: "blue"
-// Layout.fillWidth: true
-// Layout.fillHeight: true
-// Layout.minimumHeight: 20
-// Layout.preferredHeight: 20
-// visible: root.brightnessStateType
-
-// Pane {
-// anchors { left: parent.left; right: parent.right; verticalCenter: parent.verticalCenter }
-// height: parent.height
-// Material.elevation: 1
-// padding: 0
-
-// BrightnessSlider {
-// anchors.fill: parent
-// brightness: root.brightnessState ? root.brightnessState.value : 0
-// onMoved: {
-// var params = []
-// var param = {}
-// param["paramTypeId"] = root.brightnessActionType.paramTypes.get(0).id;
-// param["value"] = brightness;
-// params.push(param)
-// engine.deviceManager.executeAction(root.device.id, root.brightnessActionType.id, params);
-// }
-// }
-// }
-// }
-
-
- Rectangle {
- color: "red"
- Layout.fillWidth: true
- Layout.fillHeight: true
- Layout.minimumHeight: 20
- Layout.preferredHeight: 20
- visible: root.ctStateType
-
- Pane {
- anchors { left: parent.left; right: parent.right; verticalCenter: parent.verticalCenter }
- height: parent.height
- Material.elevation: 1
- padding: 0
-
- ColorPickerCt {
- id: pickerCt
- anchors.fill: parent
- ct: root.ctState ? root.ctState.value : 0
- minCt: root.ctActionType ? root.ctStateType.minValue : 0
- maxCt: root.ctActionType ? root.ctStateType.maxValue : 0
-
-
- touchDelegate: Rectangle {
- height: pickerCt.height
- width: 5
- color: app.accentColor
- }
-
- property var lastSentTime: new Date()
- onCtChanged: {
- var currentTime = new Date();
- if (pressed && currentTime - lastSentTime > 200) {
- setColorTemp(ct)
- lastSentTime = currentTime
- }
- }
-
- function setColorTemp(ct) {
- var params = []
- var param = {}
- param["paramTypeId"] = root.ctActionType.paramTypes.get(0).id;
- param["value"] = ct;
- params.push(param)
- engine.deviceManager.executeAction(root.device.id, root.ctActionType.id, params);
- }
- }
- }
- }
-
- Rectangle {
- color: "green"
- Layout.fillWidth: true
- Layout.fillHeight: true
- Layout.minimumHeight: 80
- Layout.preferredHeight: 80
- visible: root.colorStateType
-
- Pane {
- anchors { left: parent.left; right: parent.right; verticalCenter: parent.verticalCenter }
- height: parent.height
- Material.elevation: 1
- padding: 0
-
- ColorPicker {
- id: colorPicker
- anchors.fill: parent
-
- property int pendingCommand: -1
-
- property var queuedColor: null
-
- function sendColor(color) {
- var params = [];
- var param1 = {};
- param1["paramTypeId"] = root.colorActionType.paramTypes.get(0).id;
- param1["value"] = color;
- params.push(param1)
- colorPicker.pendingCommand = engine.deviceManager.executeAction(root.device.id, root.colorActionType.id, params)
- print("sent command", colorPicker.pendingCommand, color)
- }
-
- color: root.colorState ? root.colorState.value : "white"
- touchDelegate: Rectangle {
- height: 15
+ Layout.fillHeight: app.landscape
+ ItemDelegate {
+ height: app.hugeIconSize
width: height
- radius: height / 2
- color: app.foregroundColor
+ anchors.centerIn: parent
- Rectangle {
- color: colorPicker.hovered || colorPicker.pressed ? "#11000000" : "transparent"
- anchors.centerIn: parent
- height: 30
- width: height
- radius: width / 2
- Behavior on color {
- ColorAnimation {
- duration: 200
- }
+ leftPadding: 0
+ rightPadding: 0
+ topPadding: 0
+ bottomPadding: 0
+
+ contentItem: Rectangle {
+ color: model.color
+ radius: 6
+
+ ColorIcon {
+ anchors.fill: parent
+ name: "../images/lighting/" + model.name + ".svg"
+ color: "white"
}
}
- }
- Connections {
- target: engine.deviceManager
- onExecuteActionReply: {
- print("action finished", JSON.stringify(params))
- if (commandId === colorPicker.pendingCommand) {
- colorPicker.pendingCommand = -1;
- if (colorPicker.queuedColor) {
- colorPicker.sendColor(colorPicker.queuedColor);
- colorPicker.queuedColor = null
- }
- }
+ onClicked: {
+ // Translate from % to absolute value in min/max
+ // % : 100 = abs : (max - min)
+ print("min,max", root.ctStateType, root.ctStateType.minValue, root.ctStateType.maxValue)
+ var absoluteCtValue = (model.ct * (root.ctStateType.maxValue - root.ctStateType.minValue) / 100) + root.ctStateType.minValue
+ var params = [];
+ var param1 = {};
+ param1["paramTypeId"] = root.ctActionType.paramTypes.get(0).id;
+ param1["value"] = absoluteCtValue;
+ params.push(param1)
+ engine.deviceManager.executeAction(root.device.id, root.ctActionType.id, params)
+ params = [];
+ param1 = {};
+ param1["paramTypeId"] = root.brightnessActionType.paramTypes.get(0).id;
+ param1["value"] = model.bri;
+ params.push(param1)
+ engine.deviceManager.executeAction(root.device.id, root.brightnessActionType.id, params)
}
}
-
- onColorChanged: {
- if (!pressed) {
- return;
- }
-
- if (pendingCommand != -1) {
- queuedColor = color;
- return;
- }
-
- sendColor(color);
- }
}
}
}
+ ColorPicker {
+ Layout.fillWidth: true
+ Layout.fillHeight: true
+ Layout.maximumHeight: width
+ thing: root.thing
+ visible: root.thing.thingClass.stateTypes.findByName("color") !== null
+ }
+
+ ColorTemperaturePicker {
+ Layout.fillWidth: !app.landscape
+ Layout.fillHeight: app.landscape
+ thing: root.thing
+ orientation: app.landscape ? Qt.Vertical : Qt.Horizontal
+ visible: root.thing.thingClass.stateTypes.findByName("colorTemperature") !== null
+ }
+
+ GridLayout {
+ id: basicItems
+ Layout.fillWidth: !app.landscape
+ Layout.fillHeight: app.landscape
+ Layout.alignment: Qt.AlignHCenter
+ columnSpacing: app.margins
+ rowSpacing: app.margins
+ columns: (app.landscape && (root.colorState !== null && root.ctState !== null))
+ || (!app.landscape && (root.colorState === null && root.ctState === null)) ? 1 : 2
+ Rectangle {
+ Layout.preferredWidth: app.hugeIconSize
+ Layout.preferredHeight: width
+ radius: app.radius
+ color: root.colorState ? root.colorState.value : "red"
+// color: Qt.tint(app.backgroundColor, Qt.rgba(app.foregroundColor.r, app.foregroundColor.g, app.foregroundColor.b, 0.1))
+ ColorIcon {
+ anchors.centerIn: parent
+ height: app.largeIconSize
+ width: height
+ name: root.powerState.value === true ? "../images/light-on.svg" : "../images/light-off.svg"
+ color: root.colorState ?
+ NymeaUtils.isDark(root.colorState.value) ? "white" : "black" : "white"
+ }
+ MouseArea {
+ anchors.fill: parent
+ onClicked: {
+ engine.thingManager.executeAction(root.thing.id, root.powerStateType.id, [{paramTypeId: root.powerStateType.id, value: !root.powerState.value}])
+ }
+ }
+ }
+
+ BrightnessSlider {
+ Layout.fillWidth: orientation == Qt.Horizontal
+ Layout.fillHeight: orientation == Qt.Vertical
+ thing: root.thing
+ orientation: basicItems.columns === 1 ? Qt.Vertical : Qt.Horizontal
+ visible: root.thing.stateByName("brightness") !== null
+ }
+ }
}
}
diff --git a/nymea-app/ui/devicepages/ShutterDevicePage.qml b/nymea-app/ui/devicepages/ShutterDevicePage.qml
index ba3224ea..e49cbf17 100644
--- a/nymea-app/ui/devicepages/ShutterDevicePage.qml
+++ b/nymea-app/ui/devicepages/ShutterDevicePage.qml
@@ -196,7 +196,7 @@ DevicePageBase {
Rectangle {
id: mask
anchors.fill: parent
- radius: app.margins
+ radius: app.radius
color: "blue"
visible: false
}
diff --git a/nymea-app/ui/images/lighting/activate.svg b/nymea-app/ui/images/lighting/activate.svg
index 027b729d..b5f7c428 100644
--- a/nymea-app/ui/images/lighting/activate.svg
+++ b/nymea-app/ui/images/lighting/activate.svg
@@ -1,6 +1,4 @@
-
-
diff --git a/nymea-app/ui/images/lighting/concentrate.svg b/nymea-app/ui/images/lighting/concentrate.svg
index 9e2d636b..6765a9f8 100644
--- a/nymea-app/ui/images/lighting/concentrate.svg
+++ b/nymea-app/ui/images/lighting/concentrate.svg
@@ -1,6 +1,4 @@
-
-
diff --git a/nymea-app/ui/images/lighting/reading.svg b/nymea-app/ui/images/lighting/reading.svg
index 8b993f16..69d45cf6 100644
--- a/nymea-app/ui/images/lighting/reading.svg
+++ b/nymea-app/ui/images/lighting/reading.svg
@@ -1,6 +1,4 @@
-
-
diff --git a/nymea-app/ui/images/lighting/relax.svg b/nymea-app/ui/images/lighting/relax.svg
index 13b680ca..6cc9d468 100644
--- a/nymea-app/ui/images/lighting/relax.svg
+++ b/nymea-app/ui/images/lighting/relax.svg
@@ -1,6 +1,4 @@
-
-
diff --git a/nymea-app/ui/utils/ActionQueue.qml b/nymea-app/ui/utils/ActionQueue.qml
new file mode 100644
index 00000000..c1369520
--- /dev/null
+++ b/nymea-app/ui/utils/ActionQueue.qml
@@ -0,0 +1,48 @@
+import QtQuick 2.9
+import Nymea 1.0
+
+Item {
+ id: root
+
+ property Thing thing: null
+ property StateType stateType: null
+
+ readonly property var pendingValue: d.queuedValue || d.pendingValue
+
+ function sendValue(value) {
+ if (d.pendingCommand != -1) {
+ // busy, cache value
+ d.queuedValue = value;
+ return;
+ }
+ d.pendingValue = value;
+ d.pendingCommand = engine.thingManager.executeAction(root.thing.id,
+ root.stateType.id,
+ [{
+ paramTypeId: root.stateType.id,
+ value: value
+ }])
+ d.queuedValue = null
+ }
+
+ QtObject {
+ id: d
+ property int pendingCommand: -1
+ property var pendingValue: null
+ property var queuedValue: null
+ }
+
+ Connections {
+ target: engine.thingManager
+ onExecuteActionReply: {
+ if (d.pendingCommand == commandId) {
+ d.pendingCommand = -1;
+ if (d.queuedValue != null) {
+ root.sendValue(d.queuedValue)
+ } else {
+ d.pendingValue = null
+ }
+ }
+ }
+ }
+}