mirror of
https://github.com/AvengeMedia/DankMaterialShell.git
synced 2026-01-24 21:42:51 -05:00
popout: fix excessive repaints
- Size content window to content size, buffer for shadow - Add second window for click outside behavior - User overriding the layer disables the click outside behavior part of #716
This commit is contained in:
@@ -1,16 +1,7 @@
|
||||
import QtQuick
|
||||
import QtQuick.Controls
|
||||
import QtQuick.Effects
|
||||
import QtQuick.Layouts
|
||||
import Quickshell
|
||||
import Quickshell.Io
|
||||
import Quickshell.Wayland
|
||||
import Quickshell.Widgets
|
||||
import qs.Common
|
||||
import qs.Modules.ControlCenter
|
||||
import qs.Modules.ControlCenter.Widgets
|
||||
import qs.Modules.ControlCenter.Details
|
||||
import qs.Modules.DankBar
|
||||
import qs.Services
|
||||
import qs.Widgets
|
||||
import qs.Modules.ControlCenter.Components
|
||||
@@ -32,39 +23,39 @@ DankPopout {
|
||||
signal lockRequested
|
||||
|
||||
function collapseAll() {
|
||||
expandedSection = ""
|
||||
expandedWidgetIndex = -1
|
||||
expandedWidgetData = null
|
||||
expandedSection = "";
|
||||
expandedWidgetIndex = -1;
|
||||
expandedWidgetData = null;
|
||||
}
|
||||
|
||||
onEditModeChanged: {
|
||||
if (editMode) {
|
||||
collapseAll()
|
||||
collapseAll();
|
||||
}
|
||||
}
|
||||
|
||||
onVisibleChanged: {
|
||||
if (!visible) {
|
||||
collapseAll()
|
||||
collapseAll();
|
||||
}
|
||||
}
|
||||
|
||||
readonly property color _containerBg: Theme.withAlpha(Theme.surfaceContainerHigh, Theme.popupTransparency)
|
||||
|
||||
function openWithSection(section) {
|
||||
StateUtils.openWithSection(root, section)
|
||||
StateUtils.openWithSection(root, section);
|
||||
}
|
||||
|
||||
function toggleSection(section) {
|
||||
StateUtils.toggleSection(root, section)
|
||||
StateUtils.toggleSection(root, section);
|
||||
}
|
||||
|
||||
popupWidth: 550
|
||||
popupHeight: {
|
||||
const screenHeight = (triggerScreen?.height ?? 1080)
|
||||
const maxHeight = screenHeight - 100
|
||||
const contentHeight = contentLoader.item && contentLoader.item.implicitHeight > 0 ? contentLoader.item.implicitHeight + 20 : 400
|
||||
return Math.min(maxHeight, contentHeight)
|
||||
const screenHeight = (triggerScreen?.height ?? 1080);
|
||||
const maxHeight = screenHeight - 100;
|
||||
const contentHeight = contentLoader.item && contentLoader.item.implicitHeight > 0 ? contentLoader.item.implicitHeight + 20 : 400;
|
||||
return Math.min(maxHeight, contentHeight);
|
||||
}
|
||||
triggerX: 0
|
||||
triggerY: 0
|
||||
@@ -75,12 +66,16 @@ DankPopout {
|
||||
|
||||
property bool credentialsPromptOpen: NetworkService.credentialsRequested
|
||||
|
||||
WlrLayershell.keyboardFocus: {
|
||||
if (!shouldBeVisible) return WlrKeyboardFocus.None
|
||||
if (powerMenuOpen) return WlrKeyboardFocus.None
|
||||
if (credentialsPromptOpen) return WlrKeyboardFocus.None
|
||||
if (CompositorService.isHyprland) return WlrKeyboardFocus.OnDemand
|
||||
return WlrKeyboardFocus.Exclusive
|
||||
customKeyboardFocus: {
|
||||
if (!shouldBeVisible)
|
||||
return WlrKeyboardFocus.None;
|
||||
if (powerMenuOpen)
|
||||
return WlrKeyboardFocus.None;
|
||||
if (credentialsPromptOpen)
|
||||
return WlrKeyboardFocus.None;
|
||||
if (CompositorService.isHyprland)
|
||||
return WlrKeyboardFocus.OnDemand;
|
||||
return WlrKeyboardFocus.Exclusive;
|
||||
}
|
||||
|
||||
onBackgroundClicked: close()
|
||||
@@ -89,20 +84,20 @@ DankPopout {
|
||||
if (shouldBeVisible) {
|
||||
Qt.callLater(() => {
|
||||
if (NetworkService.activeService) {
|
||||
NetworkService.activeService.autoRefreshEnabled = NetworkService.wifiEnabled
|
||||
NetworkService.activeService.autoRefreshEnabled = NetworkService.wifiEnabled;
|
||||
}
|
||||
if (UserInfoService)
|
||||
UserInfoService.getUptime()
|
||||
})
|
||||
UserInfoService.getUptime();
|
||||
});
|
||||
} else {
|
||||
Qt.callLater(() => {
|
||||
if (NetworkService.activeService) {
|
||||
NetworkService.activeService.autoRefreshEnabled = false
|
||||
NetworkService.activeService.autoRefreshEnabled = false;
|
||||
}
|
||||
if (BluetoothService.adapter && BluetoothService.adapter.discovering)
|
||||
BluetoothService.adapter.discovering = false
|
||||
editMode = false
|
||||
})
|
||||
BluetoothService.adapter.discovering = false;
|
||||
editMode = false;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -118,9 +113,9 @@ DankPopout {
|
||||
property alias bluetoothCodecSelector: bluetoothCodecSelector
|
||||
|
||||
color: {
|
||||
const transparency = Theme.popupTransparency
|
||||
const surface = Theme.surfaceContainer || Qt.rgba(0.1, 0.1, 0.1, 1)
|
||||
return Qt.rgba(surface.r, surface.g, surface.b, transparency)
|
||||
const transparency = Theme.popupTransparency;
|
||||
const surface = Theme.surfaceContainer || Qt.rgba(0.1, 0.1, 0.1, 1);
|
||||
return Qt.rgba(surface.r, surface.g, surface.b, transparency);
|
||||
}
|
||||
radius: Theme.cornerRadius
|
||||
border.color: Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.08)
|
||||
@@ -157,20 +152,20 @@ DankPopout {
|
||||
onEditModeToggled: root.editMode = !root.editMode
|
||||
onPowerButtonClicked: {
|
||||
if (powerMenuModalLoader) {
|
||||
powerMenuModalLoader.active = true
|
||||
powerMenuModalLoader.active = true;
|
||||
if (powerMenuModalLoader.item) {
|
||||
const popoutPos = controlContent.mapToItem(null, 0, 0)
|
||||
const bounds = Qt.rect(popoutPos.x, popoutPos.y, controlContent.width, controlContent.height)
|
||||
powerMenuModalLoader.item.openFromControlCenter(bounds, root.triggerScreen)
|
||||
const popoutPos = controlContent.mapToItem(null, 0, 0);
|
||||
const bounds = Qt.rect(popoutPos.x, popoutPos.y, controlContent.width, controlContent.height);
|
||||
powerMenuModalLoader.item.openFromControlCenter(bounds, root.triggerScreen);
|
||||
}
|
||||
}
|
||||
}
|
||||
onLockRequested: {
|
||||
root.close()
|
||||
root.lockRequested()
|
||||
root.close();
|
||||
root.lockRequested();
|
||||
}
|
||||
onSettingsButtonClicked: {
|
||||
root.close()
|
||||
root.close();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -187,14 +182,14 @@ DankPopout {
|
||||
screenName: root.triggerScreen?.name || ""
|
||||
parentScreen: root.triggerScreen
|
||||
onExpandClicked: (widgetData, globalIndex) => {
|
||||
root.expandedWidgetIndex = globalIndex
|
||||
root.expandedWidgetData = widgetData
|
||||
root.expandedWidgetIndex = globalIndex;
|
||||
root.expandedWidgetData = widgetData;
|
||||
if (widgetData.id === "diskUsage") {
|
||||
root.toggleSection("diskUsage_" + (widgetData.instanceId || "default"))
|
||||
root.toggleSection("diskUsage_" + (widgetData.instanceId || "default"));
|
||||
} else if (widgetData.id === "brightnessSlider") {
|
||||
root.toggleSection("brightnessSlider_" + (widgetData.instanceId || "default"))
|
||||
root.toggleSection("brightnessSlider_" + (widgetData.instanceId || "default"));
|
||||
} else {
|
||||
root.toggleSection(widgetData.id)
|
||||
root.toggleSection(widgetData.id);
|
||||
}
|
||||
}
|
||||
onRemoveWidget: index => widgetModel.removeWidget(index)
|
||||
@@ -209,10 +204,10 @@ DankPopout {
|
||||
popoutContent: controlContent
|
||||
availableWidgets: {
|
||||
if (!editMode)
|
||||
return []
|
||||
const existingIds = (SettingsData.controlCenterWidgets || []).map(w => w.id)
|
||||
const allWidgets = widgetModel.baseWidgetDefinitions.concat(widgetModel.getPluginWidgets())
|
||||
return allWidgets.filter(w => w.allowMultiple || !existingIds.includes(w.id))
|
||||
return [];
|
||||
const existingIds = (SettingsData.controlCenterWidgets || []).map(w => w.id);
|
||||
const allWidgets = widgetModel.baseWidgetDefinitions.concat(widgetModel.getPluginWidgets());
|
||||
return allWidgets.filter(w => w.allowMultiple || !existingIds.includes(w.id));
|
||||
}
|
||||
onAddWidget: widgetId => widgetModel.addWidget(widgetId)
|
||||
onResetToDefault: () => widgetModel.resetToDefault()
|
||||
@@ -239,10 +234,10 @@ DankPopout {
|
||||
id: bluetoothDetail
|
||||
onShowCodecSelector: function (device) {
|
||||
if (contentLoader.item && contentLoader.item.bluetoothCodecSelector) {
|
||||
contentLoader.item.bluetoothCodecSelector.show(device)
|
||||
contentLoader.item.bluetoothCodecSelector.show(device);
|
||||
contentLoader.item.bluetoothCodecSelector.codecSelected.connect(function (deviceAddress, codecName) {
|
||||
bluetoothDetail.updateDeviceCodecDisplay(deviceAddress, codecName)
|
||||
})
|
||||
bluetoothDetail.updateDeviceCodecDisplay(deviceAddress, codecName);
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,18 +1,15 @@
|
||||
import QtQuick
|
||||
import QtQuick.Effects
|
||||
import Quickshell
|
||||
import Quickshell.Hyprland
|
||||
import Quickshell.Wayland
|
||||
import qs.Common
|
||||
import qs.Services
|
||||
import qs.Widgets
|
||||
|
||||
PanelWindow {
|
||||
Item {
|
||||
id: root
|
||||
|
||||
property string layerNamespace: "dms:popout"
|
||||
WlrLayershell.namespace: layerNamespace
|
||||
|
||||
property alias content: contentLoader.sourceComponent
|
||||
property alias contentLoader: contentLoader
|
||||
property real popupWidth: 400
|
||||
@@ -28,24 +25,34 @@ PanelWindow {
|
||||
property list<real> animationEnterCurve: Theme.expressiveCurves.expressiveDefaultSpatial
|
||||
property list<real> animationExitCurve: Theme.expressiveCurves.emphasized
|
||||
property bool shouldBeVisible: false
|
||||
property var customKeyboardFocus: null
|
||||
|
||||
property real storedBarThickness: Theme.barHeight - 4
|
||||
property real storedBarSpacing: 4
|
||||
property var storedBarConfig: null
|
||||
property var adjacentBarInfo: ({ "topBar": 0, "bottomBar": 0, "leftBar": 0, "rightBar": 0 })
|
||||
|
||||
visible: false
|
||||
property var adjacentBarInfo: ({
|
||||
"topBar": 0,
|
||||
"bottomBar": 0,
|
||||
"leftBar": 0,
|
||||
"rightBar": 0
|
||||
})
|
||||
property var screen: null
|
||||
|
||||
readonly property real effectiveBarThickness: {
|
||||
const padding = storedBarConfig ? (storedBarConfig.innerPadding !== undefined ? storedBarConfig.innerPadding : 4) : 4
|
||||
return Math.max(26 + padding * 0.6, Theme.barHeight - 4 - (8 - padding)) + storedBarSpacing
|
||||
const padding = storedBarConfig ? (storedBarConfig.innerPadding !== undefined ? storedBarConfig.innerPadding : 4) : 4;
|
||||
return Math.max(26 + padding * 0.6, Theme.barHeight - 4 - (8 - padding)) + storedBarSpacing;
|
||||
}
|
||||
|
||||
readonly property var barBounds: {
|
||||
if (!root.screen) {
|
||||
return { "x": 0, "y": 0, "width": 0, "height": 0, "wingSize": 0 }
|
||||
}
|
||||
return SettingsData.getBarBounds(root.screen, effectiveBarThickness, effectiveBarPosition, storedBarConfig)
|
||||
if (!screen)
|
||||
return {
|
||||
"x": 0,
|
||||
"y": 0,
|
||||
"width": 0,
|
||||
"height": 0,
|
||||
"wingSize": 0
|
||||
};
|
||||
return SettingsData.getBarBounds(screen, effectiveBarThickness, effectiveBarPosition, storedBarConfig);
|
||||
}
|
||||
|
||||
readonly property real barX: barBounds.x
|
||||
@@ -58,50 +65,57 @@ PanelWindow {
|
||||
signal popoutClosed
|
||||
signal backgroundClicked
|
||||
|
||||
property int effectiveBarPosition: 0
|
||||
property real effectiveBarBottomGap: 0
|
||||
|
||||
function setBarContext(position, bottomGap) {
|
||||
effectiveBarPosition = position !== undefined ? position : 0
|
||||
effectiveBarBottomGap = bottomGap !== undefined ? bottomGap : 0
|
||||
effectiveBarPosition = position !== undefined ? position : 0;
|
||||
effectiveBarBottomGap = bottomGap !== undefined ? bottomGap : 0;
|
||||
}
|
||||
|
||||
function setTriggerPosition(x, y, width, section, screen, barPosition, barThickness, barSpacing, barConfig) {
|
||||
triggerX = x
|
||||
triggerY = y
|
||||
triggerWidth = width
|
||||
triggerSection = section
|
||||
root.screen = screen
|
||||
function setTriggerPosition(x, y, width, section, targetScreen, barPosition, barThickness, barSpacing, barConfig) {
|
||||
triggerX = x;
|
||||
triggerY = y;
|
||||
triggerWidth = width;
|
||||
triggerSection = section;
|
||||
screen = targetScreen;
|
||||
|
||||
storedBarThickness = barThickness !== undefined ? barThickness : (Theme.barHeight - 4)
|
||||
storedBarSpacing = barSpacing !== undefined ? barSpacing : 4
|
||||
storedBarConfig = barConfig
|
||||
storedBarThickness = barThickness !== undefined ? barThickness : (Theme.barHeight - 4);
|
||||
storedBarSpacing = barSpacing !== undefined ? barSpacing : 4;
|
||||
storedBarConfig = barConfig;
|
||||
|
||||
const pos = barPosition !== undefined ? barPosition : 0
|
||||
const bottomGap = barConfig ? (barConfig.bottomGap !== undefined ? barConfig.bottomGap : 0) : 0
|
||||
const pos = barPosition !== undefined ? barPosition : 0;
|
||||
const bottomGap = barConfig ? (barConfig.bottomGap !== undefined ? barConfig.bottomGap : 0) : 0;
|
||||
|
||||
// Get adjacent bar info for proper positioning
|
||||
adjacentBarInfo = SettingsData.getAdjacentBarInfo(screen, pos, barConfig)
|
||||
adjacentBarInfo = SettingsData.getAdjacentBarInfo(targetScreen, pos, barConfig);
|
||||
setBarContext(pos, bottomGap);
|
||||
}
|
||||
|
||||
setBarContext(pos, bottomGap)
|
||||
readonly property bool useBackgroundWindow: {
|
||||
const layerOverride = Quickshell.env("DMS_POPOUT_LAYER");
|
||||
return !layerOverride || layerOverride === "overlay";
|
||||
}
|
||||
|
||||
function open() {
|
||||
closeTimer.stop()
|
||||
shouldBeVisible = true
|
||||
visible = true
|
||||
PopoutManager.showPopout(root)
|
||||
opened()
|
||||
if (!screen)
|
||||
return;
|
||||
closeTimer.stop();
|
||||
shouldBeVisible = true;
|
||||
if (useBackgroundWindow)
|
||||
backgroundWindow.visible = true;
|
||||
contentWindow.visible = true;
|
||||
PopoutManager.showPopout(root);
|
||||
opened();
|
||||
}
|
||||
|
||||
function close() {
|
||||
shouldBeVisible = false
|
||||
PopoutManager.popoutChanged()
|
||||
closeTimer.restart()
|
||||
shouldBeVisible = false;
|
||||
PopoutManager.popoutChanged();
|
||||
closeTimer.restart();
|
||||
}
|
||||
|
||||
function toggle() {
|
||||
if (shouldBeVisible)
|
||||
close()
|
||||
else
|
||||
open()
|
||||
shouldBeVisible ? close() : open();
|
||||
}
|
||||
|
||||
Timer {
|
||||
@@ -109,32 +123,95 @@ PanelWindow {
|
||||
interval: animationDuration
|
||||
onTriggered: {
|
||||
if (!shouldBeVisible) {
|
||||
visible = false
|
||||
PopoutManager.hidePopout(root)
|
||||
popoutClosed()
|
||||
contentWindow.visible = false;
|
||||
if (useBackgroundWindow)
|
||||
backgroundWindow.visible = false;
|
||||
PopoutManager.hidePopout(root);
|
||||
popoutClosed();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
color: "transparent"
|
||||
WlrLayershell.layer: {
|
||||
switch (Quickshell.env("DMS_POPOUT_LAYER")) {
|
||||
case "bottom":
|
||||
return WlrLayershell.Bottom
|
||||
case "overlay":
|
||||
return WlrLayershell.Overlay
|
||||
case "background":
|
||||
return WlrLayershell.Background
|
||||
readonly property real screenWidth: screen ? screen.width : 0
|
||||
readonly property real screenHeight: screen ? screen.height : 0
|
||||
readonly property real dpr: screen ? CompositorService.getScreenScale(screen) : 1
|
||||
|
||||
readonly property real shadowBuffer: 5
|
||||
readonly property real alignedWidth: Theme.px(popupWidth, dpr)
|
||||
readonly property real alignedHeight: Theme.px(popupHeight, dpr)
|
||||
|
||||
readonly property real alignedX: Theme.snap((() => {
|
||||
const useAutoGaps = storedBarConfig?.popupGapsAuto !== undefined ? storedBarConfig.popupGapsAuto : true;
|
||||
const manualGapValue = storedBarConfig?.popupGapsManual !== undefined ? storedBarConfig.popupGapsManual : 4;
|
||||
const popupGap = useAutoGaps ? Math.max(4, storedBarSpacing) : manualGapValue;
|
||||
|
||||
switch (effectiveBarPosition) {
|
||||
case SettingsData.Position.Left:
|
||||
return Math.max(popupGap, Math.min(screenWidth - popupWidth - popupGap, triggerX));
|
||||
case SettingsData.Position.Right:
|
||||
return Math.max(popupGap, Math.min(screenWidth - popupWidth - popupGap, triggerX - popupWidth));
|
||||
default:
|
||||
return WlrLayershell.Top
|
||||
const rawX = triggerX + (triggerWidth / 2) - (popupWidth / 2);
|
||||
const minX = adjacentBarInfo.leftBar > 0 ? adjacentBarInfo.leftBar : popupGap;
|
||||
const maxX = screenWidth - popupWidth - (adjacentBarInfo.rightBar > 0 ? adjacentBarInfo.rightBar : popupGap);
|
||||
return Math.max(minX, Math.min(maxX, rawX));
|
||||
}
|
||||
})(), dpr)
|
||||
|
||||
readonly property real alignedY: Theme.snap((() => {
|
||||
const useAutoGaps = storedBarConfig?.popupGapsAuto !== undefined ? storedBarConfig.popupGapsAuto : true;
|
||||
const manualGapValue = storedBarConfig?.popupGapsManual !== undefined ? storedBarConfig.popupGapsManual : 4;
|
||||
const popupGap = useAutoGaps ? Math.max(4, storedBarSpacing) : manualGapValue;
|
||||
|
||||
switch (effectiveBarPosition) {
|
||||
case SettingsData.Position.Bottom:
|
||||
return Math.max(popupGap, Math.min(screenHeight - popupHeight - popupGap, triggerY - popupHeight));
|
||||
case SettingsData.Position.Top:
|
||||
return Math.max(popupGap, Math.min(screenHeight - popupHeight - popupGap, triggerY));
|
||||
default:
|
||||
const rawY = triggerY - (popupHeight / 2);
|
||||
const minY = adjacentBarInfo.topBar > 0 ? adjacentBarInfo.topBar : popupGap;
|
||||
const maxY = screenHeight - popupHeight - (adjacentBarInfo.bottomBar > 0 ? adjacentBarInfo.bottomBar : popupGap);
|
||||
return Math.max(minY, Math.min(maxY, rawY));
|
||||
}
|
||||
})(), dpr)
|
||||
|
||||
readonly property real maskX: {
|
||||
const triggeringBarX = (effectiveBarPosition === SettingsData.Position.Left && barWidth > 0) ? barWidth : 0;
|
||||
const adjacentLeftBar = adjacentBarInfo?.leftBar ?? 0;
|
||||
return Math.max(triggeringBarX, adjacentLeftBar);
|
||||
}
|
||||
|
||||
readonly property real maskY: {
|
||||
const triggeringBarY = (effectiveBarPosition === SettingsData.Position.Top && barHeight > 0) ? barHeight : 0;
|
||||
const adjacentTopBar = adjacentBarInfo?.topBar ?? 0;
|
||||
return Math.max(triggeringBarY, adjacentTopBar);
|
||||
}
|
||||
|
||||
readonly property real maskWidth: {
|
||||
const triggeringBarRight = (effectiveBarPosition === SettingsData.Position.Right && barWidth > 0) ? barWidth : 0;
|
||||
const adjacentRightBar = adjacentBarInfo?.rightBar ?? 0;
|
||||
const rightExclusion = Math.max(triggeringBarRight, adjacentRightBar);
|
||||
return Math.max(100, screenWidth - maskX - rightExclusion);
|
||||
}
|
||||
|
||||
readonly property real maskHeight: {
|
||||
const triggeringBarBottom = (effectiveBarPosition === SettingsData.Position.Bottom && barHeight > 0) ? barHeight : 0;
|
||||
const adjacentBottomBar = adjacentBarInfo?.bottomBar ?? 0;
|
||||
const bottomExclusion = Math.max(triggeringBarBottom, adjacentBottomBar);
|
||||
return Math.max(100, screenHeight - maskY - bottomExclusion);
|
||||
}
|
||||
|
||||
PanelWindow {
|
||||
id: backgroundWindow
|
||||
screen: root.screen
|
||||
visible: false
|
||||
color: "transparent"
|
||||
|
||||
WlrLayershell.namespace: root.layerNamespace + ":background"
|
||||
WlrLayershell.layer: WlrLayershell.Top
|
||||
WlrLayershell.exclusiveZone: -1
|
||||
WlrLayershell.keyboardFocus: {
|
||||
if (!shouldBeVisible) return WlrKeyboardFocus.None
|
||||
if (CompositorService.isHyprland) return WlrKeyboardFocus.OnDemand
|
||||
return WlrKeyboardFocus.Exclusive
|
||||
}
|
||||
WlrLayershell.keyboardFocus: WlrKeyboardFocus.None
|
||||
|
||||
anchors {
|
||||
top: true
|
||||
@@ -143,114 +220,83 @@ PanelWindow {
|
||||
bottom: true
|
||||
}
|
||||
|
||||
readonly property real screenWidth: root.screen.width
|
||||
readonly property real screenHeight: root.screen.height
|
||||
readonly property real dpr: CompositorService.getScreenScale(root.screen)
|
||||
|
||||
readonly property real alignedWidth: Theme.px(popupWidth, dpr)
|
||||
readonly property real alignedHeight: Theme.px(popupHeight, dpr)
|
||||
property int effectiveBarPosition: 0
|
||||
property real effectiveBarBottomGap: 0
|
||||
|
||||
readonly property real alignedX: Theme.snap((() => {
|
||||
const useAutoGaps = storedBarConfig?.popupGapsAuto !== undefined ? storedBarConfig.popupGapsAuto : true
|
||||
const manualGapValue = storedBarConfig?.popupGapsManual !== undefined ? storedBarConfig.popupGapsManual : 4
|
||||
const popupGap = useAutoGaps ? Math.max(4, storedBarSpacing) : manualGapValue
|
||||
|
||||
let rawX = 0
|
||||
if (effectiveBarPosition === SettingsData.Position.Left) {
|
||||
rawX = triggerX
|
||||
} else if (effectiveBarPosition === SettingsData.Position.Right) {
|
||||
rawX = triggerX - popupWidth
|
||||
} else {
|
||||
rawX = triggerX + (triggerWidth / 2) - (popupWidth / 2)
|
||||
const minX = adjacentBarInfo.leftBar > 0 ? adjacentBarInfo.leftBar : popupGap
|
||||
const maxX = screenWidth - popupWidth - (adjacentBarInfo.rightBar > 0 ? adjacentBarInfo.rightBar : popupGap)
|
||||
return Math.max(minX, Math.min(maxX, rawX))
|
||||
}
|
||||
return Math.max(popupGap, Math.min(screenWidth - popupWidth - popupGap, rawX))
|
||||
})(), dpr)
|
||||
|
||||
readonly property real alignedY: Theme.snap((() => {
|
||||
const useAutoGaps = storedBarConfig?.popupGapsAuto !== undefined ? storedBarConfig.popupGapsAuto : true
|
||||
const manualGapValue = storedBarConfig?.popupGapsManual !== undefined ? storedBarConfig.popupGapsManual : 4
|
||||
const popupGap = useAutoGaps ? Math.max(4, storedBarSpacing) : manualGapValue
|
||||
|
||||
let rawY = 0
|
||||
if (effectiveBarPosition === SettingsData.Position.Bottom) {
|
||||
rawY = triggerY - popupHeight
|
||||
} else if (effectiveBarPosition === SettingsData.Position.Top) {
|
||||
rawY = triggerY
|
||||
} else {
|
||||
rawY = triggerY - (popupHeight / 2)
|
||||
const minY = adjacentBarInfo.topBar > 0 ? adjacentBarInfo.topBar : popupGap
|
||||
const maxY = screenHeight - popupHeight - (adjacentBarInfo.bottomBar > 0 ? adjacentBarInfo.bottomBar : popupGap)
|
||||
return Math.max(minY, Math.min(maxY, rawY))
|
||||
}
|
||||
return Math.max(popupGap, Math.min(screenHeight - popupHeight - popupGap, rawY))
|
||||
})(), dpr)
|
||||
|
||||
readonly property real maskX: {
|
||||
const triggeringBarX = (effectiveBarPosition === SettingsData.Position.Left && root.barWidth > 0) ? root.barWidth : 0
|
||||
const adjacentLeftBar = adjacentBarInfo?.leftBar ?? 0
|
||||
return Math.max(triggeringBarX, adjacentLeftBar)
|
||||
}
|
||||
|
||||
readonly property real maskY: {
|
||||
const triggeringBarY = (effectiveBarPosition === SettingsData.Position.Top && root.barHeight > 0) ? root.barHeight : 0
|
||||
const adjacentTopBar = adjacentBarInfo?.topBar ?? 0
|
||||
return Math.max(triggeringBarY, adjacentTopBar)
|
||||
}
|
||||
|
||||
readonly property real maskWidth: {
|
||||
const triggeringBarRight = (effectiveBarPosition === SettingsData.Position.Right && root.barWidth > 0) ? root.barWidth : 0
|
||||
const adjacentRightBar = adjacentBarInfo?.rightBar ?? 0
|
||||
const rightExclusion = Math.max(triggeringBarRight, adjacentRightBar)
|
||||
return Math.max(100, root.width - maskX - rightExclusion)
|
||||
}
|
||||
|
||||
readonly property real maskHeight: {
|
||||
const triggeringBarBottom = (effectiveBarPosition === SettingsData.Position.Bottom && root.barHeight > 0) ? root.barHeight : 0
|
||||
const adjacentBottomBar = adjacentBarInfo?.bottomBar ?? 0
|
||||
const bottomExclusion = Math.max(triggeringBarBottom, adjacentBottomBar)
|
||||
return Math.max(100, root.height - maskY - bottomExclusion)
|
||||
}
|
||||
|
||||
mask: Region {
|
||||
item: Rectangle {
|
||||
x: root.maskX
|
||||
y: root.maskY
|
||||
width: root.maskWidth
|
||||
height: root.maskHeight
|
||||
width: shouldBeVisible ? root.maskWidth : 0
|
||||
height: shouldBeVisible ? root.maskHeight : 0
|
||||
}
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
x: maskX
|
||||
y: maskY
|
||||
width: maskWidth
|
||||
height: maskHeight
|
||||
z: -1
|
||||
x: root.maskX
|
||||
y: root.maskY
|
||||
width: root.maskWidth
|
||||
height: root.maskHeight
|
||||
enabled: shouldBeVisible
|
||||
acceptedButtons: Qt.LeftButton | Qt.RightButton | Qt.MiddleButton
|
||||
onClicked: mouse => {
|
||||
const clickX = mouse.x + maskX
|
||||
const clickY = mouse.y + maskY
|
||||
const outsideContent = clickX < alignedX || clickX > alignedX + alignedWidth ||
|
||||
clickY < alignedY || clickY > alignedY + alignedHeight
|
||||
const clickX = mouse.x + root.maskX;
|
||||
const clickY = mouse.y + root.maskY;
|
||||
const outsideContent = clickX < root.alignedX || clickX > root.alignedX + root.alignedWidth || clickY < root.alignedY || clickY > root.alignedY + root.alignedHeight;
|
||||
|
||||
if (!outsideContent) return
|
||||
|
||||
backgroundClicked()
|
||||
if (!outsideContent)
|
||||
return;
|
||||
backgroundClicked();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
PanelWindow {
|
||||
id: contentWindow
|
||||
screen: root.screen
|
||||
visible: false
|
||||
color: "transparent"
|
||||
|
||||
WlrLayershell.namespace: root.layerNamespace
|
||||
WlrLayershell.layer: {
|
||||
switch (Quickshell.env("DMS_POPOUT_LAYER")) {
|
||||
case "bottom":
|
||||
return WlrLayershell.Bottom;
|
||||
case "top":
|
||||
return WlrLayershell.Top;
|
||||
case "background":
|
||||
return WlrLayershell.Background;
|
||||
default:
|
||||
return WlrLayershell.Overlay;
|
||||
}
|
||||
}
|
||||
WlrLayershell.exclusiveZone: -1
|
||||
WlrLayershell.keyboardFocus: {
|
||||
if (customKeyboardFocus !== null)
|
||||
return customKeyboardFocus;
|
||||
if (!shouldBeVisible)
|
||||
return WlrKeyboardFocus.None;
|
||||
if (CompositorService.isHyprland)
|
||||
return WlrKeyboardFocus.OnDemand;
|
||||
return WlrKeyboardFocus.Exclusive;
|
||||
}
|
||||
|
||||
anchors {
|
||||
left: true
|
||||
top: true
|
||||
}
|
||||
|
||||
WlrLayershell.margins {
|
||||
left: root.alignedX - shadowBuffer
|
||||
top: root.alignedY - shadowBuffer
|
||||
}
|
||||
|
||||
implicitWidth: root.alignedWidth + (shadowBuffer * 2)
|
||||
implicitHeight: root.alignedHeight + (shadowBuffer * 2)
|
||||
|
||||
Item {
|
||||
id: contentContainer
|
||||
x: alignedX
|
||||
y: alignedY
|
||||
width: alignedWidth
|
||||
height: alignedHeight
|
||||
x: shadowBuffer
|
||||
y: shadowBuffer
|
||||
width: root.alignedWidth
|
||||
height: root.alignedHeight
|
||||
|
||||
readonly property bool barTop: effectiveBarPosition === SettingsData.Position.Top
|
||||
readonly property bool barBottom: effectiveBarPosition === SettingsData.Position.Bottom
|
||||
@@ -269,9 +315,9 @@ PanelWindow {
|
||||
Connections {
|
||||
target: root
|
||||
function onShouldBeVisibleChanged() {
|
||||
contentContainer.animX = Theme.snap(root.shouldBeVisible ? 0 : contentContainer.offsetX, root.dpr)
|
||||
contentContainer.animY = Theme.snap(root.shouldBeVisible ? 0 : contentContainer.offsetY, root.dpr)
|
||||
contentContainer.scaleValue = root.shouldBeVisible ? 1.0 : root.animationScaleCollapsed
|
||||
contentContainer.animX = Theme.snap(root.shouldBeVisible ? 0 : contentContainer.offsetX, root.dpr);
|
||||
contentContainer.animY = Theme.snap(root.shouldBeVisible ? 0 : contentContainer.offsetY, root.dpr);
|
||||
contentContainer.scaleValue = root.shouldBeVisible ? 1.0 : root.animationScaleCollapsed;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -344,8 +390,8 @@ PanelWindow {
|
||||
shadowBlur: Math.max(0, Math.min(1, contentWrapper.shadowBlurPx / bgShadowLayer.blurMax))
|
||||
shadowScale: 1 + (2 * contentWrapper.shadowSpreadPx) / Math.max(1, Math.min(bgShadowLayer.width, bgShadowLayer.height))
|
||||
shadowColor: {
|
||||
const baseColor = Theme.isLightMode ? Qt.rgba(0, 0, 0, 1) : Theme.surfaceContainerHighest
|
||||
return Theme.withAlpha(baseColor, contentWrapper.effectiveShadowAlpha)
|
||||
const baseColor = Theme.isLightMode ? Qt.rgba(0, 0, 0, 1) : Theme.surfaceContainerHighest;
|
||||
return Theme.withAlpha(baseColor, contentWrapper.effectiveShadowAlpha);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -364,7 +410,7 @@ PanelWindow {
|
||||
Loader {
|
||||
id: contentLoader
|
||||
anchors.fill: parent
|
||||
active: root.visible
|
||||
active: contentWindow.visible
|
||||
asynchronous: false
|
||||
}
|
||||
}
|
||||
@@ -378,8 +424,9 @@ PanelWindow {
|
||||
focus: true
|
||||
Keys.onPressed: event => {
|
||||
if (event.key === Qt.Key_Escape) {
|
||||
close()
|
||||
event.accepted = true
|
||||
close();
|
||||
event.accepted = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user