Merge PR #471: Fixes and improvements for lights
@ -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>
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -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
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
@ -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)))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -102,5 +102,4 @@ Item {
|
||||
sourceComponent: root.touchDelegate
|
||||
visible: mouseArea.pressed && root.active
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
249
nymea-app/ui/components/ColorPickerPre510.qml
Normal 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
|
||||
}
|
||||
}
|
||||
69
nymea-app/ui/components/ColorTemperaturePicker.qml
Normal 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -280,7 +280,7 @@ ItemDelegate {
|
||||
|
||||
Component {
|
||||
id: colorPickerComponent
|
||||
ColorPicker {
|
||||
ColorPickerPre510 {
|
||||
id: colorPicker
|
||||
implicitHeight: 200
|
||||
// color: root.param.value
|
||||
|
||||
@ -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: {
|
||||
|
||||
@ -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)))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -239,7 +239,7 @@ DevicePageBase {
|
||||
}
|
||||
|
||||
property int pendingActionId: -1
|
||||
property real valueCache: 0
|
||||
property var valueCache: 0
|
||||
property bool valueCacheDirty: false
|
||||
|
||||
function enqueueSetValue(value) {
|
||||
|
||||
@ -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
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -196,7 +196,7 @@ DevicePageBase {
|
||||
Rectangle {
|
||||
id: mask
|
||||
anchors.fill: parent
|
||||
radius: app.margins
|
||||
radius: app.radius
|
||||
color: "blue"
|
||||
visible: false
|
||||
}
|
||||
|
||||
@ -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 |
@ -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 |
@ -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 |
@ -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 |
48
nymea-app/ui/utils/ActionQueue.qml
Normal 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
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||