[ExpandableListItem] make it touch-friendly
Summary: Right now ExpandableListItem is not very touch-friendly due to use of a mousearea hover effect for choosing the selected item. This patch fixes that by using a `TapHandler` to handle left-clicks and touch input. We still need a MouseArea inside it to handle non-touch hover and right-click behaviors. FEATURE: 393749 FIXED-IN: 5.70 Test Plan: Click behavior is identical to how it was before, but now touch works too: {F8234452} Reviewers: #plasma, apol, #vdg, niccolove Subscribers: kde-frameworks-devel Tags: #frameworks Differential Revision: https://phabricator.kde.org/D28808
This commit is contained in:
parent
48f60533b9
commit
52c0a136f9
@ -17,7 +17,7 @@
|
|||||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import QtQuick 2.6
|
import QtQuick 2.14
|
||||||
import QtQuick.Layouts 1.1
|
import QtQuick.Layouts 1.1
|
||||||
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 // for Highlight
|
import org.kde.plasma.components 2.0 as PlasmaComponents // for Highlight
|
||||||
@ -89,7 +89,7 @@ import org.kde.plasma.extras 2.0 as PlasmaExtras
|
|||||||
* [...]
|
* [...]
|
||||||
* @endcode
|
* @endcode
|
||||||
*/
|
*/
|
||||||
MouseArea {
|
Item {
|
||||||
id: listItem
|
id: listItem
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -321,171 +321,182 @@ MouseArea {
|
|||||||
width: parent.width // Assume that we will be used as a delegate, not placed in a layout
|
width: parent.width // Assume that we will be used as a delegate, not placed in a layout
|
||||||
height: mainLayout.height
|
height: mainLayout.height
|
||||||
|
|
||||||
acceptedButtons: Qt.LeftButton | Qt.RightButton
|
|
||||||
hoverEnabled: true
|
|
||||||
cursorShape: Qt.PointingHandCursor // To indicate that the whole thing is clickable
|
|
||||||
|
|
||||||
onContainsMouseChanged: listItem.ListView.view.currentIndex = (containsMouse ? index : -1)
|
|
||||||
|
|
||||||
onIsEnabledChanged: if (!listItem.isEnabled) { collapse() }
|
onIsEnabledChanged: if (!listItem.isEnabled) { collapse() }
|
||||||
|
|
||||||
onClicked: {
|
// Handle left clicks and taps
|
||||||
// Item is disabled: do nothing
|
TapHandler {
|
||||||
if (!listItem.isEnabled) return
|
enabled: listItem.isEnabled
|
||||||
|
|
||||||
// Left click: toggle expanded state
|
acceptedButtons: Qt.LeftButton
|
||||||
if (mouse.button & Qt.LeftButton) {
|
|
||||||
|
onSingleTapped: {
|
||||||
|
listItem.ListView.view.currentIndex = index
|
||||||
listItem.toggleExpanded()
|
listItem.toggleExpanded()
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Right-click: show context menu, if defined
|
// We still need a MouseArea to handle mouse hover and right-click
|
||||||
if (contextMenu != undefined) {
|
MouseArea {
|
||||||
if (mouse.button & Qt.RightButton) {
|
id: clickAndHoverHandler
|
||||||
|
|
||||||
|
anchors.fill: parent
|
||||||
|
|
||||||
|
enabled: listItem.isEnabled
|
||||||
|
|
||||||
|
acceptedButtons: Qt.RightButton
|
||||||
|
hoverEnabled: true
|
||||||
|
cursorShape: Qt.PointingHandCursor // To indicate that the whole thing is clickable
|
||||||
|
|
||||||
|
onContainsMouseChanged: listItem.ListView.view.currentIndex = (containsMouse ? index : -1)
|
||||||
|
|
||||||
|
// Handle right-click, if so defined
|
||||||
|
onClicked: {
|
||||||
|
if (contextMenu != undefined) {
|
||||||
contextMenu.visualParent = parent
|
contextMenu.visualParent = parent
|
||||||
contextMenu.prepare();
|
contextMenu.prepare();
|
||||||
contextMenu.open(mouse.x, mouse.y)
|
contextMenu.open(mouse.x, mouse.y)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
ColumnLayout {
|
ColumnLayout {
|
||||||
id: mainLayout
|
id: mainLayout
|
||||||
|
|
||||||
anchors.top: parent.top
|
anchors.top: parent.top
|
||||||
anchors.left: parent.left
|
anchors.left: parent.left
|
||||||
anchors.right: parent.right
|
anchors.right: parent.right
|
||||||
|
|
||||||
spacing: 0
|
spacing: 0
|
||||||
|
|
||||||
RowLayout {
|
RowLayout {
|
||||||
id: mainRowLayout
|
id: mainRowLayout
|
||||||
|
|
||||||
Layout.fillWidth: true
|
|
||||||
Layout.margins: units.smallSpacing
|
|
||||||
// Otherwise it becomes taller when the button appears
|
|
||||||
Layout.minimumHeight: defaultActionButton.height
|
|
||||||
|
|
||||||
// Icon and optional emblem
|
|
||||||
PlasmaCore.IconItem {
|
|
||||||
id: listItemIcon
|
|
||||||
|
|
||||||
usesPlasmaTheme: listItem.iconUsesPlasmaSVG
|
|
||||||
|
|
||||||
implicitWidth: units.iconSizes.medium
|
|
||||||
implicitHeight: units.iconSizes.medium
|
|
||||||
|
|
||||||
PlasmaCore.IconItem {
|
|
||||||
id: iconEmblem
|
|
||||||
|
|
||||||
visible: source != undefined && source.length > 0
|
|
||||||
|
|
||||||
anchors.right: parent.right
|
|
||||||
anchors.bottom: parent.bottom
|
|
||||||
|
|
||||||
implicitWidth: units.iconSizes.small
|
|
||||||
implicitHeight: units.iconSizes.small
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Title and subtitle
|
|
||||||
ColumnLayout {
|
|
||||||
Layout.fillWidth: true
|
Layout.fillWidth: true
|
||||||
Layout.alignment: Qt.AlignVCenter
|
Layout.margins: units.smallSpacing
|
||||||
|
// Otherwise it becomes taller when the button appears
|
||||||
|
Layout.minimumHeight: defaultActionButton.height
|
||||||
|
|
||||||
spacing: 0
|
// Icon and optional emblem
|
||||||
|
PlasmaCore.IconItem {
|
||||||
|
id: listItemIcon
|
||||||
|
|
||||||
PlasmaExtras.Heading {
|
usesPlasmaTheme: listItem.iconUsesPlasmaSVG
|
||||||
id: listItemTitle
|
|
||||||
|
|
||||||
visible: text.length > 0
|
implicitWidth: units.iconSizes.medium
|
||||||
|
implicitHeight: units.iconSizes.medium
|
||||||
|
|
||||||
Layout.fillWidth: true
|
PlasmaCore.IconItem {
|
||||||
|
id: iconEmblem
|
||||||
|
|
||||||
level: 5
|
visible: source != undefined && source.length > 0
|
||||||
|
|
||||||
textFormat: listItem.allowStyledText ? Text.StyledText : Text.PlainText
|
anchors.right: parent.right
|
||||||
elide: Text.ElideRight
|
anchors.bottom: parent.bottom
|
||||||
maximumLineCount: 1
|
|
||||||
|
|
||||||
// Even if it's the default item, only make it bold when
|
implicitWidth: units.iconSizes.small
|
||||||
// there's more than one item in the list, or else there's
|
implicitHeight: units.iconSizes.small
|
||||||
// only one item and it's bold, which is a little bit weird
|
}
|
||||||
font.weight: listItem.isDefault && listItem.ListView.count > 1
|
|
||||||
? Font.Bold
|
|
||||||
: Font.Normal
|
|
||||||
}
|
}
|
||||||
|
|
||||||
PlasmaComponents3.Label {
|
// Title and subtitle
|
||||||
id: listItemSubtitle
|
ColumnLayout {
|
||||||
|
|
||||||
enabled: false
|
|
||||||
visible: text.length > 0
|
|
||||||
|
|
||||||
Layout.fillWidth: true
|
Layout.fillWidth: true
|
||||||
|
Layout.alignment: Qt.AlignVCenter
|
||||||
|
|
||||||
textFormat: listItem.allowStyledText ? Text.StyledText : Text.PlainText
|
spacing: 0
|
||||||
elide: Text.ElideRight
|
|
||||||
maximumLineCount: subtitleCanWrap ? 9999 : 1
|
PlasmaExtras.Heading {
|
||||||
wrapMode: subtitleCanWrap ? Text.WordWrap : Text.NoWrap
|
id: listItemTitle
|
||||||
|
|
||||||
|
visible: text.length > 0
|
||||||
|
|
||||||
|
Layout.fillWidth: true
|
||||||
|
|
||||||
|
level: 5
|
||||||
|
|
||||||
|
textFormat: listItem.allowStyledText ? Text.StyledText : Text.PlainText
|
||||||
|
elide: Text.ElideRight
|
||||||
|
maximumLineCount: 1
|
||||||
|
|
||||||
|
// Even if it's the default item, only make it bold when
|
||||||
|
// there's more than one item in the list, or else there's
|
||||||
|
// only one item and it's bold, which is a little bit weird
|
||||||
|
font.weight: listItem.isDefault && listItem.ListView.count > 1
|
||||||
|
? Font.Bold
|
||||||
|
: Font.Normal
|
||||||
|
}
|
||||||
|
|
||||||
|
PlasmaComponents3.Label {
|
||||||
|
id: listItemSubtitle
|
||||||
|
|
||||||
|
enabled: false
|
||||||
|
visible: text.length > 0
|
||||||
|
|
||||||
|
Layout.fillWidth: true
|
||||||
|
|
||||||
|
textFormat: listItem.allowStyledText ? Text.StyledText : Text.PlainText
|
||||||
|
elide: Text.ElideRight
|
||||||
|
maximumLineCount: subtitleCanWrap ? 9999 : 1
|
||||||
|
wrapMode: subtitleCanWrap ? Text.WordWrap : Text.NoWrap
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Busy indicator
|
||||||
|
PlasmaComponents3.BusyIndicator {
|
||||||
|
id: busyIndicator
|
||||||
|
|
||||||
|
visible: listItem.isBusy
|
||||||
|
|
||||||
|
// Otherwise it makes the list item taller when it appears
|
||||||
|
Layout.maximumHeight: defaultActionButton.implicitHeight
|
||||||
|
Layout.maximumWidth: Layout.maximumHeight
|
||||||
|
}
|
||||||
|
|
||||||
|
// Default action button
|
||||||
|
PlasmaComponents3.Button {
|
||||||
|
id: defaultActionButton
|
||||||
|
|
||||||
|
enabled: listItem.isEnabled
|
||||||
|
visible: defaultActionButtonAction
|
||||||
|
&& listItem.defaultActionButtonVisible
|
||||||
|
&& (clickAndHoverHandler.containsMouse || expandedView.visible)
|
||||||
|
&& (!busyIndicator.visible || listItem.showDefaultActionButtonWhenBusy)
|
||||||
|
|
||||||
|
icon.width: units.iconSizes.smallMedium
|
||||||
|
icon.height: units.iconSizes.smallMedium
|
||||||
|
}
|
||||||
|
|
||||||
|
// Expand/collapse button
|
||||||
|
PlasmaComponents3.Button {
|
||||||
|
visible: clickAndHoverHandler.containsMouse
|
||||||
|
|
||||||
|
icon.name: expandedView.visible? "collapse" : "expand"
|
||||||
|
icon.width: units.iconSizes.smallMedium
|
||||||
|
icon.height: units.iconSizes.smallMedium
|
||||||
|
|
||||||
|
onClicked: listItem.toggleExpanded()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Busy indicator
|
|
||||||
PlasmaComponents3.BusyIndicator {
|
|
||||||
id: busyIndicator
|
|
||||||
|
|
||||||
visible: listItem.isBusy
|
// Expanded view, by default showing the actions list
|
||||||
|
Loader {
|
||||||
|
id: expandedView
|
||||||
|
|
||||||
// Otherwise it makes the list item taller when it appears
|
visible: false
|
||||||
Layout.maximumHeight: defaultActionButton.implicitHeight
|
opacity: visible ? 1.0 : 0
|
||||||
Layout.maximumWidth: Layout.maximumHeight
|
|
||||||
}
|
|
||||||
|
|
||||||
// Default action button
|
active: customExpandedViewContent != undefined
|
||||||
PlasmaComponents3.Button {
|
sourceComponent: customExpandedViewContent
|
||||||
id: defaultActionButton
|
|
||||||
|
|
||||||
enabled: listItem.isEnabled
|
Layout.fillWidth: true
|
||||||
visible: defaultActionButtonAction
|
Layout.margins: units.smallSpacing
|
||||||
&& listItem.defaultActionButtonVisible
|
|
||||||
&& listItem.containsMouse
|
|
||||||
&& (!busyIndicator.visible || listItem.showDefaultActionButtonWhenBusy)
|
|
||||||
|
|
||||||
icon.width: units.iconSizes.smallMedium
|
Behavior on opacity {
|
||||||
icon.height: units.iconSizes.smallMedium
|
NumberAnimation {
|
||||||
}
|
duration: units.veryLongDuration
|
||||||
|
easing.type: Easing.InOutCubic
|
||||||
// Expand/collapse button
|
}
|
||||||
PlasmaComponents3.Button {
|
|
||||||
visible: listItem.containsMouse
|
|
||||||
|
|
||||||
icon.name: expandedView.visible? "collapse" : "expand"
|
|
||||||
icon.width: units.iconSizes.smallMedium
|
|
||||||
icon.height: units.iconSizes.smallMedium
|
|
||||||
|
|
||||||
onClicked: listItem.toggleExpanded()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// Expanded view, by default showing the actions list
|
|
||||||
Loader {
|
|
||||||
id: expandedView
|
|
||||||
|
|
||||||
visible: false
|
|
||||||
opacity: visible ? 1.0 : 0
|
|
||||||
|
|
||||||
active: customExpandedViewContent != undefined
|
|
||||||
sourceComponent: customExpandedViewContent
|
|
||||||
|
|
||||||
Layout.fillWidth: true
|
|
||||||
Layout.margins: units.smallSpacing
|
|
||||||
|
|
||||||
Behavior on opacity {
|
|
||||||
NumberAnimation {
|
|
||||||
duration: units.veryLongDuration
|
|
||||||
easing.type: Easing.InOutCubic
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user