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:
@@ -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
|
||||||
|
|||||||
@@ -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 },
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|||||||
@@ -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()
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user