1
0
mirror of https://github.com/AvengeMedia/DankMaterialShell.git synced 2026-06-15 15:45:20 -04:00

Compare commits

...

3 Commits

Author SHA1 Message Date
purian23 1df7e478df fix(FileBrowser): Improve save-to-file handling w/safety override diags
Fixes #2641
2026-06-15 01:11:32 -04:00
Artrix 1fc4890857 tray: add automatic overflow popup (#2629) 2026-06-15 00:10:02 -04:00
purian23 f5d52f1506 update(ipc): docs & dms ipc list 2026-06-14 23:35:22 -04:00
20 changed files with 675 additions and 213 deletions
+9 -1
View File
@@ -19,7 +19,12 @@ var (
var colorCmd = &cobra.Command{
Use: "color",
Short: "Color utilities",
Long: "Color utilities including picking colors from the screen",
Long: `Color utilities including picking colors from the screen.
This is the screen eyedropper CLI. To open the in-shell color modal, use:
dms ipc call color-picker toggle
See: https://danklinux.com/docs/dankmaterialshell/keybinds-ipc`,
}
var colorPickCmd = &cobra.Command{
@@ -29,6 +34,9 @@ var colorPickCmd = &cobra.Command{
Click on any pixel to capture its color, or press Escape to cancel.
This is the screen eyedropper CLI. To open the in-shell color modal, use:
dms ipc call color-picker toggle
Output format flags (mutually exclusive, default: --hex):
--hex - Hexadecimal (#RRGGBB)
--rgb - RGB values (R G B)
+16 -3
View File
@@ -77,10 +77,15 @@ var killCmd = &cobra.Command{
}
var ipcCmd = &cobra.Command{
Use: "ipc [target] [function] [args...]",
Use: "ipc",
Short: "Send IPC commands to running DMS shell",
Long: `Send IPC commands to the running DMS shell.
dms ipc call <target> <function> [args...] invoke a command
dms ipc list list all targets and functions
Full reference: https://danklinux.com/docs/dankmaterialshell/keybinds-ipc`,
ValidArgsFunction: func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
_ = findConfig(cmd, args)
return getShellIPCCompletions(args, toComplete), cobra.ShellCompDirectiveNoFileComp
},
Run: func(cmd *cobra.Command, args []string) {
@@ -88,9 +93,17 @@ var ipcCmd = &cobra.Command{
},
}
var ipcListCmd = &cobra.Command{
Use: "list",
Short: "List all IPC targets and functions",
Run: func(cmd *cobra.Command, args []string) {
printIPCHelp()
},
}
func init() {
ipcCmd.AddCommand(ipcListCmd)
ipcCmd.SetHelpFunc(func(cmd *cobra.Command, args []string) {
_ = findConfig(cmd, args)
printIPCHelp()
})
}
+44 -27
View File
@@ -601,12 +601,30 @@ func parseTargetsFromIPCShowOutput(output string) ipcTargets {
return targets
}
func getShellIPCCompletions(args []string, _ string) []string {
func buildQsIPCBaseArgs() ([]string, error) {
cmdArgs := []string{"ipc"}
if qsHasAnyDisplay() {
cmdArgs = append(cmdArgs, "--any-display")
switch pid, ok := getFirstDMSPID(); {
case ok:
cmdArgs = append(cmdArgs, "--pid", strconv.Itoa(pid))
default:
if err := findConfig(nil, nil); err != nil {
return nil, err
}
if qsHasAnyDisplay() {
cmdArgs = append(cmdArgs, "--any-display")
}
cmdArgs = append(cmdArgs, "-p", configPath)
}
cmdArgs = append(cmdArgs, "-p", configPath, "show")
return cmdArgs, nil
}
func getShellIPCCompletions(args []string, _ string) []string {
baseArgs, err := buildQsIPCBaseArgs()
if err != nil {
log.Debugf("Error building IPC args for completions: %v", err)
return nil
}
cmdArgs := append(baseArgs, "show")
cmd := exec.Command("qs", cmdArgs...)
var targets ipcTargets
@@ -623,7 +641,7 @@ func getShellIPCCompletions(args []string, _ string) []string {
if len(args) == 0 {
targetNames := make([]string, 0)
targetNames = append(targetNames, "call")
targetNames = append(targetNames, "call", "list")
for k := range targets {
targetNames = append(targetNames, k)
}
@@ -696,23 +714,11 @@ func runShellIPCCommand(args []string) {
args = append([]string{"call"}, args...)
}
cmdArgs := []string{"ipc"}
switch pid, ok := getFirstDMSPID(); {
case ok:
cmdArgs = append(cmdArgs, "--pid", strconv.Itoa(pid))
default:
if err := findConfig(nil, nil); err != nil {
log.Fatalf("Error finding config: %v", err)
}
// ! TODO - remove check when QS 0.3 is released
if qsHasAnyDisplay() {
cmdArgs = append(cmdArgs, "--any-display")
}
cmdArgs = append(cmdArgs, "-p", configPath)
baseArgs, err := buildQsIPCBaseArgs()
if err != nil {
log.Fatalf("Error finding config: %v", err)
}
cmdArgs = append(cmdArgs, args...)
cmdArgs := append(baseArgs, args...)
cmd := exec.Command("qs", cmdArgs...)
cmd.Stdin = os.Stdin
cmd.Stdout = os.Stdout
@@ -724,19 +730,20 @@ func runShellIPCCommand(args []string) {
}
func printIPCHelp() {
fmt.Println("Usage: dms ipc <target> <function> [args...]")
fmt.Println("Usage: dms ipc call <target> <function> [args...]")
fmt.Println()
cmdArgs := []string{"ipc"}
if qsHasAnyDisplay() {
cmdArgs = append(cmdArgs, "--any-display")
baseArgs, err := buildQsIPCBaseArgs()
if err != nil {
printIPCHelpFailure(err)
return
}
cmdArgs = append(cmdArgs, "-p", configPath, "show")
cmdArgs := append(baseArgs, "show")
cmd := exec.Command("qs", cmdArgs...)
output, err := cmd.Output()
if err != nil {
fmt.Println("Could not retrieve available IPC targets (is DMS running?)")
printIPCHelpFailure(err)
return
}
@@ -765,6 +772,16 @@ func printIPCHelp() {
}
}
func printIPCHelpFailure(err error) {
fmt.Println("Could not retrieve IPC targets.")
if err != nil {
fmt.Printf(" %v\n", err)
}
fmt.Println()
fmt.Println(" Full docs: https://danklinux.com/docs/dankmaterialshell/keybinds-ipc")
fmt.Println(" Try: dms ipc call <target> <function>")
}
// ensureFontCache rebuilds the fontconfig cache if user-configured fonts are missing while skipping defaults
func ensureFontCache() {
if _, err := exec.LookPath("fc-list"); err != nil {
+21 -1
View File
@@ -6,6 +6,18 @@ DankMaterialShell provides comprehensive IPC (Inter-Process Communication) funct
dms ipc call <target> <function> [parameters...]
```
## Discovering IPC commands
List all available targets and functions while DMS is running:
```bash
dms ipc list
dms ipc # same
dms ipc --help # same, plus usage text
```
Live listing requires DMS to be running. If listing fails, use this document or the [Keybinds & IPC docs](https://danklinux.com/docs/dankmaterialshell/keybinds-ipc) as an offline reference.
## Target: `audio`
Audio system control and information.
@@ -707,7 +719,7 @@ File browser controls for selecting wallpapers and profile images.
- Both browsers support common image formats (jpg, jpeg, png, bmp, gif, webp)
### Target: `color-picker`
Color picker modal control.
In-shell color picker modal for theme and settings color selection.
**Functions:**
- `open` - Show color picker modal
@@ -718,6 +730,14 @@ Color picker modal control.
- `toggle` - Toggle color picker modal visibility
- `toggleInstant` - Toggle color picker modal visibility without animation on hide
**Note:** This controls the in-shell modal. To pick a pixel from the screen via CLI, use `dms color pick` instead (see [Color Picker CLI](https://danklinux.com/docs/dankmaterialshell/cli-color-picker)).
**Examples:**
```bash
dms ipc call color-picker toggle
dms ipc call color-picker openColor "#3f51b5"
```
### Target: `hypr`
Hyprland-specific controls including keybinds cheatsheet and workspace overview (Hyprland only).
+3
View File
@@ -56,6 +56,9 @@ const DMS_ACTIONS = [
{ id: "spawn dms ipc call dankdash wallpaper", label: "Wallpaper Browser" },
{ id: "spawn dms ipc call file browse wallpaper", label: "File: Browse Wallpaper" },
{ id: "spawn dms ipc call file browse profile", label: "File: Browse Profile" },
{ id: "spawn dms ipc call color-picker toggle", label: "Color Picker: Toggle" },
{ id: "spawn dms ipc call color-picker open", label: "Color Picker: Open" },
{ id: "spawn dms ipc call color-picker close", label: "Color Picker: Close" },
{ id: "spawn dms ipc call keybinds toggle niri", label: "Keybinds Cheatsheet: Toggle", compositor: "niri" },
{ id: "spawn dms ipc call keybinds open niri", label: "Keybinds Cheatsheet: Open", compositor: "niri" },
{ id: "spawn dms ipc call keybinds close", label: "Keybinds Cheatsheet: Close" },
+3
View File
@@ -405,6 +405,9 @@ Singleton {
property int barMaxVisibleApps: 0
property int barMaxVisibleRunningApps: 0
property bool barShowOverflowBadge: true
property bool trayAutoOverflow: true
property bool trayPopupSingleLine: true
property int trayMaxVisibleItems: 0
property bool appsDockHideIndicators: false
property bool appsDockColorizeActive: false
property string appsDockActiveColorMode: "primary"
@@ -164,6 +164,9 @@ var SPEC = {
barMaxVisibleApps: { def: 0 },
barMaxVisibleRunningApps: { def: 0 },
barShowOverflowBadge: { def: true },
trayAutoOverflow: { def: true },
trayPopupSingleLine: { def: true },
trayMaxVisibleItems: { def: 0 },
appsDockHideIndicators: { def: false },
appsDockColorizeActive: { def: false },
appsDockActiveColorMode: { def: "primary" },
@@ -201,6 +201,21 @@ FocusScope {
keyboardSelectionRequested = true;
}
function activateFile(path, name, isDir) {
if (isDir) {
navigateTo(path);
return;
}
if (saveMode) {
saveRow.fileName = name;
pendingFilePath = path;
showOverwriteConfirmation = true;
} else {
fileSelected(path);
closeRequested();
}
}
function handleSaveFile(filePath) {
var normalizedPath = filePath;
if (!normalizedPath.startsWith("file://")) {
@@ -652,6 +667,7 @@ FocusScope {
Row {
anchors.fill: parent
anchors.bottomMargin: root.saveMode ? 40 + Theme.spacingL * 2 : 0
spacing: 0
Row {
@@ -756,12 +772,7 @@ FocusScope {
onItemClicked: (index, path, name, isDir) => {
selectedIndex = index;
setSelectedFileData(path, name, isDir);
if (isDir) {
navigateTo(path);
} else {
fileSelected(path);
root.closeRequested();
}
root.activateFile(path, name, isDir);
}
onItemSelected: (index, path, name, isDir) => {
setSelectedFileData(path, name, isDir);
@@ -776,12 +787,7 @@ FocusScope {
root.keyboardSelectionRequested = false;
selectedIndex = index;
setSelectedFileData(filePath, fileName, fileIsDir);
if (fileIsDir) {
navigateTo(filePath);
} else {
fileSelected(filePath);
root.closeRequested();
}
root.activateFile(filePath, fileName, fileIsDir);
}
}
@@ -817,12 +823,7 @@ FocusScope {
onItemClicked: (index, path, name, isDir) => {
selectedIndex = index;
setSelectedFileData(path, name, isDir);
if (isDir) {
navigateTo(path);
} else {
fileSelected(path);
root.closeRequested();
}
root.activateFile(path, name, isDir);
}
onItemSelected: (index, path, name, isDir) => {
setSelectedFileData(path, name, isDir);
@@ -837,12 +838,7 @@ FocusScope {
root.keyboardSelectionRequested = false;
selectedIndex = index;
setSelectedFileData(filePath, fileName, fileIsDir);
if (fileIsDir) {
navigateTo(filePath);
} else {
fileSelected(filePath);
root.closeRequested();
}
root.activateFile(filePath, fileName, fileIsDir);
}
}
@@ -855,6 +851,7 @@ FocusScope {
}
FileBrowserSaveRow {
id: saveRow
anchors.bottom: parent.bottom
anchors.left: parent.left
anchors.right: parent.right
@@ -913,21 +910,21 @@ FocusScope {
}
}
}
}
FileBrowserOverwriteDialog {
anchors.fill: parent
showDialog: showOverwriteConfirmation
pendingFilePath: root.pendingFilePath
onConfirmed: filePath => {
showOverwriteConfirmation = false;
fileSelected(filePath);
pendingFilePath = "";
Qt.callLater(() => root.closeRequested());
}
onCancelled: {
showOverwriteConfirmation = false;
pendingFilePath = "";
}
FileBrowserOverwriteDialog {
anchors.fill: parent
showDialog: showOverwriteConfirmation
pendingFilePath: root.pendingFilePath
onConfirmed: filePath => {
showOverwriteConfirmation = false;
fileSelected(filePath);
pendingFilePath = "";
Qt.callLater(() => root.closeRequested());
}
onCancelled: {
showOverwriteConfirmation = false;
pendingFilePath = "";
}
}
@@ -74,7 +74,7 @@ Item {
width: 80
height: 36
radius: Theme.cornerRadius
color: cancelArea.containsMouse ? Theme.surfaceVariantHover : Theme.surfaceVariant
color: cancelArea.containsMouse ? Qt.lighter(Theme.surfaceVariant, 1.2) : Theme.surfaceVariant
border.color: Theme.outline
border.width: 1
@@ -8,6 +8,7 @@ Row {
property bool saveMode: false
property string defaultFileName: ""
property string currentPath: ""
property alias fileName: fileNameInput.text
signal saveRequested(string filePath)
@@ -15,6 +15,7 @@ Item {
property real barSpacing: 4
property var barConfig: null
property var blurBarWindow: null
property real sectionAvailablePrimarySize: 0
property bool overrideAxisLayout: false
property bool forceVerticalLayout: false
@@ -359,6 +360,7 @@ Item {
barSpacing: root.barSpacing
barConfig: root.barConfig
blurBarWindow: root.blurBarWindow
sectionAvailablePrimarySize: root.sectionAvailablePrimarySize
isFirst: index === 0
isLast: index === centerRepeater.count - 1
sectionSpacing: parent.itemSpacing
@@ -497,6 +497,7 @@ Item {
widgetThickness: barWindow.widgetThickness
barThickness: barWindow.effectiveBarThickness
barSpacing: barConfig?.spacing ?? 4
sectionAvailablePrimarySize: Math.max(1, hCenterSection.x > 0 ? hCenterSection.x : parent.width / 3)
}
Binding {
@@ -529,6 +530,7 @@ Item {
widgetThickness: barWindow.widgetThickness
barThickness: barWindow.effectiveBarThickness
barSpacing: barConfig?.spacing ?? 4
sectionAvailablePrimarySize: Math.max(1, hCenterSection.x > 0 ? parent.width - (hCenterSection.x + hCenterSection.width) : parent.width / 3)
}
Binding {
@@ -561,6 +563,7 @@ Item {
widgetThickness: barWindow.widgetThickness
barThickness: barWindow.effectiveBarThickness
barSpacing: barConfig?.spacing ?? 4
sectionAvailablePrimarySize: Math.max(1, hRightSection.x > 0 ? hRightSection.x - (hLeftSection.x + hLeftSection.width) : parent.width / 3)
}
Binding {
@@ -600,6 +603,7 @@ Item {
widgetThickness: barWindow.widgetThickness
barThickness: barWindow.effectiveBarThickness
barSpacing: barConfig?.spacing ?? 4
sectionAvailablePrimarySize: Math.max(1, vCenterSection.y > 0 ? vCenterSection.y : parent.height / 3)
}
Binding {
@@ -633,6 +637,7 @@ Item {
widgetThickness: barWindow.widgetThickness
barThickness: barWindow.effectiveBarThickness
barSpacing: barConfig?.spacing ?? 4
sectionAvailablePrimarySize: Math.max(1, vRightSection.y > 0 ? vRightSection.y - (vLeftSection.y + vLeftSection.height) : parent.height / 3)
}
Binding {
@@ -667,6 +672,7 @@ Item {
widgetThickness: barWindow.widgetThickness
barThickness: barWindow.effectiveBarThickness
barSpacing: barConfig?.spacing ?? 4
sectionAvailablePrimarySize: Math.max(1, vCenterSection.y > 0 ? parent.height - (vCenterSection.y + vCenterSection.height) : parent.height / 3)
}
Binding {
@@ -14,6 +14,7 @@ Item {
property real barSpacing: 4
property var barConfig: null
property var blurBarWindow: null
property real sectionAvailablePrimarySize: 0
property bool overrideAxisLayout: false
property bool forceVerticalLayout: false
@@ -61,6 +62,7 @@ Item {
barSpacing: root.barSpacing
barConfig: root.barConfig
blurBarWindow: root.blurBarWindow
sectionAvailablePrimarySize: root.sectionAvailablePrimarySize
isFirst: index === 0
isLast: index === rowRepeater.count - 1
sectionSpacing: parent.rowSpacing
@@ -106,6 +108,7 @@ Item {
barSpacing: root.barSpacing
barConfig: root.barConfig
blurBarWindow: root.blurBarWindow
sectionAvailablePrimarySize: root.sectionAvailablePrimarySize
isFirst: index === 0
isLast: index === columnRepeater.count - 1
sectionSpacing: parent.columnSpacing
@@ -14,6 +14,7 @@ Item {
property real barSpacing: 4
property var barConfig: null
property var blurBarWindow: null
property real sectionAvailablePrimarySize: 0
property bool overrideAxisLayout: false
property bool forceVerticalLayout: false
@@ -63,6 +64,7 @@ Item {
barSpacing: root.barSpacing
barConfig: root.barConfig
blurBarWindow: root.blurBarWindow
sectionAvailablePrimarySize: root.sectionAvailablePrimarySize
isFirst: index === 0
isLast: index === rowRepeater.count - 1
sectionSpacing: parent.rowSpacing
@@ -108,6 +110,7 @@ Item {
barSpacing: root.barSpacing
barConfig: root.barConfig
blurBarWindow: root.blurBarWindow
sectionAvailablePrimarySize: root.sectionAvailablePrimarySize
isFirst: index === 0
isLast: index === columnRepeater.count - 1
sectionSpacing: parent.columnSpacing
@@ -17,6 +17,7 @@ Loader {
property real barSpacing: 4
property var barConfig: null
property var blurBarWindow: null
property real sectionAvailablePrimarySize: 0
property bool isFirst: false
property bool isLast: false
property real sectionSpacing: 0
@@ -141,6 +142,14 @@ Loader {
restoreMode: Binding.RestoreNone
}
Binding {
target: root.item
when: root.item && "sectionAvailablePrimarySize" in root.item
property: "sectionAvailablePrimarySize"
value: root.sectionAvailablePrimarySize
restoreMode: Binding.RestoreNone
}
Binding {
target: root.item
when: root.item && "isLeftBarEdge" in root.item
@@ -22,6 +22,10 @@ BasePill {
property bool isAtBottom: false
property bool isAutoHideBar: false
property bool useOverflowPopup: !widgetData?.trayUseInlineExpansion
property bool useSingleLineOverflowPopup: widgetData?.trayPopupSingleLine ?? SettingsData.trayPopupSingleLine
property bool useAutomaticOverflow: widgetData?.trayAutoOverflow ?? SettingsData.trayAutoOverflow
property int configuredMaxVisibleItems: widgetData?.trayMaxVisibleItems ?? SettingsData.trayMaxVisibleItems
property real sectionAvailablePrimarySize: 0
readonly property var hiddenTrayIds: {
const envValue = Quickshell.env("DMS_HIDE_TRAYIDS") || "";
return envValue ? envValue.split(",").map(id => id.trim().toLowerCase()) : [];
@@ -146,12 +150,32 @@ BasePill {
readonly property var allSortedTrayItems: sortByPreferredOrder(allTrayItems, _trayOrderTrigger)
readonly property var allSortedTrayItemKeys: allSortedTrayItems.map(item => getTrayItemKey(item))
readonly property var mainBarItemsRaw: allSortedTrayItems.filter(item => !SessionData.isHiddenTrayId(root.getTrayItemKey(item)))
readonly property var visibleSortedTrayItems: allSortedTrayItems.filter(item => !SessionData.isHiddenTrayId(root.getTrayItemKey(item)))
readonly property int automaticVisibleItemLimit: {
if (!root.useAutomaticOverflow)
return root.visibleSortedTrayItems.length;
const explicitLimit = Number(root.configuredMaxVisibleItems || 0);
if (explicitLimit > 0)
return Math.max(1, Math.min(root.visibleSortedTrayItems.length, explicitLimit));
const scale = (typeof CompositorService !== "undefined" && CompositorService.getScreenScale) ? Math.max(1, CompositorService.getScreenScale(root.parentScreen)) : 1;
const sectionPrimary = root.sectionAvailablePrimarySize > 0 ? root.sectionAvailablePrimarySize : (root.isVerticalOrientation ? (root.parentScreen?.height || 0) : (root.parentScreen?.width || 0));
const logicalPrimary = sectionPrimary > 0 ? (sectionPrimary / scale) : 640;
const maxTrayShare = root.isVerticalOrientation ? 0.55 : 0.50;
const itemSize = Math.max(1, root.trayItemSize);
const slots = Math.floor((logicalPrimary * maxTrayShare) / itemSize);
return Math.max(2, Math.min(10, Math.min(root.visibleSortedTrayItems.length, slots)));
}
readonly property var mainBarItemsRaw: visibleSortedTrayItems.slice(0, automaticVisibleItemLimit)
readonly property var mainBarItems: mainBarItemsRaw.map((item, idx) => ({
key: getTrayItemKey(item),
item: item
}))
readonly property var hiddenBarItems: allSortedTrayItems.filter(item => SessionData.isHiddenTrayId(root.getTrayItemKey(item)))
readonly property var autoOverflowBarItems: visibleSortedTrayItems.slice(automaticVisibleItemLimit)
readonly property var manualHiddenBarItems: allSortedTrayItems.filter(item => SessionData.isHiddenTrayId(root.getTrayItemKey(item)))
readonly property var hiddenBarItemKeys: manualHiddenBarItems.concat(autoOverflowBarItems).map(item => root.getTrayItemKey(item))
readonly property var hiddenBarItems: allSortedTrayItems.filter(item => hiddenBarItemKeys.indexOf(root.getTrayItemKey(item)) !== -1)
readonly property string trayIconTintMode: {
const configuredMode = SettingsData.systemTrayIconTintMode || "none";
switch (configuredMode) {
@@ -219,6 +243,10 @@ BasePill {
const fromKey = mainBarItems[visibleFromIndex]?.key ?? null;
const toKey = mainBarItems[visibleToIndex]?.key ?? null;
moveTrayItemKeyInFullOrder(fromKey, toKey);
}
function moveTrayItemKeyInFullOrder(fromKey, toKey) {
if (!fromKey || !toKey)
return;
@@ -233,10 +261,103 @@ BasePill {
SessionData.setTrayItemOrder(fullOrder);
}
function promoteTrayItemToBar(item) {
const itemKey = getTrayItemKey(item);
if (!itemKey)
return;
if (SessionData.isHiddenTrayId(itemKey)) {
SessionData.showTrayId(itemKey);
return;
}
const fullOrder = [...allSortedTrayItemKeys];
const fromIndex = fullOrder.indexOf(itemKey);
if (fromIndex < 0)
return;
const movedKey = fullOrder.splice(fromIndex, 1)[0];
const targetIndex = Math.max(0, Math.min(root.automaticVisibleItemLimit - 1, fullOrder.length));
fullOrder.splice(targetIndex, 0, movedKey);
SessionData.setTrayItemOrder(fullOrder);
}
function isManualHiddenTrayItem(item) {
return SessionData.isHiddenTrayId(getTrayItemKey(item));
}
function isAutoOverflowTrayItem(item) {
const key = getTrayItemKey(item);
return key && !isManualHiddenTrayItem(item) && root.autoOverflowBarItems.some(overflowItem => getTrayItemKey(overflowItem) === key);
}
function dragShiftOffset(index, draggedIndex, dropTargetIndex, shiftAmount) {
if (draggedIndex < 0 || index === draggedIndex || dropTargetIndex < 0)
return 0;
if (draggedIndex < dropTargetIndex && index > draggedIndex && index <= dropTargetIndex)
return -shiftAmount;
if (draggedIndex > dropTargetIndex && index >= dropTargetIndex && index < draggedIndex)
return shiftAmount;
return 0;
}
function beginMainDrag(visualIndex, reversed) {
root.draggedIndex = reversed ? (root.mainBarItems.length - 1 - visualIndex) : visualIndex;
root.dropTargetIndex = root.draggedIndex;
}
function updateMainDrag(axisOffset, visualIndex, reversed) {
const itemSize = root.trayItemSize;
const slotOffset = Math.round(axisOffset / itemSize);
const visualTargetIndex = Math.max(0, Math.min(root.mainBarItems.length - 1, visualIndex + slotOffset));
const newTargetIndex = reversed ? (root.mainBarItems.length - 1 - visualTargetIndex) : visualTargetIndex;
if (newTargetIndex !== root.dropTargetIndex)
root.dropTargetIndex = newTargetIndex;
}
function finishMainDrag() {
const didReorder = root.dropTargetIndex >= 0 && root.dropTargetIndex !== root.draggedIndex;
if (didReorder) {
root.suppressShiftAnimation = true;
root.moveTrayItemInFullOrder(root.draggedIndex, root.dropTargetIndex);
Qt.callLater(() => root.suppressShiftAnimation = false);
}
root.draggedIndex = -1;
root.dropTargetIndex = -1;
return didReorder;
}
function beginPopupDrag(index) {
root.popupDraggedIndex = index;
root.popupDropTargetIndex = index;
}
function updatePopupDrag(axisOffset, index) {
const itemSize = root.trayItemSize + 6;
const slotOffset = Math.round(axisOffset / itemSize);
const newTargetIndex = Math.max(0, Math.min(root.hiddenBarItems.length - 1, index + slotOffset));
if (newTargetIndex !== root.popupDropTargetIndex)
root.popupDropTargetIndex = newTargetIndex;
}
function finishPopupDrag() {
const didReorder = root.popupDropTargetIndex >= 0 && root.popupDropTargetIndex !== root.popupDraggedIndex;
if (didReorder) {
const fromItem = root.hiddenBarItems[root.popupDraggedIndex];
const toItem = root.hiddenBarItems[root.popupDropTargetIndex];
root.suppressShiftAnimation = true;
root.moveTrayItemKeyInFullOrder(root.getTrayItemKey(fromItem), root.getTrayItemKey(toItem));
Qt.callLater(() => root.suppressShiftAnimation = false);
}
root.popupDraggedIndex = -1;
root.popupDropTargetIndex = -1;
return didReorder;
}
property int draggedIndex: -1
property int dropTargetIndex: -1
property int popupDraggedIndex: -1
property int popupDropTargetIndex: -1
property bool suppressShiftAnimation: false
readonly property bool hasHiddenItems: allTrayItems.length > mainBarItems.length
readonly property bool hasHiddenItems: hiddenBarItems.length > 0
readonly property bool inlineExpanded: hasHiddenItems && !useOverflowPopup && menuOpen
visible: allTrayItems.length > 0
opacity: allTrayItems.length > 0 ? 1 : 0
@@ -351,22 +472,7 @@ BasePill {
height: root.barThickness
z: dragHandler.dragging ? 100 : 0
property real shiftOffset: {
if (root.draggedIndex < 0)
return 0;
if (index === root.draggedIndex)
return 0;
const dragIdx = root.draggedIndex;
const dropIdx = root.dropTargetIndex;
const shiftAmount = root.trayItemSize;
if (dropIdx < 0)
return 0;
if (dragIdx < dropIdx && index > dragIdx && index <= dropIdx)
return -shiftAmount;
if (dragIdx > dropIdx && index >= dropIdx && index < dragIdx)
return shiftAmount;
return 0;
}
property real shiftOffset: root.dragShiftOffset(index, root.draggedIndex, root.dropTargetIndex, root.trayItemSize)
transform: Translate {
x: delegateRoot.shiftOffset
@@ -466,19 +572,12 @@ BasePill {
onReleased: mouse => {
longPressTimer.stop();
const wasDragging = dragHandler.dragging;
const didReorder = wasDragging && root.dropTargetIndex >= 0 && root.dropTargetIndex !== root.draggedIndex;
if (didReorder) {
root.suppressShiftAnimation = true;
root.moveTrayItemInFullOrder(root.draggedIndex, root.dropTargetIndex);
Qt.callLater(() => root.suppressShiftAnimation = false);
}
if (wasDragging)
root.finishMainDrag();
dragHandler.longPressing = false;
dragHandler.dragging = false;
dragHandler.dragAxisOffset = 0;
root.draggedIndex = -1;
root.dropTargetIndex = -1;
if (wasDragging || mouse.button !== Qt.LeftButton)
return;
@@ -501,8 +600,7 @@ BasePill {
const distance = Math.abs(mouse.x - dragHandler.dragStartPos.x);
if (distance > 5) {
dragHandler.dragging = true;
root.draggedIndex = root.reverseInlineHorizontal ? (root.mainBarItems.length - 1 - index) : index;
root.dropTargetIndex = root.draggedIndex;
root.beginMainDrag(index, root.reverseInlineHorizontal);
}
}
if (!dragHandler.dragging)
@@ -510,13 +608,7 @@ BasePill {
const axisOffset = mouse.x - dragHandler.dragStartPos.x;
dragHandler.dragAxisOffset = axisOffset;
const itemSize = root.trayItemSize;
const slotOffset = Math.round(axisOffset / itemSize);
const visualTargetIndex = Math.max(0, Math.min(root.mainBarItems.length - 1, index + slotOffset));
const newTargetIndex = root.reverseInlineHorizontal ? (root.mainBarItems.length - 1 - visualTargetIndex) : visualTargetIndex;
if (newTargetIndex !== root.dropTargetIndex) {
root.dropTargetIndex = newTargetIndex;
}
root.updateMainDrag(axisOffset, index, root.reverseInlineHorizontal);
}
onClicked: mouse => {
@@ -706,22 +798,7 @@ BasePill {
height: root.trayItemSize
z: dragHandler.dragging ? 100 : 0
property real shiftOffset: {
if (root.draggedIndex < 0)
return 0;
if (index === root.draggedIndex)
return 0;
const dragIdx = root.draggedIndex;
const dropIdx = root.dropTargetIndex;
const shiftAmount = root.trayItemSize;
if (dropIdx < 0)
return 0;
if (dragIdx < dropIdx && index > dragIdx && index <= dropIdx)
return -shiftAmount;
if (dragIdx > dropIdx && index >= dropIdx && index < dragIdx)
return shiftAmount;
return 0;
}
property real shiftOffset: root.dragShiftOffset(index, root.draggedIndex, root.dropTargetIndex, root.trayItemSize)
transform: Translate {
y: shiftOffset
@@ -821,19 +898,12 @@ BasePill {
onReleased: mouse => {
longPressTimer.stop();
const wasDragging = dragHandler.dragging;
const didReorder = wasDragging && root.dropTargetIndex >= 0 && root.dropTargetIndex !== root.draggedIndex;
if (didReorder) {
root.suppressShiftAnimation = true;
root.moveTrayItemInFullOrder(root.draggedIndex, root.dropTargetIndex);
Qt.callLater(() => root.suppressShiftAnimation = false);
}
if (wasDragging)
root.finishMainDrag();
dragHandler.longPressing = false;
dragHandler.dragging = false;
dragHandler.dragAxisOffset = 0;
root.draggedIndex = -1;
root.dropTargetIndex = -1;
if (wasDragging || mouse.button !== Qt.LeftButton)
return;
@@ -856,8 +926,7 @@ BasePill {
const distance = Math.abs(mouse.y - dragHandler.dragStartPos.y);
if (distance > 5) {
dragHandler.dragging = true;
root.draggedIndex = index;
root.dropTargetIndex = root.draggedIndex;
root.beginMainDrag(index, false);
}
}
if (!dragHandler.dragging)
@@ -865,12 +934,7 @@ BasePill {
const axisOffset = mouse.y - dragHandler.dragStartPos.y;
dragHandler.dragAxisOffset = axisOffset;
const itemSize = root.trayItemSize;
const slotOffset = Math.round(axisOffset / itemSize);
const newTargetIndex = Math.max(0, Math.min(root.mainBarItems.length - 1, index + slotOffset));
if (newTargetIndex !== root.dropTargetIndex) {
root.dropTargetIndex = newTargetIndex;
}
root.updateMainDrag(axisOffset, index, false);
}
onClicked: mouse => {
@@ -1136,20 +1200,38 @@ BasePill {
id: menuContainer
objectName: "overflowMenuContainer"
readonly property bool popupUsesVerticalLine: root.useSingleLineOverflowPopup && root.isVerticalOrientation
readonly property real popupPadding: Theme.spacingS + (popupUsesVerticalLine ? 3 : 0)
readonly property real rawWidth: {
const itemCount = root.hiddenBarItems.length;
const cols = Math.min(5, itemCount);
if (itemCount === 0)
return 0;
if (popupUsesVerticalLine)
return root.trayItemSize + 4 + popupPadding * 2;
const cols = root.useSingleLineOverflowPopup ? itemCount : Math.min(5, itemCount);
const itemSize = root.trayItemSize + 4;
const spacing = 2;
return cols * itemSize + (cols - 1) * spacing + Theme.spacingS * 2;
const desiredWidth = cols * itemSize + (cols - 1) * spacing + popupPadding * 2;
if (!root.useSingleLineOverflowPopup)
return desiredWidth;
const maxWidth = Math.max(itemSize + popupPadding * 2, overflowMenu.maskWidth - 20);
return Math.min(desiredWidth, maxWidth);
}
readonly property real rawHeight: {
const itemCount = root.hiddenBarItems.length;
const cols = Math.min(5, itemCount);
const rows = Math.ceil(itemCount / cols);
if (itemCount === 0)
return 0;
const itemSize = root.trayItemSize + 4;
const spacing = 2;
return rows * itemSize + (rows - 1) * spacing + Theme.spacingS * 2;
if (popupUsesVerticalLine) {
const desiredHeight = itemCount * itemSize + (itemCount - 1) * spacing + popupPadding * 2;
const maxHeight = Math.max(itemSize + popupPadding * 2, overflowMenu.maskHeight - 20);
return Math.min(desiredHeight, maxHeight);
}
const cols = root.useSingleLineOverflowPopup ? itemCount : Math.min(5, itemCount);
const rows = Math.ceil(itemCount / cols);
return rows * itemSize + (rows - 1) * spacing + popupPadding * 2;
}
readonly property real alignedWidth: Theme.px(rawWidth, overflowMenu.dpr)
@@ -1230,76 +1312,161 @@ BasePill {
z: 100
}
Grid {
id: menuGrid
Flickable {
anchors.centerIn: parent
columns: Math.min(5, root.hiddenBarItems.length)
spacing: 2
rowSpacing: 2
width: parent.width - menuContainer.popupPadding * 2
height: parent.height - menuContainer.popupPadding * 2
contentWidth: menuGrid.implicitWidth
contentHeight: menuGrid.implicitHeight
boundsBehavior: Flickable.StopAtBounds
clip: true
interactive: root.useSingleLineOverflowPopup && (menuContainer.popupUsesVerticalLine ? contentHeight > height : contentWidth > width)
Repeater {
model: root.hiddenBarItems
Grid {
id: menuGrid
anchors.verticalCenter: menuContainer.popupUsesVerticalLine ? undefined : parent.verticalCenter
anchors.horizontalCenter: menuContainer.popupUsesVerticalLine ? parent.horizontalCenter : undefined
columns: menuContainer.popupUsesVerticalLine ? 1 : (root.useSingleLineOverflowPopup ? root.hiddenBarItems.length : Math.min(5, root.hiddenBarItems.length))
spacing: 2
rowSpacing: 2
delegate: Rectangle {
property var trayItem: modelData
property string iconSource: root.trayIconSourceFor(trayItem)
Repeater {
model: root.hiddenBarItems
width: root.trayItemSize + 4
height: root.trayItemSize + 4
radius: Theme.cornerRadius
color: itemArea.containsMouse ? BlurService.hoverColor(Theme.widgetBaseHoverColor) : Theme.withAlpha(Theme.surfaceContainer, 0)
delegate: Rectangle {
id: overflowItemRoot
property var trayItem: modelData
property string itemKey: root.getTrayItemKey(trayItem)
property string iconSource: root.trayIconSourceFor(trayItem)
IconImage {
id: menuIconImg
anchors.centerIn: parent
width: Theme.barIconSize(root.barThickness, undefined, root.barConfig?.maximizeWidgetIcons, root.barConfig?.iconScale)
height: Theme.barIconSize(root.barThickness, undefined, root.barConfig?.maximizeWidgetIcons, root.barConfig?.iconScale)
source: parent.iconSource
asynchronous: true
smooth: true
mipmap: true
visible: status === Image.Ready
layer.enabled: root.trayIconTintEnabled
layer.effect: MultiEffect {
saturation: root.trayIconSaturation
colorization: root.trayIconColorization
colorizationColor: root.trayIconTintColor
}
}
width: root.trayItemSize + 4
height: root.trayItemSize + 4
z: popupDragHandler.dragging ? 100 : 0
radius: Theme.cornerRadius
color: itemArea.containsMouse ? BlurService.hoverColor(Theme.widgetBaseHoverColor) : Theme.withAlpha(Theme.surfaceContainer, 0)
border.width: popupDragHandler.dragging ? 2 : 0
border.color: Theme.primary
opacity: popupDragHandler.dragging ? 0.8 : 1.0
StyledText {
anchors.centerIn: parent
visible: !menuIconImg.visible
text: {
const itemId = trayItem?.id || "";
if (!itemId)
return "?";
return itemId.charAt(0).toUpperCase();
}
font.pixelSize: 10
color: Theme.widgetTextColor
}
property real shiftOffset: root.dragShiftOffset(index, root.popupDraggedIndex, root.popupDropTargetIndex, root.trayItemSize + 6)
MouseArea {
id: itemArea
anchors.fill: parent
hoverEnabled: true
acceptedButtons: Qt.LeftButton | Qt.RightButton
cursorShape: Qt.PointingHandCursor
onClicked: mouse => {
if (!trayItem)
return;
if (mouse.button === Qt.LeftButton && !trayItem.onlyMenu) {
trayItem.activate();
root.menuOpen = false;
return;
transform: Translate {
x: !menuContainer.popupUsesVerticalLine ? overflowItemRoot.shiftOffset + (popupDragHandler.dragging ? popupDragHandler.dragAxisOffset : 0) : 0
y: menuContainer.popupUsesVerticalLine ? overflowItemRoot.shiftOffset + (popupDragHandler.dragging ? popupDragHandler.dragAxisOffset : 0) : 0
Behavior on x {
enabled: !root.suppressShiftAnimation && !menuContainer.popupUsesVerticalLine
NumberAnimation {
duration: 150
easing.type: Easing.OutCubic
}
}
if (!trayItem.hasMenu) {
const gp = itemArea.mapToGlobal(mouse.x, mouse.y);
root.callContextMenuFallback(trayItem.id, Math.round(gp.x), Math.round(gp.y));
return;
Behavior on y {
enabled: !root.suppressShiftAnimation && menuContainer.popupUsesVerticalLine
NumberAnimation {
duration: 150
easing.type: Easing.OutCubic
}
}
}
Item {
id: popupDragHandler
anchors.fill: parent
property bool dragging: false
property point dragStartPos: Qt.point(0, 0)
property real dragAxisOffset: 0
property bool longPressing: false
Timer {
id: popupLongPressTimer
interval: 400
repeat: false
onTriggered: popupDragHandler.longPressing = true
}
}
IconImage {
id: menuIconImg
anchors.centerIn: parent
width: Theme.barIconSize(root.barThickness, undefined, root.barConfig?.maximizeWidgetIcons, root.barConfig?.iconScale)
height: Theme.barIconSize(root.barThickness, undefined, root.barConfig?.maximizeWidgetIcons, root.barConfig?.iconScale)
source: parent.iconSource
asynchronous: true
smooth: true
mipmap: true
visible: status === Image.Ready
layer.enabled: root.trayIconTintEnabled
layer.effect: MultiEffect {
saturation: root.trayIconSaturation
colorization: root.trayIconColorization
colorizationColor: root.trayIconTintColor
}
}
StyledText {
anchors.centerIn: parent
visible: !menuIconImg.visible
text: {
const itemId = trayItem?.id || "";
if (!itemId)
return "?";
return itemId.charAt(0).toUpperCase();
}
font.pixelSize: 10
color: Theme.widgetTextColor
}
MouseArea {
id: itemArea
anchors.fill: parent
hoverEnabled: true
acceptedButtons: Qt.LeftButton | Qt.RightButton
cursorShape: popupDragHandler.longPressing ? Qt.DragMoveCursor : Qt.PointingHandCursor
onPressed: mouse => {
if (mouse.button === Qt.LeftButton) {
popupDragHandler.dragStartPos = Qt.point(mouse.x, mouse.y);
popupLongPressTimer.start();
}
}
onReleased: mouse => {
popupLongPressTimer.stop();
const wasDragging = popupDragHandler.dragging;
if (wasDragging)
root.finishPopupDrag();
popupDragHandler.longPressing = false;
popupDragHandler.dragging = false;
popupDragHandler.dragAxisOffset = 0;
}
onPositionChanged: mouse => {
const axisDelta = menuContainer.popupUsesVerticalLine ? (mouse.y - popupDragHandler.dragStartPos.y) : (mouse.x - popupDragHandler.dragStartPos.x);
if (popupDragHandler.longPressing && !popupDragHandler.dragging && Math.abs(axisDelta) > 5) {
popupDragHandler.dragging = true;
root.beginPopupDrag(index);
}
if (!popupDragHandler.dragging)
return;
popupDragHandler.dragAxisOffset = axisDelta;
root.updatePopupDrag(axisDelta, index);
}
onClicked: mouse => {
if (popupDragHandler.dragging)
return;
if (!trayItem)
return;
if (mouse.button === Qt.LeftButton && !trayItem.onlyMenu) {
trayItem.activate();
root.menuOpen = false;
return;
}
if (!trayItem.hasMenu) {
const gp = itemArea.mapToGlobal(mouse.x, mouse.y);
root.callContextMenuFallback(trayItem.id, Math.round(gp.x), Math.round(gp.y));
return;
}
root.showForTrayItem(trayItem, menuContainer, parentScreen, root.isAtBottom, root.isVerticalOrientation, root.axis);
}
root.showForTrayItem(trayItem, menuContainer, parentScreen, root.isAtBottom, root.isVerticalOrientation, root.axis);
}
}
}
@@ -1695,7 +1862,12 @@ BasePill {
anchors.left: parent.left
anchors.leftMargin: Theme.spacingS
anchors.verticalCenter: parent.verticalCenter
text: menuRoot.trayItem?.id || "Unknown"
text: {
const itemId = menuRoot.trayItem?.id || "Unknown";
if (root.isAutoOverflowTrayItem(menuRoot.trayItem))
return itemId + " · " + I18n.tr("Keep in Bar");
return itemId;
}
font.pixelSize: Theme.fontSizeSmall
color: Theme.surfaceTextMedium
elide: Text.ElideMiddle
@@ -1706,7 +1878,11 @@ BasePill {
anchors.right: parent.right
anchors.rightMargin: Theme.spacingS
anchors.verticalCenter: parent.verticalCenter
name: SessionData.isHiddenTrayId(root.getTrayItemKey(menuRoot.trayItem)) ? "visibility" : "visibility_off"
name: {
if (root.isAutoOverflowTrayItem(menuRoot.trayItem))
return "push_pin";
return root.isManualHiddenTrayItem(menuRoot.trayItem) ? "visibility" : "visibility_off";
}
size: 16
color: Theme.widgetTextColor
}
@@ -1720,7 +1896,9 @@ BasePill {
const itemKey = root.getTrayItemKey(menuRoot.trayItem);
if (!itemKey)
return;
if (SessionData.isHiddenTrayId(itemKey)) {
if (root.isAutoOverflowTrayItem(menuRoot.trayItem)) {
root.promoteTrayItemToBar(menuRoot.trayItem);
} else if (root.isManualHiddenTrayItem(menuRoot.trayItem)) {
SessionData.showTrayId(itemKey);
} else {
SessionData.hideTrayId(itemKey);
+6
View File
@@ -44,6 +44,12 @@ Item {
service: NotepadStorageService
}
// In connected frame mode the slideout sits on the Overlay layer
onFileDialogOpenChanged: {
if (slideout)
slideout.suppressOverlayLayer = fileDialogOpen;
}
Connections {
target: slideout
enabled: slideout !== null
+7 -1
View File
@@ -460,7 +460,7 @@ Item {
"id": widget.id,
"enabled": widget.enabled
};
var keys = ["size", "selectedGpuIndex", "pciId", "mountPath", "diskUsageMode", "minimumWidth", "showSwap", "showInGb", "mediaSize", "clockCompactMode", "focusedWindowSize", "focusedWindowCompactMode", "runningAppsCompactMode", "keyboardLayoutNameCompactMode", "keyboardLayoutNameShowIcon", "runningAppsGroupByApp", "runningAppsCurrentWorkspace", "runningAppsCurrentMonitor", "showNetworkIcon", "showBluetoothIcon", "showAudioIcon", "showAudioPercent", "showVpnIcon", "showBrightnessIcon", "showBrightnessPercent", "showMicIcon", "showMicPercent", "showBatteryIcon", "showPrinterIcon", "showScreenSharingIcon", "showIdleInhibitorIcon", "showDoNotDisturbIcon", "controlCenterGroupOrder", "barMaxVisibleApps", "barMaxVisibleRunningApps", "barShowOverflowBadge", "trayUseInlineExpansion", "hideWhenIdle"];
var keys = ["size", "selectedGpuIndex", "pciId", "mountPath", "diskUsageMode", "minimumWidth", "showSwap", "showInGb", "mediaSize", "clockCompactMode", "focusedWindowSize", "focusedWindowCompactMode", "runningAppsCompactMode", "keyboardLayoutNameCompactMode", "keyboardLayoutNameShowIcon", "runningAppsGroupByApp", "runningAppsCurrentWorkspace", "runningAppsCurrentMonitor", "showNetworkIcon", "showBluetoothIcon", "showAudioIcon", "showAudioPercent", "showVpnIcon", "showBrightnessIcon", "showBrightnessPercent", "showMicIcon", "showMicPercent", "showBatteryIcon", "showPrinterIcon", "showScreenSharingIcon", "showIdleInhibitorIcon", "showDoNotDisturbIcon", "controlCenterGroupOrder", "barMaxVisibleApps", "barMaxVisibleRunningApps", "barShowOverflowBadge", "trayUseInlineExpansion", "trayPopupSingleLine", "trayAutoOverflow", "trayMaxVisibleItems", "hideWhenIdle"];
for (var i = 0; i < keys.length; i++) {
if (widget[keys[i]] !== undefined)
result[keys[i]] = widget[keys[i]];
@@ -803,6 +803,12 @@ Item {
item.barShowOverflowBadge = widget.barShowOverflowBadge;
if (widget.trayUseInlineExpansion !== undefined)
item.trayUseInlineExpansion = widget.trayUseInlineExpansion;
if (widget.trayPopupSingleLine !== undefined)
item.trayPopupSingleLine = widget.trayPopupSingleLine;
if (widget.trayAutoOverflow !== undefined)
item.trayAutoOverflow = widget.trayAutoOverflow;
if (widget.trayMaxVisibleItems !== undefined)
item.trayMaxVisibleItems = widget.trayMaxVisibleItems;
if (widget.hideWhenIdle !== undefined)
item.hideWhenIdle = widget.hideWhenIdle;
}
@@ -43,7 +43,7 @@ Column {
"id": widget.id,
"enabled": widget.enabled
};
var keys = ["size", "selectedGpuIndex", "pciId", "mountPath", "diskUsageMode", "minimumWidth", "showSwap", "showInGb", "mediaSize", "clockCompactMode", "focusedWindowSize", "focusedWindowCompactMode", "runningAppsCompactMode", "keyboardLayoutNameCompactMode", "keyboardLayoutNameShowIcon", "runningAppsGroupByApp", "runningAppsCurrentWorkspace", "runningAppsCurrentMonitor", "showNetworkIcon", "showBluetoothIcon", "showAudioIcon", "showAudioPercent", "showVpnIcon", "showBrightnessIcon", "showBrightnessPercent", "showMicIcon", "showMicPercent", "showBatteryIcon", "showPrinterIcon", "showScreenSharingIcon", "showIdleInhibitorIcon", "showDoNotDisturbIcon", "controlCenterGroupOrder", "barMaxVisibleApps", "barMaxVisibleRunningApps", "barShowOverflowBadge", "trayUseInlineExpansion"];
var keys = ["size", "selectedGpuIndex", "pciId", "mountPath", "diskUsageMode", "minimumWidth", "showSwap", "showInGb", "mediaSize", "clockCompactMode", "focusedWindowSize", "focusedWindowCompactMode", "runningAppsCompactMode", "keyboardLayoutNameCompactMode", "keyboardLayoutNameShowIcon", "runningAppsGroupByApp", "runningAppsCurrentWorkspace", "runningAppsCurrentMonitor", "showNetworkIcon", "showBluetoothIcon", "showAudioIcon", "showAudioPercent", "showVpnIcon", "showBrightnessIcon", "showBrightnessPercent", "showMicIcon", "showMicPercent", "showBatteryIcon", "showPrinterIcon", "showScreenSharingIcon", "showIdleInhibitorIcon", "showDoNotDisturbIcon", "controlCenterGroupOrder", "barMaxVisibleApps", "barMaxVisibleRunningApps", "barShowOverflowBadge", "trayUseInlineExpansion", "trayPopupSingleLine", "trayAutoOverflow", "trayMaxVisibleItems"];
for (var i = 0; i < keys.length; i++) {
if (widget[keys[i]] !== undefined)
result[keys[i]] = widget[keys[i]];
@@ -1126,6 +1126,188 @@ Column {
}
}
}
Rectangle {
width: parent.width
height: 32
radius: Theme.cornerRadius
color: trayPopupLineArea.containsMouse ? Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.12) : "transparent"
opacity: (trayContextMenu.currentWidgetData?.trayUseInlineExpansion ?? false) ? 0.55 : 1
Row {
anchors.left: parent.left
anchors.leftMargin: Theme.spacingS
anchors.verticalCenter: parent.verticalCenter
spacing: Theme.spacingS
DankIcon {
name: "view_week"
size: 16
color: Theme.surfaceText
anchors.verticalCenter: parent.verticalCenter
}
StyledText {
text: I18n.tr("Single-Line Popup")
font.pixelSize: Theme.fontSizeSmall
color: Theme.surfaceText
font.weight: Font.Normal
anchors.verticalCenter: parent.verticalCenter
}
}
DankToggle {
id: trayPopupLineToggle
anchors.right: parent.right
anchors.rightMargin: Theme.spacingS
anchors.verticalCenter: parent.verticalCenter
width: 40
height: 20
checked: trayContextMenu.currentWidgetData?.trayPopupSingleLine ?? SettingsData.trayPopupSingleLine
enabled: !(trayContextMenu.currentWidgetData?.trayUseInlineExpansion ?? false)
}
MouseArea {
id: trayPopupLineArea
anchors.fill: parent
hoverEnabled: true
cursorShape: (trayContextMenu.currentWidgetData?.trayUseInlineExpansion ?? false) ? Qt.ArrowCursor : Qt.PointingHandCursor
onClicked: {
if (trayContextMenu.currentWidgetData?.trayUseInlineExpansion ?? false)
return;
const newValue = !(trayContextMenu.currentWidgetData?.trayPopupSingleLine ?? SettingsData.trayPopupSingleLine);
root.overflowSettingChanged(trayContextMenu.sectionId, trayContextMenu.widgetIndex, "trayPopupSingleLine", newValue);
}
}
}
Rectangle {
width: parent.width
height: 32
radius: Theme.cornerRadius
color: trayAutoOverflowArea.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: "responsive_layout"
size: 16
color: Theme.surfaceText
anchors.verticalCenter: parent.verticalCenter
}
StyledText {
text: I18n.tr("Auto Overflow")
font.pixelSize: Theme.fontSizeSmall
color: Theme.surfaceText
font.weight: Font.Normal
anchors.verticalCenter: parent.verticalCenter
}
}
DankToggle {
id: trayAutoOverflowToggle
anchors.right: parent.right
anchors.rightMargin: Theme.spacingS
anchors.verticalCenter: parent.verticalCenter
width: 40
height: 20
checked: trayContextMenu.currentWidgetData?.trayAutoOverflow ?? SettingsData.trayAutoOverflow
}
MouseArea {
id: trayAutoOverflowArea
anchors.fill: parent
hoverEnabled: true
cursorShape: Qt.PointingHandCursor
onClicked: {
const newValue = !(trayContextMenu.currentWidgetData?.trayAutoOverflow ?? SettingsData.trayAutoOverflow);
root.overflowSettingChanged(trayContextMenu.sectionId, trayContextMenu.widgetIndex, "trayAutoOverflow", newValue);
}
}
}
Rectangle {
width: parent.width
height: 36
radius: Theme.cornerRadius
color: trayMaxVisibleArea.containsMouse ? Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.12) : "transparent"
opacity: (trayContextMenu.currentWidgetData?.trayAutoOverflow ?? SettingsData.trayAutoOverflow) ? 1 : 0.55
Row {
anchors.left: parent.left
anchors.leftMargin: Theme.spacingS
anchors.verticalCenter: parent.verticalCenter
spacing: Theme.spacingS
DankIcon {
name: "low_priority"
size: 16
color: Theme.surfaceText
anchors.verticalCenter: parent.verticalCenter
}
StyledText {
text: I18n.tr("Max Visible")
font.pixelSize: Theme.fontSizeSmall
color: Theme.surfaceText
font.weight: Font.Normal
anchors.verticalCenter: parent.verticalCenter
}
StyledText {
text: {
const value = trayContextMenu.currentWidgetData?.trayMaxVisibleItems ?? SettingsData.trayMaxVisibleItems;
return value > 0 ? String(value) : I18n.tr("Auto");
}
font.pixelSize: Theme.fontSizeSmall
color: Theme.surfaceTextMedium
anchors.verticalCenter: parent.verticalCenter
}
}
Row {
anchors.right: parent.right
anchors.rightMargin: Theme.spacingXS
anchors.verticalCenter: parent.verticalCenter
spacing: 2
DankActionButton {
buttonSize: 28
iconName: "remove"
iconSize: 16
iconColor: Theme.surfaceText
enabled: trayContextMenu.currentWidgetData?.trayAutoOverflow ?? SettingsData.trayAutoOverflow
onClicked: {
const current = trayContextMenu.currentWidgetData?.trayMaxVisibleItems ?? SettingsData.trayMaxVisibleItems;
root.overflowSettingChanged(trayContextMenu.sectionId, trayContextMenu.widgetIndex, "trayMaxVisibleItems", Math.max(0, current - 1));
}
}
DankActionButton {
buttonSize: 28
iconName: "add"
iconSize: 16
iconColor: Theme.surfaceText
enabled: trayContextMenu.currentWidgetData?.trayAutoOverflow ?? SettingsData.trayAutoOverflow
onClicked: {
const current = trayContextMenu.currentWidgetData?.trayMaxVisibleItems ?? SettingsData.trayMaxVisibleItems;
root.overflowSettingChanged(trayContextMenu.sectionId, trayContextMenu.widgetIndex, "trayMaxVisibleItems", Math.min(20, current + 1));
}
}
}
MouseArea {
id: trayMaxVisibleArea
anchors.fill: parent
hoverEnabled: true
acceptedButtons: Qt.NoButton
}
}
}
}
}
+3 -1
View File
@@ -16,6 +16,8 @@ PanelWindow {
property var targetScreen: null
property var modelData: null
property bool triggerUsesOverlayLayer: false
// Drop off the Overlay layer (back to Top) while an overlay modal
property bool suppressOverlayLayer: false
property real slideoutWidth: 480
property bool expandable: false
property bool expandedWidth: false
@@ -67,7 +69,7 @@ PanelWindow {
readonly property bool slideoutBlurActive: root.visible && BlurService.enabled && Theme.connectedSurfaceBlurEnabled
WlrLayershell.layer: (triggerUsesOverlayLayer || CompositorService.framePeerSurfacesUseOverlayForScreen(modelData)) ? WlrLayershell.Overlay : WlrLayershell.Top
WlrLayershell.layer: (!suppressOverlayLayer && (triggerUsesOverlayLayer || CompositorService.framePeerSurfacesUseOverlayForScreen(modelData))) ? WlrLayershell.Overlay : WlrLayershell.Top
WlrLayershell.exclusiveZone: 0
WlrLayershell.keyboardFocus: isVisible ? WlrKeyboardFocus.OnDemand : WlrKeyboardFocus.None