Tray: add drawer logic

TraySettings: add drawer toggle
i18n: add translations for drawer toggle
This commit is contained in:
Ly-sec
2025-11-06 17:10:32 +01:00
parent e29c6ee1a6
commit 9f357aef25
17 changed files with 118 additions and 66 deletions
+4
View File
@@ -278,6 +278,10 @@
"colorize-icons": {
"description": "Theme-Farben auf Tray-Symbole anwenden.",
"label": "Symbole einfärben"
},
"drawer-enabled": {
"description": "Wenn aktiviert, werden nicht angeheftete Tray-Elemente in einem Schubladen-Panel angezeigt. Wenn deaktiviert, werden alle Tray-Elemente inline angezeigt.",
"label": "Schublade aktivieren"
}
},
"volume": {
+4
View File
@@ -278,6 +278,10 @@
"colorize-icons": {
"description": "Apply theme colors to tray icons.",
"label": "Colorize Icons"
},
"drawer-enabled": {
"description": "When enabled, unpinned tray items are shown in a drawer panel. When disabled, all tray items are shown inline.",
"label": "Enable Drawer"
}
},
"volume": {
+4
View File
@@ -278,6 +278,10 @@
"colorize-icons": {
"description": "Aplicar colores del tema a los iconos de la bandeja del sistema.",
"label": "Colorear iconos"
},
"drawer-enabled": {
"description": "Cuando está habilitado, los elementos de la bandeja no anclados se muestran en un panel cajón. Cuando está deshabilitado, todos los elementos de la bandeja se muestran en línea.",
"label": "Habilitar cajón"
}
},
"volume": {
+4
View File
@@ -278,6 +278,10 @@
"colorize-icons": {
"description": "Appliquer les couleurs du thème aux icônes de la barre système.",
"label": "Coloriser les icônes"
},
"drawer-enabled": {
"description": "Lorsqu'elle est activée, les éléments de la barre système non épinglés sont affichés dans un panneau tiroir. Lorsqu'elle est désactivée, tous les éléments de la barre système sont affichés en ligne.",
"label": "Activer le tiroir"
}
},
"volume": {
+4
View File
@@ -278,6 +278,10 @@
"colorize-icons": {
"description": "Aplicar cores do tema aos ícones da bandeja do sistema.",
"label": "Colorir ícones"
},
"drawer-enabled": {
"description": "Quando habilitado, os itens da bandeja não fixados são exibidos em um painel gaveta. Quando desabilitado, todos os itens da bandeja são exibidos inline.",
"label": "Habilitar gaveta"
}
},
"volume": {
+4
View File
@@ -278,6 +278,10 @@
"colorize-icons": {
"description": "Tepsi ikonlarına tema renklerini uygula.",
"label": "İkonları Renklendir"
},
"drawer-enabled": {
"description": "Etkinleştirildiğinde, sabitlenmemiş tepsi öğeleri bir çekmece panelinde gösterilir. Devre dışı bırakıldığında, tüm tepsi öğeleri satır içi gösterilir.",
"label": "Çekmeceyi Etkinleştir"
}
},
"volume": {
+4
View File
@@ -278,6 +278,10 @@
"colorize-icons": {
"description": "Застосувати кольори теми до значків трея.",
"label": "Розфарбувати значки"
},
"drawer-enabled": {
"description": "Коли увімкнено, не закріплені елементи трея відображаються на панелі ящика. Коли вимкнено, всі елементи трея відображаються в рядку.",
"label": "Увімкнути ящик"
}
},
"volume": {
+4
View File
@@ -278,6 +278,10 @@
"colorize-icons": {
"description": "将主题颜色应用到系统托盘图标。",
"label": "着色图标"
},
"drawer-enabled": {
"description": "启用时,未固定的托盘项显示在抽屉面板中。禁用时,所有托盘项都内联显示。",
"label": "启用抽屉"
}
},
"volume": {
+57 -49
View File
@@ -37,9 +37,10 @@ Rectangle {
readonly property bool density: Settings.data.bar.density
property real itemSize: Math.round(Style.capsuleHeight * 0.65)
property list<string> blacklist: widgetSettings.blacklist || widgetMetadata.blacklist || [] // Read from settings
property list<string> favorites: widgetSettings.favorites || widgetMetadata.favorites || []
property var filteredItems: [] // Items to show inline (favorites)
property var dropdownItems: [] // Items to show in dropdown (non-favorites)
property list<string> favorites: widgetSettings.favorites || widgetMetadata.favorites || [] // Pinned items (shown inline)
property bool drawerEnabled: widgetSettings.drawerEnabled !== undefined ? widgetSettings.drawerEnabled : (widgetMetadata.drawerEnabled !== undefined ? widgetMetadata.drawerEnabled : true) // Enable drawer panel
property var filteredItems: [] // Items to show inline (pinned/favorites)
property var dropdownItems: [] // Items to show in drawer (unpinned/non-favorites)
function wildCardMatch(str, rule) {
if (!str || !rule) {
@@ -107,43 +108,49 @@ Rectangle {
}
}
// Build inline (favorites) and dropdown (non-favorites) lists
// If favorites list is empty, all items go to dropdown (none inline)
// If favorites list has items, favorites are inline, rest go to dropdown
if (favorites && favorites.length > 0) {
let fav = []
for (var k = 0; k < newItems.length; k++) {
const item2 = newItems[k]
const title2 = item2.tooltipTitle || item2.name || item2.id || ""
for (var m = 0; m < favorites.length; m++) {
const rule2 = favorites[m]
if (wildCardMatch(title2, rule2)) {
fav.push(item2)
break
}
}
}
filteredItems = fav
// Non-favorites go to dropdown
let nonFav = []
for (var v = 0; v < newItems.length; v++) {
const cand = newItems[v]
let isFavorite = false
for (var f = 0; f < filteredItems.length; f++) {
if (filteredItems[f] === cand) {
isFavorite = true
break
}
}
if (!isFavorite)
nonFav.push(cand)
}
dropdownItems = nonFav
// If drawer is disabled, show all items inline
if (!root.drawerEnabled) {
filteredItems = newItems
dropdownItems = []
} else {
// No favorites: all items go to dropdown (none inline)
filteredItems = []
dropdownItems = newItems
// Build inline (pinned/favorites) and drawer (unpinned/non-favorites) lists
// If favorites list is empty, all items go to drawer (none inline)
// If favorites list has items, favorites are inline, rest go to drawer
if (favorites && favorites.length > 0) {
let fav = []
for (var k = 0; k < newItems.length; k++) {
const item2 = newItems[k]
const title2 = item2.tooltipTitle || item2.name || item2.id || ""
for (var m = 0; m < favorites.length; m++) {
const rule2 = favorites[m]
if (wildCardMatch(title2, rule2)) {
fav.push(item2)
break
}
}
}
filteredItems = fav
// Non-favorites (unpinned) go to drawer
let nonFav = []
for (var v = 0; v < newItems.length; v++) {
const cand = newItems[v]
let isFavorite = false
for (var f = 0; f < filteredItems.length; f++) {
if (filteredItems[f] === cand) {
isFavorite = true
break
}
}
if (!isFavorite)
nonFav.push(cand)
}
dropdownItems = nonFav
} else {
// No favorites (pinned): all items go to drawer (none inline)
filteredItems = []
dropdownItems = newItems
}
}
}
@@ -188,7 +195,7 @@ Rectangle {
Repeater {
id: repeater
model: SystemTray.items
model: root.filteredItems
delegate: Item {
width: itemSize
@@ -241,27 +248,28 @@ Rectangle {
if (mouse.button === Qt.LeftButton) {
// Close any open menu first
trayPanel.close()
PanelService.getPanel("trayMenuPanel", root.screen)?.close()
if (!modelData.onlyMenu) {
modelData.activate()
}
} else if (mouse.button === Qt.MiddleButton) {
// Close any open menu first
trayPanel.close()
PanelService.getPanel("trayMenuPanel", root.screen)?.close()
modelData.secondaryActivate && modelData.secondaryActivate()
} else if (mouse.button === Qt.RightButton) {
TooltipService.hideImmediately()
// Close the menu if it was visible
if (trayPanel && trayPanel.visible) {
trayPanel.close()
const menuPanel = PanelService.getPanel("trayMenuPanel", root.screen)
if (menuPanel && menuPanel.visible) {
menuPanel.close()
return
}
if (modelData.hasMenu && modelData.menu) {
const panel = PanelService.getPanel("trayMenu", root.screen)
const panel = PanelService.getPanel("trayMenuPanel", root.screen)
if (panel) {
panel.menu = modelData.menu
panel.trayItem = modelData
@@ -277,7 +285,7 @@ Rectangle {
}
}
onEntered: {
trayPanel.close()
PanelService.getPanel("trayMenuPanel", root.screen)?.close()
TooltipService.show(Screen, trayIcon, modelData.tooltipTitle || modelData.name || modelData.id || "Tray Item", BarService.getTooltipDirection())
}
onExited: TooltipService.hide()
@@ -286,10 +294,10 @@ Rectangle {
}
}
// Dropdown opener - simple icon with hover effect
// Drawer opener - simple icon with hover effect
Item {
id: dropdownButton
visible: dropdownItems.length > 0
visible: root.drawerEnabled && dropdownItems.length > 0
width: itemSize
height: itemSize
@@ -335,7 +343,7 @@ Rectangle {
}
onClicked: {
TooltipService.hideImmediately()
const panel = PanelService.getPanel("trayDropdownPanel", root.screen)
const panel = PanelService.getPanel("trayDrawerPanel", root.screen)
if (panel) {
panel.widgetSection = root.section
panel.widgetIndex = root.sectionWidgetIndex
@@ -117,9 +117,9 @@ Item {
shapeContainer: backgroundsShape
}
// TrayDropdown
// TrayDrawer
PanelBackground {
panel: root.windowRoot.trayDropdownPanel
panel: root.windowRoot.trayDrawerPanel
shapeContainer: backgroundsShape
}
+5 -5
View File
@@ -40,7 +40,7 @@ PanelWindow {
readonly property alias sessionMenuPanel: sessionMenuPanel
readonly property alias settingsPanel: settingsPanel
readonly property alias setupWizardPanel: setupWizardPanel
readonly property alias trayDropdownPanel: trayDropdownPanel
readonly property alias trayDrawerPanel: trayDrawerPanel
readonly property alias trayMenuPanel: trayMenuPanel
readonly property alias wallpaperPanel: wallpaperPanel
readonly property alias wifiPanel: wifiPanel
@@ -306,13 +306,13 @@ PanelWindow {
}
TrayDropdownPanel {
id: trayDropdownPanel
id: trayDrawerPanel
screen: root.screen
z: 50
Component.onCompleted: {
objectName = "trayDropdownPanel-" + (screen?.name || "unknown")
PanelService.registerPanel(trayDropdownPanel)
objectName = "trayDrawerPanel-" + (screen?.name || "unknown")
PanelService.registerPanel(trayDrawerPanel)
Logger.d("MainScreen", "Panel registered:", objectName, "on screen:", screen?.name)
}
}
@@ -324,7 +324,7 @@ PanelWindow {
Component.onCompleted: {
objectName = "trayMenuPanel-" + (screen?.name || "unknown")
PanelService.registerPanel(trayDropdownPanel)
PanelService.registerPanel(trayMenuPanel)
Logger.d("MainScreen", "Panel registered:", objectName, "on screen:", screen?.name)
}
}
@@ -21,6 +21,7 @@ Popup {
height: content.implicitHeight + padding * 2
padding: Style.marginXL
modal: true
dim: false
anchors.centerIn: parent
onOpened: {
@@ -13,6 +13,7 @@ ColumnLayout {
// Local state
property var localBlacklist: widgetData.blacklist || []
property bool valueColorizeIcons: widgetData.colorizeIcons !== undefined ? widgetData.colorizeIcons : widgetMetadata.colorizeIcons
property bool valueDrawerEnabled: widgetData.drawerEnabled !== undefined ? widgetData.drawerEnabled : (widgetMetadata.drawerEnabled !== undefined ? widgetMetadata.drawerEnabled : true)
ListModel {
id: blacklistModel
@@ -37,6 +38,14 @@ ColumnLayout {
onToggled: checked => root.valueColorizeIcons = checked
}
NToggle {
Layout.fillWidth: true
label: I18n.tr("bar.widget-settings.tray.drawer-enabled.label")
description: I18n.tr("bar.widget-settings.tray.drawer-enabled.description")
checked: root.valueDrawerEnabled
onToggled: checked => root.valueDrawerEnabled = checked
}
ColumnLayout {
Layout.fillWidth: true
spacing: Style.marginS
@@ -140,6 +149,7 @@ ColumnLayout {
var settings = Object.assign({}, widgetData || {})
settings.blacklist = newBlacklist
settings.colorizeIcons = root.valueColorizeIcons
settings.drawerEnabled = root.valueDrawerEnabled
return settings
}
}
+3 -3
View File
@@ -224,7 +224,7 @@ ColumnLayout {
NSectionEditor {
sectionName: "Left"
sectionId: "left"
settingsDialogComponent: Qt.resolvedUrl(Quickshell.shellDir + "/Modules/Settings/Bar/BarWidgetSettingsDialog.qml")
settingsDialogComponent: Qt.resolvedUrl(Quickshell.shellDir + "/Modules/Panels/Settings/Bar/BarWidgetSettingsDialog.qml")
widgetRegistry: BarWidgetRegistry
widgetModel: Settings.data.bar.widgets.left
availableWidgets: availableWidgets
@@ -241,7 +241,7 @@ ColumnLayout {
NSectionEditor {
sectionName: "Center"
sectionId: "center"
settingsDialogComponent: Qt.resolvedUrl(Quickshell.shellDir + "/Modules/Settings/Bar/BarWidgetSettingsDialog.qml")
settingsDialogComponent: Qt.resolvedUrl(Quickshell.shellDir + "/Modules/Panels/Settings/Bar/BarWidgetSettingsDialog.qml")
widgetRegistry: BarWidgetRegistry
widgetModel: Settings.data.bar.widgets.center
availableWidgets: availableWidgets
@@ -258,7 +258,7 @@ ColumnLayout {
NSectionEditor {
sectionName: "Right"
sectionId: "right"
settingsDialogComponent: Qt.resolvedUrl(Quickshell.shellDir + "/Modules/Settings/Bar/BarWidgetSettingsDialog.qml")
settingsDialogComponent: Qt.resolvedUrl(Quickshell.shellDir + "/Modules/Panels/Settings/Bar/BarWidgetSettingsDialog.qml")
widgetRegistry: BarWidgetRegistry
widgetModel: Settings.data.bar.widgets.right
availableWidgets: availableWidgets
+5 -5
View File
@@ -61,7 +61,7 @@ SmartPanel {
}
// Dynamic sizing based on item count
// Show items that are NOT favorites (non-favorites go to dropdown)
// Show items that are NOT favorites (unpinned items go to drawer)
readonly property var trayValuesAll: (SystemTray.items && SystemTray.items.values) ? SystemTray.items.values : []
readonly property var trayValues: trayValuesAll.filter(function (it) {
return !root.isFavorite(it)
@@ -144,7 +144,7 @@ SmartPanel {
if (!modelData)
return
if (mouse.button === Qt.RightButton && modelData.hasMenu && modelData.menu) {
const panel = PanelService.getPanel("trayMenu", root.screen)
const panel = PanelService.getPanel("trayMenuPanel", root.screen)
if (panel) {
panel.menu = modelData.menu
panel.trayItem = modelData
@@ -154,11 +154,11 @@ SmartPanel {
}
} else if (mouse.button === Qt.LeftButton) {
modelData.activate()
// Close the dropdown after activation
PanelService.getPanel("trayDropdownPanel", root.screen)?.close()
// Close the drawer after activation
PanelService.getPanel("trayDrawerPanel", root.screen)?.close()
} else if (mouse.button === Qt.MiddleButton) {
modelData.secondaryActivate()
PanelService.getPanel("trayDropdownPanel", root.screen)?.close()
PanelService.getPanel("trayDrawerPanel", root.screen)?.close()
}
}
+1 -1
View File
@@ -575,7 +575,7 @@ SmartPanel {
Settings.data.bar.widgets[widgetSection] = widgets
Settings.saveImmediate()
if (root.screen) {
const panel = PanelService.getPanel("trayDropdownPanel", root.screen)
const panel = PanelService.getPanel("trayDrawerPanel", root.screen)
if (panel)
panel.close()
}
+2 -1
View File
@@ -155,7 +155,8 @@ Singleton {
"allowUserSettings": true,
"blacklist": [],
"colorizeIcons": false,
"favorites": []
"favorites": [],
"drawerEnabled": true
},
"WiFi": {
"allowUserSettings": true,