Merge pull request #1991 from tmarti2/workspace-show-app-hover

Show workspace applications on hover
This commit is contained in:
Lemmy
2026-03-11 19:56:04 -04:00
committed by GitHub
5 changed files with 104 additions and 19 deletions
+87 -19
View File
@@ -69,6 +69,7 @@ Item {
// Grouped mode (show applications) settings
readonly property bool showApplications: (widgetSettings.showApplications !== undefined) ? widgetSettings.showApplications : widgetMetadata.showApplications
readonly property bool showApplicationsHover: (widgetSettings.showApplicationsHover !== undefined) ? widgetSettings.showApplicationsHover : widgetMetadata.showApplicationsHover
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
@@ -106,7 +107,6 @@ Item {
}
property bool isDestroying: false
property bool hovered: false
// Revision counter to force icon re-evaluation
property int iconRevision: 0
@@ -128,8 +128,34 @@ Item {
signal workspaceChanged(int workspaceId, color accentColor)
implicitWidth: showApplications ? (isVertical ? groupedGrid.implicitWidth : Math.round(groupedGrid.implicitWidth + horizontalPadding * hasLabel)) : (isVertical ? barHeight : computeWidth())
implicitHeight: showApplications ? (isVertical ? Math.round(groupedGrid.implicitHeight + horizontalPadding * 0.6 * hasLabel) : barHeight) : (isVertical ? computeHeight() : barHeight)
property bool isHovered: false
HoverHandler {
id: workspaceHoverHandler
enabled: showApplications && showApplicationsHover
onHoveredChanged: {
if(hovered) {
hoverEval.stop();
isHovered = true;
} else {
hoverEval.restart();
}
}
}
Timer {
id: hoverEval
interval: 150
repeat: false
onTriggered: {
isHovered = workspaceHoverHandler.hovered || contextMenu.visible;
}
}
readonly property bool appVisible: showApplications && (!showApplicationsHover || root.isHovered)
implicitWidth: appVisible ? (isVertical ? groupedGrid.implicitWidth : Math.round(groupedGrid.implicitWidth + horizontalPadding * hasLabel)) : (isVertical ? barHeight : computeWidth())
implicitHeight: appVisible ? (isVertical ? Math.round(groupedGrid.implicitHeight + horizontalPadding * 0.6 * hasLabel) : barHeight) : (isVertical ? computeHeight() : barHeight)
function getWorkspaceWidth(ws, activeOverride) {
const d = Math.round(capsuleHeight * root.baseDimensionRatio);
@@ -258,7 +284,11 @@ Item {
onScreenChanged: Qt.callLater(refreshWorkspaces)
onScreenNameChanged: Qt.callLater(refreshWorkspaces)
onHideUnoccupiedChanged: Qt.callLater(refreshWorkspaces)
onShowApplicationsChanged: Qt.callLater(refreshWorkspaces)
onAppVisibleChanged: {
if (appVisible) {
Qt.callLater(refreshWorkspaces)
}
}
Connections {
target: CompositorService
@@ -266,13 +296,13 @@ Item {
refreshWorkspaces();
}
function onWindowListChanged() {
if (showApplications || showLabelsOnlyWhenOccupied) {
if (appVisible || showLabelsOnlyWhenOccupied) {
root.windowRevision++;
refreshWorkspaces();
}
}
function onActiveWindowChanged() {
if (showApplications) {
if (appVisible) {
root.windowRevision++;
refreshWorkspaces();
}
@@ -410,6 +440,15 @@ Item {
NPopupContextMenu {
id: contextMenu
onVisibleChanged: {
if (visible) {
hoverEval.stop();
root.isHovered = true;
} else {
hoverEval.restart();
}
}
model: {
var items = [];
if (root.selectedWindowId) {
@@ -486,7 +525,7 @@ Item {
Rectangle {
id: workspaceBackground
visible: !showApplications
visible: !appVisible
width: isVertical ? capsuleHeight : parent.width
height: isVertical ? parent.height : capsuleHeight
radius: Style.radiusM
@@ -557,7 +596,15 @@ Item {
spacing: spacingBetweenPills
x: horizontalPadding
y: 0
visible: !isVertical && !showApplications
visible: !isVertical && !appVisible
scale: visible ? 1.0 : 0.8
Behavior on scale {
NumberAnimation {
duration: Style.animationFast
easing.type: Easing.OutBack
easing.overshoot: 1.2
}
}
Repeater {
id: workspaceRepeaterHorizontal
@@ -592,7 +639,15 @@ Item {
spacing: spacingBetweenPills
x: 0
y: horizontalPadding
visible: isVertical && !showApplications
visible: isVertical && !appVisible
scale : visible ? 1.0 : 0.8
Behavior on scale {
NumberAnimation {
duration: Style.animationFast
easing.type: Easing.OutBack
easing.overshoot: 1.2
}
}
Repeater {
id: workspaceRepeaterVertical
@@ -622,7 +677,7 @@ Item {
}
// ========================================
// Grouped mode (showApplications = true)
// Grouped mode (appVisible = true)
// ========================================
Component {
id: groupedWorkspaceDelegate
@@ -655,11 +710,15 @@ Item {
}
}
HoverHandler {
id: groupHoverHandler
}
width: Style.toOdd((hasWindows ? groupedIconsFlow.implicitWidth : root.iconSize) + (root.isVertical ? (root.baseItemSize - root.iconSize + Style.marginXS) : Style.marginXL))
height: Style.toOdd((hasWindows ? groupedIconsFlow.implicitHeight : root.iconSize) + (root.isVertical ? Style.marginL : (root.baseItemSize - root.iconSize + Style.marginXS)))
color: Style.capsuleColor
radius: Style.radiusS
border.color: Settings.data.bar.showOutline ? Style.capsuleBorderColor : Qt.alpha((workspaceModel.isFocused ? Color.mPrimary : Color.mOutline), root.groupedBorderOpacity)
border.color: Settings.data.bar.showOutline ? Style.capsuleBorderColor : Qt.alpha((workspaceModel.isFocused ? Color.mPrimary : (groupHoverHandler.hovered ? Color.mHover : Color.mOutline)), root.groupedBorderOpacity)
border.width: Style.borderS
Behavior on width {
@@ -712,16 +771,19 @@ Item {
delegate: Item {
id: groupedTaskbarItem
property bool itemHovered: false
width: root.iconSize
height: root.iconSize
HoverHandler {
id: windowHoverHandler
}
IconImage {
id: groupedAppIcon
width: parent.width
height: parent.height
source: {
root.iconRevision; // Force re-evaluation when revision changes
return ThemeIcons.iconForAppId(modelData.appId?.toLowerCase());
@@ -733,13 +795,13 @@ Item {
Rectangle {
id: groupedFocusIndicator
visible: modelData.isFocused
visible: modelData.isFocused || windowHoverHandler.hovered
anchors.bottomMargin: -2
anchors.bottom: parent.bottom
anchors.horizontalCenter: parent.horizontalCenter
width: Style.toOdd(root.iconSize * 0.25)
height: 4
color: Color.mPrimary
color: modelData.isFocused ? Color.mPrimary : Color.mHover
radius: Math.min(Style.radiusXXS, width / 2)
}
@@ -773,11 +835,9 @@ Item {
}
}
onEntered: {
groupedTaskbarItem.itemHovered = true;
TooltipService.show(groupedTaskbarItem, modelData.title || modelData.appId || "Unknown app.", BarService.getTooltipDirection(root.screenName));
}
onExited: {
groupedTaskbarItem.itemHovered = false;
TooltipService.hide();
}
}
@@ -906,7 +966,15 @@ Item {
Flow {
id: groupedGrid
visible: showApplications
visible: appVisible
scale: visible ? 1.0 : 0.8
Behavior on scale {
NumberAnimation {
duration: Style.animationFast
easing.type: Easing.OutBack
easing.overshoot: 1.2
}
}
x: root.isVertical ? Style.pixelAlignCenter(parent.width, width) : Math.round(horizontalPadding * root.hasLabel)
y: root.isVertical ? Math.round(horizontalPadding * 0.4 * root.hasLabel) : Style.pixelAlignCenter(parent.height, height)
@@ -915,7 +983,7 @@ Item {
flow: root.isVertical ? Flow.TopToBottom : Flow.LeftToRight
Repeater {
model: showApplications ? localWorkspaces : null
model: appVisible ? localWorkspaces : null
delegate: groupedWorkspaceDelegate
}
}
@@ -22,6 +22,7 @@ ColumnLayout {
// Grouped mode settings
property bool valueShowApplications: widgetData.showApplications !== undefined ? widgetData.showApplications : widgetMetadata.showApplications
property bool valueShowApplicationsHover: widgetData.showApplicationsHover !== undefined ? widgetData.showApplicationsHover : widgetMetadata.showApplicationsHover
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
@@ -42,6 +43,7 @@ ColumnLayout {
settings.characterCount = valueCharacterCount;
settings.followFocusedScreen = valueFollowFocusedScreen;
settings.showApplications = valueShowApplications;
settings.showApplicationsHover = valueShowApplicationsHover;
settings.showLabelsOnlyWhenOccupied = valueShowLabelsOnlyWhenOccupied;
settings.colorizeIcons = valueColorizeIcons;
settings.unfocusedIconsOpacity = valueUnfocusedIconsOpacity;
@@ -201,6 +203,17 @@ ColumnLayout {
}
}
NToggle {
label: I18n.tr("bar.workspace.show-applications-hover-label")
description: I18n.tr("bar.workspace.show-applications-hover-description")
checked: valueShowApplicationsHover
onToggled: checked => {
valueShowApplicationsHover = checked;
saveSettings();
}
visible: valueShowApplications
}
NToggle {
label: I18n.tr("bar.workspace.show-badge-label")
description: I18n.tr("bar.workspace.show-badge-description")