1
0
mirror of https://github.com/AvengeMedia/DankMaterialShell.git synced 2026-04-05 05:12:05 -04:00
Files
DankMaterialShell/quickshell/Modules/DankBar/Widgets/Vpn.qml
Vladimir Kosteley cc62aa4a9e fix: VpnPopout and Vpn widget tooltip positions (#1623)
* fix(vpn-widget): correct tooltip positioning for bottom bar alignment

- Calculate tooltip Y position based on bar edge (bottom vs top)
- Position tooltip above bar when edge is bottom to prevent overflow
- Account for tooltip height when positioning on bottom edge
- Use proper screen reference for consistent positioning across displays

* fix(VpnPopout): use correct screen height for popup sizing

- Fix popup height calculation to use the assigned screen property
  instead of the global Screen object
- Prevents incorrect positioning when multiple screens are present
- Fallback to Screen.height if screen property is not set

* fix(widgets): close DankPopout when screen is removed

- Add Connections handler to monitor Quickshell.onScreensChanged
- Automatically close popout if its assigned screen no longer exists
- Prevent orphaned popouts when displays are disconnected
2026-02-08 19:17:53 -05:00

141 lines
4.8 KiB
QML

import QtQuick
import qs.Common
import qs.Modules.Plugins
import qs.Services
import qs.Widgets
BasePill {
id: root
Ref {
service: DMSNetworkService
}
property bool isHovered: clickArea.containsMouse
property bool isAutoHideBar: false
readonly property real minTooltipY: {
if (!parentScreen || !isVerticalOrientation) {
return 0;
}
if (isAutoHideBar) {
return 0;
}
if (parentScreen.y > 0) {
return barThickness + barSpacing;
}
return 0;
}
signal toggleVpnPopup
content: Component {
Item {
implicitWidth: icon.width
implicitHeight: root.widgetThickness - root.horizontalPadding * 2
DankIcon {
id: icon
name: DMSNetworkService.connected ? "vpn_lock" : "vpn_key_off"
size: Theme.barIconSize(root.barThickness, -4, root.barConfig?.noBackground)
color: DMSNetworkService.connected ? Theme.primary : Theme.widgetIconColor
opacity: DMSNetworkService.isBusy ? 0.5 : 1.0
anchors.centerIn: parent
Behavior on opacity {
NumberAnimation {
duration: Theme.shortDuration
easing.type: Easing.InOutQuad
}
}
}
}
}
Loader {
id: tooltipLoader
active: false
sourceComponent: DankTooltip {}
}
MouseArea {
id: clickArea
anchors.fill: parent
hoverEnabled: true
cursorShape: DMSNetworkService.isBusy ? Qt.BusyCursor : Qt.PointingHandCursor
acceptedButtons: Qt.LeftButton | Qt.RightButton
enabled: !DMSNetworkService.isBusy
onPressed: event => {
switch (event.button) {
case Qt.RightButton:
DMSNetworkService.toggleVpn();
return;
case Qt.LeftButton:
root.toggleVpnPopup();
return;
}
}
onEntered: {
if (!root.parentScreen || (popoutTarget?.shouldBeVisible))
return;
tooltipLoader.active = true;
if (!tooltipLoader.item)
return;
let tooltipText = "";
if (!DMSNetworkService.connected) {
tooltipText = "VPN Disconnected";
} else {
const names = DMSNetworkService.activeNames || [];
if (names.length <= 1) {
const name = names[0] || "";
const maxLength = 25;
const displayName = name.length > maxLength ? name.substring(0, maxLength) + "..." : name;
tooltipText = "VPN Connected • " + displayName;
} else {
const name = names[0];
const maxLength = 20;
const displayName = name.length > maxLength ? name.substring(0, maxLength) + "..." : name;
tooltipText = "VPN Connected • " + displayName + " +" + (names.length - 1);
}
}
if (root.isVerticalOrientation) {
const globalPos = mapToGlobal(width / 2, height / 2);
const currentScreen = root.parentScreen || Screen;
const screenX = currentScreen ? currentScreen.x : 0;
const screenY = currentScreen ? currentScreen.y : 0;
const relativeY = globalPos.y - screenY;
const adjustedY = relativeY + root.minTooltipY;
const tooltipX = root.axis?.edge === "left" ? (root.barThickness + root.barSpacing + Theme.spacingXS) : (currentScreen.width - root.barThickness - root.barSpacing - Theme.spacingXS);
const isLeft = root.axis?.edge === "left";
tooltipLoader.item.show(tooltipText, screenX + tooltipX, adjustedY, currentScreen, isLeft, !isLeft);
} else {
const isBottom = root.axis?.edge === "bottom";
const globalPos = mapToGlobal(width / 2, 0);
const currentScreen = root.parentScreen || Screen;
let tooltipY;
if (isBottom) {
const tooltipHeight = Theme.fontSizeSmall * 1.5 + Theme.spacingS * 2;
tooltipY = currentScreen.height - root.barThickness - root.barSpacing - Theme.spacingXS - tooltipHeight;
} else {
tooltipY = root.barThickness + root.barSpacing + Theme.spacingXS;
}
tooltipLoader.item.show(tooltipText, globalPos.x, tooltipY, currentScreen, false, false);
}
}
onExited: {
if (tooltipLoader.item) {
tooltipLoader.item.hide();
}
tooltipLoader.active = false;
}
}
}