Warning, /plasma/plasma-mobile/components/mobileshell/qml/widgets/krunner/KRunnerWidget.qml is written in an unsupported language. File is not indexed.
0001 /*
0002 * SPDX-FileCopyrightText: 2014 Aaron Seigo <aseigo@kde.org>
0003 * SPDX-FileCopyrightText: 2015 Marco Martin <notmart@gmail.com>
0004 * SPDX-FileCopyrightText: 2021 Devin Lin <devin@kde.org>
0005 *
0006 * SPDX-License-Identifier: LGPL-2.0-or-later
0007 */
0008
0009 import QtQuick
0010 import QtQuick.Effects
0011 import QtQuick.Controls as Controls
0012 import QtQuick.Layouts
0013
0014 import org.kde.plasma.core as PlasmaCore
0015 import org.kde.plasma.components 3.0 as PlasmaComponents
0016 import org.kde.plasma.extras 2.0 as PlasmaExtras
0017
0018 import org.kde.milou as Milou
0019 import org.kde.kirigami 2.19 as Kirigami
0020
0021 /**
0022 * Search widget that is embedded into the homescreen. The dimensions of
0023 * the root item is assumed to be the available screen area for applications.
0024 */
0025 Item {
0026 id: root
0027
0028 // content margins (background ignores this)
0029 property real topMargin: 0
0030 property real bottomMargin: 0
0031 property real leftMargin: 0
0032 property real rightMargin: 0
0033
0034 function startGesture() {
0035 queryField.text = "";
0036 flickable.contentY = closedContentY;
0037 }
0038
0039 function updateGestureOffset(yOffset) {
0040 flickable.contentY = Math.max(0, Math.min(closedContentY, flickable.contentY + yOffset));
0041 }
0042
0043 // call when the touch gesture has let go
0044 function endGesture() {
0045 flickable.opening ? open() : close();
0046 }
0047
0048 // open the search widget (animated)
0049 function open() {
0050 anim.to = openedContentY;
0051 anim.restart();
0052 }
0053
0054 // close the search widget (animated)
0055 function close() {
0056 anim.to = closedContentY;
0057 anim.restart();
0058 }
0059
0060 // emitted when an item on the ListView is triggered
0061 signal actionTriggered()
0062
0063 readonly property real closedContentY: Kirigami.Units.gridUnit * 5
0064 readonly property real openedContentY: 0
0065 readonly property real openFactor: Math.max(0, Math.min(1, 1 - flickable.contentY / closedContentY))
0066 readonly property bool isOpen: openFactor != 0
0067
0068 Rectangle {
0069 anchors.fill: parent
0070 color: Qt.rgba(0, 0, 0, 0.3)
0071 opacity: root.openFactor
0072 }
0073
0074 onOpacityChanged: {
0075 if (opacity === 0) {
0076 close();
0077 }
0078 }
0079
0080 Keys.onPressed: event => {
0081 if (event.key === Qt.Key_Down) {
0082 listView.forceActiveFocus();
0083 }
0084 }
0085
0086 Flickable {
0087 id: flickable
0088
0089 anchors.fill: parent
0090 anchors.topMargin: root.topMargin
0091 anchors.bottomMargin: root.bottomMargin
0092 anchors.leftMargin: root.leftMargin
0093 anchors.rightMargin: root.rightMargin
0094
0095 contentHeight: flickable.height + root.closedContentY
0096 contentY: root.closedContentY
0097 property real oldContentY: contentY
0098 property bool opening: false
0099
0100 onContentYChanged: {
0101 opening = contentY < oldContentY;
0102 oldContentY = contentY;
0103
0104 if (contentY !== root.openedContentY) {
0105 queryField.focus = false;
0106 }
0107 }
0108
0109 onMovementEnded: root.endGesture()
0110
0111 onDraggingChanged: {
0112 if (!dragging) {
0113 root.endGesture();
0114 }
0115 }
0116
0117 NumberAnimation on contentY {
0118 id: anim
0119 duration: Kirigami.Units.longDuration * 2
0120 easing.type: Easing.OutQuad
0121 running: false
0122 onFinished: {
0123 if (anim.to === root.openedContentY) {
0124 queryField.forceActiveFocus();
0125 }
0126 }
0127 }
0128
0129 ColumnLayout {
0130 id: column
0131 height: flickable.height
0132 width: flickable.width
0133
0134 Controls.Control {
0135 opacity: root.openFactor
0136 Layout.fillWidth: true
0137 Layout.maximumWidth: Kirigami.Units.gridUnit * 30
0138 Layout.alignment: Qt.AlignHCenter
0139 Layout.topMargin: Kirigami.Units.gridUnit
0140 Layout.leftMargin: Kirigami.Units.gridUnit
0141 Layout.rightMargin: Kirigami.Units.gridUnit
0142
0143 leftPadding: Kirigami.Units.smallSpacing
0144 rightPadding: Kirigami.Units.smallSpacing
0145 topPadding: Kirigami.Units.smallSpacing
0146 bottomPadding: Kirigami.Units.smallSpacing
0147
0148 background: Item {
0149
0150 // shadow for search window
0151 MultiEffect {
0152 anchors.fill: parent
0153 source: rectBackground
0154 blurMax: 16
0155 shadowEnabled: true
0156 shadowVerticalOffset: 1
0157 shadowOpacity: 0.15
0158 }
0159
0160 Rectangle {
0161 id: rectBackground
0162 anchors.fill: parent
0163 color: Kirigami.Theme.backgroundColor
0164 radius: Kirigami.Units.smallSpacing
0165 }
0166 }
0167
0168 contentItem: RowLayout {
0169 Item {
0170 implicitHeight: queryField.height
0171 implicitWidth: height
0172 Kirigami.Icon {
0173 anchors.fill: parent
0174 anchors.margins: Math.round(Kirigami.Units.smallSpacing)
0175 source: "start-here-symbolic"
0176 }
0177 }
0178 PlasmaComponents.TextField {
0179 id: queryField
0180 Layout.fillWidth: true
0181 placeholderText: i18n("Search…")
0182 inputMethodHints: Qt.ImhNoPredictiveText // don't need to press "enter" to update text
0183 }
0184 }
0185 }
0186
0187 Controls.ScrollView {
0188 opacity: root.openFactor === 1 ? 1 : 0
0189 Behavior on opacity {
0190 NumberAnimation { duration: Kirigami.Units.shortDuration }
0191 }
0192
0193 Layout.fillWidth: true
0194 Layout.fillHeight: listView.contentHeight > availableHeight
0195
0196 Milou.ResultsListView {
0197 id: listView
0198 queryString: queryField.text
0199 clip: true
0200 Kirigami.Theme.colorSet: Kirigami.Theme.Window
0201
0202 highlight: activeFocus ? highlightComponent : null
0203 Component {
0204 id: highlightComponent
0205
0206 PlasmaExtras.Highlight {}
0207 }
0208
0209 onActivated: {
0210 root.close();
0211 }
0212 onUpdateQueryString: {
0213 queryField.text = text
0214 queryField.cursorPosition = cursorPosition
0215 }
0216
0217 delegate: MouseArea {
0218 id: delegate
0219 height: rowLayout.height
0220 width: listView.width
0221
0222 onClicked: {
0223 listView.currentIndex = model.index;
0224 listView.runCurrentIndex();
0225
0226 root.actionTriggered();
0227 }
0228 hoverEnabled: true
0229
0230 function activateNextAction() {
0231 queryField.forceActiveFocus();
0232 queryField.selectAll();
0233 listView.currentIndex = -1;
0234 }
0235
0236 Rectangle {
0237 anchors.fill: parent
0238 color: delegate.pressed ? Qt.rgba(255, 255, 255, 0.2) : (delegate.containsMouse ? Qt.rgba(255, 255, 255, 0.05) : "transparent")
0239 Behavior on color {
0240 ColorAnimation { duration: Kirigami.Units.shortDuration }
0241 }
0242 }
0243
0244 RowLayout {
0245 id: rowLayout
0246 height: Kirigami.Units.gridUnit * 3
0247 anchors.top: parent.top
0248 anchors.left: parent.left
0249 anchors.right: parent.right
0250 anchors.leftMargin: Kirigami.Units.gridUnit
0251 anchors.rightMargin: Kirigami.Units.gridUnit
0252
0253 Kirigami.Icon {
0254 Layout.alignment: Qt.AlignVCenter
0255 source: model.decoration
0256 implicitWidth: Kirigami.Units.iconSizes.medium
0257 implicitHeight: Kirigami.Units.iconSizes.medium
0258 }
0259
0260 ColumnLayout {
0261 Layout.fillWidth: true
0262 Layout.alignment: Qt.AlignVCenter
0263 spacing: Kirigami.Units.smallSpacing
0264
0265 PlasmaComponents.Label {
0266 id: title
0267 Layout.fillWidth: true
0268 Layout.leftMargin: Kirigami.Units.smallSpacing * 2
0269 Layout.rightMargin: Kirigami.Units.gridUnit
0270
0271 maximumLineCount: 1
0272 elide: Text.ElideRight
0273 text: typeof modelData !== "undefined" ? modelData : model.display
0274 color: "white"
0275
0276 font.pointSize: Kirigami.Theme.defaultFont.pointSize
0277 }
0278 PlasmaComponents.Label {
0279 id: subtitle
0280 Layout.fillWidth: true
0281 Layout.leftMargin: Kirigami.Units.smallSpacing * 2
0282 Layout.rightMargin: Kirigami.Units.gridUnit
0283
0284 maximumLineCount: 1
0285 elide: Text.ElideRight
0286 text: model.subtext || ""
0287 color: "white"
0288 opacity: 0.8
0289
0290 font.pointSize: Math.round(Kirigami.Theme.defaultFont.pointSize * 0.8)
0291 }
0292 }
0293
0294 Repeater {
0295 id: actionsRepeater
0296 model: typeof actions !== "undefined" ? actions : []
0297
0298 Controls.ToolButton {
0299 icon: modelData.icon || ""
0300 visible: modelData.visible || true
0301 enabled: modelData.enabled || true
0302
0303 Accessible.role: Accessible.Button
0304 Accessible.name: modelData.text
0305 checkable: checked
0306 checked: delegate.activeAction === index
0307 focus: delegate.activeAction === index
0308 onClicked: delegate.ListView.view.runAction(index)
0309 }
0310 }
0311 }
0312 }
0313 }
0314 }
0315
0316 MouseArea {
0317 Layout.fillWidth: true
0318 Layout.fillHeight: true
0319
0320 onClicked: close()
0321 }
0322 }
0323 }
0324 }