1
0
mirror of https://github.com/AvengeMedia/DankMaterialShell.git synced 2025-12-05 21:15:38 -05:00

launcher: consistent spacing of grid mode

This commit is contained in:
bbedward
2025-12-01 09:31:57 -05:00
parent bcd9ece077
commit 25951ddc55
4 changed files with 224 additions and 219 deletions

View File

@@ -152,7 +152,7 @@ Item {
if (searchMode === "apps" && appLauncher.model.count > 0) { if (searchMode === "apps" && appLauncher.model.count > 0) {
const selectedApp = appLauncher.model.get(appLauncher.selectedIndex); const selectedApp = appLauncher.model.get(appLauncher.selectedIndex);
const menu = usePopupContextMenu ? popupContextMenu : layerContextMenuLoader.item; const menu = usePopupContextMenu ? popupContextMenu : layerContextMenuLoader.item;
if (selectedApp && menu && resultsView) { if (selectedApp && menu && resultsView) {
const itemPos = resultsView.getSelectedItemPosition(); const itemPos = resultsView.getSelectedItemPosition();
const contentPos = resultsView.mapToItem(spotlightKeyHandler, itemPos.x, itemPos.y); const contentPos = resultsView.mapToItem(spotlightKeyHandler, itemPos.x, itemPos.y);
@@ -192,10 +192,9 @@ Item {
} }
} }
SpotlightContextMenuPopup { SpotlightContextMenuPopup {
id: popupContextMenu id: popupContextMenu
parent: spotlightKeyHandler parent: spotlightKeyHandler
appLauncher: spotlightKeyHandler.appLauncher appLauncher: spotlightKeyHandler.appLauncher
parentHandler: spotlightKeyHandler parentHandler: spotlightKeyHandler
@@ -203,7 +202,7 @@ Item {
visible: false visible: false
z: 1000 z: 1000
} }
MouseArea { MouseArea {
anchors.fill: parent anchors.fill: parent
visible: usePopupContextMenu && popupContextMenu.visible visible: usePopupContextMenu && popupContextMenu.visible
@@ -211,7 +210,7 @@ Item {
z: 999 z: 999
onClicked: popupContextMenu.hide() onClicked: popupContextMenu.hide()
} }
Loader { Loader {
id: layerContextMenuLoader id: layerContextMenuLoader
active: !spotlightKeyHandler.usePopupContextMenu active: !spotlightKeyHandler.usePopupContextMenu
@@ -224,7 +223,7 @@ Item {
} }
} }
} }
Connections { Connections {
target: parentModal target: parentModal
function onSpotlightOpenChanged() { function onSpotlightOpenChanged() {
@@ -244,16 +243,17 @@ Item {
spacing: Theme.spacingM spacing: Theme.spacingM
clip: false clip: false
Row { Item {
width: parent.width id: searchRow
spacing: Theme.spacingM width: parent.width - Theme.spacingS * 2
leftPadding: Theme.spacingS height: 56
topPadding: Theme.spacingS anchors.horizontalCenter: parent.horizontalCenter
DankTextField { DankTextField {
id: searchField id: searchField
anchors.left: parent.left
width: parent.width - 80 - Theme.spacingL anchors.right: buttonsContainer.left
anchors.rightMargin: Theme.spacingM
height: 56 height: 56
cornerRadius: Theme.cornerRadius cornerRadius: Theme.cornerRadius
backgroundColor: Theme.withAlpha(Theme.surfaceContainerHigh, Theme.popupTransparency) backgroundColor: Theme.withAlpha(Theme.surfaceContainerHigh, Theme.popupTransparency)
@@ -302,147 +302,159 @@ Item {
} }
} }
Row { Item {
spacing: Theme.spacingXS id: buttonsContainer
visible: searchMode === "apps" && appLauncher.model.count > 0 width: viewModeButtons.visible ? viewModeButtons.width : (fileSearchButtons.visible ? fileSearchButtons.width : 0)
height: 36
anchors.right: parent.right
anchors.verticalCenter: parent.verticalCenter anchors.verticalCenter: parent.verticalCenter
Rectangle { Row {
width: 36 id: viewModeButtons
height: 36 spacing: Theme.spacingXS
radius: Theme.cornerRadius visible: searchMode === "apps" && appLauncher.model.count > 0
color: appLauncher.viewMode === "list" ? Theme.primaryHover : listViewArea.containsMouse ? Theme.surfaceHover : "transparent" anchors.right: parent.right
anchors.verticalCenter: parent.verticalCenter
DankIcon { Rectangle {
anchors.centerIn: parent width: 36
name: "view_list" height: 36
size: 18 radius: Theme.cornerRadius
color: appLauncher.viewMode === "list" ? Theme.primary : Theme.surfaceText 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 { Rectangle {
id: listViewArea width: 36
height: 36
radius: Theme.cornerRadius
color: appLauncher.viewMode === "grid" ? Theme.primaryHover : gridViewArea.containsMouse ? Theme.surfaceHover : "transparent"
anchors.fill: parent DankIcon {
hoverEnabled: true anchors.centerIn: parent
cursorShape: Qt.PointingHandCursor name: "grid_view"
onClicked: () => { size: 18
appLauncher.setViewMode("list"); color: appLauncher.viewMode === "grid" ? Theme.primary : Theme.surfaceText
}
MouseArea {
id: gridViewArea
anchors.fill: parent
hoverEnabled: true
cursorShape: Qt.PointingHandCursor
onClicked: () => {
appLauncher.setViewMode("grid");
}
} }
} }
} }
Rectangle { Row {
width: 36 id: fileSearchButtons
height: 36 spacing: Theme.spacingXS
radius: Theme.cornerRadius visible: searchMode === "files"
color: appLauncher.viewMode === "grid" ? Theme.primaryHover : gridViewArea.containsMouse ? Theme.surfaceHover : "transparent" anchors.right: parent.right
anchors.verticalCenter: parent.verticalCenter
DankIcon { Rectangle {
anchors.centerIn: parent id: filenameFilterButton
name: "grid_view"
size: 18
color: appLauncher.viewMode === "grid" ? Theme.primary : Theme.surfaceText
}
MouseArea { width: 36
id: gridViewArea height: 36
radius: Theme.cornerRadius
color: fileSearchController.searchField === "filename" ? Theme.primaryHover : filenameFilterArea.containsMouse ? Theme.surfaceHover : "transparent"
anchors.fill: parent DankIcon {
hoverEnabled: true anchors.centerIn: parent
cursorShape: Qt.PointingHandCursor name: "title"
onClicked: () => { size: 18
appLauncher.setViewMode("grid"); 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 { Rectangle {
spacing: Theme.spacingXS id: contentFilterButton
visible: searchMode === "files"
anchors.verticalCenter: parent.verticalCenter
Rectangle { width: 36
id: filenameFilterButton height: 36
radius: Theme.cornerRadius
color: fileSearchController.searchField === "body" ? Theme.primaryHover : contentFilterArea.containsMouse ? Theme.surfaceHover : "transparent"
width: 36 DankIcon {
height: 36 anchors.centerIn: parent
radius: Theme.cornerRadius name: "description"
color: fileSearchController.searchField === "filename" ? Theme.primaryHover : filenameFilterArea.containsMouse ? Theme.surfaceHover : "transparent" size: 18
color: fileSearchController.searchField === "body" ? Theme.primary : Theme.surfaceText
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; MouseArea {
} id: contentFilterArea
}
}
Rectangle { anchors.fill: parent
id: contentFilterButton 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 contentTooltipLoader.active = false;
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;
} }
} }
} }
@@ -458,13 +470,13 @@ Item {
anchors.fill: parent anchors.fill: parent
appLauncher: spotlightKeyHandler.appLauncher appLauncher: spotlightKeyHandler.appLauncher
visible: searchMode === "apps" visible: searchMode === "apps"
onItemRightClicked: (index, modelData, mouseX, mouseY) => { onItemRightClicked: (index, modelData, mouseX, mouseY) => {
const menu = usePopupContextMenu ? popupContextMenu : layerContextMenuLoader.item; const menu = usePopupContextMenu ? popupContextMenu : layerContextMenuLoader.item;
if (menu?.show) { if (menu?.show) {
const isPopup = menu.contentItem !== undefined; const isPopup = menu.contentItem !== undefined;
if (isPopup) { if (isPopup) {
const localPos = popupContextMenu.parent.mapFromItem(null, mouseX, mouseY); const localPos = popupContextMenu.parent.mapFromItem(null, mouseX, mouseY);
menu.show(localPos.x, localPos.y, modelData, false); menu.show(localPos.x, localPos.y, modelData, false);

View File

@@ -1,6 +1,4 @@
import QtQuick import QtQuick
import Quickshell
import Quickshell.Widgets
import qs.Common import qs.Common
import qs.Widgets import qs.Widgets
@@ -8,32 +6,45 @@ Rectangle {
id: resultsContainer id: resultsContainer
property var appLauncher: null property var appLauncher: null
signal itemRightClicked(int index, var modelData, real mouseX, real mouseY) signal itemRightClicked(int index, var modelData, real mouseX, real mouseY)
function resetScroll() { function resetScroll() {
resultsList.contentY = 0 resultsList.contentY = 0;
if (gridLoader.item) { if (gridLoader.item) {
gridLoader.item.contentY = 0 gridLoader.item.contentY = 0;
} }
} }
function getSelectedItemPosition() { function getSelectedItemPosition() {
if (!appLauncher) return { x: 0, y: 0 }; if (!appLauncher)
return {
x: 0,
y: 0
};
const selectedIndex = appLauncher.selectedIndex; const selectedIndex = appLauncher.selectedIndex;
if (appLauncher.viewMode === "list") { if (appLauncher.viewMode === "list") {
const itemY = selectedIndex * (resultsList.itemHeight + resultsList.itemSpacing) - resultsList.contentY; 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) { } else if (gridLoader.item) {
const grid = gridLoader.item; const grid = gridLoader.item;
const row = Math.floor(selectedIndex / grid.actualColumns); const row = Math.floor(selectedIndex / grid.actualColumns);
const col = selectedIndex % grid.actualColumns; const col = selectedIndex % grid.actualColumns;
const itemX = col * grid.cellWidth + grid.leftMargin + grid.cellWidth / 2; const itemX = col * grid.cellWidth + grid.leftMargin + grid.cellWidth / 2;
const itemY = row * grid.cellHeight - grid.contentY + grid.cellHeight / 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 radius: Theme.cornerRadius
@@ -56,14 +67,13 @@ Rectangle {
function ensureVisible(index) { function ensureVisible(index) {
if (index < 0 || index >= count) if (index < 0 || index >= count)
return return;
const itemY = index * (itemHeight + itemSpacing);
const itemY = index * (itemHeight + itemSpacing) const itemBottom = itemY + itemHeight;
const itemBottom = itemY + itemHeight
if (itemY < contentY) if (itemY < contentY)
contentY = itemY contentY = itemY;
else if (itemBottom > contentY + height) else if (itemBottom > contentY + height)
contentY = itemBottom - height contentY = itemBottom - height;
} }
anchors.fill: parent anchors.fill: parent
@@ -79,19 +89,19 @@ Rectangle {
reuseItems: true reuseItems: true
onCurrentIndexChanged: { onCurrentIndexChanged: {
if (keyboardNavigationActive) if (keyboardNavigationActive)
ensureVisible(currentIndex) ensureVisible(currentIndex);
} }
onItemClicked: (index, modelData) => { onItemClicked: (index, modelData) => {
if (appLauncher) if (appLauncher)
appLauncher.launchApp(modelData) appLauncher.launchApp(modelData);
} }
onItemRightClicked: (index, modelData, mouseX, mouseY) => { onItemRightClicked: (index, modelData, mouseX, mouseY) => {
resultsContainer.itemRightClicked(index, modelData, mouseX, mouseY); resultsContainer.itemRightClicked(index, modelData, mouseX, mouseY);
} }
onKeyboardNavigationReset: () => { onKeyboardNavigationReset: () => {
if (appLauncher) if (appLauncher)
appLauncher.keyboardNavigationActive = false appLauncher.keyboardNavigationActive = false;
} }
delegate: AppLauncherListDelegate { delegate: AppLauncherListDelegate {
listView: resultsList listView: resultsList
@@ -105,7 +115,7 @@ Rectangle {
iconUnicodeScale: 0.8 iconUnicodeScale: 0.8
onItemClicked: (idx, modelData) => resultsList.itemClicked(idx, modelData) onItemClicked: (idx, modelData) => resultsList.itemClicked(idx, modelData)
onItemRightClicked: (idx, modelData, mouseX, mouseY) => { onItemRightClicked: (idx, modelData, mouseX, mouseY) => {
resultsList.itemRightClicked(idx, modelData, mouseX, mouseY) resultsList.itemRightClicked(idx, modelData, mouseX, mouseY);
} }
onKeyboardNavigationReset: resultsList.keyboardNavigationReset onKeyboardNavigationReset: resultsList.keyboardNavigationReset
} }
@@ -121,20 +131,20 @@ Rectangle {
visible: appLauncher && appLauncher.viewMode === "grid" visible: appLauncher && appLauncher.viewMode === "grid"
active: appLauncher && appLauncher.viewMode === "grid" active: appLauncher && appLauncher.viewMode === "grid"
asynchronous: false asynchronous: false
onLoaded: { onLoaded: {
if (item) { if (item) {
item.appLauncher = Qt.binding(() => resultsContainer.appLauncher); item.appLauncher = Qt.binding(() => resultsContainer.appLauncher);
} }
} }
onWidthChanged: { onWidthChanged: {
if (visible && Math.abs(width - _lastWidth) > 1) { if (visible && Math.abs(width - _lastWidth) > 1) {
_lastWidth = width _lastWidth = width;
active = false active = false;
Qt.callLater(() => { Qt.callLater(() => {
active = true active = true;
}) });
} }
} }
sourceComponent: Component { sourceComponent: Component {
@@ -148,14 +158,13 @@ Rectangle {
property bool adaptiveColumns: false property bool adaptiveColumns: false
property int minCellWidth: 120 property int minCellWidth: 120
property int maxCellWidth: 160 property int maxCellWidth: 160
property int cellPadding: 8
property real iconSizeRatio: 0.55 property real iconSizeRatio: 0.55
property int maxIconSize: 48 property int maxIconSize: 48
property int minIconSize: 32 property int minIconSize: 32
property bool hoverUpdatesSelection: false property bool hoverUpdatesSelection: false
property bool keyboardNavigationActive: appLauncher ? appLauncher.keyboardNavigationActive : 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 real baseCellWidth: adaptiveColumns ? Math.max(minCellWidth, Math.min(maxCellWidth, width / columns)) : width / columns
property int baseCellHeight: baseCellWidth + 20 property real baseCellHeight: baseCellWidth + 20
property int actualColumns: adaptiveColumns ? Math.floor(width / cellWidth) : columns property int actualColumns: adaptiveColumns ? Math.floor(width / cellWidth) : columns
property int remainingSpace: width - (actualColumns * cellWidth) property int remainingSpace: width - (actualColumns * cellWidth)
@@ -165,47 +174,44 @@ Rectangle {
function ensureVisible(index) { function ensureVisible(index) {
if (index < 0 || index >= count) if (index < 0 || index >= count)
return return;
const itemY = Math.floor(index / actualColumns) * cellHeight;
const itemY = Math.floor(index / actualColumns) * cellHeight const itemBottom = itemY + cellHeight;
const itemBottom = itemY + cellHeight
if (itemY < contentY) if (itemY < contentY)
contentY = itemY contentY = itemY;
else if (itemBottom > contentY + height) else if (itemBottom > contentY + height)
contentY = itemBottom - height contentY = itemBottom - height;
} }
anchors.fill: parent
model: appLauncher ? appLauncher.model : null model: appLauncher ? appLauncher.model : null
clip: true clip: true
cellWidth: baseCellWidth cellWidth: baseCellWidth
cellHeight: baseCellHeight cellHeight: baseCellHeight
leftMargin: Math.max(Theme.spacingS, remainingSpace / 2)
rightMargin: leftMargin
focus: true focus: true
interactive: true interactive: true
cacheBuffer: Math.max(0, Math.min(height * 2, 1000)) cacheBuffer: Math.max(0, Math.min(height * 2, 1000))
reuseItems: true reuseItems: true
onCurrentIndexChanged: { onCurrentIndexChanged: {
if (keyboardNavigationActive) if (keyboardNavigationActive)
ensureVisible(currentIndex) ensureVisible(currentIndex);
} }
onItemClicked: (index, modelData) => { onItemClicked: (index, modelData) => {
if (appLauncher) if (appLauncher)
appLauncher.launchApp(modelData) appLauncher.launchApp(modelData);
} }
onItemRightClicked: (index, modelData, mouseX, mouseY) => { onItemRightClicked: (index, modelData, mouseX, mouseY) => {
resultsContainer.itemRightClicked(index, modelData, mouseX, mouseY); resultsContainer.itemRightClicked(index, modelData, mouseX, mouseY);
} }
onKeyboardNavigationReset: () => { onKeyboardNavigationReset: () => {
if (appLauncher) if (appLauncher)
appLauncher.keyboardNavigationActive = false appLauncher.keyboardNavigationActive = false;
} }
delegate: AppLauncherGridDelegate { delegate: AppLauncherGridDelegate {
gridView: resultsGrid gridView: resultsGrid
cellWidth: resultsGrid.cellWidth cellWidth: resultsGrid.cellWidth
cellHeight: resultsGrid.cellHeight cellHeight: resultsGrid.cellHeight
cellPadding: resultsGrid.cellPadding
minIconSize: resultsGrid.minIconSize minIconSize: resultsGrid.minIconSize
maxIconSize: resultsGrid.maxIconSize maxIconSize: resultsGrid.maxIconSize
iconSizeRatio: resultsGrid.iconSizeRatio iconSizeRatio: resultsGrid.iconSizeRatio
@@ -214,7 +220,7 @@ Rectangle {
currentIndex: resultsGrid.currentIndex currentIndex: resultsGrid.currentIndex
onItemClicked: (idx, modelData) => resultsGrid.itemClicked(idx, modelData) onItemClicked: (idx, modelData) => resultsGrid.itemClicked(idx, modelData)
onItemRightClicked: (idx, modelData, mouseX, mouseY) => { onItemRightClicked: (idx, modelData, mouseX, mouseY) => {
resultsGrid.itemRightClicked(idx, modelData, mouseX, mouseY) resultsGrid.itemRightClicked(idx, modelData, mouseX, mouseY);
} }
onKeyboardNavigationReset: resultsGrid.keyboardNavigationReset onKeyboardNavigationReset: resultsGrid.keyboardNavigationReset
} }

View File

@@ -252,18 +252,19 @@ DankPopout {
} }
} }
Row { Item {
width: parent.width width: parent.width - Theme.spacingS * 2
height: 40 height: 40
spacing: Theme.spacingM anchors.horizontalCenter: parent.horizontalCenter
visible: searchField.text.length === 0 visible: searchField.text.length === 0
leftPadding: Theme.spacingS
Rectangle { Rectangle {
width: 180 width: 180
height: 40 height: 40
radius: Theme.cornerRadius radius: Theme.cornerRadius
color: "transparent" color: "transparent"
anchors.left: parent.left
anchors.verticalCenter: parent.verticalCenter
DankDropdown { DankDropdown {
anchors.fill: parent anchors.fill: parent
@@ -278,13 +279,9 @@ DankPopout {
} }
} }
Item {
width: parent.width - 290
height: 1
}
Row { Row {
spacing: 4 spacing: 4
anchors.right: parent.right
anchors.verticalCenter: parent.verticalCenter anchors.verticalCenter: parent.verticalCenter
DankActionButton { DankActionButton {
@@ -314,7 +311,8 @@ DankPopout {
} }
Rectangle { Rectangle {
width: parent.width width: searchField.width
x: searchField.x
height: { height: {
let usedHeight = 40 + Theme.spacingS; let usedHeight = 40 + Theme.spacingS;
usedHeight += 52 + Theme.spacingS; usedHeight += 52 + Theme.spacingS;
@@ -350,8 +348,6 @@ DankPopout {
} }
anchors.fill: parent anchors.fill: parent
anchors.leftMargin: Theme.spacingS
anchors.rightMargin: Theme.spacingS
anchors.bottomMargin: Theme.spacingS anchors.bottomMargin: Theme.spacingS
visible: appLauncher.viewMode === "list" visible: appLauncher.viewMode === "list"
model: appLauncher.model model: appLauncher.model
@@ -410,14 +406,13 @@ DankPopout {
property bool adaptiveColumns: false property bool adaptiveColumns: false
property int minCellWidth: 120 property int minCellWidth: 120
property int maxCellWidth: 160 property int maxCellWidth: 160
property int cellPadding: 8
property real iconSizeRatio: 0.6 property real iconSizeRatio: 0.6
property int maxIconSize: 56 property int maxIconSize: 56
property int minIconSize: 32 property int minIconSize: 32
property bool hoverUpdatesSelection: false property bool hoverUpdatesSelection: false
property bool keyboardNavigationActive: appLauncher.keyboardNavigationActive property bool keyboardNavigationActive: appLauncher.keyboardNavigationActive
property int baseCellWidth: adaptiveColumns ? Math.max(minCellWidth, Math.min(maxCellWidth, width / columns)) : (width - Theme.spacingS * 2) / columns property real baseCellWidth: adaptiveColumns ? Math.max(minCellWidth, Math.min(maxCellWidth, width / columns)) : width / columns
property int baseCellHeight: baseCellWidth + 20 property real baseCellHeight: baseCellWidth + 20
property int actualColumns: adaptiveColumns ? Math.floor(width / cellWidth) : columns property int actualColumns: adaptiveColumns ? Math.floor(width / cellWidth) : columns
property int remainingSpace: width - (actualColumns * cellWidth) property int remainingSpace: width - (actualColumns * cellWidth)
@@ -438,16 +433,12 @@ DankPopout {
} }
anchors.fill: parent anchors.fill: parent
anchors.leftMargin: Theme.spacingS
anchors.rightMargin: Theme.spacingS
anchors.bottomMargin: Theme.spacingS anchors.bottomMargin: Theme.spacingS
visible: appLauncher.viewMode === "grid" visible: appLauncher.viewMode === "grid"
model: appLauncher.model model: appLauncher.model
clip: true clip: true
cellWidth: baseCellWidth cellWidth: baseCellWidth
cellHeight: baseCellHeight cellHeight: baseCellHeight
leftMargin: Math.max(Theme.spacingS, remainingSpace / 2)
rightMargin: leftMargin
focus: true focus: true
interactive: true interactive: true
cacheBuffer: Math.max(0, Math.min(height * 2, 1000)) cacheBuffer: Math.max(0, Math.min(height * 2, 1000))
@@ -472,7 +463,6 @@ DankPopout {
gridView: appGrid gridView: appGrid
cellWidth: appGrid.cellWidth cellWidth: appGrid.cellWidth
cellHeight: appGrid.cellHeight cellHeight: appGrid.cellHeight
cellPadding: appGrid.cellPadding
minIconSize: appGrid.minIconSize minIconSize: appGrid.minIconSize
maxIconSize: appGrid.maxIconSize maxIconSize: appGrid.maxIconSize
iconSizeRatio: appGrid.iconSizeRatio iconSizeRatio: appGrid.iconSizeRatio

View File

@@ -1,6 +1,4 @@
import QtQuick import QtQuick
import QtQuick.Controls
import Quickshell
import qs.Common import qs.Common
import qs.Widgets import qs.Widgets
@@ -12,7 +10,6 @@ Rectangle {
required property var gridView required property var gridView
property int cellWidth: 120 property int cellWidth: 120
property int cellHeight: 120 property int cellHeight: 120
property int cellPadding: 8
property int minIconSize: 32 property int minIconSize: 32
property int maxIconSize: 64 property int maxIconSize: 64
property real iconSizeRatio: 0.5 property real iconSizeRatio: 0.5
@@ -31,10 +28,10 @@ Rectangle {
signal itemClicked(int index, var modelData) signal itemClicked(int index, var modelData)
signal itemRightClicked(int index, var modelData, real mouseX, real mouseY) signal itemRightClicked(int index, var modelData, real mouseX, real mouseY)
signal keyboardNavigationReset() signal keyboardNavigationReset
width: cellWidth - cellPadding width: cellWidth
height: cellHeight - cellPadding height: cellHeight
radius: Theme.cornerRadius radius: Theme.cornerRadius
color: currentIndex === index ? Theme.withAlpha(Theme.surfaceContainerHighest, Theme.popupTransparency) : mouseArea.containsMouse ? Theme.withAlpha(Theme.surfaceContainerHighest, Theme.popupTransparency) : "transparent" 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 z: 10
onEntered: { onEntered: {
if (root.hoverUpdatesSelection && !root.keyboardNavigationActive) if (root.hoverUpdatesSelection && !root.keyboardNavigationActive)
root.gridView.currentIndex = root.index root.gridView.currentIndex = root.index;
} }
onPositionChanged: { onPositionChanged: {
root.keyboardNavigationReset() root.keyboardNavigationReset();
} }
onClicked: mouse => { onClicked: mouse => {
if (mouse.button === Qt.LeftButton) { if (mouse.button === Qt.LeftButton) {
root.itemClicked(root.index, root.model) root.itemClicked(root.index, root.model);
} }
} }
onPressAndHold: mouse => { onPressAndHold: mouse => {
if (!root.isPlugin) { if (!root.isPlugin) {
const globalPos = mapToItem(null, mouse.x, mouse.y) const globalPos = mapToItem(null, mouse.x, mouse.y);
root.itemRightClicked(root.index, root.model, globalPos.x, globalPos.y) root.itemRightClicked(root.index, root.model, globalPos.x, globalPos.y);
} }
} }
onPressed: mouse => { onPressed: mouse => {
if (mouse.button === Qt.RightButton && !root.isPlugin) { if (mouse.button === Qt.RightButton && !root.isPlugin) {
const globalPos = mapToItem(null, mouse.x, mouse.y) const globalPos = mapToItem(null, mouse.x, mouse.y);
root.itemRightClicked(root.index, root.model, globalPos.x, globalPos.y) root.itemRightClicked(root.index, root.model, globalPos.x, globalPos.y);
mouse.accepted = true mouse.accepted = true;
} }
} }
} }