diff --git a/quickshell/Modals/Clipboard/ClipboardConstants.qml b/quickshell/Modals/Clipboard/ClipboardConstants.qml index 54a701bdc..c3c91baee 100644 --- a/quickshell/Modals/Clipboard/ClipboardConstants.qml +++ b/quickshell/Modals/Clipboard/ClipboardConstants.qml @@ -17,7 +17,6 @@ Singleton { readonly property int retryInterval: 50 readonly property int viewportBuffer: 100 readonly property int extendedBuffer: 200 - readonly property int keyboardHintsHeight: 80 readonly property int headerHeight: 32 function sizeWidth(size) { diff --git a/quickshell/Modals/Clipboard/ClipboardContent.qml b/quickshell/Modals/Clipboard/ClipboardContent.qml index d5f768739..800103eee 100644 --- a/quickshell/Modals/Clipboard/ClipboardContent.qml +++ b/quickshell/Modals/Clipboard/ClipboardContent.qml @@ -214,7 +214,7 @@ Item { anchors.bottom: parent.bottom anchors.leftMargin: PopoutMetrics.contentPadding anchors.rightMargin: PopoutMetrics.contentPadding - anchors.bottomMargin: (modal.showKeyboardHints ? (ClipboardConstants.keyboardHintsHeight + PopoutMetrics.contentPadding * 2) : 0) + Theme.spacingXS + anchors.bottomMargin: (keyboardHintsLoader.item ? keyboardHintsLoader.item.implicitHeight + PopoutMetrics.contentPadding * 2 : 0) + Theme.spacingXS clip: true DankListView { @@ -299,7 +299,7 @@ Item { anchors.rightMargin: PopoutMetrics.contentPadding anchors.bottomMargin: active ? PopoutMetrics.contentPadding : 0 active: modal.showKeyboardHints - height: active ? ClipboardConstants.keyboardHintsHeight : 0 + height: item ? item.implicitHeight : 0 Behavior on height { NumberAnimation { diff --git a/quickshell/Modals/Clipboard/ClipboardKeyboardHints.qml b/quickshell/Modals/Clipboard/ClipboardKeyboardHints.qml index 929b587e3..c813db0cd 100644 --- a/quickshell/Modals/Clipboard/ClipboardKeyboardHints.qml +++ b/quickshell/Modals/Clipboard/ClipboardKeyboardHints.qml @@ -7,14 +7,9 @@ Rectangle { property bool pasteAvailable: false property bool enterToPaste: false - readonly property string navigationHintsText: (enterToPaste ? I18n.tr("↑/↓: Navigate • Enter: Paste • Ctrl+C: Copy • Del: Delete • Ctrl+E: Edit • Ctrl+S: Pin/Unpin • F10: Help", "Keyboard hints when enter-to-paste is enabled") : I18n.tr("↑/↓: Navigate • Enter/Ctrl+C: Copy • Del: Delete • Ctrl+E: Edit • Ctrl+S: Pin/Unpin • F10: Help")) + " • Ctrl+Space: " + I18n.tr("Preview") - readonly property string hintsText: { - if (!pasteAvailable) - return I18n.tr("Ctrl+Tab: Switch Tab • Ctrl+S: Pin/Unpin • Shift+Del: Clear All • Esc: Close"); - return enterToPaste ? I18n.tr("Ctrl+Tab: Switch Tabs • Ctrl+S: Pin/Unpin • Shift+Enter: Copy • Shift+Del: Clear All • F10: Help • Esc: Close", "Keyboard hints when enter-to-paste is enabled") : I18n.tr("Ctrl+Tab: Switch Tabs • Ctrl+S: Pin/Unpin • Shift+Enter: Paste • Shift+Del: Clear All • F10: Help • Esc: Close"); - } + readonly property bool enterPastes: pasteAvailable && enterToPaste - height: ClipboardConstants.keyboardHintsHeight + implicitHeight: hints.implicitHeight + Theme.spacingM * 2 radius: Theme.cornerRadius color: Theme.floatingWindowNestedSurface border.color: Theme.primary @@ -22,29 +17,63 @@ Rectangle { opacity: visible ? 1 : 0 z: 100 - Column { - width: parent.width - Theme.spacingL * 2 - anchors.centerIn: parent - spacing: Theme.spacingXXS + DankKeyHints { + id: hints - StyledText { - text: keyboardHints.navigationHintsText - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceText - width: parent.width - wrapMode: Text.WordWrap - horizontalAlignment: Text.AlignHCenter - anchors.horizontalCenter: parent.horizontalCenter - } - - StyledText { - text: keyboardHints.hintsText - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceText - width: parent.width - wrapMode: Text.WordWrap - horizontalAlignment: Text.AlignHCenter - anchors.horizontalCenter: parent.horizontalCenter + anchors.verticalCenter: parent.verticalCenter + anchors.left: parent.left + anchors.right: parent.right + anchors.margins: Theme.spacingM + hints: { + const pasteHints = keyboardHints.pasteAvailable ? [ + { + keys: keyboardHints.enterPastes ? ["Return"] : ["Shift+Return"], + label: I18n.tr("Paste") + } + ] : []; + return [ + { + keys: ["Up", "Down"], + label: I18n.tr("Navigate", "verb, keyboard shortcut hint for arrow keys") + }, + { + keys: keyboardHints.enterPastes ? ["Ctrl+C", "Shift+Return"] : ["Return", "Ctrl+C"], + label: I18n.tr("Copy") + } + ].concat(pasteHints, [ + { + keys: ["Ctrl+Space"], + label: I18n.tr("Preview", "verb, clipboard entry action button tooltip", true) + }, + { + keys: ["Ctrl+E"], + label: I18n.tr("Edit") + }, + { + keys: ["Ctrl+S"], + label: I18n.tr("Pin", "verb, keep an item pinned in place") + }, + { + keys: ["Delete"], + label: I18n.tr("Delete") + }, + { + keys: ["Shift+Delete"], + label: I18n.tr("Clear All") + }, + { + keys: ["Ctrl+Tab"], + label: I18n.tr("Tabs") + }, + { + keys: ["F10"], + label: I18n.tr("Help") + }, + { + keys: ["Escape"], + label: I18n.tr("Close") + } + ]); } } diff --git a/quickshell/Modals/MuxModal.qml b/quickshell/Modals/MuxModal.qml index 3d173bbd0..9c74df39b 100644 --- a/quickshell/Modals/MuxModal.qml +++ b/quickshell/Modals/MuxModal.qml @@ -558,73 +558,40 @@ DankModal { } } - // Shortcuts bar - Row { + DankKeyHints { id: shortcutsBar + width: parent.width - spacing: Theme.spacingM - bottomPadding: Theme.spacingS - - Repeater { - model: { - var shortcuts = [ - { - key: "↑↓", - label: I18n.tr("Navigate", "verb, keyboard shortcut hint for arrow keys") - }, - { - key: "↵", - label: I18n.tr("Attach", "verb, shortcut hint, attach to the selected multiplexer session") - }, - { - key: "^N", - label: I18n.tr("New", "adjective, shortcut or button that creates a new session or note") - }, - { - key: "^D", - label: I18n.tr("Kill") - }, - { - key: "Esc", - label: I18n.tr("Close") - } - ]; - if (MuxService.supportsRename) - shortcuts.splice(3, 0, { - key: "^R", - label: I18n.tr("Rename") - }); - return shortcuts; - } - - delegate: Row { - required property var modelData - spacing: Theme.spacingXS - - Rectangle { - width: keyText.width + Theme.spacingS - height: keyText.height + 4 - radius: Theme.cornerRadiusXS - color: Theme.foregroundColor(Theme.chipSurface, Theme.isFloatingWindow(root)) - anchors.verticalCenter: parent.verticalCenter - - StyledText { - id: keyText - anchors.centerIn: parent - text: modelData.key - font.pixelSize: Theme.fontSizeSmall - 1 - font.weight: Theme.fontWeightMedium - color: Theme.surfaceVariantText - } + height: implicitHeight + Theme.spacingS + hints: { + const shortcuts = [ + { + keys: ["Up", "Down"], + label: I18n.tr("Navigate", "verb, keyboard shortcut hint for arrow keys") + }, + { + keys: ["Return"], + label: I18n.tr("Attach", "verb, shortcut hint, attach to the selected multiplexer session") + }, + { + keys: ["Ctrl+N"], + label: I18n.tr("New", "adjective, shortcut or button that creates a new session or note") + }, + { + keys: ["Ctrl+D"], + label: I18n.tr("Kill") + }, + { + keys: ["Escape"], + label: I18n.tr("Close") } - - StyledText { - text: modelData.label - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceVariantText - anchors.verticalCenter: parent.verticalCenter - } - } + ]; + if (MuxService.supportsRename) + shortcuts.splice(3, 0, { + keys: ["Ctrl+R"], + label: I18n.tr("Rename") + }); + return shortcuts; } } } diff --git a/quickshell/Modals/NotificationModal.qml b/quickshell/Modals/NotificationModal.qml index 14bfd2d31..8a59c3f57 100644 --- a/quickshell/Modals/NotificationModal.qml +++ b/quickshell/Modals/NotificationModal.qml @@ -270,6 +270,7 @@ DankModal { anchors.right: parent.right anchors.margins: Theme.spacingL showHints: notificationHeader.currentTab === 0 ? modalKeyboardController.showKeyboardHints : historyList.showKeyboardHints + historyTab: notificationHeader.currentTab === 1 } } } diff --git a/quickshell/Modules/ControlCenter/ControlCenterContent.qml b/quickshell/Modules/ControlCenter/ControlCenterContent.qml index 03d526b82..032280cb0 100644 --- a/quickshell/Modules/ControlCenter/ControlCenterContent.qml +++ b/quickshell/Modules/ControlCenter/ControlCenterContent.qml @@ -46,10 +46,9 @@ FocusScope { readonly property int gridColumnCap: host.gridColumnCap ?? CcMetrics.columnCapFor((host.triggerScreen?.width ?? CcMetrics.sheetWidthDefault + Theme.spacingL * 2) - Theme.spacingL * 2) readonly property int gridColumns: host.gridColumns ?? Math.min(CcMetrics.gridColumns, gridColumnCap) readonly property real availableGridHeight: (host.availableHeight ?? (host.triggerScreen?.height ?? CcMetrics.fallbackScreenHeight) - CcMetrics.maxHeightInset) - CcMetrics.sheetPadding * 2 - chromeHeight - readonly property real editGutter: host.editGutter ?? 0 + readonly property vector4d chromeRoom: host.chromeRoom ?? Qt.vector4d(Infinity, Infinity, Infinity, Infinity) readonly property DankPanelResizer panelResizer: DankPanelResizer { popout: root.host - gutter: root.editGutter stepWidth: CcMetrics.columnWidth + CcMetrics.gridGap widthFor: columns => CcMetrics.sheetWidthFor(columns) + root.sheetContentWidth - CcMetrics.sheetWidthFor(root.gridColumns) currentStep: () => root.gridColumns @@ -227,14 +226,14 @@ FocusScope { readonly property real screenHeight: root.host.triggerScreen?.height ?? Infinity function ringOffset(room) { - return Math.max(0, Math.min(Theme.spacingS, room - Theme.outlineWidthFocused)); + return Math.min(Theme.spacingS, room - handleThickness / 2 - Theme.outlineWidthFocused); } anchors.fill: parent - anchors.leftMargin: -(contentInset + ringOffset(root.host.alignedX)) - anchors.rightMargin: -(contentInset + ringOffset(screenWidth - root.host.alignedX - root.width)) - anchors.topMargin: -(contentInset + ringOffset(root.host.alignedY)) - anchors.bottomMargin: -(contentInset + ringOffset(screenHeight - root.host.alignedY - root.height)) + anchors.leftMargin: -(contentInset + ringOffset(Math.min(root.host.alignedX, root.chromeRoom.x))) + anchors.rightMargin: -(contentInset + ringOffset(Math.min(screenWidth - root.host.alignedX - root.width, root.chromeRoom.z))) + anchors.topMargin: -(contentInset + ringOffset(Math.min(root.host.alignedY, root.chromeRoom.y))) + anchors.bottomMargin: -(contentInset + ringOffset(Math.min(screenHeight - root.host.alignedY - root.height, root.chromeRoom.w))) z: 1 visible: root.host.editMode enabled: detailPage.shownSection === "" && !root.widgetSheetOpen @@ -298,7 +297,7 @@ FocusScope { id: mainColumn width: root.sheetContentWidth - CcMetrics.sheetPadding * 2 - x: CcMetrics.sheetPadding + root.editGutter + x: CcMetrics.sheetPadding y: CcMetrics.sheetPadding spacing: Theme.spacingS @@ -349,7 +348,7 @@ FocusScope { CcFooter { id: footer - x: CcMetrics.sheetPadding + root.editGutter + x: CcMetrics.sheetPadding width: root.sheetContentWidth - CcMetrics.sheetPadding * 2 anchors.bottom: parent.bottom anchors.bottomMargin: CcMetrics.sheetPadding diff --git a/quickshell/Modules/ControlCenter/Widgets/BrightnessSliderRow.qml b/quickshell/Modules/ControlCenter/Widgets/BrightnessSliderRow.qml index 2a18d33a9..dd37b2871 100644 --- a/quickshell/Modules/ControlCenter/Widgets/BrightnessSliderRow.qml +++ b/quickshell/Modules/ControlCenter/Widgets/BrightnessSliderRow.qml @@ -49,7 +49,6 @@ CcSliderRow { sliderEnabled: BrightnessService.brightnessAvailable && targetDeviceName.length > 0 minimum: BrightnessService.brightnessMinimum(targetDevice) maximum: BrightnessService.brightnessMaximum(targetDevice) - unit: BrightnessService.brightnessUnit(targetDevice) onIconClicked: expandClicked() diff --git a/quickshell/Modules/ControlCenter/Widgets/CcSliderRow.qml b/quickshell/Modules/ControlCenter/Widgets/CcSliderRow.qml index d413a46b4..5ab7229bb 100644 --- a/quickshell/Modules/ControlCenter/Widgets/CcSliderRow.qml +++ b/quickshell/Modules/ControlCenter/Widgets/CcSliderRow.qml @@ -24,7 +24,6 @@ Item { property alias slider: slider property alias minimum: slider.minimum property alias maximum: slider.maximum - property alias unit: slider.unit property alias valueOverride: slider.valueOverride property alias wheelStep: slider.wheelStep property bool sliderEnabled: true @@ -71,7 +70,7 @@ Item { iconSize: CcMetrics.iconBoxIconSize iconColor: CcMetrics.tileInactiveContent enabled: root.sliderEnabled && root.interactive - tooltipText: root.iconTooltip + tooltipText: root.iconTooltip || root.iconLabel Accessible.name: root.iconLabel onClicked: root.iconClicked() } diff --git a/quickshell/Modules/DankIsland/Activities/ControlCenterExpanded.qml b/quickshell/Modules/DankIsland/Activities/ControlCenterExpanded.qml index 8be4d5ad5..c83321ded 100644 --- a/quickshell/Modules/DankIsland/Activities/ControlCenterExpanded.qml +++ b/quickshell/Modules/DankIsland/Activities/ControlCenterExpanded.qml @@ -56,7 +56,7 @@ FocusScope { onEditModeChanged: root.controller.setEditing("controlcenter", editMode) - readonly property real editGutter: editMode ? PopoutMetrics.editOverflow : 0 + readonly property vector4d chromeRoom: Qt.vector4d(root.sideInset, Theme.spacingXS, root.sideInset, root.bottomInset) readonly property int gridColumnCap: root.controller.controlCenterColumnCap readonly property int gridColumns: root.controller.controlCenterColumns readonly property real availableHeight: root.controller.controlCenterMaxHeight - Theme.spacingXS - root.bottomInset diff --git a/quickshell/Modules/DankIsland/Activities/DashTabFace.qml b/quickshell/Modules/DankIsland/Activities/DashTabFace.qml index 010f5d05c..6bc3ef4be 100644 --- a/quickshell/Modules/DankIsland/Activities/DashTabFace.qml +++ b/quickshell/Modules/DankIsland/Activities/DashTabFace.qml @@ -22,14 +22,10 @@ FocusScope { readonly property real tabHeight: tab?.implicitHeight ?? 0 readonly property real contentHeight: DashMetrics.panelHeightFor(entryId, tabHeight) readonly property bool handleHeader: !root.editMode - readonly property real chromeHeight: header.anchors.topMargin + header.height + pages.anchors.topMargin + pages.anchors.bottomMargin - readonly property real editGutter: editMode ? PopoutMetrics.editOverflow : 0 - // Mirrors the popout: the frame sits panelChromeInset inside the sheet, the header sits contentPadding - // below it, and the cards keep clear of the corner grips by the gutter. readonly property real editHeaderInset: PopoutMetrics.panelChromeInset + DashMetrics.contentPadding readonly property real editBottomInset: PopoutMetrics.panelChromeInset + PopoutMetrics.editOverflow - // Card pills overhang their card by half their height; the header row needs the same clearance below as above. - readonly property real editHeaderGap: PopoutMetrics.chromeButtonSize / 2 + DashMetrics.contentPadding + // Card pills overhang their card by half their height and must stay inside the pages clip. + readonly property real pillOverhang: editMode ? PopoutMetrics.chromeButtonSize / 2 : 0 readonly property int panelColumns: DashMetrics.panelColumnsFor(entryId) readonly property int contentRows: DashMetrics.rowsForHeight(tabHeight) readonly property int panelRows: Math.max(DashMetrics.panelFloorRowsFor(entryId), contentRows) @@ -45,7 +41,6 @@ FocusScope { readonly property DankPanelResizer panelResizer: DankPanelResizer { popout: root.resizeHost - gutter: root.editGutter stepWidth: DashMetrics.preferredColumnWidth + DashMetrics.gridGap widthFor: columns => Math.min(root.controller.dashboardAvailableWidth, DashMetrics.widthFor(SettingsData.showWeekNumber, undefined, columns)) currentStep: () => root.panelColumns @@ -94,11 +89,10 @@ FocusScope { } function reportHeight() { - root.controller.setDashboardContentHeight(root.activityId, root.contentHeight + root.chromeHeight); + root.controller.setDashboardContentHeight(root.activityId, root.contentHeight + DashMetrics.islandHandleChromeHeight); } onContentHeightChanged: reportHeight() - onChromeHeightChanged: reportHeight() onLiveChanged: { if (live) return; @@ -154,8 +148,8 @@ FocusScope { left: parent.left right: parent.right topMargin: root.editMode ? root.editHeaderInset : 0 - leftMargin: DashMetrics.contentPadding + root.editGutter - rightMargin: DashMetrics.contentPadding + root.editGutter + leftMargin: DashMetrics.contentPadding + rightMargin: DashMetrics.contentPadding } height: root.handleHeader ? DashMetrics.islandHandleHeight : DashMetrics.editHeaderHeight @@ -193,21 +187,22 @@ FocusScope { showScrollBar: false anchors { top: header.bottom - topMargin: root.editMode ? root.editHeaderGap : 0 + topMargin: root.editMode ? DashMetrics.contentPadding : 0 left: parent.left right: parent.right bottom: parent.bottom - leftMargin: DashMetrics.contentPadding + root.editGutter - rightMargin: DashMetrics.contentPadding + root.editGutter + leftMargin: DashMetrics.contentPadding + rightMargin: DashMetrics.contentPadding bottomMargin: root.editMode ? root.editBottomInset : DashMetrics.contentPadding } - contentHeight: tabLoader.height + contentHeight: tabLoader.y + tabLoader.height clip: contentHeight > height Loader { id: tabLoader + y: root.pillOverhang width: pages.width - height: Math.max(pages.height, root.tabHeight) + height: Math.max(pages.height - y, root.tabHeight) active: root.contentStaged asynchronous: true visible: status === Loader.Ready diff --git a/quickshell/Modules/DankIsland/IslandController.qml b/quickshell/Modules/DankIsland/IslandController.qml index 0432a093c..e40ac2769 100644 --- a/quickshell/Modules/DankIsland/IslandController.qml +++ b/quickshell/Modules/DankIsland/IslandController.qml @@ -74,7 +74,7 @@ QtObject { readonly property int controlCenterColumnCap: CcMetrics.columnCapFor(dashboardAvailableWidth - controlCenterSheetInset - PopoutMetrics.editOverflow * 2) readonly property int controlCenterColumns: Math.min(CcMetrics.gridColumns, controlCenterColumnCap) readonly property real controlCenterSheetWidth: CcMetrics.sheetWidthFor(controlCenterColumns) - readonly property real controlCenterMaxWidth: CcMetrics.sheetWidthFor(editingActivity === "controlcenter" ? controlCenterColumnCap : controlCenterColumns) + controlCenterSheetInset + PopoutMetrics.editOverflow * 2 + readonly property real controlCenterMaxWidth: CcMetrics.sheetWidthFor(editingActivity === "controlcenter" ? controlCenterColumnCap : controlCenterColumns) + controlCenterSheetInset readonly property real controlCenterHeight: Math.max(320, Math.min(controlCenterMaxHeight, destinationContentHeight("controlcenter"))) readonly property bool compactDense: compactThickness < 40 @@ -92,7 +92,7 @@ QtObject { property real dashboardAvailableWidth: 1920 property real dashboardAvailableHeight: 1080 readonly property int dashboardColumnCap: DashMetrics.columnCapFor(dashboardAvailableWidth - PopoutMetrics.editOverflow * 2, SettingsData.showWeekNumber) - readonly property real dashboardMaxWidth: Math.min(dashboardAvailableWidth, DashMetrics.widthFor(SettingsData.showWeekNumber, undefined, editingActivity !== "" ? dashboardColumnCap : DashRegistry.widestPanelColumns) + PopoutMetrics.editOverflow * 2) + readonly property real dashboardMaxWidth: Math.min(dashboardAvailableWidth, DashMetrics.widthFor(SettingsData.showWeekNumber, undefined, editingActivity !== "" ? dashboardColumnCap : DashRegistry.widestPanelColumns)) property var dashboardContentHeights: ({}) readonly property real dashChromeHeight: DashMetrics.islandHandleChromeHeight readonly property real dashboardHeight: Math.min(dashboardAvailableHeight, Math.max(DashMetrics.tabDefaultHeight + root.dashChromeHeight, ...Object.values(dashboardContentHeights))) @@ -144,7 +144,7 @@ QtObject { function dashboardTargetFor(activityId) { const minimum = DashMetrics.panelHeightFor(dashEntryIdFor(activityId)); const height = Math.max(minimum + root.dashChromeHeight, dashboardContentHeights[activityId] ?? 0); - return sheetTarget(dashboardWidthFor(activityId) + editGutterFor(activityId) * 2, Math.min(dashboardAvailableHeight, height)); + return sheetTarget(dashboardWidthFor(activityId), Math.min(dashboardAvailableHeight, height)); } function setMediaContentLength(length) { @@ -247,10 +247,6 @@ QtObject { } } - function editGutterFor(activityId) { - return editingActivity === activityId ? PopoutMetrics.editOverflow : 0; - } - function setDestinationContentHeight(activityId, height) { const entry = destinationState[activityId]; const next = Math.round(height); @@ -431,7 +427,7 @@ QtObject { readonly property var homeExpandedTarget: dashboardTargetFor("home") readonly property var mediaExpandedTarget: dashboardTargetFor("media") readonly property var launcherExpandedTarget: sheetTarget(Math.min(dashboardAvailableWidth, LauncherMetrics.sizeWidth(SettingsData.dankLauncherV2Size)), Math.min(dashboardAvailableHeight, LauncherMetrics.sizeHeight(SettingsData.dankLauncherV2Size))) - readonly property var controlCenterExpandedTarget: sheetTarget(controlCenterSheetWidth + controlCenterSheetInset + editGutterFor("controlcenter") * 2, controlCenterHeight) + readonly property var controlCenterExpandedTarget: sheetTarget(controlCenterSheetWidth + controlCenterSheetInset, controlCenterHeight) readonly property var systemCompactTarget: pillTarget(root.isVertical ? 240 : (SettingsData.osdAlwaysShowValue ? 330 : 282), compactFaceThickness) readonly property var systemExpandedTarget: sheetTarget(460, 176) readonly property var notificationCompactTarget: pillTarget(Math.ceil(Math.max(notificationCompactMinLength, Math.min(notificationCompactMaxLength, notificationContentLength))), compactFaceThickness) diff --git a/quickshell/Modules/Notepad/NotepadSettings.qml b/quickshell/Modules/Notepad/NotepadSettings.qml index 9bd51d219..e2c1fd12e 100644 --- a/quickshell/Modules/Notepad/NotepadSettings.qml +++ b/quickshell/Modules/Notepad/NotepadSettings.qml @@ -492,7 +492,7 @@ Item { StyledRect { width: parent.width - implicitHeight: shortcutsHeader.height + (root.shortcutsExpanded ? shortcutsColumn.implicitHeight + Theme.spacingM : 0) + implicitHeight: shortcutsHeader.height + (shortcutsLoader.item ? shortcutsLoader.height + Theme.spacingM : 0) radius: Theme.cornerRadius color: root.shortcutsExpanded ? Theme.chipSurface : Theme.withAlpha(Theme.chipSurface, 0) border.color: root.shortcutsExpanded ? Theme.primary : Theme.outlineMedium @@ -531,30 +531,48 @@ Item { } } - Column { - id: shortcutsColumn - visible: root.shortcutsExpanded + Loader { + id: shortcutsLoader + active: root.shortcutsExpanded width: parent.width - Theme.spacingL * 2 anchors.top: shortcutsHeader.bottom anchors.horizontalCenter: parent.horizontalCenter - spacing: Theme.spacingXXS - StyledText { - width: parent.width - text: I18n.tr("Ctrl+S: Save • Ctrl+O: Open • Ctrl+N: New • Ctrl+F: Find") - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceText - wrapMode: Text.WordWrap - horizontalAlignment: Text.AlignHCenter - } - - StyledText { - width: parent.width - text: I18n.tr("Ctrl+A: Select All • Ctrl+P: Preview • Enter/Shift+Enter: Find Next/Previous • Esc: Close") - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceText - wrapMode: Text.WordWrap - horizontalAlignment: Text.AlignHCenter + sourceComponent: DankKeyHints { + hints: [ + { + keys: ["Ctrl+S"], + label: I18n.tr("Save") + }, + { + keys: ["Ctrl+O"], + label: I18n.tr("Open") + }, + { + keys: ["Ctrl+N"], + label: I18n.tr("New", "adjective, shortcut or button that creates a new session or note") + }, + { + keys: ["Ctrl+F"], + label: I18n.tr("Search", "search field placeholder") + }, + { + keys: ["Return"], + label: I18n.tr("Next") + }, + { + keys: ["Shift+Return"], + label: I18n.tr("Previous") + }, + { + keys: ["Ctrl+P"], + label: I18n.tr("Preview", "verb, clipboard entry action button tooltip", true) + }, + { + keys: ["Escape"], + label: I18n.tr("Close") + } + ] } } } diff --git a/quickshell/Modules/Notifications/Center/NotificationCenterContent.qml b/quickshell/Modules/Notifications/Center/NotificationCenterContent.qml index 91154c364..634dd8aac 100644 --- a/quickshell/Modules/Notifications/Center/NotificationCenterContent.qml +++ b/quickshell/Modules/Notifications/Center/NotificationCenterContent.qml @@ -144,6 +144,7 @@ Item { anchors.right: parent.right anchors.margins: PopoutMetrics.contentPadding showHints: notificationHeader.currentTab === 0 ? (root.externalKeyboardController?.showKeyboardHints ?? false) : historyList.showKeyboardHints + historyTab: notificationHeader.currentTab === 1 z: 200 } } diff --git a/quickshell/Modules/Notifications/Center/NotificationKeyboardHints.qml b/quickshell/Modules/Notifications/Center/NotificationKeyboardHints.qml index 0ec3e7c86..73f2a115f 100644 --- a/quickshell/Modules/Notifications/Center/NotificationKeyboardHints.qml +++ b/quickshell/Modules/Notifications/Center/NotificationKeyboardHints.qml @@ -7,38 +7,70 @@ Rectangle { id: root property bool showHints: false + property bool historyTab: false - height: Theme.listItemTwoLineHeight + Theme.spacingS + implicitHeight: hintsLoader.height + Theme.spacingM * 2 radius: NotificationMetrics.menuRadius color: Theme.foregroundColor(Theme.cardSurface, Theme.isFloatingWindow(root)) border.color: Theme.primary border.width: Theme.outlineWidthFocused opacity: showHints ? 1 : 0 + visible: opacity > 0 z: 100 - Column { + Loader { + id: hintsLoader + anchors.verticalCenter: parent.verticalCenter anchors.left: parent.left anchors.right: parent.right - anchors.margins: Theme.spacingS - spacing: Theme.spacingXXS + anchors.margins: Theme.spacingM + active: root.visible - StyledText { - text: I18n.tr("↑/↓: Nav • Space: Expand • Enter: Action/Expand • E: Text") - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceText - width: parent.width - wrapMode: Text.WordWrap - horizontalAlignment: Text.AlignHCenter - } - - StyledText { - text: I18n.tr("Del: Clear • Shift+Del: Clear All • 1-9: Actions • F10: Help • Esc: Close") - font.pixelSize: Theme.fontSizeSmall - color: Theme.surfaceText - width: parent.width - wrapMode: Text.WordWrap - horizontalAlignment: Text.AlignHCenter + sourceComponent: DankKeyHints { + hints: { + const listHints = root.historyTab ? [] : [ + { + keys: ["Space"], + label: I18n.tr("Expand") + }, + { + keys: ["Return"], + label: I18n.tr("Open") + }, + { + keys: ["E"], + label: I18n.tr("Text") + }, + { + keys: ["1-9"], + label: I18n.tr("Actions") + } + ]; + return [ + { + keys: ["Up", "Down"], + label: I18n.tr("Navigate", "verb, keyboard shortcut hint for arrow keys") + } + ].concat(listHints, [ + { + keys: ["Delete"], + label: I18n.tr("Clear") + }, + { + keys: ["Shift+Delete"], + label: I18n.tr("Clear All") + }, + { + keys: ["F10"], + label: I18n.tr("Help") + }, + { + keys: ["Escape"], + label: I18n.tr("Close") + } + ]); + } } } diff --git a/quickshell/Widgets/DankGridEditChrome.qml b/quickshell/Widgets/DankGridEditChrome.qml index 699f05505..2a7299b5a 100644 --- a/quickshell/Widgets/DankGridEditChrome.qml +++ b/quickshell/Widgets/DankGridEditChrome.qml @@ -24,6 +24,7 @@ Item { property real cornerRadius: Theme.cornerRadiusXL property real buttonSize: Theme.iconSizeLarge property real iconSize: Theme.iconSizeSmall + readonly property real handleThickness: Theme.spacingM readonly property real touchTargetSize: Math.max(Theme.minimumTouchTargetSize, buttonSize) readonly property real contentInset: touchTargetSize / 2 readonly property bool showOptionsButton: hasOptions && width - contentInset * 2 >= touchTargetSize * (1 + (removable ? 1 : 0) + (horizontalResize ? 1 : 0)) @@ -185,7 +186,7 @@ Item { Rectangle { anchors.centerIn: parent - width: Theme.spacingM + width: root.handleThickness height: root.buttonSize radius: Theme.fullRadius(width, height) color: Theme.primary diff --git a/quickshell/Widgets/DankKeyHints.qml b/quickshell/Widgets/DankKeyHints.qml new file mode 100644 index 000000000..7f1cb255b --- /dev/null +++ b/quickshell/Widgets/DankKeyHints.qml @@ -0,0 +1,87 @@ +import QtQuick +import qs.Common +import "../Common/KeyUtils.js" as KeyUtils + +Item { + id: root + + property var hints: [] + + readonly property real widestHint: { + let widest = 0; + for (let i = 0; i < grid.children.length; i++) + widest = Math.max(widest, grid.children[i].implicitWidth); + return widest; + } + + implicitHeight: grid.height + LayoutMirroring.enabled: I18n.isRtl + LayoutMirroring.childrenInherit: true + + Grid { + id: grid + + anchors.horizontalCenter: parent.horizontalCenter + columns: Math.max(1, Math.min(root.hints.length, Math.floor((root.width + columnSpacing) / (root.widestHint + columnSpacing)))) + columnSpacing: Theme.spacingL + rowSpacing: Theme.spacingXS + verticalItemAlignment: Grid.AlignVCenter + + Repeater { + model: root.hints + + Row { + id: hint + + required property var modelData + + spacing: Theme.spacingS + + Row { + anchors.verticalCenter: parent.verticalCenter + spacing: Theme.spacingXXS + LayoutMirroring.enabled: false + LayoutMirroring.childrenInherit: true + + Repeater { + model: hint.modelData.keys + + Row { + id: combo + + required property string modelData + required property int index + + spacing: Theme.spacingXXS + + StyledText { + anchors.verticalCenter: parent.verticalCenter + visible: combo.index > 0 + text: "/" + font.pixelSize: Theme.fontSizeSmall + color: Theme.surfaceVariantText + } + + Repeater { + model: KeyUtils.formatKeyTokens(combo.modelData) + + DankKeycap { + required property string modelData + + text: modelData + } + } + } + } + } + + StyledText { + anchors.verticalCenter: parent.verticalCenter + text: hint.modelData.label + font.pixelSize: Theme.fontSizeSmall + color: Theme.surfaceVariantText + } + } + } + } +}