Warning, /plasma/plasma-desktop/applets/kicker/package/contents/ui/MenuRepresentation.qml is written in an unsupported language. File is not indexed.
0001 /*
0002 SPDX-FileCopyrightText: 2013-2015 Eike Hein <hein@kde.org>
0003
0004 SPDX-License-Identifier: GPL-2.0-or-later
0005 */
0006
0007 import QtQuick 2.15
0008 import QtQuick.Layouts 1.15
0009 // Deliberately imported after QtQuick to avoid missing restoreMode property in Binding. Fix in Qt 6.
0010 import QtQml 2.15
0011
0012 import org.kde.plasma.core as PlasmaCore
0013 import org.kde.ksvg 1.0 as KSvg
0014 import org.kde.plasma.extras 2.0 as PlasmaExtras
0015 import org.kde.kirigami 2.20 as Kirigami
0016 import org.kde.plasma.plasmoid 2.0
0017
0018 FocusScope {
0019 id: root
0020
0021 focus: true
0022
0023 Layout.minimumWidth: (sideBar.width + (sideBar.width ? mainRow.spacing : 0)
0024 + Math.max(searchField.defaultWidth, runnerColumns.width))
0025 Layout.maximumWidth: Math.max(mainRow.width, Layout.minimumWidth); // mainRow.width is constrained by rootList.maximumWidth
0026
0027 Layout.minimumHeight: Math.max(((rootModel.count - rootModel.separatorCount) * rootList.itemHeight)
0028 + (rootModel.separatorCount * rootList.separatorHeight)
0029 + searchField.height + (2 * Kirigami.Units.smallSpacing), sideBar.margins.top + sideBar.margins.bottom
0030 + favoriteApps.contentHeight + favoriteSystemActions.contentHeight + sidebarSeparator.height
0031 + (4 * Kirigami.Units.smallSpacing))
0032 Layout.maximumHeight: Layout.minimumHeight
0033
0034 signal appendSearchText(string text)
0035
0036 function reset() {
0037 kicker.hideOnWindowDeactivate = true;
0038
0039 rootList.currentIndex = -1;
0040
0041 searchField.text = "";
0042 searchField.focus = true;
0043 }
0044
0045 Row {
0046 id: mainRow
0047
0048 height: parent.height
0049
0050 spacing: Kirigami.Units.smallSpacing
0051
0052 LayoutMirroring.enabled: ((Plasmoid.location === PlasmaCore.Types.RightEdge)
0053 || (Qt.application.layoutDirection === Qt.RightToLeft && Plasmoid.location !== PlasmaCore.Types.LeftEdge))
0054
0055 KSvg.FrameSvgItem {
0056 id: sideBar
0057
0058 visible: width > 0
0059
0060 width: (globalFavorites && systemFavorites
0061 && (globalFavorites.count + systemFavorites.count)
0062 ? Kirigami.Units.iconSizes.medium + margins.left + margins.right : 0)
0063 height: parent.height
0064
0065 imagePath: "widgets/frame"
0066 prefix: "plain"
0067
0068 SideBarSection {
0069 id: favoriteApps
0070
0071 anchors.top: parent.top
0072 anchors.topMargin: sideBar.margins.top
0073
0074 height: (sideBar.height - sideBar.margins.top - sideBar.margins.bottom
0075 - favoriteSystemActions.height - sidebarSeparator.height - (4 * Kirigami.Units.smallSpacing))
0076
0077 model: globalFavorites
0078
0079 states: [ State {
0080 name: "top"
0081 when: (Plasmoid.location === PlasmaCore.Types.TopEdge)
0082
0083 AnchorChanges {
0084 target: favoriteApps
0085 anchors.top: undefined
0086 anchors.bottom: parent.bottom
0087 }
0088
0089 PropertyChanges {
0090 target: favoriteApps
0091 anchors.topMargin: undefined
0092 anchors.bottomMargin: sideBar.margins.bottom
0093 }
0094 }]
0095
0096 Binding {
0097 target: globalFavorites
0098 property: "iconSize"
0099 value: Kirigami.Units.iconSizes.medium
0100 restoreMode: Binding.RestoreBinding
0101 }
0102 }
0103
0104 KSvg.SvgItem {
0105 id: sidebarSeparator
0106
0107 anchors.bottom: favoriteSystemActions.top
0108 anchors.bottomMargin: (2 * Kirigami.Units.smallSpacing)
0109 anchors.horizontalCenter: parent.horizontalCenter
0110
0111 width: Kirigami.Units.iconSizes.medium
0112 height: lineSvg.horLineHeight
0113
0114 visible: (favoriteApps.model && favoriteApps.model.count
0115 && favoriteSystemActions.model && favoriteSystemActions.model.count)
0116
0117 svg: lineSvg
0118 elementId: "horizontal-line"
0119
0120 states: [ State {
0121 name: "top"
0122 when: (Plasmoid.location === PlasmaCore.Types.TopEdge)
0123
0124 AnchorChanges {
0125 target: sidebarSeparator
0126 anchors.top: favoriteSystemActions.bottom
0127 anchors.bottom: undefined
0128
0129 }
0130
0131 PropertyChanges {
0132 target: sidebarSeparator
0133 anchors.topMargin: (2 * Kirigami.Units.smallSpacing)
0134 anchors.bottomMargin: undefined
0135 }
0136 }]
0137 }
0138
0139 SideBarSection {
0140 id: favoriteSystemActions
0141
0142 anchors.bottom: parent.bottom
0143 anchors.bottomMargin: sideBar.margins.bottom
0144
0145 model: systemFavorites
0146
0147 states: [ State {
0148 name: "top"
0149 when: (Plasmoid.location === PlasmaCore.Types.TopEdge)
0150
0151 AnchorChanges {
0152 target: favoriteSystemActions
0153 anchors.top: parent.top
0154 anchors.bottom: undefined
0155 }
0156
0157 PropertyChanges {
0158 target: favoriteSystemActions
0159 anchors.topMargin: sideBar.margins.top
0160 anchors.bottomMargin: undefined
0161 }
0162 }]
0163 }
0164 }
0165
0166 ItemListView {
0167 id: rootList
0168
0169 anchors.top: parent.top
0170
0171 minimumWidth: root.Layout.minimumWidth - sideBar.width - mainRow.spacing
0172 height: ((rootModel.count - rootModel.separatorCount) * itemHeight) + (rootModel.separatorCount * separatorHeight)
0173
0174 visible: searchField.text === ""
0175
0176 iconsEnabled: Plasmoid.configuration.showIconsRootLevel
0177
0178 model: rootModel
0179
0180 onKeyNavigationAtListEnd: {
0181 searchField.focus = true;
0182 }
0183
0184 states: [ State {
0185 name: "top"
0186 when: (Plasmoid.location === PlasmaCore.Types.TopEdge)
0187
0188 AnchorChanges {
0189 target: rootList
0190 anchors.top: parent.top
0191 }
0192 }]
0193
0194 Component.onCompleted: {
0195 rootList.exited.connect(root.reset);
0196 }
0197 }
0198
0199 Row {
0200 id: runnerColumns
0201
0202 height: parent.height
0203
0204 signal focusChanged()
0205
0206 visible: searchField.text !== "" && runnerModel.count > 0
0207
0208 Repeater {
0209 id: runnerColumnsRepeater
0210
0211 model: runnerModel
0212
0213 delegate: RunnerResultsList {
0214 id: runnerMatches
0215 visible: runnerModel.modelForRow(index).count > 0
0216
0217 onKeyNavigationAtListEnd: {
0218 searchField.focus = true;
0219 }
0220
0221 onContainsMouseChanged: {
0222 if (containsMouse) {
0223 runnerMatches.focus = true;
0224 }
0225 }
0226
0227 onFocusChanged: {
0228 if (focus) {
0229 runnerColumns.focusChanged();
0230 }
0231 }
0232
0233 function focusChanged() {
0234 if (!runnerMatches.focus && runnerMatches.currentIndex != -1) {
0235 runnerMatches.currentIndex = -1;
0236 }
0237 }
0238
0239 Keys.onPressed: event => {
0240 var target = null;
0241
0242 if (event.key === Qt.Key_Right) {
0243 var targets = new Array();
0244
0245 for (var i = index + 1; i < runnerModel.count; ++i) {
0246 targets[targets.length] = i;
0247 }
0248
0249 for (var i = 0; i < index; ++i) {
0250 targets[targets.length] = i;
0251 }
0252
0253 for (var i = 0; i < targets.length; ++i) {
0254 if (runnerModel.modelForRow(targets[i]).count) {
0255 target = runnerColumnsRepeater.itemAt(targets[i]);
0256 break;
0257 }
0258 }
0259 } else if (event.key === Qt.Key_Left) {
0260 var targets = new Array();
0261
0262 for (var i = index - 1; i >= 0; --i) {
0263 targets[targets.length] = i;
0264 }
0265
0266 for (var i = runnerModel.count - 1; i > index; --i) {
0267 targets[targets.length] = i;
0268 }
0269
0270 for (var i = 0; i < targets.length; ++i) {
0271 if (runnerModel.modelForRow(targets[i]).count) {
0272 target = runnerColumnsRepeater.itemAt(targets[i]);
0273 break;
0274 }
0275 }
0276 }
0277
0278 if (target) {
0279 event.accepted = true;
0280 currentIndex = -1;
0281 target.currentIndex = 0;
0282 target.focus = true;
0283 }
0284 }
0285
0286 Component.onCompleted: {
0287 runnerColumns.focusChanged.connect(focusChanged);
0288 }
0289
0290 Component.onDestruction: {
0291 runnerColumns.focusChanged.disconnect(focusChanged);
0292 }
0293 }
0294 }
0295 }
0296 }
0297
0298 PlasmaExtras.SearchField {
0299 id: searchField
0300
0301 anchors.bottom: mainRow.bottom
0302 anchors.left: parent.left
0303 anchors.leftMargin: sideBar.width + (sideBar.width ? mainRow.spacing : Kirigami.Units.smallSpacing)
0304
0305 readonly property real defaultWidth: Kirigami.Units.gridUnit * 14
0306 width: (runnerColumnsRepeater.count !== 0 ? runnerColumnsRepeater.itemAt(0).width
0307 : (rootList.visible ? rootList.width : defaultWidth))
0308
0309 focus: !Kirigami.InputMethod.willShowOnActive
0310
0311 onTextChanged: {
0312 runnerModel.query = text;
0313 }
0314
0315 onFocusChanged: {
0316 if (focus) {
0317 // FIXME: Cleanup arbitration between rootList/runnerCols here and in Keys.
0318 if (rootList.visible) {
0319 rootList.currentIndex = -1;
0320 }
0321
0322 if (runnerColumns.visible) {
0323 runnerColumnsRepeater.itemAt(0).currentIndex = -1;
0324 }
0325 }
0326 }
0327
0328 states: [ State {
0329 name: "top"
0330 when: Plasmoid.location === PlasmaCore.Types.TopEdge
0331
0332 AnchorChanges {
0333 target: searchField
0334 anchors.top: undefined
0335 anchors.bottom: mainRow.bottom
0336 anchors.left: parent.left
0337 anchors.right: undefined
0338 }
0339
0340 PropertyChanges {
0341 target: searchField
0342 anchors.leftMargin: sideBar.width + mainRow.spacing + Kirigami.Units.smallSpacing
0343 anchors.rightMargin: undefined
0344 }
0345 },
0346 State {
0347 name: "right"
0348 when: (Plasmoid.location === PlasmaCore.Types.RightEdge && Qt.application.layoutDirection === Qt.LeftToRight)
0349 || (Plasmoid.location === PlasmaCore.Types.LeftEdge && Qt.application.layoutDirection === Qt.RightToLeft)
0350
0351 AnchorChanges {
0352 target: searchField
0353 anchors.top: undefined
0354 anchors.bottom: mainRow.bottom
0355 anchors.left: undefined
0356 anchors.right: parent.right
0357 }
0358
0359 PropertyChanges {
0360 target: searchField
0361 anchors.leftMargin: undefined
0362 anchors.rightMargin: sideBar.width + mainRow.spacing + Kirigami.Units.smallSpacing
0363 }
0364 }]
0365
0366 Keys.onPressed: event => {
0367 if (event.key === Qt.Key_Up) {
0368 if (rootList.visible) {
0369 rootList.showChildDialogs = false;
0370 rootList.currentIndex = rootList.model.count - 1;
0371 rootList.forceActiveFocus();
0372 rootList.showChildDialogs = true;
0373 }
0374
0375 if (runnerColumns.visible) {
0376 for (var i = 0; i < runnerModel.count; ++i) {
0377 if (runnerModel.modelForRow(i).count) {
0378 var targetList = runnerColumnsRepeater.itemAt(i);
0379 targetList.currentIndex = runnerModel.modelForRow(i).count - 1;
0380 targetList.forceActiveFocus();
0381 break;
0382 }
0383 }
0384 }
0385 } else if (event.key === Qt.Key_Down) {
0386 if (rootList.visible) {
0387 rootList.showChildDialogs = false;
0388 rootList.currentIndex = Math.min(1, rootList.count);
0389 rootList.forceActiveFocus();
0390 rootList.showChildDialogs = true;
0391 }
0392
0393 if (runnerColumns.visible) {
0394 for (var i = 0; i < runnerModel.count; ++i) {
0395 if (runnerModel.modelForRow(i).count) {
0396 var targetList = runnerColumnsRepeater.itemAt(i);
0397 targetList.currentIndex = Math.min(1, targetList.count);
0398 targetList.forceActiveFocus();
0399 break;
0400 }
0401 }
0402 }
0403 } else if (event.key === Qt.Key_Left && cursorPosition === 0) {
0404 for (var i = runnerModel.count; i >= 0; --i) {
0405 if (runnerModel.modelForRow(i).count) {
0406 var targetList = runnerColumnsRepeater.itemAt(i);
0407 targetList.currentIndex = 0;
0408 targetList.forceActiveFocus();
0409 break;
0410 }
0411 }
0412 } else if (event.key === Qt.Key_Right && cursorPosition === length) {
0413 for (var i = 1; i < runnerModel.count; ++i) {
0414 if (runnerModel.modelForRow(i).count) {
0415 var targetList = runnerColumnsRepeater.itemAt(i);
0416 targetList.currentIndex = 0;
0417 targetList.forceActiveFocus();
0418 break;
0419 }
0420 }
0421 } else if (event.key === Qt.Key_Enter || event.key === Qt.Key_Return) {
0422 if (runnerColumns.visible && runnerModel.modelForRow(0).count) {
0423 runnerModel.modelForRow(0).trigger(0, "", null);
0424 kicker.expanded = false;
0425 }
0426 }
0427 }
0428
0429 function appendText(newText) {
0430 focus = true;
0431 text = text + newText;
0432 }
0433 }
0434
0435 Keys.onPressed: event => {
0436 if (event.key === Qt.Key_Escape) {
0437 kicker.expanded = false;
0438 }
0439 }
0440
0441 Component.onCompleted: {
0442 appendSearchText.connect(searchField.appendText);
0443
0444 kicker.reset.connect(reset);
0445 windowSystem.hidden.connect(reset);
0446
0447 rootModel.refresh();
0448 }
0449 }