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

@@ -192,7 +192,6 @@ Item {
} }
} }
SpotlightContextMenuPopup { SpotlightContextMenuPopup {
id: popupContextMenu id: popupContextMenu
@@ -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,9 +302,18 @@ Item {
} }
} }
Item {
id: buttonsContainer
width: viewModeButtons.visible ? viewModeButtons.width : (fileSearchButtons.visible ? fileSearchButtons.width : 0)
height: 36
anchors.right: parent.right
anchors.verticalCenter: parent.verticalCenter
Row { Row {
id: viewModeButtons
spacing: Theme.spacingXS spacing: Theme.spacingXS
visible: searchMode === "apps" && appLauncher.model.count > 0 visible: searchMode === "apps" && appLauncher.model.count > 0
anchors.right: parent.right
anchors.verticalCenter: parent.verticalCenter anchors.verticalCenter: parent.verticalCenter
Rectangle { Rectangle {
@@ -359,8 +368,10 @@ Item {
} }
Row { Row {
id: fileSearchButtons
spacing: Theme.spacingXS spacing: Theme.spacingXS
visible: searchMode === "files" visible: searchMode === "files"
anchors.right: parent.right
anchors.verticalCenter: parent.verticalCenter anchors.verticalCenter: parent.verticalCenter
Rectangle { Rectangle {
@@ -448,6 +459,7 @@ Item {
} }
} }
} }
}
Item { Item {
width: parent.width width: parent.width

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
@@ -12,28 +10,41 @@ Rectangle {
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,18 +89,18 @@ 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 {
@@ -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
} }
@@ -130,11 +140,11 @@ Rectangle {
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;
} }
} }
} }