1
0
mirror of https://github.com/AvengeMedia/DankMaterialShell.git synced 2026-01-28 07:22:50 -05:00

refactors: more DankModals, remove GlobalDropdown and InputDialog

This commit is contained in:
bbedward
2025-07-23 11:11:56 -04:00
parent 56a857939b
commit 14eef59c9f
17 changed files with 194 additions and 475 deletions

View File

@@ -84,7 +84,7 @@ shell.qml # Main entry point (minimal orchestration)
├── Modules/ # UI components ├── Modules/ # UI components
│ ├── TopBar.qml │ ├── TopBar.qml
│ ├── AppLauncher.qml │ ├── AppLauncher.qml
│ ├── ControlCenterPopup.qml │ ├── ControlCenter.qml
│ └── [18 total modules] │ └── [18 total modules]
└── Widgets/ # Reusable UI controls └── Widgets/ # Reusable UI controls
├── DankIcon.qml ├── DankIcon.qml
@@ -115,7 +115,7 @@ shell.qml # Main entry point (minimal orchestration)
- Services handle system commands, state management, and hardware integration - Services handle system commands, state management, and hardware integration
4. **Modules/** - UI components 4. **Modules/** - UI components
- **Full-screen components**: AppLauncher, ClipboardHistory, ControlCenterPopup - **Full-screen components**: AppLauncher, ClipboardHistory, ControlCenter
- **Panel components**: TopBar, SystemTrayWidget, NotificationPopup - **Panel components**: TopBar, SystemTrayWidget, NotificationPopup
- **Layout components**: WorkspaceSwitcher - **Layout components**: WorkspaceSwitcher
@@ -158,7 +158,7 @@ shell.qml # Main entry point (minimal orchestration)
### Important Components ### Important Components
- **ControlCenterPopup**: System controls (WiFi, Bluetooth, brightness, volume, night mode) - **ControlCenter**: System controls (WiFi, Bluetooth, brightness, volume, night mode)
- **AppLauncher**: Full-featured app grid/list with 93+ applications, search, categories - **AppLauncher**: Full-featured app grid/list with 93+ applications, search, categories
- **ClipboardHistory**: Complete clipboard management with cliphist integration - **ClipboardHistory**: Complete clipboard management with cliphist integration
- **TopBar**: Per-monitor panels with workspace switching, clock, system tray - **TopBar**: Per-monitor panels with workspace switching, clock, system tray

View File

@@ -317,7 +317,10 @@ Rectangle {
MouseArea { MouseArea {
id: progressGlobalMouseArea id: progressGlobalMouseArea
anchors.fill: parent.parent.parent // Fill the entire media player widget x: 0
y: 0
width: mediaPlayerWidget.width
height: mediaPlayerWidget.height
enabled: progressMouseArea.isSeeking enabled: progressMouseArea.isSeeking
visible: false visible: false
preventStealing: true preventStealing: true

View File

@@ -192,7 +192,10 @@ Item {
MouseArea { MouseArea {
id: volumeGlobalMouseArea id: volumeGlobalMouseArea
anchors.fill: parent.parent.parent.parent.parent // Fill the entire control center x: 0
y: 0
width: audioTab.width
height: audioTab.height
enabled: volumeMouseArea.isDragging enabled: volumeMouseArea.isDragging
visible: false visible: false
preventStealing: true preventStealing: true
@@ -514,7 +517,10 @@ Item {
MouseArea { MouseArea {
id: micGlobalMouseArea id: micGlobalMouseArea
anchors.fill: parent.parent.parent.parent.parent // Fill the entire control center x: 0
y: 0
width: audioTab.width
height: audioTab.height
enabled: micMouseArea.isDragging enabled: micMouseArea.isDragging
visible: false visible: false
preventStealing: true preventStealing: true

View File

@@ -364,7 +364,7 @@ PanelWindow {
hoverColor: Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.12) hoverColor: Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.12)
onClicked: { onClicked: {
controlCenterVisible = false; controlCenterVisible = false;
settingsPopup.settingsVisible = true; settingsModal.settingsVisible = true;
} }
} }

View File

@@ -1,104 +0,0 @@
import QtQuick
import QtQuick.Controls
import Quickshell
import Quickshell.Wayland
import qs.Common
import qs.Widgets
PanelWindow {
id: globalDropdownWindow
property var sourceComponent: null
property var options: []
property string currentValue: ""
property int targetX: 0
property int targetY: 0
signal valueSelected(string value)
visible: sourceComponent !== null
implicitWidth: 180
implicitHeight: Math.min(200, options.length * 36 + 16)
WlrLayershell.layer: WlrLayershell.Overlay
WlrLayershell.exclusiveZone: -1
WlrLayershell.keyboardFocus: WlrKeyboardFocus.None
WlrLayershell.margins {
top: targetY
left: targetX
}
anchors {
top: true
left: true
}
color: "transparent"
function showAt(component, globalX, globalY, opts, current) {
sourceComponent = component;
options = opts;
currentValue = current;
// Set the target position using margins
targetX = globalX;
targetY = globalY;
visible = true;
}
function hide() {
sourceComponent = null;
visible = false;
}
Rectangle {
anchors.fill: parent
radius: Theme.cornerRadiusSmall
color: Qt.rgba(Theme.surfaceContainer.r, Theme.surfaceContainer.g, Theme.surfaceContainer.b, 1.0)
border.color: Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.3)
border.width: 1
ScrollView {
anchors.fill: parent
anchors.margins: Theme.spacingS
clip: true
ListView {
model: globalDropdownWindow.options
spacing: 2
delegate: Rectangle {
width: ListView.view.width
height: 32
radius: Theme.cornerRadiusSmall
color: optionArea.containsMouse ? Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.08) : "transparent"
Text {
anchors.left: parent.left
anchors.leftMargin: Theme.spacingS
anchors.verticalCenter: parent.verticalCenter
text: modelData
font.pixelSize: Theme.fontSizeMedium
color: globalDropdownWindow.currentValue === modelData ? Theme.primary : Theme.surfaceText
font.weight: globalDropdownWindow.currentValue === modelData ? Font.Medium : Font.Normal
}
MouseArea {
id: optionArea
anchors.fill: parent
hoverEnabled: true
cursorShape: Qt.PointingHandCursor
onClicked: {
globalDropdownWindow.valueSelected(modelData);
globalDropdownWindow.hide();
}
}
}
}
}
}
// Close on click outside
MouseArea {
anchors.fill: parent
z: -1
onClicked: globalDropdownWindow.hide()
}
}

View File

@@ -1,155 +0,0 @@
import QtQuick
import QtQuick.Controls
import qs.Common
import qs.Widgets
DankModal {
id: inputDialog
property bool dialogVisible: false
property string dialogTitle: "Input Required"
property string dialogSubtitle: "Please enter the required information"
property string inputPlaceholder: "Enter text"
property string inputValue: ""
property bool isPassword: false
property string confirmButtonText: "Confirm"
property string cancelButtonText: "Cancel"
signal confirmed(string value)
signal cancelled()
function showDialog(title, subtitle, placeholder, isPass, confirmText, cancelText) {
dialogTitle = title || "Input Required";
dialogSubtitle = subtitle || "Please enter the required information";
inputPlaceholder = placeholder || "Enter text";
isPassword = isPass || false;
confirmButtonText = confirmText || "Confirm";
cancelButtonText = cancelText || "Cancel";
inputValue = "";
dialogVisible = true;
}
function hideDialog() {
textInput.enabled = false; // Disable before hiding to prevent Wayland warnings
dialogVisible = false;
inputValue = "";
}
visible: dialogVisible
width: 380
height: 190
keyboardFocus: "ondemand"
onOpened: {
textInput.forceActiveFocus()
}
onVisibleChanged: {
if (visible) {
textInput.enabled = true;
} else {
textInput.enabled = false;
}
}
onBackgroundClicked: {
hideDialog();
cancelled();
}
content: Component {
Column {
anchors.centerIn: parent
width: parent.width - Theme.spacingM * 2
spacing: Theme.spacingM
Text {
text: dialogTitle
font.pixelSize: Theme.fontSizeLarge
color: Theme.surfaceText
font.weight: Font.Medium
anchors.horizontalCenter: parent.horizontalCenter
}
Text {
text: dialogSubtitle
font.pixelSize: Theme.fontSizeMedium
color: Theme.surfaceVariantText
anchors.horizontalCenter: parent.horizontalCenter
wrapMode: Text.WordWrap
width: parent.width
horizontalAlignment: Text.AlignHCenter
}
DankTextField {
id: textInput
width: parent.width
placeholderText: inputPlaceholder
text: inputValue
echoMode: isPassword ? TextInput.Password : TextInput.Normal
onTextChanged: inputValue = text
onAccepted: {
hideDialog();
confirmed(text);
}
}
Row {
anchors.horizontalCenter: parent.horizontalCenter
spacing: Theme.spacingM
Rectangle {
width: 120
height: 40
radius: Theme.cornerRadius
color: cancelButton.containsMouse ? Qt.rgba(Theme.surfaceText.r, Theme.surfaceText.g, Theme.surfaceText.b, 0.12) : Qt.rgba(Theme.surfaceVariant.r, Theme.surfaceVariant.g, Theme.surfaceVariant.b, 0.3)
Text {
text: cancelButtonText
font.pixelSize: Theme.fontSizeMedium
color: Theme.surfaceText
font.weight: Font.Medium
anchors.centerIn: parent
}
MouseArea {
id: cancelButton
anchors.fill: parent
hoverEnabled: true
cursorShape: Qt.PointingHandCursor
onClicked: {
hideDialog();
cancelled();
}
}
}
Rectangle {
width: 120
height: 40
radius: Theme.cornerRadius
color: confirmButton.containsMouse ? Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.9) : Theme.primary
Text {
text: confirmButtonText
font.pixelSize: Theme.fontSizeMedium
color: Theme.primaryText
font.weight: Font.Medium
anchors.centerIn: parent
}
MouseArea {
id: confirmButton
anchors.fill: parent
hoverEnabled: true
cursorShape: Qt.PointingHandCursor
onClicked: {
hideDialog();
confirmed(textInput.text);
}
}
}
}
}
}
}

View File

@@ -1,14 +1,13 @@
import QtQuick import QtQuick
import QtQuick.Controls import QtQuick.Controls
import Quickshell import Quickshell
import Quickshell.Wayland
import Quickshell.Widgets
import Quickshell.Io import Quickshell.Io
import Quickshell.Widgets
import qs.Common import qs.Common
import qs.Services import qs.Services
import qs.Widgets import qs.Widgets
PanelWindow { DankModal {
id: root id: root
property bool networkInfoDialogVisible: false property bool networkInfoDialogVisible: false
@@ -16,12 +15,6 @@ PanelWindow {
property var networkData: null property var networkData: null
property string networkDetails: "" property string networkDetails: ""
visible: networkInfoDialogVisible
WlrLayershell.layer: WlrLayershell.Overlay
WlrLayershell.exclusiveZone: -1
WlrLayershell.keyboardFocus: networkInfoDialogVisible ? WlrKeyboardFocus.Exclusive : WlrKeyboardFocus.None
color: "transparent"
function showNetworkInfo(ssid, data) { function showNetworkInfo(ssid, data) {
networkSSID = ssid; networkSSID = ssid;
networkData = data; networkData = data;
@@ -36,43 +29,24 @@ PanelWindow {
networkDetails = ""; networkDetails = "";
} }
anchors { visible: networkInfoDialogVisible
top: true width: 600
left: true height: 500
right: true enableShadow: true
bottom: true onBackgroundClicked: {
hideDialog();
}
onVisibleChanged: {
if (!visible) {
networkSSID = "";
networkData = null;
networkDetails = "";
}
} }
Rectangle { content: Component {
anchors.fill: parent Item {
color: Qt.rgba(0, 0, 0, 0.5)
opacity: networkInfoDialogVisible ? 1 : 0
MouseArea {
anchors.fill: parent anchors.fill: parent
onClicked: {
root.hideDialog();
}
}
Behavior on opacity {
NumberAnimation {
duration: Theme.mediumDuration
easing.type: Theme.standardEasing
}
}
}
Rectangle {
width: Math.min(600, parent.width - Theme.spacingL * 2)
height: Math.min(500, parent.height - Theme.spacingL * 2)
anchors.centerIn: parent
color: Theme.surfaceContainer
radius: Theme.cornerRadiusLarge
border.color: Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.12)
border.width: 1
opacity: networkInfoDialogVisible ? 1 : 0
scale: networkInfoDialogVisible ? 1 : 0.9
Column { Column {
anchors.fill: parent anchors.fill: parent
@@ -101,6 +75,7 @@ PanelWindow {
width: parent.width width: parent.width
elide: Text.ElideRight elide: Text.ElideRight
} }
} }
DankActionButton { DankActionButton {
@@ -112,6 +87,7 @@ PanelWindow {
root.hideDialog(); root.hideDialog();
} }
} }
} }
// Network Details // Network Details
@@ -128,6 +104,7 @@ PanelWindow {
Rectangle { Rectangle {
id: detailsRect id: detailsRect
width: parent.width width: parent.width
height: Math.max(parent.parent.height, detailsText.contentHeight + Theme.spacingM * 2) height: Math.max(parent.parent.height, detailsText.contentHeight + Theme.spacingM * 2)
radius: Theme.cornerRadius radius: Theme.cornerRadius
@@ -137,6 +114,7 @@ PanelWindow {
Text { Text {
id: detailsText id: detailsText
anchors.fill: parent anchors.fill: parent
anchors.margins: Theme.spacingM anchors.margins: Theme.spacingM
text: WifiService.networkInfoDetails.replace(/\\n/g, '\n') || "No information available" text: WifiService.networkInfoDetails.replace(/\\n/g, '\n') || "No information available"
@@ -145,8 +123,11 @@ PanelWindow {
wrapMode: Text.WordWrap wrapMode: Text.WordWrap
lineHeight: 1.5 lineHeight: 1.5
} }
} }
} }
} }
// Close Button // Close Button
@@ -164,6 +145,7 @@ PanelWindow {
Text { Text {
id: closeText id: closeText
anchors.centerIn: parent anchors.centerIn: parent
text: "Close" text: "Close"
font.pixelSize: Theme.fontSizeMedium font.pixelSize: Theme.fontSizeMedium
@@ -173,6 +155,7 @@ PanelWindow {
MouseArea { MouseArea {
id: closeArea id: closeArea
anchors.fill: parent anchors.fill: parent
hoverEnabled: true hoverEnabled: true
cursorShape: Qt.PointingHandCursor cursorShape: Qt.PointingHandCursor
@@ -186,23 +169,15 @@ PanelWindow {
duration: Theme.shortDuration duration: Theme.shortDuration
easing.type: Theme.standardEasing easing.type: Theme.standardEasing
} }
} }
} }
}
}
Behavior on opacity {
NumberAnimation {
duration: Theme.mediumDuration
easing.type: Theme.emphasizedEasing
} }
}
Behavior on scale { }
NumberAnimation {
duration: Theme.mediumDuration
easing.type: Theme.emphasizedEasing
}
} }
} }
} }

View File

@@ -10,15 +10,14 @@ import qs.Common
import qs.Services import qs.Services
import qs.Widgets import qs.Widgets
PanelWindow { DankModal {
id: processListPopup id: processListModal
property bool isVisible: false
property int currentTab: 0 property int currentTab: 0
property var tabNames: ["Processes", "Performance", "System"] property var tabNames: ["Processes", "Performance", "System"]
function show() { function show() {
processListPopup.isVisible = true; processListModal.visible = true;
ProcessMonitorService.updateSystemInfo(); ProcessMonitorService.updateSystemInfo();
ProcessMonitorService.updateProcessList(); ProcessMonitorService.updateProcessList();
SystemMonitorService.enableDetailedMonitoring(true); SystemMonitorService.enableDetailedMonitoring(true);
@@ -27,82 +26,38 @@ PanelWindow {
} }
function hide() { function hide() {
processListPopup.isVisible = false; processListModal.visible = false;
SystemMonitorService.enableDetailedMonitoring(false); SystemMonitorService.enableDetailedMonitoring(false);
} }
function toggle() { function toggle() {
if (processListPopup.isVisible) if (processListModal.visible)
hide(); hide();
else else
show(); show();
} }
WlrLayershell.layer: WlrLayershell.Overlay width: 900
WlrLayershell.exclusiveZone: -1 height: 680
WlrLayershell.keyboardFocus: isVisible ? WlrKeyboardFocus.Exclusive : WlrKeyboardFocus.None visible: false
WlrLayershell.namespace: "quickshell-processlist" keyboardFocus: "exclusive"
visible: isVisible backgroundColor: Theme.popupBackground()
color: "transparent" cornerRadius: Theme.cornerRadiusXLarge
onIsVisibleChanged: { enableShadow: true
ProcessMonitorService.enableMonitoring(isVisible);
onVisibleChanged: {
ProcessMonitorService.enableMonitoring(visible);
} }
anchors { onBackgroundClicked: hide()
top: true
left: true
right: true
bottom: true
}
Rectangle {
anchors.fill: parent
color: Qt.rgba(0, 0, 0, 0.4)
opacity: processListPopup.isVisible ? 1 : 0
visible: processListPopup.isVisible
MouseArea {
anchors.fill: parent
enabled: processListPopup.isVisible
onClicked: processListPopup.hide()
}
Behavior on opacity {
NumberAnimation {
duration: Theme.shortDuration
easing.type: Theme.standardEasing
}
}
}
Rectangle {
id: mainContainer
width: 900
height: 680
anchors.centerIn: parent
color: Theme.popupBackground()
radius: Theme.cornerRadiusXLarge
border.color: Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.08)
border.width: 1
layer.enabled: true
opacity: processListPopup.isVisible ? 1 : 0
scale: processListPopup.isVisible ? 1 : 0.96
MouseArea {
anchors.fill: parent
onClicked: {
}
}
content: Component {
Item { Item {
anchors.fill: parent anchors.fill: parent
focus: true focus: true
Keys.onPressed: function(event) { Keys.onPressed: function(event) {
if (event.key === Qt.Key_Escape) { if (event.key === Qt.Key_Escape) {
processListPopup.hide(); processListModal.hide();
event.accepted = true; event.accepted = true;
} else if (event.key === Qt.Key_1) { } else if (event.key === Qt.Key_1) {
currentTab = 0; currentTab = 0;
@@ -315,34 +270,7 @@ PanelWindow {
} }
} }
} }
layer.effect: MultiEffect {
shadowEnabled: true
shadowHorizontalOffset: 0
shadowVerticalOffset: 8
shadowBlur: 1
shadowColor: Qt.rgba(0, 0, 0, 0.3)
shadowOpacity: 0.3
}
Behavior on opacity {
NumberAnimation {
duration: Theme.mediumDuration
easing.type: Theme.emphasizedEasing
}
}
Behavior on scale {
NumberAnimation {
duration: Theme.mediumDuration
easing.type: Theme.emphasizedEasing
}
}
} }
Component { Component {
@@ -370,17 +298,17 @@ PanelWindow {
IpcHandler { IpcHandler {
function open() { function open() {
processListPopup.show(); processListModal.show();
return "PROCESSLIST_OPEN_SUCCESS"; return "PROCESSLIST_OPEN_SUCCESS";
} }
function close() { function close() {
processListPopup.hide(); processListModal.hide();
return "PROCESSLIST_CLOSE_SUCCESS"; return "PROCESSLIST_CLOSE_SUCCESS";
} }
function toggle() { function toggle() {
processListPopup.toggle(); processListModal.toggle();
return "PROCESSLIST_TOGGLE_SUCCESS"; return "PROCESSLIST_TOGGLE_SUCCESS";
} }

View File

@@ -4,18 +4,15 @@ import qs.Common
import qs.Widgets import qs.Widgets
DankModal { DankModal {
id: settingsPopup id: settingsModal
property bool settingsVisible: false property bool settingsVisible: false
signal closingPopup() signal closingModal()
onVisibleChanged: { onVisibleChanged: {
if (!visible) { if (!visible) {
closingPopup(); closingModal();
if (typeof globalDropdownWindow !== 'undefined') {
globalDropdownWindow.hide();
}
} }
} }
@@ -68,7 +65,7 @@ DankModal {
iconSize: Theme.iconSize - 4 iconSize: Theme.iconSize - 4
iconColor: Theme.surfaceText iconColor: Theme.surfaceText
hoverColor: Qt.rgba(Theme.error.r, Theme.error.g, Theme.error.b, 0.12) hoverColor: Qt.rgba(Theme.error.r, Theme.error.g, Theme.error.b, 0.12)
onClicked: settingsPopup.settingsVisible = false onClicked: settingsModal.settingsVisible = false
} }
} }
@@ -140,8 +137,8 @@ DankModal {
// Keyboard focus and shortcuts // Keyboard focus and shortcuts
FocusScope { FocusScope {
anchors.fill: parent anchors.fill: parent
focus: settingsPopup.settingsVisible focus: settingsModal.settingsVisible
Keys.onEscapePressed: settingsPopup.settingsVisible = false Keys.onEscapePressed: settingsModal.settingsVisible = false
} }
} }

View File

@@ -242,24 +242,6 @@ DankModal {
id: filteredModel id: filteredModel
} }
Connections {
function onReadyChanged() {
if (AppSearchService.ready) {
var allCategories = AppSearchService.getAllCategories().filter((cat) => {
return cat !== "Education" && cat !== "Science";
});
// Insert "Recents" after "All"
var result = ["All", "Recents"];
categories = result.concat(allCategories.filter((cat) => {
return cat !== "All";
}));
if (spotlightOpen)
updateFilteredApps();
}
}
target: AppSearchService
}
content: Component { content: Component {
Item { Item {
anchors.fill: parent anchors.fill: parent

View File

@@ -157,7 +157,7 @@ PanelWindow {
anchors.centerIn: parent anchors.centerIn: parent
onClockClicked: { onClockClicked: {
centerCommandCenter.calendarVisible = !centerCommandCenter.calendarVisible; centcomCenter.calendarVisible = !centcomCenter.calendarVisible;
} }
} }
@@ -167,7 +167,7 @@ PanelWindow {
anchors.rightMargin: Theme.spacingS anchors.rightMargin: Theme.spacingS
visible: Prefs.showMusic && MprisController.activePlayer visible: Prefs.showMusic && MprisController.activePlayer
onClicked: { onClicked: {
centerCommandCenter.calendarVisible = !centerCommandCenter.calendarVisible; centcomCenter.calendarVisible = !centcomCenter.calendarVisible;
} }
} }
@@ -179,7 +179,7 @@ PanelWindow {
anchors.leftMargin: Theme.spacingS anchors.leftMargin: Theme.spacingS
visible: Prefs.showWeather && WeatherService.weather.available && WeatherService.weather.temp > 0 && WeatherService.weather.tempF > 0 visible: Prefs.showWeather && WeatherService.weather.available && WeatherService.weather.temp > 0 && WeatherService.weather.tempF > 0
onClicked: { onClicked: {
centerCommandCenter.calendarVisible = !centerCommandCenter.calendarVisible; centcomCenter.calendarVisible = !centcomCenter.calendarVisible;
} }
} }
@@ -273,10 +273,10 @@ PanelWindow {
// Bluetooth devices are automatically updated via signals // Bluetooth devices are automatically updated via signals
anchors.verticalCenter: parent.verticalCenter anchors.verticalCenter: parent.verticalCenter
isActive: controlCenterPopup.controlCenterVisible isActive: controlCenter.controlCenterVisible
onClicked: { onClicked: {
controlCenterPopup.controlCenterVisible = !controlCenterPopup.controlCenterVisible; controlCenter.controlCenterVisible = !controlCenter.controlCenterVisible;
if (controlCenterPopup.controlCenterVisible) { if (controlCenter.controlCenterVisible) {
if (NetworkService.wifiEnabled) if (NetworkService.wifiEnabled)
WifiService.scanWifi(); WifiService.scanWifi();

View File

@@ -1,4 +1,7 @@
import QtQuick import QtQuick
import QtQuick.Controls
import Quickshell
import Quickshell.Wayland
import qs.Common import qs.Common
import qs.Widgets import qs.Widgets
@@ -84,19 +87,110 @@ Rectangle {
anchors.fill: parent anchors.fill: parent
hoverEnabled: true hoverEnabled: true
cursorShape: Qt.PointingHandCursor cursorShape: Qt.PointingHandCursor
onClicked: { onPressed: (mouse) => {
if (typeof globalDropdownWindow !== 'undefined') { mouse.accepted = true;
// Get global position of the dropdown button if (!dropdownMenu.visible) {
var globalPos = dropdown.mapToGlobal(0, 0); dropdownMenu.updatePosition();
globalDropdownWindow.showAt(root, globalPos.x, globalPos.y + dropdown.height + 4, root.options, root.currentValue); dropdownMenu.visible = true;
} else {
// Connect to value selection (with cleanup) dropdownMenu.visible = false;
globalDropdownWindow.valueSelected.connect(function(value) {
root.currentValue = value;
root.valueChanged(value);
});
} }
} }
} }
} }
// Integrated dropdown menu with full-screen overlay
PanelWindow {
id: dropdownMenu
property int targetX: 0
property int targetY: 0
visible: false
WlrLayershell.layer: WlrLayershell.Overlay
WlrLayershell.exclusiveZone: -1
WlrLayershell.keyboardFocus: WlrKeyboardFocus.None
anchors {
top: true
left: true
right: true
bottom: true
}
color: "transparent"
function updatePosition() {
var globalPos = dropdown.mapToGlobal(0, 0);
targetX = globalPos.x;
targetY = globalPos.y + dropdown.height + 4;
}
// Background click interceptor (invisible)
MouseArea {
anchors.fill: parent
z: -1
onPressed: {
dropdownMenu.visible = false;
}
}
// Dropdown menu content
Rectangle {
x: dropdownMenu.targetX
y: dropdownMenu.targetY
width: 180
height: Math.min(200, root.options.length * 36 + 16)
radius: Theme.cornerRadiusSmall
color: Qt.rgba(Theme.surfaceContainer.r, Theme.surfaceContainer.g, Theme.surfaceContainer.b, 1.0)
border.color: Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.3)
border.width: 1
ScrollView {
anchors.fill: parent
anchors.margins: Theme.spacingS
clip: true
ListView {
model: root.options
spacing: 2
delegate: Rectangle {
width: ListView.view.width
height: 32
radius: Theme.cornerRadiusSmall
color: optionArea.containsMouse ? Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.08) : "transparent"
Text {
anchors.left: parent.left
anchors.leftMargin: Theme.spacingS
anchors.verticalCenter: parent.verticalCenter
text: modelData
font.pixelSize: Theme.fontSizeMedium
color: root.currentValue === modelData ? Theme.primary : Theme.surfaceText
font.weight: root.currentValue === modelData ? Font.Medium : Font.Normal
}
MouseArea {
id: optionArea
anchors.fill: parent
hoverEnabled: true
cursorShape: Qt.PointingHandCursor
onPressed: {
root.currentValue = modelData;
root.valueChanged(modelData);
dropdownMenu.visible = false;
}
}
}
}
}
}
}
// Global keyboard handler for escape key
Keys.onEscapePressed: {
if (dropdownMenu.visible) {
dropdownMenu.visible = false;
}
}
} }

View File

@@ -2,7 +2,7 @@
import Quickshell import Quickshell
import qs.Modules import qs.Modules
import qs.Modules.CenterCommandCenter import qs.Modules.CentcomCenter
import qs.Modules.ControlCenter import qs.Modules.ControlCenter
import qs.Modules.Settings import qs.Modules.Settings
import qs.Modules.TopBar import qs.Modules.TopBar
@@ -22,8 +22,8 @@ ShellRoot {
} }
// Global popup windows // Global popup windows
CenterCommandCenter { CentcomCenter {
id: centerCommandCenter id: centcomCenter
} }
TrayMenuPopup { TrayMenuPopup {
@@ -38,8 +38,8 @@ ShellRoot {
id: notificationPopup id: notificationPopup
} }
ControlCenterPopup { ControlCenter {
id: controlCenterPopup id: controlCenter
onPowerActionRequested: (action, title, message) => { onPowerActionRequested: (action, title, message) => {
powerConfirmDialog.powerConfirmAction = action; powerConfirmDialog.powerConfirmAction = action;
powerConfirmDialog.powerConfirmTitle = title; powerConfirmDialog.powerConfirmTitle = title;
@@ -56,10 +56,6 @@ ShellRoot {
id: networkInfoDialog id: networkInfoDialog
} }
InputDialog {
id: globalInputDialog
}
BatteryControlPopup { BatteryControlPopup {
id: batteryControlPopup id: batteryControlPopup
} }
@@ -76,13 +72,10 @@ ShellRoot {
id: processListDropdown id: processListDropdown
} }
SettingsPopup { SettingsModal {
id: settingsPopup id: settingsModal
} }
GlobalDropdown {
id: globalDropdownWindow
}
// Application and clipboard components // Application and clipboard components
AppLauncher { AppLauncher {
@@ -93,8 +86,8 @@ ShellRoot {
id: spotlightLauncher id: spotlightLauncher
} }
ProcessListPopup { ProcessListModal {
id: processListPopup id: processListModal
} }
ClipboardHistory { ClipboardHistory {