mirror of
https://github.com/AvengeMedia/DankMaterialShell.git
synced 2026-01-25 05:52:50 -05:00
widgets: add spacer, divider, tweak interface
This commit is contained in:
@@ -5,21 +5,6 @@ import qs.Services
|
||||
import qs.Widgets
|
||||
|
||||
Column {
|
||||
anchors.fill: parent
|
||||
spacing: Theme.spacingM
|
||||
|
||||
Component.onCompleted: {
|
||||
SysMonitorService.addRef();
|
||||
SysMonitorService.addRef();
|
||||
// Trigger immediate updates for both services
|
||||
SysMonitorService.updateAllStats();
|
||||
}
|
||||
|
||||
Component.onDestruction: {
|
||||
SysMonitorService.removeRef();
|
||||
SysMonitorService.removeRef();
|
||||
}
|
||||
|
||||
function formatNetworkSpeed(bytesPerSec) {
|
||||
if (bytesPerSec < 1024)
|
||||
return bytesPerSec.toFixed(0) + " B/s";
|
||||
@@ -40,6 +25,19 @@ Column {
|
||||
return (bytesPerSec / (1024 * 1024 * 1024)).toFixed(1) + " GB/s";
|
||||
}
|
||||
|
||||
anchors.fill: parent
|
||||
spacing: Theme.spacingM
|
||||
Component.onCompleted: {
|
||||
SysMonitorService.addRef();
|
||||
SysMonitorService.addRef();
|
||||
// Trigger immediate updates for both services
|
||||
SysMonitorService.updateAllStats();
|
||||
}
|
||||
Component.onDestruction: {
|
||||
SysMonitorService.removeRef();
|
||||
SysMonitorService.removeRef();
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
width: parent.width
|
||||
height: 200
|
||||
@@ -279,9 +277,7 @@ Column {
|
||||
}
|
||||
|
||||
StyledText {
|
||||
text: SysMonitorService.totalSwapKB > 0 ?
|
||||
SysMonitorService.formatSystemMemory(SysMonitorService.usedSwapKB) + " / " + SysMonitorService.formatSystemMemory(SysMonitorService.totalSwapKB) :
|
||||
"No swap configured"
|
||||
text: SysMonitorService.totalSwapKB > 0 ? SysMonitorService.formatSystemMemory(SysMonitorService.usedSwapKB) + " / " + SysMonitorService.formatSystemMemory(SysMonitorService.totalSwapKB) : "No swap configured"
|
||||
font.pixelSize: Theme.fontSizeSmall
|
||||
color: Theme.surfaceVariantText
|
||||
}
|
||||
@@ -309,10 +305,16 @@ Column {
|
||||
height: parent.height
|
||||
radius: parent.radius
|
||||
color: {
|
||||
if (!SysMonitorService.totalSwapKB) return Qt.rgba(Theme.surfaceText.r, Theme.surfaceText.g, Theme.surfaceText.b, 0.3);
|
||||
if (!SysMonitorService.totalSwapKB)
|
||||
return Qt.rgba(Theme.surfaceText.r, Theme.surfaceText.g, Theme.surfaceText.b, 0.3);
|
||||
|
||||
const usage = SysMonitorService.usedSwapKB / SysMonitorService.totalSwapKB;
|
||||
if (usage > 0.9) return Theme.error;
|
||||
if (usage > 0.7) return Theme.warning;
|
||||
if (usage > 0.9)
|
||||
return Theme.error;
|
||||
|
||||
if (usage > 0.7)
|
||||
return Theme.warning;
|
||||
|
||||
return Theme.info;
|
||||
}
|
||||
|
||||
@@ -320,8 +322,11 @@ Column {
|
||||
NumberAnimation {
|
||||
duration: Theme.mediumDuration
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
StyledText {
|
||||
|
||||
@@ -12,24 +12,20 @@ Popup {
|
||||
property var processData: null
|
||||
|
||||
function show(x, y) {
|
||||
if (!processContextMenu.parent && typeof Overlay !== "undefined" && Overlay.overlay) {
|
||||
if (!processContextMenu.parent && typeof Overlay !== "undefined" && Overlay.overlay)
|
||||
processContextMenu.parent = Overlay.overlay;
|
||||
}
|
||||
|
||||
|
||||
const menuWidth = 180;
|
||||
const menuHeight = menuColumn.implicitHeight + Theme.spacingS * 2;
|
||||
const screenWidth = Screen.width;
|
||||
const screenHeight = Screen.height;
|
||||
|
||||
let finalX = x;
|
||||
let finalY = y;
|
||||
|
||||
if (x + menuWidth > screenWidth - 20) {
|
||||
if (x + menuWidth > screenWidth - 20)
|
||||
finalX = x - menuWidth;
|
||||
}
|
||||
if (y + menuHeight > screenHeight - 20) {
|
||||
|
||||
if (y + menuHeight > screenHeight - 20)
|
||||
finalY = y - menuHeight;
|
||||
}
|
||||
|
||||
processContextMenu.x = Math.max(20, finalX);
|
||||
processContextMenu.y = Math.max(20, finalY);
|
||||
@@ -41,29 +37,29 @@ Popup {
|
||||
padding: 0
|
||||
modal: false
|
||||
closePolicy: Popup.CloseOnEscape
|
||||
|
||||
onClosed: {
|
||||
closePolicy = Popup.CloseOnEscape;
|
||||
}
|
||||
|
||||
onOpened: {
|
||||
outsideClickTimer.start();
|
||||
}
|
||||
|
||||
|
||||
Timer {
|
||||
id: outsideClickTimer
|
||||
|
||||
interval: 100
|
||||
onTriggered: {
|
||||
processContextMenu.closePolicy = Popup.CloseOnEscape | Popup.CloseOnPressOutside;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
background: Rectangle {
|
||||
color: "transparent"
|
||||
}
|
||||
|
||||
contentItem: Rectangle {
|
||||
id: menuContent
|
||||
|
||||
color: Theme.popupBackground()
|
||||
radius: Theme.cornerRadiusLarge
|
||||
border.color: Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.08)
|
||||
@@ -71,6 +67,7 @@ Popup {
|
||||
|
||||
Column {
|
||||
id: menuColumn
|
||||
|
||||
anchors.fill: parent
|
||||
anchors.margins: Theme.spacingS
|
||||
spacing: 1
|
||||
@@ -93,16 +90,18 @@ Popup {
|
||||
|
||||
MouseArea {
|
||||
id: copyPidArea
|
||||
|
||||
anchors.fill: parent
|
||||
hoverEnabled: true
|
||||
cursorShape: Qt.PointingHandCursor
|
||||
onClicked: {
|
||||
if (processContextMenu.processData) {
|
||||
if (processContextMenu.processData)
|
||||
Quickshell.execDetached(["wl-copy", processContextMenu.processData.pid.toString()]);
|
||||
}
|
||||
|
||||
processContextMenu.close();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
@@ -123,6 +122,7 @@ Popup {
|
||||
|
||||
MouseArea {
|
||||
id: copyNameArea
|
||||
|
||||
anchors.fill: parent
|
||||
hoverEnabled: true
|
||||
cursorShape: Qt.PointingHandCursor
|
||||
@@ -134,6 +134,7 @@ Popup {
|
||||
processContextMenu.close();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
@@ -148,6 +149,7 @@ Popup {
|
||||
height: 1
|
||||
color: Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.2)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
@@ -170,17 +172,19 @@ Popup {
|
||||
|
||||
MouseArea {
|
||||
id: killArea
|
||||
|
||||
anchors.fill: parent
|
||||
hoverEnabled: true
|
||||
cursorShape: parent.enabled ? Qt.PointingHandCursor : Qt.ArrowCursor
|
||||
enabled: parent.enabled
|
||||
onClicked: {
|
||||
if (processContextMenu.processData) {
|
||||
if (processContextMenu.processData)
|
||||
Quickshell.execDetached(["kill", processContextMenu.processData.pid.toString()]);
|
||||
}
|
||||
|
||||
processContextMenu.close();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
@@ -203,18 +207,23 @@ Popup {
|
||||
|
||||
MouseArea {
|
||||
id: forceKillArea
|
||||
|
||||
anchors.fill: parent
|
||||
hoverEnabled: true
|
||||
cursorShape: parent.enabled ? Qt.PointingHandCursor : Qt.ArrowCursor
|
||||
enabled: parent.enabled
|
||||
onClicked: {
|
||||
if (processContextMenu.processData) {
|
||||
if (processContextMenu.processData)
|
||||
Quickshell.execDetached(["kill", "-9", processContextMenu.processData.pid.toString()]);
|
||||
}
|
||||
|
||||
processContextMenu.close();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -144,10 +144,10 @@ Rectangle {
|
||||
if (process && process.memoryKB > 1024 * 1024)
|
||||
return Theme.error;
|
||||
|
||||
if (process && process.memoryKB > 512 * 1024)
|
||||
if (process && process.memoryKB > 512 * 1024)
|
||||
return Theme.warning;
|
||||
|
||||
return Theme.surfaceText;
|
||||
return Theme.surfaceText;
|
||||
}
|
||||
anchors.centerIn: parent
|
||||
}
|
||||
@@ -212,4 +212,4 @@ Rectangle {
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,9 +7,9 @@ import Quickshell.Io
|
||||
import Quickshell.Wayland
|
||||
import Quickshell.Widgets
|
||||
import qs.Common
|
||||
import qs.Modules.ProcessList
|
||||
import qs.Services
|
||||
import qs.Widgets
|
||||
import qs.Modules.ProcessList
|
||||
|
||||
PanelWindow {
|
||||
id: processListPopout
|
||||
@@ -20,9 +20,9 @@ PanelWindow {
|
||||
function hide() {
|
||||
isVisible = false;
|
||||
// Close any open context menus
|
||||
if (processContextMenu.visible) {
|
||||
if (processContextMenu.visible)
|
||||
processContextMenu.close();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
function show() {
|
||||
@@ -37,11 +37,6 @@ PanelWindow {
|
||||
}
|
||||
|
||||
visible: isVisible
|
||||
|
||||
Ref {
|
||||
service: SysMonitorService
|
||||
}
|
||||
|
||||
implicitWidth: 600
|
||||
implicitHeight: 600
|
||||
WlrLayershell.layer: WlrLayershell.Overlay
|
||||
@@ -49,6 +44,10 @@ PanelWindow {
|
||||
WlrLayershell.keyboardFocus: WlrKeyboardFocus.None
|
||||
color: "transparent"
|
||||
|
||||
Ref {
|
||||
service: SysMonitorService
|
||||
}
|
||||
|
||||
anchors {
|
||||
top: true
|
||||
left: true
|
||||
@@ -61,58 +60,58 @@ PanelWindow {
|
||||
onClicked: function(mouse) {
|
||||
// Only close if click is outside the content loader
|
||||
var localPos = mapToItem(contentLoader, mouse.x, mouse.y);
|
||||
if (localPos.x < 0 || localPos.x > contentLoader.width ||
|
||||
localPos.y < 0 || localPos.y > contentLoader.height) {
|
||||
if (localPos.x < 0 || localPos.x > contentLoader.width || localPos.y < 0 || localPos.y > contentLoader.height)
|
||||
processListPopout.hide();
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
Loader {
|
||||
id: contentLoader
|
||||
asynchronous: true
|
||||
active: processListPopout.isVisible
|
||||
|
||||
|
||||
readonly property real targetWidth: Math.min(600, Screen.width - Theme.spacingL * 2)
|
||||
readonly property real targetHeight: Math.min(600, Screen.height - Theme.barHeight - Theme.spacingS * 2)
|
||||
|
||||
asynchronous: true
|
||||
active: processListPopout.isVisible
|
||||
width: targetWidth
|
||||
height: targetHeight
|
||||
y: Theme.barHeight + Theme.spacingXS
|
||||
x: Math.max(Theme.spacingL, Screen.width - targetWidth - Theme.spacingL)
|
||||
|
||||
// GPU-accelerated scale + opacity animation
|
||||
opacity: processListPopout.isVisible ? 1 : 0
|
||||
scale: processListPopout.isVisible ? 1 : 0.9
|
||||
|
||||
|
||||
Behavior on opacity {
|
||||
NumberAnimation {
|
||||
duration: Anims.durMed
|
||||
easing.type: Easing.BezierSpline
|
||||
easing.bezierCurve: Anims.emphasized
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
Behavior on scale {
|
||||
NumberAnimation {
|
||||
duration: Anims.durMed
|
||||
easing.type: Easing.BezierSpline
|
||||
easing.bezierCurve: Anims.emphasized
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
sourceComponent: Rectangle {
|
||||
id: dropdownContent
|
||||
|
||||
radius: Theme.cornerRadiusLarge
|
||||
color: Theme.popupBackground()
|
||||
border.color: Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.08)
|
||||
border.width: 1
|
||||
clip: true
|
||||
|
||||
// Remove layer rendering for better performance
|
||||
antialiasing: true
|
||||
smooth: true
|
||||
|
||||
|
||||
ColumnLayout {
|
||||
anchors.fill: parent
|
||||
anchors.margins: Theme.spacingL
|
||||
@@ -128,9 +127,11 @@ PanelWindow {
|
||||
|
||||
SystemOverview {
|
||||
id: systemOverview
|
||||
|
||||
anchors.centerIn: parent
|
||||
width: parent.width - Theme.spacingM * 2
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
@@ -146,12 +147,17 @@ PanelWindow {
|
||||
anchors.margins: Theme.spacingS
|
||||
contextMenu: processContextMenu
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
ProcessContextMenu {
|
||||
id: processContextMenu
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -6,12 +6,12 @@ import qs.Widgets
|
||||
|
||||
Column {
|
||||
id: root
|
||||
|
||||
property var contextMenu: null
|
||||
|
||||
Component.onCompleted: {
|
||||
SysMonitorService.addRef();
|
||||
}
|
||||
|
||||
Component.onDestruction: {
|
||||
SysMonitorService.removeRef();
|
||||
}
|
||||
@@ -31,19 +31,20 @@ Column {
|
||||
anchors.left: parent.left
|
||||
anchors.leftMargin: 0
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
|
||||
|
||||
StyledText {
|
||||
text: "Process"
|
||||
font.pixelSize: Theme.fontSizeSmall
|
||||
font.family: Prefs.monoFontFamily
|
||||
font.weight: SysMonitorService.sortBy === "name" ? Font.Bold : Font.Medium
|
||||
color: Theme.surfaceText
|
||||
opacity: SysMonitorService.sortBy === "name" ? 1.0 : 0.7
|
||||
opacity: SysMonitorService.sortBy === "name" ? 1 : 0.7
|
||||
anchors.centerIn: parent
|
||||
}
|
||||
|
||||
|
||||
MouseArea {
|
||||
id: processHeaderArea
|
||||
|
||||
anchors.fill: parent
|
||||
hoverEnabled: true
|
||||
cursorShape: Qt.PointingHandCursor
|
||||
@@ -53,10 +54,14 @@ Column {
|
||||
processListView.restoreAnchor();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Behavior on color {
|
||||
ColorAnimation { duration: Theme.shortDuration }
|
||||
ColorAnimation {
|
||||
duration: Theme.shortDuration
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
@@ -74,12 +79,13 @@ Column {
|
||||
font.family: Prefs.monoFontFamily
|
||||
font.weight: SysMonitorService.sortBy === "cpu" ? Font.Bold : Font.Medium
|
||||
color: Theme.surfaceText
|
||||
opacity: SysMonitorService.sortBy === "cpu" ? 1.0 : 0.7
|
||||
opacity: SysMonitorService.sortBy === "cpu" ? 1 : 0.7
|
||||
anchors.centerIn: parent
|
||||
}
|
||||
|
||||
|
||||
MouseArea {
|
||||
id: cpuHeaderArea
|
||||
|
||||
anchors.fill: parent
|
||||
hoverEnabled: true
|
||||
cursorShape: Qt.PointingHandCursor
|
||||
@@ -89,10 +95,14 @@ Column {
|
||||
processListView.restoreAnchor();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Behavior on color {
|
||||
ColorAnimation { duration: Theme.shortDuration }
|
||||
ColorAnimation {
|
||||
duration: Theme.shortDuration
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
@@ -110,12 +120,13 @@ Column {
|
||||
font.family: Prefs.monoFontFamily
|
||||
font.weight: SysMonitorService.sortBy === "memory" ? Font.Bold : Font.Medium
|
||||
color: Theme.surfaceText
|
||||
opacity: SysMonitorService.sortBy === "memory" ? 1.0 : 0.7
|
||||
opacity: SysMonitorService.sortBy === "memory" ? 1 : 0.7
|
||||
anchors.centerIn: parent
|
||||
}
|
||||
|
||||
|
||||
MouseArea {
|
||||
id: memoryHeaderArea
|
||||
|
||||
anchors.fill: parent
|
||||
hoverEnabled: true
|
||||
cursorShape: Qt.PointingHandCursor
|
||||
@@ -125,10 +136,14 @@ Column {
|
||||
processListView.restoreAnchor();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Behavior on color {
|
||||
ColorAnimation { duration: Theme.shortDuration }
|
||||
ColorAnimation {
|
||||
duration: Theme.shortDuration
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
@@ -139,20 +154,21 @@ Column {
|
||||
anchors.right: parent.right
|
||||
anchors.rightMargin: 53
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
|
||||
|
||||
StyledText {
|
||||
text: "PID"
|
||||
font.pixelSize: Theme.fontSizeSmall
|
||||
font.family: Prefs.monoFontFamily
|
||||
font.weight: SysMonitorService.sortBy === "pid" ? Font.Bold : Font.Medium
|
||||
color: Theme.surfaceText
|
||||
opacity: SysMonitorService.sortBy === "pid" ? 1.0 : 0.7
|
||||
opacity: SysMonitorService.sortBy === "pid" ? 1 : 0.7
|
||||
horizontalAlignment: Text.AlignHCenter
|
||||
anchors.centerIn: parent
|
||||
}
|
||||
|
||||
|
||||
MouseArea {
|
||||
id: pidHeaderArea
|
||||
|
||||
anchors.fill: parent
|
||||
hoverEnabled: true
|
||||
cursorShape: Qt.PointingHandCursor
|
||||
@@ -162,10 +178,14 @@ Column {
|
||||
processListView.restoreAnchor();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Behavior on color {
|
||||
ColorAnimation { duration: Theme.shortDuration }
|
||||
ColorAnimation {
|
||||
duration: Theme.shortDuration
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
@@ -214,6 +234,43 @@ Column {
|
||||
property real stableY: 0
|
||||
property bool isUserScrolling: false
|
||||
property bool isScrollBarDragging: false
|
||||
property real wheelMultiplier: 1.8
|
||||
property int wheelBaseStep: 160
|
||||
property string keyRoleName: "pid"
|
||||
property var _anchorKey: undefined
|
||||
property real _anchorOffset: 0
|
||||
|
||||
function captureAnchor() {
|
||||
const y = contentY + 1;
|
||||
const idx = indexAt(0, y);
|
||||
if (idx < 0 || !model || idx >= model.length)
|
||||
return ;
|
||||
|
||||
_anchorKey = model[idx][keyRoleName];
|
||||
const it = itemAtIndex(idx);
|
||||
_anchorOffset = it ? (y - it.y) : 0;
|
||||
}
|
||||
|
||||
function restoreAnchor() {
|
||||
Qt.callLater(function() {
|
||||
if (_anchorKey === undefined || !model)
|
||||
return ;
|
||||
|
||||
var i = -1;
|
||||
for (var j = 0; j < model.length; ++j) {
|
||||
if (model[j][keyRoleName] === _anchorKey) {
|
||||
i = j;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (i < 0)
|
||||
return ;
|
||||
|
||||
positionViewAtIndex(i, ListView.Beginning);
|
||||
const maxY = Math.max(0, contentHeight - height);
|
||||
contentY = Math.max(0, Math.min(maxY, contentY + _anchorOffset - 1));
|
||||
});
|
||||
}
|
||||
|
||||
width: parent.width
|
||||
height: parent.height - columnHeaders.height
|
||||
@@ -223,18 +280,37 @@ Column {
|
||||
boundsBehavior: Flickable.StopAtBounds
|
||||
flickDeceleration: 1500
|
||||
maximumFlickVelocity: 2000
|
||||
|
||||
onMovementStarted: isUserScrolling = true
|
||||
onMovementEnded: {
|
||||
isUserScrolling = false
|
||||
if (contentY > 40) {
|
||||
stableY = contentY
|
||||
}
|
||||
isUserScrolling = false;
|
||||
if (contentY > 40)
|
||||
stableY = contentY;
|
||||
|
||||
}
|
||||
onContentYChanged: {
|
||||
if (!isUserScrolling && !isScrollBarDragging && visible && stableY > 40 && Math.abs(contentY - stableY) > 10)
|
||||
contentY = stableY;
|
||||
|
||||
}
|
||||
onModelChanged: {
|
||||
if (model && model.length > 0 && !isUserScrolling && stableY > 40)
|
||||
// Preserve scroll position when model updates
|
||||
Qt.callLater(function() {
|
||||
contentY = stableY;
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
onContentYChanged: {
|
||||
if (!isUserScrolling && !isScrollBarDragging && visible && stableY > 40 && Math.abs(contentY - stableY) > 10) {
|
||||
contentY = stableY
|
||||
WheelHandler {
|
||||
target: null
|
||||
onWheel: (ev) => {
|
||||
let dy = ev.pixelDelta.y !== 0 ? ev.pixelDelta.y : (ev.angleDelta.y / 120) * processListView.wheelBaseStep;
|
||||
if (ev.inverted)
|
||||
dy = -dy;
|
||||
|
||||
const maxY = Math.max(0, processListView.contentHeight - processListView.height);
|
||||
processListView.contentY = Math.max(0, Math.min(maxY, processListView.contentY - dy * processListView.wheelMultiplier));
|
||||
ev.accepted = true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -243,74 +319,22 @@ Column {
|
||||
contextMenu: root.contextMenu
|
||||
}
|
||||
|
||||
ScrollBar.vertical: ScrollBar {
|
||||
ScrollBar.vertical: ScrollBar {
|
||||
id: verticalScrollBar
|
||||
policy: ScrollBar.AsNeeded
|
||||
|
||||
|
||||
policy: ScrollBar.AsNeeded
|
||||
onPressedChanged: {
|
||||
processListView.isScrollBarDragging = pressed
|
||||
if (!pressed && processListView.contentY > 40) {
|
||||
processListView.stableY = processListView.contentY
|
||||
}
|
||||
}
|
||||
}
|
||||
ScrollBar.horizontal: ScrollBar { policy: ScrollBar.AlwaysOff }
|
||||
processListView.isScrollBarDragging = pressed;
|
||||
if (!pressed && processListView.contentY > 40)
|
||||
processListView.stableY = processListView.contentY;
|
||||
|
||||
property real wheelMultiplier: 1.8
|
||||
property int wheelBaseStep: 160
|
||||
|
||||
WheelHandler {
|
||||
target: null
|
||||
onWheel: (ev) => {
|
||||
let dy = ev.pixelDelta.y !== 0
|
||||
? ev.pixelDelta.y
|
||||
: (ev.angleDelta.y / 120) * processListView.wheelBaseStep;
|
||||
if (ev.inverted) dy = -dy;
|
||||
|
||||
const maxY = Math.max(0, processListView.contentHeight - processListView.height);
|
||||
processListView.contentY = Math.max(0, Math.min(maxY,
|
||||
processListView.contentY - dy * processListView.wheelMultiplier));
|
||||
|
||||
ev.accepted = true;
|
||||
}
|
||||
}
|
||||
|
||||
property string keyRoleName: "pid"
|
||||
property var _anchorKey: undefined
|
||||
property real _anchorOffset: 0
|
||||
|
||||
function captureAnchor() {
|
||||
const y = contentY + 1;
|
||||
const idx = indexAt(0, y);
|
||||
if (idx < 0 || !model || idx >= model.length) return;
|
||||
_anchorKey = model[idx][keyRoleName];
|
||||
const it = itemAtIndex(idx);
|
||||
_anchorOffset = it ? (y - it.y) : 0;
|
||||
ScrollBar.horizontal: ScrollBar {
|
||||
policy: ScrollBar.AlwaysOff
|
||||
}
|
||||
|
||||
function restoreAnchor() {
|
||||
Qt.callLater(function() {
|
||||
if (_anchorKey === undefined || !model) return;
|
||||
|
||||
var i = -1;
|
||||
for (var j = 0; j < model.length; ++j) {
|
||||
if (model[j][keyRoleName] === _anchorKey) { i = j; break; }
|
||||
}
|
||||
if (i < 0) return;
|
||||
|
||||
positionViewAtIndex(i, ListView.Beginning);
|
||||
const maxY = Math.max(0, contentHeight - height);
|
||||
contentY = Math.max(0, Math.min(maxY, contentY + _anchorOffset - 1));
|
||||
});
|
||||
}
|
||||
|
||||
onModelChanged: {
|
||||
if (model && model.length > 0 && !isUserScrolling && stableY > 40) {
|
||||
// Preserve scroll position when model updates
|
||||
Qt.callLater(function() {
|
||||
contentY = stableY
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,15 +1,16 @@
|
||||
import QtQuick
|
||||
import QtQuick.Layouts
|
||||
import qs.Common
|
||||
import qs.Services
|
||||
import qs.Modules.ProcessList
|
||||
import qs.Services
|
||||
|
||||
ColumnLayout {
|
||||
id: processesTab
|
||||
|
||||
property var contextMenu: null
|
||||
|
||||
anchors.fill: parent
|
||||
spacing: Theme.spacingM
|
||||
|
||||
property var contextMenu: null
|
||||
|
||||
SystemOverview {
|
||||
Layout.fillWidth: true
|
||||
@@ -24,4 +25,5 @@ ColumnLayout {
|
||||
ProcessContextMenu {
|
||||
id: localContextMenu
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -6,11 +6,9 @@ import qs.Widgets
|
||||
Row {
|
||||
width: parent.width
|
||||
spacing: Theme.spacingM
|
||||
|
||||
Component.onCompleted: {
|
||||
SysMonitorService.addRef();
|
||||
}
|
||||
|
||||
Component.onDestruction: {
|
||||
SysMonitorService.removeRef();
|
||||
}
|
||||
|
||||
@@ -9,11 +9,9 @@ ScrollView {
|
||||
clip: true
|
||||
ScrollBar.vertical.policy: ScrollBar.AsNeeded
|
||||
ScrollBar.horizontal.policy: ScrollBar.AlwaysOff
|
||||
|
||||
Component.onCompleted: {
|
||||
SysMonitorService.addRef();
|
||||
}
|
||||
|
||||
Component.onDestruction: {
|
||||
SysMonitorService.removeRef();
|
||||
}
|
||||
@@ -31,6 +29,7 @@ ScrollView {
|
||||
|
||||
Column {
|
||||
id: systemInfoColumn
|
||||
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
anchors.top: parent.top
|
||||
@@ -108,6 +107,7 @@ ScrollView {
|
||||
|
||||
Column {
|
||||
id: hardwareColumn
|
||||
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
anchors.top: parent.top
|
||||
@@ -133,6 +133,7 @@ ScrollView {
|
||||
color: Theme.primary
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
StyledText {
|
||||
@@ -169,7 +170,9 @@ ScrollView {
|
||||
elide: Text.ElideRight
|
||||
verticalAlignment: Text.AlignVCenter
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
@@ -182,6 +185,7 @@ ScrollView {
|
||||
|
||||
Column {
|
||||
id: memoryColumn
|
||||
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
anchors.top: parent.top
|
||||
@@ -207,6 +211,7 @@ ScrollView {
|
||||
color: Theme.secondary
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
StyledText {
|
||||
@@ -234,7 +239,9 @@ ScrollView {
|
||||
width: parent.width
|
||||
height: Theme.fontSizeSmall + Theme.spacingXS
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -243,7 +250,6 @@ ScrollView {
|
||||
|
||||
}
|
||||
|
||||
|
||||
Rectangle {
|
||||
width: parent.width
|
||||
height: storageColumn.implicitHeight + 2 * Theme.spacingL
|
||||
@@ -253,6 +259,7 @@ ScrollView {
|
||||
|
||||
Column {
|
||||
id: storageColumn
|
||||
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
anchors.top: parent.top
|
||||
@@ -281,181 +288,178 @@ ScrollView {
|
||||
|
||||
}
|
||||
|
||||
|
||||
Column {
|
||||
width: parent.width
|
||||
spacing: 2
|
||||
|
||||
Row {
|
||||
width: parent.width
|
||||
height: 24
|
||||
spacing: Theme.spacingS
|
||||
|
||||
StyledText {
|
||||
text: "Device"
|
||||
font.pixelSize: Theme.fontSizeSmall
|
||||
font.family: Prefs.monoFontFamily
|
||||
font.weight: Font.Bold
|
||||
color: Theme.surfaceText
|
||||
width: parent.width * 0.25
|
||||
elide: Text.ElideRight
|
||||
verticalAlignment: Text.AlignVCenter
|
||||
}
|
||||
|
||||
StyledText {
|
||||
text: "Mount"
|
||||
font.pixelSize: Theme.fontSizeSmall
|
||||
font.family: Prefs.monoFontFamily
|
||||
font.weight: Font.Bold
|
||||
color: Theme.surfaceText
|
||||
width: parent.width * 0.2
|
||||
elide: Text.ElideRight
|
||||
verticalAlignment: Text.AlignVCenter
|
||||
}
|
||||
|
||||
StyledText {
|
||||
text: "Size"
|
||||
font.pixelSize: Theme.fontSizeSmall
|
||||
font.family: Prefs.monoFontFamily
|
||||
font.weight: Font.Bold
|
||||
color: Theme.surfaceText
|
||||
width: parent.width * 0.15
|
||||
elide: Text.ElideRight
|
||||
verticalAlignment: Text.AlignVCenter
|
||||
}
|
||||
|
||||
StyledText {
|
||||
text: "Used"
|
||||
font.pixelSize: Theme.fontSizeSmall
|
||||
font.family: Prefs.monoFontFamily
|
||||
font.weight: Font.Bold
|
||||
color: Theme.surfaceText
|
||||
width: parent.width * 0.15
|
||||
elide: Text.ElideRight
|
||||
verticalAlignment: Text.AlignVCenter
|
||||
}
|
||||
|
||||
StyledText {
|
||||
text: "Available"
|
||||
font.pixelSize: Theme.fontSizeSmall
|
||||
font.family: Prefs.monoFontFamily
|
||||
font.weight: Font.Bold
|
||||
color: Theme.surfaceText
|
||||
width: parent.width * 0.15
|
||||
elide: Text.ElideRight
|
||||
verticalAlignment: Text.AlignVCenter
|
||||
}
|
||||
|
||||
StyledText {
|
||||
text: "Use%"
|
||||
font.pixelSize: Theme.fontSizeSmall
|
||||
font.family: Prefs.monoFontFamily
|
||||
font.weight: Font.Bold
|
||||
color: Theme.surfaceText
|
||||
width: parent.width * 0.1
|
||||
elide: Text.ElideRight
|
||||
verticalAlignment: Text.AlignVCenter
|
||||
}
|
||||
Row {
|
||||
width: parent.width
|
||||
height: 24
|
||||
spacing: Theme.spacingS
|
||||
|
||||
StyledText {
|
||||
text: "Device"
|
||||
font.pixelSize: Theme.fontSizeSmall
|
||||
font.family: Prefs.monoFontFamily
|
||||
font.weight: Font.Bold
|
||||
color: Theme.surfaceText
|
||||
width: parent.width * 0.25
|
||||
elide: Text.ElideRight
|
||||
verticalAlignment: Text.AlignVCenter
|
||||
}
|
||||
|
||||
Repeater {
|
||||
id: diskMountRepeater
|
||||
StyledText {
|
||||
text: "Mount"
|
||||
font.pixelSize: Theme.fontSizeSmall
|
||||
font.family: Prefs.monoFontFamily
|
||||
font.weight: Font.Bold
|
||||
color: Theme.surfaceText
|
||||
width: parent.width * 0.2
|
||||
elide: Text.ElideRight
|
||||
verticalAlignment: Text.AlignVCenter
|
||||
}
|
||||
|
||||
model: SysMonitorService.diskMounts
|
||||
StyledText {
|
||||
text: "Size"
|
||||
font.pixelSize: Theme.fontSizeSmall
|
||||
font.family: Prefs.monoFontFamily
|
||||
font.weight: Font.Bold
|
||||
color: Theme.surfaceText
|
||||
width: parent.width * 0.15
|
||||
elide: Text.ElideRight
|
||||
verticalAlignment: Text.AlignVCenter
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
width: parent.width
|
||||
height: 24
|
||||
radius: Theme.cornerRadiusSmall
|
||||
color: diskMouseArea.containsMouse ? Qt.rgba(Theme.surfaceText.r, Theme.surfaceText.g, Theme.surfaceText.b, 0.04) : "transparent"
|
||||
StyledText {
|
||||
text: "Used"
|
||||
font.pixelSize: Theme.fontSizeSmall
|
||||
font.family: Prefs.monoFontFamily
|
||||
font.weight: Font.Bold
|
||||
color: Theme.surfaceText
|
||||
width: parent.width * 0.15
|
||||
elide: Text.ElideRight
|
||||
verticalAlignment: Text.AlignVCenter
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
id: diskMouseArea
|
||||
StyledText {
|
||||
text: "Available"
|
||||
font.pixelSize: Theme.fontSizeSmall
|
||||
font.family: Prefs.monoFontFamily
|
||||
font.weight: Font.Bold
|
||||
color: Theme.surfaceText
|
||||
width: parent.width * 0.15
|
||||
elide: Text.ElideRight
|
||||
verticalAlignment: Text.AlignVCenter
|
||||
}
|
||||
|
||||
anchors.fill: parent
|
||||
hoverEnabled: true
|
||||
StyledText {
|
||||
text: "Use%"
|
||||
font.pixelSize: Theme.fontSizeSmall
|
||||
font.family: Prefs.monoFontFamily
|
||||
font.weight: Font.Bold
|
||||
color: Theme.surfaceText
|
||||
width: parent.width * 0.1
|
||||
elide: Text.ElideRight
|
||||
verticalAlignment: Text.AlignVCenter
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Repeater {
|
||||
id: diskMountRepeater
|
||||
|
||||
model: SysMonitorService.diskMounts
|
||||
|
||||
Rectangle {
|
||||
width: parent.width
|
||||
height: 24
|
||||
radius: Theme.cornerRadiusSmall
|
||||
color: diskMouseArea.containsMouse ? Qt.rgba(Theme.surfaceText.r, Theme.surfaceText.g, Theme.surfaceText.b, 0.04) : "transparent"
|
||||
|
||||
MouseArea {
|
||||
id: diskMouseArea
|
||||
|
||||
anchors.fill: parent
|
||||
hoverEnabled: true
|
||||
}
|
||||
|
||||
Row {
|
||||
anchors.fill: parent
|
||||
spacing: Theme.spacingS
|
||||
|
||||
StyledText {
|
||||
text: modelData.device
|
||||
font.pixelSize: Theme.fontSizeSmall
|
||||
font.family: Prefs.monoFontFamily
|
||||
color: Theme.surfaceText
|
||||
width: parent.width * 0.25
|
||||
elide: Text.ElideRight
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
verticalAlignment: Text.AlignVCenter
|
||||
}
|
||||
|
||||
Row {
|
||||
anchors.fill: parent
|
||||
spacing: Theme.spacingS
|
||||
StyledText {
|
||||
text: modelData.mount
|
||||
font.pixelSize: Theme.fontSizeSmall
|
||||
font.family: Prefs.monoFontFamily
|
||||
color: Theme.surfaceText
|
||||
width: parent.width * 0.2
|
||||
elide: Text.ElideRight
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
verticalAlignment: Text.AlignVCenter
|
||||
}
|
||||
|
||||
StyledText {
|
||||
text: modelData.device
|
||||
font.pixelSize: Theme.fontSizeSmall
|
||||
font.family: Prefs.monoFontFamily
|
||||
color: Theme.surfaceText
|
||||
width: parent.width * 0.25
|
||||
elide: Text.ElideRight
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
verticalAlignment: Text.AlignVCenter
|
||||
StyledText {
|
||||
text: modelData.size
|
||||
font.pixelSize: Theme.fontSizeSmall
|
||||
font.family: Prefs.monoFontFamily
|
||||
color: Theme.surfaceText
|
||||
width: parent.width * 0.15
|
||||
elide: Text.ElideRight
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
verticalAlignment: Text.AlignVCenter
|
||||
}
|
||||
|
||||
StyledText {
|
||||
text: modelData.used
|
||||
font.pixelSize: Theme.fontSizeSmall
|
||||
font.family: Prefs.monoFontFamily
|
||||
color: Theme.surfaceText
|
||||
width: parent.width * 0.15
|
||||
elide: Text.ElideRight
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
verticalAlignment: Text.AlignVCenter
|
||||
}
|
||||
|
||||
StyledText {
|
||||
text: modelData.avail
|
||||
font.pixelSize: Theme.fontSizeSmall
|
||||
font.family: Prefs.monoFontFamily
|
||||
color: Theme.surfaceText
|
||||
width: parent.width * 0.15
|
||||
elide: Text.ElideRight
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
verticalAlignment: Text.AlignVCenter
|
||||
}
|
||||
|
||||
StyledText {
|
||||
text: modelData.percent
|
||||
font.pixelSize: Theme.fontSizeSmall
|
||||
font.family: Prefs.monoFontFamily
|
||||
color: {
|
||||
const percent = parseInt(modelData.percent);
|
||||
if (percent > 90)
|
||||
return Theme.error;
|
||||
|
||||
if (percent > 75)
|
||||
return Theme.warning;
|
||||
|
||||
return Theme.surfaceText;
|
||||
}
|
||||
|
||||
StyledText {
|
||||
text: modelData.mount
|
||||
font.pixelSize: Theme.fontSizeSmall
|
||||
font.family: Prefs.monoFontFamily
|
||||
color: Theme.surfaceText
|
||||
width: parent.width * 0.2
|
||||
elide: Text.ElideRight
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
verticalAlignment: Text.AlignVCenter
|
||||
}
|
||||
|
||||
StyledText {
|
||||
text: modelData.size
|
||||
font.pixelSize: Theme.fontSizeSmall
|
||||
font.family: Prefs.monoFontFamily
|
||||
color: Theme.surfaceText
|
||||
width: parent.width * 0.15
|
||||
elide: Text.ElideRight
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
verticalAlignment: Text.AlignVCenter
|
||||
}
|
||||
|
||||
StyledText {
|
||||
text: modelData.used
|
||||
font.pixelSize: Theme.fontSizeSmall
|
||||
font.family: Prefs.monoFontFamily
|
||||
color: Theme.surfaceText
|
||||
width: parent.width * 0.15
|
||||
elide: Text.ElideRight
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
verticalAlignment: Text.AlignVCenter
|
||||
}
|
||||
|
||||
StyledText {
|
||||
text: modelData.avail
|
||||
font.pixelSize: Theme.fontSizeSmall
|
||||
font.family: Prefs.monoFontFamily
|
||||
color: Theme.surfaceText
|
||||
width: parent.width * 0.15
|
||||
elide: Text.ElideRight
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
verticalAlignment: Text.AlignVCenter
|
||||
}
|
||||
|
||||
StyledText {
|
||||
text: modelData.percent
|
||||
font.pixelSize: Theme.fontSizeSmall
|
||||
font.family: Prefs.monoFontFamily
|
||||
color: {
|
||||
const percent = parseInt(modelData.percent);
|
||||
if (percent > 90)
|
||||
return Theme.error;
|
||||
|
||||
if (percent > 75)
|
||||
return Theme.warning;
|
||||
|
||||
return Theme.surfaceText;
|
||||
}
|
||||
width: parent.width * 0.1
|
||||
elide: Text.ElideRight
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
verticalAlignment: Text.AlignVCenter
|
||||
}
|
||||
|
||||
width: parent.width * 0.1
|
||||
elide: Text.ElideRight
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
verticalAlignment: Text.AlignVCenter
|
||||
}
|
||||
|
||||
}
|
||||
@@ -464,6 +468,8 @@ ScrollView {
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user