mirror of
https://github.com/AvengeMedia/DankMaterialShell.git
synced 2025-12-08 06:25:37 -05:00
230 lines
8.7 KiB
QML
230 lines
8.7 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 overlayActive: NiriService.inOverview && !(PopoutService.spotlightModal?.spotlightOpen ?? false)
|
|
|
|
function showSpotlight(screenName) {
|
|
searchActive = true
|
|
searchActiveScreen = screenName
|
|
}
|
|
|
|
function hideSpotlight() {
|
|
searchActive = false
|
|
searchActiveScreen = ""
|
|
}
|
|
|
|
Connections {
|
|
target: NiriService
|
|
function onInOverviewChanged() {
|
|
if (!NiriService.inOverview) {
|
|
hideSpotlight()
|
|
} else {
|
|
searchActive = false
|
|
searchActiveScreen = ""
|
|
}
|
|
}
|
|
|
|
function onCurrentOutputChanged() {
|
|
if (NiriService.inOverview && searchActive && searchActiveScreen !== "" && searchActiveScreen !== NiriService.currentOutput) {
|
|
hideSpotlight()
|
|
}
|
|
}
|
|
}
|
|
|
|
Connections {
|
|
target: PopoutService.spotlightModal
|
|
function onSpotlightOpenChanged() {
|
|
if (PopoutService.spotlightModal?.spotlightOpen && searchActive) {
|
|
hideSpotlight()
|
|
}
|
|
}
|
|
}
|
|
|
|
Loader {
|
|
id: niriOverlayLoader
|
|
active: overlayActive
|
|
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
|
|
|
|
screen: modelData
|
|
visible: NiriService.inOverview
|
|
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
|
|
return WlrKeyboardFocus.Exclusive
|
|
}
|
|
|
|
mask: Region {
|
|
item: shouldShowSpotlight ? spotlightContainer : null
|
|
}
|
|
|
|
onShouldShowSpotlightChanged: {
|
|
if (!shouldShowSpotlight && isActiveScreen) {
|
|
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) {
|
|
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) {
|
|
niriOverviewScope.showSpotlight(overlayWindow.screen.name)
|
|
if (spotlightContent?.searchField) {
|
|
spotlightContent.searchField.text = event.text.trim()
|
|
if (spotlightContent.appLauncher) {
|
|
spotlightContent.appLauncher.searchQuery = event.text.trim()
|
|
}
|
|
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)
|
|
|
|
property real scaleValue: 0.96
|
|
|
|
scale: scaleValue
|
|
opacity: overlayWindow.shouldShowSpotlight ? 1 : 0
|
|
enabled: overlayWindow.shouldShowSpotlight
|
|
|
|
layer.enabled: true
|
|
layer.smooth: false
|
|
layer.textureSize: Qt.size(Math.round(width * overlayWindow.dpr), Math.round(height * overlayWindow.dpr))
|
|
|
|
Connections {
|
|
target: overlayWindow
|
|
function onShouldShowSpotlightChanged() {
|
|
spotlightContainer.scaleValue = overlayWindow.shouldShowSpotlight ? 1.0 : 0.96
|
|
}
|
|
}
|
|
|
|
Behavior on scaleValue {
|
|
NumberAnimation {
|
|
duration: Theme.expressiveDurations.expressiveDefaultSpatial
|
|
easing.type: Easing.BezierSpline
|
|
easing.bezierCurve: niriOverviewScope.searchActive ? Theme.expressiveCurves.expressiveDefaultSpatial : Theme.expressiveCurves.emphasized
|
|
}
|
|
}
|
|
|
|
Behavior on opacity {
|
|
NumberAnimation {
|
|
duration: Theme.expressiveDurations.expressiveDefaultSpatial
|
|
easing.type: Easing.BezierSpline
|
|
easing.bezierCurve: niriOverviewScope.searchActive ? 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: overlayWindow.shouldShowSpotlight
|
|
function hide() {
|
|
niriOverviewScope.hideSpotlight()
|
|
if (overlayWindow.isActiveScreen) {
|
|
Qt.callLater(() => keyboardFocusScope.forceActiveFocus())
|
|
}
|
|
}
|
|
}
|
|
|
|
Component.onCompleted: {
|
|
parentModal = fakeParentModal
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|