diff --git a/src/controls/BasicListItem.qml b/src/controls/BasicListItem.qml index 6104a59e..2e460cc9 100644 --- a/src/controls/BasicListItem.qml +++ b/src/controls/BasicListItem.qml @@ -1,90 +1,90 @@ /* * Copyright 2010 Marco Martin * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU Library General Public License as * published by the Free Software Foundation; either version 2, 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 Library General Public License for more details * * You should have received a copy of the GNU Library 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.1 import QtQuick.Layouts 1.2 import QtQuick.Controls 2.0 as QQC2 import org.kde.kirigami 2.4 /** * An item delegate for the primitive ListView component. * * It's intended to make all listviews look coherent. * It has a default icon and a label * */ AbstractListItem { id: listItem /** * string: bool * A single text label the list item will contain */ property alias label: listItem.text /** * icon: var * A single icon that will be displayed in the list item. * The icon can be a grouped property with name,size,color etc, as QtQuickControls2 icons are defined. * The icon can also be either a QIcon, a string name of a fdo compatible name, * or any url accepted by the Image element. */ property var icon /** * reserveSpaceForIcon: bool * If true, even when there is no icon the space will be reserved for it * It's useful in layouts where only some entries have an icon, * having the text all horizontally aligned */ property alias reserveSpaceForIcon: iconItem.visible default property alias _basicDefault: layout.children - RowLayout { + contentItem: RowLayout { id: layout spacing: Units.smallSpacing*2 property bool indicateActiveFocus: listItem.pressed || Settings.tabletMode || listItem.activeFocus || (listItem.ListView.view ? listItem.ListView.view.activeFocus : false) Icon { id: iconItem source: { if (listItem.icon && listItem.icon.hasOwnProperty) { if (listItem.icon.hasOwnProperty("name") && listItem.icon.name != "") return listItem.icon.name; if (listItem.icon.hasOwnProperty("source")) return listItem.icon.source; } return listItem.icon; } Layout.minimumHeight: Units.iconSizes.smallMedium Layout.maximumHeight: Layout.minimumHeight Layout.minimumWidth: height selected: layout.indicateActiveFocus && (listItem.highlighted || listItem.checked || listItem.pressed) color: listItem.icon && listItem.icon.color && listItem.icon.color.a > 0 ? listItem.icon.color : Qt.rgba(0, 0, 0, 0) } QQC2.Label { id: labelItem text: listItem.text Layout.fillWidth: true color: layout.indicateActiveFocus && (listItem.highlighted || listItem.checked || listItem.pressed) ? listItem.activeTextColor : listItem.textColor elide: Text.ElideRight font: listItem.font } } } diff --git a/src/controls/templates/AbstractListItem.qml b/src/controls/templates/AbstractListItem.qml index 09577b08..d5cf1a74 100644 --- a/src/controls/templates/AbstractListItem.qml +++ b/src/controls/templates/AbstractListItem.qml @@ -1,128 +1,129 @@ /* * Copyright 2010 Marco Martin * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU Library General Public License as * published by the Free Software Foundation; either version 2, 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 Library General Public License for more details * * You should have received a copy of the GNU Library 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.1 import QtQuick.Layouts 1.0 import org.kde.kirigami 2.4 import QtQuick.Templates 2.0 as T2 /** * An item delegate for the primitive ListView component. * * It's intended to make all listviews look coherent. * * @inherit QtQuick.Templates.ItemDelegate */ T2.ItemDelegate { id: listItem /** * supportsMouseEvents: bool * Holds if the item emits signals related to mouse interaction. *TODO: remove * The default value is false. */ property bool supportsMouseEvents: hoverEnabled /** * containsMouse: bool * True when the user hovers the mouse over the list item * NOTE: on mobile touch devices this will be true only when pressed is also true * TODO: remove? */ property alias containsMouse: listItem.hovered /** * sectionDelegate: bool * If true the item will be a delegate for a section, so will look like a * "title" for the items under it. */ property bool sectionDelegate: false /** * separatorVisible: bool * True if the separator between items is visible * default: true */ property bool separatorVisible: true /** * textColor: color * Color for the text in the item * It is advised to leave the default value (Theme.textColor) * * Note: if custom text elements are inserted in an AbstractListItem, * their color property will have to be manually bound with this property */ property color textColor: Theme.textColor /** * backgroundColor: color * Color for the background of the item * It is advised to leave the default value (Theme.viewBackgroundColor) */ property color backgroundColor: "transparent" /** * activeTextColor: color * Color for the text in the item when pressed or selected * It is advised to leave the default value (Theme.highlightedTextColor) * * Note: if custom text elements are inserted in an AbstractListItem, * their color property will have to be manually bound with this property */ property color activeTextColor: Theme.highlightedTextColor /** * activeBackgroundColor: color * Color for the background of the item when pressed or selected * It is advised to leave the default value (Theme.highlightColor) */ property color activeBackgroundColor: Theme.highlightColor default property alias _default: listItem.contentItem Theme.colorGroup: internal.indicateActiveFocus ? Theme.Active : Theme.Inactive - leftPadding: LayoutMirroring.enabled && internal.view && internal.view.T2.ScrollBar.vertical ? internal.view.T2.ScrollBar.vertical.width : Units.largeSpacing + leftPadding: LayoutMirroring.enabled && internal.view && internal.view.T2.ScrollBar.vertical && internal.view.T2.ScrollBar.vertical.visible ? internal.view.T2.ScrollBar.vertical.width : Units.largeSpacing topPadding: Units.largeSpacing - rightPadding: !LayoutMirroring.enabled && internal.view && internal.view.T2.ScrollBar.vertical ? internal.view.T2.ScrollBar.vertical.width : Units.largeSpacing + + rightPadding: !LayoutMirroring.enabled && internal.view && internal.view.T2.ScrollBar.vertical && internal.view.T2.ScrollBar.vertical.visible ? internal.view.T2.ScrollBar.vertical.width : Units.largeSpacing bottomPadding: Units.largeSpacing implicitWidth: contentItem ? contentItem.implicitWidth : Units.gridUnit * 12 implicitHeight: contentItem.implicitHeight + Units.smallSpacing * 5 width: parent ? parent.width : implicitWidth Layout.fillWidth: true opacity: enabled ? 1 : 0.6 height: visible ? implicitHeight : 0 hoverEnabled: true QtObject { id: internal property Flickable view: listItem.ListView.view || (listItem.parent ? listItem.parent.ListView.view : null) property bool indicateActiveFocus: listItem.pressed || Settings.tabletMode || listItem.activeFocus || (view ? view.activeFocus : false) } Accessible.role: Accessible.ListItem } diff --git a/src/controls/templates/SwipeListItem.qml b/src/controls/templates/SwipeListItem.qml index 477c4e2f..abfd1ae3 100644 --- a/src/controls/templates/SwipeListItem.qml +++ b/src/controls/templates/SwipeListItem.qml @@ -1,399 +1,399 @@ /* * Copyright 2010 Marco Martin * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU Library General Public License as * published by the Free Software Foundation; either version 2, 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 Library General Public License for more details * * You should have received a copy of the GNU Library 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.7 import QtQuick.Layouts 1.2 import QtQuick.Controls 2.0 as Controls import org.kde.kirigami 2.4 import "../private" import QtQuick.Templates 2.0 as T2 /** * An item delegate Intended to support extra actions obtainable * by uncovering them by dragging away the item with the handle * This acts as a container for normal list items. * Any subclass of AbstractListItem can be assigned as the contentItem property. * @code * ListView { * model: myModel * delegate: SwipeListItem { * QQC2.Label { * text: model.text * } * actions: [ * Action { * iconName: "document-decrypt" * onTriggered: print("Action 1 clicked") * }, * Action { * iconName: model.action2Icon * onTriggered: //do something * } * ] * } * * } * @endcode * * @inherit QtQuick.Templates.ItemDelegate */ T2.ItemDelegate { id: listItem //BEGIN properties /** * supportsMouseEvents: bool * Holds if the item emits signals related to mouse interaction. *TODO: remove * The default value is false. */ property alias supportsMouseEvents: listItem.hoverEnabled /** * containsMouse: bool * True when the user hover the mouse over the list item * NOTE: on mobile touch devices this will be true only when pressed is also true */ property alias containsMouse: listItem.hovered /** * sectionDelegate: bool * If true the item will be a delegate for a section, so will look like a * "title" for the items under it. */ property bool sectionDelegate: false /** * separatorVisible: bool * True if the separator between items is visible * default: true */ property bool separatorVisible: true /** * actions: list * Defines the actions for the list item: at most 4 buttons will * contain the actions for the item, that can be revealed by * sliding away the list item. */ property list actions /** * textColor: color * Color for the text in the item * * Note: if custom text elements are inserted in an AbstractListItem, * their color property will have to be manually bound with this property */ property color textColor: Theme.textColor /** * backgroundColor: color * Color for the background of the item */ property color backgroundColor: Theme.backgroundColor /** * activeTextColor: color * Color for the text in the item when pressed or selected * It is advised to leave the default value (Theme.highlightedTextColor) * * Note: if custom text elements are inserted in an AbstractListItem, * their color property will have to be manually bound with this property */ property color activeTextColor: Theme.highlightedTextColor /** * activeBackgroundColor: color * Color for the background of the item when pressed or selected * It is advised to leave the default value (Theme.highlightColor) */ property color activeBackgroundColor: Theme.highlightColor default property alias _default: listItem.contentItem Theme.colorGroup: behindItem.indicateActiveFocus ? Theme.Active : Theme.Inactive hoverEnabled: true implicitWidth: contentItem ? contentItem.implicitWidth : Units.gridUnit * 12 width: parent ? parent.width : implicitWidth implicitHeight: contentItem.implicitHeight + Units.smallSpacing * 5 leftPadding: Units.smallSpacing * 2 rightPadding: Units.smallSpacing * 2 + (handleMouse.visible ? handleMouse.width : hovered * actionsLayout.width) + handleMouse.anchors.rightMargin topPadding: Units.smallSpacing * 2 bottomPadding: Units.smallSpacing * 2 //END properties Item { id: behindItem parent: listItem z: -1 //TODO: a global "open" state enabled: background.x !== 0 property bool indicateActiveFocus: listItem.pressed || Settings.tabletMode || listItem.activeFocus || (view ? view.activeFocus : false) property Flickable view: listItem.ListView.view || (listItem.parent ? (listItem.parent.ListView.view || listItem.parent) : null) onViewChanged: { if (view && Settings.tabletMode && !behindItem.view.parent.parent._swipeFilter) { var component = Qt.createComponent(Qt.resolvedUrl("../private/SwipeItemEventFilter.qml")); behindItem.view.parent.parent._swipeFilter = component.createObject(behindItem.view.parent.parent); } } anchors { fill: parent } Rectangle { id: shadowHolder color: Qt.darker(Theme.backgroundColor, 1.05); anchors.fill: parent } EdgeShadow { edge: Qt.TopEdge anchors { right: parent.right left: parent.left top: parent.top } } EdgeShadow { edge: LayoutMirroring.enabled ? Qt.RightEdge : Qt.LeftEdge x: LayoutMirroring.enabled ? listItem.background.x - width : (listItem.background.x + listItem.background.width) anchors { top: parent.top bottom: parent.bottom } } MouseArea { anchors.fill: parent preventStealing: true enabled: background.x != 0 onClicked: { positionAnimation.from = background.x; positionAnimation.to = 0; positionAnimation.running = true; } } Row { id: actionsLayout z: 1 parent: Settings.tabletMode ? behindItem : listItem opacity: Settings.tabletMode ? 1 : (listItem.hovered ? 1 : 0) Behavior on opacity { OpacityAnimator { duration: Units.longDuration easing.type: Easing.InOutQuad } } anchors { right: parent.right verticalCenter: parent.verticalCenter rightMargin: handleMouse.anchors.rightMargin } height: Math.min( parent.height / 1.5, Units.iconSizes.medium) width: childrenRect.width property bool exclusive: false property Item checkedButton spacing: Units.largeSpacing Repeater { model: { if (listItem.actions.length == 0) { return null; } else { return listItem.actions[0].text !== undefined && listItem.actions[0].trigger !== undefined ? listItem.actions : listItem.actions[0]; } } delegate: Icon { height: actionsLayout.height width: height source: modelData.iconName enabled: (modelData && modelData.enabled !== undefined) ? modelData.enabled : true; visible: (modelData && modelData.visible !== undefined) ? modelData.visible : true; MouseArea { id: actionMouse anchors { fill: parent; margins: Settings.tabletMode ? -Units.smallSpacing : 0; } enabled: (modelData && modelData.enabled !== undefined) ? modelData.enabled : true; hoverEnabled: !Settings.tabletMode onClicked: { if (modelData && modelData.trigger !== undefined) { modelData.trigger(); } positionAnimation.from = background.x; positionAnimation.to = 0; positionAnimation.running = true; } Controls.ToolTip.delay: 1000 Controls.ToolTip.timeout: 5000 Controls.ToolTip.visible: listItem.visible && (Settings.tabletMode ? actionMouse.pressed : actionMouse.containsMouse) && Controls.ToolTip.text.length > 0 Controls.ToolTip.text: modelData.tooltip || modelData.text } } } } } MouseArea { id: handleMouse parent: listItem.background visible: Settings.tabletMode && actions.length > 0 z: 99 anchors { right: parent.right verticalCenter: parent.verticalCenter - rightMargin: behindItem.view && behindItem.view.T2.ScrollBar && behindItem.view.T2.ScrollBar.vertical ? behindItem.view.T2.ScrollBar.vertical.width : Units.smallSpacing + rightMargin: !Settings.isMobile && behindItem.view && behindItem.view.T2.ScrollBar && behindItem.view.T2.ScrollBar.vertical && behindItem.view.T2.ScrollBar.vertical.visible ? behindItem.view.T2.ScrollBar.vertical.width : Units.smallSpacing } preventStealing: true width: Units.iconSizes.smallMedium height: width property var downTimestamp; property int startX property int startMouseX onClicked: { positionAnimation.from = background.x; if (listItem.background.x > -listItem.background.width/2) { positionAnimation.to = (LayoutMirroring.enabled ? -1 : +1) * (-listItem.width + height + handleMouse.anchors.rightMargin); } else { positionAnimation.to = 0; } positionAnimation.running = true; } onPressed: { downTimestamp = (new Date()).getTime(); startX = listItem.background.x; startMouseX = mouse.x; } onPositionChanged: { if (LayoutMirroring.enabled) { listItem.background.x = Math.max(0, Math.min(listItem.width - height, listItem.background.x - (startMouseX - mouse.x))); } else { listItem.background.x = Math.min(0, Math.max(-listItem.width + height, listItem.background.x - (startMouseX - mouse.x))); } } onReleased: { var speed = ((startX - listItem.background.x) / ((new Date()).getTime() - downTimestamp) * 1000); if (LayoutMirroring.enabled) { speed = -speed; } if (Math.abs(speed) < Units.gridUnit) { return; } if (speed > listItem.width/2) { positionAnimation.to = (LayoutMirroring.enabled ? -1 : +1) * (-listItem.width + height + handleMouse.anchors.rightMargin); } else { positionAnimation.to = 0; } positionAnimation.from = background.x; positionAnimation.running = true; } Icon { id: handleIcon anchors.fill: parent selected: listItem.checked || (listItem.pressed && !listItem.checked && !listItem.sectionDelegate) source: (LayoutMirroring.enabled ? (listItem.background.x < listItem.background.width/2 ? "overflow-menu-right" : "overflow-menu-left") : (listItem.background.x < -listItem.background.width/2 ? "overflow-menu-right" : "overflow-menu-left")) } } NumberAnimation { id: positionAnimation property: "x" target: background duration: Units.longDuration easing.type: Easing.InOutQuad } //BEGIN signal handlers onContentItemChanged: { if (!contentItem) { return; } contentItem.parent = background; contentItem.anchors.top = background.top; contentItem.anchors.left = background.left; contentItem.anchors.right = background.right; contentItem.anchors.leftMargin = Qt.binding(function() {return listItem.leftPadding}); contentItem.anchors.rightMargin = Qt.binding(function() {return listItem.rightPadding}); contentItem.anchors.topMargin = Qt.binding(function() {return listItem.topPadding}); contentItem.z = 0; } Component.onCompleted: { //this will happen only once listItem.contentItemChanged(); } Connections { target: Settings onTabletModeChanged: { if (Settings.tabletMode) { if (!internal.swipeFilterItem) { var component = Qt.createComponent(Qt.resolvedUrl("../private/SwipeItemEventFilter.qml")); listItem.ListView.view.parent.parent._swipeFilter = component.createObject(listItem.ListView.view.parent.parent); } } else { if (listItem.ListView.view.parent.parent._swipeFilter) { listItem.ListView.view.parent.parent._swipeFilter.destroy(); positionAnimation.to = 0; positionAnimation.from = background.x; positionAnimation.running = true; } } } } QtObject { id: internal readonly property QtObject swipeFilterItem: (behindItem.view && behindItem.view.parent && behindItem.view.parent.parent && behindItem.view.parent.parent._swipeFilter) ? behindItem.view.parent.parent._swipeFilter : null readonly property bool edgeEnabled: swipeFilterItem ? swipeFilterItem.currentItem === listItem || swipeFilterItem.currentItem === listItem.parent : false } Connections { id: swipeFilterConnection target: internal.edgeEnabled ? internal.swipeFilterItem : null onPeekChanged: { if (listItem.LayoutMirroring.enabled) { listItem.background.x = (listItem.background.width - listItem.background.height) * (1 - internal.swipeFilterItem.peek); } else { listItem.background.x = -(listItem.background.width - listItem.background.height) * internal.swipeFilterItem.peek; } } onCurrentItemChanged: { if (!internal.edgeEnabled) { positionAnimation.to = 0; positionAnimation.from = background.x; positionAnimation.running = true; } } } //END signal handlers Accessible.role: Accessible.ListItem }