mirror of
https://invent.kde.org/marcoa/shift-shell.git
synced 2026-04-26 14:23:09 +00:00
shell: Sync implementations with Plasma Desktop
This fixes some of the oddities with applets that we experience that are designed for Desktop. We don't really have a need for different behaviour from Desktop, so it's probably best to follow it for the least amount of bugs. Eventually we perhaps should derive our shell package from desktop?
This commit is contained in:
parent
7f011e92ed
commit
ce3ecd9e4b
4 changed files with 754 additions and 77 deletions
266
shell/contents/applet/AppletError.qml
Normal file
266
shell/contents/applet/AppletError.qml
Normal file
|
|
@ -0,0 +1,266 @@
|
|||
/*
|
||||
SPDX-FileCopyrightText: 2013 Marco Martin <mart@kde.org>
|
||||
|
||||
SPDX-License-Identifier: GPL-2.0-or-later
|
||||
*/
|
||||
|
||||
// NOTE: Below is taken straight out of Plasma Desktop so that we can
|
||||
// support desktop applets properly, try to keep it in sync:
|
||||
// plasma-desktop/desktoppackage/contents/applet/AppletError.qml
|
||||
|
||||
import QtQuick 2.15
|
||||
import QtQuick.Layouts 1.15
|
||||
import QtQuick.Window 2.15
|
||||
import QtQuick.Controls 2.15 as QQC2
|
||||
import org.kde.plasma.core as PlasmaCore
|
||||
import org.kde.plasma.components 3.0 as PC3
|
||||
import org.kde.kirigami 2.20 as Kirigami
|
||||
import org.kde.plasma.plasmoid 2.0
|
||||
|
||||
PlasmoidItem {
|
||||
id: root
|
||||
|
||||
enum LayoutType {
|
||||
HorizontalPanel,
|
||||
VerticalPanel,
|
||||
Desktop,
|
||||
DesktopCompact
|
||||
}
|
||||
|
||||
property var errorInformation
|
||||
|
||||
readonly property real minimumPreferredWidth: Kirigami.Units.gridUnit * 12
|
||||
readonly property real minimumPreferredHeight: Kirigami.Units.gridUnit * 12
|
||||
|
||||
// To properly show the error message in panel
|
||||
readonly property int layoutForm: {
|
||||
if (fullRepresentationItem.width >= root.minimumPreferredWidth) {
|
||||
if (fullRepresentationItem.height >= root.minimumPreferredHeight) {
|
||||
return AppletError.Desktop;
|
||||
} else if (fullRepresentationItem.height >= Kirigami.Units.iconSizes.huge + root.fullRepresentationItem.buttonLayout.implicitHeight) {
|
||||
return AppletError.DesktopCompact;
|
||||
}
|
||||
}
|
||||
|
||||
return Plasmoid.formFactor === PlasmaCore.Types.Vertical ? AppletError.VerticalPanel : AppletError.HorizontalPanel;
|
||||
}
|
||||
preloadFullRepresentation: true
|
||||
fullRepresentation: GridLayout {
|
||||
id: fullRep
|
||||
property alias buttonLayout: buttonLayout
|
||||
Layout.minimumWidth: {
|
||||
switch (root.layoutForm) {
|
||||
case AppletError.Desktop:
|
||||
case AppletError.DesktopCompact:
|
||||
// [Icon] [Text]
|
||||
// [Button]
|
||||
// [Information]
|
||||
return Math.max(root.minimumPreferredWidth, buttonLayout.implicitWidth);
|
||||
case AppletError.VerticalPanel:
|
||||
// [Icon]
|
||||
// [Copy]
|
||||
// [Open]
|
||||
return Math.max(headerIcon.implicitWidth, buttonLayout.implicitWidth);
|
||||
case AppletError.HorizontalPanel:
|
||||
// [Icon] [Copy] [Open]
|
||||
return headingLayout.implicitWidth + rowSpacing + buttonLayout.implicitWidth;
|
||||
}
|
||||
}
|
||||
Layout.minimumHeight: {
|
||||
switch (root.layoutForm) {
|
||||
case AppletError.Desktop:
|
||||
return headingLayout.implicitHeight + fullRep.columnSpacing + buttonLayout.implicitHeight + fullRep.columnSpacing + fullContentView.implicitHeight;
|
||||
case AppletError.DesktopCompact:
|
||||
return Math.max(headingLayout.implicitHeight, buttonLayout.implicitHeight);
|
||||
case AppletError.VerticalPanel:
|
||||
return headingLayout.implicitHeight + fullRep.columnSpacing + buttonLayout.implicitHeight;
|
||||
case AppletError.HorizontalPanel:
|
||||
return Math.max(headingLayout.implicitHeight, buttonLayout.implicitHeight);
|
||||
}
|
||||
}
|
||||
// Same as systray popups
|
||||
Layout.preferredWidth: Kirigami.Units.gridUnit * 24
|
||||
Layout.preferredHeight: Kirigami.Units.gridUnit * 24
|
||||
Layout.maximumWidth: Kirigami.Units.gridUnit * 34
|
||||
Layout.maximumHeight: Kirigami.Units.gridUnit * 34
|
||||
|
||||
rowSpacing: textArea.topPadding
|
||||
columnSpacing: rowSpacing
|
||||
flow: {
|
||||
switch (root.layoutForm) {
|
||||
case AppletError.HorizontalPanel:
|
||||
return GridLayout.LeftToRight;
|
||||
default:
|
||||
return GridLayout.TopToBottom;
|
||||
}
|
||||
}
|
||||
|
||||
RowLayout {
|
||||
id: headingLayout
|
||||
|
||||
Layout.margins: root.layoutForm !== AppletError.Desktop ? 0 : Kirigami.Units.gridUnit
|
||||
Layout.maximumWidth: fullRep.width
|
||||
spacing: 0
|
||||
Layout.fillWidth: true
|
||||
|
||||
Kirigami.Icon {
|
||||
id: headerIcon
|
||||
implicitWidth: Math.min(Kirigami.Units.iconSizes.huge, fullRep.width, fullRep.height)
|
||||
implicitHeight: implicitWidth
|
||||
|
||||
activeFocusOnTab: true
|
||||
source: "dialog-error"
|
||||
|
||||
Accessible.description: heading.text
|
||||
|
||||
PlasmaCore.ToolTipArea {
|
||||
anchors.fill: parent
|
||||
enabled: !heading.visible || heading.truncated
|
||||
mainText: heading.text
|
||||
textFormat: Text.PlainText
|
||||
}
|
||||
}
|
||||
|
||||
Kirigami.Heading {
|
||||
id: heading
|
||||
visible: root.layoutForm !== AppletError.VerticalPanel
|
||||
// Descent is equal to the amount of space above and below capital letters.
|
||||
// Add descent to the sides to make the spacing around Latin text look more even.
|
||||
leftPadding: headingFontMetrics.descent
|
||||
rightPadding: headingFontMetrics.descent
|
||||
text: root.errorInformation ? root.errorInformation.compactError : "No error information."
|
||||
textFormat: Text.PlainText
|
||||
level: 2
|
||||
wrapMode: Text.Wrap
|
||||
horizontalAlignment: Text.AlignHCenter
|
||||
verticalAlignment: Text.AlignVCenter
|
||||
elide: Text.ElideRight
|
||||
Layout.fillWidth: true
|
||||
Layout.maximumHeight: headerIcon.implicitHeight
|
||||
|
||||
FontMetrics {
|
||||
id: headingFontMetrics
|
||||
font: heading.font
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
GridLayout {
|
||||
id: buttonLayout
|
||||
|
||||
Layout.alignment: Qt.AlignCenter
|
||||
|
||||
rowSpacing: fullRep.rowSpacing
|
||||
columnSpacing: parent.columnSpacing
|
||||
flow: {
|
||||
switch (root.layoutForm) {
|
||||
case AppletError.HorizontalPanel:
|
||||
case AppletError.VerticalPanel:
|
||||
return fullRep.flow;
|
||||
default:
|
||||
return GridLayout.LeftToRight;
|
||||
}
|
||||
}
|
||||
|
||||
PC3.Button {
|
||||
id: copyButton
|
||||
display: root.layoutForm === AppletError.HorizontalPanel || root.layoutForm === AppletError.VerticalPanel ? PC3.AbstractButton.IconOnly : PC3.AbstractButton.TextBesideIcon
|
||||
text: i18nd("plasma_shell_org.kde.plasma.desktop", "Copy to Clipboard")
|
||||
icon.name: "edit-copy"
|
||||
onClicked: {
|
||||
textArea.selectAll()
|
||||
textArea.copy()
|
||||
textArea.deselect()
|
||||
}
|
||||
|
||||
PlasmaCore.ToolTipArea {
|
||||
anchors.fill: parent
|
||||
enabled: parent.display === PC3.AbstractButton.IconOnly
|
||||
mainText: parent.text
|
||||
textFormat: Text.PlainText
|
||||
}
|
||||
}
|
||||
|
||||
Loader {
|
||||
id: compactContentLoader
|
||||
active: root.layoutForm !== AppletError.Desktop
|
||||
visible: active
|
||||
sourceComponent: PC3.Button {
|
||||
display: copyButton.display
|
||||
icon.name: "window-new"
|
||||
text: i18nd("plasma_shell_org.kde.plasma.desktop", "View Error Details…")
|
||||
checked: dialog.visible
|
||||
onClicked: dialog.visible = !dialog.visible
|
||||
|
||||
PlasmaCore.ToolTipArea {
|
||||
anchors.fill: parent
|
||||
enabled: parent.display === PC3.AbstractButton.IconOnly
|
||||
mainText: parent.text
|
||||
textFormat: Text.PlainText
|
||||
}
|
||||
|
||||
QQC2.ApplicationWindow {
|
||||
id: dialog
|
||||
flags: Qt.Dialog | Qt.WindowStaysOnTopHint | Qt.WindowMinMaxButtonsHint | Qt.WindowCloseButtonHint
|
||||
minimumWidth: dialogFontMetrics.height * 12
|
||||
+ dialogTextArea.leftPadding + dialogTextArea.rightPadding
|
||||
minimumHeight: dialogFontMetrics.height * 12
|
||||
+ dialogTextArea.topPadding + dialogTextArea.bottomPadding
|
||||
width: Kirigami.Units.gridUnit * 24
|
||||
height: Kirigami.Units.gridUnit * 24
|
||||
color: palette.base
|
||||
QQC2.ScrollView {
|
||||
id: dialogScrollView
|
||||
anchors.fill: parent
|
||||
QQC2.TextArea {
|
||||
id: dialogTextArea
|
||||
// HACK: silence binding loop warnings.
|
||||
// contentWidth seems to be causing the binding loop,
|
||||
// but contentWidth is read-only and we have no control
|
||||
// over how it is calculated.
|
||||
implicitWidth: 0
|
||||
wrapMode: TextEdit.Wrap
|
||||
text: textArea.text
|
||||
font.family: "monospace"
|
||||
readOnly: true
|
||||
selectByMouse: true
|
||||
background: null
|
||||
FontMetrics {
|
||||
id: dialogFontMetrics
|
||||
font: dialogTextArea.font
|
||||
}
|
||||
}
|
||||
background: null
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
PC3.ScrollView {
|
||||
id: fullContentView
|
||||
// Not handled by a Loader because we need
|
||||
// TextEdit::copy() to copy to clipboard.
|
||||
visible: !compactContentLoader.active
|
||||
Layout.fillHeight: true
|
||||
Layout.fillWidth: true
|
||||
PC3.TextArea {
|
||||
id: textArea
|
||||
// HACK: silence binding loop warnings.
|
||||
// contentWidth seems to be causing the binding loop,
|
||||
// but contentWidth is read-only and we have no control
|
||||
// over how it is calculated.
|
||||
implicitWidth: 0
|
||||
wrapMode: TextEdit.Wrap
|
||||
text: root.errorInformation && root.errorInformation.errors ?
|
||||
root.errorInformation.errors.join("\n\n")
|
||||
// This is just to suppress warnings. Users should never see this.
|
||||
: "No error information."
|
||||
font.family: "monospace"
|
||||
readOnly: true
|
||||
selectByMouse: true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
339
shell/contents/applet/CompactApplet.qml
Normal file
339
shell/contents/applet/CompactApplet.qml
Normal file
|
|
@ -0,0 +1,339 @@
|
|||
/*
|
||||
SPDX-FileCopyrightText: 2013 Marco Martin <mart@kde.org>
|
||||
|
||||
SPDX-License-Identifier: GPL-2.0-or-later
|
||||
*/
|
||||
|
||||
// NOTE: Below is taken straight out of Plasma Desktop so that we can
|
||||
// support desktop applets properly, try to keep it in sync:
|
||||
// plasma-desktop/desktoppackage/contents/applet/CompactApplet.qml
|
||||
|
||||
import QtQuick 2.15
|
||||
import QtQuick.Layouts 1.15
|
||||
import QtQuick.Window 2.15
|
||||
|
||||
import org.kde.plasma.core as PlasmaCore
|
||||
import org.kde.ksvg 1.0 as KSvg
|
||||
import org.kde.plasma.plasmoid 2.0
|
||||
import org.kde.kquickcontrolsaddons 2.0
|
||||
import org.kde.kirigami 2.20 as Kirigami
|
||||
|
||||
PlasmaCore.ToolTipArea {
|
||||
id: root
|
||||
objectName: "org.kde.desktop-CompactApplet"
|
||||
anchors.fill: parent
|
||||
|
||||
mainText: plasmoidItem ? plasmoidItem.toolTipMainText : ""
|
||||
subText: plasmoidItem ? plasmoidItem.toolTipSubText : ""
|
||||
location: Plasmoid.location
|
||||
active: plasmoidItem ? !plasmoidItem.expanded : false
|
||||
textFormat: plasmoidItem ? plasmoidItem.toolTipTextFormat : 0
|
||||
mainItem: plasmoidItem && plasmoidItem.toolTipItem ? plasmoidItem.toolTipItem : null
|
||||
|
||||
readonly property bool vertical: location === PlasmaCore.Types.RightEdge || location === PlasmaCore.Types.LeftEdge
|
||||
|
||||
property Item fullRepresentation
|
||||
property Item compactRepresentation
|
||||
property Item expandedFeedback: expandedItem
|
||||
property PlasmoidItem plasmoidItem
|
||||
|
||||
onCompactRepresentationChanged: {
|
||||
if (compactRepresentation) {
|
||||
compactRepresentation.anchors.fill = null;
|
||||
compactRepresentation.parent = compactRepresentationParent;
|
||||
compactRepresentation.anchors.fill = compactRepresentationParent;
|
||||
compactRepresentation.visible = true;
|
||||
}
|
||||
root.visible = true;
|
||||
}
|
||||
|
||||
onFullRepresentationChanged: {
|
||||
if (fullRepresentation) {
|
||||
fullRepresentation.anchors.fill = null;
|
||||
fullRepresentation.parent = appletParent;
|
||||
fullRepresentation.anchors.fill = appletParent;
|
||||
}
|
||||
}
|
||||
|
||||
FocusScope {
|
||||
id: compactRepresentationParent
|
||||
anchors.fill: parent
|
||||
activeFocusOnTab: true
|
||||
onActiveFocusChanged: {
|
||||
// When the scope gets the active focus, try to focus its first descendant,
|
||||
// if there is on which has activeFocusOnTab
|
||||
if (!activeFocus) {
|
||||
return;
|
||||
}
|
||||
let nextItem = nextItemInFocusChain();
|
||||
let candidate = nextItem;
|
||||
while (candidate.parent) {
|
||||
if (candidate === compactRepresentationParent) {
|
||||
nextItem.forceActiveFocus();
|
||||
return;
|
||||
}
|
||||
candidate = candidate.parent;
|
||||
}
|
||||
}
|
||||
|
||||
objectName: "expandApplet"
|
||||
Accessible.name: root.mainText
|
||||
Accessible.description: i18nd("plasma_shell_org.kde.plasma.desktop", "Open %1", root.subText)
|
||||
Accessible.role: Accessible.Button
|
||||
Accessible.onPressAction: Plasmoid.activated()
|
||||
|
||||
Keys.onPressed: {
|
||||
switch (event.key) {
|
||||
case Qt.Key_Space:
|
||||
case Qt.Key_Enter:
|
||||
case Qt.Key_Return:
|
||||
case Qt.Key_Select:
|
||||
Plasmoid.activated();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
KSvg.FrameSvgItem {
|
||||
id: expandedItem
|
||||
z: -100
|
||||
|
||||
property var containerMargins: {
|
||||
let item = root;
|
||||
while (item.parent) {
|
||||
item = item.parent;
|
||||
if (item.isAppletContainer) {
|
||||
return item.getMargins;
|
||||
}
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
|
||||
anchors {
|
||||
fill: parent
|
||||
property bool returnAllMargins: true
|
||||
// The above makes sure margin is returned even for side margins, that
|
||||
// would be otherwise turned off.
|
||||
bottomMargin: !vertical && containerMargins ? -containerMargins('bottom', returnAllMargins) : 0;
|
||||
topMargin: !vertical && containerMargins ? -containerMargins('top', returnAllMargins) : 0;
|
||||
leftMargin: vertical && containerMargins ? -containerMargins('left', returnAllMargins) : 0;
|
||||
rightMargin: vertical && containerMargins ? -containerMargins('right', returnAllMargins) : 0;
|
||||
}
|
||||
imagePath: "widgets/tabbar"
|
||||
visible: opacity > 0
|
||||
prefix: {
|
||||
let prefix;
|
||||
switch (Plasmoid.location) {
|
||||
case PlasmaCore.Types.LeftEdge:
|
||||
prefix = "west-active-tab";
|
||||
break;
|
||||
case PlasmaCore.Types.TopEdge:
|
||||
prefix = "north-active-tab";
|
||||
break;
|
||||
case PlasmaCore.Types.RightEdge:
|
||||
prefix = "east-active-tab";
|
||||
break;
|
||||
default:
|
||||
prefix = "south-active-tab";
|
||||
}
|
||||
if (!hasElementPrefix(prefix)) {
|
||||
prefix = "active-tab";
|
||||
}
|
||||
return prefix;
|
||||
}
|
||||
opacity: plasmoidItem && plasmoidItem.expanded ? 1 : 0
|
||||
Behavior on opacity {
|
||||
NumberAnimation {
|
||||
duration: Kirigami.Units.shortDuration
|
||||
easing.type: Easing.InOutQuad
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Timer {
|
||||
id: expandedSync
|
||||
interval: 100
|
||||
onTriggered: plasmoidItem.expanded = dialog.visible;
|
||||
}
|
||||
|
||||
Connections {
|
||||
target: Plasmoid.internalAction("configure")
|
||||
function onTriggered() {
|
||||
if (root.plasmoidItem.hideOnWindowDeactivate) {
|
||||
plasmoidItem.expanded = false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Connections {
|
||||
target: root.Plasmoid
|
||||
function onContextualActionsAboutToShow() { root.hideImmediately() }
|
||||
}
|
||||
|
||||
PlasmaCore.AppletPopup {
|
||||
id: dialog
|
||||
objectName: "popupWindow"
|
||||
|
||||
popupDirection: switch (Plasmoid.location) {
|
||||
case PlasmaCore.Types.TopEdge:
|
||||
return Qt.BottomEdge
|
||||
case PlasmaCore.Types.LeftEdge:
|
||||
return Qt.RightEdge
|
||||
case PlasmaCore.Types.RightEdge:
|
||||
return Qt.LeftEdge
|
||||
default:
|
||||
return Qt.TopEdge
|
||||
}
|
||||
margin: (Plasmoid.containmentDisplayHints & PlasmaCore.Types.ContainmentPrefersFloatingApplets) ? Kirigami.Units.largeSpacing : 0
|
||||
floating: Plasmoid.location == PlasmaCore.Types.Floating
|
||||
removeBorderStrategy: Plasmoid.location === PlasmaCore.Types.Floating
|
||||
? PlasmaCore.AppletPopup.AtScreenEdges
|
||||
: PlasmaCore.AppletPopup.AtScreenEdges | PlasmaCore.AppletPopup.AtPanelEdges
|
||||
|
||||
hideOnWindowDeactivate: root.plasmoidItem && root.plasmoidItem.hideOnWindowDeactivate
|
||||
visible: root.plasmoidItem && root.plasmoidItem.expanded && fullRepresentation
|
||||
visualParent: root.compactRepresentation
|
||||
backgroundHints: (Plasmoid.containmentDisplayHints & PlasmaCore.Types.ContainmentPrefersOpaqueBackground) ? PlasmaCore.AppletPopup.SolidBackground : PlasmaCore.AppletPopup.StandardBackground
|
||||
appletInterface: root.plasmoidItem
|
||||
|
||||
property var oldStatus: PlasmaCore.Types.UnknownStatus
|
||||
|
||||
onVisibleChanged: {
|
||||
if (!visible) {
|
||||
expandedSync.restart();
|
||||
Plasmoid.status = oldStatus;
|
||||
} else {
|
||||
oldStatus = Plasmoid.status;
|
||||
Plasmoid.status = PlasmaCore.Types.RequiresAttentionStatus;
|
||||
// This call currently fails and complains at runtime:
|
||||
// QWindow::setWindowState: QWindow::setWindowState does not accept Qt::WindowActive
|
||||
dialog.requestActivate();
|
||||
}
|
||||
}
|
||||
//It's a MouseEventListener to get all the events, so the eventfilter will be able to catch them
|
||||
mainItem: MouseEventListener {
|
||||
id: appletParent
|
||||
|
||||
focus: true
|
||||
|
||||
Keys.onEscapePressed: {
|
||||
root.plasmoidItem.expanded = false;
|
||||
}
|
||||
|
||||
Layout.minimumWidth: fullRepresentation ? fullRepresentation.Layout.minimumWidth : 0
|
||||
Layout.minimumHeight: fullRepresentation ? fullRepresentation.Layout.minimumHeight : 0
|
||||
|
||||
Layout.maximumWidth: fullRepresentation ? fullRepresentation.Layout.maximumWidth : Infinity
|
||||
Layout.maximumHeight: fullRepresentation ? fullRepresentation.Layout.maximumHeight : Infinity
|
||||
|
||||
implicitWidth: {
|
||||
if (root.fullRepresentation !== null) {
|
||||
/****/ if (root.fullRepresentation.Layout.preferredWidth > 0) {
|
||||
return root.fullRepresentation.Layout.preferredWidth;
|
||||
} else if (root.fullRepresentation.implicitWidth > 0) {
|
||||
return root.fullRepresentation.implicitWidth;
|
||||
}
|
||||
}
|
||||
return Kirigami.Units.iconSizes.sizeForLabels * 35;
|
||||
}
|
||||
implicitHeight: {
|
||||
if (root.fullRepresentation !== null) {
|
||||
/****/ if (fullRepresentation.Layout.preferredHeight > 0) {
|
||||
return fullRepresentation.Layout.preferredHeight;
|
||||
} else if (fullRepresentation.implicitHeight > 0) {
|
||||
return fullRepresentation.implicitHeight;
|
||||
}
|
||||
}
|
||||
return Kirigami.Units.iconSizes.sizeForLabels * 25;
|
||||
}
|
||||
|
||||
onActiveFocusChanged: {
|
||||
if (activeFocus && fullRepresentation) {
|
||||
fullRepresentation.forceActiveFocus()
|
||||
}
|
||||
}
|
||||
|
||||
// Draws a line between the applet dialog and the panel
|
||||
KSvg.SvgItem {
|
||||
id: separator
|
||||
// Only draw for popups of panel applets, not desktop applets
|
||||
visible: [PlasmaCore.Types.TopEdge, PlasmaCore.Types.LeftEdge, PlasmaCore.Types.RightEdge, PlasmaCore.Types.BottomEdge]
|
||||
.includes(Plasmoid.location) && !dialog.margin
|
||||
anchors {
|
||||
topMargin: -dialog.topPadding
|
||||
leftMargin: -dialog.leftPadding
|
||||
rightMargin: -dialog.rightPadding
|
||||
bottomMargin: -dialog.bottomPadding
|
||||
}
|
||||
z: 999 /* Draw the line on top of the applet */
|
||||
elementId: (Plasmoid.location === PlasmaCore.Types.TopEdge || Plasmoid.location === PlasmaCore.Types.BottomEdge) ? "horizontal-line" : "vertical-line"
|
||||
imagePath: "widgets/line"
|
||||
states: [
|
||||
State {
|
||||
when: Plasmoid.location === PlasmaCore.Types.TopEdge
|
||||
AnchorChanges {
|
||||
target: separator
|
||||
anchors {
|
||||
top: separator.parent.top
|
||||
left: separator.parent.left
|
||||
right: separator.parent.right
|
||||
}
|
||||
}
|
||||
PropertyChanges {
|
||||
target: separator
|
||||
height: 1
|
||||
}
|
||||
},
|
||||
State {
|
||||
when: Plasmoid.location === PlasmaCore.Types.LeftEdge
|
||||
AnchorChanges {
|
||||
target: separator
|
||||
anchors {
|
||||
left: separator.parent.left
|
||||
top: separator.parent.top
|
||||
bottom: separator.parent.bottom
|
||||
}
|
||||
}
|
||||
PropertyChanges {
|
||||
target: separator
|
||||
width: 1
|
||||
}
|
||||
},
|
||||
State {
|
||||
when: Plasmoid.location === PlasmaCore.Types.RightEdge
|
||||
AnchorChanges {
|
||||
target: separator
|
||||
anchors {
|
||||
top: separator.parent.top
|
||||
right: separator.parent.right
|
||||
bottom: separator.parent.bottom
|
||||
}
|
||||
}
|
||||
PropertyChanges {
|
||||
target: separator
|
||||
width: 1
|
||||
}
|
||||
},
|
||||
State {
|
||||
when: Plasmoid.location === PlasmaCore.Types.BottomEdge
|
||||
AnchorChanges {
|
||||
target: separator
|
||||
anchors {
|
||||
left: separator.parent.left
|
||||
right: separator.parent.right
|
||||
bottom: separator.parent.bottom
|
||||
}
|
||||
}
|
||||
PropertyChanges {
|
||||
target: separator
|
||||
height: 1
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
LayoutMirroring.enabled: Qt.application.layoutDirection === Qt.RightToLeft
|
||||
LayoutMirroring.childrenInherit: true
|
||||
}
|
||||
}
|
||||
}
|
||||
76
shell/contents/applet/DefaultCompactRepresentation.qml
Normal file
76
shell/contents/applet/DefaultCompactRepresentation.qml
Normal file
|
|
@ -0,0 +1,76 @@
|
|||
/*
|
||||
SPDX-FileCopyrightText: 2013 Marco Martin <mart@kde.org>
|
||||
|
||||
SPDX-License-Identifier: GPL-2.0-or-later
|
||||
*/
|
||||
|
||||
// NOTE: Below is taken straight out of Plasma Desktop so that we can
|
||||
// support desktop applets properly, try to keep it in sync:
|
||||
// plasma-desktop/desktoppackage/contents/applet/DefaultCompactRepresentation.qml
|
||||
|
||||
import QtQuick 2.15
|
||||
import QtQuick.Layouts 1.15
|
||||
|
||||
import org.kde.plasma.core as PlasmaCore
|
||||
import org.kde.plasma.plasmoid 2.0
|
||||
import org.kde.kirigami 2.20 as Kirigami
|
||||
|
||||
Kirigami.Icon {
|
||||
property PlasmoidItem plasmoidItem
|
||||
readonly property bool inPanel: [PlasmaCore.Types.TopEdge, PlasmaCore.Types.RightEdge, PlasmaCore.Types.BottomEdge, PlasmaCore.Types.LeftEdge]
|
||||
.includes(Plasmoid.location)
|
||||
|
||||
Layout.minimumWidth: {
|
||||
switch (Plasmoid.formFactor) {
|
||||
case PlasmaCore.Types.Vertical:
|
||||
return 0;
|
||||
case PlasmaCore.Types.Horizontal:
|
||||
return height;
|
||||
default:
|
||||
return Kirigami.Units.gridUnit * 3;
|
||||
}
|
||||
}
|
||||
|
||||
Layout.minimumHeight: {
|
||||
switch (Plasmoid.formFactor) {
|
||||
case PlasmaCore.Types.Vertical:
|
||||
return width;
|
||||
case PlasmaCore.Types.Horizontal:
|
||||
return 0;
|
||||
default:
|
||||
return Kirigami.Units.gridUnit * 3;
|
||||
}
|
||||
}
|
||||
|
||||
source: Plasmoid.icon || "plasma"
|
||||
active: mouseArea.containsMouse
|
||||
|
||||
activeFocusOnTab: true
|
||||
|
||||
Keys.onPressed: event => {
|
||||
switch (event.key) {
|
||||
case Qt.Key_Space:
|
||||
case Qt.Key_Enter:
|
||||
case Qt.Key_Return:
|
||||
case Qt.Key_Select:
|
||||
Plasmoid.activated();
|
||||
event.accepted = true; // BUG 481393: Prevent system tray from receiving the event
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
Accessible.name: Plasmoid.title
|
||||
Accessible.description: plasmoidItem.toolTipSubText ?? ""
|
||||
Accessible.role: Accessible.Button
|
||||
|
||||
MouseArea {
|
||||
id: mouseArea
|
||||
|
||||
property bool wasExpanded: false
|
||||
|
||||
anchors.fill: parent
|
||||
hoverEnabled: true
|
||||
onPressed: wasExpanded = plasmoidItem.expanded
|
||||
onClicked: plasmoidItem.expanded = !wasExpanded
|
||||
}
|
||||
}
|
||||
|
|
@ -24,8 +24,8 @@ Item {
|
|||
// NOTE: Plasma Mobile specific:
|
||||
Connections {
|
||||
target: root
|
||||
|
||||
function onContainmentChanged() {
|
||||
|
||||
function onContainmentChanged() {
|
||||
// HACK: add PanelView into the containment so that it can be used
|
||||
if (containment.panel !== undefined) {
|
||||
containment.panel = panel;
|
||||
|
|
@ -36,7 +36,7 @@ Item {
|
|||
}
|
||||
}
|
||||
|
||||
// NOTE: Below is taken straight out of Plasma Desktop so that we can
|
||||
// NOTE: Below is taken straight out of Plasma Desktop so that we can
|
||||
// support desktop panels properly, try to keep it in sync:
|
||||
// plasma-desktop/desktoppackage/contents/views/Panel.qml
|
||||
|
||||
|
|
@ -59,29 +59,41 @@ Item {
|
|||
imagePath: "widgets/panel-background"
|
||||
}
|
||||
|
||||
readonly property bool topEdge: containment?.plasmoid?.location === PlasmaCore.Types.TopEdge
|
||||
readonly property bool leftEdge: containment?.plasmoid?.location === PlasmaCore.Types.LeftEdge
|
||||
readonly property bool rightEdge: containment?.plasmoid?.location === PlasmaCore.Types.RightEdge
|
||||
readonly property bool bottomEdge: containment?.plasmoid?.location === PlasmaCore.Types.BottomEdge
|
||||
|
||||
readonly property int topPadding: Math.round(Math.min(thickPanelSvg.fixedMargins.top + Kirigami.Units.smallSpacing, spacingAtMinSize));
|
||||
readonly property int bottomPadding: Math.round(Math.min(thickPanelSvg.fixedMargins.bottom + Kirigami.Units.smallSpacing, spacingAtMinSize));
|
||||
readonly property int leftPadding: Math.round(Math.min(thickPanelSvg.fixedMargins.left + Kirigami.Units.smallSpacing, spacingAtMinSize));
|
||||
readonly property int rightPadding: Math.round(Math.min(thickPanelSvg.fixedMargins.right + Kirigami.Units.smallSpacing, spacingAtMinSize));
|
||||
|
||||
readonly property int fixedBottomFloatingPadding: floating && (floatingPrefix ? floatingPanelSvg.fixedMargins.bottom : 8)
|
||||
readonly property int fixedLeftFloatingPadding: floating && (floatingPrefix ? floatingPanelSvg.fixedMargins.left : 8)
|
||||
readonly property int fixedRightFloatingPadding: floating && (floatingPrefix ? floatingPanelSvg.fixedMargins.right : 8)
|
||||
readonly property int fixedTopFloatingPadding: floating && (floatingPrefix ? floatingPanelSvg.fixedMargins.top : 8)
|
||||
|
||||
readonly property int bottomFloatingPadding: Math.round(fixedBottomFloatingPadding * floatingness)
|
||||
readonly property int leftFloatingPadding: Math.round(fixedLeftFloatingPadding * floatingness)
|
||||
readonly property int rightFloatingPadding: Math.round(fixedRightFloatingPadding * floatingness)
|
||||
readonly property int topFloatingPadding: Math.round(fixedTopFloatingPadding * floatingness)
|
||||
|
||||
|
||||
// NOTE: Many of the properties in this file are accessed directly in C++ PanelView!
|
||||
// If you change these, make sure to also correct the related code in panelview.cpp.
|
||||
readonly property int fixedBottomFloatingPadding: floating && (floatingPrefix ? floatingPanelSvg.fixedMargins.bottom : 8)
|
||||
readonly property int fixedLeftFloatingPadding: floating && (floatingPrefix ? floatingPanelSvg.fixedMargins.left : 8)
|
||||
readonly property int fixedRightFloatingPadding: floating && (floatingPrefix ? floatingPanelSvg.fixedMargins.right : 8)
|
||||
readonly property int fixedTopFloatingPadding: floating && (floatingPrefix ? floatingPanelSvg.fixedMargins.top : 8)
|
||||
|
||||
readonly property int topPadding: Math.round(Math.min(thickPanelSvg.fixedMargins.top + Kirigami.Units.smallSpacing, spacingAtMinSize));
|
||||
readonly property int bottomPadding: Math.round(Math.min(thickPanelSvg.fixedMargins.bottom + Kirigami.Units.smallSpacing, spacingAtMinSize));
|
||||
readonly property int leftPadding: Math.round(Math.min(thickPanelSvg.fixedMargins.left + Kirigami.Units.smallSpacing, spacingAtMinSize));
|
||||
readonly property int rightPadding: Math.round(Math.min(thickPanelSvg.fixedMargins.right + Kirigami.Units.smallSpacing, spacingAtMinSize));
|
||||
|
||||
readonly property int minPanelHeight: translucentItem.minimumDrawingHeight
|
||||
readonly property int minPanelWidth: translucentItem.minimumDrawingWidth
|
||||
|
||||
// This value is read from panelview.cpp which needs it to decide which border should be enabled
|
||||
property real topShadowMargin: -floatingTranslucentItem.y
|
||||
property real leftShadowMargin: -floatingTranslucentItem.x
|
||||
property real rightShadowMargin: -(width - floatingTranslucentItem.width - floatingTranslucentItem.x)
|
||||
property real bottomShadowMargin: -(height - floatingTranslucentItem.height - floatingTranslucentItem.y)
|
||||
|
||||
property var panelMask: floatingness === 0 ? (panelOpacity === 1 ? opaqueItem.mask : translucentItem.mask) : (panelOpacity === 1 ? floatingOpaqueItem.mask : floatingTranslucentItem.mask)
|
||||
|
||||
// The point is read from panelview.cpp and is used as an offset for the mask
|
||||
readonly property point floatingTranslucentItemOffset: Qt.point(floatingTranslucentItem.x, floatingTranslucentItem.y)
|
||||
|
||||
TaskManager.VirtualDesktopInfo {
|
||||
id: virtualDesktopInfo
|
||||
}
|
||||
|
|
@ -90,13 +102,28 @@ Item {
|
|||
id: activityInfo
|
||||
}
|
||||
|
||||
property bool touchingWindow: visibleWindowsModel.count > 0
|
||||
// We need to have a little gap between the raw visibleWindowsModel count
|
||||
// and actually determining if a window is touching.
|
||||
// This is because certain dialog windows start off with a position of (screenwidth/2, screenheight/2)
|
||||
// and they register as "touching" in the split-second before KWin can place them correctly.
|
||||
// This avoids the panel flashing if it is auto-hide etc and such a window is shown.
|
||||
// Examples of such windows: properties of a file on desktop, or portal "open with" dialog
|
||||
property bool touchingWindow: false
|
||||
property bool touchingWindowDirect: visibleWindowsModel.count > 0
|
||||
property bool showingDesktop: KWindowSystem.showingDesktop
|
||||
Timer {
|
||||
id: touchingWindowDebounceTimer
|
||||
interval: 10 // ms, I find that this value is enough while not causing unresponsiveness while dragging windows close
|
||||
onTriggered: root.touchingWindow = !KWindowSystem.showingDesktop && root.touchingWindowDirect
|
||||
}
|
||||
onTouchingWindowDirectChanged: touchingWindowDebounceTimer.start()
|
||||
onShowingDesktopChanged: touchingWindowDebounceTimer.start()
|
||||
|
||||
TaskManager.TasksModel {
|
||||
id: visibleWindowsModel
|
||||
filterByVirtualDesktop: true
|
||||
filterByActivity: true
|
||||
filterByScreen: true
|
||||
filterByScreen: false
|
||||
filterByRegion: TaskManager.RegionFilterMode.Intersect
|
||||
filterHidden: true
|
||||
filterMinimized: true
|
||||
|
|
@ -109,38 +136,28 @@ Item {
|
|||
|
||||
Binding on regionGeometry {
|
||||
delayed: true
|
||||
property real verticalMargin: (fixedTopFloatingPadding + fixedBottomFloatingPadding) * (1 - floatingness)
|
||||
property real horizontalMargin: (fixedLeftFloatingPadding + fixedRightFloatingPadding) * (1 - floatingness)
|
||||
// This makes the panel de-float when a window is 6px from it or less.
|
||||
// 6px is chosen to avoid any potential issue with kwin snapping behavior,
|
||||
// and it looks like the panel hides away from the active window.
|
||||
value: floatingness, panel.width, panel.height, panel.x, panel.y, panel.geometryByDistance(6 + (verticalPanel ? horizontalMargin : verticalMargin))
|
||||
value: panel.width, panel.height, panel.x, panel.y, panel.dogdeGeometryByDistance(panel.visibilityMode === Panel.Global.DodgeWindows ? -1 : 1) // +1 is for overlap detection, -1 is for snapping to panel
|
||||
}
|
||||
}
|
||||
|
||||
Connections {
|
||||
target: containment
|
||||
target: root.containment?.plasmoid ?? null
|
||||
function onActivated() {
|
||||
// BUG 472909: status changes to PassiveStatus or ActiveStatus after applet shortcut is pressed for the second time
|
||||
if (containment.status === PlasmaCore.Types.PassiveStatus /*After pressing panel shortcut*/ || containment.status === PlasmaCore.Types.ActiveStatus) {
|
||||
containment.status = PlasmaCore.Types.AcceptingInputStatus;
|
||||
// BUG 472909: if applet shortcut is pressed, panel also gets activated, but status will change to RequiresAttentionStatus after applet has focus
|
||||
} else /* Panel has focus, or applet has focus */ {
|
||||
containment.status = PlasmaCore.Types.PassiveStatus;
|
||||
if (root.containment.plasmoid.status === PlasmaCore.Types.AcceptingInputStatus) {
|
||||
root.containment.plasmoid.status = PlasmaCore.Types.PassiveStatus;
|
||||
} else {
|
||||
root.containment.plasmoid.status = PlasmaCore.Types.AcceptingInputStatus;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Floatingness is a value in [0, 1] that's multiplied to the floating margin; 0: not floating, 1: floating, between 0 and 1: animation between the two states
|
||||
property double floatingness
|
||||
readonly property int floatingnessAnimationDuration: Kirigami.Units.longDuration
|
||||
property double floatingnessTarget: 0.0 // The animation is handled in panelview.cpp for efficiency
|
||||
property double floatingness: 0.0
|
||||
|
||||
// PanelOpacity is a value in [0, 1] that's used as the opacity of the opaque elements over the transparent ones; values between 0 and 1 are used for animations
|
||||
property double panelOpacity
|
||||
Behavior on floatingness {
|
||||
NumberAnimation {
|
||||
duration: Kirigami.Units.longDuration
|
||||
easing.type: Easing.OutCubic
|
||||
}
|
||||
}
|
||||
Behavior on panelOpacity {
|
||||
NumberAnimation {
|
||||
duration: Kirigami.Units.longDuration
|
||||
|
|
@ -148,14 +165,6 @@ Item {
|
|||
}
|
||||
}
|
||||
|
||||
// This value is read from panelview.cpp and disables shadow for floating panels, as they'd be detached from the panel
|
||||
property bool hasShadows: floatingness < 0.5
|
||||
property var panelMask: floatingness === 0 ? (panelOpacity === 1 ? opaqueItem.mask : translucentItem.mask) : (panelOpacity === 1 ? floatingOpaqueItem.mask : floatingTranslucentItem.mask)
|
||||
|
||||
// These two values are read from panelview.cpp and are used as an offset for the mask
|
||||
property int maskOffsetX: floatingTranslucentItem.x
|
||||
property int maskOffsetY: floatingTranslucentItem.y
|
||||
|
||||
KSvg.FrameSvgItem {
|
||||
id: translucentItem
|
||||
visible: floatingness === 0 && panelOpacity !== 1
|
||||
|
|
@ -166,8 +175,8 @@ Item {
|
|||
KSvg.FrameSvgItem {
|
||||
id: floatingTranslucentItem
|
||||
visible: floatingness !== 0 && panelOpacity !== 1
|
||||
x: root.leftEdge ? fixedLeftFloatingPadding + fixedRightFloatingPadding * (1 - floatingness) : leftFloatingPadding
|
||||
y: root.topEdge ? fixedTopFloatingPadding + fixedBottomFloatingPadding * (1 - floatingness) : topFloatingPadding
|
||||
x: root.rightEdge ? fixedLeftFloatingPadding + fixedRightFloatingPadding * (1 - floatingness) : leftFloatingPadding
|
||||
y: root.bottomEdge ? fixedTopFloatingPadding + fixedBottomFloatingPadding * (1 - floatingness) : topFloatingPadding
|
||||
width: verticalPanel ? panel.thickness : parent.width - leftFloatingPadding - rightFloatingPadding
|
||||
height: verticalPanel ? parent.height - topFloatingPadding - bottomFloatingPadding : panel.thickness
|
||||
|
||||
|
|
@ -188,20 +197,6 @@ Item {
|
|||
anchors.fill: floatingTranslucentItem
|
||||
imagePath: containment?.plasmoid?.backgroundHints === PlasmaCore.Types.NoBackground ? "" : "solid/widgets/panel-background"
|
||||
}
|
||||
KSvg.FrameSvgItem {
|
||||
id: floatingShadow
|
||||
visible: !hasShadows
|
||||
z: -100
|
||||
imagePath: containment?.plasmoid?.backgroundHints === PlasmaCore.Types.NoBackground ? "" : "solid/widgets/panel-background"
|
||||
prefix: "shadow"
|
||||
anchors {
|
||||
fill: floatingTranslucentItem
|
||||
topMargin: -floatingShadow.margins.top
|
||||
leftMargin: -floatingShadow.margins.left
|
||||
rightMargin: -floatingShadow.margins.right
|
||||
bottomMargin: -floatingShadow.margins.bottom
|
||||
}
|
||||
}
|
||||
|
||||
Keys.onEscapePressed: {
|
||||
root.parent.focus = false
|
||||
|
|
@ -211,29 +206,30 @@ Item {
|
|||
property bool isTransparent: panel.opacityMode === Panel.Global.Translucent
|
||||
property bool isAdaptive: panel.opacityMode === Panel.Global.Adaptive
|
||||
property bool floating: panel.floating
|
||||
readonly property bool screenCovered: !KWindowSystem.showingDesktop && touchingWindow && panel.visibilityMode == Panel.Global.NormalPanel
|
||||
property var stateTriggers: [floating, screenCovered, isOpaque, isAdaptive, isTransparent]
|
||||
property bool hasCompositing: KWindowSystem.isPlatformX11 ? KX11Extras.compositingActive : true
|
||||
readonly property bool screenCovered: touchingWindow && panel.visibilityMode == Panel.Global.NormalPanel
|
||||
property var stateTriggers: [floating, screenCovered, isOpaque, isAdaptive, isTransparent, hasCompositing, containment]
|
||||
onStateTriggersChanged: {
|
||||
let opaqueApplets = false
|
||||
let floatingApplets = false
|
||||
if ((!floating || screenCovered) && (isOpaque || (screenCovered && isAdaptive))) {
|
||||
panelOpacity = 1
|
||||
opaqueApplets = true
|
||||
floatingness = 0
|
||||
floatingnessTarget = 0
|
||||
} else if ((!floating || screenCovered) && (isTransparent || (!screenCovered && isAdaptive))) {
|
||||
panelOpacity = 0
|
||||
floatingness = 0
|
||||
floatingnessTarget = 0
|
||||
} else if ((floating && !screenCovered) && (isTransparent || isAdaptive)) {
|
||||
panelOpacity = 0
|
||||
floatingness = 1
|
||||
floatingnessTarget = 1
|
||||
floatingApplets = true
|
||||
} else if (floating && !screenCovered && isOpaque) {
|
||||
panelOpacity = 1
|
||||
opaqueApplets = true
|
||||
floatingness = 1
|
||||
floatingnessTarget = 1
|
||||
floatingApplets = true
|
||||
}
|
||||
if (!KWindowSystem.isPlatformWayland) {
|
||||
if (!KWindowSystem.isPlatformWayland && !KX11Extras.compositingActive) {
|
||||
opaqueApplets = false
|
||||
panelOpacity = 0
|
||||
}
|
||||
|
|
@ -293,7 +289,6 @@ Item {
|
|||
target: panel
|
||||
property: "length"
|
||||
when: containment
|
||||
delayed: true
|
||||
value: {
|
||||
if (!containment) {
|
||||
return;
|
||||
|
|
@ -322,19 +317,21 @@ Item {
|
|||
}
|
||||
|
||||
KSvg.FrameSvgItem {
|
||||
id: tabBar
|
||||
|
||||
Accessible.name: i18n("Panel Focus Indicator")
|
||||
|
||||
x: root.verticalPanel || !panel.activeFocusItem
|
||||
? 0
|
||||
? translucentItem.x
|
||||
: Math.max(panel.activeFocusItem.Kirigami.ScenePosition.x, panel.activeFocusItem.Kirigami.ScenePosition.x)
|
||||
y: root.verticalPanel && panel.activeFocusItem
|
||||
? Math.max(panel.activeFocusItem.Kirigami.ScenePosition.y, panel.activeFocusItem.Kirigami.ScenePosition.y)
|
||||
: 0
|
||||
: translucentItem.y
|
||||
|
||||
width: panel.activeFocusItem
|
||||
? (root.verticalPanel ? root.width : Math.min(panel.activeFocusItem.width, panel.activeFocusItem.width))
|
||||
? (root.verticalPanel ? translucentItem.width : Math.min(panel.activeFocusItem.width, panel.activeFocusItem.width))
|
||||
: 0
|
||||
height: panel.activeFocusItem
|
||||
? (root.verticalPanel ? Math.min(panel.activeFocusItem.height, panel.activeFocusItem.height) : root.height)
|
||||
? (root.verticalPanel ? Math.min(panel.activeFocusItem.height, panel.activeFocusItem.height) : translucentItem.height)
|
||||
: 0
|
||||
|
||||
visible: panel.active && panel.activeFocusItem
|
||||
|
|
@ -367,8 +364,7 @@ Item {
|
|||
Item {
|
||||
id: containmentParent
|
||||
anchors.centerIn: isOpaque ? floatingOpaqueItem : floatingTranslucentItem
|
||||
width: root.verticalPanel ? panel.thickness : root.width - root.floatingness * (fixedLeftFloatingPadding + fixedRightFloatingPadding)
|
||||
height: root.verticalPanel ? root.height - root.floatingness * (fixedBottomFloatingPadding - fixedTopFloatingPadding) : panel.thickness
|
||||
width: root.verticalPanel ? panel.thickness : root.width - fixedLeftFloatingPadding - fixedRightFloatingPadding
|
||||
height: root.verticalPanel ? root.height - fixedBottomFloatingPadding - fixedTopFloatingPadding : panel.thickness
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue