mirror of
https://github.com/zoriya/noctalia-shell.git
synced 2026-08-15 18:43:59 +00:00
Refactor: Panels and Bar background are now drawn separately with Shapes.
This commit is contained in:
@@ -0,0 +1,180 @@
|
||||
import QtQuick
|
||||
import QtQuick.Layouts
|
||||
import Quickshell
|
||||
import Quickshell.Widgets
|
||||
import Quickshell.Services.SystemTray
|
||||
import qs.Commons
|
||||
import qs.Services
|
||||
import qs.Widgets
|
||||
import qs.Modules.MainScreen
|
||||
|
||||
// A compact grid panel listing all tray items, opened from the Tray widget
|
||||
SmartPanel {
|
||||
id: root
|
||||
|
||||
// Widget info for menu functionality
|
||||
property string widgetSection: ""
|
||||
property int widgetIndex: -1
|
||||
|
||||
// Trigger refresh when settings change
|
||||
property int settingsVersion: 0
|
||||
|
||||
// Read widget settings for reactivity
|
||||
readonly property var widgetSettings: {
|
||||
// Reference settingsVersion to force recalculation when it changes
|
||||
var _ = root.settingsVersion
|
||||
if (widgetSection === "" || widgetIndex < 0)
|
||||
return {}
|
||||
var widgets = Settings.data.bar.widgets[widgetSection]
|
||||
if (!widgets || widgetIndex >= widgets.length)
|
||||
return {}
|
||||
var settings = widgets[widgetIndex]
|
||||
if (!settings || settings.id !== "Tray")
|
||||
return {}
|
||||
return settings
|
||||
}
|
||||
|
||||
// Read favorites directly from settings for reactivity
|
||||
readonly property var favoritesList: widgetSettings.favorites || []
|
||||
|
||||
function wildCardMatch(str, rule) {
|
||||
if (!str || !rule)
|
||||
return false
|
||||
let escaped = rule.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')
|
||||
let pattern = '^' + escaped.replace(/\\\*/g, '.*') + '$'
|
||||
try {
|
||||
return new RegExp(pattern, 'i').test(str)
|
||||
} catch (e) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
function isFavorite(item) {
|
||||
if (!favoritesList || favoritesList.length === 0)
|
||||
return false
|
||||
const title = item?.tooltipTitle || item?.name || item?.id || ""
|
||||
for (var i = 0; i < favoritesList.length; i++) {
|
||||
if (wildCardMatch(title, favoritesList[i]))
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// Dynamic sizing based on item count
|
||||
// Show items that are NOT favorites (non-favorites go to dropdown)
|
||||
readonly property var trayValuesAll: (SystemTray.items && SystemTray.items.values) ? SystemTray.items.values : []
|
||||
readonly property var trayValues: trayValuesAll.filter(function (it) {
|
||||
return !root.isFavorite(it)
|
||||
})
|
||||
readonly property int itemCount: trayValues.length
|
||||
readonly property int maxColumns: 8
|
||||
readonly property real cellSize: Math.round(Style.capsuleHeight * 0.65)
|
||||
readonly property real outerPadding: Style.marginM
|
||||
readonly property real innerSpacing: Style.marginM
|
||||
readonly property int columns: Math.max(1, Math.min(maxColumns, itemCount))
|
||||
readonly property int rows: Math.max(1, Math.ceil(itemCount / Math.max(1, columns)))
|
||||
|
||||
// Add 2*gap margins around the grid
|
||||
preferredWidth: (columns * cellSize) + ((columns - 1) * innerSpacing) + (2 * outerPadding)
|
||||
preferredHeight: (rows * cellSize) + ((rows - 1) * innerSpacing) + (2 * outerPadding)
|
||||
|
||||
// Positioning is handled automatically by SmartPanel when toggle(buttonItem) is called
|
||||
|
||||
// Watch for settings changes to refresh the dropdown
|
||||
Connections {
|
||||
target: Settings
|
||||
function onSettingsSaved() {
|
||||
// Force refresh by incrementing settingsVersion, which triggers recalculation of favoritesList
|
||||
root.settingsVersion++
|
||||
}
|
||||
}
|
||||
|
||||
panelContent: Item {
|
||||
id: content
|
||||
|
||||
Grid {
|
||||
id: grid
|
||||
anchors.fill: parent
|
||||
anchors.margins: outerPadding
|
||||
spacing: innerSpacing
|
||||
columns: root.columns
|
||||
rowSpacing: innerSpacing
|
||||
columnSpacing: innerSpacing
|
||||
|
||||
Repeater {
|
||||
id: repeater
|
||||
model: root.trayValues
|
||||
|
||||
delegate: Item {
|
||||
width: root.cellSize
|
||||
height: root.cellSize
|
||||
|
||||
IconImage {
|
||||
id: trayIcon
|
||||
anchors.fill: parent
|
||||
asynchronous: true
|
||||
backer.fillMode: Image.PreserveAspectFit
|
||||
source: {
|
||||
let icon = modelData?.icon || ""
|
||||
if (!icon)
|
||||
return ""
|
||||
if (icon.includes("?path=")) {
|
||||
const chunks = icon.split("?path=")
|
||||
const name = chunks[0]
|
||||
const path = chunks[1]
|
||||
const fileName = name.substring(name.lastIndexOf("/") + 1)
|
||||
return `file://${path}/${fileName}`
|
||||
}
|
||||
return icon
|
||||
}
|
||||
|
||||
layer.enabled: root.widgetSettings.colorizeIcons !== false
|
||||
layer.effect: ShaderEffect {
|
||||
property color targetColor: Settings.data.colorSchemes.darkMode ? Color.mOnSurface : Color.mSurfaceVariant
|
||||
property real colorizeMode: 1.0
|
||||
fragmentShader: Qt.resolvedUrl(Quickshell.shellDir + "/Shaders/qsb/appicon_colorize.frag.qsb")
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
anchors.fill: parent
|
||||
hoverEnabled: true
|
||||
acceptedButtons: Qt.LeftButton | Qt.RightButton | Qt.MiddleButton
|
||||
|
||||
onClicked: mouse => {
|
||||
if (!modelData)
|
||||
return
|
||||
if (mouse.button === Qt.RightButton && modelData.hasMenu && modelData.menu) {
|
||||
const panel = PanelService.getPanel("trayMenu", root.screen)
|
||||
if (panel) {
|
||||
panel.menu = modelData.menu
|
||||
panel.trayItem = modelData
|
||||
panel.widgetSection = root.widgetSection
|
||||
panel.widgetIndex = root.widgetIndex
|
||||
panel.openAt(trayIcon)
|
||||
}
|
||||
} else if (mouse.button === Qt.LeftButton) {
|
||||
modelData.activate()
|
||||
// Close the dropdown after activation
|
||||
PanelService.getPanel("trayDropdownPanel", root.screen)?.close()
|
||||
} else if (mouse.button === Qt.MiddleButton) {
|
||||
modelData.secondaryActivate()
|
||||
PanelService.getPanel("trayDropdownPanel", root.screen)?.close()
|
||||
}
|
||||
}
|
||||
|
||||
onWheel: wheel => {
|
||||
if (wheel.angleDelta.y > 0)
|
||||
modelData?.scrollUp()
|
||||
else if (wheel.angleDelta.y < 0)
|
||||
modelData?.scrollDown()
|
||||
}
|
||||
|
||||
onEntered: TooltipService.show(Screen, trayIcon, modelData.tooltipTitle || modelData.name || modelData.id || "Tray Item", BarService.getTooltipDirection())
|
||||
onExited: TooltipService.hide()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user