Commit 876eedfb authored by Nate Graham's avatar Nate Graham 🔩
Browse files

Add a SpinBox (with draggability) to panel thickness adjustment UI

Summary:
We receive many complaints and bug reports about the current UI for adjusting panel
thickness. People don't figure out that they have to drag on the button, and when they do,
they complain that it's too hard to set the value finely enough.

This patch removes the draggable button and replaces it with a more conventional SpinBox,
which in D29534 is given ability to adjust the values by scrolling over it or clicking and
dragging. This yields the following improvements:
- The way you adjust panel thickness is now more obvious
- The existing drag-to-adjust behavior is much nicer and less buggy
- Panel thickness can now be specified numerically
- Fine-tuning panel thickness is now easier using any adjustment method
- We have one fewer custom control to maintain
- Bugs in custom scrolling implementation go away

Touch friendliness is maintained because this SpinBox has an inherently touch-friendly design
with large touchable buttons that can be held down to quickly adjust the value, and touch-and
-drag still works after D29534 is applied.

I wouldn't mind using this SpinBox design elsewhere too; see T9460.

BUG: 418700
BUG: 421169
FIXED-IN: 5.19

Test Plan:
{F8301480}
{F8301388}

Reviewers: abetts, #vdg, #plasma, mart

Reviewed By: #vdg, #plasma, mart

Subscribers: mart, ahiemstra, cblack, plasma-devel

Tags: #plasma

