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 WidgetTemplate { id: widget title: qsTr("Round Clock") editing: styleDialog.active resizable: true version: "1.0.0" defaultValues: { "Sec Continue": true, "BG Color": "#2196f3", "BG Alpha": 50, "HGRID Color": "#ffffff", "MGRID Color": "#ffffff", "Hhand Color": "#ffffff", "Mhand Color": "#ffffff", "Shand Color": "#f3a829" } property real maxr: Math.min(width/2, height/2) -10 property real thour: 0 property real tmin: 0 property real tsec: 0 property var configs: widget.settings.styles onConfigsChanged: { background.requestPaint(); hour.requestPaint(); min.requestPaint(); sec.requestPaint(); sec_tail.requestPaint(); sec_center.requestPaint(); } function colorToRGBA(color, alpha) { var color1, color2, color3; color = ""+color; if (typeof color !== "string") return; if (color.charAt(0) === "#") { color = color.substring(1); } var not16num = color.split("").filter(function (item, index) { return isNaN(parseInt(item, 16)) }); if(not16num.length) return; switch (color.length) { case 3: color1 = color.substr(0,1); color2 = color.substr(1,1); color3 = color.substr(2,1); color1 = color1 + color1; color2 = color2 + color2; color3 = color3 + color3; break; case 6: color1 = color.substr(0,2); color2 = color.substr(2,2); color3 = color.substr(4,2); break; default: return false; } color1 = parseInt(color1, 16); color2 = parseInt(color2, 16); color3 = parseInt(color3, 16); return "rgba("+color1+","+color2+","+color3+","+alpha+")"; } Timer { interval: configs["Sec Continue"] ? 50 : 250 running: widget.NVG.View.exposed repeat: true onTriggered: { var now = new Date(); tsec = now.getSeconds() + (configs["Sec Continue"] ? now.getMilliseconds()/1000 : 0); tmin = now.getMinutes(); thour = now.getHours(); thour = thour % 12; } } Canvas { id: background width: widget.width; height: widget.height; contextType: "2d"; renderTarget: Canvas.FramebufferObject renderStrategy: Canvas.Cooperative onWidthChanged: { requestPaint(); } onHeightChanged: { requestPaint(); } onPaint: { context.resetTransform(); context.clearRect(0,0,widget.width,widget.height); context.translate(width/2, height/2); //将坐标原点移到画布中心 context.rotate(-Math.PI/2); //将坐标轴逆时针旋转90度,x轴正方向对准12点方向 context.fillStyle = colorToRGBA(configs["BG Color"], configs["BG Alpha"]/100); context.beginPath(); context.arc(0, 0, maxr, 0, Math.PI * 2, true); context.fill(); context.strokeStyle = configs["HGRID Color"]; context.lineWidth = maxr*0.04; context.lineCap = "round"; for (var i = 0; i < 12; i++) { context.beginPath(); context.rotate(Math.PI / 6); context.moveTo(maxr*0.92, 0); context.lineTo(maxr*0.78, 0); context.stroke(); } context.strokeStyle = configs["MGRID Color"]; context.lineWidth = maxr*0.015; for (i = 0; i < 60; i++) { if (i % 5 !== 0) { //去掉与小时刻度重叠的部分 context.beginPath(); context.moveTo(maxr*0.92, 0); context.lineTo(maxr*0.86, 0); context.stroke(); } context.rotate(Math.PI / 30); } } } Canvas { id: hour width: widget.width; height: widget.height; contextType: "2d"; renderTarget: Canvas.FramebufferObject renderStrategy: Canvas.Cooperative rotation: thour*30+tmin*0.5+tsec*0.01 onWidthChanged: { requestPaint(); } onHeightChanged: { requestPaint(); } onPaint: { context.resetTransform(); context.clearRect(0,0,widget.width,widget.height); context.translate(width/2, height/2); context.shadowColor = 'rgba(0,0,0,.5)'; context.shadowBlur = maxr*0.03; context.lineCap = "round"; context.strokeStyle = configs["Hhand Color"]; context.lineWidth = maxr*0.08; context.beginPath(); context.moveTo(0,0); context.lineTo(0, -maxr*0.56); context.stroke(); } } Canvas { id: min width: widget.width; height: widget.height; contextType: "2d"; renderTarget: Canvas.FramebufferObject renderStrategy: Canvas.Cooperative rotation: tmin*6+tsec*0.1 onWidthChanged: { requestPaint(); } onHeightChanged: { requestPaint(); } onPaint: { context.resetTransform(); context.clearRect(0,0,widget.width,widget.height); context.translate(width/2, height/2); context.shadowColor = 'rgba(0,0,0,.5)'; context.shadowBlur = maxr*0.04; context.lineCap = "round"; context.strokeStyle = configs["Mhand Color"]; context.lineWidth = maxr*0.045; context.beginPath(); context.moveTo(0,0); context.lineTo(0, -maxr*0.82); context.stroke(); } } Canvas { id: sec width: widget.width; height: widget.height; contextType: "2d"; renderTarget: Canvas.FramebufferObject renderStrategy: Canvas.Cooperative rotation: widget.tsec*6 onWidthChanged: { requestPaint(); } onHeightChanged: { requestPaint(); } onPaint: { context.resetTransform(); context.clearRect(0,0,widget.width,widget.height); context.translate(width/2, height/2); context.shadowColor = 'rgba(0,0,0,.5)'; context.shadowBlur = maxr*0.05; context.lineCap = "round"; context.strokeStyle = configs["Shand Color"]; context.lineWidth = maxr*0.016; context.beginPath(); context.moveTo(0,0); context.lineTo(0, -maxr*0.9); context.stroke(); } } Canvas { id: sec_tail width: widget.width; height: widget.height; contextType: "2d"; renderTarget: Canvas.FramebufferObject renderStrategy: Canvas.Cooperative rotation: widget.tsec*6 onWidthChanged: { requestPaint(); } onHeightChanged: { requestPaint(); } onPaint: { context.resetTransform(); context.clearRect(0,0,widget.width,widget.height); context.translate(width/2, height/2); context.shadowColor = 'rgba(0,0,0,.5)'; context.shadowBlur = maxr*0.05; context.lineCap = "round"; context.strokeStyle = configs["Shand Color"]; context.beginPath(); context.moveTo(0,0); context.lineTo(0, maxr*0.07); context.lineWidth = maxr*0.07; context.stroke(); } } Canvas { id: sec_center width: widget.width; height: widget.height; contextType: "2d"; renderTarget: Canvas.FramebufferObject renderStrategy: Canvas.Cooperative onWidthChanged: { requestPaint(); } onHeightChanged: { requestPaint(); } onPaint: { context.resetTransform(); context.clearRect(0,0,widget.width,widget.height); context.translate(width/2, height/2); context.shadowColor = 'rgba(0,0,0,.5)'; context.shadowBlur = maxr*0.1; context.shadowOffsetX = maxr*0.05/2.5; context.shadowOffsetY = maxr*0.05/2.5; context.beginPath(); context.arc(0, 0, maxr*0.07, 0, Math.PI * 2, true); context.fillStyle = configs["Shand Color"]; context.fill(); } } menu: Menu { Action { text: qsTr("Settings") + "..." onTriggered: styleDialog.active = true } } Loader { id: styleDialog active: false sourceComponent: NVG.Window { id: window title: qsTr("Clock Settings") visible: true minimumWidth: 380 minimumHeight: 540 width: minimumWidth height: minimumHeight transientParent: widget.NVG.View.window property var configuration Page { id: cfg_page anchors.fill: parent header: TitleBar { text: qsTr("Round 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: 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.SwitchPreference { name: "Sec Continue" label: qsTr("Continuous Second Hand") defaultValue: defaultValues["Sec Continue"] } P.Separator {} P.ColorPreference { name: "BG Color" label: qsTr("Background Color") defaultValue: defaultValues["BG Color"] } P.SliderPreference { name: "BG Alpha" label: qsTr("Background transparency") from: 0 to: 100 stepSize: 1 defaultValue: defaultValues["BG Alpha"] displayValue: value + "%" } P.Separator {} P.ColorPreference { name: "HGRID Color" label: qsTr("Hour Scale Color") defaultValue: defaultValues["HGRID Color"] } P.ColorPreference { name: "MGRID Color" label: qsTr("Minute Scale Color") defaultValue: defaultValues["MGRID Color"] } P.Separator {} P.ColorPreference { name: "Hhand Color" label: qsTr("Hour Hand Color") defaultValue: defaultValues["Hhand Color"] } P.ColorPreference { name: "Mhand Color" label: qsTr("Minute Hand Color") defaultValue: defaultValues["Mhand Color"] } P.ColorPreference { name: "Shand Color" label: qsTr("Second Hand Color") defaultValue: defaultValues["Shand Color"] } Component.onCompleted: { rootPreference.load(widget.settings.styles); configuration = widget.settings.styles; } } } } } } onClosing: { widget.settings.styles = configuration; styleDialog.active = false; } } } }