added two new themes, reworked Crypto.qml and Stats.qml, standardized the buttons for the modules, added a new Sidebar widget which contains new 3 modules
This commit is contained in:
588
widgets/sidebar/sysinfo/SysInfo.qml
Normal file
588
widgets/sidebar/sysinfo/SysInfo.qml
Normal file
@@ -0,0 +1,588 @@
|
||||
import QtQuick
|
||||
import QtQuick.Layouts
|
||||
import Quickshell
|
||||
import Quickshell.Io
|
||||
import "../../../config" as Cfg
|
||||
|
||||
ColumnLayout {
|
||||
id: root
|
||||
spacing: 0
|
||||
|
||||
readonly property var t: Cfg.Config.theme
|
||||
|
||||
property string osName: "Linux"
|
||||
property string kernelVer: ""
|
||||
property real cpuPct: 0
|
||||
property real memPct: 0
|
||||
property real memUsedGb: 0
|
||||
property real swapPct: 0
|
||||
property real swapUsedGb: 0
|
||||
property bool hasSwap: false
|
||||
property real diskPct: 0
|
||||
property real diskUsedGb: 0
|
||||
property string uptimeStr: "—"
|
||||
property real battPct: -1
|
||||
property bool battCharging: false
|
||||
property real cpuTemp: -1
|
||||
property real gpuTemp: -1
|
||||
property bool netOnline: false
|
||||
property var _cpuPrev: ({ total: 0, idle: 0 })
|
||||
|
||||
Behavior on cpuPct { NumberAnimation { duration: 800; easing.type: Easing.OutCubic } }
|
||||
Behavior on memPct { NumberAnimation { duration: 800; easing.type: Easing.OutCubic } }
|
||||
Behavior on memUsedGb { NumberAnimation { duration: 800; easing.type: Easing.OutCubic } }
|
||||
Behavior on swapPct { NumberAnimation { duration: 800; easing.type: Easing.OutCubic } }
|
||||
Behavior on swapUsedGb { NumberAnimation { duration: 800; easing.type: Easing.OutCubic } }
|
||||
Behavior on diskPct { NumberAnimation { duration: 800; easing.type: Easing.OutCubic } }
|
||||
Behavior on diskUsedGb { NumberAnimation { duration: 800; easing.type: Easing.OutCubic } }
|
||||
Behavior on battPct { NumberAnimation { duration: 800; easing.type: Easing.OutCubic } }
|
||||
Behavior on cpuTemp { NumberAnimation { duration: 800; easing.type: Easing.OutCubic } }
|
||||
Behavior on gpuTemp { NumberAnimation { duration: 800; easing.type: Easing.OutCubic } }
|
||||
|
||||
Process {
|
||||
running: true
|
||||
command: ["sh", "-c",
|
||||
"grep '^PRETTY_NAME=' /etc/os-release 2>/dev/null | cut -d'\"' -f2 || echo Linux"]
|
||||
stdout: SplitParser { onRead: d => { root.osName = d.trim() } }
|
||||
}
|
||||
Process {
|
||||
running: true
|
||||
command: ["uname", "-r"]
|
||||
stdout: SplitParser { onRead: d => { root.kernelVer = d.trim() } }
|
||||
}
|
||||
|
||||
Process {
|
||||
id: cpuTempProc
|
||||
property string _buf: ""
|
||||
command: ["sh", "-c",
|
||||
"t=-1; for d in /sys/class/hwmon/hwmon*; do " +
|
||||
"n=$(cat $d/name 2>/dev/null); " +
|
||||
"if echo \"$n\" | grep -qiE 'coretemp|k10temp'; then " +
|
||||
"t=$(( $(cat $d/temp1_input 2>/dev/null) / 1000 )); break; " +
|
||||
"fi; done; echo $t"]
|
||||
stdout: SplitParser { onRead: d => { cpuTempProc._buf = d } }
|
||||
onRunningChanged: {
|
||||
if (running || !_buf) return
|
||||
root.cpuTemp = parseInt(_buf)
|
||||
_buf = ""
|
||||
}
|
||||
}
|
||||
|
||||
Process {
|
||||
id: gpuTempProc
|
||||
property string _buf: ""
|
||||
command: ["sh", "-c",
|
||||
"t=-1; for d in /sys/class/hwmon/hwmon*; do " +
|
||||
"n=$(cat $d/name 2>/dev/null); " +
|
||||
"if echo \"$n\" | grep -qiE 'amdgpu|radeon'; then " +
|
||||
"t=$(( $(cat $d/temp1_input 2>/dev/null) / 1000 )); break; " +
|
||||
"fi; done; echo $t"]
|
||||
stdout: SplitParser { onRead: d => { gpuTempProc._buf = d } }
|
||||
onRunningChanged: {
|
||||
if (running || !_buf) return
|
||||
root.gpuTemp = parseInt(_buf)
|
||||
_buf = ""
|
||||
}
|
||||
}
|
||||
|
||||
Process {
|
||||
id: cpuProc
|
||||
property string _buf: ""
|
||||
command: ["sh", "-c", "grep '^cpu ' /proc/stat | head -1"]
|
||||
stdout: SplitParser { onRead: d => { cpuProc._buf = d } }
|
||||
onRunningChanged: {
|
||||
if (running || !_buf) return
|
||||
var p = _buf.trim().split(/\s+/)
|
||||
var user = +p[1], nice = +p[2], sys = +p[3]
|
||||
var idle = +p[4], iow = +p[5], irq = +p[6], sirq = +p[7]
|
||||
var total = user + nice + sys + idle + iow + irq + sirq
|
||||
var idleSum = idle + iow
|
||||
if (root._cpuPrev.total > 0) {
|
||||
var dt = total - root._cpuPrev.total
|
||||
var di = idleSum - root._cpuPrev.idle
|
||||
root.cpuPct = dt > 0 ? Math.round((dt - di) / dt * 100) : 0
|
||||
}
|
||||
root._cpuPrev = { total: total, idle: idleSum }
|
||||
_buf = ""
|
||||
}
|
||||
}
|
||||
|
||||
Process {
|
||||
id: memProc
|
||||
property string _buf: ""
|
||||
command: ["sh", "-c", "free -b | awk '/^Mem:/{print $2,$3,$7}'"]
|
||||
stdout: SplitParser { onRead: d => { memProc._buf = d } }
|
||||
onRunningChanged: {
|
||||
if (running || !_buf) return
|
||||
var p = _buf.trim().split(/\s+/)
|
||||
var total = +p[0], avail = +p[2]
|
||||
var used = total - avail
|
||||
root.memUsedGb = used / 1073741824
|
||||
root.memPct = total > 0 ? (used / total * 100) : 0
|
||||
_buf = ""
|
||||
}
|
||||
}
|
||||
|
||||
Process {
|
||||
id: swapProc
|
||||
property string _buf: ""
|
||||
command: ["sh", "-c", "free -b | awk '/^Swap:/{print $2,$3}'"]
|
||||
stdout: SplitParser { onRead: d => { swapProc._buf = d } }
|
||||
onRunningChanged: {
|
||||
if (running || !_buf) return
|
||||
var p = _buf.trim().split(/\s+/)
|
||||
var total = +p[0], used = +p[1]
|
||||
root.hasSwap = total > 0
|
||||
root.swapUsedGb = total > 0 ? used / 1073741824 : 0
|
||||
root.swapPct = total > 0 ? (used / total * 100) : 0
|
||||
_buf = ""
|
||||
}
|
||||
}
|
||||
|
||||
Process {
|
||||
id: uptimeProc
|
||||
property string _buf: ""
|
||||
command: ["sh", "-c",
|
||||
"u=$(awk '{print int($1)}' /proc/uptime); " +
|
||||
"d=$((u/86400)); h=$(((u%86400)/3600)); m=$(((u%3600)/60)); " +
|
||||
"[ $d -gt 0 ] && echo ${d}d${h}h || [ $h -gt 0 ] && echo ${h}h${m}m || echo ${m}m"]
|
||||
stdout: SplitParser { onRead: d => { uptimeProc._buf = d } }
|
||||
onRunningChanged: {
|
||||
if (running || !_buf) return
|
||||
root.uptimeStr = _buf.trim()
|
||||
_buf = ""
|
||||
}
|
||||
}
|
||||
|
||||
Process {
|
||||
id: diskProc
|
||||
property string _buf: ""
|
||||
command: ["sh", "-c", "df -B1 / | awk 'NR==2{print $3,$2}'"]
|
||||
stdout: SplitParser { onRead: d => { diskProc._buf = d } }
|
||||
onRunningChanged: {
|
||||
if (running || !_buf) return
|
||||
var p = _buf.trim().split(/\s+/)
|
||||
var used = +p[0], total = +p[1]
|
||||
root.diskUsedGb = used / 1073741824
|
||||
root.diskPct = total > 0 ? (used / total * 100) : 0
|
||||
_buf = ""
|
||||
}
|
||||
}
|
||||
|
||||
Process {
|
||||
id: battProc
|
||||
property string _buf: ""
|
||||
command: ["sh", "-c",
|
||||
"p=/sys/class/power_supply/BAT0; " +
|
||||
"[ -f $p/capacity ] && echo $(cat $p/capacity) $(cat $p/status) || echo -1 Unknown"]
|
||||
stdout: SplitParser { onRead: d => { battProc._buf = d } }
|
||||
onRunningChanged: {
|
||||
if (running || !_buf) return
|
||||
var p = _buf.trim().split(/\s+/)
|
||||
root.battPct = parseInt(p[0])
|
||||
root.battCharging = (p[1] === "Charging" || p[1] === "Full")
|
||||
_buf = ""
|
||||
}
|
||||
}
|
||||
|
||||
Process {
|
||||
id: netProc
|
||||
property string _buf: ""
|
||||
command: ["sh", "-c", "ip route show default 2>/dev/null | grep -c default || echo 0"]
|
||||
stdout: SplitParser { onRead: d => { netProc._buf = d } }
|
||||
onRunningChanged: {
|
||||
if (running) return
|
||||
root.netOnline = parseInt(netProc._buf.trim()) > 0
|
||||
_buf = ""
|
||||
}
|
||||
}
|
||||
|
||||
function refresh() {
|
||||
if (!cpuProc.running) cpuProc.running = true
|
||||
if (!memProc.running) memProc.running = true
|
||||
if (!swapProc.running) swapProc.running = true
|
||||
if (!diskProc.running) diskProc.running = true
|
||||
if (!uptimeProc.running) uptimeProc.running = true
|
||||
if (!battProc.running) battProc.running = true
|
||||
if (!netProc.running) netProc.running = true
|
||||
if (!cpuTempProc.running) cpuTempProc.running = true
|
||||
if (!gpuTempProc.running) gpuTempProc.running = true
|
||||
}
|
||||
|
||||
Timer {
|
||||
interval: 5000
|
||||
running: true
|
||||
repeat: true
|
||||
triggeredOnStart: true
|
||||
onTriggered: root.refresh()
|
||||
}
|
||||
|
||||
RowLayout {
|
||||
Layout.fillWidth: true
|
||||
spacing: 10
|
||||
|
||||
Rectangle {
|
||||
width: 32; height: 32
|
||||
radius: 8
|
||||
color: Qt.alpha(root.t.sysInfoAccent, 0.12)
|
||||
border.color: Qt.alpha(root.t.sysInfoAccent, 0.22)
|
||||
border.width: 1
|
||||
Layout.alignment: Qt.AlignVCenter
|
||||
|
||||
Text {
|
||||
anchors.centerIn: parent
|
||||
text: ""
|
||||
color: root.t.sysInfoAccent
|
||||
font.pixelSize: 20
|
||||
}
|
||||
}
|
||||
|
||||
ColumnLayout {
|
||||
spacing: 2
|
||||
Layout.fillWidth: true
|
||||
Layout.alignment: Qt.AlignVCenter
|
||||
|
||||
Text {
|
||||
text: root.osName
|
||||
color: root.t.sysInfoTextMain
|
||||
font.pixelSize: 13
|
||||
font.weight: Font.DemiBold
|
||||
elide: Text.ElideRight
|
||||
Layout.fillWidth: true
|
||||
}
|
||||
Text {
|
||||
text: root.kernelVer
|
||||
color: root.t.sysInfoTextDim
|
||||
font.pixelSize: 10
|
||||
opacity: 0.75
|
||||
elide: Text.ElideRight
|
||||
Layout.fillWidth: true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Item { Layout.preferredHeight: 12 }
|
||||
|
||||
Rectangle {
|
||||
Layout.fillWidth: true
|
||||
height: 1
|
||||
gradient: Gradient {
|
||||
orientation: Gradient.Horizontal
|
||||
GradientStop { position: 0.0; color: Qt.alpha(root.t.sysInfoAccent, 0.5) }
|
||||
GradientStop { position: 1.0; color: "transparent" }
|
||||
}
|
||||
}
|
||||
|
||||
Item { Layout.preferredHeight: 10 }
|
||||
|
||||
SysInfoRow {
|
||||
Layout.fillWidth: true
|
||||
icon: ""
|
||||
label: "CPU"
|
||||
value: Math.round(root.cpuPct) + "%"
|
||||
iconColor: root.t.sysInfoCpuColor
|
||||
dimColor: root.t.sysInfoTextDim
|
||||
textColor: root.t.sysInfoTextMain
|
||||
showBar: true
|
||||
barPct: root.cpuPct
|
||||
barColor: root.t.sysInfoCpuColor
|
||||
trackColor: root.t.sysInfoTrackColor
|
||||
}
|
||||
|
||||
Item { Layout.preferredHeight: 9 }
|
||||
|
||||
SysInfoRow {
|
||||
Layout.fillWidth: true
|
||||
visible: root.cpuTemp >= 0
|
||||
icon: ""
|
||||
label: "CPU Temp"
|
||||
value: root.cpuTemp >= 0 ? Math.round(root.cpuTemp) + "°C" : "—"
|
||||
iconColor: root.cpuTemp > 80 ? root.t.statusErr
|
||||
: root.cpuTemp > 60 ? root.t.statusWarn
|
||||
: root.t.sysInfoCpuTempColor
|
||||
dimColor: root.t.sysInfoTextDim
|
||||
textColor: root.t.sysInfoTextMain
|
||||
showBar: true
|
||||
barPct: Math.min(100, Math.round(root.cpuTemp * 100 / 95))
|
||||
barColor: root.cpuTemp > 80 ? root.t.statusErr
|
||||
: root.cpuTemp > 60 ? root.t.statusWarn
|
||||
: root.t.sysInfoCpuTempColor
|
||||
trackColor: root.t.sysInfoTrackColor
|
||||
}
|
||||
|
||||
Item {
|
||||
Layout.fillWidth: true
|
||||
implicitHeight: root.gpuTemp >= 0 ? 9 : 0
|
||||
visible: root.gpuTemp >= 0
|
||||
}
|
||||
|
||||
SysInfoRow {
|
||||
Layout.fillWidth: true
|
||||
visible: root.gpuTemp >= 0
|
||||
icon: ""
|
||||
label: "GPU Temp"
|
||||
value: Math.round(root.gpuTemp) + "°C"
|
||||
iconColor: root.gpuTemp > 80 ? root.t.statusErr
|
||||
: root.gpuTemp > 65 ? root.t.statusWarn
|
||||
: root.t.sysInfoGpuColor
|
||||
dimColor: root.t.sysInfoTextDim
|
||||
textColor: root.t.sysInfoTextMain
|
||||
showBar: true
|
||||
barPct: Math.min(100, Math.round(root.gpuTemp * 100 / 95))
|
||||
barColor: root.gpuTemp > 80 ? root.t.statusErr
|
||||
: root.gpuTemp > 65 ? root.t.statusWarn
|
||||
: root.t.sysInfoGpuColor
|
||||
trackColor: root.t.sysInfoTrackColor
|
||||
}
|
||||
|
||||
Item { Layout.preferredHeight: 9 }
|
||||
|
||||
SysInfoRow {
|
||||
Layout.fillWidth: true
|
||||
icon: ""
|
||||
label: "Memory"
|
||||
value: root.memUsedGb.toFixed(2) + " GB"
|
||||
iconColor: root.t.sysInfoMemColor
|
||||
dimColor: root.t.sysInfoTextDim
|
||||
textColor: root.t.sysInfoTextMain
|
||||
showBar: true
|
||||
barPct: root.memPct
|
||||
barColor: root.t.sysInfoMemColor
|
||||
trackColor: root.t.sysInfoTrackColor
|
||||
}
|
||||
|
||||
Item { Layout.preferredHeight: 9 }
|
||||
|
||||
SysInfoRow {
|
||||
Layout.fillWidth: true
|
||||
icon: ""
|
||||
label: "Disk (/)"
|
||||
value: root.diskUsedGb.toFixed(1) + " GB"
|
||||
iconColor: root.t.sysInfoDiskColor
|
||||
dimColor: root.t.sysInfoTextDim
|
||||
textColor: root.t.sysInfoTextMain
|
||||
showBar: true
|
||||
barPct: root.diskPct
|
||||
barColor: root.t.sysInfoDiskColor
|
||||
trackColor: root.t.sysInfoTrackColor
|
||||
}
|
||||
|
||||
Item {
|
||||
Layout.fillWidth: true
|
||||
implicitHeight: root.hasSwap ? swapItem.implicitHeight + 9 : 0
|
||||
visible: root.hasSwap
|
||||
clip: true
|
||||
|
||||
ColumnLayout {
|
||||
id: swapItem
|
||||
anchors { top: parent.top; left: parent.left; right: parent.right }
|
||||
anchors.topMargin: 9
|
||||
spacing: 5
|
||||
|
||||
SysInfoRow {
|
||||
Layout.fillWidth: true
|
||||
icon: ""
|
||||
label: "Swap"
|
||||
value: root.swapUsedGb.toFixed(1) + " GB"
|
||||
iconColor: root.t.sysInfoMemColor
|
||||
dimColor: root.t.sysInfoTextDim
|
||||
textColor: root.t.sysInfoTextMain
|
||||
showBar: true
|
||||
barPct: root.swapPct
|
||||
barColor: root.t.sysInfoMemColor
|
||||
trackColor: root.t.sysInfoTrackColor
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Item { Layout.preferredHeight: 9 }
|
||||
|
||||
RowLayout {
|
||||
Layout.fillWidth: true
|
||||
spacing: 10
|
||||
|
||||
Rectangle {
|
||||
width: 18; height: 18
|
||||
radius: 4
|
||||
color: Qt.alpha(root.t.sysInfoAccent, 0.15)
|
||||
Layout.alignment: Qt.AlignVCenter
|
||||
|
||||
Text {
|
||||
anchors.centerIn: parent
|
||||
text: ""
|
||||
color: root.t.sysInfoAccent
|
||||
font.pixelSize: 12
|
||||
}
|
||||
}
|
||||
|
||||
Text {
|
||||
text: "Uptime"
|
||||
color: root.t.sysInfoTextDim
|
||||
font.pixelSize: 12
|
||||
Layout.fillWidth: true
|
||||
Layout.alignment: Qt.AlignVCenter
|
||||
}
|
||||
|
||||
Text {
|
||||
text: root.uptimeStr
|
||||
color: root.t.sysInfoTextMain
|
||||
font.pixelSize: 12
|
||||
font.weight: Font.Medium
|
||||
Layout.alignment: Qt.AlignVCenter
|
||||
}
|
||||
}
|
||||
|
||||
Item { Layout.preferredHeight: 9 }
|
||||
|
||||
RowLayout {
|
||||
Layout.fillWidth: true
|
||||
spacing: 10
|
||||
|
||||
Rectangle {
|
||||
width: 18; height: 18
|
||||
radius: 4
|
||||
color: Qt.alpha(root.t.sysInfoAccent, 0.15)
|
||||
Layout.alignment: Qt.AlignVCenter
|
||||
|
||||
Text {
|
||||
anchors.centerIn: parent
|
||||
text: ""
|
||||
color: root.t.sysInfoAccent
|
||||
font.pixelSize: 12
|
||||
}
|
||||
}
|
||||
|
||||
Text {
|
||||
text: "Kernel"
|
||||
color: root.t.sysInfoTextDim
|
||||
font.pixelSize: 12
|
||||
Layout.fillWidth: true
|
||||
Layout.alignment: Qt.AlignVCenter
|
||||
}
|
||||
|
||||
Text {
|
||||
text: root.kernelVer
|
||||
color: root.t.sysInfoTextMain
|
||||
font.pixelSize: 12
|
||||
font.weight: Font.Medium
|
||||
Layout.alignment: Qt.AlignVCenter
|
||||
}
|
||||
}
|
||||
|
||||
Item {
|
||||
Layout.fillWidth: true
|
||||
implicitHeight: root.battPct >= 0 ? battItem.implicitHeight + 9 : 0
|
||||
visible: root.battPct >= 0
|
||||
clip: true
|
||||
|
||||
ColumnLayout {
|
||||
id: battItem
|
||||
anchors { top: parent.top; left: parent.left; right: parent.right }
|
||||
anchors.topMargin: 9
|
||||
spacing: 5
|
||||
|
||||
RowLayout {
|
||||
Layout.fillWidth: true
|
||||
spacing: 10
|
||||
|
||||
Rectangle {
|
||||
width: 18; height: 18
|
||||
radius: 4
|
||||
color: Qt.alpha(battIconColor, 0.15)
|
||||
Layout.alignment: Qt.AlignVCenter
|
||||
readonly property color battIconColor:
|
||||
root.battPct <= 20 ? root.t.statusErr
|
||||
: root.battPct <= 40 ? root.t.statusWarn
|
||||
: root.battCharging ? root.t.statusOk
|
||||
: root.t.sysInfoAccent
|
||||
|
||||
Text {
|
||||
anchors.centerIn: parent
|
||||
text: root.battCharging ? ""
|
||||
: root.battPct > 80 ? ""
|
||||
: root.battPct > 60 ? ""
|
||||
: root.battPct > 40 ? ""
|
||||
: root.battPct > 20 ? ""
|
||||
: ""
|
||||
color: parent.battIconColor
|
||||
font.pixelSize: 12
|
||||
}
|
||||
}
|
||||
|
||||
Text {
|
||||
text: "Battery"
|
||||
color: root.t.sysInfoTextDim
|
||||
font.pixelSize: 12
|
||||
Layout.fillWidth: true
|
||||
Layout.alignment: Qt.AlignVCenter
|
||||
}
|
||||
|
||||
Text {
|
||||
text: Math.round(root.battPct) + "%"
|
||||
color: root.t.sysInfoTextMain
|
||||
font.pixelSize: 12
|
||||
Layout.alignment: Qt.AlignVCenter
|
||||
}
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
Layout.fillWidth: true
|
||||
height: 3
|
||||
radius: 2
|
||||
color: root.t.sysInfoTrackColor
|
||||
|
||||
readonly property color fillColor:
|
||||
root.battPct <= 20 ? root.t.statusErr
|
||||
: root.battPct <= 40 ? root.t.statusWarn
|
||||
: root.battCharging ? root.t.statusOk
|
||||
: root.t.sysInfoAccent
|
||||
|
||||
Rectangle {
|
||||
width: parent.width * Math.max(0, Math.min(root.battPct, 100)) / 100
|
||||
height: parent.height
|
||||
radius: parent.radius
|
||||
color: parent.fillColor
|
||||
Behavior on width { NumberAnimation { duration: 800; easing.type: Easing.OutCubic } }
|
||||
Behavior on color { ColorAnimation { duration: 400 } }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Item { Layout.preferredHeight: 9 }
|
||||
|
||||
RowLayout {
|
||||
Layout.fillWidth: true
|
||||
spacing: 10
|
||||
|
||||
Rectangle {
|
||||
width: 18; height: 18
|
||||
radius: 4
|
||||
color: Qt.alpha(root.netOnline ? root.t.statusOk : root.t.sysInfoTextDim, 0.15)
|
||||
Layout.alignment: Qt.AlignVCenter
|
||||
|
||||
Text {
|
||||
anchors.centerIn: parent
|
||||
text: root.netOnline ? "" : ""
|
||||
color: root.netOnline ? root.t.statusOk : root.t.sysInfoTextDim
|
||||
font.pixelSize: 12
|
||||
}
|
||||
}
|
||||
|
||||
Text {
|
||||
text: "Network"
|
||||
color: root.t.sysInfoTextDim
|
||||
font.pixelSize: 12
|
||||
Layout.fillWidth: true
|
||||
Layout.alignment: Qt.AlignVCenter
|
||||
}
|
||||
|
||||
Text {
|
||||
text: root.netOnline ? "Connected" : "Offline"
|
||||
color: root.netOnline ? root.t.statusOk : root.t.statusErr
|
||||
font.pixelSize: 12
|
||||
font.weight: Font.Medium
|
||||
Layout.alignment: Qt.AlignVCenter
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user