mirror of
https://invent.kde.org/marcoa/shift-shell.git
synced 2026-04-26 14:23:09 +00:00
In convergence mode the separate navigation panel is redundant with window title-bar controls. Remove it by setting its thickness to zero and visibility to false, then embed Home and Overview buttons at the left and right ends of the favourites bar. Running application icons with context menus are shown between the favourites and the Overview button. Add HomeScreen::triggerOverview() to invoke the KWin Overview shortcut over D-Bus so the homescreen containment can open it without access to the task-panel Plasmoid.
498 lines
17 KiB
QML
498 lines
17 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
|
|
// NOTE: Disabled — running apps now shown in FavouritesBar dock
|
|
ListView {
|
|
id: taskStrip
|
|
visible: false
|
|
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: "convergence-horizontal"
|
|
when: !root.isVertical && root.convergenceMode
|
|
PropertyChanges {
|
|
target: icons
|
|
anchors {
|
|
leftMargin: root.leftPadding
|
|
rightMargin: root.rightPadding
|
|
}
|
|
buttonLength: Math.min(Kirigami.Units.gridUnit * 8, icons.width * 0.7 / 3)
|
|
}
|
|
// Home button: far left
|
|
AnchorChanges {
|
|
target: middleButton
|
|
anchors {
|
|
verticalCenter: parent.verticalCenter
|
|
left: parent.left
|
|
right: undefined
|
|
}
|
|
}
|
|
PropertyChanges {
|
|
target: middleButton
|
|
height: parent.height
|
|
width: icons.buttonLength
|
|
anchors.centerIn: undefined
|
|
}
|
|
// Overview button: far right
|
|
AnchorChanges {
|
|
target: leftButton
|
|
anchors {
|
|
verticalCenter: parent.verticalCenter
|
|
right: parent.right
|
|
left: undefined
|
|
}
|
|
}
|
|
PropertyChanges {
|
|
target: leftButton
|
|
height: parent.height
|
|
width: icons.buttonLength
|
|
}
|
|
// Hide close button (already not visible via action)
|
|
PropertyChanges {
|
|
target: rightButton
|
|
height: parent.height
|
|
width: 0
|
|
visible: false
|
|
}
|
|
// Hide corner buttons in convergence
|
|
PropertyChanges {
|
|
target: leftCornerButton
|
|
width: 0
|
|
visible: false
|
|
}
|
|
PropertyChanges {
|
|
target: rightCornerButton
|
|
width: 0
|
|
visible: false
|
|
}
|
|
// Workspace indicator: left of Overview button
|
|
AnchorChanges {
|
|
target: workspaceIndicator
|
|
anchors {
|
|
verticalCenter: parent.verticalCenter
|
|
right: leftButton.left
|
|
left: undefined
|
|
}
|
|
}
|
|
// Task strip hidden
|
|
PropertyChanges {
|
|
target: taskStrip
|
|
height: 0
|
|
visible: false
|
|
}
|
|
}, 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
|
|
}
|
|
}
|
|
}
|
|
]
|
|
}
|