Merge PR #471: Fixes and improvements for lights

This commit is contained in:
Jenkins nymea 2020-12-04 13:48:22 +01:00
commit cdfc63973c
19 changed files with 855 additions and 756 deletions

View File

@ -21,7 +21,7 @@
<file>ui/connection/wifisetup/BoxInfoPage.qml</file>
<file>ui/components/NymeaHeader.qml</file>
<file>ui/components/HeaderButton.qml</file>
<file>ui/components/ColorPicker.qml</file>
<file>ui/components/ColorPickerPre510.qml</file>
<file>ui/components/ColorIcon.qml</file>
<file>ui/components/ThinDivider.qml</file>
<file>ui/components/ThrottledSlider.qml</file>
@ -232,5 +232,8 @@
<file>ui/components/NymeaItemDelegate.qml</file>
<file>ui/components/NymeaSwipeDelegate.qml</file>
<file>ui/customviews/GarageController.qml</file>
<file>ui/components/ColorPicker.qml</file>
<file>ui/utils/ActionQueue.qml</file>
<file>ui/components/ColorTemperaturePicker.qml</file>
</qresource>
</RCC>

View File

@ -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

View File

@ -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()
}
}
}

View File

@ -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
}
}

View File

@ -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 <https://www.gnu.org/licenses/>.
*
* 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)))
}
}
}

View File

@ -102,5 +102,4 @@ Item {
sourceComponent: root.touchDelegate
visible: mouseArea.pressed && root.active
}
}

View File

@ -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 <https://www.gnu.org/licenses/>.
*
* 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
}
}

View File

@ -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);
}
}
}

View File

@ -280,7 +280,7 @@ ItemDelegate {
Component {
id: colorPickerComponent
ColorPicker {
ColorPickerPre510 {
id: colorPicker
implicitHeight: 200
// color: root.param.value

View File

@ -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: {

View File

@ -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)))
}
}
}

View File

@ -239,7 +239,7 @@ DevicePageBase {
}
property int pendingActionId: -1
property real valueCache: 0
property var valueCache: 0
property bool valueCacheDirty: false
function enqueueSetValue(value) {

View File

@ -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
}
}
}
}

View File

