fix search trickle through actions and variants view and mouse event stealing by wallpapertile
C++ / fmt (pull_request) Successful in 4s
JS/TS / fmt (pull_request) Successful in 7s
JS/TS / lint (pull_request) Successful in 10s
Python / static (pull_request) Successful in 1m6s
Rust / fmt (pull_request) Successful in 1m3s
Rust / build (pull_request) Successful in 2m17s
Rust / clippy (pull_request) Successful in 1m29s
C++ / build (pull_request) Successful in 2m48s
Python / verify (pull_request) Successful in 3m16s
C++ / clang-tidy (pull_request) Successful in 4m17s

This commit is contained in:
2026-08-16 23:13:37 +02:00
parent 43647dd486
commit 69c2bfae9d
4 changed files with 168 additions and 30 deletions
+1
View File
@@ -26,6 +26,7 @@ Singleton {
function query(search: string): list<var> { function query(search: string): list<var> {
search = transformSearch(search); search = transformSearch(search);
console.log(!search, search, ...list);
if (!search) if (!search)
return [...list]; return [...list];
+81 -30
View File
@@ -1,28 +1,36 @@
pragma ComponentBehavior: Bound pragma ComponentBehavior: Bound
import Quickshell
import QtQuick import QtQuick
import qs.Modules.Launcher.Services import Quickshell
import qs.Modules.Launcher.Items
import qs.Components
import ZShell.Config import ZShell.Config
import qs.Components
import qs.Services import qs.Services
import qs.Modules.Launcher.Items
import qs.Modules.Launcher.Services
CustomListView { CustomListView {
id: root id: root
readonly property string displayState: stateForText(displayText)
property string displayText
readonly property string requestedState: stateForText(search.text)
required property SearchBar search required property SearchBar search
required property PersistentProperties visibilities required property PersistentProperties visibilities
highlightFollowsCurrentItem: false function resultsForText(text: string): var {
highlightRangeMode: ListView.ApplyRange switch (stateForText(text)) {
implicitHeight: (Config.launcher.sizes.itemHeight + spacing) * Math.min(Config.launcher.maxAppsShown, count) - spacing case "actions":
orientation: Qt.Vertical return Actions.query(text);
preferredHighlightBegin: 0 case "calc":
preferredHighlightEnd: height return [0];
spacing: Tokens.spacing.small case "variant":
state: { return SchemeVariants.query(text);
const text = search.text; default:
return Apps.search(text);
}
}
function stateForText(text: string): string {
const prefix = Config.launcher.actionPrefix; const prefix = Config.launcher.actionPrefix;
if (text.startsWith(prefix)) { if (text.startsWith(prefix)) {
for (const action of ["calc", "scheme", "variant"]) for (const action of ["calc", "scheme", "variant"])
@@ -34,6 +42,20 @@ CustomListView {
return "apps"; return "apps";
} }
function syncDisplayText(): void {
if (visibilities.launcher && requestedState === displayState)
displayText = search.text;
}
highlightFollowsCurrentItem: false
highlightRangeMode: ListView.ApplyRange
implicitHeight: (Config.launcher.sizes.itemHeight + spacing) * Math.min(Config.launcher.maxAppsShown, count) - spacing
orientation: Qt.Vertical
preferredHighlightBegin: 0
preferredHighlightEnd: height
spacing: Tokens.spacing.small
state: visibilities.launcher ? requestedState : displayState
verticalLayoutDirection: ListView.BottomToTop verticalLayoutDirection: ListView.BottomToTop
CustomScrollBar.vertical: CustomScrollBar { CustomScrollBar.vertical: CustomScrollBar {
@@ -44,19 +66,21 @@ CustomListView {
Anim { Anim {
from: 0 from: 0
properties: "opacity,scale" property: "opacity"
to: 1 to: 1
type: Anim.DefaultEffects
} }
} }
addDisplaced: Transition { addDisplaced: Transition {
Anim { Anim {
duration: Tokens.anim.durations.small
property: "y" property: "y"
type: Anim.StandardSmall
} }
Anim { Anim {
properties: "opacity,scale" property: "opacity"
to: 1 to: 1
type: Anim.DefaultEffects
} }
} }
displaced: Transition { displaced: Transition {
@@ -65,8 +89,9 @@ CustomListView {
} }
Anim { Anim {
properties: "opacity,scale" property: "opacity"
to: 1 to: 1
type: Anim.DefaultEffects
} }
} }
highlight: CustomRect { highlight: CustomRect {
@@ -85,7 +110,7 @@ CustomListView {
} }
} }
model: ScriptModel { model: ScriptModel {
id: model values: root.resultsForText(root.displayText)
onValuesChanged: root.currentIndex = 0 onValuesChanged: root.currentIndex = 0
} }
@@ -95,8 +120,9 @@ CustomListView {
} }
Anim { Anim {
properties: "opacity,scale" property: "opacity"
to: 1 to: 1
type: Anim.DefaultEffects
} }
} }
remove: Transition { remove: Transition {
@@ -104,8 +130,9 @@ CustomListView {
Anim { Anim {
from: 1 from: 1
properties: "opacity,scale" property: "opacity"
to: 0 to: 0
type: Anim.DefaultEffects
} }
} }
states: [ states: [
@@ -113,7 +140,6 @@ CustomListView {
name: "apps" name: "apps"
PropertyChanges { PropertyChanges {
model.values: Apps.search(search.text)
root.delegate: appItem root.delegate: appItem
} }
}, },
@@ -121,7 +147,6 @@ CustomListView {
name: "actions" name: "actions"
PropertyChanges { PropertyChanges {
model.values: Actions.query(search.text)
root.delegate: actionItem root.delegate: actionItem
} }
}, },
@@ -129,7 +154,6 @@ CustomListView {
name: "calc" name: "calc"
PropertyChanges { PropertyChanges {
model.values: [0]
root.delegate: calcItem root.delegate: calcItem
} }
}, },
@@ -137,7 +161,6 @@ CustomListView {
name: "variant" name: "variant"
PropertyChanges { PropertyChanges {
model.values: SchemeVariants.query(search.text)
root.delegate: variantItem root.delegate: variantItem
} }
} }
@@ -147,7 +170,7 @@ CustomListView {
ParallelAnimation { ParallelAnimation {
Anim { Anim {
duration: Tokens.anim.durations.small duration: Tokens.anim.durations.small
easing.bezierCurve: Tokens.anim.curves.expressiveEffects easing.bezierCurve: Tokens.anim.curves.standardAccel
from: 1 from: 1
property: "opacity" property: "opacity"
target: root target: root
@@ -156,7 +179,7 @@ CustomListView {
Anim { Anim {
duration: Tokens.anim.durations.small duration: Tokens.anim.durations.small
easing.bezierCurve: Tokens.anim.curves.expressiveEffects easing.bezierCurve: Tokens.anim.curves.standardAccel
from: 1 from: 1
property: "scale" property: "scale"
target: root target: root
@@ -165,14 +188,24 @@ CustomListView {
} }
PropertyAction { PropertyAction {
properties: "values,delegate" property: "delegate"
targets: [model, root] target: root
value: null
}
ScriptAction {
script: root.displayText = root.search.text
}
PropertyAction {
property: "delegate"
target: root
} }
ParallelAnimation { ParallelAnimation {
Anim { Anim {
duration: Tokens.anim.durations.small duration: Tokens.anim.durations.small
easing.bezierCurve: Tokens.anim.curves.expressiveEffects easing.bezierCurve: Tokens.anim.curves.standardDecel
from: 0 from: 0
property: "opacity" property: "opacity"
target: root target: root
@@ -181,7 +214,7 @@ CustomListView {
Anim { Anim {
duration: Tokens.anim.durations.small duration: Tokens.anim.durations.small
easing.bezierCurve: Tokens.anim.curves.expressiveEffects easing.bezierCurve: Tokens.anim.curves.standardDecel
from: 0.9 from: 0.9
property: "scale" property: "scale"
target: root target: root
@@ -197,6 +230,8 @@ CustomListView {
} }
} }
Component.onCompleted: displayText = search.text
Component { Component {
id: appItem id: appItem
@@ -228,4 +263,20 @@ CustomListView {
list: root list: root
} }
} }
Connections {
function onTextChanged() {
root.syncDisplayText();
}
target: root.search
}
Connections {
function onLauncherChanged() {
root.syncDisplayText();
}
target: root.visibilities
}
} }
@@ -21,6 +21,7 @@ constexpr int kMaxLayoutCapacity = 64;
CarouselView::CarouselView(QQuickItem* parent) : QQuickItem(parent) { CarouselView::CarouselView(QQuickItem* parent) : QQuickItem(parent) {
setAcceptedMouseButtons(Qt::LeftButton); setAcceptedMouseButtons(Qt::LeftButton);
setFiltersChildMouseEvents(true);
setFlag(QQuickItem::ItemHasContents, false); setFlag(QQuickItem::ItemHasContents, false);
setClip(false); setClip(false);
@@ -80,6 +81,89 @@ void CarouselView::setDelegate(QQmlComponent* c) {
relayout(); relayout();
} }
bool CarouselView::childMouseEventFilter(QQuickItem* item, QEvent* event) {
Q_UNUSED(item);
auto* mouseEvent = dynamic_cast<QMouseEvent*>(event);
if (!mouseEvent) return false;
const QPointF pos = mapFromItem(item, mouseEvent->position());
switch (mouseEvent->type()) {
case QEvent::MouseButtonPress: {
if (mouseEvent->button() != Qt::LeftButton) return false;
m_dragging = true;
m_dragActive = false;
m_pressPos = pos;
m_pressContentX = m_contentX;
m_dragTimer.start();
m_lastMoveX = pos.x();
m_lastMoveT = 0;
m_velocity = 0;
return false;
}
case QEvent::MouseMove: {
if (!m_dragging) return false;
const qreal dx = pos.x() - m_pressPos.x();
if (!m_dragActive && std::abs(dx) > kDragThreshold) {
m_dragActive = true;
m_pressContentX = m_contentX;
cancelAnimations();
grabMouse();
}
if (!m_dragActive) return false;
m_contentX = m_pressContentX - dx;
wrapContentIfNeeded();
updateCurrentIndexFromContentX(true);
relayout();
const qint64 t = m_dragTimer.elapsed();
const qint64 dt = t - m_lastMoveT;
if (dt > 0) {
const qreal instVel = (m_lastMoveX - pos.x()) / (dt / 1000.0);
m_velocity = m_velocity * 0.7 + instVel * 0.3;
}
m_lastMoveX = pos.x();
m_lastMoveT = t;
mouseEvent->accept();
return true;
}
case QEvent::MouseButtonRelease: {
if (!m_dragging) return false;
if (!m_dragActive) {
m_dragging = false;
return false;
}
return false;
}
case QEvent::MouseButtonDblClick:
return false;
default:
return false;
}
}
void CarouselView::setModel(const QVariantList& m) { void CarouselView::setModel(const QVariantList& m) {
m_model = m; m_model = m;
@@ -118,6 +118,8 @@ class CarouselView : public QQuickItem {
void previewIndexChanged(int realIndex, QVariant modelData); void previewIndexChanged(int realIndex, QVariant modelData);
protected: protected:
bool childMouseEventFilter(QQuickItem* item, QEvent* event) override;
void geometryChange(const QRectF& newGeo, const QRectF& oldGeo) override; void geometryChange(const QRectF& newGeo, const QRectF& oldGeo) override;
void mousePressEvent(QMouseEvent* event) override; void mousePressEvent(QMouseEvent* event) override;