mirror of
https://github.com/noctalia-dev/noctalia-shell.git
synced 2026-05-11 17:08:27 +08:00
Tray: dropdown shenanigans
This commit is contained in:
@@ -771,7 +771,9 @@
|
||||
"description": "Add tray exclusion rules, supports wildcards (*).",
|
||||
"label": "Blacklist",
|
||||
"placeholder": "e.g., nm-applet, Fcitx*"
|
||||
}
|
||||
},
|
||||
"add-as-favorite": "Add as Favorite",
|
||||
"remove-from-favorites": "Remove from Favorites"
|
||||
},
|
||||
"widgets": {
|
||||
"section": {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
{
|
||||
"settingsVersion": 16,
|
||||
"settingsVersion": 18,
|
||||
"setupCompleted": false,
|
||||
"bar": {
|
||||
"position": "top",
|
||||
@@ -70,6 +70,9 @@
|
||||
"compactLockScreen": false,
|
||||
"lockOnSuspend": true,
|
||||
"enableShadows": true,
|
||||
"shadowDirection": "bottom_right",
|
||||
"shadowOffsetX": 2,
|
||||
"shadowOffsetY": 3,
|
||||
"language": ""
|
||||
},
|
||||
"ui": {
|
||||
@@ -118,11 +121,11 @@
|
||||
"transitionType": "random",
|
||||
"transitionEdgeSmoothness": 0.05,
|
||||
"monitors": [],
|
||||
"selectorPosition": "follow_bar"
|
||||
"panelPosition": "folow_bar"
|
||||
},
|
||||
"appLauncher": {
|
||||
"enableClipboardHistory": false,
|
||||
"position": "follow_bar",
|
||||
"position": "center",
|
||||
"backgroundOpacity": 1,
|
||||
"pinnedExecs": [],
|
||||
"useApp2Unit": false,
|
||||
@@ -249,6 +252,7 @@
|
||||
"kitty": false,
|
||||
"ghostty": false,
|
||||
"foot": false,
|
||||
"wezterm": false,
|
||||
"fuzzel": false,
|
||||
"discord": false,
|
||||
"discord_vesktop": false,
|
||||
|
||||
@@ -0,0 +1,172 @@
|
||||
import QtQuick
|
||||
import QtQuick.Layouts
|
||||
import Quickshell
|
||||
import Quickshell.Widgets
|
||||
import Quickshell.Services.SystemTray
|
||||
import qs.Commons
|
||||
import qs.Services
|
||||
import qs.Widgets
|
||||
|
||||
// A compact grid panel listing all tray items, opened from the Tray widget
|
||||
NPanel {
|
||||
id: root
|
||||
|
||||
objectName: "trayDropdownPanel"
|
||||
|
||||
// Widget info for menu functionality
|
||||
property string widgetSection: ""
|
||||
property int widgetIndex: -1
|
||||
|
||||
// Trigger refresh when settings change
|
||||
property int settingsVersion: 0
|
||||
|
||||
// Read favorites directly from settings for reactivity
|
||||
readonly property var favoritesList: {
|
||||
// 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 widgetSettings = widgets[widgetIndex]
|
||||
if (!widgetSettings || widgetSettings.id !== "Tray") return []
|
||||
return 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 NPanel 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: true
|
||||
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 && trayMenu.item) {
|
||||
trayMenu.item.menu = modelData.menu
|
||||
trayMenu.item.screen = root.screen
|
||||
trayMenu.item.trayItem = modelData
|
||||
trayMenu.item.widgetSection = root.widgetSection
|
||||
trayMenu.item.widgetIndex = root.widgetIndex
|
||||
const menuX = (root.columns > 1) ? (trayIcon.width / 2) : 0
|
||||
const menuY = trayIcon.height
|
||||
trayMenu.item.showAt(trayIcon, menuX, menuY)
|
||||
} 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()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Tray menu host
|
||||
Loader {
|
||||
id: trayMenu
|
||||
asynchronous: false
|
||||
active: true
|
||||
source: "TrayMenu.qml"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -15,8 +15,12 @@ PopupWindow {
|
||||
property bool isSubMenu: false
|
||||
property bool isHovered: rootMouseArea.containsMouse
|
||||
property ShellScreen screen
|
||||
// Properties for adding tray item to favorites
|
||||
property var trayItem: null
|
||||
property string widgetSection: ""
|
||||
property int widgetIndex: -1
|
||||
|
||||
readonly property int menuWidth: 180
|
||||
readonly property int menuWidth: 240
|
||||
|
||||
implicitWidth: menuWidth
|
||||
|
||||
@@ -117,9 +121,7 @@ PopupWindow {
|
||||
if (modelData?.isSeparator) {
|
||||
return 8
|
||||
} else {
|
||||
// Calculate based on text content
|
||||
const textHeight = text.contentHeight || (Style.fontSizeS * 1.2)
|
||||
return Math.max(28, textHeight + (Style.marginS * 2))
|
||||
return 28
|
||||
}
|
||||
}
|
||||
|
||||
@@ -151,7 +153,7 @@ PopupWindow {
|
||||
text: modelData?.text !== "" ? modelData?.text.replace(/[\n\r]+/g, ' ') : "..."
|
||||
pointSize: Style.fontSizeS
|
||||
verticalAlignment: Text.AlignVCenter
|
||||
wrapMode: Text.WordWrap
|
||||
elide: Text.ElideRight
|
||||
}
|
||||
|
||||
Image {
|
||||
@@ -276,6 +278,190 @@ PopupWindow {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Separator before custom menu item
|
||||
Rectangle {
|
||||
visible: !root.isSubMenu && root.trayItem !== null && root.widgetSection !== "" && root.widgetIndex >= 0
|
||||
Layout.preferredWidth: parent.width
|
||||
Layout.preferredHeight: visible ? 8 : 0
|
||||
color: Color.transparent
|
||||
|
||||
NDivider {
|
||||
anchors.centerIn: parent
|
||||
width: parent.width - (Style.marginM * 2)
|
||||
visible: parent.visible
|
||||
}
|
||||
}
|
||||
|
||||
// Custom "Add/Remove Favorite" menu item (only for non-submenus with tray item info)
|
||||
Rectangle {
|
||||
id: addToFavoriteEntry
|
||||
visible: !root.isSubMenu && root.trayItem !== null && root.widgetSection !== "" && root.widgetIndex >= 0
|
||||
Layout.preferredWidth: parent.width
|
||||
Layout.preferredHeight: visible ? 28 : 0
|
||||
color: Color.transparent
|
||||
|
||||
// Check if item is already a favorite
|
||||
readonly property bool isFavorite: {
|
||||
if (!root.trayItem || root.widgetSection === "" || root.widgetIndex < 0) return false
|
||||
const itemName = root.trayItem.tooltipTitle || root.trayItem.name || root.trayItem.id || ""
|
||||
if (!itemName) return false
|
||||
|
||||
var widgets = Settings.data.bar.widgets[root.widgetSection]
|
||||
if (!widgets || root.widgetIndex >= widgets.length) return false
|
||||
var widgetSettings = widgets[root.widgetIndex]
|
||||
if (!widgetSettings || widgetSettings.id !== "Tray") return false
|
||||
|
||||
var favorites = widgetSettings.favorites || []
|
||||
for (var i = 0; i < favorites.length; i++) {
|
||||
if (favorites[i] === itemName) return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
anchors.fill: parent
|
||||
color: addToFavoriteMouseArea.containsMouse ? Qt.alpha(Color.mPrimary, 0.2) : Qt.alpha(Color.mPrimary, 0.08)
|
||||
radius: Style.radiusS
|
||||
border.color: Qt.alpha(Color.mPrimary, addToFavoriteMouseArea.containsMouse ? 0.4 : 0.2)
|
||||
border.width: Style.borderS
|
||||
|
||||
RowLayout {
|
||||
anchors.fill: parent
|
||||
anchors.leftMargin: Style.marginM
|
||||
anchors.rightMargin: Style.marginM
|
||||
spacing: Style.marginS
|
||||
|
||||
NIcon {
|
||||
icon: addToFavoriteEntry.isFavorite ? "star" : "star-outline"
|
||||
pointSize: Style.fontSizeS
|
||||
applyUiScale: false
|
||||
verticalAlignment: Text.AlignVCenter
|
||||
color: Color.mPrimary
|
||||
}
|
||||
|
||||
NText {
|
||||
Layout.fillWidth: true
|
||||
color: Color.mPrimary
|
||||
text: addToFavoriteEntry.isFavorite ? I18n.tr("settings.bar.tray.remove-from-favorites") : I18n.tr("settings.bar.tray.add-as-favorite")
|
||||
pointSize: Style.fontSizeS
|
||||
font.weight: Font.Medium
|
||||
verticalAlignment: Text.AlignVCenter
|
||||
elide: Text.ElideRight
|
||||
}
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
id: addToFavoriteMouseArea
|
||||
anchors.fill: parent
|
||||
hoverEnabled: true
|
||||
enabled: root.visible
|
||||
|
||||
onClicked: {
|
||||
if (addToFavoriteEntry.isFavorite) {
|
||||
root.removeFromFavorites()
|
||||
} else {
|
||||
root.addToFavorites()
|
||||
}
|
||||
root.hideMenu()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function addToFavorites() {
|
||||
if (!trayItem || widgetSection === "" || widgetIndex < 0) {
|
||||
Logger.w("TrayMenu", "Cannot add as favorite: missing tray item or widget info")
|
||||
return
|
||||
}
|
||||
|
||||
// Get the tray item name
|
||||
const itemName = trayItem.tooltipTitle || trayItem.name || trayItem.id || ""
|
||||
if (!itemName) {
|
||||
Logger.w("TrayMenu", "Cannot add as favorite: tray item has no name")
|
||||
return
|
||||
}
|
||||
|
||||
// Get current widget settings
|
||||
var widgets = Settings.data.bar.widgets[widgetSection]
|
||||
if (!widgets || widgetIndex >= widgets.length) {
|
||||
Logger.w("TrayMenu", "Cannot add as favorite: invalid widget index")
|
||||
return
|
||||
}
|
||||
|
||||
var widgetSettings = widgets[widgetIndex]
|
||||
if (!widgetSettings || widgetSettings.id !== "Tray") {
|
||||
Logger.w("TrayMenu", "Cannot add as favorite: widget is not a Tray widget")
|
||||
return
|
||||
}
|
||||
|
||||
// Get current favorites list
|
||||
var favorites = widgetSettings.favorites || []
|
||||
|
||||
// Add to favorites
|
||||
var newFavorites = favorites.slice()
|
||||
newFavorites.push(itemName)
|
||||
|
||||
// Update widget settings
|
||||
var newSettings = Object.assign({}, widgetSettings)
|
||||
newSettings.favorites = newFavorites
|
||||
|
||||
// Update settings
|
||||
widgets[widgetIndex] = newSettings
|
||||
Settings.data.bar.widgets[widgetSection] = widgets
|
||||
Settings.saveImmediate()
|
||||
|
||||
Logger.i("TrayMenu", "Added", itemName, "as favorite")
|
||||
}
|
||||
|
||||
function removeFromFavorites() {
|
||||
if (!trayItem || widgetSection === "" || widgetIndex < 0) {
|
||||
Logger.w("TrayMenu", "Cannot remove from favorites: missing tray item or widget info")
|
||||
return
|
||||
}
|
||||
|
||||
// Get the tray item name
|
||||
const itemName = trayItem.tooltipTitle || trayItem.name || trayItem.id || ""
|
||||
if (!itemName) {
|
||||
Logger.w("TrayMenu", "Cannot remove from favorites: tray item has no name")
|
||||
return
|
||||
}
|
||||
|
||||
// Get current widget settings
|
||||
var widgets = Settings.data.bar.widgets[widgetSection]
|
||||
if (!widgets || widgetIndex >= widgets.length) {
|
||||
Logger.w("TrayMenu", "Cannot remove from favorites: invalid widget index")
|
||||
return
|
||||
}
|
||||
|
||||
var widgetSettings = widgets[widgetIndex]
|
||||
if (!widgetSettings || widgetSettings.id !== "Tray") {
|
||||
Logger.w("TrayMenu", "Cannot remove from favorites: widget is not a Tray widget")
|
||||
return
|
||||
}
|
||||
|
||||
// Get current favorites list
|
||||
var favorites = widgetSettings.favorites || []
|
||||
|
||||
// Remove from favorites
|
||||
var newFavorites = []
|
||||
for (var i = 0; i < favorites.length; i++) {
|
||||
if (favorites[i] !== itemName) {
|
||||
newFavorites.push(favorites[i])
|
||||
}
|
||||
}
|
||||
|
||||
// Update widget settings
|
||||
var newSettings = Object.assign({}, widgetSettings)
|
||||
newSettings.favorites = newFavorites
|
||||
|
||||
// Update settings
|
||||
widgets[widgetIndex] = newSettings
|
||||
Settings.data.bar.widgets[widgetSection] = widgets
|
||||
Settings.saveImmediate()
|
||||
|
||||
Logger.i("TrayMenu", "Removed", itemName, "from favorites")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -37,7 +37,9 @@ 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 var filteredItems: []
|
||||
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)
|
||||
|
||||
function wildCardMatch(str, rule) {
|
||||
if (!str || !rule) {
|
||||
@@ -77,15 +79,6 @@ Rectangle {
|
||||
}
|
||||
|
||||
function _performFilteredItemsUpdate() {
|
||||
if (!root.blacklist || root.blacklist.length === 0) {
|
||||
if (SystemTray.items && SystemTray.items.values) {
|
||||
filteredItems = SystemTray.items.values
|
||||
} else {
|
||||
filteredItems = []
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
let newItems = []
|
||||
if (SystemTray.items && SystemTray.items.values) {
|
||||
const trayItems = SystemTray.items.values
|
||||
@@ -97,7 +90,9 @@ Rectangle {
|
||||
|
||||
const title = item.tooltipTitle || item.name || item.id || ""
|
||||
|
||||
// Check if blacklisted
|
||||
let isBlacklisted = false
|
||||
if (root.blacklist && root.blacklist.length > 0) {
|
||||
for (var j = 0; j < root.blacklist.length; j++) {
|
||||
const rule = root.blacklist[j]
|
||||
if (wildCardMatch(title, rule)) {
|
||||
@@ -105,13 +100,48 @@ Rectangle {
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!isBlacklisted) {
|
||||
newItems.push(item)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Build inline (favorites) and dropdown (non-favorites) lists
|
||||
// If favorites list is empty, all items are 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
|
||||
} else {
|
||||
// No favorites: all items are inline
|
||||
filteredItems = newItems
|
||||
dropdownItems = []
|
||||
}
|
||||
}
|
||||
|
||||
function updateFilteredItems() {
|
||||
@@ -143,7 +173,7 @@ Rectangle {
|
||||
root.updateFilteredItems() // Initial update
|
||||
}
|
||||
|
||||
visible: filteredItems.length > 0
|
||||
visible: filteredItems.length > 0 || dropdownItems.length > 0
|
||||
implicitWidth: isVertical ? Style.capsuleHeight : Math.round(trayFlow.implicitWidth + Style.marginM * 2)
|
||||
implicitHeight: isVertical ? Math.round(trayFlow.implicitHeight + Style.marginM * 2) : Style.capsuleHeight
|
||||
radius: Style.radiusM
|
||||
@@ -250,6 +280,9 @@ Rectangle {
|
||||
menuY = Style.barHeight
|
||||
}
|
||||
trayMenu.item.menu = modelData.menu
|
||||
trayMenu.item.trayItem = modelData
|
||||
trayMenu.item.widgetSection = root.section
|
||||
trayMenu.item.widgetIndex = root.sectionWidgetIndex
|
||||
trayMenu.item.showAt(parent, menuX, menuY)
|
||||
} else {
|
||||
Logger.i("Tray", "No menu available for", modelData.id, "or trayMenu not set")
|
||||
@@ -265,6 +298,24 @@ Rectangle {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Dropdown opener
|
||||
NIconButton {
|
||||
id: dropdownButton
|
||||
visible: dropdownItems.length > 0
|
||||
width: itemSize
|
||||
height: itemSize
|
||||
icon: isVertical ? (barPosition === "left" ? "chevron-right" : "chevron-left") : "chevron-down"
|
||||
tooltipText: I18n.tr("open-control-center") // reuse generic tooltip text
|
||||
onClicked: {
|
||||
const panel = PanelService.getPanel("trayDropdownPanel", root.screen)
|
||||
if (panel) {
|
||||
panel.widgetSection = root.section
|
||||
panel.widgetIndex = root.sectionWidgetIndex
|
||||
panel.toggle(this)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
PanelWindow {
|
||||
|
||||
@@ -154,7 +154,8 @@ Singleton {
|
||||
"Tray": {
|
||||
"allowUserSettings": true,
|
||||
"blacklist": [],
|
||||
"colorizeIcons": false
|
||||
"colorizeIcons": false,
|
||||
"favorites": []
|
||||
},
|
||||
"WiFi": {
|
||||
"allowUserSettings": true,
|
||||
|
||||
@@ -87,6 +87,11 @@ ShellRoot {
|
||||
ControlCenterPanel {}
|
||||
}
|
||||
|
||||
Component {
|
||||
id: trayDropdownComponent
|
||||
TrayDropdownPanel {}
|
||||
}
|
||||
|
||||
Component {
|
||||
id: calendarComponent
|
||||
CalendarPanel {}
|
||||
@@ -240,6 +245,9 @@ ShellRoot {
|
||||
}, {
|
||||
"id": "controlCenterPanel",
|
||||
"component": controlCenterComponent
|
||||
}, {
|
||||
"id": "trayDropdownPanel",
|
||||
"component": trayDropdownComponent
|
||||
}, {
|
||||
"id": "calendarPanel",
|
||||
"component": calendarComponent
|
||||
|
||||
Reference in New Issue
Block a user