Kirigami2

controls/templates/SwipeListItem.qml
1 /*
2  * SPDX-FileCopyrightText: 2019 Marco Martin <[email protected]>
3  *
4  * SPDX-License-Identifier: LGPL-2.0-or-later
5  */
6 
7 import QtQuick 2.6
8 import QtQuick.Layouts 1.4
9 import QtQuick.Controls 2.4 as Controls
10 import QtQuick.Templates 2.4 as T2
11 import org.kde.kirigami 2.11 as Kirigami
12 import "../private"
13 
42 T2.SwipeDelegate {
43  id: listItem
44 
51  property alias supportsMouseEvents: listItem.hoverEnabled
52 
59  property alias containsMouse: listItem.hovered
60 
68  property bool alternatingBackground: false
69 
75  property bool sectionDelegate: false
76 
82  property bool separatorVisible: true
83 
91  readonly property bool actionsVisible: actionsLayout.hasVisibleActions
92 
99  property list<Controls.Action> actions
100 
108  property color textColor: Kirigami.Theme.textColor
109 
114  property color backgroundColor: Kirigami.Theme.backgroundColor
115 
122  property color alternateBackgroundColor: Kirigami.Theme.alternateBackgroundColor
123 
132  property color activeTextColor: Kirigami.Theme.highlightedTextColor
133 
139  property color activeBackgroundColor: Kirigami.Theme.highlightColor
140 
147  property bool alwaysVisibleActions: false
148 
149  //TODO KF6 remove this super wrong thing
150  default property alias _default: listItem.contentItem
151 
152  LayoutMirroring.childrenInherit: true
153 
154  hoverEnabled: true
155  implicitWidth: contentItem ? contentItem.implicitWidth : Kirigami.Units.gridUnit * 12
156  width: parent ? parent.width : implicitWidth
157  implicitHeight: Math.max(Kirigami.Units.gridUnit * 2, contentItem.implicitHeight) + topPadding + bottomPadding
158 
159  padding: !listItem.alwaysVisibleActions && Kirigami.Settings.tabletMode ? Kirigami.Units.largeSpacing : Kirigami.Units.smallSpacing
160 
161  leftPadding: padding * 2
162 
163  rightPadding: padding * 2 + (overlayLoader.visible ? overlayLoader.width : 0) + Kirigami.Units.smallSpacing
164 
165  topPadding: padding
166  bottomPadding: padding
167 
168  contentItem: Item {}
169  QtObject {
170  id: internal
171 
172  property Flickable view: listItem.ListView.view || (listItem.parent ? (listItem.parent.ListView.view || listItem.parent) : null)
173 
174  readonly property QtObject swipeFilterItem: (view && view.parent && view.parent.parent && view.parent.parent._swipeFilter) ? view.parent.parent._swipeFilter : null
175 
176  readonly property bool edgeEnabled: swipeFilterItem ? swipeFilterItem.currentItem === listItem || swipeFilterItem.currentItem === listItem.parent : false
177 
178  property bool indicateActiveFocus: listItem.pressed || Kirigami.Settings.tabletMode || listItem.activeFocus || (view ? view.activeFocus : false)
179 
180  // Search for scrollbar of the view or of the ScrollView
181  property T2.ScrollBar verticalScrollBar: {
182  if (!view) {
183  return null;
184  }
185  return view.T2.ScrollBar.vertical || view.parent.T2.ScrollBar.vertical;
186  }
187 
188  //install the SwipeItemEventFilter
189  onViewChanged: {
190  if (listItem.alwaysVisibleActions || !Kirigami.Settings.tabletMode) {
191  return;
192  }
193  if (internal.view && Kirigami.Settings.tabletMode && !internal.view.parent.parent._swipeFilter) {
194  var component = Qt.createComponent(Qt.resolvedUrl("../private/SwipeItemEventFilter.qml"));
195  internal.view.parent.parent._swipeFilter = component.createObject(internal.view.parent.parent);
196  }
197  }
198  }
199 
200  Connections {
201  target: Kirigami.Settings
202  onTabletModeChanged: {
203  if (Kirigami.Settings.tabletMode) {
204  if (!internal.swipeFilterItem) {
205  var component = Qt.createComponent(Qt.resolvedUrl("../private/SwipeItemEventFilter.qml"));
206  listItem.ListView.view.parent.parent._swipeFilter = component.createObject(listItem.ListView.view.parent.parent);
207  }
208  } else {
209  if (listItem.ListView.view.parent.parent._swipeFilter) {
210  listItem.ListView.view.parent.parent._swipeFilter.destroy();
211  slideAnim.to = 0;
212  slideAnim.restart();
213  }
214  }
215  }
216  }
217 
218 //BEGIN Items
219  Loader {
220  id: overlayLoader
221  anchors {
222  right: contentItem ? contentItem.right : undefined
223  top: parent.top
224  bottom: parent.bottom
225  rightMargin: -listItem.rightPadding + Kirigami.Units.smallSpacing
226  }
227 
228  parent: listItem
229  z: contentItem ? contentItem.z + 1 : 0
230  width: item ? item.implicitWidth : actionsLayout.implicitWidth
231  active: !listItem.alwaysVisibleActions && Kirigami.Settings.tabletMode
232  visible: listItem.actionsVisible && opacity > 0
233  sourceComponent: handleComponent
234  opacity: listItem.alwaysVisibleActions || Kirigami.Settings.tabletMode || listItem.hovered || !listItem.supportsMouseEvents ? 1 : 0
235  Behavior on opacity {
236  OpacityAnimator {
237  id: opacityAnim
238  duration: Kirigami.Units.longDuration
239  easing.type: Easing.InOutQuad
240  }
241  }
242  }
243 
244  Component {
245  id: handleComponent
246 
247  MouseArea {
248  id: dragButton
249  anchors {
250  right: parent.right
251  }
252  implicitWidth: Kirigami.Units.iconSizes.smallMedium
253 
254  preventStealing: true
255  readonly property real openPosition: (listItem.width - width - listItem.leftPadding * 2)/listItem.width
256  property real startX: 0
257  property real lastPosition: 0
258  property bool openIntention
259 
260  onPressed: startX = mapToItem(listItem, 0, 0).x;
261  onClicked: {
262  if (Math.abs(mapToItem(listItem, 0, 0).x - startX) > Qt.styleHints.startDragDistance) {
263  return;
264  }
265  if (listItem.LayoutMirroring.enabled) {
266  if (listItem.swipe.position < 0.5) {
267  slideAnim.to = openPosition
268  } else {
269  slideAnim.to = 0
270  }
271  } else {
272  if (listItem.swipe.position > -0.5) {
273  slideAnim.to = -openPosition
274  } else {
275  slideAnim.to = 0
276  }
277  }
278  slideAnim.restart();
279  }
280  onPositionChanged: {
281  var pos = mapToItem(listItem, mouse.x, mouse.y);
282 
283  if (listItem.LayoutMirroring.enabled) {
284  listItem.swipe.position = Math.max(0, Math.min(openPosition, (pos.x / listItem.width)));
285  openIntention = listItem.swipe.position > lastPosition;
286  } else {
287  listItem.swipe.position = Math.min(0, Math.max(-openPosition, (pos.x / (listItem.width -listItem.rightPadding) - 1)));
288  openIntention = listItem.swipe.position < lastPosition;
289  }
290  lastPosition = listItem.swipe.position;
291  }
292  onReleased: {
293  if (listItem.LayoutMirroring.enabled) {
294  if (openIntention) {
295  slideAnim.to = openPosition
296  } else {
297  slideAnim.to = 0
298  }
299  } else {
300  if (openIntention) {
301  slideAnim.to = -openPosition
302  } else {
303  slideAnim.to = 0
304  }
305  }
306  slideAnim.restart();
307  }
308 
309  Kirigami.Icon {
310  id: handleIcon
311  anchors.fill: parent
312  selected: listItem.checked || (listItem.pressed && !listItem.checked && !listItem.sectionDelegate)
313  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"))
314  }
315 
316  Connections {
317  id: swipeFilterConnection
318 
319  target: internal.edgeEnabled ? internal.swipeFilterItem : null
320  onPeekChanged: {
321  if (!listItem.actionsVisible) {
322  return;
323  }
324 
325  if (listItem.LayoutMirroring.enabled) {
326  listItem.swipe.position = Math.max(0, Math.min(dragButton.openPosition, internal.swipeFilterItem.peek));
327  dragButton.openIntention = listItem.swipe.position > dragButton.lastPosition;
328 
329  } else {
330  listItem.swipe.position = Math.min(0, Math.max(-dragButton.openPosition, -internal.swipeFilterItem.peek));
331  dragButton.openIntention = listItem.swipe.position < dragButton.lastPosition;
332  }
333 
334  dragButton.lastPosition = listItem.swipe.position;
335  }
336  onPressed: {
337  if (internal.edgeEnabled) {
338  dragButton.onPressed(mouse);
339  }
340  }
341  onClicked: {
342  if (Math.abs(listItem.background.x) < Kirigami.Units.gridUnit && internal.edgeEnabled) {
343  dragButton.clicked(mouse);
344  }
345  }
346  onReleased: {
347  if (internal.edgeEnabled) {
348  dragButton.released(mouse);
349  }
350  }
351  onCurrentItemChanged: {
352  if (!internal.edgeEnabled) {
353  slideAnim.to = 0;
354  slideAnim.restart();
355  }
356  }
357  }
358  }
359  }
360 
361  //TODO: expose in API?
362  Component {
363  id: actionsBackgroundDelegate
364  MouseArea {
365 
366  anchors.fill: parent
367 
368  // Controls.SwipeDelegate.onPressedChanged is broken with touch
369  onClicked: {
370  slideAnim.to = 0;
371  slideAnim.restart();
372  }
373  Rectangle {
374  anchors.fill: parent
375  color: parent.pressed ? Qt.darker(Kirigami.Theme.backgroundColor, 1.1) : Qt.darker(Kirigami.Theme.backgroundColor, 1.05)
376  }
377 
378  visible: listItem.swipe.position != 0
379 
380 
381  EdgeShadow {
382  edge: Qt.TopEdge
383  visible: background.x != 0
384  anchors {
385  right: parent.right
386  left: parent.left
387  top: parent.top
388  }
389  }
390  EdgeShadow {
391  edge: LayoutMirroring.enabled ? Qt.RightEdge : Qt.LeftEdge
392  x: LayoutMirroring.enabled ? listItem.background.x - width : (listItem.background.x + listItem.background.width)
393  visible: background.x != 0
394  anchors {
395  top: parent.top
396  bottom: parent.bottom
397  }
398  }
399  }
400  }
401 
402 
403  RowLayout {
404  id: actionsLayout
405  anchors {
406  right: parent.right
407  top: parent.top
408  bottom: parent.bottom
409  rightMargin: Kirigami.Units.smallSpacing
410  }
411  visible: parent != listItem
412  parent: !listItem.alwaysVisibleActions && Kirigami.Settings.tabletMode
413  ? listItem.swipe.leftItem || listItem.swipe.rightItem || listItem
414  : overlayLoader
415 
416  property bool hasVisibleActions: false
417  function updateVisibleActions(definitelyVisible = false) {
418  if (definitelyVisible) {
419  hasVisibleActions = true;
420  } else {
421  var actionCount = listItem.actions.length;
422  for (var i = 0; i < actionCount; i++) {
423  // Assuming that visible is only false if it is explicitly false, and not just falsy
424  if (listItem.actions[i].visible === false) {
425  continue;
426  }
427  hasVisibleActions = true;
428  break;
429  }
430  }
431  }
432 
433  Repeater {
434  model: {
435  if (listItem.actions.length === 0) {
436  return null;
437  } else {
438  return listItem.actions[0].text !== undefined &&
439  listItem.actions[0].trigger !== undefined ?
440  listItem.actions :
441  listItem.actions[0];
442  }
443  }
444  delegate: Controls.ToolButton {
445  icon.name: modelData.iconName !== "" ? modelData.iconName : ""
446  icon.source: modelData.iconSource !== "" ? modelData.iconSource : ""
447  enabled: (modelData && modelData.enabled !== undefined) ? modelData.enabled : true;
448  visible: (modelData && modelData.visible !== undefined) ? modelData.visible : true;
449  onVisibleChanged: actionsLayout.updateVisibleActions(visible);
450  Component.onCompleted: actionsLayout.updateVisibleActions(visible);
451  Component.onDestruction: actionsLayout.updateVisibleActions(visible);
452  Controls.ToolTip.delay: Kirigami.Units.toolTipDelay
453  Controls.ToolTip.timeout: 5000
454  Controls.ToolTip.visible: listItem.visible && (Kirigami.Settings.tabletMode ? pressed : hovered) && Controls.ToolTip.text.length > 0
455  Controls.ToolTip.text: modelData.tooltip || modelData.text
456 
457  onClicked: {
458  if (modelData && modelData.trigger !== undefined) {
459  modelData.trigger();
460  }
461  slideAnim.to = 0;
462  slideAnim.restart();
463  }
464  }
465  }
466  }
467 
468 
469  background: DefaultListItemBackground {}
470 
471  swipe {
472  enabled: false
473  right: listItem.alwaysVisibleActions ||listItem.LayoutMirroring.enabled || !Kirigami.Settings.tabletMode ? null : actionsBackgroundDelegate
474  left: listItem.alwaysVisibleActions ||listItem.LayoutMirroring.enabled && Kirigami.Settings.tabletMode ? actionsBackgroundDelegate : null
475  }
476  NumberAnimation {
477  id: slideAnim
478  duration: Kirigami.Units.longDuration
479  easing.type: Easing.InOutQuad
480  target: listItem.swipe
481  property: "position"
482  from: listItem.swipe.position
483  }
484 //END Items
485 }
486 
Definition: icon.h:19
QString from() const
if(recurs()&&!first)
QTextStream & right(QTextStream &stream)
QTextStream & left(QTextStream &stream)
KIOFILEWIDGETS_EXPORT QStringList list(const QString &fileClass)
This file is part of the KDE documentation.
Documentation copyright © 1996-2020 The KDE developers.
Generated on Fri Jun 5 2020 22:39:02 by doxygen 1.8.11 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.