mirror of
https://github.com/AvengeMedia/DankMaterialShell.git
synced 2026-10-15 15:54:00 -04:00
154 lines
5.0 KiB
QML
154 lines
5.0 KiB
QML
import QtQuick
|
|
import qs.Common
|
|
|
|
FocusScope {
|
|
id: root
|
|
|
|
required property Item sidebar
|
|
required property Item content
|
|
required property var parentModal
|
|
property string activePane: "sidebar"
|
|
property Item sidebarFocus: null
|
|
readonly property Item focusedItem: Window.activeFocusItem
|
|
property int focusRevision: 0
|
|
|
|
focus: true
|
|
|
|
// Controls take focus on press with the mouse reason, so visualFocus tells how the activating control was reached
|
|
function keyboardDriven() {
|
|
return focusedItem?.visualFocus ?? false;
|
|
}
|
|
|
|
function contains(ancestor, item) {
|
|
for (let p = item; p; p = p.parent) {
|
|
if (p === ancestor)
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
function transientOwnsFocus() {
|
|
for (let p = focusedItem; p && p !== root; p = p.parent) {
|
|
if (p.capturing === true || p.Accessible.role === Accessible.Dialog || p.Accessible.role === Accessible.PopupMenu)
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
onFocusedItemChanged: {
|
|
if (transientOwnsFocus())
|
|
return;
|
|
if (contains(sidebar, focusedItem)) {
|
|
if (focusedItem !== sidebar)
|
|
sidebarFocus = focusedItem;
|
|
activePane = "sidebar";
|
|
} else if (contains(content, focusedItem)) {
|
|
activePane = "content";
|
|
content.rememberFocus();
|
|
// Focus that falls back to a container when its control is destroyed must not scroll the page
|
|
if (keyboardDriven() || focusedItem.cursorPosition !== undefined)
|
|
content._reveal(focusedItem);
|
|
}
|
|
}
|
|
|
|
function focusSidebar() {
|
|
focusRevision++;
|
|
activePane = "sidebar";
|
|
if (parentModal.isCompactMode)
|
|
parentModal.menuVisible = true;
|
|
if (sidebarFocus?.visible && sidebarFocus.enabled && contains(sidebar, sidebarFocus)) {
|
|
sidebarFocus.forceActiveFocus(Qt.TabFocusReason);
|
|
sidebar.ensureRowVisible(sidebarFocus);
|
|
} else {
|
|
sidebar.focusNavigation();
|
|
}
|
|
}
|
|
|
|
function focusContent(keyboard = true) {
|
|
focusRevision++;
|
|
activePane = "content";
|
|
if (parentModal.isCompactMode)
|
|
parentModal.menuVisible = false;
|
|
content.keyboardNavigation = keyboard;
|
|
content._focusPage();
|
|
}
|
|
|
|
function focusSearch() {
|
|
focusRevision++;
|
|
activePane = "sidebar";
|
|
if (parentModal.isCompactMode)
|
|
parentModal.menuVisible = true;
|
|
sidebar.focusSearch();
|
|
}
|
|
|
|
function pointerFocus(pane) {
|
|
const revision = ++focusRevision;
|
|
activePane = pane;
|
|
// Child controls get the press first. A background click only moves the keyboard region, highlighting nothing.
|
|
Qt.callLater(() => {
|
|
if (revision !== focusRevision || transientOwnsFocus())
|
|
return;
|
|
const region = pane === "sidebar" ? sidebar : content;
|
|
if (contains(region, focusedItem))
|
|
return;
|
|
if (pane === "sidebar")
|
|
sidebar.forceActiveFocus(Qt.MouseFocusReason);
|
|
else
|
|
content.parkFocus();
|
|
});
|
|
}
|
|
|
|
TapHandler {
|
|
parent: root.sidebar
|
|
onPressedChanged: {
|
|
if (pressed)
|
|
root.pointerFocus("sidebar");
|
|
}
|
|
}
|
|
|
|
// Page scrollers accept presses before this handler sees them; SettingsContent gives each one its own
|
|
TapHandler {
|
|
parent: root.content
|
|
onPressedChanged: {
|
|
if (pressed)
|
|
root.pointerFocus("content");
|
|
}
|
|
}
|
|
|
|
TapHandler {
|
|
acceptedButtons: Qt.BackButton
|
|
onTapped: {
|
|
if (!transientOwnsFocus())
|
|
root.content.goBack(false);
|
|
}
|
|
}
|
|
|
|
Keys.onPressed: event => {
|
|
const mods = event.modifiers & ~Qt.KeypadModifier;
|
|
if (transientOwnsFocus()) {
|
|
if ((event.key === Qt.Key_Tab || event.key === Qt.Key_Backtab || event.key === Qt.Key_F) && (mods & Qt.ControlModifier))
|
|
event.accepted = true;
|
|
return;
|
|
}
|
|
if ((event.key === Qt.Key_Tab || event.key === Qt.Key_Backtab) && (mods === Qt.ControlModifier || mods === (Qt.ControlModifier | Qt.ShiftModifier))) {
|
|
if (activePane === "sidebar")
|
|
focusContent();
|
|
else
|
|
focusSidebar();
|
|
event.accepted = true;
|
|
} else if (mods === Qt.AltModifier && (event.key === Qt.Key_Left || event.key === Qt.Key_Right)) {
|
|
const forward = (event.key === Qt.Key_Right) !== I18n.isRtl;
|
|
if (forward !== (activePane === "sidebar"))
|
|
return;
|
|
if (forward)
|
|
focusContent();
|
|
else
|
|
focusSidebar();
|
|
event.accepted = true;
|
|
} else if (event.key === Qt.Key_F && mods === Qt.ControlModifier) {
|
|
focusSearch();
|
|
event.accepted = true;
|
|
}
|
|
}
|
|
}
|