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

Scroll bars and fix position

This commit is contained in:
bbedward
2025-07-10 20:19:10 -04:00
parent 052e47614b
commit cf1f610eff
2 changed files with 220 additions and 233 deletions

View File

@@ -7,6 +7,7 @@ import Quickshell.Wayland
import Quickshell.Io
import "../Common"
// Fixed version icon loaders now swap to fallback components instead of showing the magenta checkerboard
PanelWindow {
id: launcher
@@ -241,6 +242,54 @@ PanelWindow {
})
}
/* ----------------------------------------------------------------------------
* LOADER UTILITIES
* ---------------------------------------------------------------------------- */
/** Returns an IconImage component or the fallback badge depending on availability. */
function makeIconLoader(iconName, appName, fallbackId) {
return Qt.createComponent("", {
"anchors.fill": parent,
"_iconName": iconName,
"_appName": appName,
"sourceComponent": iconComponent
})
}
Component {
id: iconComponent
IconImage {
id: img
anchors.fill: parent
source: _iconName ? Quickshell.iconPath(_iconName, "") : ""
smooth: true
asynchronous: true
onStatusChanged: {
if (status === Image.Error || status === Image.Null || !source) {
// defer the swap to avoid reentrancy in Loader
Qt.callLater(() => img.parent.sourceComponent = fallbackComponent)
}
}
}
}
Component {
id: fallbackComponent
Rectangle {
color: Qt.rgba(activeTheme.primary.r, activeTheme.primary.g, activeTheme.primary.b, 0.10)
radius: activeTheme.cornerRadiusLarge
border.width: 1
border.color: Qt.rgba(activeTheme.primary.r, activeTheme.primary.g, activeTheme.primary.b, 0.20)
Text {
anchors.centerIn: parent
text: _appName ? _appName.charAt(0).toUpperCase() : "A"
font.pixelSize: 28
color: activeTheme.primary
font.weight: Font.Bold
}
}
}
// Main launcher panel with enhanced design
Rectangle {
id: launcherPanel
@@ -607,244 +656,53 @@ PanelWindow {
height: parent.height - searchContainer.height - (searchField.text.length === 0 ? 128 : 60) - parent.spacing * 3
color: "transparent"
// List view scroll container
ScrollView {
anchors.fill: parent
clip: true
visible: viewMode === "list"
ScrollBar.vertical.policy: ScrollBar.AsNeeded
ScrollBar.horizontal.policy: ScrollBar.AlwaysOff
Item {
anchors.fill: parent
ListView {
id: appList
width: parent.width
anchors.margins: activeTheme.spacingS
spacing: activeTheme.spacingS
// List view
ListView {
id: appList
anchors.fill: parent
anchors.margins: activeTheme.spacingS
spacing: activeTheme.spacingS
visible: viewMode === "list"
model: filteredModel
delegate: Rectangle {
width: appList.width
height: 72
radius: activeTheme.cornerRadiusLarge
color: appMouseArea.hovered ?
Qt.rgba(activeTheme.primary.r, activeTheme.primary.g, activeTheme.primary.b, 0.08) :
Qt.rgba(activeTheme.surfaceVariant.r, activeTheme.surfaceVariant.g, activeTheme.surfaceVariant.b, 0.03)
border.color: Qt.rgba(activeTheme.outline.r, activeTheme.outline.g, activeTheme.outline.b, 0.08)
border.width: 1
Behavior on color {
ColorAnimation {
duration: activeTheme.shortDuration
easing.type: activeTheme.standardEasing
}
}
Row {
anchors.fill: parent
anchors.margins: activeTheme.spacingM
spacing: activeTheme.spacingL
Item {
width: 56
height: 56
anchors.verticalCenter: parent.verticalCenter
Loader {
anchors.fill: parent
sourceComponent: model.icon ? iconComponent : fallbackComponent
Component {
id: iconComponent
IconImage {
source: model.icon ? Quickshell.iconPath(model.icon) : ""
smooth: true
asynchronous: true
onStatusChanged: {
if (status === Image.Error || status === Image.Null) {
parent.sourceComponent = fallbackComponent
}
}
}
}
Component {
id: fallbackComponent
Rectangle {
color: Qt.rgba(activeTheme.primary.r, activeTheme.primary.g, activeTheme.primary.b, 0.1)
radius: activeTheme.cornerRadiusLarge
border.width: 1
border.color: Qt.rgba(activeTheme.primary.r, activeTheme.primary.g, activeTheme.primary.b, 0.2)
Text {
anchors.centerIn: parent
text: model.name ? model.name.charAt(0).toUpperCase() : "A"
font.pixelSize: 28
color: activeTheme.primary
font.weight: Font.Bold
}
}
}
}
}
Column {
anchors.verticalCenter: parent.verticalCenter
width: parent.width - 56 - activeTheme.spacingL
spacing: activeTheme.spacingXS
Text {
width: parent.width
text: model.name
font.pixelSize: activeTheme.fontSizeLarge
color: activeTheme.surfaceText
font.weight: Font.Medium
elide: Text.ElideRight
}
Text {
width: parent.width
text: model.comment || "Application"
font.pixelSize: activeTheme.fontSizeMedium
color: activeTheme.surfaceVariantText
elide: Text.ElideRight
visible: model.comment && model.comment.length > 0
}
}
}
MouseArea {
id: appMouseArea
anchors.fill: parent
hoverEnabled: true
cursorShape: Qt.PointingHandCursor
onClicked: {
launcher.launchApp(model.exec)
launcher.hide()
}
}
}
}
model: filteredModel
delegate: listDelegate
}
}
// Grid view scroll container
ScrollView {
anchors.fill: parent
clip: true
visible: viewMode === "grid"
ScrollBar.vertical.policy: ScrollBar.AsNeeded
ScrollBar.horizontal.policy: ScrollBar.AlwaysOff
GridView {
id: appGrid
width: parent.width
anchors.margins: activeTheme.spacingS
// Grid view
GridView {
id: appGrid
anchors.fill: parent
anchors.margins: activeTheme.spacingS
// Responsive cell sizes based on screen width
property int baseCellWidth: Math.max(100, Math.min(140, width / 8))
property int baseCellHeight: baseCellWidth + 20
cellWidth: baseCellWidth
cellHeight: baseCellHeight
visible: viewMode === "grid"
// Center the grid content
property int columnsCount: Math.floor(width / cellWidth)
property int remainingSpace: width - (columnsCount * cellWidth)
leftMargin: Math.max(activeTheme.spacingS, remainingSpace / 2)
rightMargin: leftMargin
model: filteredModel
delegate: Rectangle {
width: appGrid.cellWidth - 8
height: appGrid.cellHeight - 8
radius: activeTheme.cornerRadiusLarge
color: gridAppArea.hovered ? Qt.rgba(activeTheme.primary.r, activeTheme.primary.g, activeTheme.primary.b, 0.08) :
Qt.rgba(activeTheme.surfaceVariant.r, activeTheme.surfaceVariant.g, activeTheme.surfaceVariant.b, 0.03)
border.color: Qt.rgba(activeTheme.outline.r, activeTheme.outline.g, activeTheme.outline.b, 0.08)
border.width: 1
Behavior on color {
ColorAnimation {
duration: activeTheme.shortDuration
easing.type: activeTheme.standardEasing
}
}
Column {
anchors.centerIn: parent
spacing: activeTheme.spacingS
Item {
property int iconSize: Math.min(56, Math.max(32, appGrid.cellWidth * 0.6))
width: iconSize
height: iconSize
anchors.horizontalCenter: parent.horizontalCenter
Loader {
anchors.fill: parent
sourceComponent: model.icon ? gridIconComponent : gridFallbackComponent
Component {
id: gridIconComponent
IconImage {
source: model.icon ? Quickshell.iconPath(model.icon) : ""
smooth: true
asynchronous: true
onStatusChanged: {
if (status === Image.Error || status === Image.Null) {
parent.sourceComponent = gridFallbackComponent
}
}
}
}
Component {
id: gridFallbackComponent
Rectangle {
color: Qt.rgba(activeTheme.primary.r, activeTheme.primary.g, activeTheme.primary.b, 0.1)
radius: activeTheme.cornerRadiusLarge
border.width: 1
border.color: Qt.rgba(activeTheme.primary.r, activeTheme.primary.g, activeTheme.primary.b, 0.2)
Text {
anchors.centerIn: parent
text: model.name ? model.name.charAt(0).toUpperCase() : "A"
font.pixelSize: parent.parent.parent.iconSize / 2
color: activeTheme.primary
font.weight: Font.Bold
}
}
}
}
}
Text {
anchors.horizontalCenter: parent.horizontalCenter
width: 88
text: model.name
font.pixelSize: activeTheme.fontSizeSmall
color: activeTheme.surfaceText
font.weight: Font.Medium
elide: Text.ElideRight
horizontalAlignment: Text.AlignHCenter
maximumLineCount: 2
wrapMode: Text.WordWrap
}
}
MouseArea {
id: gridAppArea
anchors.fill: parent
hoverEnabled: true
cursorShape: Qt.PointingHandCursor
onClicked: {
launcher.launchApp(model.exec)
launcher.hide()
}
}
}
}
// Responsive cell sizes based on screen width
property int baseCellWidth: Math.max(100, Math.min(140, width / 8))
property int baseCellHeight: baseCellWidth + 20
cellWidth: baseCellWidth
cellHeight: baseCellHeight
// Center the grid content
property int columnsCount: Math.floor(width / cellWidth)
property int remainingSpace: width - (columnsCount * cellWidth)
leftMargin: Math.max(activeTheme.spacingS, remainingSpace / 2)
rightMargin: leftMargin
model: filteredModel
delegate: gridDelegate
}
}
}
@@ -886,6 +744,8 @@ PanelWindow {
anchors.fill: parent
anchors.margins: activeTheme.spacingS
clip: true
ScrollBar.vertical.policy: ScrollBar.AsNeeded
ScrollBar.horizontal.policy: ScrollBar.AlwaysOff
ListView {
model: categories
@@ -925,6 +785,133 @@ PanelWindow {
}
}
}
// List delegate with new loader
Component {
id: listDelegate
Rectangle {
width: appList.width
height: 72
radius: activeTheme.cornerRadiusLarge
color: appMouseArea.hovered ? Qt.rgba(activeTheme.primary.r, activeTheme.primary.g, activeTheme.primary.b, 0.08)
: Qt.rgba(activeTheme.surfaceVariant.r, activeTheme.surfaceVariant.g, activeTheme.surfaceVariant.b, 0.03)
border.color: Qt.rgba(activeTheme.outline.r, activeTheme.outline.g, activeTheme.outline.b, 0.08)
border.width: 1
Row {
anchors.fill: parent
anchors.margins: activeTheme.spacingM
spacing: activeTheme.spacingL
Item {
width: 56
height: 56
anchors.verticalCenter: parent.verticalCenter
Loader {
id: listIconLoader
anchors.fill: parent
property string _iconName: model.icon
property string _appName: model.name
sourceComponent: iconComponent
}
}
Column {
anchors.verticalCenter: parent.verticalCenter
width: parent.width - 56 - activeTheme.spacingL
spacing: activeTheme.spacingXS
Text {
width: parent.width
text: model.name
font.pixelSize: activeTheme.fontSizeLarge
color: activeTheme.surfaceText
font.weight: Font.Medium
elide: Text.ElideRight
}
Text {
width: parent.width
text: model.comment || "Application"
font.pixelSize: activeTheme.fontSizeMedium
color: activeTheme.surfaceVariantText
elide: Text.ElideRight
visible: model.comment && model.comment.length > 0
}
}
}
MouseArea {
id: appMouseArea
anchors.fill: parent
hoverEnabled: true
cursorShape: Qt.PointingHandCursor
onClicked: {
launcher.launchApp(model.exec)
launcher.hide()
}
}
}
}
// Grid delegate with new loader (uses dynamic icon size)
Component {
id: gridDelegate
Rectangle {
width: appGrid.cellWidth - 8
height: appGrid.cellHeight - 8
radius: activeTheme.cornerRadiusLarge
color: gridAppArea.hovered ? Qt.rgba(activeTheme.primary.r, activeTheme.primary.g, activeTheme.primary.b, 0.08)
: Qt.rgba(activeTheme.surfaceVariant.r, activeTheme.surfaceVariant.g, activeTheme.surfaceVariant.b, 0.03)
border.color: Qt.rgba(activeTheme.outline.r, activeTheme.outline.g, activeTheme.outline.b, 0.08)
border.width: 1
Column {
anchors.centerIn: parent
spacing: activeTheme.spacingS
Item {
property int iconSize: Math.min(56, Math.max(32, appGrid.cellWidth * 0.6))
width: iconSize
height: iconSize
anchors.horizontalCenter: parent.horizontalCenter
Loader {
id: gridIconLoader
anchors.fill: parent
property string _iconName: model.icon
property string _appName: model.name
sourceComponent: iconComponent
}
}
Text {
anchors.horizontalCenter: parent.horizontalCenter
width: 88
text: model.name
font.pixelSize: activeTheme.fontSizeSmall
color: activeTheme.surfaceText
font.weight: Font.Medium
elide: Text.ElideRight
horizontalAlignment: Text.AlignHCenter
maximumLineCount: 2
wrapMode: Text.WordWrap
}
}
MouseArea {
id: gridAppArea
anchors.fill: parent
hoverEnabled: true
cursorShape: Qt.PointingHandCursor
onClicked: {
launcher.launchApp(model.exec)
launcher.hide()
}
}
}
}
Process {
id: appLauncher

View File

@@ -549,7 +549,7 @@ PanelWindow {
root.currentTrayItem = trayItem
// Simple positioning: right side of screen, below the panel
root.trayMenuX = rightSection.x + rightSection.width - 180 - Theme.spacingL
root.trayMenuX = rightSection.x + rightSection.width - 400 - Theme.spacingL
root.trayMenuY = Theme.barHeight + Theme.spacingS
console.log("Showing menu at:", root.trayMenuX, root.trayMenuY)