You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 

604 lines
25 KiB

import QtQuick 2.12
import QtQuick.Controls 2.12
import QtQuick.Layouts 1.12
import QtQuick.Shapes 1.1
import QtGraphicalEffects 1.12
import NERvGear 1.0 as NVG
import NERvGear.Controls 1.0
import NERvGear.Templates 1.0 as T
import NERvGear.Preferences 1.0 as P
import "qrc:/qml/com.gpbeta.data.weather" as Private
import "utils.js" as Utils
WidgetTemplate {
id: widget
title: qsTr("Ordinal Scale Weather Widget")
editing: styleDialog.active
version: "1.0.0"
defaultValues: {
"Display Location": "",
"Update Interval":
{
"Value": 1,
"Unit": 1
},
"Background Color": "#ffa502",
"Background Opacity": 60,
"Area Opacity Difference": 17,
"Icon Color": "#fefefe",
"Temperature Text Settings":
{
"Font Color": "#f5f5f5",
"Font Size": 90,
"Font Name": fonts.length - 1,
"Font Weight": 1,
"X Offset": 33,
"Y Offset": 32
},
"Area Text Settings":
{
"Font Color": "#f5f5f5",
"Font Size": 60,
"Font Name": fonts.length - 1,
"Font Weight": 1,
"X Offset": 0,
"Y Offset": -56,
"Border Margin": 40
}
}
onUpdated: {
widget.settings.styles = Object.assign(defaultValues, widget.settings.styles);
}
readonly property var configs: widget.settings.styles
readonly property real w: widget.width
readonly property real h: 0.46*widget.width
readonly property var fonts: Qt.fontFamilies()
readonly property var fontweight: [Font.Light, Font.Normal, Font.Bold]
readonly property var sfontweight: [qsTr("Light"), qsTr("Normal"), qsTr("Bold")]
readonly property NVG.DataSource dataSource: NVG.DataSource {
configuration: {"mode":0,"unit":"","interval":60000*configs["Update Interval"]["Value"]*(1+59*configs["Update Interval"]["Unit"]),"update":configs["Address"],"source":"nvg://weather.data.gpbeta.com/data#raw","value":"current"}
}
NVG.DataSourceRawOutput {
id: output
source: dataSource
}
Item {
id: main
width: w
height: h
anchors.centerIn: parent
layer.enabled: true
layer.effect: OpacityMask{
maskSource: Rectangle {
width: w
height: h
color: "black"
radius: h/15
}
}
Rectangle {
id: weather_box
width: w
height: h
anchors.left: parent.left
anchors.top: parent.top
opacity: configs["Background Opacity"]/100
color: configs["Background Color"]
}
Item {
id: sdialog
width: h/8
height: h/8
anchors.left: parent.left
anchors.leftMargin: h/16
anchors.topMargin: h/14
anchors.top: parent.top
Shape {
anchors.fill: parent
ShapePath {
strokeWidth: parent.height/120
strokeColor: configs["Icon Color"]
startX: h/44; startY: h/800
PathLine { x: h*0.10227272727272727; y: h/800 }
}
ShapePath {
strokeWidth: parent.height/120
strokeColor: configs["Icon Color"]
startX: h/44; startY: h/800 + h/32
PathLine { x: h*0.10227272727272727; y: h/800 + h/32 }
}
ShapePath {
strokeWidth: parent.height/120
strokeColor: configs["Icon Color"]
startX: h/44; startY: h/800 + h/16
PathLine { x: h*0.10227272727272727; y: h/800 + h/16 }
}
}
MouseArea {
anchors.fill: parent
enabled: !styleDialog.active
onClicked: {
styleDialog.active = true;
}
}
}
Item {
id: weather
width: 0.655*w
height: h
anchors.left: parent.left
anchors.top: parent.top
Image {
id: weather_mask
anchors.centerIn: weather
autoTransform: true
visible: false
source: "../Images/Weather/" + Utils.weather_codes[output.result?.iconCode ?? "44"] + ".png"
}
Rectangle {
id: wcolor
width: h/1.1
height: h/1.1
anchors.centerIn: weather
visible: false
color: configs["Icon Color"]
}
OpacityMask {
anchors.fill: wcolor
source: wcolor
maskSource: weather_mask
}
}
Rectangle {
id: temper_box
width: 0.345*w
height: h
anchors.right: parent.right
anchors.top: parent.top
opacity: configs["Background Opacity"]*configs["Area Opacity Difference"]/10000
color: "black"
}
Text {
id: area
anchors.centerIn: temper_box
anchors.horizontalCenterOffset: temper_box.width*configs["Area Text Settings"]["X Offset"]/200
anchors.verticalCenterOffset: h*configs["Area Text Settings"]["Y Offset"]/200
color: configs["Area Text Settings"]["Font Color"]
text: configs["Display Location"]
font.pixelSize: w*0.0009*configs["Area Text Settings"]["Font Size"]
font.family: fonts[configs["Area Text Settings"]["Font Name"]]
font.weight: fontweight[configs["Area Text Settings"]["Font Weight"]]
Rectangle {
anchors.fill: parent
anchors.margins: -area.font.pixelSize*configs["Area Text Settings"]["Border Margin"]/100
color: "transparent"
border.color: configs["Area Text Settings"]["Font Color"]
border.width: area.font.pixelSize/15
radius: area.font.pixelSize/3.5
visible: Boolean(area.text)
}
}
Text {
id: temperature
anchors.centerIn: temper_box
anchors.horizontalCenterOffset: temper_box.width*configs["Temperature Text Settings"]["X Offset"]/200
anchors.verticalCenterOffset: h*configs["Temperature Text Settings"]["Y Offset"]/200
color: configs["Temperature Text Settings"]["Font Color"]
text: (output.result?.temperature ?? "--") + "°"
font.pixelSize: w*0.002*configs["Temperature Text Settings"]["Font Size"]
font.family: fonts[configs["Temperature Text Settings"]["Font Name"]]
font.weight: fontweight[configs["Temperature Text Settings"]["Font Weight"]]
}
}
menu: Menu {
Action {
text: qsTr("Settings") + "..."
onTriggered: styleDialog.active = true
}
}
Loader {
id: styleDialog
active: false
sourceComponent: NVG.Window {
id: window
title: qsTr("Settings")
visible: true
minimumWidth: 450
minimumHeight: 550
width: minimumWidth
height: minimumHeight
transientParent: widget.NVG.View.window
property var configuration
Page {
anchors.fill: parent
header: TitleBar {
text: qsTr("Settings")
standardButtons: Dialog.Save | Dialog.Reset
onAccepted: {
configuration = rootPreference.save();
widget.settings.styles = configuration;
styleDialog.active = false;
}
onReset: {
rootPreference.load({"Address": widget.settings.styles?.Address});
let cfg = rootPreference.save();
widget.settings.styles = cfg;
}
}
ColumnLayout {
id: root
anchors.fill: parent
anchors.margins: 16
anchors.topMargin: 0
Flickable {
Layout.fillWidth: true
Layout.fillHeight: true
clip: true
contentWidth: preferenceLayout.implicitWidth
contentHeight: preferenceLayout.implicitHeight
ColumnLayout {
id: preferenceLayout
width: root.width
P.PreferenceGroup {
id: rootPreference
Layout.fillWidth: true
label: qsTr("Configuration")
onPreferenceEdited: {
widget.settings.styles = rootPreference.save();
}
P.DialogPreference {
id: rootPref
label: qsTr("Location")
name: "Address"
displayValue: widget.settings.styles?.Address ? widget.settings.styles.Address.address : qsTr("Click to set location.")
load: function (newValue) {
errorLabel.visible = false;
queryField.text = "";
radioRepeater.model = newValue ? [ newValue ] : undefined;
if (radioRepeater.count)
radioColumn.children[0].checked = true;
}
save: function () {
return radioGroup.checkedButton ? radioGroup.checkedButton.location : undefined;
}
function searchLocation() {
if (!queryField.text)
return;
rootPref.enabled = false;
errorLabel.visible = false;
busyIndicator.running = true;
Private.Manager.searchLocation(queryField.text)
.then(function (result) {
radioRepeater.model = result;
if (radioRepeater.count)
radioColumn.children[0].checked = true;
}, function (err) {
console.warn(err);
errorLabel.visible = true;
radioRepeater.model = undefined;
})
.then(function () {
rootPref.enabled = true;
busyIndicator.running = false;
});
}
RowLayout {
TextField {
id: queryField
Layout.fillWidth: true
placeholderText: qsTr("Search: country, city, district...")
onAccepted: rootPref.searchLocation()
}
ToolButton {
icon.name: "regular:\uf002"
onClicked: rootPref.searchLocation()
}
}
Item {
implicitWidth: Math.max(busyIndicator.implicitWidth, radioColumn.implicitWidth)
implicitHeight: Math.max(busyIndicator.implicitHeight, radioColumn.implicitHeight)
BusyIndicator {
id: busyIndicator
anchors.centerIn: parent
running: false
}
Label {
id: errorLabel
anchors.centerIn: parent
enabled: false
visible: false
text: qsTr("Location not found")
}
ButtonGroup {
id: radioGroup
buttons: radioColumn.children
}
Column {
id: radioColumn
width: parent.width
Repeater {
id: radioRepeater
RadioButton {
readonly property var location: modelData
text: modelData.address
width: radioColumn.width
}
}
}
}
}
P.TextFieldPreference {
name: "Display Location"
label: qsTr("Display Location")
message: qsTr("The location to display in widget.")
defaultValue: defaultValues["Display Location"]
}
P.DialogPreference {
name: "Update Interval"
label: qsTr("Update Interval")
live: true
displayValue: _cfg_update_interval_value.value + " " + [qsTr("Minutes"), qsTr("Hours")][_cfg_update_interval_unit.value]
P.SpinPreference {
id: _cfg_update_interval_value
name: "Value"
from: 1
to: 1440
editable: true
defaultValue: defaultValues["Update Interval"]["Value"]
}
P.SelectPreference {
id: _cfg_update_interval_unit
name: "Unit"
label: qsTr("Unit")
defaultValue: defaultValues["Update Interval"]["Unit"]
model: [qsTr("Minutes"), qsTr("Hours")]
}
}
P.ColorPreference {
name: "Background Color"
label: qsTr("Background Color")
defaultValue: defaultValues["Background Color"]
}
P.SliderPreference {
name: "Background Opacity"
label: qsTr("Background Opacity")
from: 0
to: 100
stepSize: 1
defaultValue: defaultValues["Background Opacity"]
displayValue: value + "%"
}
P.SliderPreference {
name: "Area Opacity Difference"
label: qsTr("Area Opacity Difference")
from: 0
to: 100
stepSize: 1
defaultValue: defaultValues["Area Opacity Difference"]
displayValue: value + "%"
}
P.ColorPreference {
name: "Icon Color"
label: qsTr("Icon Color")
defaultValue: defaultValues["Icon Color"]
}
P.Separator {}
P.DialogPreference {
name: "Temperature Text Settings"
label: qsTr("Temperature Text Settings")
icon.name: "solid:\uf1fc"
live: true
P.ColorPreference {
name: "Font Color"
label: qsTr("Font Color")
defaultValue: defaultValues["Temperature Text Settings"]["Font Color"]
}
P.SliderPreference {
name: "Font Size"
label: qsTr("Font Size")
from: 1
to: 100
stepSize: 1
defaultValue: defaultValues["Temperature Text Settings"]["Font Size"]
displayValue: value + "%"
}
P.SelectPreference {
name: "Font Name"
label: qsTr("Font Style")
defaultValue: defaultValues["Temperature Text Settings"]["Font Name"]
model: fonts
}
P.SelectPreference {
name: "Font Weight"
label: qsTr("Font Weight")
defaultValue: defaultValues["Temperature Text Settings"]["Font Weight"]
model: sfontweight
}
P.SliderPreference {
name: "X Offset"
label: qsTr("X Offset")
from: -100
to: 100
stepSize: 1
defaultValue: defaultValues["Temperature Text Settings"]["X Offset"]
displayValue: value + "%"
}
P.SliderPreference {
name: "Y Offset"
label: qsTr("Y Offset")
from: -100
to: 100
stepSize: 1
defaultValue: defaultValues["Temperature Text Settings"]["Y Offset"]
displayValue: value + "%"
}
}
P.DialogPreference {
name: "Area Text Settings"
label: qsTr("Area Text Settings")
icon.name: "solid:\uf1fc"
live: true
P.ColorPreference {
name: "Font Color"
label: qsTr("Font Color")
defaultValue: defaultValues["Area Text Settings"]["Font Color"]
}
P.SliderPreference {
name: "Font Size"
label: qsTr("Font Size")
from: 1
to: 100
stepSize: 1
defaultValue: defaultValues["Area Text Settings"]["Font Size"]
displayValue: value + "%"
}
P.SelectPreference {
name: "Font Name"
label: qsTr("Font Style")
defaultValue: defaultValues["Area Text Settings"]["Font Name"]
model: fonts
}
P.SelectPreference {
name: "Font Weight"
label: qsTr("Font Weight")
defaultValue: defaultValues["Area Text Settings"]["Font Weight"]
model: sfontweight
}
P.SliderPreference {
name: "X Offset"
label: qsTr("X Offset")
from: -100
to: 100
stepSize: 1
defaultValue: defaultValues["Area Text Settings"]["X Offset"]
displayValue: value + "%"
}
P.SliderPreference {
name: "Y Offset"
label: qsTr("Y Offset")
from: -100
to: 100
stepSize: 1
defaultValue: defaultValues["Area Text Settings"]["Y Offset"]
displayValue: value + "%"
}
P.SliderPreference {
name: "Border Margin"
label: qsTr("Border Margin")
from: 0
to: 100
stepSize: 1
defaultValue: defaultValues["Area Text Settings"]["Border Margin"]
displayValue: value + "%"
}
}
Component.onCompleted: {
if(!widget.settings.styles) {
configuration = rootPreference.save();
widget.settings.styles = configuration;
}
rootPreference.load(widget.settings.styles);
configuration = widget.settings.styles;
}
}
}
}
}
}
onClosing: {
widget.settings.styles = configuration;
styleDialog.active = false;
}
}
}
}