Merge pull request #6348 from InfeCtlll3/agent/scroll-long-tray-menus
Make long tray menus scrollable
This commit is contained in:
@@ -1,5 +1,6 @@
|
|||||||
import Quickshell
|
import Quickshell
|
||||||
import QtQuick
|
import QtQuick
|
||||||
|
import QtQuick.Controls
|
||||||
import QtQuick.Effects
|
import QtQuick.Effects
|
||||||
import Quickshell.Services.SystemTray
|
import Quickshell.Services.SystemTray
|
||||||
import qs.Commons
|
import qs.Commons
|
||||||
@@ -446,116 +447,129 @@ BarWidget {
|
|||||||
contentWidth: trayMenuPopup.fittedContentWidth(Style.space(232))
|
contentWidth: trayMenuPopup.fittedContentWidth(Style.space(232))
|
||||||
contentHeight: trayMenuPopup.fittedContentHeight(trayMenuColumn.implicitHeight, Style.space(420))
|
contentHeight: trayMenuPopup.fittedContentHeight(trayMenuColumn.implicitHeight, Style.space(420))
|
||||||
|
|
||||||
Column {
|
Flickable {
|
||||||
id: trayMenuColumn
|
id: trayMenuFlick
|
||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
spacing: 0
|
contentWidth: width
|
||||||
|
contentHeight: trayMenuColumn.implicitHeight
|
||||||
|
clip: true
|
||||||
|
boundsBehavior: Flickable.StopAtBounds
|
||||||
|
flickableDirection: Flickable.VerticalFlick
|
||||||
|
interactive: contentHeight > height
|
||||||
|
|
||||||
Repeater {
|
ScrollBar.vertical: ScrollBar { policy: ScrollBar.AsNeeded }
|
||||||
model: trayMenuOpener.children
|
|
||||||
|
|
||||||
delegate: Item {
|
Column {
|
||||||
id: menuRow
|
id: trayMenuColumn
|
||||||
required property var modelData
|
width: trayMenuFlick.width
|
||||||
required property int index
|
spacing: 0
|
||||||
|
|
||||||
readonly property string rowText: String(modelData.text || "")
|
Repeater {
|
||||||
readonly property string activeTitle: root.activeTrayItem ? String(root.activeTrayItem.title || root.activeTrayItem.id || "") : ""
|
model: trayMenuOpener.children
|
||||||
readonly property bool rootTitleEntry: index === 0 && modelData.hasChildren && rowText.toLowerCase() === activeTitle.toLowerCase()
|
|
||||||
readonly property bool leadingSeparator: modelData.isSeparator && index <= 1
|
|
||||||
readonly property bool hiddenRow: rootTitleEntry || leadingSeparator
|
|
||||||
|
|
||||||
visible: !hiddenRow
|
delegate: Item {
|
||||||
width: trayMenuColumn.width
|
id: menuRow
|
||||||
implicitHeight: hiddenRow ? 0 : (modelData.isSeparator ? Style.space(11) : Style.space(30))
|
required property var modelData
|
||||||
opacity: modelData.enabled ? 1.0 : 0.45
|
required property int index
|
||||||
|
|
||||||
Rectangle {
|
readonly property string rowText: String(modelData.text || "")
|
||||||
visible: menuRow.modelData.isSeparator
|
readonly property string activeTitle: root.activeTrayItem ? String(root.activeTrayItem.title || root.activeTrayItem.id || "") : ""
|
||||||
anchors.left: parent.left
|
readonly property bool rootTitleEntry: index === 0 && modelData.hasChildren && rowText.toLowerCase() === activeTitle.toLowerCase()
|
||||||
anchors.leftMargin: Style.space(10)
|
readonly property bool leadingSeparator: modelData.isSeparator && index <= 1
|
||||||
anchors.right: parent.right
|
readonly property bool hiddenRow: rootTitleEntry || leadingSeparator
|
||||||
anchors.rightMargin: Style.space(10)
|
|
||||||
anchors.verticalCenter: parent.verticalCenter
|
|
||||||
height: 1
|
|
||||||
color: Color.popups.border
|
|
||||||
opacity: 0.45
|
|
||||||
}
|
|
||||||
|
|
||||||
Rectangle {
|
visible: !hiddenRow
|
||||||
visible: !menuRow.modelData.isSeparator
|
width: trayMenuColumn.width
|
||||||
anchors.fill: parent
|
implicitHeight: hiddenRow ? 0 : (modelData.isSeparator ? Style.space(11) : Style.space(30))
|
||||||
radius: Math.max(2, Style.cornerRadius)
|
opacity: modelData.enabled ? 1.0 : 0.45
|
||||||
color: rowMouse.containsMouse && menuRow.modelData.enabled ? Style.hoverFillFor(root.foreground, root.foreground) : "transparent"
|
|
||||||
}
|
|
||||||
|
|
||||||
Text {
|
Rectangle {
|
||||||
visible: !menuRow.modelData.isSeparator && menuRow.modelData.buttonType !== QsMenuButtonType.None
|
visible: menuRow.modelData.isSeparator
|
||||||
anchors.verticalCenter: parent.verticalCenter
|
anchors.left: parent.left
|
||||||
anchors.left: parent.left
|
anchors.leftMargin: Style.space(10)
|
||||||
width: Style.space(22)
|
anchors.right: parent.right
|
||||||
horizontalAlignment: Text.AlignHCenter
|
anchors.rightMargin: Style.space(10)
|
||||||
text: menuRow.modelData.checkState === Qt.Checked ? "\uf00c" : ""
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
color: root.foreground
|
height: 1
|
||||||
font.family: root.fontFamily
|
color: Color.popups.border
|
||||||
font.pixelSize: Style.font.bodySmall
|
opacity: 0.45
|
||||||
}
|
}
|
||||||
|
|
||||||
Image {
|
Rectangle {
|
||||||
id: menuIcon
|
visible: !menuRow.modelData.isSeparator
|
||||||
visible: !menuRow.modelData.isSeparator && String(menuRow.modelData.icon || "") !== ""
|
anchors.fill: parent
|
||||||
anchors.verticalCenter: parent.verticalCenter
|
radius: Math.max(2, Style.cornerRadius)
|
||||||
anchors.left: parent.left
|
color: rowMouse.containsMouse && menuRow.modelData.enabled ? Style.hoverFillFor(root.foreground, root.foreground) : "transparent"
|
||||||
anchors.leftMargin: Style.space(24)
|
}
|
||||||
width: Style.space(16)
|
|
||||||
height: Style.space(16)
|
|
||||||
fillMode: Image.PreserveAspectFit
|
|
||||||
// Decode at physical pixels: IconImage uses the logical size,
|
|
||||||
// which leaves PNG icons upscaled and blurry on HiDPI displays.
|
|
||||||
sourceSize.width: width * Screen.devicePixelRatio
|
|
||||||
sourceSize.height: height * Screen.devicePixelRatio
|
|
||||||
source: menuRow.modelData.icon
|
|
||||||
}
|
|
||||||
|
|
||||||
Text {
|
Text {
|
||||||
visible: !menuRow.modelData.isSeparator
|
visible: !menuRow.modelData.isSeparator && menuRow.modelData.buttonType !== QsMenuButtonType.None
|
||||||
anchors.verticalCenter: parent.verticalCenter
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
anchors.left: parent.left
|
anchors.left: parent.left
|
||||||
anchors.leftMargin: menuIcon.visible ? Style.space(46) : Style.space(28)
|
width: Style.space(22)
|
||||||
anchors.right: submenuGlyph.left
|
horizontalAlignment: Text.AlignHCenter
|
||||||
anchors.rightMargin: Style.space(8)
|
text: menuRow.modelData.checkState === Qt.Checked ? "\uf00c" : ""
|
||||||
text: menuRow.rowText
|
color: root.foreground
|
||||||
color: root.foreground
|
font.family: root.fontFamily
|
||||||
font.family: root.fontFamily
|
font.pixelSize: Style.font.bodySmall
|
||||||
font.pixelSize: Style.font.bodySmall
|
}
|
||||||
elide: Text.ElideRight
|
|
||||||
}
|
|
||||||
|
|
||||||
Text {
|
Image {
|
||||||
id: submenuGlyph
|
id: menuIcon
|
||||||
visible: !menuRow.modelData.isSeparator && menuRow.modelData.hasChildren
|
visible: !menuRow.modelData.isSeparator && String(menuRow.modelData.icon || "") !== ""
|
||||||
anchors.verticalCenter: parent.verticalCenter
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
anchors.right: parent.right
|
anchors.left: parent.left
|
||||||
anchors.rightMargin: Style.space(10)
|
anchors.leftMargin: Style.space(24)
|
||||||
text: "\u203a"
|
width: Style.space(16)
|
||||||
color: root.foreground
|
height: Style.space(16)
|
||||||
font.family: root.fontFamily
|
fillMode: Image.PreserveAspectFit
|
||||||
font.pixelSize: Style.font.bodySmall
|
// Decode at physical pixels: IconImage uses the logical size,
|
||||||
}
|
// which leaves PNG icons upscaled and blurry on HiDPI displays.
|
||||||
|
sourceSize.width: width * Screen.devicePixelRatio
|
||||||
|
sourceSize.height: height * Screen.devicePixelRatio
|
||||||
|
source: menuRow.modelData.icon
|
||||||
|
}
|
||||||
|
|
||||||
MouseArea {
|
Text {
|
||||||
id: rowMouse
|
visible: !menuRow.modelData.isSeparator
|
||||||
anchors.fill: parent
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
hoverEnabled: true
|
anchors.left: parent.left
|
||||||
enabled: !menuRow.modelData.isSeparator && menuRow.modelData.enabled
|
anchors.leftMargin: menuIcon.visible ? Style.space(46) : Style.space(28)
|
||||||
cursorShape: enabled ? Qt.PointingHandCursor : Qt.ArrowCursor
|
anchors.right: submenuGlyph.left
|
||||||
onClicked: {
|
anchors.rightMargin: Style.space(8)
|
||||||
if (menuRow.modelData.hasChildren) {
|
text: menuRow.rowText
|
||||||
var point = menuRow.QsWindow.contentItem.mapFromItem(menuRow, menuRow.width, menuRow.height / 2)
|
color: root.foreground
|
||||||
menuRow.modelData.display(menuRow.QsWindow.window, point.x, point.y)
|
font.family: root.fontFamily
|
||||||
} else {
|
font.pixelSize: Style.font.bodySmall
|
||||||
menuRow.modelData.triggered()
|
elide: Text.ElideRight
|
||||||
root.close()
|
}
|
||||||
|
|
||||||
|
Text {
|
||||||
|
id: submenuGlyph
|
||||||
|
visible: !menuRow.modelData.isSeparator && menuRow.modelData.hasChildren
|
||||||
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
|
anchors.right: parent.right
|
||||||
|
anchors.rightMargin: Style.space(10)
|
||||||
|
text: "\u203a"
|
||||||
|
color: root.foreground
|
||||||
|
font.family: root.fontFamily
|
||||||
|
font.pixelSize: Style.font.bodySmall
|
||||||
|
}
|
||||||
|
|
||||||
|
MouseArea {
|
||||||
|
id: rowMouse
|
||||||
|
anchors.fill: parent
|
||||||
|
hoverEnabled: true
|
||||||
|
enabled: !menuRow.modelData.isSeparator && menuRow.modelData.enabled
|
||||||
|
cursorShape: enabled ? Qt.PointingHandCursor : Qt.ArrowCursor
|
||||||
|
onClicked: {
|
||||||
|
if (menuRow.modelData.hasChildren) {
|
||||||
|
var point = menuRow.QsWindow.contentItem.mapFromItem(menuRow, menuRow.width, menuRow.height / 2)
|
||||||
|
menuRow.modelData.display(menuRow.QsWindow.window, point.x, point.y)
|
||||||
|
} else {
|
||||||
|
menuRow.modelData.triggered()
|
||||||
|
root.close()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user