From 71c1fbe1dd3a8c01308fd4f920756ce118e48c36 Mon Sep 17 00:00:00 2001 From: end-4 <97237370+end-4@users.noreply.github.com> Date: Wed, 3 Dec 2025 23:23:08 +0100 Subject: [PATCH] waffles: start: more search progress --- .../ii/modules/waffle/looks/Looks.qml | 3 +- .../ii/modules/waffle/looks/WChoiceButton.qml | 1 + .../ii/modules/waffle/looks/WMenu.qml | 83 ++++++++++------- .../modules/waffle/looks/WPanelIconButton.qml | 13 ++- .../ii/modules/waffle/looks/WTextInput.qml | 1 + .../ii/modules/waffle/startMenu/SearchBar.qml | 24 +++-- .../waffle/startMenu/SearchPageContent.qml | 22 ++++- .../waffle/startMenu/SearchResults.qml | 60 ++++++++++++ .../waffle/startMenu/StartMenuContent.qml | 31 +++++-- .../waffle/startMenu/StartPageContent.qml | 2 +- .../ii/modules/waffle/startMenu/TagStrip.qml | 92 +++++++++++++++++++ .../waffle/startMenu/WSearchResultButton.qml | 81 ++++++++++++++++ 12 files changed, 356 insertions(+), 57 deletions(-) create mode 100644 dots/.config/quickshell/ii/modules/waffle/startMenu/SearchResults.qml create mode 100644 dots/.config/quickshell/ii/modules/waffle/startMenu/TagStrip.qml create mode 100644 dots/.config/quickshell/ii/modules/waffle/startMenu/WSearchResultButton.qml diff --git a/dots/.config/quickshell/ii/modules/waffle/looks/Looks.qml b/dots/.config/quickshell/ii/modules/waffle/looks/Looks.qml index 609c9877b..b9cbc00bd 100644 --- a/dots/.config/quickshell/ii/modules/waffle/looks/Looks.qml +++ b/dots/.config/quickshell/ii/modules/waffle/looks/Looks.qml @@ -64,7 +64,7 @@ Singleton { property color bg0: "#1C1C1C" property color bg0Border: "#404040" property color bg1Base: "#2C2C2C" - property color bg1: "#a8a8a8" + property color bg1: '#9f9f9f' property color bg1Hover: "#b3b3b3" property color bg1Active: '#727272' property color bg1Border: '#bebebe' @@ -125,6 +125,7 @@ Singleton { property color accentUnfocused: root.dark ? root.darkColors.accentUnfocused : root.lightColors.accentUnfocused property color accentFg: ColorUtils.isDark(accent) ? "#FFFFFF" : "#000000" property color selection: Appearance.colors.colPrimaryContainer + property color selectionFg: Appearance.colors.colOnPrimaryContainer } radius: QtObject { diff --git a/dots/.config/quickshell/ii/modules/waffle/looks/WChoiceButton.qml b/dots/.config/quickshell/ii/modules/waffle/looks/WChoiceButton.qml index eff776601..14691c716 100644 --- a/dots/.config/quickshell/ii/modules/waffle/looks/WChoiceButton.qml +++ b/dots/.config/quickshell/ii/modules/waffle/looks/WChoiceButton.qml @@ -44,6 +44,7 @@ WButton { radius: Looks.radius.medium color: root.color Behavior on color { + enabled: root.animateChoiceHighlight animation: Looks.transition.color.createObject(this) } diff --git a/dots/.config/quickshell/ii/modules/waffle/looks/WMenu.qml b/dots/.config/quickshell/ii/modules/waffle/looks/WMenu.qml index a208f355b..a18c59ec9 100644 --- a/dots/.config/quickshell/ii/modules/waffle/looks/WMenu.qml +++ b/dots/.config/quickshell/ii/modules/waffle/looks/WMenu.qml @@ -14,17 +14,18 @@ Menu { property bool downDirection: false property bool hasIcons: false // TODO: implement - implicitWidth: background.implicitWidth + root.padding * 2 - implicitHeight: background.implicitHeight + root.padding * 2 + implicitWidth: background.implicitWidth + margins * 2 + implicitHeight: background.implicitHeight + margins * 2 + margins: 10 padding: 3 property real sourceEdgeMargin: -implicitHeight clip: true - + enter: Transition { NumberAnimation { property: "sourceEdgeMargin" from: -root.implicitHeight - to: root.padding + to: root.margins duration: 200 easing.type: Easing.BezierSpline easing.bezierCurve: Looks.transition.easing.bezierCurve.easeIn @@ -33,7 +34,7 @@ Menu { exit: Transition { NumberAnimation { property: "sourceEdgeMargin" - from: root.padding + from: root.margins to: -root.implicitHeight duration: 150 easing.type: Easing.BezierSpline @@ -41,43 +42,55 @@ Menu { } } - background: WPane { - anchors { - left: parent.left - right: parent.right - top: root.downDirection ? parent.top : undefined - bottom: root.downDirection ? undefined : parent.bottom - margins: root.padding - topMargin: root.downDirection ? root.sourceEdgeMargin : root.padding - bottomMargin: root.downDirection ? root.padding : root.sourceEdgeMargin - } - contentItem: Rectangle { - color: Looks.colors.bg1Base - implicitWidth: menuListView.implicitWidth + root.padding * 2 - implicitHeight: root.contentItem.implicitHeight + root.padding * 2 + background: Item { + id: bgItem + implicitWidth: bgPane.implicitWidth + implicitHeight: bgPane.implicitHeight + WPane { + id: bgPane + anchors { + left: parent.left + right: parent.right + top: root.downDirection ? parent.top : undefined + bottom: root.downDirection ? undefined : parent.bottom + margins: root.margins + topMargin: root.downDirection ? root.sourceEdgeMargin : root.margins + bottomMargin: root.downDirection ? root.margins : root.sourceEdgeMargin + } + contentItem: Rectangle { + color: Looks.colors.bg1Base + implicitWidth: menuListView.implicitWidth + root.padding * 2 + implicitHeight: root.contentItem.implicitHeight + root.padding * 2 + } + } } - contentItem: ListView { - id: menuListView - anchors { - left: parent.left - right: parent.right - top: root.downDirection ? parent.top : undefined - bottom: root.downDirection ? undefined : parent.bottom - margins: root.padding * 2 - topMargin: root.downDirection ? root.sourceEdgeMargin : root.padding - bottomMargin: root.downDirection ? root.padding : root.sourceEdgeMargin - } - implicitHeight: contentHeight - implicitWidth: Array.from({ - length: count - }, (_, i) => itemAtIndex(i)?.implicitWidth ?? 0).reduce((a, b) => a > b ? a : b) + contentItem: Item { + implicitWidth: menuListView.implicitWidth + implicitHeight: menuListView.implicitHeight + ListView { + id: menuListView + anchors { + left: parent.left + right: parent.right + top: root.downDirection ? parent.top : undefined + bottom: root.downDirection ? undefined : parent.bottom + margins: root.margins // ???? + topMargin: root.downDirection ? root.sourceEdgeMargin : root.margins + bottomMargin: root.downDirection ? root.margins : root.sourceEdgeMargin + } + implicitHeight: contentHeight + implicitWidth: Array.from({ + length: count + }, (_, i) => itemAtIndex(i)?.implicitWidth ?? 0).reduce((a, b) => a > b ? a : b) - model: root.contentModel + model: root.contentModel + } } delegate: WMenuItem { id: menuItemDelegate + width: ListView.view?.width } } diff --git a/dots/.config/quickshell/ii/modules/waffle/looks/WPanelIconButton.qml b/dots/.config/quickshell/ii/modules/waffle/looks/WPanelIconButton.qml index e0e966022..3cdb3abfd 100644 --- a/dots/.config/quickshell/ii/modules/waffle/looks/WPanelIconButton.qml +++ b/dots/.config/quickshell/ii/modules/waffle/looks/WPanelIconButton.qml @@ -10,14 +10,17 @@ WButton { id: root property alias iconName: iconContent.icon + property alias iconSize: iconContent.implicitSize property alias monochrome: iconContent.monochrome implicitWidth: 40 implicitHeight: 40 - contentItem: FluentIcon { - id: iconContent - anchors.centerIn: parent - implicitSize: 18 - icon: root.iconName + contentItem: Item { + FluentIcon { + id: iconContent + anchors.centerIn: parent + implicitSize: 18 + icon: root.iconName + } } } diff --git a/dots/.config/quickshell/ii/modules/waffle/looks/WTextInput.qml b/dots/.config/quickshell/ii/modules/waffle/looks/WTextInput.qml index a3f3e8a40..84bed180d 100644 --- a/dots/.config/quickshell/ii/modules/waffle/looks/WTextInput.qml +++ b/dots/.config/quickshell/ii/modules/waffle/looks/WTextInput.qml @@ -15,4 +15,5 @@ TextInput { } selectionColor: Looks.colors.selection + selectedTextColor: Looks.colors.selectionFg } diff --git a/dots/.config/quickshell/ii/modules/waffle/startMenu/SearchBar.qml b/dots/.config/quickshell/ii/modules/waffle/startMenu/SearchBar.qml index 6bd23ae9b..ce5652329 100644 --- a/dots/.config/quickshell/ii/modules/waffle/startMenu/SearchBar.qml +++ b/dots/.config/quickshell/ii/modules/waffle/startMenu/SearchBar.qml @@ -12,26 +12,36 @@ import qs.modules.waffle.looks FooterRectangle { id: root + property real horizontalPadding: 32 + property real verticalPadding: 16 property bool searching: text.length > 0 property alias text: searchInput.text + implicitHeight: outline.implicitHeight + verticalPadding * 2 Component.onCompleted: searchInput.forceActiveFocus() focus: true color: searching ? Looks.colors.bgPanelBody : Looks.colors.bgPanelFooter - implicitWidth: 832 // TODO: Make sizes naturally inferred - implicitHeight: 63 + Behavior on horizontalPadding { + enabled: Config.options.waffles.tweaks.smootherSearchBar + animation: Looks.transition.move.createObject(this) + } + Behavior on verticalPadding { + enabled: Config.options.waffles.tweaks.smootherSearchBar + animation: Looks.transition.move.createObject(this) + } Rectangle { id: outline anchors { - fill: parent - leftMargin: 32 - rightMargin: 32 - topMargin: 16 - bottomMargin: 15 + left: parent.left + right: parent.right + leftMargin: root.horizontalPadding + rightMargin: root.horizontalPadding + verticalCenter: parent.verticalCenter } + implicitHeight: 32 color: "transparent" radius: height / 2 border.width: 1 diff --git a/dots/.config/quickshell/ii/modules/waffle/startMenu/SearchPageContent.qml b/dots/.config/quickshell/ii/modules/waffle/startMenu/SearchPageContent.qml index cdbb7d3b8..a294950fd 100644 --- a/dots/.config/quickshell/ii/modules/waffle/startMenu/SearchPageContent.qml +++ b/dots/.config/quickshell/ii/modules/waffle/startMenu/SearchPageContent.qml @@ -12,5 +12,25 @@ import qs.modules.waffle.looks BodyRectangle { id: root - + property string searchText: LauncherSearch.query + + ColumnLayout { + anchors { + fill: parent + topMargin: 2 + leftMargin: 24 + rightMargin: 24 + } + spacing: 12 + + TagStrip { + Layout.fillWidth: true + Layout.fillHeight: false + } + + SearchResults { + Layout.fillWidth: true + Layout.fillHeight: true + } + } } diff --git a/dots/.config/quickshell/ii/modules/waffle/startMenu/SearchResults.qml b/dots/.config/quickshell/ii/modules/waffle/startMenu/SearchResults.qml new file mode 100644 index 000000000..5f3d93411 --- /dev/null +++ b/dots/.config/quickshell/ii/modules/waffle/startMenu/SearchResults.qml @@ -0,0 +1,60 @@ +import qs.modules.waffle.looks +import qs.modules.common.functions +import qs.modules.common +import qs.services +import qs +import Quickshell +import QtQuick.Layouts +import QtQuick.Controls +import QtQuick +pragma ComponentBehavior: Bound + +RowLayout { + id: root + + function focusFirstItem() { + resultList.currentIndex = 0; + } + + ResultList { + id: resultList + Layout.fillHeight: true + Layout.fillWidth: true + } + ResultPreview { + Layout.preferredWidth: 386 + Layout.leftMargin: 1 + Layout.rightMargin: 1 + } + + component ResultList: ListView { + section { + criteria: ViewSection.FullString + property: "type" + } + clip: true + spacing: 4 + model: ScriptModel { + values: { + // TODO: categorize and have max per category + LauncherSearch.results.slice(0, 10) + } + onValuesChanged: { + root.focusFirstItem(); + } + } + delegate: WSearchResultButton { + required property int index + required property var modelData + entry: modelData + firstEntry: index === 0 + width: ListView.view?.width + } + } + + component ResultPreview: Rectangle { + Layout.fillHeight: true + color: Looks.colors.bg1 + radius: Looks.radius.large + } +} diff --git a/dots/.config/quickshell/ii/modules/waffle/startMenu/StartMenuContent.qml b/dots/.config/quickshell/ii/modules/waffle/startMenu/StartMenuContent.qml index 6e97f88be..09de017ee 100644 --- a/dots/.config/quickshell/ii/modules/waffle/startMenu/StartMenuContent.qml +++ b/dots/.config/quickshell/ii/modules/waffle/startMenu/StartMenuContent.qml @@ -14,26 +14,43 @@ WBarAttachedPanelContent { id: root property bool searching: false - property string searchText: "" + property string searchText: LauncherSearch.query contentItem: WPane { contentItem: WPanelPageColumn { SearchBar { focus: true Layout.fillWidth: true + implicitWidth: 832 // TODO: Make sizes naturally inferred + horizontalPadding: root.searching ? 24 : 32 + // verticalPadding: root.searching ? 32 : 16 // TODO: make this not nuke the panel Synchronizer on searching { property alias target: root.searching } - Synchronizer on text { - property alias source: root.searchText + text: root.searchText + onTextChanged: { + LauncherSearch.query = text; } } - Loader { - id: pageContentLoader + Item { + implicitHeight: root.searching ? 736 : 736 // TODO: Make sizes naturally inferred Layout.fillWidth: true - source: root.searching ? "SearchPageContent.qml" : "StartPageContent.qml" + Loader { + id: pageContentLoader + anchors.fill: parent + sourceComponent: root.searching ? searchPageComp : startPageComp + } } } } - + + Component { + id: searchPageComp + SearchPageContent {} + } + + Component { + id: startPageComp + StartPageContent {} + } } diff --git a/dots/.config/quickshell/ii/modules/waffle/startMenu/StartPageContent.qml b/dots/.config/quickshell/ii/modules/waffle/startMenu/StartPageContent.qml index eb3c96a80..f2f863cd2 100644 --- a/dots/.config/quickshell/ii/modules/waffle/startMenu/StartPageContent.qml +++ b/dots/.config/quickshell/ii/modules/waffle/startMenu/StartPageContent.qml @@ -17,7 +17,7 @@ WPanelPageColumn { WPanelSeparator {} BodyRectangle { - implicitHeight: 736 // TODO: Make sizes naturally inferred + Layout.fillHeight: true } WPanelSeparator {} diff --git a/dots/.config/quickshell/ii/modules/waffle/startMenu/TagStrip.qml b/dots/.config/quickshell/ii/modules/waffle/startMenu/TagStrip.qml new file mode 100644 index 000000000..10448b5cd --- /dev/null +++ b/dots/.config/quickshell/ii/modules/waffle/startMenu/TagStrip.qml @@ -0,0 +1,92 @@ +pragma ComponentBehavior: Bound +import QtQuick +import QtQuick.Controls +import QtQuick.Layouts +import Quickshell +import qs +import qs.services +import qs.modules.common +import qs.modules.common.functions +import qs.modules.waffle.looks + +RowLayout { + WPanelIconButton { + implicitWidth: 36 + implicitHeight: 36 + iconSize: 24 + iconName: "arrow-left" + onClicked: LauncherSearch.query = "" + } + ListView { + id: tagListView + Layout.fillWidth: true + Layout.fillHeight: true + orientation: Qt.Horizontal + spacing: 4 + model: [ + { + name: Translation.tr("All"), + prefix: "" + }, + { + name: Translation.tr("Apps"), + prefix: Config.options.search.prefix.app + }, + { + name: Translation.tr("Actions"), + prefix: Config.options.search.prefix.action + }, + { + name: Translation.tr("Clipboard"), + prefix: Config.options.search.prefix.clipboard + }, + { + name: Translation.tr("Emojis"), + prefix: Config.options.search.prefix.emojis + }, + { + name: Translation.tr("Math"), + prefix: Config.options.search.prefix.math + }, + { + name: Translation.tr("Commands"), + prefix: Config.options.search.prefix.shellCommand + }, + { + name: Translation.tr("Web"), + prefix: Config.options.search.prefix.webSearch + }, + ] + delegate: WBorderedButton { + id: tagButton + required property var modelData + border.width: 1 + radius: height / 2 + implicitWidth: tagButtonText.implicitWidth + 12 * 2 + implicitHeight: 32 + checked: { + if (modelData.prefix != "") { + return LauncherSearch.query.startsWith(modelData.prefix); + } else { + return !tagListView.model.some(i => (i.prefix != "" && LauncherSearch.query.startsWith(i.prefix))) + } + } + contentItem: Item { + WText { + id: tagButtonText + anchors.centerIn: parent + color: tagButton.fgColor + text: tagButton.modelData.name + font.pixelSize: Looks.font.pixelSize.large + } + } + onClicked: LauncherSearch.ensurePrefix(tagButton.modelData.prefix) + } + } + WPanelIconButton { + implicitWidth: 36 + implicitHeight: 36 + iconSize: 24 + iconName: "more-horizontal" + } +} diff --git a/dots/.config/quickshell/ii/modules/waffle/startMenu/WSearchResultButton.qml b/dots/.config/quickshell/ii/modules/waffle/startMenu/WSearchResultButton.qml new file mode 100644 index 000000000..1aca104b0 --- /dev/null +++ b/dots/.config/quickshell/ii/modules/waffle/startMenu/WSearchResultButton.qml @@ -0,0 +1,81 @@ +import QtQuick +import QtQuick.Layouts +import Quickshell +import qs +import qs.services +import qs.modules.common +import qs.modules.common.models +import qs.modules.common.functions +import qs.modules.common.widgets +import qs.modules.waffle.looks + +WChoiceButton { + id: root + + required property LauncherSearchResult entry + property bool firstEntry: false + + checked: focus + animateChoiceHighlight: false + implicitWidth: contentLayout.implicitWidth + leftPadding + rightPadding + implicitHeight: contentLayout.implicitHeight + topPadding + bottomPadding + + onClicked: { + GlobalStates.searchOpen = false + root.entry.execute() + } + + contentItem: RowLayout { + id: contentLayout + spacing: 8 + + EntryIcon {} + EntryNameColumn { + Layout.fillWidth: true + Layout.alignment: Qt.AlignVCenter + } + } + + component EntryIcon: Item { + implicitWidth: 24 + implicitHeight: 24 + Loader { + anchors.centerIn: parent + active: root.entry.iconType === LauncherSearchResult.IconType.System + sourceComponent: WAppIcon { + implicitSize: 24 + tryCustomIcon: false + iconName: root.entry.iconName + } + } + Loader { + anchors.centerIn: parent + active: root.entry.iconType === LauncherSearchResult.IconType.Text + sourceComponent: WText { + text: root.entry.iconName + font.pixelSize: 24 + horizontalAlignment: Text.AlignHCenter + verticalAlignment: Text.AlignVCenter + } + } + } + + component EntryNameColumn: ColumnLayout { + spacing: 4 + + WText { + Layout.fillWidth: true + wrapMode: Text.Wrap + text: root.entry.name + font.pixelSize: Looks.font.pixelSize.large + maximumLineCount: 2 + } + + WText { + Layout.fillWidth: true + visible: root.firstEntry + text: root.entry.type + color: Looks.colors.accentUnfocused + } + } +}