shift-shell/components/mobileshell/qml/widgets/krunner/KRunnerWidget.qml

Ignoring revisions in .git-blame-ignore-revs. Click here to bypass and see the normal blame view.

325 lines
12 KiB
QML
Raw Normal View History

2022-01-03 05:25:33 +00:00
/*
* SPDX-FileCopyrightText: 2014 Aaron Seigo <aseigo@kde.org>
* SPDX-FileCopyrightText: 2015 Marco Martin <notmart@gmail.com>
* SPDX-FileCopyrightText: 2021 Devin Lin <devin@kde.org>
*
* SPDX-License-Identifier: LGPL-2.0-or-later
*/
2023-05-13 02:07:48 +00:00
import QtQuick
import QtQuick.Effects
import QtQuick.Controls as Controls
import QtQuick.Layouts
2022-01-03 05:25:33 +00:00
import org.kde.plasma.core as PlasmaCore
2022-01-03 05:25:33 +00:00
import org.kde.plasma.components 3.0 as PlasmaComponents
import org.kde.plasma.extras 2.0 as PlasmaExtras
2023-05-13 02:07:48 +00:00
import org.kde.milou as Milou
2022-01-03 05:25:33 +00:00
import org.kde.kirigami 2.19 as Kirigami
/**
* Search widget that is embedded into the homescreen. The dimensions of
* the root item is assumed to be the available screen area for applications.
*/
Item {
id: root
// content margins (background ignores this)
property real topMargin: 0
property real bottomMargin: 0
property real leftMargin: 0
property real rightMargin: 0
2022-01-03 05:25:33 +00:00
function startGesture() {
queryField.text = "";
flickable.contentY = closedContentY;
}
function updateGestureOffset(yOffset) {
flickable.contentY = Math.max(0, Math.min(closedContentY, flickable.contentY + yOffset));
}
// call when the touch gesture has let go
function endGesture() {
flickable.opening ? open() : close();
}
// open the search widget (animated)
function open() {
anim.to = openedContentY;
anim.restart();
}
// close the search widget (animated)
function close() {
anim.to = closedContentY;
anim.restart();
}
2023-03-19 02:23:37 +00:00
// emitted when an item on the ListView is triggered
signal actionTriggered()
2022-01-03 05:25:33 +00:00
readonly property real closedContentY: Kirigami.Units.gridUnit * 5
2022-01-03 05:25:33 +00:00
readonly property real openedContentY: 0
readonly property real openFactor: Math.max(0, Math.min(1, 1 - flickable.contentY / closedContentY))
readonly property bool isOpen: openFactor != 0
2022-01-03 05:25:33 +00:00
Rectangle {
anchors.fill: parent
color: Qt.rgba(0, 0, 0, 0.3)
opacity: root.openFactor
}
2022-01-03 16:49:18 +00:00
onOpacityChanged: {
if (opacity === 0) {
close();
}
}
Keys.onPressed: event => {
if (event.key === Qt.Key_Down) {
listView.forceActiveFocus();
}
}
2022-01-03 05:25:33 +00:00
Flickable {
id: flickable
anchors.fill: parent
anchors.topMargin: root.topMargin
anchors.bottomMargin: root.bottomMargin
anchors.leftMargin: root.leftMargin
anchors.rightMargin: root.rightMargin
2022-01-03 05:25:33 +00:00
contentHeight: flickable.height + root.closedContentY
2022-01-03 05:25:33 +00:00
contentY: root.closedContentY
property real oldContentY: contentY
property bool opening: false
onContentYChanged: {
opening = contentY < oldContentY;
oldContentY = contentY;
2022-01-03 16:49:18 +00:00
if (contentY !== root.openedContentY) {
queryField.focus = false;
}
2022-01-03 05:25:33 +00:00
}
onMovementEnded: root.endGesture()
onDraggingChanged: {
if (!dragging) {
root.endGesture();
}
}
NumberAnimation on contentY {
id: anim
duration: Kirigami.Units.longDuration * 2
2022-01-03 05:25:33 +00:00
easing.type: Easing.OutQuad
running: false
2022-01-03 05:25:33 +00:00
onFinished: {
2022-01-03 16:49:18 +00:00
if (anim.to === root.openedContentY) {
2022-01-03 05:25:33 +00:00
queryField.forceActiveFocus();
}
}
}
ColumnLayout {
id: column
height: flickable.height
width: flickable.width
Controls.Control {
opacity: root.openFactor
Layout.fillWidth: true
Layout.maximumWidth: Kirigami.Units.gridUnit * 30
2022-01-03 16:49:18 +00:00
Layout.alignment: Qt.AlignHCenter
Layout.topMargin: Kirigami.Units.gridUnit
Layout.leftMargin: Kirigami.Units.gridUnit
Layout.rightMargin: Kirigami.Units.gridUnit
2022-01-03 05:25:33 +00:00
leftPadding: Kirigami.Units.smallSpacing
rightPadding: Kirigami.Units.smallSpacing
topPadding: Kirigami.Units.smallSpacing
bottomPadding: Kirigami.Units.smallSpacing
2022-01-03 05:25:33 +00:00
background: Item {
// shadow for search window
2023-05-13 02:07:48 +00:00
MultiEffect {
2022-01-03 05:25:33 +00:00
anchors.fill: parent
2023-05-13 02:07:48 +00:00
source: rectBackground
blurMax: 16
shadowEnabled: true
shadowVerticalOffset: 1
shadowOpacity: 0.15
2022-01-03 05:25:33 +00:00
}
Rectangle {
2023-05-13 02:07:48 +00:00
id: rectBackground
2022-01-03 05:25:33 +00:00
anchors.fill: parent
color: Kirigami.Theme.backgroundColor
radius: Kirigami.Units.smallSpacing
2022-01-03 05:25:33 +00:00
}
}
contentItem: RowLayout {
Item {
implicitHeight: queryField.height
implicitWidth: height
Kirigami.Icon {
2022-01-03 05:25:33 +00:00
anchors.fill: parent
anchors.margins: Math.round(Kirigami.Units.smallSpacing)
2022-01-03 05:25:33 +00:00
source: "start-here-symbolic"
}
}
PlasmaComponents.TextField {
2022-01-03 05:25:33 +00:00
id: queryField
Layout.fillWidth: true
placeholderText: i18n("Search…")
2022-01-09 18:53:39 +00:00
inputMethodHints: Qt.ImhNoPredictiveText // don't need to press "enter" to update text
2022-01-03 05:25:33 +00:00
}
}
}
Controls.ScrollView {
opacity: root.openFactor === 1 ? 1 : 0
Behavior on opacity {
NumberAnimation { duration: Kirigami.Units.shortDuration }
2022-01-03 05:25:33 +00:00
}
Layout.fillWidth: true
Layout.fillHeight: listView.contentHeight > availableHeight
2022-01-03 05:25:33 +00:00
2023-03-19 02:23:37 +00:00
Milou.ResultsListView {
id: listView
queryString: queryField.text
clip: true
Kirigami.Theme.colorSet: Kirigami.Theme.Window
2023-03-19 02:23:37 +00:00
highlight: activeFocus ? highlightComponent : null
Component {
id: highlightComponent
PlasmaExtras.Highlight {}
}
onActivated: {
root.close();
}
2023-03-19 02:23:37 +00:00
onUpdateQueryString: {
queryField.text = text
queryField.cursorPosition = cursorPosition
}
delegate: MouseArea {
id: delegate
height: rowLayout.height
width: listView.width
onClicked: {
listView.currentIndex = model.index;
listView.runCurrentIndex();
root.actionTriggered();
}
hoverEnabled: true
function activateNextAction() {
queryField.forceActiveFocus();
queryField.selectAll();
listView.currentIndex = -1;
}
2023-03-19 02:23:37 +00:00
Rectangle {
anchors.fill: parent
color: delegate.pressed ? Qt.rgba(255, 255, 255, 0.2) : (delegate.containsMouse ? Qt.rgba(255, 255, 255, 0.05) : "transparent")
Behavior on color {
ColorAnimation { duration: Kirigami.Units.shortDuration }
2023-03-19 02:23:37 +00:00
}
}
RowLayout {
id: rowLayout
height: Kirigami.Units.gridUnit * 3
2023-03-19 02:23:37 +00:00
anchors.top: parent.top
anchors.left: parent.left
anchors.right: parent.right
anchors.leftMargin: Kirigami.Units.gridUnit
anchors.rightMargin: Kirigami.Units.gridUnit
2023-03-19 02:23:37 +00:00
Kirigami.Icon {
Layout.alignment: Qt.AlignVCenter
source: model.decoration
implicitWidth: Kirigami.Units.iconSizes.medium
implicitHeight: Kirigami.Units.iconSizes.medium
2023-03-19 02:23:37 +00:00
}
ColumnLayout {
Layout.fillWidth: true
Layout.alignment: Qt.AlignVCenter
spacing: Kirigami.Units.smallSpacing
2023-03-19 02:23:37 +00:00
PlasmaComponents.Label {
id: title
Layout.fillWidth: true
Layout.leftMargin: Kirigami.Units.smallSpacing * 2
Layout.rightMargin: Kirigami.Units.gridUnit
2023-03-19 02:23:37 +00:00
maximumLineCount: 1
elide: Text.ElideRight
text: typeof modelData !== "undefined" ? modelData : model.display
color: "white"
font.pointSize: Kirigami.Theme.defaultFont.pointSize
2023-03-19 02:23:37 +00:00
}
PlasmaComponents.Label {
id: subtitle
Layout.fillWidth: true
Layout.leftMargin: Kirigami.Units.smallSpacing * 2
Layout.rightMargin: Kirigami.Units.gridUnit
2023-03-19 02:23:37 +00:00
maximumLineCount: 1
elide: Text.ElideRight
text: model.subtext || ""
color: "white"
opacity: 0.8
font.pointSize: Math.round(Kirigami.Theme.defaultFont.pointSize * 0.8)
2023-03-19 02:23:37 +00:00
}
}
Repeater {
id: actionsRepeater
model: typeof actions !== "undefined" ? actions : []
Controls.ToolButton {
icon: modelData.icon || ""
visible: modelData.visible || true
enabled: modelData.enabled || true
Accessible.role: Accessible.Button
Accessible.name: modelData.text
checkable: checked
checked: delegate.activeAction === index
focus: delegate.activeAction === index
onClicked: delegate.ListView.view.runAction(index)
}
}
}
}
}
2022-01-03 05:25:33 +00:00
}
MouseArea {
Layout.fillWidth: true
Layout.fillHeight: true
onClicked: close()
}
2022-01-03 05:25:33 +00:00
}
}
}