Warning, /plasma/kwin/src/tabbox/switchers/thumbnail_grid/contents/ui/main.qml is written in an unsupported language. File is not indexed.
0001 /* 0002 KWin - the KDE window manager 0003 This file is part of the KDE project. 0004 0005 SPDX-FileCopyrightText: 2020 Chris Holland <zrenfire@gmail.com> 0006 SPDX-FileCopyrightText: 2023 Nate Graham <nate@kde.org> 0007 0008 SPDX-License-Identifier: GPL-2.0-or-later 0009 */ 0010 0011 import QtQuick 0012 import QtQuick.Layouts 1.1 0013 import org.kde.plasma.core as PlasmaCore 0014 import org.kde.ksvg 1.0 as KSvg 0015 import org.kde.plasma.components 3.0 as PlasmaComponents3 0016 import org.kde.kwin 3.0 as KWin 0017 import org.kde.kirigami 2.20 as Kirigami 0018 0019 KWin.TabBoxSwitcher { 0020 id: tabBox 0021 0022 Instantiator { 0023 active: tabBox.visible 0024 delegate: PlasmaCore.Dialog { 0025 location: PlasmaCore.Types.Floating 0026 visible: true 0027 flags: Qt.X11BypassWindowManagerHint 0028 x: tabBox.screenGeometry.x + tabBox.screenGeometry.width * 0.5 - dialogMainItem.width * 0.5 0029 y: tabBox.screenGeometry.y + tabBox.screenGeometry.height * 0.5 - dialogMainItem.height * 0.5 0030 0031 mainItem: FocusScope { 0032 id: dialogMainItem 0033 0034 focus: true 0035 0036 property int maxWidth: tabBox.screenGeometry.width * 0.9 0037 property int maxHeight: tabBox.screenGeometry.height * 0.7 0038 property real screenFactor: tabBox.screenGeometry.width / tabBox.screenGeometry.height 0039 property int maxGridColumnsByWidth: Math.floor(maxWidth / thumbnailGridView.cellWidth) 0040 0041 property int gridColumns: { // Simple greedy algorithm 0042 // respect screenGeometry 0043 const c = Math.min(thumbnailGridView.count, maxGridColumnsByWidth); 0044 const residue = thumbnailGridView.count % c; 0045 if (residue == 0) { 0046 return c; 0047 } 0048 // start greedy recursion 0049 return columnCountRecursion(c, c, c - residue); 0050 } 0051 0052 property int gridRows: Math.ceil(thumbnailGridView.count / gridColumns) 0053 property int optimalWidth: thumbnailGridView.cellWidth * gridColumns 0054 property int optimalHeight: thumbnailGridView.cellHeight * gridRows 0055 width: Math.min(Math.max(thumbnailGridView.cellWidth, optimalWidth), maxWidth) 0056 height: Math.min(Math.max(thumbnailGridView.cellHeight, optimalHeight), maxHeight) 0057 0058 clip: true 0059 0060 // Step for greedy algorithm 0061 function columnCountRecursion(prevC, prevBestC, prevDiff) { 0062 const c = prevC - 1; 0063 0064 // don't increase vertical extent more than horizontal 0065 // and don't exceed maxHeight 0066 if (prevC * prevC <= thumbnailGridView.count + prevDiff || 0067 maxHeight < Math.ceil(thumbnailGridView.count / c) * thumbnailGridView.cellHeight) { 0068 return prevBestC; 0069 } 0070 const residue = thumbnailGridView.count % c; 0071 // halts algorithm at some point 0072 if (residue == 0) { 0073 return c; 0074 } 0075 // empty slots 0076 const diff = c - residue; 0077 0078 // compare it to previous count of empty slots 0079 if (diff < prevDiff) { 0080 return columnCountRecursion(c, c, diff); 0081 } else if (diff == prevDiff) { 0082 // when it's the same try again, we'll stop early enough thanks to the landscape mode condition 0083 return columnCountRecursion(c, prevBestC, diff); 0084 } 0085 // when we've found a local minimum choose this one (greedy) 0086 return columnCountRecursion(c, prevBestC, diff); 0087 } 0088 0089 // Just to get the margin sizes 0090 KSvg.FrameSvgItem { 0091 id: hoverItem 0092 imagePath: "widgets/viewitem" 0093 prefix: "hover" 0094 visible: false 0095 } 0096 0097 GridView { 0098 id: thumbnailGridView 0099 anchors.fill: parent 0100 focus: true 0101 model: tabBox.model 0102 currentIndex: tabBox.currentIndex 0103 0104 readonly property int iconSize: Kirigami.Units.iconSizes.huge 0105 readonly property int captionRowHeight: Kirigami.Units.gridUnit * 2 0106 readonly property int columnSpacing: Kirigami.Units.gridUnit 0107 readonly property int thumbnailWidth: Kirigami.Units.gridUnit * 16 0108 readonly property int thumbnailHeight: thumbnailWidth * (1.0/dialogMainItem.screenFactor) 0109 cellWidth: hoverItem.margins.left + thumbnailWidth + hoverItem.margins.right 0110 cellHeight: hoverItem.margins.top + captionRowHeight + thumbnailHeight + hoverItem.margins.bottom 0111 0112 keyNavigationWraps: true 0113 highlightMoveDuration: 0 0114 0115 delegate: MouseArea { 0116 id: thumbnailGridItem 0117 width: thumbnailGridView.cellWidth 0118 height: thumbnailGridView.cellHeight 0119 focus: GridView.isCurrentItem 0120 hoverEnabled: true 0121 0122 Accessible.name: model.caption 0123 Accessible.role: Accessible.ListItem 0124 0125 onClicked: { 0126 tabBox.currentIndex = index; 0127 } 0128 0129 ColumnLayout { 0130 id: columnLayout 0131 z: 0 0132 spacing: thumbnailGridView.columnSpacing 0133 anchors.fill: parent 0134 anchors.leftMargin: hoverItem.margins.left * 2 0135 anchors.topMargin: hoverItem.margins.top * 2 0136 anchors.rightMargin: hoverItem.margins.right * 2 0137 anchors.bottomMargin: hoverItem.margins.bottom * 2 0138 0139 0140 // KWin.WindowThumbnail needs a container 0141 // otherwise it will be drawn the same size as the parent ColumnLayout 0142 Item { 0143 Layout.fillWidth: true 0144 Layout.fillHeight: true 0145 0146 KWin.WindowThumbnail { 0147 anchors.fill: parent 0148 wId: windowId 0149 } 0150 0151 Kirigami.Icon { 0152 anchors.horizontalCenter: parent.horizontalCenter 0153 anchors.verticalCenter: parent.bottom 0154 anchors.verticalCenterOffset: Math.round(-thumbnailGridView.iconSize / 4) 0155 width: thumbnailGridView.iconSize 0156 height: thumbnailGridView.iconSize 0157 0158 source: model.icon 0159 } 0160 0161 PlasmaComponents3.ToolButton { 0162 id: closeButton 0163 anchors { 0164 right: parent.right 0165 top: parent.top 0166 // Deliberately touch the inner edges of the frame 0167 rightMargin: -columnLayout.anchors.rightMargin 0168 topMargin: -columnLayout.anchors.topMargin 0169 } 0170 visible: model.closeable && typeof tabBox.model.close !== 'undefined' && 0171 (thumbnailGridItem.containsMouse 0172 || closeButton.hovered 0173 || thumbnailGridItem.focus 0174 || Kirigami.Settings.tabletMode 0175 || Kirigami.Settings.hasTransientTouchInput 0176 ) 0177 icon.name: 'window-close-symbolic' 0178 onClicked: { 0179 tabBox.model.close(index); 0180 } 0181 } 0182 } 0183 0184 PlasmaComponents3.Label { 0185 Layout.fillWidth: true 0186 text: model.caption 0187 font.weight: thumbnailGridItem.focus ? Font.Bold : Font.Normal 0188 horizontalAlignment: Text.AlignHCenter 0189 verticalAlignment: Text.AlignVCenter 0190 textFormat: Text.PlainText 0191 elide: Text.ElideRight 0192 } 0193 } 0194 } // GridView.delegate 0195 0196 highlight: KSvg.FrameSvgItem { 0197 imagePath: "widgets/viewitem" 0198 prefix: "hover" 0199 } 0200 0201 onCurrentIndexChanged: tabBox.currentIndex = thumbnailGridView.currentIndex; 0202 } // GridView 0203 0204 Kirigami.PlaceholderMessage { 0205 anchors.centerIn: parent 0206 width: parent.width - Kirigami.Units.largeSpacing * 2 0207 icon.source: "edit-none" 0208 text: i18ndc("kwin", "@info:placeholder no entries in the task switcher", "No open windows") 0209 visible: thumbnailGridView.count === 0 0210 } 0211 0212 Keys.onPressed: { 0213 if (event.key == Qt.Key_Left) { 0214 thumbnailGridView.moveCurrentIndexLeft(); 0215 } else if (event.key == Qt.Key_Right) { 0216 thumbnailGridView.moveCurrentIndexRight(); 0217 } else if (event.key == Qt.Key_Up) { 0218 thumbnailGridView.moveCurrentIndexUp(); 0219 } else if (event.key == Qt.Key_Down) { 0220 thumbnailGridView.moveCurrentIndexDown(); 0221 } else { 0222 return; 0223 } 0224 0225 thumbnailGridView.currentIndexChanged(thumbnailGridView.currentIndex); 0226 } 0227 } // Dialog.mainItem 0228 } // Dialog 0229 } // Instantiator 0230 }