commit de5149080799bccce71e992542da78ed2f291782 Author: SO_RA <490328928@qq.com> Date: Thu Mar 24 02:31:42 2022 +0800 initial commit diff --git a/Locales/zh.qm b/Locales/zh.qm new file mode 100644 index 0000000..1d112c1 Binary files /dev/null and b/Locales/zh.qm differ diff --git a/package.json b/package.json new file mode 100644 index 0000000..e8ed14e --- /dev/null +++ b/package.json @@ -0,0 +1,76 @@ +{ + "name": "top.mashiros.widget.nclocks", + "version": "1.0.0", + + "title": { + "en": "Clock Collections Plugin", + "zh": "时钟合集插件" + }, + + "description": { + "en": "Cool collection of clocks for SAO Utils 2", + "zh": "用于 SAO Utils 2的酷炫时钟集合" + }, + + "author": { + "name": "Mashiro_Sorata", + "email": "mashiro_sorata@qq.com", + "url": "http://www.mashiros.top/" + }, + + "homepage": "https://nvg.dev/Mashiro_Sorata/nClocks", + + "bugs": { + "email": "mashiro_sorata@qq.com", + "url": "https://nvg.dev/Mashiro_Sorata/nClocks/issues" + }, + + "engines": { + "qt": "~5", + "qt.quick": ">=2.12", + "nvg.api": "~1" + }, + + "resources": [ + { + "location": "/nclocks/solars", + "catalog": "widget", + "title": { + "en": "Solars Clock Widget", + "zh": "太阳系时钟挂件" + }, + "preview": "preview/solars_clock.png", + "entry": "solars_clock.qml" + }, + { + "location": "/nclocks/reflection", + "catalog": "widget", + "title": { + "en": "Reflection Clock Widget", + "zh": "倒影时钟挂件" + }, + "preview": "preview/reflection_clock.png", + "entry": "reflection_clock.qml" + }, + { + "location": "/nclocks/round", + "catalog": "widget", + "title": { + "en": "Round Clock Widget", + "zh": "圆盘时钟挂件" + }, + "preview": "preview/round_clock.png", + "entry": "round_clock.qml" + }, + { + "location": "/nclocks/text", + "catalog": "widget", + "title": { + "en": "Text Clock Widget", + "zh": "文字时钟挂件" + }, + "preview": "preview/text_clock.png", + "entry": "text_clock.qml" + } + ] +} \ No newline at end of file diff --git a/preview/reflection_clock.png b/preview/reflection_clock.png new file mode 100644 index 0000000..345f5c9 Binary files /dev/null and b/preview/reflection_clock.png differ diff --git a/preview/round_clock.png b/preview/round_clock.png new file mode 100644 index 0000000..9385ffd Binary files /dev/null and b/preview/round_clock.png differ diff --git a/preview/solars_clock.png b/preview/solars_clock.png new file mode 100644 index 0000000..fd0cfd8 Binary files /dev/null and b/preview/solars_clock.png differ diff --git a/preview/text_clock.png b/preview/text_clock.png new file mode 100644 index 0000000..94dd672 Binary files /dev/null and b/preview/text_clock.png differ diff --git a/reflection_clock.qml b/reflection_clock.qml new file mode 100644 index 0000000..b22c216 --- /dev/null +++ b/reflection_clock.qml @@ -0,0 +1,465 @@ +import QtQuick 2.12 + +import QtQuick.Controls 2.12 +import QtQuick.Layouts 1.12 +import QtGraphicalEffects 1.0 + +import NERvGear 1.0 as NVG +import NERvGear.Templates 1.0 as T +import NERvGear.Preferences 1.0 as P + + + +T.Widget { + id: widget + solid: true + title: qsTr("Reflection Clock") + resizable: true + + readonly property real minWH: Math.min(width, height) + readonly property real multi: minWH/220 + + readonly property bool full_clock: widget.settings.styles ? widget.settings.styles["Hour Settings"]["Full Clock"] : true + property string am_pm: "" + + Rectangle { + id: main + color: "transparent" + anchors.top: parent.top + anchors.topMargin: 0 + anchors.left: parent.left + anchors.leftMargin: 0 + width: 345*multi + height: 222*multi + + Rectangle { + id: hour + color: "transparent" + anchors.top: parent.top + anchors.topMargin: 0 + anchors.left: parent.left + anchors.leftMargin: 15*multi + width: 100*multi + height: 111*multi + + Rectangle { + id: hour_top + color: widget.settings.styles ? widget.settings.styles["Hour Settings"]["Clock BG Color"] : "#2196f3" + width: 100*multi + height: 80*multi + anchors.top: parent.top + anchors.topMargin: 0 + anchors.left: parent.left + anchors.leftMargin: 0 + + Text { + id: hour_text + text: "" + color: widget.settings.styles ? widget.settings.styles["Hour Settings"]["Clock Font Color"] : "#ffffff" + anchors.centerIn: parent + font.pointSize: 35*multi + font.weight: Font.Light + font.family: "Microsoft YaHei" + } + } + + Rectangle { + id: hour_bottom + color: widget.settings.styles ? widget.settings.styles["Hour Settings"]["Panel BG Color"] : "#2196f3" + width: 100*multi + height: 30*multi + anchors.top: hour_top.bottom + anchors.topMargin: multi + anchors.left: parent.left + anchors.leftMargin: 0 + + Text { + text: "HOURS"+am_pm + color: widget.settings.styles ? widget.settings.styles["Hour Settings"]["Panel Font Color"] : "#ffffff" + anchors.centerIn: parent + font.pointSize: 9*multi + font.weight: Font.Normal + font.family: "Microsoft YaHei" + font.letterSpacing: 2*multi + } + } + } + + + Rectangle { + id: min + color: "transparent" + anchors.top: parent.top + anchors.topMargin: 0 + anchors.left: hour.right + anchors.leftMargin: 15*multi + width: 100*multi + height: 111*multi + + Rectangle { + id: min_top + color: widget.settings.styles ? widget.settings.styles["Min Settings"]["Clock BG Color"] : "#2196f3" + anchors.top: parent.top + anchors.topMargin: 0 + anchors.left: parent.left + anchors.leftMargin: 0 + width: 100*multi + height: 80*multi + + Text { + id: min_text + text: "" + color: widget.settings.styles ? widget.settings.styles["Min Settings"]["Clock Font Color"] : "#ffffff" + anchors.centerIn: parent + font.pointSize: 35*multi + font.weight: Font.Light + font.family: "Microsoft YaHei" + } + } + + Rectangle { + id: min_bottom + color: widget.settings.styles ? widget.settings.styles["Min Settings"]["Panel BG Color"] : "#2196f3" + width: 100*multi + height: 30*multi + anchors.top: min_top.bottom + anchors.topMargin: multi + anchors.left: parent.left + anchors.leftMargin: 0 + + Text { + text: "MINUTES" + color: widget.settings.styles ? widget.settings.styles["Min Settings"]["Panel Font Color"] : "#ffffff" + anchors.centerIn: parent + font.pointSize: 9*multi + font.weight: Font.Normal + font.family: "Microsoft YaHei" + font.letterSpacing: 2*multi + } + } + } + + + Rectangle { + id: sec + color: "transparent" + anchors.top: parent.top + anchors.topMargin: 0 + anchors.left: min.right + anchors.leftMargin: 15*multi + visible: widget.settings.styles ? widget.settings.styles["Sec Settings"]["Visible"] : true + width: 100*multi + height: 111*multi + + Rectangle { + id: sec_top + color: widget.settings.styles ? widget.settings.styles["Sec Settings"]["Clock BG Color"] : "#ff006a" + width: 100*multi + height: 80*multi + anchors.top: parent.top + anchors.topMargin: 0 + anchors.left: parent.left + anchors.leftMargin: 0 + + Text { + id: sec_text + text: "" + color: widget.settings.styles ? widget.settings.styles["Sec Settings"]["Clock Font Color"] : "#ffffff" + anchors.centerIn: parent + font.pointSize: 35*multi + font.weight: Font.Light + font.family: "Microsoft YaHei" + } + } + + Rectangle { + id: sec_bottom + color: widget.settings.styles ? widget.settings.styles["Sec Settings"]["Panel BG Color"] : "#ff006a" + width: 100*multi + height: 30*multi + anchors.top: sec_top.bottom + anchors.topMargin: multi + anchors.left: parent.left + anchors.leftMargin: 0 + + Text { + text: "SECONDS" + color: widget.settings.styles ? widget.settings.styles["Sec Settings"]["Panel Font Color"] : "#ffffff" + anchors.centerIn: parent + font.pointSize: 9*multi + font.weight: Font.Normal + font.family: "Microsoft YaHei" + font.letterSpacing: 2*multi + } + } + } + } + + OpacityMask { + width: main.width + height: main.height + anchors.top: main.bottom + anchors.topMargin: multi + + source: main + maskSource: Rectangle { + width: main.width + height: main.height + gradient: Gradient{ + GradientStop{position: 0.0;color:"transparent"} + GradientStop{position: 1.0;color:"#FFF"} + } + } + transform: Scale {yScale: -1} + } + + Timer { + interval: 250 + repeat: true + running: widget.NVG.View.exposed + onTriggered: { + var now = new Date(), + sec = now.getSeconds(), + min = now.getMinutes(), + hr = now.getHours(); + if(!full_clock) { + am_pm = "|" + (hr > 11 ? "PM" : "AM"); + if (hr === 0 || hr === 24) + hr = 12; + else if(hr > 12) + hr -= 12; + } else { + am_pm = ""; + } + + hour_text.text = hr < 10 ? "0"+hr : hr; + min_text.text = min < 10 ? "0"+min : min; + sec_text.text = sec < 10 ? "0"+sec : sec; + } + } + + 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: 480 + maximumWidth: minimumWidth + maximumHeight: minimumHeight + width: minimumWidth + height: minimumHeight + + transientParent: widget.NVG.View.window + + property var configuration + + ColumnLayout { + id: root + anchors.fill: parent + anchors.margins: 16 + anchors.topMargin: 0 + + Row { + spacing: 234 + + ToolButton { + text: qsTr("Save") + onClicked: { + configuration = rootPreference.save(); + widget.settings.styles = configuration; + styleDialog.active = false; + } + } + + ToolButton { + text: qsTr("Reset") + onClicked: { + rootPreference.load(); + let cfg = rootPreference.save(); + widget.settings.styles = cfg; + } + } + } + + Label { + Layout.alignment: Qt.AlignCenter + text: qsTr("Settings") + font.pixelSize: 24 + } + + 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: "Hour Settings" + label: qsTr("Hour Settings") + live: true + icon.name: "regular:\uf1de" + + P.SwitchPreference { + name: "Full Clock" + label: qsTr("24 Hour Clock") + defaultValue: true + } + + P.Separator {} + + P.ColorPreference { + name: "Clock BG Color" + label: qsTr("Clock Background Color") + defaultValue: "#2196f3" + } + + P.ColorPreference { + name: "Clock Font Color" + label: qsTr("Clock Font Color") + defaultValue: "#ffffff" + } + + P.Separator {} + + P.ColorPreference { + name: "Panel BG Color" + label: qsTr("Panel Background Color") + defaultValue: "#2196f3" + } + + P.ColorPreference { + name: "Panel Font Color" + label: qsTr("Panel Font Color") + defaultValue: "#ffffff" + } + } + + P.Separator {} + + P.DialogPreference { + name: "Min Settings" + label: qsTr("Minute Settings") + live: true + icon.name: "regular:\uf1de" + + P.ColorPreference { + name: "Clock BG Color" + label: qsTr("Clock Background Color") + defaultValue: "#2196f3" + } + + P.ColorPreference { + name: "Clock Font Color" + label: qsTr("Clock Font Color") + defaultValue: "#ffffff" + } + + P.Separator {} + + P.ColorPreference { + name: "Panel BG Color" + label: qsTr("Panel Background Color") + defaultValue: "#2196f3" + } + + P.ColorPreference { + name: "Panel Font Color" + label: qsTr("Panel Font Color") + defaultValue: "#ffffff" + } + } + + P.Separator {} + + P.DialogPreference { + name: "Sec Settings" + label: qsTr("Second Settings") + live: true + icon.name: "regular:\uf1de" + + P.SwitchPreference { + id: cfg_sec_en + name: "Visible" + label: qsTr("Show") + defaultValue: true + } + + P.Separator {} + + P.ColorPreference { + name: "Clock BG Color" + label: qsTr("Clock Background Color") + enabled: cfg_sec_en.value + defaultValue: "#ff006a" + } + + P.ColorPreference { + name: "Clock Font Color" + label: qsTr("Clock Font Color") + enabled: cfg_sec_en.value + defaultValue: "#ffffff" + } + + P.Separator {} + + P.ColorPreference { + name: "Panel BG Color" + label: qsTr("Panel Background Color") + enabled: cfg_sec_en.value + defaultValue: "#ff006a" + } + + P.ColorPreference { + name: "Panel Font Color" + label: qsTr("Panel Font Color") + enabled: cfg_sec_en.value + defaultValue: "#ffffff" + } + } + + 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; + } + } + } +} diff --git a/round_clock.qml b/round_clock.qml new file mode 100644 index 0000000..1657a82 --- /dev/null +++ b/round_clock.qml @@ -0,0 +1,463 @@ +import QtQuick 2.12 + +import QtQuick.Controls 2.12 +import QtQuick.Layouts 1.12 + +import NERvGear 1.0 as NVG +import NERvGear.Templates 1.0 as T +import NERvGear.Preferences 1.0 as P + + + +T.Widget { + id: widget + solid: true + title: qsTr("Round Clock") + resizable: true + + 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 ? widget.settings.styles : {"Sec Continue":true,"BG Color":"#2196f3","BG Alpha":50,"HGRID Color":"#ffffff","MGRID Color":"#ffffff","Hhand Color":"#ffffff","Mhand Color":"#ffffff","Shand Color":"#f3a829"} + + 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.6/60 + + 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 + maximumWidth: minimumWidth + maximumHeight: minimumHeight + width: minimumWidth + height: minimumHeight + + transientParent: widget.NVG.View.window + + property var configuration + + ColumnLayout { + id: root + anchors.fill: parent + anchors.margins: 16 + anchors.topMargin: 0 + + Row { + spacing: 234 + + ToolButton { + text: qsTr("Save") + onClicked: { + configuration = rootPreference.save(); + widget.settings.styles = configuration; + styleDialog.active = false; + } + } + + ToolButton { + text: qsTr("Reset") + onClicked: { + rootPreference.load(); + let cfg = rootPreference.save(); + widget.settings.styles = cfg; + } + } + } + + Label { + Layout.alignment: Qt.AlignCenter + text: qsTr("Settings") + font.pixelSize: 24 + } + + 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: true + } + + P.Separator {} + + P.ColorPreference { + name: "BG Color" + label: qsTr("Background Color") + defaultValue: "#2196f3" + } + + P.SliderPreference { + name: "BG Alpha" + label: qsTr("Background transparency") + from: 0 + to: 100 + stepSize: 1 + defaultValue: 50 + displayValue: value + "%" + } + + P.Separator {} + + P.ColorPreference { + name: "HGRID Color" + label: qsTr("Hour Scale Color") + defaultValue: "#fff" + } + + P.ColorPreference { + name: "MGRID Color" + label: qsTr("Minute Scale Color") + defaultValue: "#fff" + } + + P.Separator {} + + P.ColorPreference { + name: "Hhand Color" + label: qsTr("Hour Hand Color") + defaultValue: "#fff" + } + + P.ColorPreference { + name: "Mhand Color" + label: qsTr("Minute Hand Color") + defaultValue: "#fff" + } + + P.ColorPreference { + name: "Shand Color" + label: qsTr("Second Hand Color") + defaultValue: "#F3A829" + } + + 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; + } + } + } +} diff --git a/solars_clock.qml b/solars_clock.qml new file mode 100644 index 0000000..34bdc32 --- /dev/null +++ b/solars_clock.qml @@ -0,0 +1,687 @@ +import QtQuick 2.12 + +import QtQuick.Controls 2.12 +import QtQuick.Layouts 1.12 + +import NERvGear 1.0 as NVG +import NERvGear.Templates 1.0 as T +import NERvGear.Preferences 1.0 as P + + + +T.Widget { + id: widget + solid: true + title: qsTr("Solar Clock") + resizable: true + + editing: styleDialog.active + + property real maxr: Math.min(width/2, height/2) -10 + readonly property real rhour: maxr*0.9 + readonly property real rmin: maxr*0.72 + readonly property real rsec: maxr*0.5 + property real thour: 0 + property real tmin: 0 + property real tsec: 0 + property real tmsec: 0 + + property var configs: widget.settings.styles ? widget.settings.styles : {"BG Settings":{"BG Color":"#212121","BG Alpha":100,"Show HGrid":true,"HGRID Color":"#616161","Show Center":true,"Center Color":"#ffeb3b","Center Radius":85,"Show Clock":true,"Clock Color":"#616161","Font Size":100},"Hour Settings":{"Hstar Color":"#ffa000","Show Orbit":true,"Horbit Color":"#616161"},"Min Settings":{"Mstar Color":"#ff5722","Show Orbit":true,"Morbit Color":"#616161"},"Sec Settings":{"Sstar Color":"#2196f3","Show Orbit":true,"Sorbit Color":"#616161"},"MSec Settings":{"MSstar Color":"#9e9e9e","Show Orbit":true,"MSorbit Color":"#9e9e9e"}} + + onConfigsChanged: { + background.requestPaint(); + hour.requestPaint(); + min.requestPaint(); + sec.requestPaint(); + millisec_orbit.requestPaint(); + millisec_star.requestPaint(); + 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: 50 + running: widget.NVG.View.exposed + repeat: true + onTriggered: { + var now = new Date(); + tmsec = now.getMilliseconds(); + tsec = now.getSeconds(); + tmin = now.getMinutes(); + thour = now.getHours(); + main_time.text = (thour<10 ? "0"+thour : thour) + ":" + (tmin<10 ? "0"+tmin : tmin) + ":" + (tsec<10 ? "0"+tsec : tsec); + thour = thour > 12 ? thour - 12 : thour; + tsec += tmsec/1000; + } + } + + 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 Settings"]["BG Color"], configs["BG Settings"]["BG Alpha"]/100); + context.beginPath(); + context.arc(0, 0, maxr, 0, Math.PI * 2, true); + context.fill(); + + if (configs["Hour Settings"]["Show Orbit"]) { + context.strokeStyle = configs["Hour Settings"]["Horbit Color"]; + context.lineWidth = maxr*0.01; + context.beginPath(); + context.arc(0, 0, rhour, 0, Math.PI * 2, true); + context.stroke(); + } + + if (configs["Min Settings"]["Show Orbit"]) { + context.strokeStyle = configs["Min Settings"]["Morbit Color"]; + context.lineWidth = maxr*0.01; + context.beginPath(); + context.arc(0, 0, rmin, 0, Math.PI * 2, true); + context.stroke(); + } + + if (configs["Sec Settings"]["Show Orbit"]) { + context.strokeStyle = configs["Sec Settings"]["Sorbit Color"]; + context.lineWidth = maxr*0.01; + context.beginPath(); + context.arc(0, 0, rsec, 0, Math.PI * 2, true); + context.stroke(); + } + + if (configs["BG Settings"]["Show HGrid"]) { + context.strokeStyle = configs["BG Settings"]["HGRID Color"]; + context.lineWidth = maxr*0.016; + context.lineCap = "round"; + for (var i = 0; i < 12; i++) { + context.beginPath(); + if (!(i%3)) { + context.moveTo(rmin+maxr*0.07, 0); + } else { + context.moveTo(rmin+maxr*0.035, 0); + } + context.lineTo(rmin, 0); + context.stroke(); + context.rotate(Math.PI / 6); + } + } + } + } + + 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.6/60 + + 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.fillStyle = configs["Hour Settings"]["Hstar Color"]; + + context.beginPath(); + context.arc(0, -rhour, maxr*0.075, 0, Math.PI * 2, true); + context.fill(); + } + } + + 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.fillStyle = configs["Min Settings"]["Mstar Color"]; + context.beginPath(); + context.arc(0, -rmin, maxr*0.06, 0, Math.PI * 2, true); + context.fill(); + } + } + + 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.04; + context.lineCap = "round"; + context.fillStyle = configs["Sec Settings"]["Sstar Color"]; + context.beginPath(); + context.arc(0, -rsec, maxr*0.045, 0, Math.PI * 2, true); + context.fill(); + } + } + + Canvas { + id: millisec_orbit + 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); + if (configs["MSec Settings"]["Show Orbit"]) { + context.translate(width/2, height/2); + context.strokeStyle = configs["MSec Settings"]["MSorbit Color"]; + context.lineWidth = maxr*0.005; + context.beginPath(); + context.arc(0, -rsec, maxr*0.1, 0, Math.PI * 2, true); + context.stroke(); + } + } + + Canvas { + id: millisec_star + width: widget.width; + height: widget.height; + contextType: "2d"; + renderTarget: Canvas.FramebufferObject + renderStrategy: Canvas.Cooperative + + onWidthChanged: { + requestPaint(); + } + + onHeightChanged: { + requestPaint(); + } + + transform: Rotation { + //设置图像原点 + origin.x: width/2 + origin.y: height/2-rsec + axis{ + x: 0 + y: 0 + z: 1 + } + angle: tmsec*0.360 + } + + 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.fillStyle = configs["MSec Settings"]["MSstar Color"]; + context.beginPath(); + context.arc(0, -rsec-maxr*0.1, maxr*0.025, 0, Math.PI * 2, true); + context.fill(); + } + } + } + + Canvas { + id: center + width: widget.width; + height: widget.height; + contextType: "2d"; + renderTarget: Canvas.FramebufferObject + renderStrategy: Canvas.Cooperative + + visible: configs["BG Settings"]["Show Center"] + + onWidthChanged: { + requestPaint(); + } + + onHeightChanged: { + requestPaint(); + } + + onPaint: { + context.resetTransform(); + context.clearRect(0,0,widget.width,widget.height); + context.translate(width/2, height/2); + context.shadowColor = colorToRGBA(configs["BG Settings"]["Center Color"], 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.003*configs["BG Settings"]["Center Radius"], 0, Math.PI * 2, true); + context.fillStyle = configs["BG Settings"]["Center 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: 400 + minimumHeight: 660 + maximumWidth: minimumWidth + maximumHeight: minimumHeight + width: minimumWidth + height: minimumHeight + + transientParent: widget.NVG.View.window + + property var configuration + + ColumnLayout { + id: root + anchors.fill: parent + anchors.margins: 16 + anchors.topMargin: 0 + + Row { + spacing: 270 + + ToolButton { + text: qsTr("Save") + onClicked: { + configuration = rootPreference.save(); + widget.settings.styles = configuration; + styleDialog.active = false; + } + } + + ToolButton { + text: qsTr("Reset") + onClicked: { + rootPreference.load(); + let cfg = rootPreference.save(); + widget.settings.styles = cfg; + } + } + } + + Label { + Layout.alignment: Qt.AlignCenter + text: qsTr("Settings") + font.pixelSize: 24 + } + + 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: "BG Settings" + label: qsTr("Background Settings") + live: true + icon.name: "regular:\uf1de" + + P.ColorPreference { + name: "BG Color" + label: qsTr("Color") + defaultValue: "#212121" + } + + P.SliderPreference { + name: "BG Alpha" + label: qsTr("Transparency") + from: 0 + to: 100 + stepSize: 1 + defaultValue: 100 + displayValue: value + "%" + } + + P.Separator {} + + P.SwitchPreference { + id: show_hgrid + name: "Show HGrid" + label: qsTr("Show Scale") + defaultValue: true + } + + P.ColorPreference { + name: "HGRID Color" + label: qsTr("Scale Color") + enabled: show_hgrid.value + defaultValue: "#616161" + } + + P.Separator {} + + P.SwitchPreference { + id: showCenter + name: "Show Center" + label: qsTr("Show Center") + defaultValue: true + } + + P.ColorPreference { + name: "Center Color" + label: qsTr("Center Color") + enabled: showCenter.value + defaultValue: "#ffeb3b" + } + + P.SliderPreference { + name: "Center Radius" + label: qsTr("Center Radius") + enabled: showCenter.value + from: 30 + to: 100 + stepSize: 1 + defaultValue: 85 + displayValue: value + "%" + } + + P.Separator {} + + P.SwitchPreference { + id: showClock + name: "Show Clock" + label: qsTr("Display Time") + defaultValue: true + } + + P.ColorPreference { + name: "Clock Color" + label: qsTr("Font Color") + enabled: showClock.value + defaultValue: "#616161" + } + + P.SliderPreference { + name: "Font Size" + label: qsTr("Font Size") + enabled: showClock.value + from: 50 + to: 100 + stepSize: 1 + defaultValue: 100 + displayValue: value + "%" + } + } + + P.Separator {} + + P.DialogPreference { + name: "Hour Settings" + label: qsTr("Hour Settings") + live: true + icon.name: "regular:\uf1de" + + P.ColorPreference { + name: "Hstar Color" + label: qsTr("Star Color") + defaultValue: "#ffa000" + } + + P.Separator {} + + P.SwitchPreference { + id: hour_settings_show_orbit + name: "Show Orbit" + label: qsTr("Show Orbit") + defaultValue: true + } + + P.ColorPreference { + name: "Horbit Color" + label: qsTr("Orbit Color") + enabled: hour_settings_show_orbit.value + defaultValue: "#616161" + } + } + + P.DialogPreference { + name: "Min Settings" + label: qsTr("Minute Settings") + live: true + icon.name: "regular:\uf1de" + + P.ColorPreference { + name: "Mstar Color" + label: qsTr("Star Color") + defaultValue: "#ff5722" + } + + P.Separator {} + + P.SwitchPreference { + id: min_settings_show_orbit + name: "Show Orbit" + label: qsTr("Show Orbit") + defaultValue: true + } + + P.ColorPreference { + name: "Morbit Color" + label: qsTr("Orbit Color") + enabled: min_settings_show_orbit.value + defaultValue: "#616161" + } + } + + P.DialogPreference { + name: "Sec Settings" + label: qsTr("Second Settings") + live: true + icon.name: "regular:\uf1de" + + P.ColorPreference { + name: "Sstar Color" + label: qsTr("Star Color") + defaultValue: "#2196f3" + } + + P.Separator {} + + P.SwitchPreference { + id: sec_settings_show_orbit + name: "Show Orbit" + label: qsTr("Show Orbit") + defaultValue: true + } + + P.ColorPreference { + name: "Sorbit Color" + label: qsTr("Orbit Color") + enabled: sec_settings_show_orbit.value + defaultValue: "#616161" + } + } + + P.DialogPreference { + name: "MSec Settings" + label: qsTr("Millisecond Settings") + live: true + icon.name: "regular:\uf1de" + + P.ColorPreference { + name: "MSstar Color" + label: qsTr("Star Color") + defaultValue: "#9e9e9e" + } + + P.Separator {} + + P.SwitchPreference { + id: msec_settings_show_orbit + name: "Show Orbit" + label: qsTr("Show Orbit") + defaultValue: true + } + + P.ColorPreference { + name: "MSorbit Color" + label: qsTr("Orbit Color") + enabled: msec_settings_show_orbit.value + defaultValue: "#9e9e9e" + } + } + + 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; + } + } + } + + Text { + id: main_time + text: "" + visible: configs["BG Settings"]["Show Clock"] + color: configs["BG Settings"]["Clock Color"] + anchors.centerIn: parent + font.pointSize: 0.0009*configs["BG Settings"]["Center Radius"]*maxr*configs["BG Settings"]["Font Size"]/100 + font.weight: Font.Normal + font.family: "Microsoft YaHei" + } +} diff --git a/text_clock.qml b/text_clock.qml new file mode 100644 index 0000000..45fe1ca --- /dev/null +++ b/text_clock.qml @@ -0,0 +1,312 @@ +import QtQuick 2.12 + +import QtQuick.Controls 2.12 +import QtQuick.Layouts 1.12 +import QtGraphicalEffects 1.0 + +import NERvGear 1.0 as NVG +import NERvGear.Templates 1.0 as T +import NERvGear.Preferences 1.0 as P + + + +T.Widget { + id: widget + solid: true + title: qsTr("Text Clock") + resizable: true + + property real day: 1 + property real hours: 0 + property string minutes: "" + property string seconds: "" + + readonly property string hlight_color: widget.settings.styles["HighLight Color"] + readonly property string normal_color: widget.settings.styles["Normal Color"] + readonly property string rfulltext: "ITAISSL" + ((day===5) ? "TGIF" : "GTFI") + "
" + + "FJLVZGABOUT
" + + "ACQUARTERBS
" + + "TWENTYFIVEX
" + + "HALFBTENFTO
" + + "PASTERUNINE
" + + "ONESIXTHREE
" + + "FOURFIVETWO
" + + "EIGHTELEVEN
" + + "SEVENTNOONE
" + + "TENSEOCLOCK
" + + "AMIDNIGHTVW
" + + + property var rcolors: [hlight_color, hlight_color, hlight_color, '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', ''] + readonly property var rcindex: {"M15": 3, "M20": 4, "M5": 5, "M30": 6, "M10": 7, "TO": 8, "PAST": 9, + "9": 10, "1": 11, "13": 11, "6": 12, "3": 13, "4": 14, "5": 15, "2": 16, + "8": 17, "11": 18, "23": 18, "7": 19, "12": 20, "10": 21, "OCLOCK": 22, "0": 23, "24": 23} + + readonly property var fonts: Qt.fontFamilies() + readonly property var fontweight: [Font.Light, Font.Normal, Font.DemiBold, Font.Bold, Font.Black] + readonly property var sfontweight: ["Light", "Normal", "DemiBold", "Bold", "Black"] + + function stringFormat(rtext, format) { + if (!rtext) + return null; + var str = rtext; + for (var i = 0; i < format.length; i++) + { + var re = new RegExp('\\{' + i + '\\}', 'gm'); + str = str.replace(re, format[i]); + } + return str; + } + + function clearHLColors() { + for(let i=3; i<24; i++) { + rcolors[i] = ""; + } + } + + function updateHLColors(){ + for(let i=0; i 12 && hours !== 23) { + hours = hours - 12; + } + + if (minutes < 10) { + minutes = 0 + minutes; + } + if (seconds < 10) { + seconds = 0 + seconds; + } + + var minsSecs = minutes + seconds; + if (minsSecs > 3230) { + hours++; + } + + clearHLColors(); + updateHLColors(hours); + + if ((minsSecs >= 5730 && minsSecs < 6000) || (minsSecs >= 0 && minsSecs < 230)) { + if (hours !== 24 && hours !== 0) { + updateHLColors("OCLOCK"); + } + } else if (minsSecs >= 230 && minsSecs < 730) { + updateHLColors("M5","PAST"); + } else if (minsSecs >= 730 && minsSecs < 1230) { + updateHLColors("M10", "PAST"); + } else if (minsSecs >= 1230 && minsSecs < 1730) { + updateHLColors("M15","PAST"); + } else if (minsSecs >= 1730 && minsSecs < 2230) { + updateHLColors("M20", "PAST"); + } else if (minsSecs >= 2230 && minsSecs < 2730) { + updateHLColors("M20", "M5", "PAST"); + } else if (minsSecs >= 2730 && minsSecs < 3230) { + updateHLColors("M30", "PAST"); + } else if (minsSecs >= 3230 && minsSecs < 3730) { + updateHLColors("M20", "M5", "TO"); + } else if (minsSecs >= 3730 && minsSecs < 4230) { + updateHLColors("M20", "TO"); + } else if (minsSecs >= 4230 && minsSecs < 4730) { + updateHLColors("M15", "TO"); + } else if (minsSecs >= 4730 && minsSecs < 5230) { + updateHLColors("M10", "TO"); + } else if (minsSecs >= 5230 && minsSecs < 5730) { + updateHLColors("M5", "TO"); + } + main.text = stringFormat(rfulltext, rcolors); + } + } + + 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: 580 + maximumWidth: minimumWidth + maximumHeight: minimumHeight + width: minimumWidth + height: minimumHeight + + transientParent: widget.NVG.View.window + + property var configuration + + ColumnLayout { + id: root + anchors.fill: parent + anchors.margins: 16 + anchors.topMargin: 0 + + Row { + spacing: 234 + + ToolButton { + text: qsTr("Save") + onClicked: { + configuration = rootPreference.save(); + widget.settings.styles = configuration; + styleDialog.active = false; + } + } + + ToolButton { + text: qsTr("Reset") + onClicked: { + rootPreference.load(); + let cfg = rootPreference.save(); + widget.settings.styles = cfg; + } + } + } + + Label { + Layout.alignment: Qt.AlignCenter + text: qsTr("Settings") + font.pixelSize: 24 + } + + 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.SelectPreference { + name: "Font Name" + label: qsTr("Font Style") + icon.name: "solid:\uf1fc" + defaultValue: 408 + model: fonts + } + + P.SelectPreference { + name: "Font Weight" + label: qsTr("Font Weight") + icon.name: "solid:\uf1fc" + defaultValue: 0 + model: sfontweight + } + + P.ColorPreference { + name: "HighLight Color" + label: qsTr("HighLight Color") + defaultValue: "#FFF" + } + + P.ColorPreference { + name: "Normal Color" + label: qsTr("Normal Color") + defaultValue: "#333333" + } + + P.SliderPreference { + name: "Font Size" + label: qsTr("Font Size") + from: 1 + to: 40 + stepSize: 1 + defaultValue: 20 + displayValue: value + } + + P.SliderPreference { + name: "Letter Space" + label: qsTr("Letter Space") + from: 1 + to: 40 + stepSize: 1 + defaultValue: 20 + displayValue: value + } + + P.SliderPreference { + name: "Line Height" + label: qsTr("Line Spacing") + from: 0.8 + to: 2 + stepSize: 0.1 + defaultValue: 1.5 + displayValue: value.toFixed(1) + } + + 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; + } + } + } + + Component.onCompleted: { + if (!widget.settings.styles) { + widget.settings.styles = {"Font Name": fonts.length-1, "Font Weight": 0, "Normal Color": "#333333", "HighLight Color": "#FFF", "Font Size": 20, "Letter Space": 20, "Line Height": 1.5}; + } + } +}