This commit is contained in:
Ly-sec
2025-12-28 20:58:05 +01:00
12 changed files with 249 additions and 105 deletions
+11 -3
View File
@@ -433,6 +433,10 @@
"description": "Choose how workspace labels are displayed.",
"label": "Label mode"
},
"unfocused-icons-opacity": {
"description": "Set the opacity level for unfocused app icons",
"label": "Unfocused icons opacity"
},
"show-applications": {
"description": "Display application icons inside each workspace.",
"label": "Show applications"
@@ -1077,9 +1081,13 @@
"description": "Displays a visible border around every widget.",
"label": "Show widget outlines"
},
"transparent": {
"description": "This will prevent the panels from attaching to the bar.",
"label": "Transparent background"
"use-separate-opacity": {
"description": "Enable to use a separate opacity value for the bar background.",
"label": "Use separate bar opacity"
},
"background-opacity": {
"description": "Set the background opacity specifically for the bar.",
"label": "Bar background opacity"
}
},
"monitors": {
+7 -3
View File
@@ -1077,9 +1077,13 @@
"description": "在每个小部件周围显示可见边框。",
"label": "显示小部件轮廓"
},
"transparent": {
"description": "这将阻止面板附加到工具栏。",
"label": "透明背景"
"use-separate-opacity": {
"description": "启用后为任务栏背景使用单独的不透明度值。",
"label": "使用单独的任务栏不透明度"
},
"background-opacity": {
"description": "为任务栏设置背景不透明度。",
"label": "任务栏背景不透明度"
}
},
"monitors": {
+4 -8
View File
@@ -4,7 +4,8 @@
"position": "top",
"monitors": [],
"density": "default",
"transparent": false,
"barBackgroundOpacity": 0.93,
"useSeparateBarOpacity": false,
"showOutline": false,
"showCapsule": true,
"capsuleOpacity": 1,
@@ -354,12 +355,7 @@
"autoHideMs": 2000,
"overlayLayer": true,
"backgroundOpacity": 1,
"enabledTypes": [
0,
1,
2,
4
],
"enabledTypes": [0, 1, 2, 4],
"monitors": []
},
"audio": {
@@ -436,4 +432,4 @@
"gridSnap": false,
"monitorWidgets": []
}
}
}
+4 -1
View File
@@ -189,11 +189,14 @@ Singleton {
property string position: "top" // "top", "bottom", "left", or "right"
property list<string> monitors: [] // holds bar visibility per monitor
property string density: "default" // "compact", "default", "comfortable"
property bool transparent: false
property bool showOutline: false
property bool showCapsule: true
property real capsuleOpacity: 1.0
// Bar background opacity settings
property real backgroundOpacity: 0.93
property bool useSeparateOpacity: false
// Floating bar settings
property bool floating: false
property real marginVertical: 0.25
+2
View File
@@ -54,6 +54,7 @@ Item {
readonly property bool showApplications: (widgetSettings.showApplications !== undefined) ? widgetSettings.showApplications : widgetMetadata.showApplications
readonly property bool showLabelsOnlyWhenOccupied: (widgetSettings.showLabelsOnlyWhenOccupied !== undefined) ? widgetSettings.showLabelsOnlyWhenOccupied : widgetMetadata.showLabelsOnlyWhenOccupied
readonly property bool colorizeIcons: (widgetSettings.colorizeIcons !== undefined) ? widgetSettings.colorizeIcons : widgetMetadata.colorizeIcons
readonly property real unfocusedIconsOpacity: (widgetSettings.unfocusedIconsOpacity !== undefined) ? widgetSettings.unfocusedIconsOpacity : widgetMetadata.unfocusedIconsOpacity
readonly property bool enableScrollWheel: (widgetSettings.enableScrollWheel !== undefined) ? widgetSettings.enableScrollWheel : widgetMetadata.enableScrollWheel
readonly property int itemSize: Math.round(Style.capsuleHeight * 0.8)
@@ -833,6 +834,7 @@ Item {
source: ThemeIcons.iconForAppId(model.appId)
smooth: true
asynchronous: true
opacity: model.isFocused ? Style.opacityFull : unfocusedIconsOpacity
layer.enabled: root.colorizeIcons && !model.isFocused
Rectangle {
+133 -53
View File
@@ -27,73 +27,153 @@ Item {
anchors.fill: parent
// Wrapper with layer caching for better shadow performance
// Unified background container
Item {
anchors.fill: parent
// Enable layer caching to prevent continuous re-rendering
// This caches the Shape to a GPU texture, reducing GPU tessellation overhead
layer.enabled: true
// Apply opacity to all backgrounds
opacity: Settings.data.ui.panelBackgroundOpacity
// The unified Shape container
Shape {
id: backgroundsShape
// When not using separate bar opacity, use unified approach (original behavior)
Item {
anchors.fill: parent
visible: !Settings.data.bar.useSeparateOpacity
// Use curve renderer for smooth corners (GPU-accelerated)
preferredRendererType: Shape.CurveRenderer
// Enable layer caching to prevent continuous re-rendering
layer.enabled: true
opacity: Settings.data.ui.panelBackgroundOpacity
enabled: false // Disable mouse input on the Shape itself
Shape {
id: unifiedBackgroundsShape
anchors.fill: parent
preferredRendererType: Shape.CurveRenderer
enabled: false
Component.onCompleted: {
Logger.d("AllBackgrounds", "AllBackgrounds initialized");
}
/**
* Bar
*/
BarBackground {
bar: root.bar
shapeContainer: backgroundsShape
windowRoot: root.windowRoot
backgroundColor: Settings.data.bar.transparent ? Color.transparent : panelBackgroundColor
}
/**
* Panel Background Slots
* Only 2 slots needed: one for currently open/opening panel, one for closing panel
*/
// Slot 0: Currently open/opening panel
PanelBackground {
assignedPanel: {
var p = PanelService.backgroundSlotAssignments[0];
// Only render if this panel belongs to this screen
return (p && p.screen === root.windowRoot.screen) ? p : null;
Component.onCompleted: {
Logger.d("AllBackgrounds", "AllBackgrounds initialized");
}
/**
* Bar
*/
BarBackground {
bar: root.bar
shapeContainer: unifiedBackgroundsShape
windowRoot: root.windowRoot
backgroundColor: panelBackgroundColor
}
/**
* Panel Background Slots
* Only 2 slots needed: one for currently open/opening panel, one for closing panel
*/
// Slot 0: Currently open/opening panel
PanelBackground {
assignedPanel: {
var p = PanelService.backgroundSlotAssignments[0];
// Only render if this panel belongs to this screen
return (p && p.screen === root.windowRoot.screen) ? p : null;
}
shapeContainer: unifiedBackgroundsShape
defaultBackgroundColor: panelBackgroundColor
}
// Slot 1: Closing panel (during transitions)
PanelBackground {
assignedPanel: {
var p = PanelService.backgroundSlotAssignments[1];
// Only render if this panel belongs to this screen
return (p && p.screen === root.windowRoot.screen) ? p : null;
}
shapeContainer: unifiedBackgroundsShape
defaultBackgroundColor: panelBackgroundColor
}
shapeContainer: backgroundsShape
defaultBackgroundColor: panelBackgroundColor
}
// Slot 1: Closing panel (during transitions)
PanelBackground {
assignedPanel: {
var p = PanelService.backgroundSlotAssignments[1];
// Only render if this panel belongs to this screen
return (p && p.screen === root.windowRoot.screen) ? p : null;
}
shapeContainer: backgroundsShape
defaultBackgroundColor: panelBackgroundColor
// Apply shadow to the unified backgrounds
NDropShadow {
anchors.fill: parent
source: unifiedBackgroundsShape
}
}
// Apply shadow to the cached layer
NDropShadow {
// When using separate bar opacity, separate the rendering
Item {
anchors.fill: parent
source: backgroundsShape
visible: Settings.data.bar.useSeparateOpacity
// Panel backgrounds with panel opacity
Item {
anchors.fill: parent
layer.enabled: true
opacity: Settings.data.ui.panelBackgroundOpacity
Shape {
id: panelBackgroundsShape
anchors.fill: parent
preferredRendererType: Shape.CurveRenderer
enabled: false
/**
* Panel Background Slots
* Only 2 slots needed: one for currently open/opening panel, one for closing panel
*/
// Slot 0: Currently open/opening panel
PanelBackground {
assignedPanel: {
var p = PanelService.backgroundSlotAssignments[0];
// Only render if this panel belongs to this screen
return (p && p.screen === root.windowRoot.screen) ? p : null;
}
shapeContainer: panelBackgroundsShape
defaultBackgroundColor: panelBackgroundColor
}
// Slot 1: Closing panel (during transitions)
PanelBackground {
assignedPanel: {
var p = PanelService.backgroundSlotAssignments[1];
// Only render if this panel belongs to this screen
return (p && p.screen === root.windowRoot.screen) ? p : null;
}
shapeContainer: panelBackgroundsShape
defaultBackgroundColor: panelBackgroundColor
}
}
// Apply shadow to the panel backgrounds
NDropShadow {
anchors.fill: parent
source: panelBackgroundsShape
}
}
// Bar background with separate opacity
Item {
anchors.fill: parent
layer.enabled: true
opacity: Settings.data.bar.backgroundOpacity
Shape {
id: barBackgroundShape
anchors.fill: parent
preferredRendererType: Shape.CurveRenderer
enabled: false
BarBackground {
bar: root.bar
shapeContainer: barBackgroundShape
windowRoot: root.windowRoot
backgroundColor: panelBackgroundColor
}
}
NDropShadow {
anchors.fill: parent
source: barBackgroundShape
}
}
}
}
}
+35 -28
View File
@@ -149,38 +149,45 @@ Item {
buttonItem = BarService.lookupWidget(buttonName, screen.name);
}
if (buttonItem) {
root.buttonItem = buttonItem;
// Map button position within its window
var buttonLocal = buttonItem.mapToItem(null, 0, 0);
// Validate buttonItem is a valid QML Item with mapToItem function
if (buttonItem && typeof buttonItem.mapToItem === "function") {
try {
root.buttonItem = buttonItem;
// Map button position within its window
var buttonLocal = buttonItem.mapToItem(null, 0, 0);
// Calculate the bar window's position on screen based on bar settings
// The BarContentWindow uses anchors, so we need to compute its position
var barWindowX = 0;
var barWindowY = 0;
var screenWidth = root.screen?.width || 0;
var screenHeight = root.screen?.height || 0;
// Calculate the bar window's position on screen based on bar settings
// The BarContentWindow uses anchors, so we need to compute its position
var barWindowX = 0;
var barWindowY = 0;
var screenWidth = root.screen?.width || 0;
var screenHeight = root.screen?.height || 0;
if (root.barPosition === "right") {
barWindowX = screenWidth - root.barMarginH - Style.barHeight;
} else if (root.barPosition === "left") {
barWindowX = root.barMarginH;
if (root.barPosition === "right") {
barWindowX = screenWidth - root.barMarginH - Style.barHeight;
} else if (root.barPosition === "left") {
barWindowX = root.barMarginH;
}
// For top/bottom bars, barWindowX stays 0 (full width window)
if (root.barPosition === "bottom") {
barWindowY = screenHeight - root.barMarginV - Style.barHeight;
} else if (root.barPosition === "top") {
barWindowY = root.barMarginV;
}
// For left/right bars, barWindowY stays 0 (full height window)
root.buttonPosition = Qt.point(barWindowX + buttonLocal.x, barWindowY + buttonLocal.y);
root.buttonWidth = buttonItem.width;
root.buttonHeight = buttonItem.height;
root.useButtonPosition = true;
} catch (e) {
Logger.w("SmartPanel", "Failed to get button position, using default positioning:", e);
root.buttonItem = null;
root.useButtonPosition = false;
}
// For top/bottom bars, barWindowX stays 0 (full width window)
if (root.barPosition === "bottom") {
barWindowY = screenHeight - root.barMarginV - Style.barHeight;
} else if (root.barPosition === "top") {
barWindowY = root.barMarginV;
}
// For left/right bars, barWindowY stays 0 (full height window)
root.buttonPosition = Qt.point(barWindowX + buttonLocal.x, barWindowY + buttonLocal.y);
root.buttonWidth = buttonItem.width;
root.buttonHeight = buttonItem.height;
root.useButtonPosition = true;
} else {
// No button provided: reset button position mode
// No valid button provided: reset button position mode
root.buttonItem = null;
root.useButtonPosition = false;
}
+1 -1
View File
@@ -332,7 +332,7 @@ SmartPanel {
}
var availableCount = Bluetooth.devices.values.filter(dev => {
return dev && !dev.paired && !dev.pairing && !dev.blocked && (dev.signalStrength === undefined || dev.signalStrength > 0);
return dev && !dev.blocked && (dev.signalStrength === undefined || dev.signalStrength > 0);
}).length;
return (availableCount === 0);
}
@@ -21,6 +21,7 @@ ColumnLayout {
property bool valueShowApplications: widgetData.showApplications !== undefined ? widgetData.showApplications : widgetMetadata.showApplications
property bool valueShowLabelsOnlyWhenOccupied: widgetData.showLabelsOnlyWhenOccupied !== undefined ? widgetData.showLabelsOnlyWhenOccupied : widgetMetadata.showLabelsOnlyWhenOccupied
property bool valueColorizeIcons: widgetData.colorizeIcons !== undefined ? widgetData.colorizeIcons : widgetMetadata.colorizeIcons
property real valueUnfocusedIconsOpacity: widgetData.unfocusedIconsOpacity !== undefined ? widgetData.unfocusedIconsOpacity : widgetMetadata.unfocusedIconsOpacity
property bool valueEnableScrollWheel: widgetData.enableScrollWheel !== undefined ? widgetData.enableScrollWheel : widgetMetadata.enableScrollWheel
function saveSettings() {
@@ -32,6 +33,7 @@ ColumnLayout {
settings.showApplications = valueShowApplications;
settings.showLabelsOnlyWhenOccupied = valueShowLabelsOnlyWhenOccupied;
settings.colorizeIcons = valueColorizeIcons;
settings.unfocusedIconsOpacity = valueUnfocusedIconsOpacity;
settings.enableScrollWheel = valueEnableScrollWheel;
return settings;
}
@@ -115,4 +117,22 @@ ColumnLayout {
onToggled: checked => valueColorizeIcons = checked
visible: valueShowApplications
}
RowLayout {
spacing: Style.marginL
Layout.fillWidth: true
NLabel {
label: I18n.tr("bar.widget-settings.workspace.unfocused-icons-opacity.label")
description: I18n.tr("bar.widget-settings.workspace.unfocused-icons-opacity.description")
}
NValueSlider {
Layout.fillWidth: true
from: 0
to: 1
stepSize: 0.01
value: valueUnfocusedIconsOpacity
visible: valueShowApplications
onMoved: value => valueUnfocusedIconsOpacity = value
text: Math.floor(valueUnfocusedIconsOpacity * 100) + "%"
}
}
}
+22 -6
View File
@@ -86,14 +86,30 @@ ColumnLayout {
onSelected: key => Settings.data.bar.density = key
}
// Use Separate Bar Opacity Toggle
NToggle {
Layout.fillWidth: true
label: I18n.tr("settings.bar.appearance.transparent.label")
description: I18n.tr("settings.bar.appearance.transparent.description")
checked: Settings.data.bar.transparent
label: I18n.tr("settings.bar.appearance.use-separate-opacity.label")
description: I18n.tr("settings.bar.appearance.use-separate-opacity.description")
checked: Settings.data.bar.useSeparateOpacity
isSettings: true
defaultValue: Settings.getDefaultValue("bar.transparent")
onToggled: checked => Settings.data.bar.transparent = checked
defaultValue: Settings.getDefaultValue("bar.useSeparateOpacity")
onToggled: checked => Settings.data.bar.useSeparateOpacity = checked
}
// Bar Background Opacity (only visible when separate opacity is enabled)
NValueSlider {
Layout.fillWidth: true
visible: Settings.data.bar.useSeparateOpacity
label: I18n.tr("settings.bar.appearance.background-opacity.label")
description: I18n.tr("settings.bar.appearance.background-opacity.description")
from: 0
to: 1
stepSize: 0.01
value: Settings.data.bar.backgroundOpacity
isSettings: true
defaultValue: Settings.getDefaultValue("bar.backgroundOpacity")
onMoved: value => Settings.data.bar.backgroundOpacity = value
text: Math.floor(Settings.data.bar.backgroundOpacity * 100) + "%"
}
NToggle {
+9 -2
View File
@@ -60,7 +60,7 @@ Item {
Timer {
id: screenDetectorDebounce
running: false
interval: 20
interval: 40
onTriggered: {
Logger.d("CurrentScreenDetector", "Screen debounced to:", root.detectedScreen?.name || "null");
@@ -77,8 +77,15 @@ Item {
}
Logger.d("CurrentScreenDetector", "Executing callback on screen:", root.detectedScreen.name);
root.pendingCallback(root.detectedScreen);
// Store callback locally and clear pendingCallback first to prevent deadlock
// if the callback throws an error
var callback = root.pendingCallback;
root.pendingCallback = null;
try {
callback(root.detectedScreen);
} catch (e) {
Logger.e("CurrentScreenDetector", "Callback failed:", e);
}
}
// Clean up
+1
View File
@@ -222,6 +222,7 @@ Singleton {
"showApplications": false,
"showLabelsOnlyWhenOccupied": true,
"colorizeIcons": false,
"unfocusedIconsOpacity": 1.0,
"enableScrollWheel": true
},
"Volume": {