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