mirror of
https://invent.kde.org/marcoa/shift-shell.git
synced 2026-04-26 14:23:09 +00:00
NavigationPanel: the taskStrip ListView checked contentWidth > width to decide whether scrolling is enabled, which is wrong when the panel is vertical. Check contentHeight > height in that case. taskpanel: dockSpaceReserver used a hardcoded gridUnit * 3 for both height and exclusionZone. Use navigationPanelHeight so the reserved strip tracks the actual panel thickness.
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: root.isVertical ? contentHeight > height : 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
|
|
}
|
|
}
|
|
}
|
|
]
|
|
}
|