1
0
mirror of https://github.com/AvengeMedia/DankMaterialShell.git synced 2026-01-28 23:42:51 -05:00

feat: appsDock Widget Overflow & Config Options

This commit is contained in:
purian23
2026-01-27 21:15:33 -05:00
parent 78662f9613
commit a168a8160c
6 changed files with 572 additions and 24 deletions

View File

@@ -263,6 +263,9 @@ Singleton {
property bool clockCompactMode: false property bool clockCompactMode: false
property bool focusedWindowCompactMode: false property bool focusedWindowCompactMode: false
property bool runningAppsCompactMode: true property bool runningAppsCompactMode: true
property int barMaxVisibleApps: 0
property int barMaxVisibleRunningApps: 0
property bool barShowOverflowBadge: true
property bool keyboardLayoutNameCompactMode: false property bool keyboardLayoutNameCompactMode: false
property bool runningAppsCurrentWorkspace: false property bool runningAppsCurrentWorkspace: false
property bool runningAppsGroupByApp: false property bool runningAppsGroupByApp: false

View File

@@ -120,6 +120,9 @@ var SPEC = {
clockCompactMode: { def: false }, clockCompactMode: { def: false },
focusedWindowCompactMode: { def: false }, focusedWindowCompactMode: { def: false },
runningAppsCompactMode: { def: true }, runningAppsCompactMode: { def: true },
barMaxVisibleApps: { def: 0 },
barMaxVisibleRunningApps: { def: 0 },
barShowOverflowBadge: { def: true },
keyboardLayoutNameCompactMode: { def: false }, keyboardLayoutNameCompactMode: { def: false },
runningAppsCurrentWorkspace: { def: false }, runningAppsCurrentWorkspace: { def: false },
runningAppsGroupByApp: { def: false }, runningAppsGroupByApp: { def: false },

View File

@@ -31,6 +31,15 @@ Item {
property bool suppressShiftAnimation: false property bool suppressShiftAnimation: false
property int pinnedAppCount: 0 property int pinnedAppCount: 0
property int maxVisibleApps: widgetData?.barMaxVisibleApps !== undefined ? widgetData.barMaxVisibleApps : SettingsData.barMaxVisibleApps
property int maxVisibleRunningApps: widgetData?.barMaxVisibleRunningApps !== undefined ? widgetData.barMaxVisibleRunningApps : SettingsData.barMaxVisibleRunningApps
property bool showOverflowBadge: widgetData?.barShowOverflowBadge !== undefined ? widgetData.barShowOverflowBadge : SettingsData.barShowOverflowBadge
property bool overflowExpanded: false
property int overflowItemCount: 0
onMaxVisibleAppsChanged: updateModel()
onMaxVisibleRunningAppsChanged: updateModel()
readonly property real effectiveBarThickness: { readonly property real effectiveBarThickness: {
if (barThickness > 0 && barSpacing > 0) { if (barThickness > 0 && barSpacing > 0) {
return barThickness + barSpacing; return barThickness + barSpacing;
@@ -116,6 +125,12 @@ Item {
function onRunningAppsCurrentWorkspaceChanged() { function onRunningAppsCurrentWorkspaceChanged() {
updateModel(); updateModel();
} }
function onBarMaxVisibleAppsChanged() {
updateModel();
}
function onBarMaxVisibleRunningAppsChanged() {
updateModel();
}
} }
Connections { Connections {
@@ -165,7 +180,51 @@ Item {
return null; return null;
} }
function updateModel() { function createSeparator(key) {
return {
uniqueKey: key,
type: "separator",
appId: "__SEPARATOR__",
toplevel: null,
isPinned: false,
isRunning: false,
isInOverflow: false
};
}
function markAsOverflow(item) {
return {
uniqueKey: item.uniqueKey,
type: item.type,
appId: item.appId,
toplevel: item.toplevel,
isPinned: item.isPinned,
isRunning: item.isRunning,
windowCount: item.windowCount,
allWindows: item.allWindows,
isCoreApp: item.isCoreApp,
coreAppData: item.coreAppData,
isInOverflow: true
};
}
function markAsVisible(item) {
return {
uniqueKey: item.uniqueKey,
type: item.type,
appId: item.appId,
toplevel: item.toplevel,
isPinned: item.isPinned,
isRunning: item.isRunning,
windowCount: item.windowCount,
allWindows: item.allWindows,
isCoreApp: item.isCoreApp,
coreAppData: item.coreAppData,
isInOverflow: false
};
}
function buildBaseItems() {
const items = []; const items = [];
const pinnedApps = [...(SessionData.barPinnedApps || [])]; const pinnedApps = [...(SessionData.barPinnedApps || [])];
_toplevelsUpdateTrigger; _toplevelsUpdateTrigger;
@@ -235,7 +294,8 @@ Item {
windowCount: group.windows.length, windowCount: group.windows.length,
allWindows: group.windows, allWindows: group.windows,
isCoreApp: group.isCoreApp || false, isCoreApp: group.isCoreApp || false,
coreAppData: group.coreAppData || null coreAppData: group.coreAppData || null,
isInOverflow: false
}; };
if (group.isPinned) { if (group.isPinned) {
@@ -248,20 +308,97 @@ Item {
pinnedGroups.forEach(item => items.push(item)); pinnedGroups.forEach(item => items.push(item));
if (pinnedGroups.length > 0 && unpinnedGroups.length > 0) { if (pinnedGroups.length > 0 && unpinnedGroups.length > 0) {
items.push({ items.push(createSeparator("separator_grouped"));
uniqueKey: "separator_grouped",
type: "separator",
appId: "__SEPARATOR__",
toplevel: null,
isPinned: false,
isRunning: false
});
} }
unpinnedGroups.forEach(item => items.push(item)); unpinnedGroups.forEach(item => items.push(item));
root.pinnedAppCount = pinnedGroups.length; root.pinnedAppCount = pinnedGroups.length;
dockItems = items; return {
items,
pinnedCount: pinnedGroups.length,
runningCount: unpinnedGroups.length
};
}
function applyOverflow(baseResult) {
const { items } = baseResult;
const maxPinned = root.maxVisibleApps;
const maxRunning = root.maxVisibleRunningApps;
const pinnedItems = items.filter(i => i.type === "grouped" && i.isPinned);
const runningItems = items.filter(i => i.type === "grouped" && i.isRunning && !i.isPinned);
const pinnedOverflow = maxPinned > 0 && pinnedItems.length > maxPinned;
const runningOverflow = maxRunning > 0 && runningItems.length > maxRunning;
if (!pinnedOverflow && !runningOverflow) {
root.overflowItemCount = 0;
return items.map(i => markAsVisible(i));
}
const visiblePinnedKeys = new Set(pinnedOverflow ? pinnedItems.slice(0, maxPinned).map(i => i.uniqueKey) : pinnedItems.map(i => i.uniqueKey));
const visibleRunningKeys = new Set(runningOverflow ? runningItems.slice(0, maxRunning).map(i => i.uniqueKey) : runningItems.map(i => i.uniqueKey));
const overflowPinnedCount = pinnedOverflow ? pinnedItems.length - maxPinned : 0;
const overflowRunningCount = runningOverflow ? runningItems.length - maxRunning : 0;
const totalOverflow = overflowPinnedCount + overflowRunningCount;
root.overflowItemCount = totalOverflow;
const finalItems = [];
let addedSeparator = false;
for (let i = 0; i < items.length; i++) {
const item = items[i];
switch (item.type) {
case "separator":
break;
case "grouped":
if (item.isPinned) {
if (visiblePinnedKeys.has(item.uniqueKey)) {
finalItems.push(markAsVisible(item));
} else {
finalItems.push(markAsOverflow(item));
}
} else if (item.isRunning) {
if (!addedSeparator && finalItems.length > 0) {
finalItems.push(createSeparator("separator_overflow"));
addedSeparator = true;
}
if (visibleRunningKeys.has(item.uniqueKey)) {
finalItems.push(markAsVisible(item));
} else {
finalItems.push(markAsOverflow(item));
}
}
break;
default:
finalItems.push(item);
break;
}
}
if (totalOverflow > 0) {
const toggleIndex = finalItems.findIndex(i => i.type === "separator");
const insertPos = toggleIndex >= 0 ? toggleIndex : finalItems.length;
finalItems.splice(insertPos, 0, {
uniqueKey: "overflow_toggle",
type: "overflow-toggle",
appId: "__OVERFLOW_TOGGLE__",
toplevel: null,
isPinned: false,
isRunning: false,
isInOverflow: false,
overflowCount: totalOverflow
});
}
return finalItems;
}
function updateModel() {
const baseResult = buildBaseItems();
dockItems = applyOverflow(baseResult);
} }
Component.onCompleted: updateModel() Component.onCompleted: updateModel()
@@ -284,6 +421,10 @@ Item {
for (let i = 0; i < dockItems.length; i++) { for (let i = 0; i < dockItems.length; i++) {
const item = dockItems[i]; const item = dockItems[i];
const isInOverflow = item.isInOverflow === true;
if (isInOverflow && !root.overflowExpanded)
continue;
let itemSize = 0; let itemSize = 0;
if (item.type === "separator") { if (item.type === "separator") {
itemSize = 8; itemSize = 8;
@@ -411,13 +552,33 @@ Item {
Item { Item {
id: delegateItem id: delegateItem
property bool isSeparator: modelData.type === "separator" property bool isSeparator: modelData.type === "separator"
readonly property bool isOverflowToggle: modelData.type === "overflow-toggle"
readonly property bool isInOverflow: modelData.isInOverflow === true
readonly property real visualSize: isSeparator ? 8 : ((widgetData?.runningAppsCompactMode !== undefined ? widgetData.runningAppsCompactMode : SettingsData.runningAppsCompactMode) ? 24 : (24 + Theme.spacingXS + 120)) readonly property real visualSize: isSeparator ? 8 : ((widgetData?.runningAppsCompactMode !== undefined ? widgetData.runningAppsCompactMode : SettingsData.runningAppsCompactMode) ? 24 : (24 + Theme.spacingXS + 120))
readonly property real visualWidth: root.isVertical ? root.barThickness : visualSize readonly property real visualWidth: root.isVertical ? root.barThickness : visualSize
readonly property real visualHeight: root.isVertical ? visualSize : root.barThickness readonly property real visualHeight: root.isVertical ? visualSize : root.barThickness
width: visualWidth visible: !isInOverflow || root.overflowExpanded
height: visualHeight opacity: (isInOverflow && !root.overflowExpanded) ? 0 : 1
scale: (isInOverflow && !root.overflowExpanded) ? 0.8 : 1
width: (isInOverflow && !root.overflowExpanded) ? 0 : visualWidth
height: (isInOverflow && !root.overflowExpanded) ? 0 : visualHeight
Behavior on opacity {
NumberAnimation {
duration: Theme.shortDuration
easing.type: Easing.OutCubic
}
}
Behavior on scale {
NumberAnimation {
duration: Theme.shortDuration
easing.type: Easing.OutCubic
}
}
z: (dragHandler.dragging) ? 100 : 0 z: (dragHandler.dragging) ? 100 : 0
@@ -471,9 +632,27 @@ Item {
anchors.centerIn: parent anchors.centerIn: parent
} }
AppsDockOverflowButton {
visible: isOverflowToggle
anchors.centerIn: parent
width: delegateItem.visualWidth
height: delegateItem.visualHeight
iconSize: 24
overflowCount: modelData.overflowCount || 0
overflowExpanded: root.overflowExpanded
isVertical: root.isVertical
showBadge: root.showOverflowBadge
z: 10
onClicked: {
console.log("Overflow button clicked! Current state:", root.overflowExpanded);
root.overflowExpanded = !root.overflowExpanded;
console.log("New state:", root.overflowExpanded);
}
}
Item { Item {
id: appItem id: appItem
visible: !isSeparator visible: !isSeparator && !isOverflowToggle
anchors.fill: parent anchors.fill: parent
property bool isFocused: { property bool isFocused: {
@@ -786,21 +965,22 @@ Item {
onEntered: { onEntered: {
root.hoveredItem = delegateItem; root.hoveredItem = delegateItem;
if (isSeparator) if (isSeparator || isOverflowToggle)
return; return;
tooltipLoader.active = true; tooltipLoader.active = true;
if (tooltipLoader.item) { if (tooltipLoader.item) {
if (root.isVertical) { if (root.isVertical) {
const globalPos = delegateItem.mapToGlobal(delegateItem.width / 2, delegateItem.height / 2); const globalPos = delegateItem.mapToGlobal(0, delegateItem.height / 2);
const screenX = root.parentScreen ? root.parentScreen.x : 0; const screenX = root.parentScreen ? root.parentScreen.x : 0;
const screenY = root.parentScreen ? root.parentScreen.y : 0; const screenY = root.parentScreen ? root.parentScreen.y : 0;
const relativeY = globalPos.y - screenY; const barThickness = root.effectiveBarThickness;
const tooltipX = root.axis?.edge === "left" ? (Theme.barHeight + (barConfig?.spacing ?? 4) + Theme.spacingXS) : (root.parentScreen.width - Theme.barHeight - (barConfig?.spacing ?? 4) - Theme.spacingXS); const spacing = barConfig?.spacing ?? 4;
const isLeft = root.axis?.edge === "left"; const isLeft = root.axis?.edge === "left";
const adjustedY = relativeY + root.minTooltipY; const tooltipOffset = barThickness + spacing + Theme.spacingM;
const finalX = screenX + tooltipX; const tooltipX = isLeft ? tooltipOffset : (root.parentScreen.width - tooltipOffset);
tooltipLoader.item.show(appItem.tooltipText, finalX, adjustedY, root.parentScreen, isLeft, !isLeft); const screenRelativeY = globalPos.y - screenY + root.barY;
tooltipLoader.item.show(appItem.tooltipText, screenX + tooltipX, screenRelativeY, root.parentScreen, isLeft, !isLeft);
} else { } else {
const globalPos = delegateItem.mapToGlobal(delegateItem.width / 2, delegateItem.height); const globalPos = delegateItem.mapToGlobal(delegateItem.width / 2, delegateItem.height);
const screenHeight = root.parentScreen ? root.parentScreen.height : Screen.height; const screenHeight = root.parentScreen ? root.parentScreen.height : Screen.height;

View File

@@ -0,0 +1,76 @@
import QtQuick
import qs.Common
import qs.Widgets
Item {
id: root
property real iconSize: 24
property int overflowCount: 0
property bool overflowExpanded: false
property bool isVertical: false
property bool showBadge: true
signal clicked
Rectangle {
id: buttonBackground
anchors.centerIn: parent
width: root.iconSize
height: root.iconSize
radius: Theme.cornerRadius
color: Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, mouseArea.containsMouse ? 0.2 : 0.1)
Behavior on color {
ColorAnimation {
duration: Theme.shortDuration
}
}
DankIcon {
id: arrowIcon
anchors.centerIn: parent
size: root.iconSize * 0.6
name: "expand_more"
color: Theme.widgetIconColor
rotation: isVertical ? (overflowExpanded ? 180 : 0) : (overflowExpanded ? 90 : -90)
Behavior on rotation {
NumberAnimation {
duration: Theme.shortDuration
easing.type: Easing.OutCubic
}
}
}
}
Rectangle {
visible: overflowCount > 0 && !overflowExpanded && root.showBadge
anchors.right: buttonBackground.right
anchors.top: buttonBackground.top
anchors.rightMargin: -4
anchors.topMargin: -4
width: Math.max(18, badgeText.width + 8)
height: 18
radius: 9
color: Theme.primary
z: 10
StyledText {
id: badgeText
anchors.centerIn: parent
text: `+${overflowCount}`
font.pixelSize: Theme.fontSizeSmall
font.weight: Font.Bold
color: Theme.onPrimary
}
}
MouseArea {
id: mouseArea
anchors.fill: parent
hoverEnabled: true
cursorShape: Qt.PointingHandCursor
onClicked: root.clicked()
}
}

View File

@@ -419,7 +419,7 @@ Item {
"id": widget.id, "id": widget.id,
"enabled": widget.enabled "enabled": widget.enabled
}; };
var keys = ["size", "selectedGpuIndex", "pciId", "mountPath", "minimumWidth", "showSwap", "mediaSize", "clockCompactMode", "focusedWindowCompactMode", "runningAppsCompactMode", "keyboardLayoutNameCompactMode", "showNetworkIcon", "showBluetoothIcon", "showAudioIcon", "showAudioPercent", "showVpnIcon", "showBrightnessIcon", "showBrightnessPercent", "showMicIcon", "showMicPercent", "showBatteryIcon", "showPrinterIcon", "showScreenSharingIcon"]; var keys = ["size", "selectedGpuIndex", "pciId", "mountPath", "minimumWidth", "showSwap", "mediaSize", "clockCompactMode", "focusedWindowCompactMode", "runningAppsCompactMode", "keyboardLayoutNameCompactMode", "showNetworkIcon", "showBluetoothIcon", "showAudioIcon", "showAudioPercent", "showVpnIcon", "showBrightnessIcon", "showBrightnessPercent", "showMicIcon", "showMicPercent", "showBatteryIcon", "showPrinterIcon", "showScreenSharingIcon", "barMaxVisibleApps", "barMaxVisibleRunningApps", "barShowOverflowBadge"];
for (var i = 0; i < keys.length; i++) { for (var i = 0; i < keys.length; i++) {
if (widget[keys[i]] !== undefined) if (widget[keys[i]] !== undefined)
result[keys[i]] = widget[keys[i]]; result[keys[i]] = widget[keys[i]];
@@ -530,6 +530,18 @@ Item {
setWidgetsForSection(sectionId, widgets); setWidgetsForSection(sectionId, widgets);
} }
function handleOverflowSettingChanged(sectionId, widgetIndex, settingName, value) {
var widgets = getWidgetsForSection(sectionId).slice();
if (widgetIndex < 0 || widgetIndex >= widgets.length) {
setWidgetsForSection(sectionId, widgets);
return;
}
var newWidget = cloneWidgetData(widgets[widgetIndex]);
newWidget[settingName] = value;
widgets[widgetIndex] = newWidget;
setWidgetsForSection(sectionId, widgets);
}
function handleCompactModeChanged(sectionId, widgetId, value) { function handleCompactModeChanged(sectionId, widgetId, value) {
var widgets = getWidgetsForSection(sectionId).slice(); var widgets = getWidgetsForSection(sectionId).slice();
for (var i = 0; i < widgets.length; i++) { for (var i = 0; i < widgets.length; i++) {
@@ -621,6 +633,12 @@ Item {
item.runningAppsCompactMode = widget.runningAppsCompactMode; item.runningAppsCompactMode = widget.runningAppsCompactMode;
if (widget.keyboardLayoutNameCompactMode !== undefined) if (widget.keyboardLayoutNameCompactMode !== undefined)
item.keyboardLayoutNameCompactMode = widget.keyboardLayoutNameCompactMode; item.keyboardLayoutNameCompactMode = widget.keyboardLayoutNameCompactMode;
if (widget.barMaxVisibleApps !== undefined)
item.barMaxVisibleApps = widget.barMaxVisibleApps;
if (widget.barMaxVisibleRunningApps !== undefined)
item.barMaxVisibleRunningApps = widget.barMaxVisibleRunningApps;
if (widget.barShowOverflowBadge !== undefined)
item.barShowOverflowBadge = widget.barShowOverflowBadge;
} }
widgets.push(item); widgets.push(item);
}); });
@@ -897,6 +915,9 @@ Item {
onCompactModeChanged: (widgetId, value) => { onCompactModeChanged: (widgetId, value) => {
widgetsTab.handleCompactModeChanged(sectionId, widgetId, value); widgetsTab.handleCompactModeChanged(sectionId, widgetId, value);
} }
onOverflowSettingChanged: (sectionId, widgetIndex, settingName, value) => {
widgetsTab.handleOverflowSettingChanged(sectionId, widgetIndex, settingName, value);
}
} }
} }
@@ -952,6 +973,9 @@ Item {
onCompactModeChanged: (widgetId, value) => { onCompactModeChanged: (widgetId, value) => {
widgetsTab.handleCompactModeChanged(sectionId, widgetId, value); widgetsTab.handleCompactModeChanged(sectionId, widgetId, value);
} }
onOverflowSettingChanged: (sectionId, widgetIndex, settingName, value) => {
widgetsTab.handleOverflowSettingChanged(sectionId, widgetIndex, settingName, value);
}
} }
} }
@@ -1007,6 +1031,9 @@ Item {
onCompactModeChanged: (widgetId, value) => { onCompactModeChanged: (widgetId, value) => {
widgetsTab.handleCompactModeChanged(sectionId, widgetId, value); widgetsTab.handleCompactModeChanged(sectionId, widgetId, value);
} }
onOverflowSettingChanged: (sectionId, widgetIndex, settingName, value) => {
widgetsTab.handleOverflowSettingChanged(sectionId, widgetIndex, settingName, value);
}
} }
} }
} }

View File

@@ -30,13 +30,14 @@ Column {
signal privacySettingChanged(string sectionId, int widgetIndex, string settingName, bool value) signal privacySettingChanged(string sectionId, int widgetIndex, string settingName, bool value)
signal minimumWidthChanged(string sectionId, int widgetIndex, bool enabled) signal minimumWidthChanged(string sectionId, int widgetIndex, bool enabled)
signal showSwapChanged(string sectionId, int widgetIndex, bool enabled) signal showSwapChanged(string sectionId, int widgetIndex, bool enabled)
signal overflowSettingChanged(string sectionId, int widgetIndex, string settingName, var value)
function cloneWidgetData(widget) { function cloneWidgetData(widget) {
var result = { var result = {
"id": widget.id, "id": widget.id,
"enabled": widget.enabled "enabled": widget.enabled
}; };
var keys = ["size", "selectedGpuIndex", "pciId", "mountPath", "minimumWidth", "showSwap", "mediaSize", "clockCompactMode", "focusedWindowCompactMode", "runningAppsCompactMode", "keyboardLayoutNameCompactMode", "showNetworkIcon", "showBluetoothIcon", "showAudioIcon", "showAudioPercent", "showVpnIcon", "showBrightnessIcon", "showBrightnessPercent", "showMicIcon", "showMicPercent", "showBatteryIcon", "showPrinterIcon", "showScreenSharingIcon"]; var keys = ["size", "selectedGpuIndex", "pciId", "mountPath", "minimumWidth", "showSwap", "mediaSize", "clockCompactMode", "focusedWindowCompactMode", "runningAppsCompactMode", "keyboardLayoutNameCompactMode", "showNetworkIcon", "showBluetoothIcon", "showAudioIcon", "showAudioPercent", "showVpnIcon", "showBrightnessIcon", "showBrightnessPercent", "showMicIcon", "showMicPercent", "showBatteryIcon", "showPrinterIcon", "showScreenSharingIcon", "barMaxVisibleApps", "barMaxVisibleRunningApps", "barShowOverflowBadge"];
for (var i = 0; i < keys.length; i++) { for (var i = 0; i < keys.length; i++) {
if (widget[keys[i]] !== undefined) if (widget[keys[i]] !== undefined)
result[keys[i]] = widget[keys[i]]; result[keys[i]] = widget[keys[i]];
@@ -408,7 +409,7 @@ Column {
Row { Row {
spacing: Theme.spacingXS spacing: Theme.spacingXS
visible: modelData.id === "clock" || modelData.id === "focusedWindow" || modelData.id === "runningApps" || modelData.id === "keyboard_layout_name" visible: modelData.id === "clock" || modelData.id === "focusedWindow" || modelData.id === "runningApps" || modelData.id === "keyboard_layout_name" || modelData.id === "appsDock"
DankActionButton { DankActionButton {
id: compactModeButton id: compactModeButton
@@ -508,6 +509,49 @@ Column {
} }
} }
DankActionButton {
id: overflowMenuButton
buttonSize: 28
visible: modelData.id === "appsDock"
iconName: "unfold_more"
iconSize: 16
iconColor: {
const maxApps = modelData.barMaxVisibleApps !== undefined ? modelData.barMaxVisibleApps : SettingsData.barMaxVisibleApps;
const maxRunning = modelData.barMaxVisibleRunningApps !== undefined ? modelData.barMaxVisibleRunningApps : SettingsData.barMaxVisibleRunningApps;
return (maxApps > 0 || maxRunning > 0) ? Theme.primary : Theme.outline;
}
onClicked: {
overflowContextMenu.widgetData = modelData;
overflowContextMenu.sectionId = root.sectionId;
overflowContextMenu.widgetIndex = index;
var buttonPos = overflowMenuButton.mapToItem(root, 0, 0);
var popupWidth = overflowContextMenu.width;
var popupHeight = overflowContextMenu.height;
var xPos = buttonPos.x - popupWidth - Theme.spacingS;
if (xPos < 0)
xPos = buttonPos.x + overflowMenuButton.width + Theme.spacingS;
var yPos = buttonPos.y - popupHeight / 2 + overflowMenuButton.height / 2;
if (yPos < 0) {
yPos = Theme.spacingS;
} else if (yPos + popupHeight > root.height) {
yPos = root.height - popupHeight - Theme.spacingS;
}
overflowContextMenu.x = xPos;
overflowContextMenu.y = yPos;
overflowContextMenu.open();
}
onEntered: {
sharedTooltip.show(I18n.tr("Overflow"), overflowMenuButton, 0, 0, "bottom");
}
onExited: {
sharedTooltip.hide();
}
}
Rectangle { Rectangle {
id: compactModeTooltip id: compactModeTooltip
width: tooltipText.contentWidth + Theme.spacingM * 2 width: tooltipText.contentWidth + Theme.spacingM * 2
@@ -1384,4 +1428,219 @@ Column {
} }
} }
} }
Popup {
id: overflowContextMenu
property var widgetData: null
property string sectionId: ""
property int widgetIndex: -1
// Dynamically get current widget data from the items list
readonly property var currentWidgetData: (widgetIndex >= 0 && widgetIndex < root.items.length) ? root.items[widgetIndex] : widgetData
width: 280
height: overflowMenuColumn.implicitHeight + Theme.spacingS * 2
padding: 0
modal: true
focus: true
closePolicy: Popup.CloseOnEscape | Popup.CloseOnPressOutside
background: Rectangle {
color: Theme.withAlpha(Theme.surfaceContainer, Theme.popupTransparency)
radius: Theme.cornerRadius
border.color: Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.08)
border.width: 0
}
contentItem: Item {
Column {
id: overflowMenuColumn
anchors.fill: parent
anchors.margins: Theme.spacingS
spacing: Theme.spacingS
StyledText {
text: I18n.tr("Overflow")
font.pixelSize: Theme.fontSizeSmall
font.weight: Font.Medium
color: Theme.surfaceText
leftPadding: Theme.spacingS
}
Column {
width: parent.width
spacing: Theme.spacingXS
Row {
width: parent.width
spacing: Theme.spacingS
StyledText {
text: I18n.tr("Max Pinned Apps")
font.pixelSize: Theme.fontSizeSmall
color: Theme.surfaceText
anchors.verticalCenter: parent.verticalCenter
width: 120
}
Row {
spacing: Theme.spacingXS
anchors.verticalCenter: parent.verticalCenter
DankActionButton {
buttonSize: 24
iconName: "remove"
iconSize: 14
iconColor: Theme.outline
onClicked: {
var current = overflowContextMenu.currentWidgetData?.barMaxVisibleApps ?? SettingsData.barMaxVisibleApps;
var newVal = Math.max(0, current - 1);
root.overflowSettingChanged(overflowContextMenu.sectionId, overflowContextMenu.widgetIndex, "barMaxVisibleApps", newVal);
}
}
StyledText {
text: {
var val = overflowContextMenu.currentWidgetData?.barMaxVisibleApps ?? SettingsData.barMaxVisibleApps;
return val === 0 ? I18n.tr("All") : val;
}
font.pixelSize: Theme.fontSizeSmall
color: Theme.surfaceText
anchors.verticalCenter: parent.verticalCenter
horizontalAlignment: Text.AlignHCenter
width: 30
}
DankActionButton {
buttonSize: 24
iconName: "add"
iconSize: 14
iconColor: Theme.outline
onClicked: {
var current = overflowContextMenu.currentWidgetData?.barMaxVisibleApps ?? SettingsData.barMaxVisibleApps;
var newVal = current + 1;
root.overflowSettingChanged(overflowContextMenu.sectionId, overflowContextMenu.widgetIndex, "barMaxVisibleApps", newVal);
}
}
}
}
Row {
width: parent.width
spacing: Theme.spacingS
StyledText {
text: I18n.tr("Max Running Apps")
font.pixelSize: Theme.fontSizeSmall
color: Theme.surfaceText
anchors.verticalCenter: parent.verticalCenter
width: 120
}
Row {
spacing: Theme.spacingXS
anchors.verticalCenter: parent.verticalCenter
DankActionButton {
buttonSize: 24
iconName: "remove"
iconSize: 14
iconColor: Theme.outline
onClicked: {
var current = overflowContextMenu.currentWidgetData?.barMaxVisibleRunningApps ?? SettingsData.barMaxVisibleRunningApps;
var newVal = Math.max(0, current - 1);
root.overflowSettingChanged(overflowContextMenu.sectionId, overflowContextMenu.widgetIndex, "barMaxVisibleRunningApps", newVal);
}
}
StyledText {
text: {
var val = overflowContextMenu.currentWidgetData?.barMaxVisibleRunningApps ?? SettingsData.barMaxVisibleRunningApps;
return val === 0 ? I18n.tr("All") : val;
}
font.pixelSize: Theme.fontSizeSmall
color: Theme.surfaceText
anchors.verticalCenter: parent.verticalCenter
horizontalAlignment: Text.AlignHCenter
width: 30
}
DankActionButton {
buttonSize: 24
iconName: "add"
iconSize: 14
iconColor: Theme.outline
onClicked: {
var current = overflowContextMenu.currentWidgetData?.barMaxVisibleRunningApps ?? SettingsData.barMaxVisibleRunningApps;
var newVal = current + 1;
root.overflowSettingChanged(overflowContextMenu.sectionId, overflowContextMenu.widgetIndex, "barMaxVisibleRunningApps", newVal);
}
}
}
}
Rectangle {
width: parent.width
height: 1
color: Theme.outline
opacity: 0.15
}
Rectangle {
width: parent.width
height: 32
radius: Theme.cornerRadius
color: badgeToggleArea.containsMouse ? Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.12) : "transparent"
Row {
anchors.left: parent.left
anchors.leftMargin: Theme.spacingS
anchors.verticalCenter: parent.verticalCenter
spacing: Theme.spacingS
DankIcon {
name: "notifications"
size: 16
color: Theme.surfaceText
anchors.verticalCenter: parent.verticalCenter
}
StyledText {
text: I18n.tr("Show Badge")
font.pixelSize: Theme.fontSizeSmall
color: Theme.surfaceText
font.weight: Font.Normal
anchors.verticalCenter: parent.verticalCenter
}
}
DankToggle {
id: badgeToggle
anchors.right: parent.right
anchors.rightMargin: Theme.spacingS
anchors.verticalCenter: parent.verticalCenter
width: 40
height: 20
checked: overflowContextMenu.currentWidgetData?.barShowOverflowBadge ?? SettingsData.barShowOverflowBadge
onToggled: {
root.overflowSettingChanged(overflowContextMenu.sectionId, overflowContextMenu.widgetIndex, "barShowOverflowBadge", toggled);
}
}
MouseArea {
id: badgeToggleArea
anchors.fill: parent
hoverEnabled: true
cursorShape: Qt.PointingHandCursor
onPressed: {
badgeToggle.checked = !badgeToggle.checked;
root.overflowSettingChanged(overflowContextMenu.sectionId, overflowContextMenu.widgetIndex, "barShowOverflowBadge", badgeToggle.checked);
}
}
}
}
}
}
}
} }