Differential Revision: https://phabricator.kde.org/D29535
parent 773dd600
/*
* Copyright 2013 Marco Martin <mart@kde.org>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 2.010-1301, USA.
*/
import QtQuick 2.0
import QtQuick.Controls 2.0 as QQC2
import org.kde.plasma.components 2.0 as PlasmaComponents
import org.kde.plasma.extras 2.0 as PlasmaExtras
import org.kde.plasma.core 2.0 as PlasmaCore
import org.kde.plasma.configuration 2.0
import org.kde.kquickcontrolsaddons 2.0 as KQuickControlsAddons
PlasmaComponents.Button {
readonly property string textLabel: panel.location === PlasmaCore.Types.LeftEdge || panel.location === PlasmaCore.Types.RightEdge ? i18nd("plasma_shell_org.kde.plasma.desktop", "Width") : i18nd("plasma_shell_org.kde.plasma.desktop", "Height")
text: panelResizeHintTimer.running ? panel.thickness : textLabel
readonly property string sizeIcon: panel.location === PlasmaCore.Types.LeftEdge || panel.location === PlasmaCore.Types.RightEdge ? "resizecol" : "resizerow"
iconSource: sizeIcon
checkable: true
checked: mel.pressed
Timer {
id: panelResizeHintTimer
interval: 1000
}
Connections {
target: panel
onThicknessChanged: panelResizeHintTimer.restart()
}
QQC2.ToolTip {
id: tooltip
visible: false
delay: 0
timeout: 10000
contentItem: PlasmaComponents.Label {
anchors.fill: parent
text: i18nd("plasma_shell_org.kde.plasma.desktop", "Click and drag the button to resize the panel.")
horizontalAlignment: Text.AlignHCenter
verticalAlignment: Text.AlignVCenter
wrapMode: Text.WordWrap
color: tooltip.palette.toolTipText
}
KQuickControlsAddons.MouseEventListener {
anchors.fill: parent
onPressed: tooltip.visible = false
}
}
KQuickControlsAddons.MouseEventListener {
id: mel
anchors.fill: parent
cursorShape: panel.location === PlasmaCore.Types.LeftEdge || panel.location === PlasmaCore.Types.RightEdge ? Qt.SizeHorCursor : Qt.SizeVerCursor
property int startMouseX
property int startMouseY
onPressed: {
dialogRoot.closeContextMenu();
startMouseX = mouse.x
startMouseY = mouse.y
tooltip.visible = true
}
onPositionChanged: {
switch (panel.location) {
case PlasmaCore.Types.TopEdge:
var y = Math.min(panel.screenToFollow.geometry.y + panel.screenToFollow.geometry.height/2, mouse.screenY - mapToItem(dialogRoot, 0, startMouseY).y);
var thickness = Math.max(units.gridUnit, y - panel.y);
if (thickness % 2 != 0) {
if (mouse.y > startMouseY) {
thickness += 1;
y -= 1;
} else {
thickness -= 1;
y += 1;
}
}
configDialog.y = y;
panel.thickness = thickness;
break;
case PlasmaCore.Types.LeftEdge:
var x = Math.min(panel.screenToFollow.geometry.x + panel.screenToFollow.geometry.width/2, mouse.screenX - mapToItem(dialogRoot, startMouseX, 0).x);
var thickness = Math.max(units.gridUnit, x - panel.x);
if (thickness % 2 != 0) {
if (mouse.x > startMouseX) {
thickness += 1;
x += 1;
} else {
thickness -= 1;
x -= 1;
}
}
configDialog.x = x;
panel.thickness = thickness;
break;
case PlasmaCore.Types.RightEdge:
var x = Math.max(panel.screenToFollow.geometry.x + panel.screenToFollow.geometry.width/2, mouse.screenX - mapToItem(dialogRoot, startMouseX, 0).x);
var thickness = Math.max(units.gridUnit, panel.screenToFollow.geometry.x + panel.screenToFollow.geometry.width - (x + configDialog.width));
if (thickness % 2 != 0) {
if (mouse.x > startMouseX) {
thickness -= 1;
x += 1;
} else {
thickness += 1;
x -= 1;
}
}
configDialog.x = x;
panel.thickness = thickness;
break;
case PlasmaCore.Types.BottomEdge:
default:
var y = Math.max(panel.screenToFollow.geometry.y + panel.screenToFollow.geometry.height/2, mouse.screenY - mapToItem(dialogRoot, 0, startMouseY).y);
var thickness = Math.max(units.gridUnit, panel.screenToFollow.geometry.y + panel.screenToFollow.geometry.height - (y + configDialog.height));
if (thickness % 2 != 0) {
if (mouse.y > startMouseY) {
thickness -= 1;
y += 1;
} else {
thickness += 1;
y -= 1;
}
}
configDialog.y = y;
panel.thickness = thickness;
}
}
property int wheelDelta: 0
onWheelMoved: {
wheelDelta += wheel.delta;
var deltaThickness = 0;
// Magic number 120 for common "one click"
// See: https://doc.qt.io/qt-5/qml-qtquick-wheelevent.html#angleDelta-prop
while (wheelDelta >= 120) {
wheelDelta -= 120;
deltaThickness += 1;
}
while (wheelDelta <= -120) {
wheelDelta += 120;
deltaThickness -= 1;
}
deltaThickness = deltaThickness * 2;
var newThickness = Math.max(units.gridUnit, panel.thickness + deltaThickness);
if (panel.location === PlasmaCore.Types.LeftEdge || panel.location === PlasmaCore.Types.RightEdge) {
newThickness = Math.min(newThickness, panel.screenToFollow.geometry.width/2);
} else {
newThickness = Math.min(newThickness, panel.screenToFollow.geometry.height/2);
}
if (newThickness % 2 != 0) {
newThickness -= 1;
}
panel.thickness = newThickness;
panelResetAnimation.running = true;
}
}
}
......@@ -20,6 +20,7 @@ import QtQuick 2.0
import QtQuick.Controls 2.5 as QQC2
import QtQuick.Layouts 1.0
import org.kde.plasma.components 2.0 as PlasmaComponents
import org.kde.plasma.components 3.0 as PlasmaComponents3
import org.kde.plasma.core 2.0 as PlasmaCore
import org.kde.plasma.configuration 2.0
import org.kde.kirigami 2.0 as Kirigami
......@@ -39,7 +40,7 @@ Item {
onTriggered: {
// avoid leaving the panel in an inconsistent state when escaping while dragging it
// "checked" means "pressed" in this case, we abuse that property to make the button look pressed
if (edgeHandle.checked || sizeHandle.checked) {
if (edgeHandle.checked) {
return
}
......@@ -89,8 +90,8 @@ Item {
GridLayout {
id: row
columns: dialogRoot.vertical ? 1 : 2
rows: dialogRoot.vertical ? 2 : 1
columns: dialogRoot.vertical ? 1 : 4
rows: dialogRoot.vertical ? 4 : 1
anchors.centerIn: parent
rowSpacing: units.smallSpacing
......@@ -100,9 +101,45 @@ Item {
id: edgeHandle
Layout.alignment: Qt.AlignHCenter
}
SizeHandle {
id: sizeHandle
Layout.alignment: Qt.AlignHCenter
Item {
Layout.preferredWidth: units.gridUnit
Layout.preferredHeight: units.gridUnit
}
PlasmaComponents3.Label {
Layout.fillWidth: true
wrapMode: Text.Wrap
text: panel.location === PlasmaCore.Types.LeftEdge || panel.location === PlasmaCore.Types.RightEdge ? i18nd("plasma_shell_org.kde.plasma.desktop", "Panel width:") : i18nd("plasma_shell_org.kde.plasma.desktop", "Panel height:")
}
PlasmaComponents3.SpinBox {
Layout.fillWidth: true
editable: true
from: 20 // below this size, the panel is mostly unusable
to: PlasmaCore.Types.LeftEdge || panel.location === PlasmaCore.Types.RightEdge ? panel.screenToFollow.geometry.width / 2 : panel.screenToFollow.geometry.height / 2
stepSize: 2
value: panel.thickness
onValueModified: {
panel.thickness = value
// Adjust the position of the config bar too
switch (panel.location) {
case PlasmaCore.Types.TopEdge:
configDialog.y = panel.y + panel.thickness;
break;
case PlasmaCore.Types.LeftEdge:
configDialog.x = panel.x + panel.thickness;
break;
case PlasmaCore.Types.RightEdge:
configDialog.x = panel.x - configDialog.width;
break;
case PlasmaCore.Types.BottomEdge:
default:
configDialog.y = panel.y - configDialog.height;
break;
}
}
}
}
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment