effects/overview: Add desktop bar
This provides a way to create, destroy, and rename virtual desktops in the overview effect as well as switch between desktops. The mechanics of switching between virtual desktops can be revisited later though.
This commit is contained in:
parent
d73610d6d6
commit
ce2fc670c4
6 changed files with 392 additions and 19 deletions
|
@ -261,6 +261,11 @@ void OverviewEffect::deactivate()
|
|||
m_shutdownTimer->start(animationDuration());
|
||||
}
|
||||
|
||||
void OverviewEffect::quickDeactivate()
|
||||
{
|
||||
m_shutdownTimer->start(0);
|
||||
}
|
||||
|
||||
void OverviewEffect::realDeactivate()
|
||||
{
|
||||
qDeleteAll(m_screenViews);
|
||||
|
|
|
@ -70,6 +70,7 @@ Q_SIGNALS:
|
|||
public Q_SLOTS:
|
||||
void activate();
|
||||
void deactivate();
|
||||
void quickDeactivate();
|
||||
void toggle();
|
||||
|
||||
private:
|
||||
|
|
257
src/effects/overview/qml/DesktopBar.qml
Normal file
257
src/effects/overview/qml/DesktopBar.qml
Normal file
|
@ -0,0 +1,257 @@
|
|||
/*
|
||||
SPDX-FileCopyrightText: 2021 Vlad Zahorodnii <vlad.zahorodnii@kde.org>
|
||||
|
||||
SPDX-License-Identifier: GPL-2.0-or-later
|
||||
*/
|
||||
|
||||
import QtQuick 2.12
|
||||
import QtQuick.Controls 2.12
|
||||
import QtQuick.Layouts 1.12
|
||||
import QtGraphicalEffects 1.12
|
||||
import org.kde.kirigami 2.12 as Kirigami
|
||||
import org.kde.kwin 3.0 as KWinComponents
|
||||
import org.kde.plasma.components 3.0 as PC3
|
||||
import org.kde.plasma.core 2.0 as PlasmaCore
|
||||
|
||||
Item {
|
||||
id: bar
|
||||
|
||||
readonly property real desktopHeight: PlasmaCore.Units.gridUnit * 4
|
||||
readonly property real desktopWidth: desktopHeight * targetScreen.geometry.width / targetScreen.geometry.height
|
||||
readonly property real columnHeight: desktopHeight + PlasmaCore.Units.gridUnit
|
||||
|
||||
property QtObject clientModel
|
||||
property alias desktopModel: desktopRepeater.model
|
||||
property QtObject selectedDesktop: null
|
||||
|
||||
implicitHeight: columnHeight + 2 * PlasmaCore.Units.smallSpacing
|
||||
|
||||
Flickable {
|
||||
anchors.fill: parent
|
||||
leftMargin: Math.max((width - contentWidth) / 2, 0)
|
||||
topMargin: Math.max((height - contentHeight) / 2, 0)
|
||||
contentWidth: contentItem.childrenRect.width
|
||||
contentHeight: contentItem.childrenRect.height
|
||||
clip: true
|
||||
flickableDirection: Flickable.HorizontalFlick
|
||||
|
||||
Row {
|
||||
spacing: PlasmaCore.Units.largeSpacing
|
||||
|
||||
Repeater {
|
||||
id: desktopRepeater
|
||||
|
||||
Column {
|
||||
id: delegate
|
||||
width: bar.desktopWidth
|
||||
height: bar.columnHeight
|
||||
spacing: PlasmaCore.Units.smallSpacing
|
||||
|
||||
required property QtObject desktop
|
||||
required property int index
|
||||
|
||||
function remove() {
|
||||
bar.desktopModel.remove(delegate.index);
|
||||
}
|
||||
|
||||
Item {
|
||||
width: bar.desktopWidth
|
||||
height: bar.desktopHeight
|
||||
|
||||
Rectangle {
|
||||
id: mask
|
||||
anchors.fill: parent
|
||||
radius: 3
|
||||
visible: false
|
||||
}
|
||||
|
||||
DesktopView {
|
||||
id: thumbnail
|
||||
|
||||
property bool scaled: state == "scaled"
|
||||
|
||||
width: targetScreen.geometry.width
|
||||
height: targetScreen.geometry.height
|
||||
visible: scaled
|
||||
clientModel: bar.clientModel
|
||||
desktop: delegate.desktop
|
||||
scale: bar.desktopHeight / targetScreen.geometry.height
|
||||
transformOrigin: Item.TopLeft
|
||||
|
||||
// Disable the item layer while being scaled.
|
||||
layer.enabled: !scaled
|
||||
layer.textureSize: Qt.size(bar.desktopWidth, bar.desktopHeight)
|
||||
|
||||
states: State {
|
||||
name: "scaled"
|
||||
ParentChange {
|
||||
target: thumbnail
|
||||
parent: container
|
||||
x: 0
|
||||
y: 0
|
||||
scale: 1
|
||||
}
|
||||
}
|
||||
|
||||
transitions: Transition {
|
||||
SequentialAnimation {
|
||||
ParentAnimation {
|
||||
NumberAnimation {
|
||||
properties: "x,y,scale"
|
||||
duration: effect.animationDuration
|
||||
easing.type: Easing.OutCubic
|
||||
}
|
||||
}
|
||||
ScriptAction {
|
||||
script: {
|
||||
KWinComponents.Workspace.currentVirtualDesktop = delegate.desktop;
|
||||
effect.quickDeactivate();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
OpacityMask {
|
||||
anchors.fill: parent
|
||||
cached: true
|
||||
source: thumbnail
|
||||
maskSource: mask
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
anchors.fill: parent
|
||||
radius: 3
|
||||
color: "transparent"
|
||||
border.width: 2
|
||||
border.color: PlasmaCore.ColorScope.highlightColor
|
||||
opacity: dropArea.containsDrag ? 0.5 : 1.0
|
||||
visible: !thumbnail.scaled && (dropArea.containsDrag || bar.selectedDesktop == delegate.desktop)
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
anchors.fill: parent
|
||||
acceptedButtons: Qt.LeftButton | Qt.MiddleButton
|
||||
onClicked: {
|
||||
mouse.accepted = true;
|
||||
switch (mouse.button) {
|
||||
case Qt.LeftButton:
|
||||
thumbnail.state = "scaled";
|
||||
break;
|
||||
case Qt.MiddleButton:
|
||||
delegate.remove();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Loader {
|
||||
LayoutMirroring.enabled: Qt.application.layoutDirection == Qt.RightToLeft
|
||||
active: hoverHandler.hovered
|
||||
anchors.right: parent.right
|
||||
anchors.top: parent.top
|
||||
sourceComponent: PC3.Button {
|
||||
icon.name: "delete"
|
||||
onClicked: delegate.remove()
|
||||
}
|
||||
}
|
||||
|
||||
DropArea {
|
||||
id: dropArea
|
||||
anchors.fill: parent
|
||||
|
||||
onEntered: {
|
||||
drag.accepted = true;
|
||||
}
|
||||
onDropped: {
|
||||
drag.source.desktop = delegate.desktop.x11DesktopNumber;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Item {
|
||||
id: label
|
||||
width: bar.desktopWidth
|
||||
height: PlasmaCore.Units.gridUnit
|
||||
state: "normal"
|
||||
|
||||
PC3.Label {
|
||||
PlasmaCore.ColorScope.colorGroup: PlasmaCore.Theme.ComplementaryColorGroup
|
||||
anchors.fill: parent
|
||||
elide: Text.ElideRight
|
||||
text: delegate.desktop.name
|
||||
horizontalAlignment: Text.AlignHCenter
|
||||
verticalAlignment: Text.AlignVCenter
|
||||
visible: label.state == "normal"
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
anchors.fill: parent
|
||||
onPressed: {
|
||||
mouse.accepted = true;
|
||||
label.startEditing();
|
||||
}
|
||||
}
|
||||
|
||||
TextInput {
|
||||
id: editor
|
||||
anchors.fill: parent
|
||||
visible: label.state == "editing"
|
||||
color: PlasmaCore.ColorScope.textColor
|
||||
text: delegate.desktop.name
|
||||
onAccepted: {
|
||||
delegate.desktop.name = text;
|
||||
label.stopEditing();
|
||||
}
|
||||
Keys.onEscapePressed: label.stopEditing();
|
||||
}
|
||||
|
||||
states: [
|
||||
State {
|
||||
name: "normal"
|
||||
},
|
||||
State {
|
||||
name: "editing"
|
||||
}
|
||||
]
|
||||
|
||||
function startEditing() {
|
||||
state = "editing";
|
||||
editor.forceActiveFocus();
|
||||
}
|
||||
function stopEditing() {
|
||||
state = "normal";
|
||||
}
|
||||
}
|
||||
|
||||
HoverHandler {
|
||||
id: hoverHandler
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
PC3.Button {
|
||||
width: bar.desktopWidth
|
||||
height: bar.desktopHeight
|
||||
icon.name: "list-add"
|
||||
opacity: hovered ? 1 : 0.75
|
||||
onClicked: desktopModel.create(desktopModel.rowCount())
|
||||
|
||||
ToolTip.text: i18n("Add Desktop")
|
||||
ToolTip.visible: hovered
|
||||
ToolTip.delay: Kirigami.Units.toolTipDelay
|
||||
|
||||
DropArea {
|
||||
anchors.fill: parent
|
||||
onEntered: {
|
||||
drag.accepted = desktopModel.rowCount() < 20
|
||||
}
|
||||
onDropped: {
|
||||
desktopModel.create(desktopModel.rowCount());
|
||||
drag.source.desktop = desktopModel.rowCount() + 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
33
src/effects/overview/qml/DesktopView.qml
Normal file
33
src/effects/overview/qml/DesktopView.qml
Normal file
|
@ -0,0 +1,33 @@
|
|||
/*
|
||||
SPDX-FileCopyrightText: 2021 Vlad Zahorodnii <vlad.zahorodnii@kde.org>
|
||||
|
||||
SPDX-License-Identifier: GPL-2.0-or-later
|
||||
*/
|
||||
|
||||
import QtQuick 2.12
|
||||
import org.kde.kwin 3.0 as KWinComponents
|
||||
|
||||
Item {
|
||||
id: desktopView
|
||||
|
||||
required property QtObject clientModel
|
||||
required property QtObject desktop
|
||||
|
||||
Repeater {
|
||||
model: KWinComponents.ClientFilterModel {
|
||||
activity: KWinComponents.Workspace.currentActivity
|
||||
desktop: desktopView.desktop
|
||||
screenName: targetScreen.name
|
||||
clientModel: desktopView.clientModel
|
||||
}
|
||||
|
||||
KWinComponents.WindowThumbnailItem {
|
||||
wId: model.client.internalId
|
||||
x: model.client.x - targetScreen.geometry.x
|
||||
y: model.client.y - targetScreen.geometry.y
|
||||
width: model.client.width
|
||||
height: model.client.height
|
||||
z: model.client.stackingOrder
|
||||
}
|
||||
}
|
||||
}
|
|
@ -89,34 +89,56 @@ FocusScope {
|
|||
height: heapArea.height
|
||||
|
||||
Item {
|
||||
id: searchBar
|
||||
width: parent.width
|
||||
height: searchField.height + 2 * PlasmaCore.Units.largeSpacing
|
||||
id: topBar
|
||||
state: container.organized ? "visible" : "hidden"
|
||||
width: parent.width
|
||||
height: searchBar.height + desktopBar.height
|
||||
|
||||
PC3.TextField {
|
||||
id: searchField
|
||||
anchors.centerIn: parent
|
||||
width: Math.min(parent.width, 20 * PlasmaCore.Units.gridUnit)
|
||||
focus: true
|
||||
placeholderText: i18n("Search...")
|
||||
clearButtonShown: true
|
||||
Keys.priority: Keys.AfterItem
|
||||
Keys.forwardTo: heap
|
||||
Rectangle {
|
||||
id: desktopBar
|
||||
width: parent.width
|
||||
implicitHeight: bar.implicitHeight + 2 * PlasmaCore.Units.smallSpacing
|
||||
color: Qt.rgba(0, 0, 0, 0.25)
|
||||
|
||||
DesktopBar {
|
||||
id: bar
|
||||
anchors.fill: parent
|
||||
clientModel: stackModel
|
||||
desktopModel: desktopModel
|
||||
selectedDesktop: KWinComponents.Workspace.currentVirtualDesktop
|
||||
}
|
||||
}
|
||||
|
||||
Item {
|
||||
id: searchBar
|
||||
anchors.top: desktopBar.bottom
|
||||
width: parent.width
|
||||
height: searchField.height + 2 * PlasmaCore.Units.largeSpacing
|
||||
|
||||
PC3.TextField {
|
||||
id: searchField
|
||||
anchors.centerIn: parent
|
||||
width: Math.min(parent.width, 20 * PlasmaCore.Units.gridUnit)
|
||||
focus: true
|
||||
placeholderText: i18n("Search...")
|
||||
clearButtonShown: true
|
||||
Keys.priority: Keys.AfterItem
|
||||
Keys.forwardTo: heap
|
||||
}
|
||||
}
|
||||
|
||||
states: [
|
||||
State {
|
||||
name: "hidden"
|
||||
PropertyChanges {
|
||||
target: searchBar
|
||||
target: topBar
|
||||
opacity: 0
|
||||
}
|
||||
},
|
||||
State {
|
||||
name: "visible"
|
||||
PropertyChanges {
|
||||
target: searchBar
|
||||
target: topBar
|
||||
opacity: 1
|
||||
}
|
||||
}
|
||||
|
@ -141,7 +163,7 @@ FocusScope {
|
|||
WindowHeap {
|
||||
id: heap
|
||||
width: parent.width
|
||||
height: parent.height - searchBar.height
|
||||
height: parent.height - topBar.height
|
||||
padding: PlasmaCore.Units.largeSpacing
|
||||
filter: searchField.text
|
||||
animationEnabled: container.animationEnabled
|
||||
|
@ -184,5 +206,9 @@ FocusScope {
|
|||
id: stackModel
|
||||
}
|
||||
|
||||
KWinComponents.VirtualDesktopModel {
|
||||
id: desktopModel
|
||||
}
|
||||
|
||||
Component.onCompleted: start();
|
||||
}
|
||||
|
|
|
@ -65,12 +65,40 @@ FocusScope {
|
|||
}
|
||||
|
||||
visible: opacity > 0
|
||||
z: client.stackingOrder
|
||||
z: dragHandler.active ? 100 : client.stackingOrder
|
||||
|
||||
KWinComponents.WindowThumbnailItem {
|
||||
id: thumbSource
|
||||
anchors.fill: parent
|
||||
wId: thumb.client.internalId
|
||||
state: dragHandler.active ? "drag" : "normal"
|
||||
|
||||
Drag.active: dragHandler.active
|
||||
Drag.source: thumb.client
|
||||
|
||||
states: [
|
||||
State {
|
||||
name: "normal"
|
||||
PropertyChanges {
|
||||
target: thumbSource
|
||||
x: 0
|
||||
y: 0
|
||||
width: thumb.width
|
||||
height: thumb.height
|
||||
}
|
||||
},
|
||||
State {
|
||||
name: "drag"
|
||||
PropertyChanges {
|
||||
target: thumbSource
|
||||
x: -dragHandler.centroid.pressPosition.x * dragHandler.targetScale +
|
||||
dragHandler.centroid.position.x
|
||||
y: -dragHandler.centroid.pressPosition.y * dragHandler.targetScale +
|
||||
dragHandler.centroid.position.y
|
||||
width: cell.width * dragHandler.targetScale
|
||||
height: cell.height * dragHandler.targetScale
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
PlasmaCore.IconItem {
|
||||
|
@ -81,6 +109,7 @@ FocusScope {
|
|||
anchors.horizontalCenter: thumbSource.horizontalCenter
|
||||
anchors.bottom: thumbSource.bottom
|
||||
anchors.bottomMargin: -height / 4
|
||||
visible: !dragHandler.active
|
||||
}
|
||||
|
||||
PC3.Label {
|
||||
|
@ -92,6 +121,7 @@ FocusScope {
|
|||
text: thumb.client.caption
|
||||
horizontalAlignment: Text.AlignHCenter
|
||||
verticalAlignment: Text.AlignVCenter
|
||||
visible: !dragHandler.active
|
||||
PlasmaCore.ColorScope.colorGroup: PlasmaCore.Theme.ComplementaryColorGroup
|
||||
|
||||
layer.enabled: true
|
||||
|
@ -157,7 +187,7 @@ FocusScope {
|
|||
]
|
||||
|
||||
component TweenBehavior : Behavior {
|
||||
enabled: heap.animationEnabled
|
||||
enabled: heap.animationEnabled && !dragHandler.active
|
||||
NumberAnimation {
|
||||
duration: effect.animationDuration
|
||||
easing.type: Easing.InOutCubic
|
||||
|
@ -199,6 +229,27 @@ FocusScope {
|
|||
onTapped: thumb.client.closeWindow()
|
||||
}
|
||||
|
||||
DragHandler {
|
||||
id: dragHandler
|
||||
target: null
|
||||
|
||||
readonly property double targetScale: {
|
||||
const localPressPosition = centroid.scenePressPosition.y - expoLayout.Kirigami.ScenePosition.y;
|
||||
if (localPressPosition == 0) {
|
||||
return 0.1
|
||||
} else {
|
||||
const localPosition = centroid.scenePosition.y - expoLayout.Kirigami.ScenePosition.y;
|
||||
return Math.max(0.1, Math.min(localPosition / localPressPosition, 1))
|
||||
}
|
||||
}
|
||||
|
||||
onActiveChanged: {
|
||||
if (!active) {
|
||||
thumbSource.Drag.drop();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
PC3.Button {
|
||||
LayoutMirroring.enabled: Qt.application.layoutDirection == Qt.RightToLeft
|
||||
icon.name: "window-close"
|
||||
|
@ -208,7 +259,7 @@ FocusScope {
|
|||
anchors.topMargin: PlasmaCore.Units.largeSpacing
|
||||
implicitWidth: PlasmaCore.Units.iconSizes.medium
|
||||
implicitHeight: implicitWidth
|
||||
visible: (hovered || hoverHandler.hovered) && thumb.client.closeable
|
||||
visible: (hovered || hoverHandler.hovered) && thumb.client.closeable && !dragHandler.active
|
||||
onClicked: thumb.client.closeWindow();
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue