diff --git a/quickshell/Modals/Spotlight/SpotlightContent.qml b/quickshell/Modals/Spotlight/SpotlightContent.qml index 23ba83e3..7bb40fa5 100644 --- a/quickshell/Modals/Spotlight/SpotlightContent.qml +++ b/quickshell/Modals/Spotlight/SpotlightContent.qml @@ -152,7 +152,7 @@ Item { if (searchMode === "apps" && appLauncher.model.count > 0) { const selectedApp = appLauncher.model.get(appLauncher.selectedIndex); const menu = usePopupContextMenu ? popupContextMenu : layerContextMenuLoader.item; - + if (selectedApp && menu && resultsView) { const itemPos = resultsView.getSelectedItemPosition(); const contentPos = resultsView.mapToItem(spotlightKeyHandler, itemPos.x, itemPos.y); @@ -192,10 +192,9 @@ Item { } } - SpotlightContextMenuPopup { id: popupContextMenu - + parent: spotlightKeyHandler appLauncher: spotlightKeyHandler.appLauncher parentHandler: spotlightKeyHandler @@ -203,7 +202,7 @@ Item { visible: false z: 1000 } - + MouseArea { anchors.fill: parent visible: usePopupContextMenu && popupContextMenu.visible @@ -211,7 +210,7 @@ Item { z: 999 onClicked: popupContextMenu.hide() } - + Loader { id: layerContextMenuLoader active: !spotlightKeyHandler.usePopupContextMenu @@ -224,7 +223,7 @@ Item { } } } - + Connections { target: parentModal function onSpotlightOpenChanged() { @@ -244,16 +243,17 @@ Item { spacing: Theme.spacingM clip: false - Row { - width: parent.width - spacing: Theme.spacingM - leftPadding: Theme.spacingS - topPadding: Theme.spacingS + Item { + id: searchRow + width: parent.width - Theme.spacingS * 2 + height: 56 + anchors.horizontalCenter: parent.horizontalCenter DankTextField { id: searchField - - width: parent.width - 80 - Theme.spacingL + anchors.left: parent.left + anchors.right: buttonsContainer.left + anchors.rightMargin: Theme.spacingM height: 56 cornerRadius: Theme.cornerRadius backgroundColor: Theme.withAlpha(Theme.surfaceContainerHigh, Theme.popupTransparency) @@ -302,147 +302,159 @@ Item { } } - Row { - spacing: Theme.spacingXS - visible: searchMode === "apps" && appLauncher.model.count > 0 + Item { + id: buttonsContainer + width: viewModeButtons.visible ? viewModeButtons.width : (fileSearchButtons.visible ? fileSearchButtons.width : 0) + height: 36 + anchors.right: parent.right anchors.verticalCenter: parent.verticalCenter - Rectangle { - width: 36 - height: 36 - radius: Theme.cornerRadius - color: appLauncher.viewMode === "list" ? Theme.primaryHover : listViewArea.containsMouse ? Theme.surfaceHover : "transparent" + Row { + id: viewModeButtons + spacing: Theme.spacingXS + visible: searchMode === "apps" && appLauncher.model.count > 0 + anchors.right: parent.right + anchors.verticalCenter: parent.verticalCenter - DankIcon { - anchors.centerIn: parent - name: "view_list" - size: 18 - color: appLauncher.viewMode === "list" ? Theme.primary : Theme.surfaceText + Rectangle { + width: 36 + height: 36 + radius: Theme.cornerRadius + color: appLauncher.viewMode === "list" ? Theme.primaryHover : listViewArea.containsMouse ? Theme.surfaceHover : "transparent" + + DankIcon { + anchors.centerIn: parent + name: "view_list" + size: 18 + color: appLauncher.viewMode === "list" ? Theme.primary : Theme.surfaceText + } + + MouseArea { + id: listViewArea + + anchors.fill: parent + hoverEnabled: true + cursorShape: Qt.PointingHandCursor + onClicked: () => { + appLauncher.setViewMode("list"); + } + } } - MouseArea { - id: listViewArea + Rectangle { + width: 36 + height: 36 + radius: Theme.cornerRadius + color: appLauncher.viewMode === "grid" ? Theme.primaryHover : gridViewArea.containsMouse ? Theme.surfaceHover : "transparent" - anchors.fill: parent - hoverEnabled: true - cursorShape: Qt.PointingHandCursor - onClicked: () => { - appLauncher.setViewMode("list"); + DankIcon { + anchors.centerIn: parent + name: "grid_view" + size: 18 + color: appLauncher.viewMode === "grid" ? Theme.primary : Theme.surfaceText + } + + MouseArea { + id: gridViewArea + + anchors.fill: parent + hoverEnabled: true + cursorShape: Qt.PointingHandCursor + onClicked: () => { + appLauncher.setViewMode("grid"); + } } } } - Rectangle { - width: 36 - height: 36 - radius: Theme.cornerRadius - color: appLauncher.viewMode === "grid" ? Theme.primaryHover : gridViewArea.containsMouse ? Theme.surfaceHover : "transparent" + Row { + id: fileSearchButtons + spacing: Theme.spacingXS + visible: searchMode === "files" + anchors.right: parent.right + anchors.verticalCenter: parent.verticalCenter - DankIcon { - anchors.centerIn: parent - name: "grid_view" - size: 18 - color: appLauncher.viewMode === "grid" ? Theme.primary : Theme.surfaceText - } + Rectangle { + id: filenameFilterButton - MouseArea { - id: gridViewArea + width: 36 + height: 36 + radius: Theme.cornerRadius + color: fileSearchController.searchField === "filename" ? Theme.primaryHover : filenameFilterArea.containsMouse ? Theme.surfaceHover : "transparent" - anchors.fill: parent - hoverEnabled: true - cursorShape: Qt.PointingHandCursor - onClicked: () => { - appLauncher.setViewMode("grid"); + DankIcon { + anchors.centerIn: parent + name: "title" + size: 18 + color: fileSearchController.searchField === "filename" ? Theme.primary : Theme.surfaceText + } + + MouseArea { + id: filenameFilterArea + + anchors.fill: parent + hoverEnabled: true + cursorShape: Qt.PointingHandCursor + onClicked: () => { + fileSearchController.searchField = "filename"; + } + onEntered: { + filenameTooltipLoader.active = true; + Qt.callLater(() => { + if (filenameTooltipLoader.item) { + const p = mapToItem(null, width / 2, height + Theme.spacingXS); + filenameTooltipLoader.item.show(I18n.tr("Search filenames"), p.x, p.y, null); + } + }); + } + onExited: { + if (filenameTooltipLoader.item) + filenameTooltipLoader.item.hide(); + + filenameTooltipLoader.active = false; + } } } - } - } - Row { - spacing: Theme.spacingXS - visible: searchMode === "files" - anchors.verticalCenter: parent.verticalCenter + Rectangle { + id: contentFilterButton - Rectangle { - id: filenameFilterButton + width: 36 + height: 36 + radius: Theme.cornerRadius + color: fileSearchController.searchField === "body" ? Theme.primaryHover : contentFilterArea.containsMouse ? Theme.surfaceHover : "transparent" - width: 36 - height: 36 - radius: Theme.cornerRadius - color: fileSearchController.searchField === "filename" ? Theme.primaryHover : filenameFilterArea.containsMouse ? Theme.surfaceHover : "transparent" - - DankIcon { - anchors.centerIn: parent - name: "title" - size: 18 - color: fileSearchController.searchField === "filename" ? Theme.primary : Theme.surfaceText - } - - MouseArea { - id: filenameFilterArea - - anchors.fill: parent - hoverEnabled: true - cursorShape: Qt.PointingHandCursor - onClicked: () => { - fileSearchController.searchField = "filename"; + DankIcon { + anchors.centerIn: parent + name: "description" + size: 18 + color: fileSearchController.searchField === "body" ? Theme.primary : Theme.surfaceText } - onEntered: { - filenameTooltipLoader.active = true; - Qt.callLater(() => { - if (filenameTooltipLoader.item) { - const p = mapToItem(null, width / 2, height + Theme.spacingXS); - filenameTooltipLoader.item.show(I18n.tr("Search filenames"), p.x, p.y, null); - } - }); - } - onExited: { - if (filenameTooltipLoader.item) - filenameTooltipLoader.item.hide(); - filenameTooltipLoader.active = false; - } - } - } + MouseArea { + id: contentFilterArea - Rectangle { - id: contentFilterButton + anchors.fill: parent + hoverEnabled: true + cursorShape: Qt.PointingHandCursor + onClicked: () => { + fileSearchController.searchField = "body"; + } + onEntered: { + contentTooltipLoader.active = true; + Qt.callLater(() => { + if (contentTooltipLoader.item) { + const p = mapToItem(null, width / 2, height + Theme.spacingXS); + contentTooltipLoader.item.show(I18n.tr("Search file contents"), p.x, p.y, null); + } + }); + } + onExited: { + if (contentTooltipLoader.item) + contentTooltipLoader.item.hide(); - width: 36 - height: 36 - radius: Theme.cornerRadius - color: fileSearchController.searchField === "body" ? Theme.primaryHover : contentFilterArea.containsMouse ? Theme.surfaceHover : "transparent" - - DankIcon { - anchors.centerIn: parent - name: "description" - size: 18 - color: fileSearchController.searchField === "body" ? Theme.primary : Theme.surfaceText - } - - MouseArea { - id: contentFilterArea - - anchors.fill: parent - hoverEnabled: true - cursorShape: Qt.PointingHandCursor - onClicked: () => { - fileSearchController.searchField = "body"; - } - onEntered: { - contentTooltipLoader.active = true; - Qt.callLater(() => { - if (contentTooltipLoader.item) { - const p = mapToItem(null, width / 2, height + Theme.spacingXS); - contentTooltipLoader.item.show(I18n.tr("Search file contents"), p.x, p.y, null); - } - }); - } - onExited: { - if (contentTooltipLoader.item) - contentTooltipLoader.item.hide(); - - contentTooltipLoader.active = false; + contentTooltipLoader.active = false; + } } } } @@ -458,13 +470,13 @@ Item { anchors.fill: parent appLauncher: spotlightKeyHandler.appLauncher visible: searchMode === "apps" - + onItemRightClicked: (index, modelData, mouseX, mouseY) => { const menu = usePopupContextMenu ? popupContextMenu : layerContextMenuLoader.item; - + if (menu?.show) { const isPopup = menu.contentItem !== undefined; - + if (isPopup) { const localPos = popupContextMenu.parent.mapFromItem(null, mouseX, mouseY); menu.show(localPos.x, localPos.y, modelData, false); diff --git a/quickshell/Modals/Spotlight/SpotlightResults.qml b/quickshell/Modals/Spotlight/SpotlightResults.qml index 3f099cfd..12464134 100644 --- a/quickshell/Modals/Spotlight/SpotlightResults.qml +++ b/quickshell/Modals/Spotlight/SpotlightResults.qml @@ -1,6 +1,4 @@ import QtQuick -import Quickshell -import Quickshell.Widgets import qs.Common import qs.Widgets @@ -8,32 +6,45 @@ Rectangle { id: resultsContainer property var appLauncher: null - + signal itemRightClicked(int index, var modelData, real mouseX, real mouseY) function resetScroll() { - resultsList.contentY = 0 + resultsList.contentY = 0; if (gridLoader.item) { - gridLoader.item.contentY = 0 + gridLoader.item.contentY = 0; } } function getSelectedItemPosition() { - if (!appLauncher) return { x: 0, y: 0 }; - + if (!appLauncher) + return { + x: 0, + y: 0 + }; + const selectedIndex = appLauncher.selectedIndex; if (appLauncher.viewMode === "list") { const itemY = selectedIndex * (resultsList.itemHeight + resultsList.itemSpacing) - resultsList.contentY; - return { x: resultsList.width / 2, y: itemY + resultsList.itemHeight / 2 }; + return { + x: resultsList.width / 2, + y: itemY + resultsList.itemHeight / 2 + }; } else if (gridLoader.item) { const grid = gridLoader.item; const row = Math.floor(selectedIndex / grid.actualColumns); const col = selectedIndex % grid.actualColumns; const itemX = col * grid.cellWidth + grid.leftMargin + grid.cellWidth / 2; const itemY = row * grid.cellHeight - grid.contentY + grid.cellHeight / 2; - return { x: itemX, y: itemY }; + return { + x: itemX, + y: itemY + }; } - return { x: 0, y: 0 }; + return { + x: 0, + y: 0 + }; } radius: Theme.cornerRadius @@ -56,14 +67,13 @@ Rectangle { function ensureVisible(index) { if (index < 0 || index >= count) - return - - const itemY = index * (itemHeight + itemSpacing) - const itemBottom = itemY + itemHeight + return; + const itemY = index * (itemHeight + itemSpacing); + const itemBottom = itemY + itemHeight; if (itemY < contentY) - contentY = itemY + contentY = itemY; else if (itemBottom > contentY + height) - contentY = itemBottom - height + contentY = itemBottom - height; } anchors.fill: parent @@ -79,19 +89,19 @@ Rectangle { reuseItems: true onCurrentIndexChanged: { if (keyboardNavigationActive) - ensureVisible(currentIndex) + ensureVisible(currentIndex); } onItemClicked: (index, modelData) => { - if (appLauncher) - appLauncher.launchApp(modelData) - } + if (appLauncher) + appLauncher.launchApp(modelData); + } onItemRightClicked: (index, modelData, mouseX, mouseY) => { resultsContainer.itemRightClicked(index, modelData, mouseX, mouseY); } onKeyboardNavigationReset: () => { - if (appLauncher) - appLauncher.keyboardNavigationActive = false - } + if (appLauncher) + appLauncher.keyboardNavigationActive = false; + } delegate: AppLauncherListDelegate { listView: resultsList @@ -105,7 +115,7 @@ Rectangle { iconUnicodeScale: 0.8 onItemClicked: (idx, modelData) => resultsList.itemClicked(idx, modelData) onItemRightClicked: (idx, modelData, mouseX, mouseY) => { - resultsList.itemRightClicked(idx, modelData, mouseX, mouseY) + resultsList.itemRightClicked(idx, modelData, mouseX, mouseY); } onKeyboardNavigationReset: resultsList.keyboardNavigationReset } @@ -121,20 +131,20 @@ Rectangle { visible: appLauncher && appLauncher.viewMode === "grid" active: appLauncher && appLauncher.viewMode === "grid" asynchronous: false - + onLoaded: { if (item) { item.appLauncher = Qt.binding(() => resultsContainer.appLauncher); } } - + onWidthChanged: { if (visible && Math.abs(width - _lastWidth) > 1) { - _lastWidth = width - active = false + _lastWidth = width; + active = false; Qt.callLater(() => { - active = true - }) + active = true; + }); } } sourceComponent: Component { @@ -148,14 +158,13 @@ Rectangle { property bool adaptiveColumns: false property int minCellWidth: 120 property int maxCellWidth: 160 - property int cellPadding: 8 property real iconSizeRatio: 0.55 property int maxIconSize: 48 property int minIconSize: 32 property bool hoverUpdatesSelection: false property bool keyboardNavigationActive: appLauncher ? appLauncher.keyboardNavigationActive : false - property int baseCellWidth: adaptiveColumns ? Math.max(minCellWidth, Math.min(maxCellWidth, width / columns)) : (width - Theme.spacingS * 2) / columns - property int baseCellHeight: baseCellWidth + 20 + property real baseCellWidth: adaptiveColumns ? Math.max(minCellWidth, Math.min(maxCellWidth, width / columns)) : width / columns + property real baseCellHeight: baseCellWidth + 20 property int actualColumns: adaptiveColumns ? Math.floor(width / cellWidth) : columns property int remainingSpace: width - (actualColumns * cellWidth) @@ -165,47 +174,44 @@ Rectangle { function ensureVisible(index) { if (index < 0 || index >= count) - return - - const itemY = Math.floor(index / actualColumns) * cellHeight - const itemBottom = itemY + cellHeight + return; + const itemY = Math.floor(index / actualColumns) * cellHeight; + const itemBottom = itemY + cellHeight; if (itemY < contentY) - contentY = itemY + contentY = itemY; else if (itemBottom > contentY + height) - contentY = itemBottom - height + contentY = itemBottom - height; } + anchors.fill: parent model: appLauncher ? appLauncher.model : null clip: true cellWidth: baseCellWidth cellHeight: baseCellHeight - leftMargin: Math.max(Theme.spacingS, remainingSpace / 2) - rightMargin: leftMargin focus: true interactive: true cacheBuffer: Math.max(0, Math.min(height * 2, 1000)) reuseItems: true onCurrentIndexChanged: { if (keyboardNavigationActive) - ensureVisible(currentIndex) + ensureVisible(currentIndex); } onItemClicked: (index, modelData) => { - if (appLauncher) - appLauncher.launchApp(modelData) - } + if (appLauncher) + appLauncher.launchApp(modelData); + } onItemRightClicked: (index, modelData, mouseX, mouseY) => { resultsContainer.itemRightClicked(index, modelData, mouseX, mouseY); } onKeyboardNavigationReset: () => { - if (appLauncher) - appLauncher.keyboardNavigationActive = false - } + if (appLauncher) + appLauncher.keyboardNavigationActive = false; + } delegate: AppLauncherGridDelegate { gridView: resultsGrid cellWidth: resultsGrid.cellWidth cellHeight: resultsGrid.cellHeight - cellPadding: resultsGrid.cellPadding minIconSize: resultsGrid.minIconSize maxIconSize: resultsGrid.maxIconSize iconSizeRatio: resultsGrid.iconSizeRatio @@ -214,7 +220,7 @@ Rectangle { currentIndex: resultsGrid.currentIndex onItemClicked: (idx, modelData) => resultsGrid.itemClicked(idx, modelData) onItemRightClicked: (idx, modelData, mouseX, mouseY) => { - resultsGrid.itemRightClicked(idx, modelData, mouseX, mouseY) + resultsGrid.itemRightClicked(idx, modelData, mouseX, mouseY); } onKeyboardNavigationReset: resultsGrid.keyboardNavigationReset } diff --git a/quickshell/Modules/AppDrawer/AppDrawerPopout.qml b/quickshell/Modules/AppDrawer/AppDrawerPopout.qml index ff0b7c19..5c253734 100644 --- a/quickshell/Modules/AppDrawer/AppDrawerPopout.qml +++ b/quickshell/Modules/AppDrawer/AppDrawerPopout.qml @@ -252,18 +252,19 @@ DankPopout { } } - Row { - width: parent.width + Item { + width: parent.width - Theme.spacingS * 2 height: 40 - spacing: Theme.spacingM + anchors.horizontalCenter: parent.horizontalCenter visible: searchField.text.length === 0 - leftPadding: Theme.spacingS Rectangle { width: 180 height: 40 radius: Theme.cornerRadius color: "transparent" + anchors.left: parent.left + anchors.verticalCenter: parent.verticalCenter DankDropdown { anchors.fill: parent @@ -278,13 +279,9 @@ DankPopout { } } - Item { - width: parent.width - 290 - height: 1 - } - Row { spacing: 4 + anchors.right: parent.right anchors.verticalCenter: parent.verticalCenter DankActionButton { @@ -314,7 +311,8 @@ DankPopout { } Rectangle { - width: parent.width + width: searchField.width + x: searchField.x height: { let usedHeight = 40 + Theme.spacingS; usedHeight += 52 + Theme.spacingS; @@ -350,8 +348,6 @@ DankPopout { } anchors.fill: parent - anchors.leftMargin: Theme.spacingS - anchors.rightMargin: Theme.spacingS anchors.bottomMargin: Theme.spacingS visible: appLauncher.viewMode === "list" model: appLauncher.model @@ -410,14 +406,13 @@ DankPopout { property bool adaptiveColumns: false property int minCellWidth: 120 property int maxCellWidth: 160 - property int cellPadding: 8 property real iconSizeRatio: 0.6 property int maxIconSize: 56 property int minIconSize: 32 property bool hoverUpdatesSelection: false property bool keyboardNavigationActive: appLauncher.keyboardNavigationActive - property int baseCellWidth: adaptiveColumns ? Math.max(minCellWidth, Math.min(maxCellWidth, width / columns)) : (width - Theme.spacingS * 2) / columns - property int baseCellHeight: baseCellWidth + 20 + property real baseCellWidth: adaptiveColumns ? Math.max(minCellWidth, Math.min(maxCellWidth, width / columns)) : width / columns + property real baseCellHeight: baseCellWidth + 20 property int actualColumns: adaptiveColumns ? Math.floor(width / cellWidth) : columns property int remainingSpace: width - (actualColumns * cellWidth) @@ -438,16 +433,12 @@ DankPopout { } anchors.fill: parent - anchors.leftMargin: Theme.spacingS - anchors.rightMargin: Theme.spacingS anchors.bottomMargin: Theme.spacingS visible: appLauncher.viewMode === "grid" model: appLauncher.model clip: true cellWidth: baseCellWidth cellHeight: baseCellHeight - leftMargin: Math.max(Theme.spacingS, remainingSpace / 2) - rightMargin: leftMargin focus: true interactive: true cacheBuffer: Math.max(0, Math.min(height * 2, 1000)) @@ -472,7 +463,6 @@ DankPopout { gridView: appGrid cellWidth: appGrid.cellWidth cellHeight: appGrid.cellHeight - cellPadding: appGrid.cellPadding minIconSize: appGrid.minIconSize maxIconSize: appGrid.maxIconSize iconSizeRatio: appGrid.iconSizeRatio diff --git a/quickshell/Widgets/AppLauncherGridDelegate.qml b/quickshell/Widgets/AppLauncherGridDelegate.qml index bf6a3b5d..a5b96ce0 100644 --- a/quickshell/Widgets/AppLauncherGridDelegate.qml +++ b/quickshell/Widgets/AppLauncherGridDelegate.qml @@ -1,6 +1,4 @@ import QtQuick -import QtQuick.Controls -import Quickshell import qs.Common import qs.Widgets @@ -12,7 +10,6 @@ Rectangle { required property var gridView property int cellWidth: 120 property int cellHeight: 120 - property int cellPadding: 8 property int minIconSize: 32 property int maxIconSize: 64 property real iconSizeRatio: 0.5 @@ -31,10 +28,10 @@ Rectangle { signal itemClicked(int index, var modelData) signal itemRightClicked(int index, var modelData, real mouseX, real mouseY) - signal keyboardNavigationReset() + signal keyboardNavigationReset - width: cellWidth - cellPadding - height: cellHeight - cellPadding + width: cellWidth + height: cellHeight radius: Theme.cornerRadius color: currentIndex === index ? Theme.withAlpha(Theme.surfaceContainerHighest, Theme.popupTransparency) : mouseArea.containsMouse ? Theme.withAlpha(Theme.surfaceContainerHighest, Theme.popupTransparency) : "transparent" @@ -87,27 +84,27 @@ Rectangle { z: 10 onEntered: { if (root.hoverUpdatesSelection && !root.keyboardNavigationActive) - root.gridView.currentIndex = root.index + root.gridView.currentIndex = root.index; } onPositionChanged: { - root.keyboardNavigationReset() + root.keyboardNavigationReset(); } onClicked: mouse => { if (mouse.button === Qt.LeftButton) { - root.itemClicked(root.index, root.model) + root.itemClicked(root.index, root.model); } } onPressAndHold: mouse => { if (!root.isPlugin) { - const globalPos = mapToItem(null, mouse.x, mouse.y) - root.itemRightClicked(root.index, root.model, globalPos.x, globalPos.y) + const globalPos = mapToItem(null, mouse.x, mouse.y); + root.itemRightClicked(root.index, root.model, globalPos.x, globalPos.y); } } onPressed: mouse => { if (mouse.button === Qt.RightButton && !root.isPlugin) { - const globalPos = mapToItem(null, mouse.x, mouse.y) - root.itemRightClicked(root.index, root.model, globalPos.x, globalPos.y) - mouse.accepted = true + const globalPos = mapToItem(null, mouse.x, mouse.y); + root.itemRightClicked(root.index, root.model, globalPos.x, globalPos.y); + mouse.accepted = true; } } }