1
0
mirror of https://github.com/AvengeMedia/DankMaterialShell.git synced 2026-01-24 13:32:50 -05:00

processlist: add full keyboard navigation

This commit is contained in:
bbedward
2026-01-18 21:03:34 -05:00
parent 0f6ae11c3d
commit ac68451cdf
5 changed files with 507 additions and 154 deletions

View File

@@ -71,6 +71,14 @@ FloatingWindow {
return (bytes / (1024 * 1024 * 1024)).toFixed(2) + " GB/s"; return (bytes / (1024 * 1024 * 1024)).toFixed(2) + " GB/s";
} }
function nextTab() {
currentTab = (currentTab + 1) % 4;
}
function previousTab() {
currentTab = (currentTab - 1 + 4) % 4;
}
objectName: "processListModal" objectName: "processListModal"
title: I18n.tr("System Monitor", "sysmon window title") title: I18n.tr("System Monitor", "sysmon window title")
minimumSize: Qt.size(750, 550) minimumSize: Qt.size(750, 550)
@@ -79,16 +87,25 @@ FloatingWindow {
color: Theme.surfaceContainer color: Theme.surfaceContainer
visible: false visible: false
onCurrentTabChanged: {
if (visible && currentTab === 0 && searchField.visible)
searchField.forceActiveFocus();
}
onVisibleChanged: { onVisibleChanged: {
if (!visible) { if (!visible) {
closingModal(); closingModal();
searchText = ""; searchText = "";
expandedPid = ""; expandedPid = "";
if (processesTabLoader.item)
processesTabLoader.item.reset();
DgopService.removeRef(["cpu", "memory", "network", "disk", "system"]); DgopService.removeRef(["cpu", "memory", "network", "disk", "system"]);
} else { } else {
DgopService.addRef(["cpu", "memory", "network", "disk", "system"]); DgopService.addRef(["cpu", "memory", "network", "disk", "system"]);
Qt.callLater(() => { Qt.callLater(() => {
if (contentFocusScope) if (currentTab === 0 && searchField.visible)
searchField.forceActiveFocus();
else if (contentFocusScope)
contentFocusScope.forceActiveFocus(); contentFocusScope.forceActiveFocus();
}); });
} }
@@ -96,6 +113,11 @@ FloatingWindow {
ProcessContextMenu { ProcessContextMenu {
id: processContextMenu id: processContextMenu
parentFocusItem: contentFocusScope
onProcessKilled: {
if (processesTabLoader.item)
processesTabLoader.item.forceRefresh(3);
}
} }
FocusScope { FocusScope {
@@ -108,6 +130,9 @@ FloatingWindow {
focus: true focus: true
Keys.onPressed: event => { Keys.onPressed: event => {
if (processContextMenu.visible)
return;
switch (event.key) { switch (event.key) {
case Qt.Key_1: case Qt.Key_1:
currentTab = 0; currentTab = 0;
@@ -125,12 +150,25 @@ FloatingWindow {
currentTab = 3; currentTab = 3;
event.accepted = true; event.accepted = true;
return; return;
case Qt.Key_Tab:
nextTab();
event.accepted = true;
return;
case Qt.Key_Backtab:
previousTab();
event.accepted = true;
return;
case Qt.Key_Escape: case Qt.Key_Escape:
if (searchText.length > 0) { if (searchText.length > 0) {
searchText = ""; searchText = "";
event.accepted = true; event.accepted = true;
return; return;
} }
if (currentTab === 0 && processesTabLoader.item?.keyboardNavigationActive) {
processesTabLoader.item.reset();
event.accepted = true;
return;
}
hide(); hide();
event.accepted = true; event.accepted = true;
return; return;
@@ -142,6 +180,9 @@ FloatingWindow {
} }
break; break;
} }
if (currentTab === 0 && processesTabLoader.item)
processesTabLoader.item.handleKey(event);
} }
Rectangle { Rectangle {
@@ -336,6 +377,8 @@ FloatingWindow {
text: searchText text: searchText
visible: currentTab === 0 visible: currentTab === 0
onTextChanged: searchText = text onTextChanged: searchText = text
ignoreUpDownKeys: true
keyForwardTargets: [contentFocusScope]
} }
} }

View File

@@ -8,8 +8,61 @@ Popup {
id: processContextMenu id: processContextMenu
property var processData: null property var processData: null
property int selectedIndex: -1
property bool keyboardNavigation: false
property var parentFocusItem: null
function show(x, y) { signal menuClosed
signal processKilled
readonly property var menuItems: [
{
text: I18n.tr("Copy PID"),
icon: "tag",
action: copyPid,
enabled: true
},
{
text: I18n.tr("Copy Name"),
icon: "content_copy",
action: copyName,
enabled: true
},
{
text: I18n.tr("Copy Full Command"),
icon: "code",
action: copyFullCommand,
enabled: true
},
{
type: "separator"
},
{
text: I18n.tr("Kill Process"),
icon: "close",
action: killProcess,
enabled: true,
dangerous: true
},
{
text: I18n.tr("Force Kill (SIGKILL)"),
icon: "dangerous",
action: forceKillProcess,
enabled: processData && processData.pid > 1000,
dangerous: true
}
]
readonly property int visibleItemCount: {
let count = 0;
for (let i = 0; i < menuItems.length; i++) {
if (menuItems[i].type !== "separator")
count++;
}
return count;
}
function show(x, y, fromKeyboard) {
let finalX = x; let finalX = x;
let finalY = y; let finalY = y;
@@ -27,17 +80,98 @@ Popup {
processContextMenu.x = finalX; processContextMenu.x = finalX;
processContextMenu.y = finalY; processContextMenu.y = finalY;
keyboardNavigation = fromKeyboard || false;
selectedIndex = fromKeyboard ? 0 : -1;
open(); open();
} }
function selectNext() {
if (visibleItemCount === 0)
return;
let current = selectedIndex;
let next = current;
do {
next = (next + 1) % menuItems.length;
} while (menuItems[next].type === "separator" && next !== current)
selectedIndex = next;
}
function selectPrevious() {
if (visibleItemCount === 0)
return;
let current = selectedIndex;
let prev = current;
do {
prev = (prev - 1 + menuItems.length) % menuItems.length;
} while (menuItems[prev].type === "separator" && prev !== current)
selectedIndex = prev;
}
function activateSelected() {
if (selectedIndex < 0 || selectedIndex >= menuItems.length)
return;
const item = menuItems[selectedIndex];
if (item.type === "separator" || !item.enabled)
return;
item.action();
}
function copyPid() {
if (processData)
Quickshell.execDetached(["dms", "cl", "copy", processData.pid.toString()]);
close();
}
function copyName() {
if (processData) {
const name = processData.command || "";
Quickshell.execDetached(["dms", "cl", "copy", name]);
}
close();
}
function copyFullCommand() {
if (processData) {
const fullCmd = processData.fullCommand || processData.command || "";
Quickshell.execDetached(["dms", "cl", "copy", fullCmd]);
}
close();
}
function killProcess() {
if (processData)
Quickshell.execDetached(["kill", processData.pid.toString()]);
processKilled();
close();
}
function forceKillProcess() {
if (processData)
Quickshell.execDetached(["kill", "-9", processData.pid.toString()]);
processKilled();
close();
}
width: 200 width: 200
height: menuColumn.implicitHeight + Theme.spacingS * 2 height: menuColumn.implicitHeight + Theme.spacingS * 2
padding: 0 padding: 0
modal: false modal: false
closePolicy: Popup.CloseOnEscape closePolicy: Popup.CloseOnEscape
onClosed: closePolicy = Popup.CloseOnEscape onClosed: {
onOpened: outsideClickTimer.start() closePolicy = Popup.CloseOnEscape;
keyboardNavigation = false;
selectedIndex = -1;
menuClosed();
if (parentFocusItem)
Qt.callLater(() => parentFocusItem.forceActiveFocus());
}
onOpened: {
outsideClickTimer.start();
if (keyboardNavigation)
Qt.callLater(() => keyboardHandler.forceActiveFocus());
}
Timer { Timer {
id: outsideClickTimer id: outsideClickTimer
@@ -55,142 +189,145 @@ Popup {
border.color: Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.08) border.color: Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.08)
border.width: 1 border.width: 1
Item {
id: keyboardHandler
anchors.fill: parent
focus: keyboardNavigation
Keys.onPressed: event => {
switch (event.key) {
case Qt.Key_Down:
case Qt.Key_J:
keyboardNavigation = true;
selectNext();
event.accepted = true;
return;
case Qt.Key_Up:
case Qt.Key_K:
keyboardNavigation = true;
selectPrevious();
event.accepted = true;
return;
case Qt.Key_Return:
case Qt.Key_Enter:
case Qt.Key_Space:
activateSelected();
event.accepted = true;
return;
case Qt.Key_Escape:
case Qt.Key_Left:
case Qt.Key_H:
close();
event.accepted = true;
return;
}
}
}
Column { Column {
id: menuColumn id: menuColumn
anchors.fill: parent anchors.fill: parent
anchors.margins: Theme.spacingS anchors.margins: Theme.spacingS
spacing: 1 spacing: 1
MenuItem { Repeater {
text: I18n.tr("Copy PID") model: menuItems
iconName: "tag"
onClicked: {
if (processContextMenu.processData)
Quickshell.execDetached(["dms", "cl", "copy", processContextMenu.processData.pid.toString()]);
processContextMenu.close();
}
}
MenuItem { Item {
text: I18n.tr("Copy Name") width: parent.width
iconName: "content_copy" height: modelData.type === "separator" ? 5 : 32
onClicked: { visible: modelData.type !== "separator" || index > 0
if (processContextMenu.processData) {
const name = processContextMenu.processData.command || ""; property int itemVisibleIndex: {
Quickshell.execDetached(["dms", "cl", "copy", name]); let count = 0;
for (let i = 0; i < index; i++) {
if (menuItems[i].type !== "separator")
count++;
}
return count;
} }
processContextMenu.close();
}
}
MenuItem { Rectangle {
text: I18n.tr("Copy Full Command") visible: modelData.type === "separator"
iconName: "code" width: parent.width - Theme.spacingS * 2
onClicked: { height: 1
if (processContextMenu.processData) { anchors.horizontalCenter: parent.horizontalCenter
const fullCmd = processContextMenu.processData.fullCommand || processContextMenu.processData.command || ""; anchors.verticalCenter: parent.verticalCenter
Quickshell.execDetached(["dms", "cl", "copy", fullCmd]); color: Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.15)
}
Rectangle {
id: menuItem
visible: modelData.type !== "separator"
width: parent.width
height: 32
radius: Theme.cornerRadius
color: {
if (!modelData.enabled)
return "transparent";
const isSelected = keyboardNavigation && selectedIndex === index;
if (modelData.dangerous) {
if (isSelected)
return Qt.rgba(Theme.error.r, Theme.error.g, Theme.error.b, 0.2);
return menuItemArea.containsMouse ? Qt.rgba(Theme.error.r, Theme.error.g, Theme.error.b, 0.12) : "transparent";
}
if (isSelected)
return Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.2);
return menuItemArea.containsMouse ? Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.12) : "transparent";
}
opacity: modelData.enabled ? 1 : 0.5
Row {
anchors.left: parent.left
anchors.leftMargin: Theme.spacingS
anchors.verticalCenter: parent.verticalCenter
spacing: Theme.spacingS
DankIcon {
name: modelData.icon || ""
size: 16
color: {
if (!modelData.enabled)
return Theme.surfaceVariantText;
const isSelected = keyboardNavigation && selectedIndex === index;
if (modelData.dangerous && (menuItemArea.containsMouse || isSelected))
return Theme.error;
return Theme.surfaceText;
}
anchors.verticalCenter: parent.verticalCenter
}
StyledText {
text: modelData.text || ""
font.pixelSize: Theme.fontSizeSmall
font.weight: Font.Normal
color: {
if (!modelData.enabled)
return Theme.surfaceVariantText;
const isSelected = keyboardNavigation && selectedIndex === index;
if (modelData.dangerous && (menuItemArea.containsMouse || isSelected))
return Theme.error;
return Theme.surfaceText;
}
anchors.verticalCenter: parent.verticalCenter
}
}
MouseArea {
id: menuItemArea
anchors.fill: parent
hoverEnabled: true
cursorShape: modelData.enabled ? Qt.PointingHandCursor : Qt.ArrowCursor
enabled: modelData.enabled
onEntered: {
keyboardNavigation = false;
selectedIndex = index;
}
onClicked: modelData.action()
}
} }
processContextMenu.close();
} }
} }
Rectangle {
width: parent.width - Theme.spacingS * 2
height: 1
anchors.horizontalCenter: parent.horizontalCenter
color: Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.15)
}
MenuItem {
text: I18n.tr("Kill Process")
iconName: "close"
dangerous: true
enabled: processContextMenu.processData
onClicked: {
if (processContextMenu.processData)
Quickshell.execDetached(["kill", processContextMenu.processData.pid.toString()]);
processContextMenu.close();
}
}
MenuItem {
text: I18n.tr("Force Kill (SIGKILL)")
iconName: "dangerous"
dangerous: true
enabled: processContextMenu.processData && processContextMenu.processData.pid > 1000
onClicked: {
if (processContextMenu.processData)
Quickshell.execDetached(["kill", "-9", processContextMenu.processData.pid.toString()]);
processContextMenu.close();
}
}
}
}
component MenuItem: Rectangle {
id: menuItem
property string text: ""
property string iconName: ""
property bool dangerous: false
property bool enabled: true
signal clicked
width: parent.width
height: 32
radius: Theme.cornerRadius
color: {
if (!enabled)
return "transparent";
if (dangerous)
return menuItemArea.containsMouse ? Qt.rgba(Theme.error.r, Theme.error.g, Theme.error.b, 0.12) : "transparent";
return menuItemArea.containsMouse ? Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.12) : "transparent";
}
opacity: enabled ? 1 : 0.5
Row {
anchors.left: parent.left
anchors.leftMargin: Theme.spacingS
anchors.verticalCenter: parent.verticalCenter
spacing: Theme.spacingS
DankIcon {
name: menuItem.iconName
size: 16
color: {
if (!menuItem.enabled)
return Theme.surfaceVariantText;
if (menuItem.dangerous && menuItemArea.containsMouse)
return Theme.error;
return Theme.surfaceText;
}
anchors.verticalCenter: parent.verticalCenter
}
StyledText {
text: menuItem.text
font.pixelSize: Theme.fontSizeSmall
font.weight: Font.Normal
color: {
if (!menuItem.enabled)
return Theme.surfaceVariantText;
if (menuItem.dangerous && menuItemArea.containsMouse)
return Theme.error;
return Theme.surfaceText;
}
anchors.verticalCenter: parent.verticalCenter
}
}
MouseArea {
id: menuItemArea
anchors.fill: parent
hoverEnabled: true
cursorShape: menuItem.enabled ? Qt.PointingHandCursor : Qt.ArrowCursor
enabled: menuItem.enabled
onClicked: menuItem.clicked()
} }
} }
} }

