mirror of
https://github.com/AvengeMedia/DankMaterialShell.git
synced 2025-12-06 05:25:41 -05:00
278 lines
11 KiB
QML
278 lines
11 KiB
QML
import QtQuick
|
|
import QtQuick.Controls
|
|
import Quickshell
|
|
import Quickshell.Wayland
|
|
import qs.Common
|
|
import qs.Modals.Spotlight
|
|
import qs.Services
|
|
|
|
Scope {
|
|
id: niriOverviewScope
|
|
|
|
property bool searchActive: false
|
|
property string searchActiveScreen: ""
|
|
property bool isClosing: false
|
|
property bool releaseKeyboard: false
|
|
property bool overlayActive: (NiriService.inOverview && !(PopoutService.spotlightModal?.spotlightOpen ?? false)) || searchActive
|
|
|
|
function showSpotlight(screenName) {
|
|
isClosing = false;
|
|
releaseKeyboard = false;
|
|
searchActive = true;
|
|
searchActiveScreen = screenName;
|
|
}
|
|
|
|
function hideSpotlight() {
|
|
if (!searchActive)
|
|
return;
|
|
isClosing = true;
|
|
}
|
|
|
|
function hideAndReleaseKeyboard() {
|
|
releaseKeyboard = true;
|
|
hideSpotlight();
|
|
}
|
|
|
|
function completeHide() {
|
|
searchActive = false;
|
|
searchActiveScreen = "";
|
|
isClosing = false;
|
|
releaseKeyboard = false;
|
|
}
|
|
|
|
Connections {
|
|
target: NiriService
|
|
function onInOverviewChanged() {
|
|
if (!NiriService.inOverview) {
|
|
if (searchActive) {
|
|
isClosing = true;
|
|
return;
|
|
}
|
|
searchActive = false;
|
|
searchActiveScreen = "";
|
|
isClosing = false;
|
|
return;
|
|
}
|
|
searchActive = false;
|
|
searchActiveScreen = "";
|
|
isClosing = false;
|
|
}
|
|
|
|
function onCurrentOutputChanged() {
|
|
if (!NiriService.inOverview || !searchActive || searchActiveScreen === "" || searchActiveScreen === NiriService.currentOutput)
|
|
return;
|
|
hideSpotlight();
|
|
}
|
|
}
|
|
|
|
Connections {
|
|
target: PopoutService.spotlightModal
|
|
function onSpotlightOpenChanged() {
|
|
if (!PopoutService.spotlightModal?.spotlightOpen || !searchActive)
|
|
return;
|
|
hideSpotlight();
|
|
}
|
|
}
|
|
|
|
Loader {
|
|
id: niriOverlayLoader
|
|
active: overlayActive || isClosing
|
|
asynchronous: false
|
|
|
|
sourceComponent: Variants {
|
|
id: overlayVariants
|
|
model: Quickshell.screens
|
|
|
|
PanelWindow {
|
|
id: overlayWindow
|
|
required property var modelData
|
|
|
|
readonly property real dpr: CompositorService.getScreenScale(screen)
|
|
readonly property bool isActiveScreen: screen.name === NiriService.currentOutput
|
|
readonly property bool shouldShowSpotlight: niriOverviewScope.searchActive && screen.name === niriOverviewScope.searchActiveScreen && !niriOverviewScope.isClosing
|
|
readonly property bool isSpotlightScreen: screen.name === niriOverviewScope.searchActiveScreen
|
|
|
|
screen: modelData
|
|
visible: NiriService.inOverview || niriOverviewScope.isClosing
|
|
color: "transparent"
|
|
|
|
WlrLayershell.namespace: "dms:niri-overview-spotlight"
|
|
WlrLayershell.layer: WlrLayer.Overlay
|
|
WlrLayershell.exclusiveZone: -1
|
|
WlrLayershell.keyboardFocus: {
|
|
if (!NiriService.inOverview)
|
|
return WlrKeyboardFocus.None;
|
|
if (!isActiveScreen)
|
|
return WlrKeyboardFocus.None;
|
|
if (niriOverviewScope.releaseKeyboard)
|
|
return WlrKeyboardFocus.None;
|
|
return WlrKeyboardFocus.Exclusive;
|
|
}
|
|
|
|
mask: Region {
|
|
item: spotlightContainer.visible ? spotlightContainer : null
|
|
}
|
|
|
|
onShouldShowSpotlightChanged: {
|
|
if (shouldShowSpotlight || !isActiveScreen)
|
|
return;
|
|
Qt.callLater(() => keyboardFocusScope.forceActiveFocus());
|
|
}
|
|
|
|
anchors {
|
|
top: true
|
|
left: true
|
|
right: true
|
|
bottom: true
|
|
}
|
|
|
|
FocusScope {
|
|
id: keyboardFocusScope
|
|
anchors.fill: parent
|
|
focus: true
|
|
|
|
Keys.onPressed: event => {
|
|
if (overlayWindow.shouldShowSpotlight || niriOverviewScope.isClosing)
|
|
return;
|
|
if ([Qt.Key_Escape, Qt.Key_Return].includes(event.key)) {
|
|
NiriService.toggleOverview();
|
|
event.accepted = true;
|
|
return;
|
|
}
|
|
|
|
if (event.key === Qt.Key_Left) {
|
|
NiriService.moveColumnLeft();
|
|
event.accepted = true;
|
|
return;
|
|
}
|
|
|
|
if (event.key === Qt.Key_Right) {
|
|
NiriService.moveColumnRight();
|
|
event.accepted = true;
|
|
return;
|
|
}
|
|
|
|
if (event.key === Qt.Key_Up) {
|
|
NiriService.moveWorkspaceUp();
|
|
event.accepted = true;
|
|
return;
|
|
}
|
|
|
|
if (event.key === Qt.Key_Down) {
|
|
NiriService.moveWorkspaceDown();
|
|
event.accepted = true;
|
|
return;
|
|
}
|
|
|
|
if (event.modifiers & (Qt.ControlModifier | Qt.MetaModifier) || [Qt.Key_Delete, Qt.Key_Backspace].includes(event.key)) {
|
|
event.accepted = false;
|
|
return;
|
|
}
|
|
|
|
if (event.isAutoRepeat || !event.text)
|
|
return;
|
|
if (!spotlightContent?.searchField)
|
|
return;
|
|
const trimmedText = event.text.trim();
|
|
spotlightContainer.waitingForResults = true;
|
|
spotlightContent.searchField.text = trimmedText;
|
|
if (spotlightContent.appLauncher) {
|
|
spotlightContent.appLauncher.searchQuery = trimmedText;
|
|
}
|
|
niriOverviewScope.showSpotlight(overlayWindow.screen.name);
|
|
Qt.callLater(() => spotlightContent.searchField.forceActiveFocus());
|
|
event.accepted = true;
|
|
}
|
|
}
|
|
|
|
Item {
|
|
id: spotlightContainer
|
|
x: Theme.snap((parent.width - width) / 2, overlayWindow.dpr)
|
|
y: Theme.snap((parent.height - height) / 2, overlayWindow.dpr)
|
|
width: Theme.px(500, overlayWindow.dpr)
|
|
height: Theme.px(600, overlayWindow.dpr)
|
|
|
|
readonly property bool animatingOut: niriOverviewScope.isClosing && overlayWindow.isSpotlightScreen
|
|
property bool waitingForResults: false
|
|
|
|
Connections {
|
|
target: spotlightContent.appLauncher?.model ?? null
|
|
function onCountChanged() {
|
|
spotlightContainer.waitingForResults = false;
|
|
}
|
|
}
|
|
|
|
scale: (overlayWindow.shouldShowSpotlight && !waitingForResults) ? 1.0 : 0.96
|
|
opacity: (overlayWindow.shouldShowSpotlight && !waitingForResults) ? 1 : 0
|
|
visible: (overlayWindow.shouldShowSpotlight && !waitingForResults) || animatingOut
|
|
enabled: overlayWindow.shouldShowSpotlight
|
|
|
|
layer.enabled: true
|
|
layer.smooth: false
|
|
layer.textureSize: Qt.size(Math.round(width * overlayWindow.dpr), Math.round(height * overlayWindow.dpr))
|
|
|
|
Behavior on scale {
|
|
NumberAnimation {
|
|
duration: Theme.expressiveDurations.expressiveDefaultSpatial
|
|
easing.type: Easing.BezierSpline
|
|
easing.bezierCurve: spotlightContainer.visible ? Theme.expressiveCurves.expressiveDefaultSpatial : Theme.expressiveCurves.emphasized
|
|
onRunningChanged: {
|
|
if (running || !spotlightContainer.animatingOut)
|
|
return;
|
|
niriOverviewScope.completeHide();
|
|
}
|
|
}
|
|
}
|
|
|
|
Behavior on opacity {
|
|
NumberAnimation {
|
|
duration: Theme.expressiveDurations.expressiveDefaultSpatial
|
|
easing.type: Easing.BezierSpline
|
|
easing.bezierCurve: spotlightContainer.visible ? Theme.expressiveCurves.expressiveDefaultSpatial : Theme.expressiveCurves.emphasized
|
|
}
|
|
}
|
|
|
|
Rectangle {
|
|
anchors.fill: parent
|
|
color: Theme.withAlpha(Theme.surfaceContainer, Theme.popupTransparency)
|
|
radius: Theme.cornerRadius
|
|
border.color: Theme.outlineMedium
|
|
border.width: 1
|
|
}
|
|
|
|
SpotlightContent {
|
|
id: spotlightContent
|
|
anchors.fill: parent
|
|
anchors.margins: 0
|
|
|
|
property var fakeParentModal: QtObject {
|
|
property bool spotlightOpen: spotlightContainer.visible
|
|
function hide() {
|
|
niriOverviewScope.hideSpotlight();
|
|
}
|
|
}
|
|
|
|
Component.onCompleted: {
|
|
parentModal = fakeParentModal;
|
|
}
|
|
|
|
Connections {
|
|
target: spotlightContent.appLauncher
|
|
function onAppLaunched() {
|
|
niriOverviewScope.releaseKeyboard = true;
|
|
}
|
|
}
|
|
|
|
Connections {
|
|
target: spotlightContent.fileSearchController
|
|
function onFileOpened() {
|
|
niriOverviewScope.releaseKeyboard = true;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|