refactor(dash): kb nav tab switches tabs while arrows work the content & ctrl+tab steps in

Port 2.0

(cherry picked from commit d4cd0f0465)
This commit is contained in:
purian23 authored and dux-ci[bot] committed 2026-10-31 01:49:47 +00:00
1 parent 47769deff4
commit 1e15db8fd7
4 files changed
+47 -32

No files matched your search

@@ -93,7 +93,7 @@ Injected: `pluginId`, `pluginService`, `popoutService`, `entryId`, `dashHost` (`
Base provides: `options`, `pluginData`, `getData(key, def)`, `setData(key, value)`.
Optional: `implicitHeight`, `focusTarget`, `restoreFocus()`, `handleKeyEvent(event)` (return true to consume; Ctrl+Tab and Ctrl+PgUp/PgDown are reserved), `blocksTabNavigation`, `menuActions`, `signal tabRequested(string id)`, `signal navFocusRequested`.
Optional: `implicitHeight`, `focusTarget`, `restoreFocus()`, `handleKeyEvent(event)` (return true to consume; Tab, Ctrl+Tab, F6 and Ctrl+PgUp/PgDown are reserved), `blocksTabNavigation`, `menuActions`, `signal tabRequested(string id)`, `signal navFocusRequested`.
For tiles inside a tab, use `Card` from `qs.Modules.DankDash.Overview` so colors, radius and tones match the overview.
+2 -1
View File
@@ -383,6 +383,7 @@ DPopout {
contentScope: pages.currentHost
contentTarget: pages.focusTarget
headerTargets: root.editMode ? pageActions.focusTargets : [tabBar, pageTitle.focusTarget]
tabsShown: root.showTabs
headerEdge: root.verticalNavigation ? (root.navigationEdge === SettingsData.Right ? "right" : "left") : (root.navigationEdge === SettingsData.Bottom ? "down" : "up")
onTabCycleRequested: direction => {
root.cycleTab(direction);
@@ -390,6 +391,7 @@ DPopout {
mainContainer.focusInitial();
}
onEditModeRequested: on => root.editMode = on
onLeaveRequested: mainContainer.focusInitial()
onOptionsDismissRequested: tabOptions.dismiss()
onCloseRequested: {
if (root.detailTabId !== "")
@@ -468,7 +470,6 @@ DPopout {
onEditRequested: root.editMode = true
visible: root.showTabs && !root.editMode
orientation: root.verticalNavigation ? Qt.Vertical : Qt.Horizontal
tabHighlights: true
currentIndex: root.currentTabIndex
nextFocusTarget: pageActions.focusTargets[0] ?? pages.focusTarget
previousFocusTarget: pages.currentItem?.previousFocusTarget ?? pages.focusTarget
+42 -29
View File
@@ -16,6 +16,13 @@ Item {
property Item contentTarget: null
property var headerTargets: []
property string headerEdge: "up"
property bool tabsShown: true
// Outside the content, Tab switches tabs and the tab keeps Space and the arrows.
property bool steppedIn: false
onActiveChanged: steppedIn = false
onTabItemChanged: steppedIn = false
onEditModeChanged: steppedIn = false
readonly property bool idle: active && !optionsShown && !menuOpen
readonly property bool contentFocused: contentScope?.activeFocus ?? false
@@ -26,31 +33,39 @@ Item {
signal editModeRequested(bool on)
signal optionsDismissRequested
signal closeRequested
signal leaveRequested
function visibleHeaderTargets() {
return headerTargets.filter(item => item && item.visible && item.enabled);
}
// Outside edit mode the header is not a keyboard stop; leaving the content goes back to the tabs.
function focusHeader(backwards) {
if (!editMode) {
leaveContent();
return;
}
const targets = visibleHeaderTargets();
const target = backwards ? targets[targets.length - 1] : targets[0];
target?.forceActiveFocus(backwards ? Qt.BacktabFocusReason : Qt.TabFocusReason);
}
function enterContent(backwards) {
steppedIn = true;
const target = backwards ? (tabItem?.previousFocusTarget ?? contentTarget) : contentTarget;
FocusNavigation.focusItem(target, backwards);
}
function cycleRegion(backwards) {
const targets = visibleHeaderTargets();
if (!targets.some(FocusNavigation.containsFocus) && targets.length > 0) {
focusHeader(backwards);
return;
}
if (FocusNavigation.moveFocus(targets, backwards))
return;
enterContent(backwards);
function leaveContent() {
steppedIn = false;
leaveRequested();
}
function toggleContent(backwards) {
if (steppedIn)
leaveContent();
else
enterContent(backwards);
}
function inContent(item) {
@@ -61,6 +76,13 @@ Item {
return false;
}
function tabKey(backwards) {
if (tabsShown && !steppedIn)
tabCycleRequested(backwards ? -1 : 1);
else
walkContent(backwards);
}
// Tab wraps inside the content, as in Settings.
function walkContent(backwards) {
if (!contentFocused) {
@@ -77,24 +99,14 @@ Item {
}
}
// A tab without restoreFocus parks focus on the host, which counts as content.
function toggleRegion() {
if (headerFocused || visibleHeaderTargets().length === 0)
enterContent(false);
else
focusHeader(false);
}
function moveCard(direction) {
if (!contentFocused) {
if (direction === headerEdge)
focusHeader(false);
else
if (direction !== headerEdge)
enterContent(false);
return;
}
if (tabItem?.moveCardFocus?.(direction) !== true && direction === headerEdge)
focusHeader(false);
leaveContent();
}
function arrowDirection(event) {
@@ -155,31 +167,32 @@ Item {
return false;
if (editMode)
editModeRequested(false);
else if (steppedIn && tabsShown)
leaveContent();
else
closeRequested();
return true;
}
// The tab row takes Tab itself to move its highlight.
Shortcut {
sequence: "Tab"
enabled: root.browsing && !root.headerFocused
enabled: root.browsing
context: Qt.WindowShortcut
onActivated: root.walkContent(false)
onActivated: root.tabKey(false)
}
Shortcut {
sequence: "Shift+Tab"
enabled: root.browsing && !root.headerFocused
enabled: root.browsing
context: Qt.WindowShortcut
onActivated: root.walkContent(true)
onActivated: root.tabKey(true)
}
Shortcut {
sequences: ["Ctrl+Tab", "Ctrl+Shift+Tab"]
enabled: root.browsing
context: Qt.WindowShortcut
onActivated: root.toggleRegion()
onActivated: root.toggleContent(false)
}
Shortcut {
@@ -207,14 +220,14 @@ Item {
sequence: "F6"
enabled: root.browsing
context: Qt.WindowShortcut
onActivated: root.cycleRegion(false)
onActivated: root.toggleContent(false)
}
Shortcut {
sequence: "Shift+F6"
enabled: root.browsing
context: Qt.WindowShortcut
onActivated: root.cycleRegion(true)
onActivated: root.toggleContent(true)
}
Shortcut {
@@ -131,8 +131,10 @@ FocusScope {
contentScope: tabLoader
contentTarget: root.tab?.focusTarget ?? null
headerTargets: root.editMode ? pageActions.focusTargets : [tabBarLoader.item, sheetHandle.focusTarget]
tabsShown: root.tabsShown
onTabCycleRequested: direction => root.controller.cycleDashTab(direction, tabBarLoader.item?.activeFocus ?? false)
onEditModeRequested: on => root.editMode = on
onLeaveRequested: root.focusFace()
onOptionsDismissRequested: tabOptions.dismiss()
onCloseRequested: root.controller.requestCollapse()
}
@@ -160,7 +162,6 @@ FocusScope {
id: tabBar
editable: true
tabHighlights: true
evenlySpaced: SettingsData.dashTabsEvenlySpaced
currentIndex: root.controller.dashTabIds.indexOf(root.entryId)
nextFocusTarget: root.tab?.focusTarget ?? null