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 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 ? 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":fonts.length-1,"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 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: fonts.length-1 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(); } } } }