mirror of
https://invent.kde.org/marcoa/shift-shell.git
synced 2026-04-26 14:23:09 +00:00
Show numbered desktop indicator buttons between the nav buttons and the keyboard toggle corner button. Each button highlights the current desktop and switches on click via VirtualDesktopInfo.requestActivate. Only visible in convergence mode when multiple desktops exist. Add Minimize and Maximize/Restore actions to the task strip right-click context menu alongside the existing Close action.
424 lines
15 KiB
QML
424 lines
15 KiB
QML
/*
|
|
* SPDX-FileCopyrightText: 2015 Marco Martin <mart@kde.org>
|
|
* SPDX-FileCopyrightText: 2021 Devin Lin <devin@kde.org>
|
|
*
|
|
* SPDX-License-Identifier: GPL-2.0-or-later
|
|
*/
|
|
|
|
import QtQuick
|
|
import QtQuick.Layouts
|
|
import QtQuick.Window
|
|
import QtQuick.Effects
|
|
import QtQuick.Controls as Controls
|
|
|
|
import org.kde.kirigami as Kirigami
|
|
import org.kde.taskmanager 0.1 as TaskManager
|
|
import org.kde.kquickcontrolsaddons 2.0
|
|
import org.kde.plasma.private.mobileshell.state as MobileShellState
|
|
|
|
Item {
|
|
id: root
|
|
|
|
property bool shadow: false
|
|
property color backgroundColor
|
|
property var foregroundColorGroup
|
|
|
|
property NavigationPanelAction leftAction
|
|
property NavigationPanelAction middleAction
|
|
property NavigationPanelAction rightAction
|
|
|
|
property NavigationPanelAction leftCornerAction
|
|
property NavigationPanelAction rightCornerAction
|
|
|
|
property real leftPadding: 0
|
|
property real rightPadding: 0
|
|
|
|
property bool isVertical: false
|
|
|
|
// Convergence mode: show running-app task strip
|
|
property bool convergenceMode: false
|
|
property var taskModel: null
|
|
property var virtualDesktopInfo: null
|
|
|
|
// drop shadow for icons
|
|
MultiEffect {
|
|
anchors.fill: icons
|
|
visible: shadow
|
|
source: icons
|
|
blurMax: 16
|
|
shadowEnabled: true
|
|
shadowVerticalOffset: 1
|
|
shadowOpacity: 0.8
|
|
}
|
|
|
|
// background colour
|
|
Rectangle {
|
|
anchors.fill: parent
|
|
color: root.backgroundColor
|
|
}
|
|
|
|
Item {
|
|
id: icons
|
|
anchors.fill: parent
|
|
|
|
property real buttonLength: 0
|
|
|
|
NavigationPanelButton {
|
|
id: leftCornerButton
|
|
visible: root.leftCornerAction.visible
|
|
Kirigami.Theme.colorSet: root.foregroundColorGroup
|
|
Kirigami.Theme.inherit: false
|
|
enabled: root.leftCornerAction.enabled
|
|
shrinkSize: root.leftCornerAction.shrinkSize
|
|
iconSource: root.leftCornerAction.iconSource
|
|
onClicked: {
|
|
if (enabled) {
|
|
root.leftCornerAction.triggered();
|
|
}
|
|
}
|
|
}
|
|
|
|
// button row (anchors provided by state)
|
|
NavigationPanelButton {
|
|
id: leftButton
|
|
visible: root.leftAction.visible
|
|
Kirigami.Theme.colorSet: root.foregroundColorGroup
|
|
Kirigami.Theme.inherit: false
|
|
enabled: root.leftAction.enabled
|
|
shrinkSize: root.leftAction.shrinkSize
|
|
iconSource: root.leftAction.iconSource
|
|
onClicked: {
|
|
if (enabled) {
|
|
root.leftAction.triggered();
|
|
}
|
|
}
|
|
}
|
|
|
|
NavigationPanelButton {
|
|
id: middleButton
|
|
anchors.centerIn: parent
|
|
visible: root.middleAction.visible
|
|
Kirigami.Theme.colorSet: root.foregroundColorGroup
|
|
Kirigami.Theme.inherit: false
|
|
enabled: root.middleAction.enabled
|
|
shrinkSize: root.middleAction.shrinkSize
|
|
iconSource: root.middleAction.iconSource
|
|
onClicked: {
|
|
if (enabled) {
|
|
root.middleAction.triggered();
|
|
}
|
|
}
|
|
}
|
|
|
|
NavigationPanelButton {
|
|
id: rightButton
|
|
visible: root.rightAction.visible
|
|
Kirigami.Theme.colorSet: root.foregroundColorGroup
|
|
Kirigami.Theme.inherit: false
|
|
enabled: root.rightAction.enabled
|
|
shrinkSize: root.rightAction.shrinkSize
|
|
iconSource: root.rightAction.iconSource
|
|
onClicked: {
|
|
if (enabled) {
|
|
root.rightAction.triggered();
|
|
}
|
|
}
|
|
}
|
|
|
|
NavigationPanelButton {
|
|
id: rightCornerButton
|
|
visible: root.rightCornerAction.visible
|
|
Kirigami.Theme.colorSet: root.foregroundColorGroup
|
|
Kirigami.Theme.inherit: false
|
|
enabled: root.rightCornerAction.enabled
|
|
shrinkSize: root.rightCornerAction.shrinkSize
|
|
iconSource: root.rightCornerAction.iconSource
|
|
onClicked: {
|
|
if (enabled) {
|
|
root.rightCornerAction.triggered();
|
|
}
|
|
}
|
|
}
|
|
|
|
// Running-app task strip for convergence (desktop) mode
|
|
ListView {
|
|
id: taskStrip
|
|
visible: root.convergenceMode && root.taskModel !== null && root.taskModel.count > 0
|
|
orientation: root.isVertical ? ListView.Vertical : ListView.Horizontal
|
|
spacing: Kirigami.Units.smallSpacing
|
|
clip: true
|
|
interactive: contentWidth > width
|
|
model: root.taskModel
|
|
|
|
delegate: NavigationPanelButton {
|
|
id: taskDelegate
|
|
required property int index
|
|
required property var model
|
|
width: taskStrip.orientation === ListView.Horizontal ? height : taskStrip.width
|
|
height: taskStrip.orientation === ListView.Horizontal ? taskStrip.height : taskStrip.width
|
|
|
|
Kirigami.Theme.colorSet: root.foregroundColorGroup
|
|
Kirigami.Theme.inherit: false
|
|
iconSource: taskDelegate.model.decoration
|
|
enabled: true
|
|
shrinkSize: 0
|
|
|
|
onClicked: {
|
|
root.taskModel.requestActivate(root.taskModel.makeModelIndex(taskDelegate.index));
|
|
}
|
|
|
|
// Right-click context menu
|
|
MouseArea {
|
|
anchors.fill: parent
|
|
acceptedButtons: Qt.RightButton
|
|
onClicked: taskContextMenu.popup()
|
|
}
|
|
|
|
Controls.Menu {
|
|
id: taskContextMenu
|
|
Controls.MenuItem {
|
|
text: taskDelegate.model.IsMinimized ? i18n("Restore") : i18n("Minimize")
|
|
icon.name: taskDelegate.model.IsMinimized ? "window-restore" : "window-minimize"
|
|
onTriggered: root.taskModel.requestToggleMinimized(root.taskModel.makeModelIndex(taskDelegate.index))
|
|
}
|
|
Controls.MenuItem {
|
|
text: taskDelegate.model.IsMaximized ? i18n("Restore") : i18n("Maximize")
|
|
icon.name: taskDelegate.model.IsMaximized ? "window-restore" : "window-maximize"
|
|
onTriggered: root.taskModel.requestToggleMaximized(root.taskModel.makeModelIndex(taskDelegate.index))
|
|
}
|
|
Controls.MenuSeparator {}
|
|
Controls.MenuItem {
|
|
text: i18n("Close")
|
|
icon.name: "window-close"
|
|
onTriggered: root.taskModel.requestClose(root.taskModel.makeModelIndex(taskDelegate.index))
|
|
}
|
|
}
|
|
|
|
// Active-window indicator dot
|
|
Rectangle {
|
|
anchors.bottom: parent.bottom
|
|
anchors.horizontalCenter: parent.horizontalCenter
|
|
anchors.bottomMargin: Kirigami.Units.smallSpacing / 2
|
|
width: Kirigami.Units.smallSpacing * 2
|
|
height: width
|
|
radius: width / 2
|
|
color: Kirigami.Theme.highlightColor
|
|
visible: taskDelegate.model.IsActive === true
|
|
}
|
|
}
|
|
}
|
|
|
|
// Virtual desktop switcher (convergence mode, multiple desktops)
|
|
Row {
|
|
id: workspaceIndicator
|
|
visible: root.convergenceMode && root.virtualDesktopInfo !== null && root.virtualDesktopInfo.numberOfDesktops > 1
|
|
spacing: Kirigami.Units.smallSpacing / 2
|
|
|
|
Repeater {
|
|
model: root.virtualDesktopInfo ? root.virtualDesktopInfo.desktopIds : []
|
|
|
|
delegate: Rectangle {
|
|
required property int index
|
|
required property var modelData
|
|
width: Kirigami.Units.gridUnit * 1.5
|
|
height: width
|
|
radius: Kirigami.Units.smallSpacing
|
|
|
|
color: modelData === root.virtualDesktopInfo.currentDesktop
|
|
? Kirigami.Theme.highlightColor
|
|
: Qt.rgba(Kirigami.Theme.textColor.r, Kirigami.Theme.textColor.g, Kirigami.Theme.textColor.b, 0.2)
|
|
|
|
Text {
|
|
anchors.centerIn: parent
|
|
text: index + 1
|
|
color: parent.modelData === root.virtualDesktopInfo.currentDesktop
|
|
? Kirigami.Theme.highlightedTextColor
|
|
: Kirigami.Theme.textColor
|
|
font.pixelSize: parent.height * 0.6
|
|
}
|
|
|
|
MouseArea {
|
|
anchors.fill: parent
|
|
onClicked: root.virtualDesktopInfo.requestActivate(parent.modelData)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
states: [
|
|
State {
|
|
name: "vertical"
|
|
when: root.isVertical
|
|
PropertyChanges {
|
|
target: icons
|
|
anchors {
|
|
topMargin: root.leftPadding
|
|
bottomMargin: root.rightPadding
|
|
}
|
|
buttonLength: Math.min(Kirigami.Units.gridUnit * 10, icons.height * 0.7 / 3)
|
|
}
|
|
AnchorChanges {
|
|
target: leftButton
|
|
anchors {
|
|
horizontalCenter: parent.horizontalCenter
|
|
top: middleButton.bottom
|
|
}
|
|
}
|
|
PropertyChanges {
|
|
target: leftButton
|
|
width: parent.width
|
|
height: icons.buttonLength
|
|
}
|
|
PropertyChanges {
|
|
target: middleButton
|
|
width: parent.width
|
|
height: icons.buttonLength
|
|
}
|
|
AnchorChanges {
|
|
target: rightButton
|
|
anchors {
|
|
horizontalCenter: parent.horizontalCenter
|
|
bottom: middleButton.top
|
|
}
|
|
}
|
|
PropertyChanges {
|
|
target: rightButton
|
|
height: icons.buttonLength
|
|
width: icons.width
|
|
}
|
|
AnchorChanges {
|
|
target: rightCornerButton
|
|
anchors {
|
|
horizontalCenter: parent.horizontalCenter
|
|
top: parent.top
|
|
}
|
|
}
|
|
PropertyChanges {
|
|
target: rightCornerButton
|
|
height: Kirigami.Units.gridUnit * 2
|
|
width: icons.width
|
|
}
|
|
AnchorChanges {
|
|
target: leftCornerButton
|
|
anchors {
|
|
horizontalCenter: parent.horizontalCenter
|
|
bottom: parent.bottom
|
|
}
|
|
}
|
|
PropertyChanges {
|
|
target: leftCornerButton
|
|
height: Kirigami.Units.gridUnit * 2
|
|
width: icons.width
|
|
}
|
|
// Task strip: vertical layout — positioned between leftCornerButton (bottom) and leftButton (above middle)
|
|
AnchorChanges {
|
|
target: taskStrip
|
|
anchors {
|
|
horizontalCenter: parent.horizontalCenter
|
|
bottom: leftButton.top
|
|
top: undefined
|
|
}
|
|
}
|
|
PropertyChanges {
|
|
target: taskStrip
|
|
width: parent.width
|
|
// Fill space between leftCorner (bottom) and the nav button group
|
|
height: taskStrip.visible ? (leftButton.y - leftCornerButton.y - leftCornerButton.height - Kirigami.Units.smallSpacing * 2) : 0
|
|
}
|
|
// Workspace indicator: vertical — above rightCornerButton (top)
|
|
AnchorChanges {
|
|
target: workspaceIndicator
|
|
anchors {
|
|
horizontalCenter: parent.horizontalCenter
|
|
top: rightCornerButton.bottom
|
|
}
|
|
}
|
|
}, State {
|
|
name: "horizontal"
|
|
when: !root.isVertical
|
|
PropertyChanges {
|
|
target: icons
|
|
anchors {
|
|
leftMargin: root.leftPadding
|
|
rightMargin: root.rightPadding
|
|
}
|
|
buttonLength: Math.min(Kirigami.Units.gridUnit * 8, icons.width * 0.7 / 3)
|
|
}
|
|
AnchorChanges {
|
|
target: leftButton
|
|
anchors {
|
|
verticalCenter: parent.verticalCenter
|
|
right: middleButton.left
|
|
}
|
|
}
|
|
PropertyChanges {
|
|
target: leftButton
|
|
height: parent.height
|
|
width: icons.buttonLength
|
|
}
|
|
PropertyChanges {
|
|
target: middleButton
|
|
height: parent.height
|
|
width: icons.buttonLength
|
|
}
|
|
AnchorChanges {
|
|
target: rightButton
|
|
anchors {
|
|
verticalCenter: parent.verticalCenter
|
|
left: middleButton.right
|
|
}
|
|
}
|
|
PropertyChanges {
|
|
target: rightButton
|
|
height: parent.height
|
|
width: icons.buttonLength
|
|
}
|
|
AnchorChanges {
|
|
target: rightCornerButton
|
|
anchors {
|
|
verticalCenter: parent.verticalCenter
|
|
right: parent.right
|
|
}
|
|
}
|
|
PropertyChanges {
|
|
target: rightCornerButton
|
|
height: parent.height
|
|
width: Kirigami.Units.gridUnit * 2
|
|
}
|
|
AnchorChanges {
|
|
target: leftCornerButton
|
|
anchors {
|
|
verticalCenter: parent.verticalCenter
|
|
left: parent.left
|
|
}
|
|
}
|
|
PropertyChanges {
|
|
target: leftCornerButton
|
|
height: parent.height
|
|
width: Kirigami.Units.gridUnit * 2
|
|
}
|
|
// Task strip: horizontal layout — positioned between leftCornerButton (left) and leftButton (near center)
|
|
AnchorChanges {
|
|
target: taskStrip
|
|
anchors {
|
|
verticalCenter: parent.verticalCenter
|
|
left: leftCornerButton.right
|
|
right: leftButton.left
|
|
}
|
|
}
|
|
PropertyChanges {
|
|
target: taskStrip
|
|
height: parent.height
|
|
}
|
|
// Workspace indicator: horizontal — between rightButton and rightCornerButton
|
|
AnchorChanges {
|
|
target: workspaceIndicator
|
|
anchors {
|
|
verticalCenter: parent.verticalCenter
|
|
left: rightButton.right
|
|
}
|
|
}
|
|
}
|
|
]
|
|
}
|