initial push
BIN
Images/Weather/Cloudy.png
Normal file
After Width: | Height: | Size: 4.9 KiB |
BIN
Images/Weather/Fog.png
Normal file
After Width: | Height: | Size: 4.6 KiB |
BIN
Images/Weather/HeavyRain.png
Normal file
After Width: | Height: | Size: 6.1 KiB |
BIN
Images/Weather/HeavySnow.png
Normal file
After Width: | Height: | Size: 5.3 KiB |
BIN
Images/Weather/LightRain.png
Normal file
After Width: | Height: | Size: 5.6 KiB |
BIN
Images/Weather/LightSleet.png
Normal file
After Width: | Height: | Size: 6.2 KiB |
BIN
Images/Weather/LightSnow.png
Normal file
After Width: | Height: | Size: 5.3 KiB |
BIN
Images/Weather/PartlyCloudy.png
Normal file
After Width: | Height: | Size: 4.1 KiB |
BIN
Images/Weather/Showers.png
Normal file
After Width: | Height: | Size: 5.4 KiB |
BIN
Images/Weather/SnowShowers.png
Normal file
After Width: | Height: | Size: 5.7 KiB |
BIN
Images/Weather/Sunny.png
Normal file
After Width: | Height: | Size: 3.9 KiB |
BIN
Images/Weather/ThunderyHeavyRain.png
Normal file
After Width: | Height: | Size: 6.2 KiB |
BIN
Images/Weather/ThunderyShowers.png
Normal file
After Width: | Height: | Size: 5.4 KiB |
BIN
Images/Weather/Unknown.png
Normal file
After Width: | Height: | Size: 8.9 KiB |
BIN
Images/Weather/VeryCloudy.png
Normal file
After Width: | Height: | Size: 5.4 KiB |
4
Presets/TopUI/preset.json
Normal file
@ -0,0 +1,4 @@
|
||||
{
|
||||
"source": "nvg://ordinalscale.widget.mashiros.top/widget/topui",
|
||||
"settings": "settings.xml"
|
||||
}
|
BIN
Presets/TopUI/preview.png
Normal file
After Width: | Height: | Size: 23 KiB |
4
Presets/TopUI/settings.xml
Normal file
@ -0,0 +1,4 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<map>
|
||||
<value name="styles">{"Circle Color":"#fffcf9","Line Color":"#fffcf9","Line Width":38,"Shadow Color":"#e0e0e0","Shadow Size":0.5,"Battle UI":true,"Clock Visible":true,"Full Clock":true,"Font Color":"#f5f5f5","Font Size":44,"Font Name":0,"Font Weight":0,"Text Vertical Offset":16}</value>
|
||||
</map>
|
BIN
Previews/BottomUI.png
Normal file
After Width: | Height: | Size: 2.7 KiB |
BIN
Previews/TopUI.png
Normal file
After Width: | Height: | Size: 22 KiB |
BIN
Previews/Weather.png
Normal file
After Width: | Height: | Size: 11 KiB |
77
package.json
Normal file
@ -0,0 +1,77 @@
|
||||
{
|
||||
"name": "top.mashiros.widget.ordinalscale",
|
||||
"version": "1.0.0",
|
||||
|
||||
"title": {
|
||||
"en": "Ordinal Scale Widget Collections",
|
||||
"zh": "序列之争挂件合集"
|
||||
},
|
||||
|
||||
"description": {
|
||||
"en": "A collection of Ordinal Scale widget for SAO Utils 2, including top line, bottom line and weather widget with rich configuration options.",
|
||||
"zh": "用于SAO Utils 2的序列之争挂件合集,包含顶部、底部线与天气挂件,并提供丰富的配置选项。"
|
||||
},
|
||||
|
||||
"homepage": "https://nvg.dev/Mashiro_Sorata/ordinal-scale-widgets",
|
||||
|
||||
"bugs": {
|
||||
"email": "mashiro_sorata@qq.com",
|
||||
"url": "https://nvg.dev/Mashiro_Sorata/ordinal-scale-widgets/issues"
|
||||
},
|
||||
|
||||
|
||||
"author": {
|
||||
"name": "Mashiro_Sorata",
|
||||
"email": "mashiro_sorata@qq.com",
|
||||
"url": "http://www.mashiros.top/"
|
||||
},
|
||||
|
||||
"engines": {
|
||||
"qt": "~5",
|
||||
"qt.quick": ">=2.12",
|
||||
"nvg.api": "~1"
|
||||
},
|
||||
|
||||
"resources": [
|
||||
{
|
||||
"location": "/widget/topui",
|
||||
"catalog": "widget",
|
||||
"title": {
|
||||
"en": "Ordinal Scale Top UI",
|
||||
"zh": "序列之争顶部UI"
|
||||
},
|
||||
"preview": "Previews/TopUI.png",
|
||||
"entry": "qml/TopUI.qml"
|
||||
},
|
||||
{
|
||||
"location": "/widget/bottomui",
|
||||
"catalog": "widget",
|
||||
"title": {
|
||||
"en": "Ordinal Scale Bottom UI",
|
||||
"zh": "序列之争底部UI"
|
||||
},
|
||||
"preview": "Previews/BottomUI.png",
|
||||
"entry": "qml/BottomUI.qml"
|
||||
},
|
||||
{
|
||||
"location": "/widget/weather",
|
||||
"catalog": "widget",
|
||||
"title": {
|
||||
"en": "Ordinal Scale Weather Widget",
|
||||
"zh": "序列之争天气挂件"
|
||||
},
|
||||
"preview": "Previews/Weather.png",
|
||||
"entry": "qml/WeatherWidget.qml"
|
||||
},
|
||||
{
|
||||
"location": "/preset/widget/topui",
|
||||
"catalog": "preset/widget",
|
||||
"title": {
|
||||
"en": "Ordinal Scale Top Battle UI",
|
||||
"zh": "序列之争顶部战斗UI"
|
||||
},
|
||||
"preview": "Presets/TopUI/preview.png",
|
||||
"entry": "Presets/TopUI/preset.json"
|
||||
}
|
||||
]
|
||||
}
|
208
qml/BottomUI.qml
Normal file
@ -0,0 +1,208 @@
|
||||
import QtQuick 2.12
|
||||
import QtQuick.Controls 2.12
|
||||
import QtQuick.Layouts 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
|
||||
|
||||
T.Widget {
|
||||
id: widget
|
||||
solid: true
|
||||
visible: true
|
||||
title: qsTr("Ordinal Scale Bottom UI widget")
|
||||
|
||||
property real thour: 0
|
||||
property real t12hour: 0
|
||||
property real tmin: 0
|
||||
editing: styleDialog.active
|
||||
|
||||
readonly property var configs: widget.settings.styles ? widget.settings.styles : {"Circle Color":"#fffcf9","Line Color":"#fffcf9","Line Width":38,"Shadow Color":"#e0e0e0","Shadow Size":0.5,"Battle UI":false,"Clock Visible":true,"Full Clock":true,"Font Color":"#f5f5f5","Font Size":44,"Font Name":0,"Font Weight":0,"Text Vertical Offset":16}
|
||||
|
||||
property string line_color: configs["Line Color"]
|
||||
property string shadowColor: configs["Shadow Color"]
|
||||
property real shadowBlur: configs["Shadow Size"]
|
||||
|
||||
readonly property real h: Math.min(widget.width, widget.height)
|
||||
readonly property real w: widget.width
|
||||
readonly property real r: (w**2+4*h**2)/2/h
|
||||
|
||||
property real triangle_size: 24
|
||||
|
||||
Canvas {
|
||||
id: triangle
|
||||
anchors.centerIn: parent
|
||||
anchors.verticalCenterOffset: height/2
|
||||
width: triangle_size
|
||||
height: triangle_size*Math.sin(Math.PI/6)
|
||||
contextType: "2d"
|
||||
onPaint: {
|
||||
context.reset();
|
||||
context.clearRect(0,0,width,height);
|
||||
context.shadowBlur = shadowBlur;
|
||||
context.shadowColor = shadowColor;
|
||||
context.lineWidth = Math.max(0.08*configs["Line Width"] - shadowBlur, 0.1);
|
||||
context.strokeStyle = line_color;
|
||||
context.beginPath();
|
||||
context.moveTo(0,0);
|
||||
context.lineTo(width/2, height);
|
||||
context.lineTo(width, 0);
|
||||
context.lineTo(0, 0);
|
||||
context.fillStyle = line_color;
|
||||
context.fill();
|
||||
}
|
||||
}
|
||||
|
||||
Canvas {
|
||||
id: line
|
||||
anchors.centerIn: parent
|
||||
width: widget.width
|
||||
height: widget.height
|
||||
contextType: "2d"
|
||||
onPaint: {
|
||||
context.reset();
|
||||
context.clearRect(0,0,width,height);
|
||||
context.shadowBlur = shadowBlur;
|
||||
context.shadowColor = shadowColor;
|
||||
context.lineWidth = Math.max(0.08*configs["Line Width"] - shadowBlur, 0.1);
|
||||
context.strokeStyle = line_color;
|
||||
let deg = Math.asin(w/2/r)*0.95;
|
||||
context.beginPath();
|
||||
context.arc(w/2, r+h/2, r-shadowBlur/2, deg+Math.PI*3/2, -deg+Math.PI*3/2, true);
|
||||
context.stroke();
|
||||
}
|
||||
}
|
||||
|
||||
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: 380
|
||||
minimumHeight: 500
|
||||
width: minimumWidth
|
||||
height: minimumHeight
|
||||
|
||||
transientParent: widget.NVG.View.window
|
||||
|
||||
property var configuration
|
||||
|
||||
Page {
|
||||
id: cfg_page
|
||||
anchors.fill: parent
|
||||
|
||||
header: TitleBar {
|
||||
text: qsTr("UI Settings")
|
||||
|
||||
standardButtons: Dialog.Save | Dialog.Reset
|
||||
|
||||
onAccepted: {
|
||||
configuration = rootPreference.save();
|
||||
widget.settings.styles = configuration;
|
||||
styleDialog.active = false;
|
||||
}
|
||||
|
||||
onReset: {
|
||||
rootPreference.load();
|
||||
let cfg = rootPreference.save();
|
||||
widget.settings.styles = cfg;
|
||||
line.requestPaint();
|
||||
triangle.requestPaint();
|
||||
}
|
||||
}
|
||||
|
||||
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();
|
||||
line.requestPaint();
|
||||
triangle.requestPaint();
|
||||
}
|
||||
|
||||
P.ColorPreference {
|
||||
name: "Line Color"
|
||||
label: qsTr("Line Color")
|
||||
defaultValue: "#fffcf9"
|
||||
}
|
||||
|
||||
P.SliderPreference {
|
||||
name: "Line Width"
|
||||
label: qsTr("Line Width")
|
||||
from: 1
|
||||
to: 100
|
||||
stepSize: 1
|
||||
defaultValue: 38
|
||||
displayValue: value + "%"
|
||||
}
|
||||
|
||||
P.ColorPreference {
|
||||
name: "Shadow Color"
|
||||
label: qsTr("Shadow Color")
|
||||
defaultValue: "#e0e0e0"
|
||||
}
|
||||
|
||||
P.SliderPreference {
|
||||
name: "Shadow Size"
|
||||
label: qsTr("Shadow Size")
|
||||
from: 0
|
||||
to: 3
|
||||
stepSize: 0.1
|
||||
defaultValue: 0.5
|
||||
displayValue: Math.round(value*10)/10 + "px"
|
||||
}
|
||||
|
||||
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;
|
||||
line.requestPaint();
|
||||
triangle.requestPaint();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
520
qml/TopUI.qml
Normal file
@ -0,0 +1,520 @@
|
||||
import QtQuick 2.12
|
||||
import QtQuick.Controls 2.12
|
||||
import QtQuick.Layouts 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
|
||||
|
||||
T.Widget {
|
||||
id: widget
|
||||
solid: true
|
||||
visible: true
|
||||
title: qsTr("Ordinal Scale Top UI widget")
|
||||
|
||||
property real thour: 0
|
||||
property real t12hour: 0
|
||||
property real tmin: 0
|
||||
editing: styleDialog.active
|
||||
|
||||
readonly property var configs: widget.settings.styles ? widget.settings.styles : {"Circle Color":"#fffcf9","Line Color":"#fffcf9","Line Width":38,"Shadow Color":"#e0e0e0","Shadow Size":0.5,"Battle UI":false,"Clock Visible":true,"Full Clock":true,"Font Color":"#f5f5f5","Font Size":44,"Font Name":0,"Font Weight":0,"Text Vertical Offset":16}
|
||||
|
||||
property string circle_color: configs["Circle Color"]
|
||||
property string line_color: configs["Line Color"]
|
||||
property string shadowColor: configs["Shadow Color"]
|
||||
property real shadowBlur: configs["Shadow Size"]
|
||||
readonly property real size: 155
|
||||
|
||||
readonly property real h: Math.min(widget.width, widget.height)
|
||||
readonly property real w: widget.width
|
||||
readonly property real r: (w**2+h**2)/4/h
|
||||
|
||||
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")]
|
||||
|
||||
Timer {
|
||||
interval: 250
|
||||
running: text_clock.visible
|
||||
repeat: true
|
||||
onTriggered: {
|
||||
var now = new Date();
|
||||
tmin = now.getMinutes();
|
||||
thour = now.getHours();
|
||||
if (!configs["Full Clock"])
|
||||
t12hour = thour > 12 ? thour - 12 : thour;
|
||||
}
|
||||
}
|
||||
|
||||
Text {
|
||||
id: text_clock
|
||||
anchors.top: parent.top
|
||||
anchors.topMargin: widget.height/200*configs["Text Vertical Offset"]
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
color: configs["Font Color"]
|
||||
text: configs["Full Clock"] ? ("0"+thour).slice(-2) + ":" + ("0"+tmin).slice(-2) : ("0"+t12hour).slice(-2) + ":" + ("0"+tmin).slice(-2)
|
||||
font.pointSize: widget.height/200*configs["Font Size"]
|
||||
font.family: fonts[configs["Font Name"]]
|
||||
font.weight: fontweight[configs["Font Weight"]]
|
||||
visible: widget.NVG.View.exposed && !configs["Battle UI"] && configs["Clock Visible"]
|
||||
}
|
||||
|
||||
Item {
|
||||
id: circle
|
||||
anchors.centerIn: parent
|
||||
anchors.verticalCenterOffset: -2.5
|
||||
scale: widget.height/size/1.25
|
||||
visible: widget.NVG.View.exposed && configs["Battle UI"]
|
||||
|
||||
Canvas {
|
||||
id: c1
|
||||
anchors.centerIn: parent
|
||||
width: size
|
||||
height: size
|
||||
contextType: "2d"
|
||||
renderTarget: Canvas.FramebufferObject
|
||||
renderStrategy: Canvas.Cooperative
|
||||
onPaint: {
|
||||
context.reset();
|
||||
context.clearRect(0,0,size,size);
|
||||
context.shadowBlur = shadowBlur;
|
||||
context.shadowColor = shadowColor;
|
||||
context.lineWidth = size*0.04 - shadowBlur;
|
||||
context.beginPath();
|
||||
context.arc(size/2, size/2, size*0.38-shadowBlur/2, -Math.PI/6, -Math.PI/6+Math.PI*2/3 , true);
|
||||
context.strokeStyle = circle_color;
|
||||
context.stroke();
|
||||
}
|
||||
rotation: -140
|
||||
SequentialAnimation on rotation {
|
||||
running: circle.visible
|
||||
loops: Animation.Infinite
|
||||
RotationAnimation {
|
||||
duration: 1250
|
||||
easing.type: Easing.InOutCubic
|
||||
from: -140
|
||||
to: 220
|
||||
}
|
||||
RotationAnimation {
|
||||
duration: 1250
|
||||
easing.type: Easing.InOutCubic
|
||||
from: 220
|
||||
to: -140
|
||||
direction: RotationAnimation.Counterclockwise
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Canvas {
|
||||
id: c2
|
||||
anchors.centerIn: parent
|
||||
width: size
|
||||
height: size
|
||||
contextType: "2d"
|
||||
renderTarget: Canvas.FramebufferObject
|
||||
renderStrategy: Canvas.Cooperative
|
||||
onPaint: {
|
||||
context.reset();
|
||||
context.clearRect(0,0,size,size);
|
||||
context.shadowBlur = shadowBlur;
|
||||
context.shadowColor = shadowColor;
|
||||
context.lineWidth = size*0.08 - shadowBlur;
|
||||
context.beginPath();
|
||||
context.arc(size/2, size/2, size*0.30-shadowBlur/2, -Math.PI/6, -Math.PI/24+Math.PI*2/3 , true);
|
||||
context.strokeStyle = circle_color;
|
||||
context.stroke();
|
||||
}
|
||||
rotation: 20
|
||||
NumberAnimation on rotation {
|
||||
duration: 2800
|
||||
easing.type: Easing.Linear
|
||||
from: 20
|
||||
to: 380
|
||||
loops: Animation.Infinite
|
||||
running: circle.visible
|
||||
}
|
||||
}
|
||||
|
||||
Canvas {
|
||||
id: c3
|
||||
anchors.centerIn: parent
|
||||
width: size
|
||||
height: size
|
||||
contextType: "2d"
|
||||
renderTarget: Canvas.FramebufferObject
|
||||
renderStrategy: Canvas.Cooperative
|
||||
onPaint: {
|
||||
context.reset();
|
||||
context.clearRect(0,0,size,size);
|
||||
context.shadowBlur = shadowBlur;
|
||||
context.shadowColor = shadowColor;
|
||||
context.lineWidth = size*0.03 - shadowBlur;
|
||||
context.beginPath();
|
||||
context.arc(size/2, size/2, size*0.23-shadowBlur/2, -Math.PI/6, Math.PI/12+Math.PI*2/3 , true);
|
||||
context.strokeStyle = circle_color;
|
||||
context.stroke();
|
||||
}
|
||||
rotation: 90
|
||||
NumberAnimation on rotation {
|
||||
duration: 2000
|
||||
easing.type: Easing.Linear
|
||||
from: 90
|
||||
to: -270
|
||||
loops: Animation.Infinite
|
||||
running: circle.visible
|
||||
}
|
||||
}
|
||||
|
||||
Canvas {
|
||||
id: c4
|
||||
anchors.centerIn: parent
|
||||
width: size
|
||||
height: size
|
||||
contextType: "2d"
|
||||
renderTarget: Canvas.FramebufferObject
|
||||
renderStrategy: Canvas.Cooperative
|
||||
onPaint: {
|
||||
context.reset();
|
||||
context.clearRect(0,0,size,size);
|
||||
context.shadowBlur = shadowBlur;
|
||||
context.shadowColor = shadowColor;
|
||||
context.lineWidth = size*0.06 - shadowBlur;
|
||||
context.beginPath();
|
||||
context.arc(size/2, size/2, size*0.17-shadowBlur/2, -Math.PI/6, Math.PI/4+Math.PI*2/3 , true);
|
||||
context.strokeStyle = circle_color;
|
||||
context.stroke();
|
||||
}
|
||||
rotation: -70
|
||||
SequentialAnimation on rotation {
|
||||
running: circle.visible
|
||||
loops: Animation.Infinite
|
||||
RotationAnimation {
|
||||
duration: 1150
|
||||
easing.type: Easing.InOutCubic
|
||||
from: -70
|
||||
to: 290
|
||||
}
|
||||
RotationAnimation {
|
||||
duration: 1150
|
||||
easing.type: Easing.InOutCubic
|
||||
from: 290
|
||||
to: -70
|
||||
direction: RotationAnimation.Counterclockwise
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Canvas {
|
||||
id: c5
|
||||
anchors.centerIn: parent
|
||||
width: size
|
||||
height: size
|
||||
contextType: "2d"
|
||||
renderTarget: Canvas.FramebufferObject
|
||||
renderStrategy: Canvas.Cooperative
|
||||
onPaint: {
|
||||
context.reset();
|
||||
context.clearRect(0,0,size,size);
|
||||
context.shadowBlur = shadowBlur;
|
||||
context.shadowColor = shadowColor;
|
||||
context.lineWidth = size*0.1 - shadowBlur;
|
||||
context.beginPath();
|
||||
context.arc(size/2, size/2, size*0.05-shadowBlur/2, 0, -Math.PI*2 , true);
|
||||
context.strokeStyle = circle_color;
|
||||
context.stroke();
|
||||
}
|
||||
}
|
||||
|
||||
Canvas {
|
||||
id: c0
|
||||
anchors.centerIn: parent
|
||||
width: size
|
||||
height: size
|
||||
contextType: "2d"
|
||||
renderTarget: Canvas.FramebufferObject
|
||||
renderStrategy: Canvas.Cooperative
|
||||
onPaint: {
|
||||
context.reset();
|
||||
context.clearRect(0,0,size,size);
|
||||
context.shadowBlur = shadowBlur;
|
||||
context.shadowColor = shadowColor;
|
||||
context.lineWidth = size*0.16 - shadowBlur;
|
||||
context.beginPath();
|
||||
context.arc(size/2, size/2, size*0.38-shadowBlur/2, 0, -Math.PI/3 , true);
|
||||
context.strokeStyle = circle_color;
|
||||
context.stroke();
|
||||
}
|
||||
|
||||
NumberAnimation on rotation {
|
||||
duration: 1500
|
||||
easing.type: Easing.Linear
|
||||
from: 0
|
||||
to: 360
|
||||
loops: Animation.Infinite
|
||||
running: circle.visible
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Canvas {
|
||||
id: line
|
||||
anchors.centerIn: parent
|
||||
width: widget.width
|
||||
height: widget.height
|
||||
contextType: "2d"
|
||||
onPaint: {
|
||||
context.reset();
|
||||
context.clearRect(0,0,width,height);
|
||||
context.shadowBlur = shadowBlur;
|
||||
context.shadowColor = shadowColor;
|
||||
context.lineWidth = Math.max(0.08*configs["Line Width"] - shadowBlur, 0.1);
|
||||
context.strokeStyle = line_color;
|
||||
let deg = Math.asin(w/2/r)*0.95;
|
||||
context.beginPath();
|
||||
if (circle.visible) {
|
||||
context.arc(w/2, -r+h/2, r-shadowBlur/2, deg+Math.PI/2, Math.PI/2+circle.scale*size/1.22/r, true);
|
||||
context.stroke();
|
||||
context.beginPath();
|
||||
context.arc(w/2, -r+h/2, r-shadowBlur/2, -deg+Math.PI/2, Math.PI/2-circle.scale*size/1.22/r, false);
|
||||
context.stroke();
|
||||
} else {
|
||||
context.arc(w/2, -r+h/2, r-shadowBlur/2, deg+Math.PI/2, -deg+Math.PI/2, true);
|
||||
context.stroke();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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: 380
|
||||
minimumHeight: 500
|
||||
width: minimumWidth
|
||||
height: minimumHeight
|
||||
|
||||
transientParent: widget.NVG.View.window
|
||||
|
||||
property var configuration
|
||||
|
||||
Page {
|
||||
id: cfg_page
|
||||
anchors.fill: parent
|
||||
|
||||
header: TitleBar {
|
||||
text: qsTr("UI Settings")
|
||||
|
||||
standardButtons: Dialog.Save | Dialog.Reset
|
||||
|
||||
onAccepted: {
|
||||
configuration = rootPreference.save();
|
||||
widget.settings.styles = configuration;
|
||||
styleDialog.active = false;
|
||||
}
|
||||
|
||||
onReset: {
|
||||
rootPreference.load();
|
||||
let cfg = rootPreference.save();
|
||||
widget.settings.styles = cfg;
|
||||
line.requestPaint();
|
||||
c0.requestPaint();
|
||||
c1.requestPaint();
|
||||
c2.requestPaint();
|
||||
c3.requestPaint();
|
||||
c4.requestPaint();
|
||||
c5.requestPaint();
|
||||
}
|
||||
}
|
||||
|
||||
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();
|
||||
line.requestPaint();
|
||||
c0.requestPaint();
|
||||
c1.requestPaint();
|
||||
c2.requestPaint();
|
||||
c3.requestPaint();
|
||||
c4.requestPaint();
|
||||
c5.requestPaint();
|
||||
}
|
||||
|
||||
P.ColorPreference {
|
||||
name: "Circle Color"
|
||||
label: qsTr("Circle Color")
|
||||
defaultValue: "#fffcf9"
|
||||
}
|
||||
|
||||
P.ColorPreference {
|
||||
name: "Line Color"
|
||||
label: qsTr("Line Color")
|
||||
defaultValue: "#fffcf9"
|
||||
}
|
||||
|
||||
P.SliderPreference {
|
||||
name: "Line Width"
|
||||
label: qsTr("Line Width")
|
||||
from: 1
|
||||
to: 100
|
||||
stepSize: 1
|
||||
defaultValue: 38
|
||||
displayValue: value + "%"
|
||||
}
|
||||
|
||||
P.ColorPreference {
|
||||
name: "Shadow Color"
|
||||
label: qsTr("Shadow Color")
|
||||
defaultValue: "#e0e0e0"
|
||||
}
|
||||
|
||||
P.SliderPreference {
|
||||
name: "Shadow Size"
|
||||
label: qsTr("Shadow Size")
|
||||
from: 0
|
||||
to: 3
|
||||
stepSize: 0.1
|
||||
defaultValue: 0.5
|
||||
displayValue: Math.round(value*10)/10 + "px"
|
||||
}
|
||||
|
||||
P.Separator {}
|
||||
|
||||
P.SwitchPreference {
|
||||
id: _cfg_battle_ui
|
||||
name: "Battle UI"
|
||||
label: qsTr("Battle UI")
|
||||
defaultValue: false
|
||||
}
|
||||
|
||||
P.Separator {}
|
||||
|
||||
P.SwitchPreference {
|
||||
id: _cfg_clock_visible
|
||||
name: "Clock Visible"
|
||||
label: qsTr("Clock Visible")
|
||||
visible: !_cfg_battle_ui.value
|
||||
enabled: visible
|
||||
defaultValue: true
|
||||
}
|
||||
|
||||
P.SwitchPreference {
|
||||
name: "Full Clock"
|
||||
label: qsTr("24 Hour Clock")
|
||||
visible: !_cfg_battle_ui.value
|
||||
enabled: visible && _cfg_clock_visible.value
|
||||
defaultValue: true
|
||||
}
|
||||
|
||||
P.ColorPreference {
|
||||
name: "Font Color"
|
||||
label: qsTr("Font Color")
|
||||
visible: !_cfg_battle_ui.value
|
||||
enabled: visible && _cfg_clock_visible.value
|
||||
defaultValue: "#f5f5f5"
|
||||
}
|
||||
|
||||
P.SliderPreference {
|
||||
name: "Font Size"
|
||||
label: qsTr("Font Size")
|
||||
visible: !_cfg_battle_ui.value
|
||||
enabled: visible && _cfg_clock_visible.value
|
||||
from: 1
|
||||
to: 100
|
||||
stepSize: 1
|
||||
defaultValue: 44
|
||||
displayValue: value + "%"
|
||||
}
|
||||
|
||||
P.SelectPreference {
|
||||
name: "Font Name"
|
||||
label: qsTr("Font Style")
|
||||
visible: !_cfg_battle_ui.value
|
||||
enabled: visible && _cfg_clock_visible.value
|
||||
icon.name: "solid:\uf1fc"
|
||||
defaultValue: 0
|
||||
model: fonts
|
||||
}
|
||||
|
||||
P.SelectPreference {
|
||||
name: "Font Weight"
|
||||
label: qsTr("Font Weight")
|
||||
visible: !_cfg_battle_ui.value
|
||||
enabled: visible && _cfg_clock_visible.value
|
||||
icon.name: "solid:\uf1fc"
|
||||
defaultValue: 0
|
||||
model: sfontweight
|
||||
}
|
||||
|
||||
P.SliderPreference {
|
||||
name: "Text Vertical Offset"
|
||||
label: qsTr("Text Vertical Offset")
|
||||
visible: !_cfg_battle_ui.value
|
||||
enabled: visible && _cfg_clock_visible.value
|
||||
from: -100
|
||||
to: 100
|
||||
stepSize: 1
|
||||
defaultValue: 16
|
||||
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;
|
||||
line.requestPaint();
|
||||
c0.requestPaint();
|
||||
c1.requestPaint();
|
||||
c2.requestPaint();
|
||||
c3.requestPaint();
|
||||
c4.requestPaint();
|
||||
c5.requestPaint();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
509
qml/WeatherWidget.qml
Normal file
@ -0,0 +1,509 @@
|
||||
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 "utils.js" as Utils
|
||||
|
||||
T.Widget {
|
||||
id: widget
|
||||
|
||||
title: qsTr("Weather Widget")
|
||||
solid: true
|
||||
|
||||
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 var configs: widget.settings.styles ?? {"Location":"","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}}
|
||||
|
||||
readonly property real w: widget.width
|
||||
readonly property real h: 0.46*widget.width
|
||||
|
||||
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/Unknown.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: ""
|
||||
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: "--°"
|
||||
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"]]
|
||||
}
|
||||
}
|
||||
|
||||
function setWeather() {
|
||||
var xhr = new XMLHttpRequest();
|
||||
xhr.onreadystatechange = function() {
|
||||
if(xhr.readyState === XMLHttpRequest.DONE) {
|
||||
let data = xhr.responseText.toString();
|
||||
if (data) {
|
||||
let jdata = JSON.parse(data);
|
||||
temperature.text = jdata["current_condition"][0]["temp_C"] + "°";
|
||||
if (!configs["Display Location"] && !configs["Location"]) {
|
||||
area.text = jdata["nearest_area"][0]["areaName"][0]["value"];
|
||||
}
|
||||
weather_mask.source = "../Images/Weather/" + Utils.weather_codes[jdata["current_condition"][0]["weatherCode"]] ?? "Unknown" + ".png";
|
||||
} else {
|
||||
weather_mask.source = "../Images/Weather/Unknown.png";
|
||||
}
|
||||
}
|
||||
}
|
||||
if (configs["Location"])
|
||||
xhr.open("GET", 'https://wttr.in/'+configs["Location"]+'?format=j1');
|
||||
else
|
||||
xhr.open("GET", 'https://wttr.in/?format=j1');
|
||||
xhr.send();
|
||||
if (configs["Display Location"]) {
|
||||
area.text = configs["Display Location"];
|
||||
} else if (configs["Location"]) {
|
||||
area.text = configs["Location"]
|
||||
}
|
||||
}
|
||||
|
||||
Timer {
|
||||
id: timer
|
||||
interval: 600000
|
||||
running: widget.NVG.View.exposed
|
||||
repeat: true
|
||||
triggeredOnStart: true
|
||||
onTriggered: {
|
||||
setWeather();
|
||||
}
|
||||
}
|
||||
|
||||
menu: Menu {
|
||||
Action {
|
||||
text: qsTr("Settings") + "..."
|
||||
onTriggered: styleDialog.active = true
|
||||
}
|
||||
|
||||
Action {
|
||||
text: qsTr("Refresh")
|
||||
onTriggered: timer.restart()
|
||||
}
|
||||
}
|
||||
|
||||
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 {
|
||||
id: cfg_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;
|
||||
timer.interval = 60000*configs["Update Interval"]["Value"]*(1+59*configs["Update Interval"]["Unit"])
|
||||
setWeather();
|
||||
}
|
||||
|
||||
onReset: {
|
||||
rootPreference.load();
|
||||
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.TextFieldPreference {
|
||||
name: "Location"
|
||||
label: qsTr("Location")
|
||||
message: qsTr("Search address by location, latitude and longitude.")
|
||||
}
|
||||
|
||||
P.TextFieldPreference {
|
||||
name: "Display Location"
|
||||
label: qsTr("Display Location")
|
||||
message: "The location to display in widget."
|
||||
}
|
||||
|
||||
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: 1
|
||||
}
|
||||
|
||||
P.SelectPreference {
|
||||
id: _cfg_update_interval_unit
|
||||
name: "Unit"
|
||||
label: qsTr("Unit")
|
||||
defaultValue: 1
|
||||
model: [qsTr("Minutes"), qsTr("Hours")]
|
||||
}
|
||||
}
|
||||
|
||||
P.ColorPreference {
|
||||
name: "Background Color"
|
||||
label: qsTr("Background Color")
|
||||
defaultValue: "#ffa502"
|
||||
}
|
||||
|
||||
P.SliderPreference {
|
||||
name: "Background Opacity"
|
||||
label: qsTr("Background Opacity")
|
||||
from: 0
|
||||
to: 100
|
||||
stepSize: 1
|
||||
defaultValue: 60
|
||||
displayValue: value + "%"
|
||||
}
|
||||
|
||||
P.SliderPreference {
|
||||
name: "Area Opacity Difference"
|
||||
label: qsTr("Area Opacity Difference")
|
||||
from: 0
|
||||
to: 100
|
||||
stepSize: 1
|
||||
defaultValue: 17
|
||||
displayValue: value + "%"
|
||||
}
|
||||
|
||||
P.ColorPreference {
|
||||
name: "Icon Color"
|
||||
label: qsTr("Icon Color")
|
||||
defaultValue: "#fefefe"
|
||||
}
|
||||
|
||||
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: "#f5f5f5"
|
||||
}
|
||||
|
||||
P.SliderPreference {
|
||||
name: "Font Size"
|
||||
label: qsTr("Font Size")
|
||||
from: 1
|
||||
to: 100
|
||||
stepSize: 1
|
||||
defaultValue: 90
|
||||
displayValue: value + "%"
|
||||
}
|
||||
|
||||
P.SelectPreference {
|
||||
name: "Font Name"
|
||||
label: qsTr("Font Style")
|
||||
defaultValue: fonts.length-1
|
||||
model: fonts
|
||||
}
|
||||
|
||||
P.SelectPreference {
|
||||
name: "Font Weight"
|
||||
label: qsTr("Font Weight")
|
||||
defaultValue: 1
|
||||
model: sfontweight
|
||||
}
|
||||
|
||||
P.SliderPreference {
|
||||
name: "X Offset"
|
||||
label: qsTr("X Offset")
|
||||
from: -100
|
||||
to: 100
|
||||
stepSize: 1
|
||||
defaultValue: 33
|
||||
displayValue: value + "%"
|
||||
}
|
||||
|
||||
P.SliderPreference {
|
||||
name: "Y Offset"
|
||||
label: qsTr("Y Offset")
|
||||
from: -100
|
||||
to: 100
|
||||
stepSize: 1
|
||||
defaultValue: 32
|
||||
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: "#f5f5f5"
|
||||
}
|
||||
|
||||
P.SliderPreference {
|
||||
name: "Font Size"
|
||||
label: qsTr("Font Size")
|
||||
from: 1
|
||||
to: 100
|
||||
stepSize: 1
|
||||
defaultValue: 60
|
||||
displayValue: value + "%"
|
||||
}
|
||||
|
||||
P.SelectPreference {
|
||||
name: "Font Name"
|
||||
label: qsTr("Font Style")
|
||||
defaultValue: fonts.length-1
|
||||
model: fonts
|
||||
}
|
||||
|
||||
P.SelectPreference {
|
||||
name: "Font Weight"
|
||||
label: qsTr("Font Weight")
|
||||
defaultValue: 1
|
||||
model: sfontweight
|
||||
}
|
||||
|
||||
P.SliderPreference {
|
||||
name: "X Offset"
|
||||
label: qsTr("X Offset")
|
||||
from: -100
|
||||
to: 100
|
||||
stepSize: 1
|
||||
defaultValue: 0
|
||||
displayValue: value + "%"
|
||||
}
|
||||
|
||||
P.SliderPreference {
|
||||
name: "Y Offset"
|
||||
label: qsTr("Y Offset")
|
||||
from: -100
|
||||
to: 100
|
||||
stepSize: 1
|
||||
defaultValue: -56
|
||||
displayValue: value + "%"
|
||||
}
|
||||
|
||||
P.SliderPreference {
|
||||
name: "Border Margin"
|
||||
label: qsTr("Border Margin")
|
||||
from: 0
|
||||
to: 100
|
||||
stepSize: 1
|
||||
defaultValue: 40
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
53
qml/utils.js
Normal file
@ -0,0 +1,53 @@
|
||||
.pragma library
|
||||
|
||||
// https://github.com/chubin/wttr.in/blob/master/lib/constants.py
|
||||
var weather_codes = {
|
||||
"113": "Sunny",
|
||||
"116": "PartlyCloudy",
|
||||
"119": "Cloudy",
|
||||
"122": "VeryCloudy",
|
||||
"143": "Fog",
|
||||
"176": "Showers",
|
||||
"179": "LightSleet",
|
||||
"182": "LightSleet",
|
||||
"185": "LightSleet",
|
||||
"200": "ThunderyShowers",
|
||||
"227": "LightSnow",
|
||||
"230": "HeavySnow",
|
||||
"248": "Fog",
|
||||
"260": "Fog",
|
||||
"263": "Showers",
|
||||
"266": "LightRain",
|
||||
"281": "LightSleet",
|
||||
"284": "LightSleet",
|
||||
"293": "LightRain",
|
||||
"296": "LightRain",
|
||||
"299": "Showers",
|
||||
"302": "HeavyRain",
|
||||
"305": "Showers",
|
||||
"308": "HeavyRain",
|
||||
"311": "LightSleet",
|
||||
"314": "LightSleet",
|
||||
"317": "LightSleet",
|
||||
"320": "LightSnow",
|
||||
"323": "SnowShowers",
|
||||
"326": "SnowShowers",
|
||||
"329": "HeavySnow",
|
||||
"332": "HeavySnow",
|
||||
"335": "SnowShowers",
|
||||
"338": "HeavySnow",
|
||||
"350": "LightSleet",
|
||||
"353": "Showers",
|
||||
"356": "Showers",
|
||||
"359": "HeavyRain",
|
||||
"362": "LightSleet",
|
||||
"365": "LightSleet",
|
||||
"368": "SnowShowers",
|
||||
"371": "SnowShowers",
|
||||
"374": "LightSleet",
|
||||
"377": "LightSleet",
|
||||
"386": "ThunderyShowers",
|
||||
"389": "ThunderyHeavyRain",
|
||||
"392": "SnowShowers",
|
||||
"395": "SnowShowers"
|
||||
};
|