After Width: | Height: | Size: 4.9 KiB |
After Width: | Height: | Size: 4.6 KiB |
After Width: | Height: | Size: 6.1 KiB |
After Width: | Height: | Size: 5.3 KiB |
After Width: | Height: | Size: 5.6 KiB |
After Width: | Height: | Size: 6.2 KiB |
After Width: | Height: | Size: 5.3 KiB |
After Width: | Height: | Size: 4.1 KiB |
After Width: | Height: | Size: 5.4 KiB |
After Width: | Height: | Size: 5.7 KiB |
After Width: | Height: | Size: 3.9 KiB |
After Width: | Height: | Size: 6.2 KiB |
After Width: | Height: | Size: 5.4 KiB |
After Width: | Height: | Size: 8.9 KiB |
After Width: | Height: | Size: 5.4 KiB |
@ -0,0 +1,4 @@ |
|||||||
|
{ |
||||||
|
"source": "nvg://ordinalscale.widget.mashiros.top/widget/topui", |
||||||
|
"settings": "settings.xml" |
||||||
|
} |
After Width: | Height: | Size: 23 KiB |
@ -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> |
After Width: | Height: | Size: 2.7 KiB |
After Width: | Height: | Size: 22 KiB |
After Width: | Height: | Size: 11 KiB |
@ -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" |
||||||
|
} |
||||||
|
] |
||||||
|
} |
@ -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(); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} |
@ -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(); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} |
@ -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; |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} |
@ -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" |
||||||
|
}; |