View File

@@ -42,6 +42,8 @@ DankPopout {
if (!shouldBeVisible) { if (!shouldBeVisible) {
searchText = ""; searchText = "";
expandedPid = ""; expandedPid = "";
if (processesView)
processesView.reset();
} }
} }
@@ -69,9 +71,13 @@ DankPopout {
if (processListPopout.shouldBeVisible) if (processListPopout.shouldBeVisible)
forceActiveFocus(); forceActiveFocus();
processContextMenu.parent = processListContent; processContextMenu.parent = processListContent;
processContextMenu.parentFocusItem = processListContent;
} }
Keys.onPressed: event => { Keys.onPressed: event => {
if (processContextMenu.visible)
return;
switch (event.key) { switch (event.key) {
case Qt.Key_Escape: case Qt.Key_Escape:
if (processListPopout.searchText.length > 0) { if (processListPopout.searchText.length > 0) {
@@ -79,6 +85,11 @@ DankPopout {
event.accepted = true; event.accepted = true;
return; return;
} }
if (processesView.keyboardNavigationActive) {
processesView.reset();
event.accepted = true;
return;
}
processListPopout.close(); processListPopout.close();
event.accepted = true; event.accepted = true;
return; return;
@@ -90,14 +101,15 @@ DankPopout {
} }
break; break;
} }
processesView.handleKey(event);
} }
Connections { Connections {
target: processListPopout target: processListPopout
function onShouldBeVisibleChanged() { function onShouldBeVisibleChanged() {
if (processListPopout.shouldBeVisible) { if (processListPopout.shouldBeVisible)
Qt.callLater(() => processListContent.forceActiveFocus()); Qt.callLater(() => processListContent.forceActiveFocus());
}
} }
} }
@@ -142,6 +154,8 @@ DankPopout {
showClearButton: true showClearButton: true
text: processListPopout.searchText text: processListPopout.searchText
onTextChanged: processListPopout.searchText = text onTextChanged: processListPopout.searchText = text
ignoreUpDownKeys: true
keyForwardTargets: [processListContent]
} }
} }
@@ -314,6 +328,7 @@ DankPopout {
clip: true clip: true
ProcessesView { ProcessesView {
id: processesView
anchors.fill: parent anchors.fill: parent
anchors.margins: Theme.spacingS anchors.margins: Theme.spacingS
searchText: processListPopout.searchText searchText: processListPopout.searchText

View File

@@ -11,18 +11,27 @@ Item {
property string searchText: "" property string searchText: ""
property string expandedPid: "" property string expandedPid: ""
property var contextMenu: null property var contextMenu: null
property bool hoveringExpandedItem: false
readonly property bool pauseUpdates: hoveringExpandedItem || (contextMenu?.visible ?? false) property int selectedIndex: -1
property bool keyboardNavigationActive: false
property int forceRefreshCount: 0
readonly property bool pauseUpdates: (contextMenu?.visible ?? false) || expandedPid.length > 0
readonly property bool shouldUpdate: !pauseUpdates || forceRefreshCount > 0
property var cachedProcesses: [] property var cachedProcesses: []
signal openContextMenuRequested(int index, real x, real y, bool fromKeyboard)
onFilteredProcessesChanged: { onFilteredProcessesChanged: {
if (!pauseUpdates) if (!shouldUpdate)
cachedProcesses = filteredProcesses; return;
cachedProcesses = filteredProcesses;
if (forceRefreshCount > 0)
forceRefreshCount--;
} }
onPauseUpdatesChanged: { onShouldUpdateChanged: {
if (!pauseUpdates) if (shouldUpdate)
cachedProcesses = filteredProcesses; cachedProcesses = filteredProcesses;
} }
@@ -75,6 +84,135 @@ Item {
return procs; return procs;
} }
function selectNext() {
if (cachedProcesses.length === 0)
return;
keyboardNavigationActive = true;
selectedIndex = Math.min(selectedIndex + 1, cachedProcesses.length - 1);
ensureVisible();
}
function selectPrevious() {
if (cachedProcesses.length === 0)
return;
keyboardNavigationActive = true;
if (selectedIndex <= 0) {
selectedIndex = -1;
keyboardNavigationActive = false;
return;
}
selectedIndex = selectedIndex - 1;
ensureVisible();
}
function selectFirst() {
if (cachedProcesses.length === 0)
return;
keyboardNavigationActive = true;
selectedIndex = 0;
ensureVisible();
}
function selectLast() {
if (cachedProcesses.length === 0)
return;
keyboardNavigationActive = true;
selectedIndex = cachedProcesses.length - 1;
ensureVisible();
}
function toggleExpand() {
if (selectedIndex < 0 || selectedIndex >= cachedProcesses.length)
return;
const process = cachedProcesses[selectedIndex];
const pidStr = (process?.pid ?? -1).toString();
expandedPid = (expandedPid === pidStr) ? "" : pidStr;
}
function openContextMenu() {
if (selectedIndex < 0 || selectedIndex >= cachedProcesses.length)
return;
const delegate = processListView.itemAtIndex(selectedIndex);
if (!delegate)
return;
const process = cachedProcesses[selectedIndex];
if (!process || !contextMenu)
return;
contextMenu.processData = process;
const itemPos = delegate.mapToItem(contextMenu.parent, delegate.width / 2, delegate.height / 2);
contextMenu.parentFocusItem = root;
contextMenu.show(itemPos.x, itemPos.y, true);
}
function reset() {
selectedIndex = -1;
keyboardNavigationActive = false;
expandedPid = "";
}
function forceRefresh(count) {
forceRefreshCount = count || 3;
}
function ensureVisible() {
if (selectedIndex < 0)
return;
processListView.positionViewAtIndex(selectedIndex, ListView.Contain);
}
function handleKey(event) {
switch (event.key) {
case Qt.Key_Down:
selectNext();
event.accepted = true;
return;
case Qt.Key_Up:
selectPrevious();
event.accepted = true;
return;
case Qt.Key_J:
if (event.modifiers & Qt.ControlModifier) {
selectNext();
event.accepted = true;
}
return;
case Qt.Key_K:
if (event.modifiers & Qt.ControlModifier) {
selectPrevious();
event.accepted = true;
}
return;
case Qt.Key_Home:
selectFirst();
event.accepted = true;
return;
case Qt.Key_End:
selectLast();
event.accepted = true;
return;
case Qt.Key_Space:
if (keyboardNavigationActive) {
toggleExpand();
event.accepted = true;
}
return;
case Qt.Key_Return:
case Qt.Key_Enter:
if (keyboardNavigationActive) {
toggleExpand();
event.accepted = true;
}
return;
case Qt.Key_Menu:
case Qt.Key_F10:
if (keyboardNavigationActive && selectedIndex >= 0) {
openContextMenu();
event.accepted = true;
}
return;
}
}
Component.onCompleted: { Component.onCompleted: {
DgopService.addRef(["processes", "cpu", "memory", "system"]); DgopService.addRef(["processes", "cpu", "memory", "system"]);
cachedProcesses = filteredProcesses; cachedProcesses = filteredProcesses;
@@ -163,22 +301,28 @@ Item {
delegate: ProcessItem { delegate: ProcessItem {
required property var modelData required property var modelData
required property int index
width: processListView.width width: processListView.width
process: modelData process: modelData
isExpanded: root.expandedPid === (modelData?.pid ?? -1).toString() isExpanded: root.expandedPid === (modelData?.pid ?? -1).toString()
isSelected: root.keyboardNavigationActive && root.selectedIndex === index
contextMenu: root.contextMenu contextMenu: root.contextMenu
onToggleExpand: { onToggleExpand: {
const pidStr = (modelData?.pid ?? -1).toString(); const pidStr = (modelData?.pid ?? -1).toString();
root.expandedPid = (root.expandedPid === pidStr) ? "" : pidStr; root.expandedPid = (root.expandedPid === pidStr) ? "" : pidStr;
} }
onHoveringExpandedChanged: { onClicked: {
if (hoveringExpanded) root.keyboardNavigationActive = true;
root.hoveringExpandedItem = true; root.selectedIndex = index;
else }
Qt.callLater(() => { onContextMenuRequested: (mouseX, mouseY) => {
root.hoveringExpandedItem = false; if (root.contextMenu) {
}); root.contextMenu.processData = modelData;
root.contextMenu.parentFocusItem = root;
const globalPos = mapToItem(root.contextMenu.parent, mouseX, mouseY);
root.contextMenu.show(globalPos.x, globalPos.y, false);
}
} }
} }
@@ -288,10 +432,12 @@ Item {
property var process: null property var process: null
property bool isExpanded: false property bool isExpanded: false
property bool isSelected: false
property var contextMenu: null property var contextMenu: null
readonly property bool hoveringExpanded: (isExpanded && processMouseArea.containsMouse) || copyMouseArea.containsMouse
signal toggleExpand signal toggleExpand
signal clicked
signal contextMenuRequested(real mouseX, real mouseY)
readonly property int processPid: process?.pid ?? 0 readonly property int processPid: process?.pid ?? 0
readonly property real processCpu: process?.cpu ?? 0 readonly property real processCpu: process?.cpu ?? 0
@@ -301,8 +447,16 @@ Item {
height: isExpanded ? (44 + expandedRect.height + Theme.spacingXS) : 44 height: isExpanded ? (44 + expandedRect.height + Theme.spacingXS) : 44
radius: Theme.cornerRadius radius: Theme.cornerRadius
color: processMouseArea.containsMouse ? Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.06) : "transparent" color: {
border.color: processMouseArea.containsMouse ? Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.12) : "transparent" if (isSelected)
return Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.15);
return processMouseArea.containsMouse ? Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.06) : "transparent";
}
border.color: {
if (isSelected)
return Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.3);
return processMouseArea.containsMouse ? Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.12) : "transparent";
}
border.width: 1 border.width: 1
clip: true clip: true
@@ -327,14 +481,10 @@ Item {
acceptedButtons: Qt.LeftButton | Qt.RightButton acceptedButtons: Qt.LeftButton | Qt.RightButton
onClicked: mouse => { onClicked: mouse => {
if (mouse.button === Qt.RightButton) { if (mouse.button === Qt.RightButton) {
if (processItemRoot.processPid > 0 && processItemRoot.contextMenu) { processItemRoot.contextMenuRequested(mouse.x, mouse.y);
processItemRoot.contextMenu.processData = processItemRoot.process;
const globalPos = processMouseArea.mapToGlobal(mouse.x, mouse.y);
const localPos = processItemRoot.contextMenu.parent ? processItemRoot.contextMenu.parent.mapFromGlobal(globalPos.x, globalPos.y) : globalPos;
processItemRoot.contextMenu.show(localPos.x, localPos.y);
}
return; return;
} }
processItemRoot.clicked();
processItemRoot.toggleExpand(); processItemRoot.toggleExpand();
} }
} }

View File

@@ -53,6 +53,7 @@ StyledRect {
property real topPadding: Theme.spacingM property real topPadding: Theme.spacingM
property real bottomPadding: Theme.spacingM property real bottomPadding: Theme.spacingM
property bool ignoreLeftRightKeys: false property bool ignoreLeftRightKeys: false
property bool ignoreUpDownKeys: false
property bool ignoreTabKeys: false property bool ignoreTabKeys: false
property var keyForwardTargets: [] property var keyForwardTargets: []
property Item keyNavigationTab: null property Item keyNavigationTab: null
@@ -145,9 +146,16 @@ StyledRect {
if (root.ignoreTabKeys && (event.key === Qt.Key_Tab || event.key === Qt.Key_Backtab)) { if (root.ignoreTabKeys && (event.key === Qt.Key_Tab || event.key === Qt.Key_Backtab)) {
event.accepted = false; event.accepted = false;
for (var i = 0; i < root.keyForwardTargets.length; i++) { for (var i = 0; i < root.keyForwardTargets.length; i++) {
if (root.keyForwardTargets[i]) { if (root.keyForwardTargets[i])
root.keyForwardTargets[i].Keys.pressed(event);
}
return;
}
if (root.ignoreUpDownKeys && (event.key === Qt.Key_Up || event.key === Qt.Key_Down)) {
event.accepted = false;
for (var i = 0; i < root.keyForwardTargets.length; i++) {
if (root.keyForwardTargets[i])
root.keyForwardTargets[i].Keys.pressed(event); root.keyForwardTargets[i].Keys.pressed(event);
}
} }
} }
} }