@ -196,7 +196,7 @@ DevicePageBase {
Rectangle {
id: mask
anchors.fill: parent
radius: app.margins
radius: app.radius
color: "blue"
visible: false
}

View File

@ -1,6 +1,4 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
@ -14,7 +12,7 @@
viewBox="0 0 256 256"
id="svg2"
version="1.1"
inkscape:version="0.91 r13725"
inkscape:version="1.0.1 (1.0.1+r74)"
sodipodi:docname="activate.svg">
<defs
id="defs4" />
@ -25,18 +23,19 @@
borderopacity="1.0"
inkscape:pageopacity="0.0"
inkscape:pageshadow="2"
inkscape:zoom="2.8"
inkscape:cx="66.409554"
inkscape:cy="199.91527"
inkscape:zoom="2.1753186"
inkscape:cx="123.21035"
inkscape:cy="147.11516"
inkscape:document-units="px"
inkscape:current-layer="layer1"
showgrid="true"
units="px"
inkscape:window-width="2880"
inkscape:window-height="1752"
inkscape:window-x="0"
inkscape:window-y="48"
inkscape:window-maximized="1">
inkscape:window-width="1380"
inkscape:window-height="873"
inkscape:window-x="60"
inkscape:window-y="27"
inkscape:window-maximized="1"
inkscape:document-rotation="0">
<inkscape:grid
type="xygrid"
id="grid4136" />
@ -49,7 +48,7 @@
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title></dc:title>
<dc:title />
</cc:Work>
</rdf:RDF>
</metadata>
@ -58,24 +57,10 @@
inkscape:groupmode="layer"
id="layer1"
transform="translate(0,-796.36216)">
<rect
style="opacity:1;fill:#00c5ff;fill-opacity:1;stroke:none;stroke-width:2;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
id="rect4138"
width="256"
height="256"
x="0"
y="796.36218" />
<circle
style="opacity:1;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:2;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
id="path4140"
cx="128"
cy="924.36218"
r="92.000023" />
<path
style="opacity:1;fill:#00c5ff;fill-opacity:1;stroke:none;stroke-width:2;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
d="m 210.00002,924.36218 c 0,45.28736 -36.71266,82.00002 -82.00002,82.00002 -39.180492,0 -71.94291,-27.47904 -80.066297,-64.21617 C 55,937.36216 130.28569,892.21933 130.28569,892.21933 l -0.14284,40.14283 c 0,0 64.85715,-45 69.81602,-47.35033 6.4013,11.68105 10.04115,25.09063 10.04115,39.35035 z"
id="path4202"
inkscape:connector-curvature="0"
sodipodi:nodetypes="ssccccs" />
id="path4140"
style="opacity:1;fill:#808080;fill-opacity:1;stroke:none;stroke-width:2;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
d="M 127.86133 36 A 92.000023 92.000023 0 0 0 36 128 A 92.000023 92.000023 0 0 0 128 220 A 92.000023 92.000023 0 0 0 220 128 A 92.000023 92.000023 0 0 0 128 36 A 92.000023 92.000023 0 0 0 127.86133 36 z M 199.95898 88.650391 C 206.36028 100.33144 210 113.74028 210 128 C 210 173.28736 173.28736 210 128 210 C 88.819508 210 56.056981 182.52033 47.933594 145.7832 C 54.999891 140.99933 130.28516 95.857422 130.28516 95.857422 L 130.14258 136 C 130.14258 136 195.00011 91.000721 199.95898 88.650391 z "
transform="translate(0,796.36216)" />
</g>
</svg>

Before

Width:  |  Height:  |  Size: 2.7 KiB

After

Width:  |  Height:  |  Size: 2.4 KiB

View File

@ -1,6 +1,4 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
@ -14,7 +12,7 @@
viewBox="0 0 256 256"
id="svg2"
version="1.1"
inkscape:version="0.91 r13725"
inkscape:version="1.0.1 (1.0.1+r74)"
sodipodi:docname="concentrate.svg">
<defs
id="defs4" />
@ -25,18 +23,19 @@
borderopacity="1.0"
inkscape:pageopacity="0.0"
inkscape:pageshadow="2"
inkscape:zoom="11.2"
inkscape:cx="128.78304"
inkscape:cy="130.74689"
inkscape:zoom="2.0704471"
inkscape:cx="115.75638"
inkscape:cy="121.69523"
inkscape:document-units="px"
inkscape:current-layer="layer1"
showgrid="true"
units="px"
inkscape:window-width="2880"
inkscape:window-height="1752"
inkscape:window-x="0"
inkscape:window-y="48"
inkscape:window-maximized="1">
inkscape:window-width="1380"
inkscape:window-height="873"
inkscape:window-x="60"
inkscape:window-y="27"
inkscape:window-maximized="1"
inkscape:document-rotation="0">
<inkscape:grid
type="xygrid"
id="grid4136" />
@ -49,7 +48,7 @@
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title></dc:title>
<dc:title />
</cc:Work>
</rdf:RDF>
</metadata>
@ -58,46 +57,10 @@
inkscape:groupmode="layer"
id="layer1"
transform="translate(0,-796.36216)">
<rect
style="opacity:1;fill:#3dddff;fill-opacity:1;stroke:none;stroke-width:2;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
id="rect4138"
width="256"
height="256"
x="0"
y="796.36218" />
<circle
style="opacity:1;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:2;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
id="path4140"
cx="128"
cy="924.36218"
r="92.000023" />
<path
style="opacity:1;fill:#3dddff;fill-opacity:1;stroke:none;stroke-width:2;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
d="M 210.00002,924.36218 A 82.000023,82.000023 0 0 1 128,1006.3622 82.000023,82.000023 0 0 1 45.999977,924.36218 82.000023,82.000023 0 0 1 128,842.36216 a 82.000023,82.000023 0 0 1 82.00002,82.00002 z"
id="path4202" />
<circle
style="opacity:1;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:2;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
id="path4254"
cx="128"
cy="924.36218"
r="70" />
<circle
style="opacity:1;fill:#3dddff;fill-opacity:1;stroke:none;stroke-width:2;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
id="path4256"
cx="128"
cy="924.36218"
r="55.000023" />
<circle
style="opacity:1;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:2;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
id="path4258"
cx="128"
cy="924.36218"
r="35.000023" />
<circle
style="opacity:1;fill:#3dddff;fill-opacity:1;stroke:none;stroke-width:2;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
id="path4260"
cx="128"
cy="924.36218"
r="20.000023" />
id="path4140"
style="opacity:1;fill:#808080;fill-opacity:1;stroke:none;stroke-width:2;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
d="M 127.86133 36 A 92.000023 92.000023 0 0 0 36 128 A 92.000023 92.000023 0 0 0 128 220 A 92.000023 92.000023 0 0 0 220 128 A 92.000023 92.000023 0 0 0 128 36 A 92.000023 92.000023 0 0 0 127.86133 36 z M 127.88281 46 A 82.000023 82.000023 0 0 1 128 46 A 82.000023 82.000023 0 0 1 210 128 A 82.000023 82.000023 0 0 1 128 210 A 82.000023 82.000023 0 0 1 46 128 A 82.000023 82.000023 0 0 1 127.88281 46 z M 127.79688 58 A 70 70 0 0 0 58 128 A 70 70 0 0 0 128 198 A 70 70 0 0 0 198 128 A 70 70 0 0 0 128 58 A 70 70 0 0 0 127.79688 58 z M 128 73 A 55.000023 55.000023 0 0 1 183 128 A 55.000023 55.000023 0 0 1 128 183 A 55.000023 55.000023 0 0 1 73 128 A 55.000023 55.000023 0 0 1 128 73 z M 127.74414 93 A 35.000023 35.000023 0 0 0 93 128 A 35.000023 35.000023 0 0 0 128 163 A 35.000023 35.000023 0 0 0 163 128 A 35.000023 35.000023 0 0 0 128 93 A 35.000023 35.000023 0 0 0 127.74414 93 z M 128 108 A 20.000023 20.000023 0 0 1 148 128 A 20.000023 20.000023 0 0 1 128 148 A 20.000023 20.000023 0 0 1 108 128 A 20.000023 20.000023 0 0 1 128 108 z "
transform="translate(0,796.36216)" />
</g>
</svg>

Before

Width:  |  Height:  |  Size: 3.4 KiB

After

Width:  |  Height:  |  Size: 2.9 KiB

View File

@ -1,6 +1,4 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
@ -14,7 +12,7 @@
viewBox="0 0 256 256"
id="svg2"
version="1.1"
inkscape:version="0.91 r13725"
inkscape:version="1.0.1 (1.0.1+r74)"
sodipodi:docname="reading.svg">
<defs
id="defs4" />
@ -26,17 +24,18 @@
inkscape:pageopacity="0.0"
inkscape:pageshadow="2"
inkscape:zoom="2.8"
inkscape:cx="66.409554"
inkscape:cy="199.91527"
inkscape:cx="122.92774"
inkscape:cy="133.69504"
inkscape:document-units="px"
inkscape:current-layer="layer1"
showgrid="true"
units="px"
inkscape:window-width="2880"
inkscape:window-height="1752"
inkscape:window-x="0"
inkscape:window-y="48"
inkscape:window-maximized="1">
inkscape:window-width="1380"
inkscape:window-height="873"
inkscape:window-x="60"
inkscape:window-y="27"
inkscape:window-maximized="1"
inkscape:document-rotation="0">
<inkscape:grid
type="xygrid"
id="grid4136" />
@ -49,7 +48,7 @@
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title></dc:title>
<dc:title />
</cc:Work>
</rdf:RDF>
</metadata>
@ -58,65 +57,10 @@
inkscape:groupmode="layer"
id="layer1"
transform="translate(0,-796.36216)">
<rect
style="opacity:1;fill:#f4de00;fill-opacity:1;stroke:none;stroke-width:2;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
id="rect4138"
width="256"
height="256"
x="0"
y="796.36218" />
<circle
style="opacity:1;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:2;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
<path
id="path4140"
cx="128"
cy="924.36218"
r="92.000023" />
<g
id="g4156"
transform="translate(-2,1.9999774)"
style="fill:#f4de00;fill-opacity:1">
<rect
y="867.36218"
x="80"
height="10"
width="100"
id="rect4142"
style="opacity:1;fill:#f4de00;fill-opacity:1;stroke:none;stroke-width:2;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
<rect
style="opacity:1;fill:#f4de00;fill-opacity:1;stroke:none;stroke-width:2;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
id="rect4144"
width="100"
height="10"
x="80"
y="887.36218" />
<rect
y="907.36218"
x="80"
height="10"
width="100"
id="rect4146"
style="opacity:1;fill:#f4de00;fill-opacity:1;stroke:none;stroke-width:2;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
<rect
style="opacity:1;fill:#f4de00;fill-opacity:1;stroke:none;stroke-width:2;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
id="rect4148"
width="100"
height="10"
x="80"
y="927.36218" />
<rect
y="947.36218"
x="80"
height="10"
width="100"
id="rect4150"
style="opacity:1;fill:#f4de00;fill-opacity:1;stroke:none;stroke-width:2;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
<rect
style="opacity:1;fill:#f4de00;fill-opacity:1;stroke:none;stroke-width:2;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
id="rect4152"
width="100"
height="10"
x="80"
y="967.36218" />
</g>
style="opacity:1;fill:#808080;fill-opacity:1;stroke:none;stroke-width:2;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
d="M 127.86133 36 A 92.000023 92.000023 0 0 0 36 128 A 92.000023 92.000023 0 0 0 128 220 A 92.000023 92.000023 0 0 0 220 128 A 92.000023 92.000023 0 0 0 128 36 A 92.000023 92.000023 0 0 0 127.86133 36 z M 78 73 L 178 73 L 178 83 L 78 83 L 78 73 z M 78 93 L 178 93 L 178 103 L 78 103 L 78 93 z M 78 113 L 178 113 L 178 123 L 78 123 L 78 113 z M 78 133 L 178 133 L 178 143 L 78 143 L 78 133 z M 78 153 L 178 153 L 178 163 L 78 163 L 78 153 z M 78 173 L 178 173 L 178 183 L 78 183 L 78 173 z "
transform="translate(0,796.36216)" />
</g>
</svg>

Before

Width:  |  Height:  |  Size: 3.8 KiB

After

Width:  |  Height:  |  Size: 2.3 KiB

View File

@ -1,6 +1,4 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
@ -14,7 +12,7 @@
viewBox="0 0 256 256"
id="svg2"
version="1.1"
inkscape:version="0.91 r13725"
inkscape:version="1.0.1 (1.0.1+r74)"
sodipodi:docname="relax.svg">
<defs
id="defs4" />
@ -25,18 +23,19 @@
borderopacity="1.0"
inkscape:pageopacity="0.0"
inkscape:pageshadow="2"
inkscape:zoom="2.8"
inkscape:cx="66.409554"
inkscape:cy="199.91527"
inkscape:zoom="1.1480033"
inkscape:cx="56.435095"
inkscape:cy="139.24953"
inkscape:document-units="px"
inkscape:current-layer="layer1"
showgrid="true"
units="px"
inkscape:window-width="2880"
inkscape:window-height="1752"
inkscape:window-x="0"
inkscape:window-y="48"
inkscape:window-maximized="1">
inkscape:window-width="1380"
inkscape:window-height="873"
inkscape:window-x="60"
inkscape:window-y="27"
inkscape:window-maximized="1"
inkscape:document-rotation="0">
<inkscape:grid
type="xygrid"
id="grid4136" />
@ -49,7 +48,7 @@
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title></dc:title>
<dc:title />
</cc:Work>
</rdf:RDF>
</metadata>
@ -58,24 +57,10 @@
inkscape:groupmode="layer"
id="layer1"
transform="translate(0,-796.36216)">
<rect
style="opacity:1;fill:#ffaf2a;fill-opacity:1;stroke:none;stroke-width:2;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
id="rect4138"
width="256"
height="256"
x="0"
y="796.36218" />
<circle
style="opacity:1;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:2;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
id="path4140"
cx="128"
cy="924.36218"
r="92.000023" />
<path
id="circle4230"
style="opacity:1;fill:#ffaf2a;fill-opacity:1;stroke:none;stroke-width:2;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
d="m 128,1006.3622 c 45.28736,0 82.00002,-36.71266 82.21429,-82.00002 0.21428,22.88037 -18.33392,41.42857 -41.21429,41.42857 -22.88037,0 -41.42857,-18.5482 -41,-41.42857 0.42857,-22.88037 -18.11963,-41.42857 -41,-41.42857 -22.880367,0 -41.42857,18.5482 -41.214297,41.42857 0.214276,45.28736 36.926936,82.00002 82.214297,82.00002 z"
inkscape:connector-curvature="0"
sodipodi:nodetypes="scscscs" />
id="path4140"
style="opacity:1;fill:#808080;fill-opacity:1;stroke:none;stroke-width:2;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
d="M 127.86133 36 A 92.000023 92.000023 0 0 0 36 128 A 92.000023 92.000023 0 0 0 128 220 A 92.000023 92.000023 0 0 0 220 128 A 92.000023 92.000023 0 0 0 128 36 A 92.000023 92.000023 0 0 0 127.86133 36 z M 87 86.572266 C 109.88037 86.572266 128.42857 105.11963 128 128 C 127.57143 150.88037 146.11963 169.42773 169 169.42773 C 191.12817 169.42773 209.2011 152.08002 210.17188 130.24219 C 210.1953 129.49734 210.2113 128.74967 210.21484 128 C 210.22189 128.7522 210.20487 129.49986 210.17188 130.24219 C 208.78032 174.49311 172.53769 210 128 210 C 82.712639 210 45.999432 173.28736 45.785156 128 C 45.570883 105.11963 64.119633 86.572266 87 86.572266 z "
transform="translate(0,796.36216)" />
</g>
</svg>

Before

Width:  |  Height:  |  Size: 2.7 KiB

After

Width:  |  Height:  |  Size: 2.5 KiB

View File

@ -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
}
}
}
}
}