from the bottom??
This commit is contained in:
@@ -0,0 +1,82 @@
|
|||||||
|
import Quickshell
|
||||||
|
import QtQuick
|
||||||
|
import QtQuick.Controls
|
||||||
|
|
||||||
|
TextField {
|
||||||
|
id: root
|
||||||
|
color: "white"
|
||||||
|
horizontalAlignment: Text.AlignLeft
|
||||||
|
echoMode: TextInput.Normal
|
||||||
|
placeholderText: qsTr("Search applications...")
|
||||||
|
background: null
|
||||||
|
renderType: TextInput.NativeRendering
|
||||||
|
|
||||||
|
font.family: "Rubik"
|
||||||
|
|
||||||
|
cursorDelegate: Rectangle {
|
||||||
|
id: cursor
|
||||||
|
|
||||||
|
property bool disableBlink
|
||||||
|
|
||||||
|
implicitWidth: 2
|
||||||
|
color: "white"
|
||||||
|
radius: 2
|
||||||
|
|
||||||
|
Connections {
|
||||||
|
target: root
|
||||||
|
|
||||||
|
function onCursorPositionChanged(): void {
|
||||||
|
if ( root.activeFocus && root.cursorVisible ) {
|
||||||
|
cursor.opacity = 1;
|
||||||
|
cursor.disableBlink = true;
|
||||||
|
enableBlink.restart();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Timer {
|
||||||
|
id: enableBlink
|
||||||
|
|
||||||
|
interval: 100
|
||||||
|
onTriggered: cursor.disableBlink = false
|
||||||
|
}
|
||||||
|
|
||||||
|
Timer {
|
||||||
|
running: root.activeFocus && root.cursorVisible && !cursor.disableBlink
|
||||||
|
repeat: true
|
||||||
|
triggeredOnStart: true
|
||||||
|
interval: 500
|
||||||
|
onTriggered: parent.opacity = parent.opacity === 1 ? 0 : 1
|
||||||
|
}
|
||||||
|
|
||||||
|
Binding {
|
||||||
|
when: !root.activeFocus || !root.cursorVisible
|
||||||
|
cursor.opacity: 0
|
||||||
|
}
|
||||||
|
|
||||||
|
Behavior on opacity {
|
||||||
|
Anim {
|
||||||
|
duration: 200
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Keys.onPressed: {
|
||||||
|
if ( event.key === Qt.Key_Down ) {
|
||||||
|
appListView.decrementCurrentIndex();
|
||||||
|
event.accepted = true;
|
||||||
|
} else if ( event.key === Qt.Key_Up ) {
|
||||||
|
appListView.incrementCurrentIndex();
|
||||||
|
event.accepted = true;
|
||||||
|
} else if ( event.key === Qt.Key_Return || event.key === Qt.Key_Enter ) {
|
||||||
|
if ( appListView.currentItem ) {
|
||||||
|
Search.launch(appListView.currentItem.modelData);
|
||||||
|
launcherWindow.visible = false;
|
||||||
|
}
|
||||||
|
event.accepted = true;
|
||||||
|
} else if ( event.key === Qt.Key_Escape ) {
|
||||||
|
closeAnim.start();
|
||||||
|
event.accepted = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
+183
-90
@@ -3,6 +3,7 @@ import Quickshell.Wayland
|
|||||||
import Quickshell.Hyprland
|
import Quickshell.Hyprland
|
||||||
import QtQuick
|
import QtQuick
|
||||||
import QtQuick.Controls
|
import QtQuick.Controls
|
||||||
|
import QtQuick.Effects
|
||||||
import QtQuick.Layouts
|
import QtQuick.Layouts
|
||||||
import qs
|
import qs
|
||||||
|
|
||||||
@@ -38,30 +39,133 @@ Scope {
|
|||||||
appid: "z-cast"
|
appid: "z-cast"
|
||||||
name: "toggle-launcher"
|
name: "toggle-launcher"
|
||||||
onPressed: {
|
onPressed: {
|
||||||
launcherWindow.visible = !launcherWindow.visible;
|
if ( !launcherWindow.visible ) {
|
||||||
|
openAnim.start();
|
||||||
|
} else if ( launcherWindow.visible ) {
|
||||||
|
closeAnim.start();
|
||||||
|
}
|
||||||
focusGrab.active = true;
|
focusGrab.active = true;
|
||||||
searchInput.forceActiveFocus();
|
searchInput.forceActiveFocus();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
mask: Region { item: backgroundRect }
|
// mask: Region { item: backgroundRect }
|
||||||
|
|
||||||
|
Rectangle {
|
||||||
|
id: shadowRect
|
||||||
|
anchors {
|
||||||
|
top: appListView.count > 0 ? appListRect.top : backgroundRect.top
|
||||||
|
bottom: backgroundRect.bottom
|
||||||
|
left: appListRect.left
|
||||||
|
right: appListRect.right
|
||||||
|
}
|
||||||
|
layer.enabled: true
|
||||||
|
radius: 8
|
||||||
|
color: "black"
|
||||||
|
visible: false
|
||||||
|
}
|
||||||
|
|
||||||
|
MultiEffect {
|
||||||
|
id: effects
|
||||||
|
source: shadowRect
|
||||||
|
anchors.fill: shadowRect
|
||||||
|
shadowBlur: 2.0
|
||||||
|
shadowEnabled: true
|
||||||
|
shadowOpacity: 1
|
||||||
|
shadowColor: "black"
|
||||||
|
maskSource: shadowRect
|
||||||
|
maskEnabled: true
|
||||||
|
maskInverted: true
|
||||||
|
autoPaddingEnabled: true
|
||||||
|
}
|
||||||
|
|
||||||
Rectangle {
|
Rectangle {
|
||||||
id: backgroundRect
|
id: backgroundRect
|
||||||
anchors.top: parent.top
|
anchors.bottom: parent.bottom
|
||||||
anchors.topMargin: 200
|
anchors.bottomMargin: -1
|
||||||
implicitHeight: mainLayout.childrenRect.height + 20
|
implicitHeight: mainLayout.childrenRect.height + 20
|
||||||
implicitWidth: 600
|
implicitWidth: 600
|
||||||
x: Math.round(( parent.width - width ) / 2 )
|
x: Math.round(( parent.width - width ) / 2 )
|
||||||
color: "#d01a1a1a"
|
color: "#d01a1a1a"
|
||||||
radius: 8
|
opacity: 1
|
||||||
border.color: "#444444"
|
border.color: "#444444"
|
||||||
border.width: 1
|
border.width: 1
|
||||||
|
|
||||||
Behavior on implicitHeight {
|
ParallelAnimation {
|
||||||
|
id: openAnim
|
||||||
Anim {
|
Anim {
|
||||||
|
target: appListRect
|
||||||
duration: MaterialEasing.expressiveFastSpatialTime
|
duration: MaterialEasing.expressiveFastSpatialTime
|
||||||
easing.bezierCurve: MaterialEasing.expressiveDefaultSpatial
|
easing.bezierCurve: MaterialEasing.expressiveDefaultSpatial
|
||||||
|
property: "implicitHeight"
|
||||||
|
from: 40
|
||||||
|
to: appListView.implicitHeight + 20
|
||||||
|
}
|
||||||
|
Anim {
|
||||||
|
target: appListRect
|
||||||
|
duration: 50
|
||||||
|
property: "opacity"
|
||||||
|
from: 0
|
||||||
|
to: 1
|
||||||
|
}
|
||||||
|
Anim {
|
||||||
|
target: backgroundRect
|
||||||
|
duration: 50
|
||||||
|
property: "opacity"
|
||||||
|
from: 0
|
||||||
|
to: 1
|
||||||
|
}
|
||||||
|
Anim {
|
||||||
|
target: effects
|
||||||
|
duration: 50
|
||||||
|
property: "opacity"
|
||||||
|
from: 0
|
||||||
|
to: 1
|
||||||
|
}
|
||||||
|
onStarted: {
|
||||||
|
launcherWindow.visible = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ParallelAnimation {
|
||||||
|
id: closeAnim
|
||||||
|
Anim {
|
||||||
|
target: appListRect
|
||||||
|
duration: MaterialEasing.expressiveFastSpatialTime
|
||||||
|
easing.bezierCurve: MaterialEasing.expressiveDefaultSpatial
|
||||||
|
property: "implicitHeight"
|
||||||
|
from: appListView.implicitHeight
|
||||||
|
to: 40
|
||||||
|
}
|
||||||
|
SequentialAnimation {
|
||||||
|
PauseAnimation { duration: 120 }
|
||||||
|
|
||||||
|
ParallelAnimation {
|
||||||
|
Anim {
|
||||||
|
target: backgroundRect
|
||||||
|
duration: 50
|
||||||
|
property: "opacity"
|
||||||
|
from: 1
|
||||||
|
to: 0
|
||||||
|
}
|
||||||
|
Anim {
|
||||||
|
target: appListRect
|
||||||
|
duration: 50
|
||||||
|
property: "opacity"
|
||||||
|
from: 1
|
||||||
|
to: 0
|
||||||
|
}
|
||||||
|
Anim {
|
||||||
|
target: effects
|
||||||
|
duration: 50
|
||||||
|
property: "opacity"
|
||||||
|
from: 1
|
||||||
|
to: 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
onStopped: {
|
||||||
|
launcherWindow.visible = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -70,97 +174,39 @@ Scope {
|
|||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
anchors.margins: 10
|
anchors.margins: 10
|
||||||
spacing: 5
|
spacing: 5
|
||||||
|
clip: true
|
||||||
|
|
||||||
TextField {
|
CustomTextField {
|
||||||
id: searchInput
|
id: searchInput
|
||||||
implicitHeight: 30
|
implicitHeight: 30
|
||||||
implicitWidth: parent.width
|
implicitWidth: parent.width
|
||||||
color: "white"
|
|
||||||
horizontalAlignment: Text.AlignLeft
|
|
||||||
echoMode: TextInput.Normal
|
|
||||||
placeholderText: qsTr("Search applications...")
|
|
||||||
background: null
|
|
||||||
|
|
||||||
cursorDelegate: Rectangle {
|
|
||||||
id: cursor
|
|
||||||
|
|
||||||
property bool disableBlink
|
|
||||||
|
|
||||||
implicitWidth: 2
|
|
||||||
color: "white"
|
|
||||||
radius: 2
|
|
||||||
|
|
||||||
Connections {
|
|
||||||
target: searchInput
|
|
||||||
|
|
||||||
function onCursorPositionChanged(): void {
|
|
||||||
if ( searchInput.activeFocus && searchInput.cursorVisible ) {
|
|
||||||
cursor.opacity = 1;
|
|
||||||
cursor.disableBlink = true;
|
|
||||||
enableBlink.restart();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Timer {
|
|
||||||
id: enableBlink
|
|
||||||
|
|
||||||
interval: 100
|
|
||||||
onTriggered: cursor.disableBlink = false
|
|
||||||
}
|
|
||||||
|
|
||||||
Timer {
|
|
||||||
running: searchInput.activeFocus && searchInput.cursorVisible && !cursor.disableBlink
|
|
||||||
repeat: true
|
|
||||||
triggeredOnStart: true
|
|
||||||
interval: 500
|
|
||||||
onTriggered: parent.opacity = parent.opacity === 1 ? 0 : 1
|
|
||||||
}
|
|
||||||
|
|
||||||
Binding {
|
|
||||||
when: !searchInput.activeFocus || !searchInput.cursorVisible
|
|
||||||
cursor.opacity: 0
|
|
||||||
}
|
|
||||||
|
|
||||||
Behavior on opacity {
|
|
||||||
Anim {
|
|
||||||
duration: 200
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Keys.onPressed: {
|
|
||||||
if ( event.key === Qt.Key_Down ) {
|
|
||||||
appListView.incrementCurrentIndex();
|
|
||||||
event.accepted = true;
|
|
||||||
} else if ( event.key === Qt.Key_Up ) {
|
|
||||||
appListView.decrementCurrentIndex();
|
|
||||||
event.accepted = true;
|
|
||||||
} else if ( event.key === Qt.Key_Return || event.key === Qt.Key_Enter ) {
|
|
||||||
if ( appListView.currentItem ) {
|
|
||||||
Search.launch(appListView.currentItem.modelData);
|
|
||||||
launcherWindow.visible = false;
|
|
||||||
}
|
|
||||||
event.accepted = true;
|
|
||||||
} else if ( event.key === Qt.Key_Escape ) {
|
|
||||||
launcherWindow.visible = false;
|
|
||||||
event.accepted = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Rectangle {
|
|
||||||
id: separator
|
|
||||||
implicitWidth: parent.width
|
|
||||||
implicitHeight: 1
|
|
||||||
color: "#444444"
|
|
||||||
}
|
|
||||||
|
|
||||||
Rectangle {
|
Rectangle {
|
||||||
id: appListRect
|
id: appListRect
|
||||||
implicitWidth: parent.width
|
x: Math.round(( parent.width - width ) / 2 )
|
||||||
implicitHeight: appListView.implicitHeight
|
implicitWidth: backgroundRect.implicitWidth
|
||||||
color: "transparent"
|
implicitHeight: appListView.implicitHeight + 20
|
||||||
|
anchors.bottom: backgroundRect.top
|
||||||
|
anchors.bottomMargin: -1
|
||||||
|
color: backgroundRect.color
|
||||||
|
topRightRadius: 8
|
||||||
|
topLeftRadius: 8
|
||||||
|
border.color: backgroundRect.border.color
|
||||||
|
|
||||||
|
Behavior on implicitHeight {
|
||||||
|
Anim {
|
||||||
|
duration: MaterialEasing.expressiveFastSpatialTime
|
||||||
|
easing.bezierCurve: MaterialEasing.expressiveDefaultSpatial
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Item {
|
||||||
|
anchors.fill: parent
|
||||||
|
anchors.margins: 10
|
||||||
|
visible: appListView.count > 0
|
||||||
clip: true
|
clip: true
|
||||||
ListView {
|
ListView {
|
||||||
id: appListView
|
id: appListView
|
||||||
@@ -173,7 +219,8 @@ Scope {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
implicitHeight: Math.min( count, 15 ) * 48
|
verticalLayoutDirection: ListView.BottomToTop
|
||||||
|
implicitHeight: Math.min( count, 20 ) * 48
|
||||||
|
|
||||||
preferredHighlightBegin: 0
|
preferredHighlightBegin: 0
|
||||||
preferredHighlightEnd: appListRect.height
|
preferredHighlightEnd: appListRect.height
|
||||||
@@ -197,7 +244,9 @@ Scope {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
state: "apps"
|
property list<var> search: Search.search( searchInput.text )
|
||||||
|
|
||||||
|
state: search.length === 0 ? "noresults" : "apps"
|
||||||
|
|
||||||
states: [
|
states: [
|
||||||
State {
|
State {
|
||||||
@@ -206,6 +255,13 @@ Scope {
|
|||||||
appModel.values: Search.search(searchInput.text)
|
appModel.values: Search.search(searchInput.text)
|
||||||
appListView.delegate: appItem
|
appListView.delegate: appItem
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
State {
|
||||||
|
name: "noresults"
|
||||||
|
PropertyChanges {
|
||||||
|
appModel.values: [1]
|
||||||
|
appListView.delegate: noResultsItem
|
||||||
|
}
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
|
||||||
@@ -215,6 +271,42 @@ Scope {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Component {
|
||||||
|
id: noResultsItem
|
||||||
|
Item {
|
||||||
|
width: appListView.width
|
||||||
|
height: 48
|
||||||
|
Text {
|
||||||
|
id: icon
|
||||||
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
|
property real fill: 0
|
||||||
|
text: "\ue000"
|
||||||
|
color: "#cccccc"
|
||||||
|
renderType: Text.NativeRendering
|
||||||
|
font.pointSize: 28
|
||||||
|
font.family: "Material Symbols Outlined"
|
||||||
|
font.variableAxes: ({
|
||||||
|
FILL: fill.toFixed(1),
|
||||||
|
GRAD: -25,
|
||||||
|
opsz: fontInfo.pixelSize,
|
||||||
|
wght: fontInfo.weight
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
Text {
|
||||||
|
anchors.left: icon.right
|
||||||
|
anchors.leftMargin: 10
|
||||||
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
|
text: "No results found"
|
||||||
|
color: "#cccccc"
|
||||||
|
renderType: Text.NativeRendering
|
||||||
|
|
||||||
|
font.pointSize: 12
|
||||||
|
font.family: "Rubik"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
transitions: Transition {
|
transitions: Transition {
|
||||||
SequentialAnimation {
|
SequentialAnimation {
|
||||||
ParallelAnimation {
|
ParallelAnimation {
|
||||||
@@ -266,6 +358,7 @@ Scope {
|
|||||||
}
|
}
|
||||||
|
|
||||||
add: Transition {
|
add: Transition {
|
||||||
|
enabled: !appListView.state
|
||||||
Anim {
|
Anim {
|
||||||
properties: "opacity"
|
properties: "opacity"
|
||||||
from: 0
|
from: 0
|
||||||
@@ -280,6 +373,7 @@ Scope {
|
|||||||
}
|
}
|
||||||
|
|
||||||
remove: Transition {
|
remove: Transition {
|
||||||
|
enabled: !appListView.state
|
||||||
Anim {
|
Anim {
|
||||||
properties: "opacity"
|
properties: "opacity"
|
||||||
from: 1
|
from: 1
|
||||||
@@ -327,5 +421,4 @@ Scope {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
+30
-1
@@ -21,10 +21,39 @@ Searcher {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function search(search: string): list<var> {
|
function search(search: string): list<var> {
|
||||||
|
const prefix = ">";
|
||||||
|
if (search.startsWith(`${prefix}i `)) {
|
||||||
|
keys = ["id", "name"];
|
||||||
|
weights = [0.9, 0.1];
|
||||||
|
} else if (search.startsWith(`${prefix}c `)) {
|
||||||
|
keys = ["categories", "name"];
|
||||||
|
weights = [0.9, 0.1];
|
||||||
|
} else if (search.startsWith(`${prefix}d `)) {
|
||||||
|
keys = ["comment", "name"];
|
||||||
|
weights = [0.9, 0.1];
|
||||||
|
} else if (search.startsWith(`${prefix}e `)) {
|
||||||
|
keys = ["execString", "name"];
|
||||||
|
weights = [0.9, 0.1];
|
||||||
|
} else if (search.startsWith(`${prefix}w `)) {
|
||||||
|
keys = ["startupClass", "name"];
|
||||||
|
weights = [0.9, 0.1];
|
||||||
|
} else if (search.startsWith(`${prefix}g `)) {
|
||||||
|
keys = ["genericName", "name"];
|
||||||
|
weights = [0.9, 0.1];
|
||||||
|
} else if (search.startsWith(`${prefix}k `)) {
|
||||||
|
keys = ["keywords", "name"];
|
||||||
|
weights = [0.9, 0.1];
|
||||||
|
} else {
|
||||||
keys = ["name"];
|
keys = ["name"];
|
||||||
weights = [1];
|
weights = [1];
|
||||||
|
|
||||||
const results = query(search).map(e => e.entry);
|
if (!search.startsWith(`${prefix}t `))
|
||||||
|
return query(search).map(e => e.entry);
|
||||||
|
}
|
||||||
|
|
||||||
|
const results = query(search.slice(prefix.length + 2)).map(e => e.entry);
|
||||||
|
if (search.startsWith(`${prefix}t `))
|
||||||
|
return results.filter(a => a.runInTerminal);
|
||||||
return results;
|
return results;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user