2 step top panel slide

a top panel can be just "half" opened showing only the top row of icons. don't duplicate the icons but dynamically fade in/out those making also possible to open the drawer completely by a single, longer swipe
This commit is contained in:
Marco Martin 2021-03-09 12:52:17 +00:00
parent 33400a872f
commit 113fe48caf
5 changed files with 145 additions and 52 deletions

View file

@ -18,7 +18,7 @@ DrawerBackground {
visible: shouldBeVisible visible: shouldBeVisible
property bool shouldBeVisible: applet && (applet.status != PlasmaCore.Types.HiddenStatus && applet.status != PlasmaCore.Types.PassiveStatus) property bool shouldBeVisible: applet && (applet.status != PlasmaCore.Types.HiddenStatus && applet.status != PlasmaCore.Types.PassiveStatus)
height: parent.height height: parent.height
width: visible ? quickSettingsParent.width : 0 width: visible ? quickSettings.width : 0
Layout.minimumHeight: applet && applet.switchHeight Layout.minimumHeight: applet && applet.switchHeight
onShouldBeVisibleChanged: fullContainer.visible = fullContainer.shouldBeVisible onShouldBeVisibleChanged: fullContainer.visible = fullContainer.shouldBeVisible

View file

@ -4,7 +4,7 @@
* SPDX-License-Identifier: LGPL-2.0-or-later * SPDX-License-Identifier: LGPL-2.0-or-later
*/ */
import QtQuick 2.0 import QtQuick 2.14
import QtQuick.Layouts 1.1 import QtQuick.Layouts 1.1
import QtQuick.Window 2.2 import QtQuick.Window 2.2
import org.kde.plasma.core 2.0 as PlasmaCore import org.kde.plasma.core 2.0 as PlasmaCore
@ -23,14 +23,15 @@ NanoShell.FullScreenOverlay {
property alias fixedArea: mainScope property alias fixedArea: mainScope
property alias flickable: mainFlickable property alias flickable: mainFlickable
color: "transparent"//Qt.rgba(0, 0, 0, 0.6 * Math.min(1, offset/contentArea.height)) color: "transparent"
property alias contentItem: contentArea.contentItem property alias contentItem: contentArea.contentItem
property int headerHeight property int headerHeight
property real topEmptyAreaHeight
signal closed signal closed
//width: Screen.width width: Screen.width
//height: Screen.height height: Screen.height
enum MovementDirection { enum MovementDirection {
None = 0, None = 0,
@ -115,7 +116,7 @@ NanoShell.FullScreenOverlay {
easing.type: Easing.InOutQuad easing.type: Easing.InOutQuad
properties: "offset" properties: "offset"
from: window.offset from: window.offset
to: contentArea.height to: contentArea.height - topEmptyAreaHeight
} }
Rectangle { Rectangle {
@ -188,9 +189,9 @@ NanoShell.FullScreenOverlay {
oldContentY = contentY; oldContentY = contentY;
} }
property real oldContentY property real oldContentY
boundsBehavior: Flickable.StopAtBounds boundsMovement: Flickable.StopAtBounds
contentWidth: window.width contentWidth: window.width
contentHeight: window.height*2 contentHeight: window.height*2 - headerHeight*2
bottomMargin: window.height bottomMargin: window.height
onMovementStarted: { onMovementStarted: {
window.cancelAnimations(); window.cancelAnimations();

View file

@ -269,6 +269,10 @@ Item {
slidingPanel.userInteracting = false; slidingPanel.userInteracting = false;
slidingPanel.updateState(); slidingPanel.updateState();
} }
onCanceled: {
slidingPanel.userInteracting = false;
slidingPanel.updateState();
}
} }
SlidingPanel { SlidingPanel {
@ -277,35 +281,36 @@ Item {
height: plasmoid.availableScreenRect.height height: plasmoid.availableScreenRect.height
openThreshold: units.gridUnit * 2 openThreshold: units.gridUnit * 2
headerHeight: root.height headerHeight: root.height
topEmptyAreaHeight: quickSettings.topEmptyAreaHeight
offset: quickSettingsParent.height offset: quickSettings.height
onClosed: quickSettings.closed() onClosed: quickSettings.closed()
contentItem: Item { contentItem: Item {
implicitWidth: panelContents.implicitWidth implicitWidth: panelContents.implicitWidth
implicitHeight: Math.min(slidingPanel.height, quickSettingsParent.implicitHeight)
implicitHeight: Math.min(slidingPanel.height, quickSettings.implicitHeight)
GridLayout { GridLayout {
id: panelContents id: panelContents
anchors.fill: parent anchors.fill: parent
implicitWidth: quickSettingsParent.implicitWidth implicitWidth: quickSettings.implicitWidth
implicitHeight: Math.min(slidingPanel.height, quickSettingsParent.implicitHeight) implicitHeight: Math.min(slidingPanel.height, quickSettings.implicitHeight)
columns: slidingPanel.wideScreen ? 2 : 1 columns: slidingPanel.wideScreen ? 2 : 1
rows: slidingPanel.wideScreen ? 1 : 2 rows: slidingPanel.wideScreen ? 1 : 2
DrawerBackground { QuickSettings {
id: quickSettingsParent id: quickSettings
//anchors.fill: parent
Layout.alignment: Qt.AlignTop Layout.alignment: Qt.AlignTop
Layout.preferredWidth: slidingPanel.wideScreen ? Math.min(slidingPanel.width/2, units.gridUnit * 25) : panelContents.width Layout.preferredWidth: slidingPanel.wideScreen ? Math.min(slidingPanel.width/2, units.gridUnit * 25) : panelContents.width
z: 4 z: 4
contentItem: QuickSettings { parentSlidingPanel: slidingPanel
id: quickSettings
onCloseRequested: { onCloseRequested: {
slidingPanel.hide() slidingPanel.hide()
} }
} background: DrawerBackground {}
} }
ListView { ListView {
@ -313,12 +318,14 @@ Item {
z: 1 z: 1
interactive: width < contentWidth interactive: width < contentWidth
//parent: slidingPanel.wideScreen ? slidingPanel.flickable.contentItem : panelContents //parent: slidingPanel.wideScreen ? slidingPanel.flickable.contentItem : panelContents
Layout.preferredWidth: slidingPanel.wideScreen ? Math.min(slidingPanel.width - quickSettingsParent.width, quickSettingsParent.width*fullRepresentationModel.count) : panelContents.width
Layout.preferredWidth: slidingPanel.wideScreen ? Math.min(slidingPanel.width/2, quickSettings.width*fullRepresentationModel.count) : panelContents.width
//Layout.fillWidth: true //Layout.fillWidth: true
clip: slidingPanel.wideScreen clip: slidingPanel.wideScreen
y: slidingPanel.wideScreen ? 0 : quickSettingsParent.height - height * (1-opacity) y: slidingPanel.wideScreen ? 0 : quickSettings.height - (quickSettings.height + height) * (1-opacity)
opacity: slidingPanel.wideScreen ? 1 : fullRepresentationModel.count > 0 && slidingPanel.offset/panelContents.height opacity: slidingPanel.wideScreen ? 1 : fullRepresentationModel.count > 0 && (slidingPanel.offset + slidingPanel.headerHeight)/(quickSettings.height -slidingPanel.topEmptyAreaHeight)
height: Math.min(plasmoid.screenGeometry.height - slidingPanel.headerHeight - quickSettingsParent.height - bottomBar.height, implicitHeight) Layout.preferredHeight: Math.min(plasmoid.screenGeometry.height - slidingPanel.headerHeight - quickSettings.height - bottomBar.height + slidingPanel.topEmptyAreaHeight, implicitHeight)
//leftMargin: slidingPanel.drawerX //leftMargin: slidingPanel.drawerX
preferredHighlightBegin: slidingPanel.drawerX preferredHighlightBegin: slidingPanel.drawerX

View file

@ -23,6 +23,7 @@ ColumnLayout {
required property bool enabled required property bool enabled
required property string settingsCommand required property string settingsCommand
required property var toggleFunction required property var toggleFunction
property alias labelOpacity: label.opacity
Rectangle { Rectangle {
Layout.preferredWidth: units.iconSizes.large + units.smallSpacing Layout.preferredWidth: units.iconSizes.large + units.smallSpacing

View file

@ -4,13 +4,17 @@
* SPDX-License-Identifier: LGPL-2.0-or-later * SPDX-License-Identifier: LGPL-2.0-or-later
*/ */
import QtQuick 2.1 import QtQuick 2.14
import QtQuick.Layouts 1.1 import QtQuick.Layouts 1.1
import QtQuick.Window 2.2
import org.kde.plasma.core 2.0 as PlasmaCore import org.kde.plasma.core 2.0 as PlasmaCore
import org.kde.plasma.components 2.0 as PlasmaComponents import org.kde.plasma.components 2.0 as PlasmaComponents
import org.kde.plasma.networkmanagement 0.2 as PlasmaNM import org.kde.plasma.networkmanagement 0.2 as PlasmaNM
import org.kde.bluezqt 1.0 as BluezQt import org.kde.bluezqt 1.0 as BluezQt
import org.kde.colorcorrect 0.1 as CC import org.kde.colorcorrect 0.1 as CC
import org.kde.plasma.private.nanoshell 2.0 as NanoShell
import org.kde.plasma.components 3.0 as PC3
Item { Item {
id: root id: root
@ -21,8 +25,37 @@ Item {
signal closeRequested signal closeRequested
signal closed signal closed
property bool expandedMode: parentSlidingPanel.wideScreen
readonly property real expandedRatio: expandedMode ? 1 : Math.max(0, Math.min(1, (parentSlidingPanel.offset - firstRowHeight - parentSlidingPanel.headerHeight) / otherRowsHeight))
readonly property real topEmptyAreaHeight: parentSlidingPanel.userInteracting
? (root.height - collapsedHeight) * (1 - expandedRatio)
: (expandedMode ? 0 : root.height - collapsedHeight)
readonly property real collapsedHeight: firstRowHeight + PlasmaCore.Units.largeSpacing * 2
readonly property real firstRowHeight: flow.children[0].height
readonly property real otherRowsHeight: flow.height - firstRowHeight
Connections {
target: root.parentSlidingPanel
function onUserInteractingChanged() {
if (!parentSlidingPanel.userInteracting) {
if (root.expandedRatio > 0.7) {
root.expandedMode = true;
}
}
}
}
property bool screenshotRequested: false property bool screenshotRequested: false
property NanoShell.FullScreenOverlay parentSlidingPanel
property Item background
onBackgroundChanged: {
background.parent = backgroundParent
background.anchors.fill = backgroundParent
}
PlasmaNM.Handler { PlasmaNM.Handler {
id: nmHandler id: nmHandler
} }
@ -31,6 +64,14 @@ Item {
id: enabledConnections id: enabledConnections
} }
Connections {
target: root.Window.window
function onVisibilityChanged() {
root.expandedMode = parentSlidingPanel.wideScreen;
}
}
Connections { Connections {
target: BluezQt.Manager target: BluezQt.Manager
@ -249,12 +290,32 @@ Item {
id: settingsModel id: settingsModel
} }
Flow { Item {
id: flow id: backgroundParent
anchors {
left: parent.left
right: parent.right
bottom: parent.bottom
}
height: firstRowHeight + units.largeSpacing*2 + otherRowsHeight * root.expandedRatio
}
Item {
anchors { anchors {
fill: parent fill: parent
margins: units.smallSpacing margins: units.smallSpacing
} }
readonly property real cellSizeHint: units.iconSizes.large + units.smallSpacing * 6
readonly property real columnWidth: Math.floor(width / Math.floor(width / cellSizeHint))
Flow {
id: flow
anchors {
fill: parent
margins: units.largeSpacing
}
readonly property real cellSizeHint: units.iconSizes.large + units.smallSpacing * 6 readonly property real cellSizeHint: units.iconSizes.large + units.smallSpacing * 6
readonly property real columnWidth: Math.floor(width / Math.floor(width / cellSizeHint)) readonly property real columnWidth: Math.floor(width / Math.floor(width / cellSizeHint))
spacing: 0 spacing: 0
@ -264,7 +325,15 @@ Item {
id: delegateItem id: delegateItem
//FIXME: why this is needed? //FIXME: why this is needed?
width: flow.columnWidth width: flow.columnWidth - (y > 0 ? 0 : (flow.columnWidth/Math.floor(flow.width / flow.columnWidth)) * (1 - root.expandedRatio))
height: item ? item.implicitHeight : 0
labelOpacity: y > 0 ? 1 : root.expandedRatio
opacity: y <= 0 ? 1 : root.expandedRatio
transform: Translate {
y: otherRowsHeight * (1 - root.expandedRatio)
}
Connections { Connections {
target: delegateItem target: delegateItem
@ -277,6 +346,15 @@ Item {
} }
} }
move: Transition {
NumberAnimation {
duration: units.shortDuration
//Here a linear easing actually looks better
//easing.type: Easing.InOutQuad
properties: "x,y"
}
}
BrightnessItem { BrightnessItem {
id: brightnessSlider id: brightnessSlider
width: flow.width width: flow.width
@ -284,6 +362,11 @@ Item {
label: i18n("Display Brightness") label: i18n("Display Brightness")
value: root.screenBrightness value: root.screenBrightness
maximumValue: root.maximumScreenBrightness maximumValue: root.maximumScreenBrightness
opacity: root.expandedRatio
transform: Translate{
y: otherRowsHeight * (1 - root.expandedRatio)
}
Connections { Connections {
target: root target: root
onScreenBrightnessChanged: brightnessSlider.value = root.screenBrightness onScreenBrightnessChanged: brightnessSlider.value = root.screenBrightness
@ -291,3 +374,4 @@ Item {
} }
} }
} }
}