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.

628 lines
26 KiB

import QtQuick 2.12
import QtQuick.Controls 2.12
import QtQuick.Layouts 1.12
import QtGraphicalEffects 1.0
import QtQuick.Shapes 1.1
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 "."
WidgetTemplate {
id: widget
title: qsTr("Vecto Clock")
editing: styleDialog.active
resizable: true
version: "1.0.0"
defaultValues: {
"Weekday Settings": {
"Color": "#ffffff",
"Font Size": 43,
"Font Name": Common.fonts.length - 1,
"Font Weight": 2,
"Letter Spacing": 4,
"Y Offset": 50,
"Gap": 12
},
"Line Settings": {
"Color": "#ffffff",
"Width": 30,
"Position": -8
},
"Clock Settings": {
"Full Clock": false,
"Text Color": "#554e49",
"Background Visible": true,
"Background Color": "#ffffff",
"Font Size": 33,
"Font Name": Common.fonts.length - 1,
"Font Weight": 1,
"Letter Spacing": 0,
"X Offset": 0,
"Y Offset": 24,
"Gap": 9
},
"Date Settings": {
"Color": "#ffffff",
"Font Size": 10,
"Font Name": Common.fonts.length - 1,
"Font Weight": 1,
"Letter Spacing": 25,
"X Offset": 29,
"Y Offset": 12
}
}
menu: Menu {
Action {
text: qsTr("Settings") + "..."
onTriggered: styleDialog.active = true
}
}
readonly property var configs: widget.settings.styles
onConfigsChanged: {
weekday_mask_source.requestPaint();
divline.requestPaint();
clockbg.requestPaint();
configsFlag = true;
}
property bool configsFlag: false
property real thour: 0
property real t12hour: 0
property real tmin: -1
readonly property var weekdays: ["SUNDAY", "MONDAY", "TUESDAY", "WEDNESDAY", "THURSDAY", "FRIDAY", "SATURDAY"]
property int weekday: -1
readonly property var months: ["JAN", "FEB", "MAR", "APR", "MAY", "JUN", "JUL", "AUG", "SEP", "OCT", "NOV", "DEC"]
property string dateString: ""
readonly property real whRatio: width/height
readonly property real fixWHRatio: 2.1
property real clock_width: main.height*fixWHRatio * (0.5-0.005*configs["Line Settings"]["Position"])
property real left_gap_ratio: configs["Weekday Settings"]["Gap"]/100
property real right_gap_ratio: configs["Clock Settings"]["Gap"]/100
property real clock_text_size: weekday_mask.height*configs["Clock Settings"]["Font Size"]/100
property real right_topMargin: (timeinfo.height-clock_text_size)*configs["Clock Settings"]["Y Offset"]/100
Item {
id: main
anchors.centerIn: parent
width: widget.width
height: whRatio > fixWHRatio ? widget.height : widget.width/fixWHRatio
Item {
id: weekday_mask
width: main.width - clock_width
height: main.height
anchors.left: parent.left
anchors.verticalCenter: parent.verticalCenter
layer.enabled: true
layer.effect: OpacityMask{
maskSource: weekday_mask_source
}
Canvas {
id: weekday_mask_source
visible: false
anchors.fill: parent
renderStrategy: Canvas.Cooperative
contextType: "2d"
onPaint: {
context.reset();
context.clearRect(0,0,width,height);
context.beginPath();
context.lineTo(weekday_mask.width-weekday_mask.height*left_gap_ratio, 0);
context.lineTo(weekday_mask.width-0.45*weekday_mask.height-weekday_mask.height*left_gap_ratio, weekday_mask.height);
context.lineTo(0, weekday_mask.height);
context.lineTo(0, 0);
context.closePath();
context.fill();
}
onHeightChanged: {
requestPaint();
}
onWidthChanged: {
requestPaint();
}
}
Text {
id: weekday_text
text: weekday>-1 ? weekdays[weekday] : ""
color: configs["Weekday Settings"]["Color"]
anchors.left: parent.left
anchors.top: parent.top
anchors.topMargin: (weekday_mask.height-height*0.75)*configs["Weekday Settings"]["Y Offset"]/100
style: Text.Outline
styleColor: "transparent"
font.pixelSize: weekday_mask.height*configs["Weekday Settings"]["Font Size"]/100
font.letterSpacing: weekday_mask.width/text.length*configs["Weekday Settings"]["Letter Spacing"]/100
font.family: Common.fonts[configs["Weekday Settings"]["Font Name"]]
font.weight: Common.fontweight[configs["Weekday Settings"]["Font Weight"]]
}
}
Item {
id: timeinfo
width: clock_width+0.45*timeinfo.height
height: main.height
anchors.right: parent.right
anchors.top: parent.top
Canvas {
id: divline
anchors.fill: parent
renderTarget: Canvas.FramebufferObject
renderStrategy: Canvas.Cooperative
contextType: "2d"
onPaint: {
context.reset();
context.clearRect(0,0,width,height);
context.lineWidth = 6*configs["Line Settings"]["Width"]/100;
context.strokeStyle = configs["Line Settings"]["Color"];
context.beginPath();
context.moveTo(0, timeinfo.height);
context.lineTo(0.45*timeinfo.height, 0);
context.closePath();
context.stroke();
}
onHeightChanged: {
requestPaint();
}
}
Canvas {
id: clockbg
width: timeinfo.width
height: clock_text_size
visible: configs["Clock Settings"]["Background Visible"]
anchors.right: parent.right
anchors.top: parent.top
anchors.topMargin: right_topMargin
renderStrategy: Canvas.Cooperative
contextType: "2d"
onPaint: {
context.reset();
context.clearRect(0,0,width,height);
context.fillStyle = configs["Clock Settings"]["Background Color"];
context.beginPath();
context.moveTo(timeinfo.width, 0);
context.lineTo(0.45*(timeinfo.height-right_topMargin)+timeinfo.height*right_gap_ratio, 0);
context.lineTo(timeinfo.height*right_gap_ratio, timeinfo.height-right_topMargin);
context.lineTo(timeinfo.width, timeinfo.height);
context.closePath();
context.fill();
}
onHeightChanged: {
requestPaint();
}
}
Text {
id: clock_text
anchors.horizontalCenter: clockbg.horizontalCenter
anchors.horizontalCenterOffset: -right_topMargin*0.225 + timeinfo.width*(0.225*configs["Clock Settings"]["X Offset"]+12.5)/100 + timeinfo.height*right_gap_ratio/2
anchors.verticalCenterOffset: height/100
anchors.verticalCenter: clockbg.verticalCenter
text: ""
color: configs["Clock Settings"]["Text Color"]
style: Text.Outline
styleColor: "transparent"
font.pixelSize: clock_text_size/1.7
font.letterSpacing: clock_width/text.length*configs["Clock Settings"]["Letter Spacing"]/100
font.family: Common.fonts[configs["Clock Settings"]["Font Name"]]
font.weight: Common.fontweight[configs["Clock Settings"]["Font Weight"]]
}
Text {
id: date_text
anchors.top: clockbg.bottom
anchors.topMargin: (configs["Date Settings"]["Y Offset"]>0 ? (main.height-right_topMargin-clock_text_size-height) : right_topMargin+clock_text_size)*configs["Date Settings"]["Y Offset"]/100
anchors.left: clockbg.left
anchors.leftMargin: (configs["Date Settings"]["X Offset"]>0 ? clock_width : main.width-timeinfo.width)*configs["Date Settings"]["X Offset"]/100
text: dateString
color: configs["Date Settings"]["Color"]
style: Text.Outline
styleColor: "transparent"
font.pixelSize: timeinfo.height*configs["Date Settings"]["Font Size"]/100
font.letterSpacing: clock_width/text.length*configs["Date Settings"]["Letter Spacing"]/100
font.family: Common.fonts[configs["Date Settings"]["Font Name"]]
font.weight: Common.fontweight[configs["Date Settings"]["Font Weight"]]
}
}
}
Timer {
interval: 250
running: true
repeat: true
onTriggered: {
var now = new Date();
if (tmin !== now.getMinutes() || configsFlag) {
configsFlag = false;
tmin = now.getMinutes();
thour = now.getHours();
if (configs["Clock Settings"]["Full Clock"]) {
clock_text.text = [("0"+thour).slice(-2), ("0"+tmin).slice(-2)].join(":");
} else {
t12hour = thour > 12 ? thour - 12 : thour;
clock_text.text = [t12hour,("0"+tmin).slice(-2)].join(":") + (thour > 11 ? "PM" : "AM");
}
if (weekday !== now.getDay()) {
weekday = now.getDay();
dateString = [months[now.getMonth()], now.getDate(), now.getFullYear()].join(" ");
}
}
}
}
Loader {
id: styleDialog
active: false
sourceComponent: NVG.Window {
id: window
title: qsTr("Settings")
visible: true
minimumWidth: 500
minimumHeight: 600
width: minimumWidth
height: minimumHeight
transientParent: widget.NVG.View.window
property var configuration
Page {
id: cfg_page
anchors.fill: parent
header: TitleBar {
text: qsTr("Vecto Clock")
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;
}
}
ColumnLayout {
id: root
anchors.fill: parent
anchors.margins: 16
anchors.topMargin: 16
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 {
name: "Weekday Settings"
label: qsTr("Weekday Settings")
live: true
icon.name: "regular:\uf1de"
P.ColorPreference {
name: "Color"
label: qsTr("Color")
defaultValue: defaultValues["Weekday Settings"]["Color"]
}
P.SliderPreference {
name: "Font Size"
label: qsTr("Font Size")
from: 1
to: 100
stepSize: 1
defaultValue: defaultValues["Weekday Settings"]["Font Size"]
displayValue: value + "%"
}
P.SelectPreference {
name: "Font Name"
label: qsTr("Font Style")
defaultValue: defaultValues["Weekday Settings"]["Font Name"]
model: Common.fonts
}
P.SelectPreference {
name: "Font Weight"
label: qsTr("Font Weight")
defaultValue: defaultValues["Weekday Settings"]["Font Weight"]
model: Common.sfontweight
}
P.SliderPreference {
name: "Letter Spacing"
label: qsTr("Letter Spacing")
from: 0
to: 100
stepSize: 1
defaultValue: defaultValues["Weekday Settings"]["Letter Spacing"]
displayValue: value + "%"
}
P.SliderPreference {
name: "Y Offset"
label: qsTr("Y Offset")
from: 0
to: 100
stepSize: 1
defaultValue: defaultValues["Weekday Settings"]["Y Offset"]
displayValue: value + "%"
}
P.SliderPreference {
name: "Gap"
label: qsTr("Gap")
from: 0
to: 100
stepSize: 1
defaultValue: defaultValues["Weekday Settings"]["Gap"]
displayValue: value + "%"
}
}
P.DialogPreference {
name: "Line Settings"
label: qsTr("Line Settings")
live: true
icon.name: "regular:\uf1de"
P.ColorPreference {
name: "Color"
label: qsTr("Color")
defaultValue: defaultValues["Line Settings"]["Color"]
}
P.SliderPreference {
name: "Width"
label: qsTr("Width")
from: 1
to: 100
stepSize: 1
defaultValue: defaultValues["Line Settings"]["Width"]
displayValue: value + "%"
}
P.SliderPreference {
name: "Position"
label: qsTr("Position")
from: -100
to: 100
stepSize: 1
defaultValue: defaultValues["Line Settings"]["Position"]
displayValue: value + "%"
}
}
P.DialogPreference {
name: "Clock Settings"
label: qsTr("Clock Settings")
live: true
icon.name: "regular:\uf1de"
P.SwitchPreference {
name: "Full Clock"
label: qsTr("24 Hour Clock")
defaultValue: defaultValues["Clock Settings"]["Full Clock"]
}
P.ColorPreference {
name: "Text Color"
label: qsTr("Text Color")
defaultValue: defaultValues["Clock Settings"]["Text Color"]
}
P.SwitchPreference {
id: _cfg_clock_background_visible
name:"Background Visible"
label: qsTr("Background Visible")
defaultValue: defaultValues["Clock Settings"]["Background Visible"]
}
P.ColorPreference {
name: "Background Color"
label: qsTr("Background Color")
enabled: _cfg_clock_background_visible.value
defaultValue: defaultValues["Clock Settings"]["Background Color"]
}
P.SliderPreference {
name: "Font Size"
label: qsTr("Font Size")
from: 1
to: 100
stepSize: 1
defaultValue: defaultValues["Clock Settings"]["Font Size"]
displayValue: value + "%"
}
P.SelectPreference {
name: "Font Name"
label: qsTr("Font Style")
defaultValue: defaultValues["Clock Settings"]["Font Name"]
model: Common.fonts
}
P.SelectPreference {
name: "Font Weight"
label: qsTr("Font Weight")
defaultValue: defaultValues["Clock Settings"]["Font Weight"]
model: Common.sfontweight
}
P.SliderPreference {
name: "Letter Spacing"
label: qsTr("Letter Spacing")
from: 0
to: 100
stepSize: 1
defaultValue: defaultValues["Clock Settings"]["Letter Spacing"]
displayValue: value + "%"
}
P.SliderPreference {
name: "X Offset"
label: qsTr("X Offset")
from: -100
to: 100
stepSize: 1
defaultValue: defaultValues["Clock Settings"]["X Offset"]
displayValue: value + "%"
}
P.SliderPreference {
name: "Y Offset"
label: qsTr("Y Offset")
from: 0
to: 100
stepSize: 1
defaultValue: defaultValues["Clock Settings"]["Y Offset"]
displayValue: value + "%"
}
P.SliderPreference {
name: "Gap"
label: qsTr("Gap")
from: 0
to: 100
stepSize: 1
defaultValue: defaultValues["Clock Settings"]["Gap"]
displayValue: value + "%"
}
}
P.DialogPreference {
name: "Date Settings"
label: qsTr("Date Settings")
live: true
icon.name: "regular:\uf1de"
P.ColorPreference {
name: "Color"
label: qsTr("Color")
defaultValue: defaultValues["Date Settings"]["Color"]
}
P.SliderPreference {
name: "Font Size"
label: qsTr("Font Size")
from: 1
to: 100
stepSize: 1
defaultValue: defaultValues["Date Settings"]["Font Size"]
displayValue: value + "%"
}
P.SelectPreference {
name: "Font Name"
label: qsTr("Font Style")
defaultValue: defaultValues["Date Settings"]["Font Name"]
model: Common.fonts
}
P.SelectPreference {
name: "Font Weight"
label: qsTr("Font Weight")
defaultValue: defaultValues["Date Settings"]["Font Weight"]
model: Common.sfontweight
}
P.SliderPreference {
name: "Letter Spacing"
label: qsTr("Letter Spacing")
from: 0
to: 100
stepSize: 1
defaultValue: defaultValues["Date Settings"]["Letter Spacing"]
displayValue: value + "%"
}
P.SliderPreference {
name: "X Offset"
label: qsTr("X Offset")
from: -100
to: 100
stepSize: 1
defaultValue: defaultValues["Date Settings"]["X Offset"]
displayValue: value + "%"
}
P.SliderPreference {
name: "Y Offset"
label: qsTr("Y Offset")
from: -100
to: 100
stepSize: 1
defaultValue: defaultValues["Date Settings"]["Y Offset"]
displayValue: value + "%"
}
}
Component.onCompleted: {
rootPreference.load(widget.settings.styles);
configuration = widget.settings.styles;
}
}
}
}
}
}
onClosing: {
widget.settings.styles = configuration;
styleDialog.active = false;
}
}
}
}