Merge lp:~zsombi/ubuntu-ui-toolkit/35-options-panel-swipe into lp:~zsombi/ubuntu-ui-toolkit/listitem-master

Proposed by Zsombor Egri
Status: Merged
Approved by: Zsombor Egri
Approved revision: 1311
Merged at revision: 1272
Proposed branch: lp:~zsombi/ubuntu-ui-toolkit/35-options-panel-swipe
Merge into: lp:~zsombi/ubuntu-ui-toolkit/listitem-master
Prerequisite: lp:~zsombi/ubuntu-ui-toolkit/34-snap-animator
Diff against target: 1767 lines (+1074/-69)
22 files modified
components.api (+9/-0)
modules/Ubuntu/Components/Themes/Ambiance/ListItemPanel.qml (+64/-0)
modules/Ubuntu/Components/Themes/Ambiance/ListItemStyle.qml (+34/-0)
modules/Ubuntu/Components/Themes/Ambiance/qmldir (+4/-0)
modules/Ubuntu/Components/plugin/plugin.cpp (+5/-0)
modules/Ubuntu/Components/plugin/plugin.pro (+4/-2)
modules/Ubuntu/Components/plugin/uclistitem.cpp (+389/-47)
modules/Ubuntu/Components/plugin/uclistitem.h (+9/-1)
modules/Ubuntu/Components/plugin/uclistitem_p.h (+24/-3)
modules/Ubuntu/Components/plugin/uclistitemactions.cpp (+158/-3)
modules/Ubuntu/Components/plugin/uclistitemactions.h (+1/-0)
modules/Ubuntu/Components/plugin/uclistitemactions_p.h (+14/-2)
modules/Ubuntu/Components/plugin/uclistitemactionsattached.cpp (+6/-3)
modules/Ubuntu/Components/plugin/uclistitemstyle.cpp (+92/-0)
modules/Ubuntu/Components/plugin/uclistitemstyle.h (+54/-0)
tests/qmlapicheck.sh (+1/-1)
tests/resources/listitems/ListItemTest.qml (+29/-0)
tests/unit/tst_performance/ListItemWithActionsList.qml (+6/-0)
tests/unit/tst_performance/ListItemWithInlineActionsList.qml (+41/-0)
tests/unit/tst_performance/tst_performance.cpp (+2/-1)
tests/unit/tst_performance/tst_performance.pro (+3/-2)
tests/unit_x11/tst_components/tst_listitem.qml (+125/-4)
To merge this branch: bzr merge lp:~zsombi/ubuntu-ui-toolkit/35-options-panel-swipe
Reviewer Review Type Date Requested Status
Tim Peeters Approve
Review via email: mp+241036@code.launchpad.net

Description of the change

Actions panel handling, swiping and snap animation take in use. Uses fix-size panel for testing.

To post a comment you must log in.
1287. By Zsombor Egri

small fixes

1288. By Zsombor Egri

prereq sync

1289. By Zsombor Egri

adjustments to prerequisite changes; documentation fix

1290. By Zsombor Egri

accessing private property fix

1291. By Zsombor Egri

test cases fixed

1292. By Zsombor Egri

prereq sync

1293. By Zsombor Egri

fixing eronous trailingActions assignment

1294. By Zsombor Egri

introduce styling; move ListItemPanel into Ambiance theme, expose ListItemStyle C++ style component from the main plugin

1295. By Zsombor Egri

animation cleanup

1296. By Zsombor Egri

make leadingPanel property readonly

1297. By Zsombor Egri

prereq sync

1298. By Zsombor Egri

adjusting code to prereq changes

1299. By Zsombor Egri

prereq sync

1300. By Zsombor Egri

staging in test fixing

1301. By Zsombor Egri

prereq sync

1302. By Zsombor Egri

prereq sync

1303. By Zsombor Egri

test fix

1304. By Zsombor Egri

fixing tests to comply with prereq changes

1305. By Zsombor Egri

prereq sync

1306. By Zsombor Egri

prereq sync

1307. By Zsombor Egri

method name fixed

1308. By Zsombor Egri

prereq sync

1309. By Zsombor Egri

prereq sync

1310. By Zsombor Egri

prereq sync

Revision history for this message
Tim Peeters (tpeeters) wrote :

I don't see icons with this code: http://pastebin.ubuntu.com/9145869/

Revision history for this message
Tim Peeters (tpeeters) wrote :

with the code above, the list item text never becomes red, so swiping never becomes true?

Revision history for this message
Tim Peeters (tpeeters) wrote :

66 + // for testing
67 + objectName: "ListItemPanel" + (leadingPanel ? "Leading" : "Trailing")

That might appear like you left some debugging code that should not be in the final version.

Change the comment to // Used for autopilot testing in filename.py?
or something similar.

Revision history for this message
Tim Peeters (tpeeters) wrote :

74 + Specifies whether the panel is used to visualize leading or trailing options.
75 + */
76 + readonly property bool leadingPanel: panel.ListItemActions.status == panel.ListItemActions.Leading

I prefer readonly property bool leading.
We know we are a panel.

Revision history for this message
Zsombor Egri (zsombi) wrote :

> 66 + // for testing
> 67 + objectName: "ListItemPanel" + (leadingPanel ? "Leading" :
> "Trailing")
>
> That might appear like you left some debugging code that should not be in the
> final version.
>
> Change the comment to // Used for autopilot testing in filename.py?
> or something similar.

It is used in module testing.

Revision history for this message
Tim Peeters (tpeeters) wrote :

321 + , xAxisMoveThresholdGU(1.5)
322 , overshoot(UCUnits::instance().gu(2))

let's do the x-axis threshold like the overshoot, so:
xAxisMoveThreshold(UCUnits::instance().gu(1.5))

Revision history for this message
Tim Peeters (tpeeters) wrote :

372 + if (!UCListItemActionsPrivate::isConnectedTo(leadingActions, q) && !UCListItemActionsPrivate::isConnectedTo(trailingActions, q)) {

add a linebreak

Revision history for this message
Tim Peeters (tpeeters) wrote :

383 + * animations. The component does not assume any visuals present in the style,
384 + * and will load its content only when requested, i.e. either of the mentioned
385 + * components are visualized.

the part from i.e. is a bit unclear to me. What do you try to say there?

Revision history for this message
Tim Peeters (tpeeters) wrote :

458 + setTugged(false);

didn't we switch from "tug" to "swipe" in a previous MR?

Revision history for this message
Tim Peeters (tpeeters) wrote :

should we include a link to ListItemStyle in the ListItem docs?

Revision history for this message
Tim Peeters (tpeeters) wrote :

Can we improve this text?

> The component defines the style API for the ListItem component.
> Provides the default actions visualization panel, snap animation,
> selection mode and drag handler delegates. ListItem treats the
> style differently compared to the other components, as it will
> load it only when needed, to load the components defining the
> look and feel of the different configurable elements of the component,
> and will ignore any visuals declared in the style.

Style API for the ListItem component which provides actions, select and
drag handler delegates, and snap animation via its properties.
ListItem treats the style differently compared to the other components,
as it:
- loads the style only when needed
- gets delegates and snap animation from the style properties
- ignores any other visuals defined in the style

Revision history for this message
Tim Peeters (tpeeters) wrote :

replace "tug" by "swipe" everywhere?

Revision history for this message
Tim Peeters (tpeeters) wrote :

Remove this completely?
I understand the example, but I think it is bad practice to show the same action on both sides, so we should not include it as a code example.

 If
568 + * it is desired to have the same action present in both leading and trailing
569 + * actions, one of the ListItemActions actions list can use the other's list. In
570 + * the following example the list item can be deleted through both leading and
571 + * trailing actions:
572 + * \qml
573 + * ListItem {
574 + * id: listItem
575 + * leadingActions: ListItemActions {
576 + * actions: [
577 + * Action {
578 + * iconName: "delete"
579 + * onTriggered: listItem.destroy()
580 + * }
581 + * ]
582 + * }
583 + * trailingActions: ListItemActions {
584 + * actions: leadingActions.actions
585 + * }
586 + * }

Revision history for this message
Tim Peeters (tpeeters) wrote :

1478 === added file 'tests/unit/tst_performance/ListItemWithInlineOptionsList.qml'

filename options-->actions

Revision history for this message
Zsombor Egri (zsombi) wrote :

> with the code above, the list item text never becomes red, so swiping never
> becomes true?

First, ListItem attached properties are only valid when attached to their parent, or if used in ListView, then attached to ListView, or when used in Flickables, attached to Flickables.

Second, swiping is not defined for ListItem, but for ListItemAttached. Now that property is valid only for leadin/trailing panels.

It is unfortunate that you can attach the property to any object, but this is something we cannot change. The same happens with ListView attached properties, it doesn't give you any warning/error (as it cannot) if attached to other elements but the ListView's delegate, but only works with the delegate.

Revision history for this message
Zsombor Egri (zsombi) wrote :

> 321 + , xAxisMoveThresholdGU(1.5)
> 322 , overshoot(UCUnits::instance().gu(2))
>
> let's do the x-axis threshold like the overshoot, so:
> xAxisMoveThreshold(UCUnits::instance().gu(1.5))

No, I would not. Especially that this is not configurable. If we decide to make it configurable, we can do it later. Yet, there's no reason to watch the units change to update this property, as we need the threshold only when swiping. And if we don't configure it, we can always get the proper pixel amount by converting in place.

Revision history for this message
Zsombor Egri (zsombi) wrote :

> 383 + * animations. The component does not assume any visuals present in
> the style,
> 384 + * and will load its content only when requested, i.e. either of the
> mentioned
> 385 + * components are visualized.
>
> the part from i.e. is a bit unclear to me. What do you try to say there?

Perhaps that si not even needed... Will remove it.

Revision history for this message
Zsombor Egri (zsombi) wrote :

> 458 + setTugged(false);
>
> didn't we switch from "tug" to "swipe" in a previous MR?

The concept yes, but this staid... I'll change it to swipe

Revision history for this message
Zsombor Egri (zsombi) wrote :

> should we include a link to ListItemStyle in the ListItem docs?

Yep. Added.

Revision history for this message
Zsombor Egri (zsombi) wrote :

> Can we improve this text?
>
> > The component defines the style API for the ListItem component.
> > Provides the default actions visualization panel, snap animation,
> > selection mode and drag handler delegates. ListItem treats the
> > style differently compared to the other components, as it will
> > load it only when needed, to load the components defining the
> > look and feel of the different configurable elements of the component,
> > and will ignore any visuals declared in the style.
>
> Style API for the ListItem component which provides actions, select and
> drag handler delegates, and snap animation via its properties.
> ListItem treats the style differently compared to the other components,
> as it:
> - loads the style only when needed
> - gets delegates and snap animation from the style properties
> - ignores any other visuals defined in the style

Done.

Revision history for this message
Zsombor Egri (zsombi) wrote :

> replace "tug" by "swipe" everywhere?

No. We agreed with design that they call it tug, so we will, at least in the doc.

Revision history for this message
Zsombor Egri (zsombi) wrote :

> Remove this completely?
> I understand the example, but I think it is bad practice to show the same
> action on both sides, so we should not include it as a code example.
>
>
> If
> 568 + * it is desired to have the same action present in both leading and
> trailing
> 569 + * actions, one of the ListItemActions actions list can use the
> other's list. In
> 570 + * the following example the list item can be deleted through both
> leading and
> 571 + * trailing actions:
> 572 + * \qml
> 573 + * ListItem {
> 574 + * id: listItem
> 575 + * leadingActions: ListItemActions {
> 576 + * actions: [
> 577 + * Action {
> 578 + * iconName: "delete"
> 579 + * onTriggered: listItem.destroy()
> 580 + * }
> 581 + * ]
> 582 + * }
> 583 + * trailingActions: ListItemActions {
> 584 + * actions: leadingActions.actions
> 585 + * }
> 586 + * }

Why not? this is a practice some apps may apply. So why shouldn't we have it documented on how to do it? This way we can be sure we won't spend useless time by triaging these kind of bugs...

1311. By Zsombor Egri

review comments applied

Revision history for this message
Tim Peeters (tpeeters) wrote :

okay, thanks

review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file 'components.api'
--- components.api 2014-11-21 14:40:26 +0000
+++ components.api 2014-11-21 14:40:28 +0000
@@ -876,6 +876,8 @@
876 Property { name: "highlightColor"; type: "QColor" }876 Property { name: "highlightColor"; type: "QColor" }
877 Property { name: "data"; type: "QObject"; isList: true; isReadonly: true }877 Property { name: "data"; type: "QObject"; isList: true; isReadonly: true }
878 Property { name: "children"; type: "QQuickItem"; isList: true; isReadonly: true }878 Property { name: "children"; type: "QQuickItem"; isList: true; isReadonly: true }
879 Property { name: "style"; type: "QQmlComponent"; isPointer: true }
880 Property { name: "__styleInstance"; type: "QQuickItem"; isReadonly: true; isPointer: true }
879 Signal { name: "clicked" }881 Signal { name: "clicked" }
880 Signal { name: "contentMovementStarted" }882 Signal { name: "contentMovementStarted" }
881 Signal { name: "contentMovementEnded" }883 Signal { name: "contentMovementEnded" }
@@ -910,6 +912,13 @@
910 Property { name: "rightMargin"; type: "double" }912 Property { name: "rightMargin"; type: "double" }
911 Property { name: "colorFrom"; type: "QColor" }913 Property { name: "colorFrom"; type: "QColor" }
912 Property { name: "colorTo"; type: "QColor" }914 Property { name: "colorTo"; type: "QColor" }
915 name: "UCListItemStyle"
916 prototype: "QQuickItem"
917 exports: ["Ubuntu.Components.Styles/ListItemStyle 1.2"]
918 Property { name: "actionsDelegate"; type: "QQmlComponent"; isPointer: true }
919 Property { name: "selectionDelegate"; type: "QQmlComponent"; isPointer: true }
920 Property { name: "dragHandlerDelegate"; type: "QQmlComponent"; isPointer: true }
921 Property { name: "snapAnimation"; type: "QQuickPropertyAnimation"; isPointer: true }
913 name: "UCMouse"922 name: "UCMouse"
914 prototype: "QObject"923 prototype: "QObject"
915 exports: ["Mouse 0.1", "Mouse 1.0"]924 exports: ["Mouse 0.1", "Mouse 1.0"]
916925
=== added file 'modules/Ubuntu/Components/Themes/Ambiance/ListItemPanel.qml'
--- modules/Ubuntu/Components/Themes/Ambiance/ListItemPanel.qml 1970-01-01 00:00:00 +0000
+++ modules/Ubuntu/Components/Themes/Ambiance/ListItemPanel.qml 2014-11-21 14:40:28 +0000
@@ -0,0 +1,64 @@
1/*
2 * Copyright 2014 Canonical Ltd.
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU Lesser General Public License as published by
6 * the Free Software Foundation; version 3.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU Lesser General Public License for more details.
12 *
13 * You should have received a copy of the GNU Lesser General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 */
16
17import QtQuick 2.2
18import Ubuntu.Components 1.2
19
20/*
21 This component is the holder of the ListItem options.
22 */
23Item {
24 id: panel
25
26 // styling properties
27 /*
28 Color of teh background.
29 */
30 // FIXME: use Palette colors instead when available
31 property color backgroundColor: (leading ? UbuntuColors.red : "white")
32
33 width: units.gu(20)
34
35 // used for module/autopilot testing
36 objectName: "ListItemPanel" + (leading ? "Leading" : "Trailing")
37
38 /*
39 Property holding the ListItem's contentItem instance
40 */
41 readonly property Item contentItem: parent ? parent.contentItem : null
42 /*
43 Specifies whether the panel is used to visualize leading or trailing options.
44 */
45 readonly property bool leading: panel.ListItemActions.status == panel.ListItemActions.Leading
46
47 anchors {
48 left: contentItem ? (leading ? undefined : contentItem.right) : undefined
49 right: contentItem ? (leading ? contentItem.left : undefined) : undefined
50 top: contentItem ? contentItem.top : undefined
51 bottom: contentItem ? contentItem.bottom : undefined
52 }
53
54 Rectangle {
55 objectName: "panel_background"
56 anchors {
57 fill: parent
58 // add 4 times the overshoot margins to cover the background when tugged
59 leftMargin: leading ? -units.gu(4 * panel.ListItemActions.overshoot) : 0
60 rightMargin: leading ? 0 : -units.gu(4 * panel.ListItemActions.overshoot)
61 }
62 color: panel.backgroundColor
63 }
64}
065
=== added file 'modules/Ubuntu/Components/Themes/Ambiance/ListItemStyle.qml'
--- modules/Ubuntu/Components/Themes/Ambiance/ListItemStyle.qml 1970-01-01 00:00:00 +0000
+++ modules/Ubuntu/Components/Themes/Ambiance/ListItemStyle.qml 2014-11-21 14:40:28 +0000
@@ -0,0 +1,34 @@
1import QtQuick 2.3
2import Ubuntu.Components.Styles 1.2 as Styles
3import Ubuntu.Components 1.2
4/*
5 * Copyright 2014 Canonical Ltd.
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU Lesser General Public License as published by
9 * the Free Software Foundation; version 3.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU Lesser General Public License for more details.
15 *
16 * You should have received a copy of the GNU Lesser General Public License
17 * along with this program. If not, see <http://www.gnu.org/licenses/>.
18 */
19
20Styles.ListItemStyle {
21
22 actionsDelegate: ListItemPanel{}
23
24 snapAnimation: PropertyAnimation {
25 property: "x"
26 easing {
27 type: Easing.OutElastic
28 period: 0.5
29 }
30 duration: UbuntuAnimation.BriskDuration
31 alwaysRunToEnd: true
32 }
33
34}
035
=== modified file 'modules/Ubuntu/Components/Themes/Ambiance/qmldir'
--- modules/Ubuntu/Components/Themes/Ambiance/qmldir 2014-11-10 17:08:05 +0000
+++ modules/Ubuntu/Components/Themes/Ambiance/qmldir 2014-11-21 14:40:28 +0000
@@ -55,3 +55,7 @@
55internal OverflowPanel OverflowPanel.qml55internal OverflowPanel OverflowPanel.qml
56internal HeadSeparatorImageStyle HeadSeparatorImageStyle.qml56internal HeadSeparatorImageStyle HeadSeparatorImageStyle.qml
57internal HeadDividerStyle HeadDividerStyle.qml57internal HeadDividerStyle HeadDividerStyle.qml
58
59#version 1.2
60ListItemPanel 1.2 ListItemPanel.qml
61ListItemStyle 1.2 ListItemStyle.qml
5862
=== modified file 'modules/Ubuntu/Components/plugin/plugin.cpp'
--- modules/Ubuntu/Components/plugin/plugin.cpp 2014-11-21 14:40:26 +0000
+++ modules/Ubuntu/Components/plugin/plugin.cpp 2014-11-21 14:40:28 +0000
@@ -55,6 +55,7 @@
55#include "uclistitem.h"55#include "uclistitem.h"
56#include "uclistitem_p.h"56#include "uclistitem_p.h"
57#include "uclistitemactions.h"57#include "uclistitemactions.h"
58#include "uclistitemstyle.h"
5859
59#include <sys/types.h>60#include <sys/types.h>
60#include <unistd.h>61#include <unistd.h>
@@ -176,6 +177,10 @@
176 // initialize baseURL177 // initialize baseURL
177 m_baseUrl = QUrl(baseUrl().toString() + '/');178 m_baseUrl = QUrl(baseUrl().toString() + '/');
178179
180 // register internal styles
181 const char *styleUri = "Ubuntu.Components.Styles";
182 qmlRegisterType<UCListItemStyle, 2>(styleUri, 1, 2, "ListItemStyle");
183
179 QQmlExtensionPlugin::initializeEngine(engine, uri);184 QQmlExtensionPlugin::initializeEngine(engine, uri);
180 QQmlContext* context = engine->rootContext();185 QQmlContext* context = engine->rootContext();
181186
182187
=== modified file 'modules/Ubuntu/Components/plugin/plugin.pro'
--- modules/Ubuntu/Components/plugin/plugin.pro 2014-11-21 14:40:26 +0000
+++ modules/Ubuntu/Components/plugin/plugin.pro 2014-11-21 14:40:28 +0000
@@ -73,7 +73,8 @@
73 uclistitem_p.h \73 uclistitem_p.h \
74 uclistitemactions.h \74 uclistitemactions.h \
75 uclistitemactions_p.h \75 uclistitemactions_p.h \
76 propertychange_p.h76 propertychange_p.h \
77 uclistitemstyle.h
7778
78SOURCES += plugin.cpp \79SOURCES += plugin.cpp \
79 uctheme.cpp \80 uctheme.cpp \
@@ -115,7 +116,8 @@
115 uclistitemactions.cpp \116 uclistitemactions.cpp \
116 uclistitemactionsattached.cpp \117 uclistitemactionsattached.cpp \
117 uclistitemattached.cpp \118 uclistitemattached.cpp \
118 propertychange_p.cpp119 propertychange_p.cpp \
120 uclistitemstyle.cpp
119121
120# adapters122# adapters
121SOURCES += adapters/alarmsadapter_organizer.cpp123SOURCES += adapters/alarmsadapter_organizer.cpp
122124
=== modified file 'modules/Ubuntu/Components/plugin/uclistitem.cpp'
--- modules/Ubuntu/Components/plugin/uclistitem.cpp 2014-11-21 14:40:26 +0000
+++ modules/Ubuntu/Components/plugin/uclistitem.cpp 2014-11-21 14:40:28 +0000
@@ -18,12 +18,20 @@
18#include "uctheme.h"18#include "uctheme.h"
19#include "uclistitem.h"19#include "uclistitem.h"
20#include "uclistitem_p.h"20#include "uclistitem_p.h"
21#include "uclistitemactions.h"
22#include "uclistitemactions_p.h"
23#include "ucubuntuanimation.h"
24#include "propertychange_p.h"
21#include <QtQml/QQmlInfo>25#include <QtQml/QQmlInfo>
22#include <QtQuick/private/qquickitem_p.h>26#include <QtQuick/private/qquickitem_p.h>
23#include <QtQuick/private/qquickflickable_p.h>27#include <QtQuick/private/qquickflickable_p.h>
24#include <QtQuick/private/qquickpositioners_p.h>28#include <QtQuick/private/qquickpositioners_p.h>
25#include <QtQuick/private/qquickanimation_p.h>29#include <QtQuick/private/qquickanimation_p.h>
26#include "ucubuntuanimation.h"30#include "uclistitemstyle.h"
31
32#define MIN(x, y) ((x < y) ? x : y)
33#define MAX(x, y) ((x > y) ? x : y)
34#define CLAMP(v, min, max) (min <= max) ? MAX(min, MIN(v, max)) : MAX(max, MIN(v, min))
2735
28QColor getPaletteColor(const char *profile, const char *color)36QColor getPaletteColor(const char *profile, const char *color)
29{37{
@@ -90,8 +98,7 @@
90 snap->setFrom(listItem->contentItem->property(snap->property().toLocal8Bit().constData()));98 snap->setFrom(listItem->contentItem->property(snap->property().toLocal8Bit().constData()));
91 snap->setTo(to);99 snap->setTo(to);
92 snap->setAlwaysRunToEnd(true);100 snap->setAlwaysRunToEnd(true);
93 // FIXME - this will be used later101 listItem->setContentMoving(true);
94// listItem->setContentMoved(true);
95 snap->start();102 snap->start();
96 return true;103 return true;
97}104}
@@ -127,11 +134,11 @@
127 // no need to listen flickables any longer134 // no need to listen flickables any longer
128 listItem->attachedProperties->listenToRebind(item, false);135 listItem->attachedProperties->listenToRebind(item, false);
129 }136 }
130 // disconnect actions - FIXME this will be used later137 // disconnect actions
131// listItem->grabPanel(listItem->leadingActions, false);138 listItem->grabPanel(listItem->leadingActions, false);
132// listItem->grabPanel(listItem->trailingActions, false);139 listItem->grabPanel(listItem->trailingActions, false);
133 // set contentMoving to false - FIXME used later140 // set contentMoved to false
134// listItem->setContentMoving(false);141 listItem->setContentMoving(false);
135}142}
136143
137/*144/*
@@ -145,9 +152,9 @@
145 QQuickAbstractAnimation *snap = getDefaultAnimation();152 QQuickAbstractAnimation *snap = getDefaultAnimation();
146 QObject::disconnect(snap, 0, 0, 0);153 QObject::disconnect(snap, 0, 0, 0);
147 }154 }
148 // turn content moving off - FIXME used later155 // turn content moving off
149// UCListItemPrivate *listItem = UCListItemPrivate::get(item);156 UCListItemPrivate *listItem = UCListItemPrivate::get(item);
150// listItem->setContentMoving(false);157 listItem->setContentMoving(false);
151}158}
152159
153/*160/*
@@ -155,8 +162,11 @@
155 */162 */
156QQuickPropertyAnimation *UCListItemSnapAnimator::getDefaultAnimation()163QQuickPropertyAnimation *UCListItemSnapAnimator::getDefaultAnimation()
157{164{
158 // FIXME - return the animation from the style165 UCListItemPrivate *listItem = UCListItemPrivate::get(item);
159 return 0;166 if (!listItem->styleItem && listItem->loadStyle()) {
167 listItem->initStyleItem();
168 }
169 return listItem->styleItem ? listItem->styleItem->m_snapAnimation : 0;
160}170}
161171
162/******************************************************************************172/******************************************************************************
@@ -236,22 +246,23 @@
236 }246 }
237}247}
238248
239QSGNode *UCListItemDivider::paint(const QRectF &rect)249QSGNode *UCListItemDivider::paint(QSGNode *node, const QRectF &rect)
240{250{
241 if (m_visible && (m_gradient.size() > 0)) {251 QSGRectangleNode *dividerNode = static_cast<QSGRectangleNode*>(node);
242 // the parent always recreates the node, so no worries for the existing child node252 if (m_visible && (m_gradient.size() > 0) && ((m_colorFrom.alphaF() >= (1.0f / 255.0f)) || (m_colorTo.alphaF() >= (1.0f / 255.0f)))) {
243 QSGRectangleNode *rectNode = m_listItem->sceneGraphContext()->createRectangleNode();253 if (!dividerNode) {
244 // margins are only applied when the ListItem is in normal state, when pressed,254 dividerNode = m_listItem->sceneGraphContext()->createRectangleNode();
245 // the divider is painted from edge to edge255 }
246 qreal left = (m_listItem && m_listItem->pressed) ? 0 : m_leftMargin;256 QRectF divider(m_leftMargin, rect.height() - m_thickness, rect.width() - m_leftMargin - m_rightMargin, m_thickness);
247 qreal right = (m_listItem && m_listItem->pressed) ? rect.width() : rect.width() - m_leftMargin - m_rightMargin;257 dividerNode->setRect(divider);
248 rectNode->setRect(QRectF(left, rect.height() - m_thickness, right, m_thickness));258 dividerNode->setGradientStops(m_gradient);
249 rectNode->setGradientStops(m_gradient);259 dividerNode->update();
250 rectNode->update();260 return dividerNode;
251 return rectNode;261 } else if (node) {
252 } else {262 // delete the node
253 return 0;263 delete node;
254 }264 }
265 return 0;
255}266}
256267
257void UCListItemDivider::setVisible(bool visible)268void UCListItemDivider::setVisible(bool visible)
@@ -317,7 +328,12 @@
317 , pressed(false)328 , pressed(false)
318 , contentMoved(false)329 , contentMoved(false)
319 , highlightColorChanged(false)330 , highlightColorChanged(false)
331 , swiped(false)
332 , suppressClick(false)
320 , ready(false)333 , ready(false)
334 , customStyle(false)
335 , customColor(false)
336 , xAxisMoveThresholdGU(1.5)
321 , overshoot(UCUnits::instance().gu(2))337 , overshoot(UCUnits::instance().gu(2))
322 , color(Qt::transparent)338 , color(Qt::transparent)
323 , highlightColor(Qt::transparent)339 , highlightColor(Qt::transparent)
@@ -327,6 +343,8 @@
327 , leadingActions(0)343 , leadingActions(0)
328 , trailingActions(0)344 , trailingActions(0)
329 , animator(0)345 , animator(0)
346 , styleComponent(0)
347 , styleItem(0)
330{348{
331}349}
332UCListItemPrivate::~UCListItemPrivate()350UCListItemPrivate::~UCListItemPrivate()
@@ -348,33 +366,122 @@
348 // turn activeFocusOnPress on366 // turn activeFocusOnPress on
349 q->setActiveFocusOnPress(true);367 q->setActiveFocusOnPress(true);
350368
351 // catch theme palette changes369 // catch theme changes
352 QObject::connect(&UCTheme::instance(), SIGNAL(paletteChanged()), q, SLOT(_q_updateColors()));370 QObject::connect(&UCTheme::instance(), SIGNAL(nameChanged()), q, SLOT(_q_updateThemedData()));
353 _q_updateColors();371 _q_updateThemedData();
354372
355 // watch size change and set implicit size;373 // watch size change and set implicit size;
356 QObject::connect(&UCUnits::instance(), SIGNAL(gridUnitChanged()), q, SLOT(_q_updateSize()));374 QObject::connect(&UCUnits::instance(), SIGNAL(gridUnitChanged()), q, SLOT(_q_updateSize()));
357 _q_updateSize();375 _q_updateSize();
358}376}
359377
360void UCListItemPrivate::_q_updateColors()378void UCListItemPrivate::_q_updateThemedData()
361{379{
362 Q_Q(UCListItem);380 // update colors, panels
363 highlightColor = getPaletteColor("selected", "background");381 if (!customColor) {
364 q->update();382 Q_Q(UCListItem);
383 highlightColor = getPaletteColor("selected", "background");
384 q->update();
385 }
386 loadStyle();
365}387}
366388
367void UCListItemPrivate::_q_rebound()389void UCListItemPrivate::_q_rebound()
368{390{
369 setPressed(false);391 setPressed(false);
370 // disconnect the flickable392 // initiate rebinding only if there were actions tugged
371 listenToRebind(false);393 Q_Q(UCListItem);
394 if (!UCListItemActionsPrivate::isConnectedTo(leadingActions, q) &&
395 !UCListItemActionsPrivate::isConnectedTo(trailingActions, q)) {
396 return;
397 }
398 setSwiped(false);
399 // rebound to zero
400 animator->snap(0);
401}
402/*!
403 * \qmlproperty Component ListItem::style
404 * Holds the style of the component defining the components visualizing the leading/
405 * trailing actions, selection and dragging mode handlers as well as different
406 * animations. The component does not assume any visuals present in the style,
407 * and will load its content only when requested.
408 * \sa ListItemStyle
409 */
410QQmlComponent *UCListItemPrivate::style() const
411{
412 return styleComponent;
413}
414void UCListItemPrivate::setStyle(QQmlComponent *delegate)
415{
416 if (styleComponent == delegate) {
417 return;
418 }
419 Q_Q(UCListItem);
420 // make sure we're rebound before we change the panel component
421 promptRebound();
422 if (styleItem) {
423 delete styleItem;
424 styleItem = 0;
425 Q_EMIT q->__styleInstanceChanged();
426 }
427 delete styleComponent;
428 customStyle = (delegate == 0);
429 styleComponent = delegate;
430 loadStyle();
431 Q_EMIT q->styleChanged();
432}
433
434// update themed components
435bool UCListItemPrivate::loadStyle()
436{
437 if (!ready) {
438 return false;
439 }
440 if (!customStyle && !styleComponent) {
441 Q_Q(UCListItem);
442 if (styleItem) {
443 delete styleItem;
444 styleItem = 0;
445 Q_EMIT q->__styleInstanceChanged();
446 }
447 delete styleComponent;
448 styleComponent = UCTheme::instance().createStyleComponent("ListItemStyle.qml", q);
449 }
450 return (styleComponent != NULL);
451}
452// creates the style item
453void UCListItemPrivate::initStyleItem()
454{
455 if (!styleComponent || styleItem) {
456 return;
457 }
458 Q_Q(UCListItem);
459 QObject *object = styleComponent->beginCreate(qmlContext(q));
460 styleItem = qobject_cast<UCListItemStyle*>(object);
461 if (!styleItem) {
462 delete object;
463 }
464 QQml_setParent_noEvent(styleItem, q);
465 styleComponent->completeCreate();
466}
467
468/*!
469 * \qmlproperty Item ListItem::__styleInstance
470 * \internal
471 */
472QQuickItem *UCListItemPrivate::styleInstance() const
473{
474 return styleItem;
372}475}
373476
374// rebound without animation477// rebound without animation
375void UCListItemPrivate::promptRebound()478void UCListItemPrivate::promptRebound()
376{479{
377 setPressed(false);480 setPressed(false);
481 setSwiped(false);
482 if (animator) {
483 animator->snapOut();
484 }
378}485}
379486
380// called when units size changes487// called when units size changes
@@ -406,11 +513,45 @@
406{513{
407 if (this->pressed != pressed) {514 if (this->pressed != pressed) {
408 this->pressed = pressed;515 this->pressed = pressed;
516 suppressClick = false;
409 Q_Q(UCListItem);517 Q_Q(UCListItem);
410 q->update();518 q->update();
411 Q_EMIT q->pressedChanged();519 Q_EMIT q->pressedChanged();
412 }520 }
413}521}
522// toggles the tugged flag and installs/removes event filter
523void UCListItemPrivate::setSwiped(bool swiped)
524{
525 suppressClick = swiped;
526 if (this->swiped == swiped) {
527 return;
528 }
529 this->swiped = swiped;
530 Q_Q(UCListItem);
531 QQuickWindow *window = q->window();
532 if (swiped) {
533 window->installEventFilter(q);
534 } else {
535 window->removeEventFilter(q);
536 }
537}
538
539// grabs the panels from the leading/trailing actions and disables all ascending flickables
540bool UCListItemPrivate::grabPanel(UCListItemActions *actionsList, bool isTugged)
541{
542 Q_Q(UCListItem);
543 if (isTugged) {
544 bool grab = UCListItemActionsPrivate::connectToListItem(actionsList, q, (actionsList == leadingActions));
545 if (attachedProperties) {
546 attachedProperties->disableInteractive(q, true);
547 }
548 return grab;
549 } else {
550 UCListItemActionsPrivate::disconnectFromListItem(actionsList);
551 return false;
552 }
553}
554
414555
415// connects/disconnects from the Flickable anchestor to get notified when to do rebound556// connects/disconnects from the Flickable anchestor to get notified when to do rebound
416void UCListItemPrivate::listenToRebind(bool listen)557void UCListItemPrivate::listenToRebind(bool listen)
@@ -440,6 +581,19 @@
440 q->update();581 q->update();
441}582}
442583
584// clamps the X value and moves the contentItem to the new X value
585void UCListItemPrivate::clampAndMoveX(qreal &x, qreal dx)
586{
587 UCListItemActionsPrivate *leading = UCListItemActionsPrivate::get(leadingActions);
588 UCListItemActionsPrivate *trailing = UCListItemActionsPrivate::get(trailingActions);
589 x += dx;
590 // min cannot be less than the trailing's panel width
591 qreal min = (trailing && trailing->panelItem) ? -trailing->panelItem->width() : 0;
592 // max cannot be bigger than 0 or the leading's width in case we have leading panel
593 qreal max = (leading && leading->panelItem) ? leading->panelItem->width() : 0;
594 x = CLAMP(x, min, max);
595}
596
443/*!597/*!
444 * \qmltype ListItem598 * \qmltype ListItem
445 * \instantiates UCListItem599 * \instantiates UCListItem
@@ -466,6 +620,62 @@
466 * Each ListItem has a thin divider shown on the bottom of the component. This620 * Each ListItem has a thin divider shown on the bottom of the component. This
467 * divider can be configured through the \c divider grouped property, which can621 * divider can be configured through the \c divider grouped property, which can
468 * configure its margins from the edges of the ListItem as well as its visibility.622 * configure its margins from the edges of the ListItem as well as its visibility.
623 *
624 * ListItem can handle actions that can get tugged from front to back of the item.
625 * These actions are Action elements visualized in panels attached to the front
626 * or to the back of the item, and are revealed by swiping the item horizontally.
627 * The tug is started only after the mouse/touch move had passed a given threshold.
628 * These actions are configured through the \l leadingActions as well as \l
629 * trailingActions properties.
630 * \qml
631 * ListItem {
632 * id: listItem
633 * leadingActions: ListItemActions {
634 * actions: [
635 * Action {
636 * iconName: "delete"
637 * onTriggered: listItem.destroy()
638 * }
639 * ]
640 * }
641 * trailingActions: ListItemActions {
642 * actions: [
643 * Action {
644 * iconName: "search"
645 * onTriggered: {
646 * // do some search
647 * }
648 * }
649 * ]
650 * }
651 * }
652 * \endqml
653 * \note When a list item is tugged, it automatically connects both leading and
654 * trailing actions to the list item. This implies that a ListItem cannot use
655 * the same ListItemActions instance for both leading and trailing actions. If
656 * it is desired to have the same action present in both leading and trailing
657 * actions, one of the ListItemActions actions list can use the other's list. In
658 * the following example the list item can be deleted through both leading and
659 * trailing actions:
660 * \qml
661 * ListItem {
662 * id: listItem
663 * leadingActions: ListItemActions {
664 * actions: [
665 * Action {
666 * iconName: "delete"
667 * onTriggered: listItem.destroy()
668 * }
669 * ]
670 * }
671 * trailingActions: ListItemActions {
672 * actions: leadingActions.actions
673 * }
674 * }
675 * \endqml
676 * \sa ListItemActions
677 *
678 * The component is styled using the \l ListItemStyle style interface.
469 */679 */
470680
471/*!681/*!
@@ -494,6 +704,8 @@
494void UCListItem::componentComplete()704void UCListItem::componentComplete()
495{705{
496 UCStyledItemBase::componentComplete();706 UCStyledItemBase::componentComplete();
707 // must load the theme!
708 Q_D(UCListItem);
497 d_func()->ready = true;709 d_func()->ready = true;
498}710}
499711
@@ -515,6 +727,7 @@
515727
516 // attach ListItem properties to the flickable or to the parent item728 // attach ListItem properties to the flickable or to the parent item
517 if (d->flickable) {729 if (d->flickable) {
730 // connect to flickable to get width changes
518 d->attachedProperties = static_cast<UCListItemAttached*>(qmlAttachedPropertiesObject<UCListItem>(d->flickable));731 d->attachedProperties = static_cast<UCListItemAttached*>(qmlAttachedPropertiesObject<UCListItem>(d->flickable));
519 } else if (data.item) {732 } else if (data.item) {
520 d->attachedProperties = static_cast<UCListItemAttached*>(qmlAttachedPropertiesObject<UCListItem>(data.item));733 d->attachedProperties = static_cast<UCListItemAttached*>(qmlAttachedPropertiesObject<UCListItem>(data.item));
@@ -535,7 +748,7 @@
535void UCListItem::geometryChanged(const QRectF &newGeometry, const QRectF &oldGeometry)748void UCListItem::geometryChanged(const QRectF &newGeometry, const QRectF &oldGeometry)
536{749{
537 UCStyledItemBase::geometryChanged(newGeometry, oldGeometry);750 UCStyledItemBase::geometryChanged(newGeometry, oldGeometry);
538 // resize background item751 // resize contentItem item
539 Q_D(UCListItem);752 Q_D(UCListItem);
540 d->resize();753 d->resize();
541}754}
@@ -547,27 +760,47 @@
547 Q_D(UCListItem);760 Q_D(UCListItem);
548 QColor color = d->pressed ? d->highlightColor : d->color;761 QColor color = d->pressed ? d->highlightColor : d->color;
549762
550 delete oldNode;
551 if (width() <= 0 || height() <= 0) {763 if (width() <= 0 || height() <= 0) {
764 delete oldNode;
552 return 0;765 return 0;
553 }766 }
554767
555 QSGRectangleNode *rectNode = 0;768 QSGRectangleNode *rectNode = 0;
556 if (color.alpha() > 0) {769 rectNode = static_cast<QSGRectangleNode*>(oldNode);
770 if (!rectNode) {
557 rectNode = QQuickItemPrivate::get(this)->sceneGraphContext()->createRectangleNode();771 rectNode = QQuickItemPrivate::get(this)->sceneGraphContext()->createRectangleNode();
772 }
773 if (color.alphaF() >= (1.0f / 255.0f)) {
558 rectNode->setColor(color);774 rectNode->setColor(color);
559 // cover only the area of the contentItem775 // cover only the area of the contentItem
560 rectNode->setRect(d->contentItem->boundingRect());776 rectNode->setRect(d->contentItem->boundingRect());
777 rectNode->setGradientStops(QGradientStops());
778 rectNode->setAntialiasing(true);
779 rectNode->setAntialiasing(false);
561 rectNode->update();780 rectNode->update();
781 } else {
782 // delete node, this will delete the divider node as well
783 delete rectNode;
784 rectNode = 0;
562 }785 }
563 oldNode = rectNode;786 oldNode = rectNode;
787 QSGNode *dividerNode = oldNode ? oldNode->childAtIndex(0) : 0;
564 if (d->divider && d->divider->m_visible) {788 if (d->divider && d->divider->m_visible) {
565 QSGNode * dividerNode = d->divider->paint(boundingRect());789 QSGNode *newNode = d->divider->paint(dividerNode, boundingRect());
566 if (dividerNode && oldNode) {790 if (newNode != dividerNode && oldNode) {
567 oldNode->appendChildNode(dividerNode);791 if (dividerNode) {
568 } else if (dividerNode) {792 oldNode->removeChildNode(dividerNode);
569 oldNode = dividerNode;793 }
570 }794 if (newNode) {
795 oldNode->appendChildNode(newNode);
796 }
797 }
798 if (!oldNode) {
799 oldNode = newNode;
800 }
801 } else if (dividerNode) {
802 // the divider painter node may be still added as child, so remove it
803 oldNode->removeChildNode(dividerNode);
571 }804 }
572 return oldNode;805 return oldNode;
573}806}
@@ -582,8 +815,14 @@
582 }815 }
583 if (event->button() == Qt::LeftButton) {816 if (event->button() == Qt::LeftButton) {
584 d->setPressed(true);817 d->setPressed(true);
818 d->lastPos = d->pressedPos = event->localPos();
585 // connect the Flickable to know when to rebound819 // connect the Flickable to know when to rebound
586 d->listenToRebind(true);820 d->listenToRebind(true);
821 // if it was moved, grab the panels
822 if (d->swiped) {
823 d->grabPanel(d->leadingActions, true);
824 d->grabPanel(d->trailingActions, true);
825 }
587 }826 }
588 // accept the event so we get the rest of the events as well827 // accept the event so we get the rest of the events as well
589 event->setAccepted(true);828 event->setAccepted(true);
@@ -596,11 +835,113 @@
596 // set released835 // set released
597 if (d->pressed) {836 if (d->pressed) {
598 d->listenToRebind(false);837 d->listenToRebind(false);
599 Q_EMIT clicked();838 if (d->attachedProperties) {
839 d->attachedProperties->disableInteractive(this, false);
840 }
841
842 if (!d->suppressClick) {
843 Q_EMIT clicked();
844 d->_q_rebound();
845 } else if (d->contentItem->x() == 0.0) {
846 // if no actions list is connected, release flickable blockade
847 d->promptRebound();
848 } else {
849 d->setContentMoving(false);
850 }
600 }851 }
601 d->setPressed(false);852 d->setPressed(false);
602}853}
603854
855void UCListItem::mouseMoveEvent(QMouseEvent *event)
856{
857 Q_D(UCListItem);
858 UCStyledItemBase::mouseMoveEvent(event);
859
860 // accept the tugging only if the move is within the threshold
861 bool leadingAttached = UCListItemActionsPrivate::isConnectedTo(d->leadingActions, this);
862 bool trailingAttached = UCListItemActionsPrivate::isConnectedTo(d->trailingActions, this);
863 if (d->pressed && !(leadingAttached || trailingAttached)) {
864 // check if we can initiate the drag at all
865 // only X direction matters, if Y-direction leaves the threshold, but X not, the tug is not valid
866 qreal threshold = UCUnits::instance().gu(d->xAxisMoveThresholdGU);
867 qreal mouseX = event->localPos().x();
868 qreal pressedX = d->pressedPos.x();
869
870 if ((mouseX < (pressedX - threshold)) || (mouseX > (pressedX + threshold))) {
871 // the press went out of the threshold area, enable move, if the direction allows it
872 d->lastPos = event->localPos();
873 // tries to connect both panels so we do no longer need to take care which
874 // got connected ad which not; this may fail in case of shared ListItemActions,
875 // as then the panel is shared between the list items, and the panel might be
876 // still in use in other panels. See UCListItemActionsPrivate::connectToListItem
877 leadingAttached = d->grabPanel(d->leadingActions, true);
878 trailingAttached = d->grabPanel(d->trailingActions, true);
879 // create animator if not created yet
880 if (!d->animator) {
881 d->animator = new UCListItemSnapAnimator(this);
882 }
883 }
884 }
885
886 if (leadingAttached || trailingAttached) {
887 qreal x = d->contentItem->x();
888 qreal dx = event->localPos().x() - d->lastPos.x();
889 d->lastPos = event->localPos();
890
891 if (dx) {
892 d->setContentMoving(true);
893 // clamp X into allowed dragging area
894 d->clampAndMoveX(x, dx);
895 // block flickable
896 d->setSwiped(true);
897 d->contentItem->setX(x);
898 // decide which panel is visible by checking the contentItem's X coordinates
899 if (d->contentItem->x() > 0) {
900 if (leadingAttached) {
901 UCListItemActionsPrivate::get(d->leadingActions)->panelItem->setVisible(true);
902 }
903 if (trailingAttached) {
904 UCListItemActionsPrivate::get(d->trailingActions)->panelItem->setVisible(false);
905 }
906 } else if (d->contentItem->x() < 0) {
907 // trailing revealed
908 if (leadingAttached) {
909 UCListItemActionsPrivate::get(d->leadingActions)->panelItem->setVisible(false);
910 }
911 if (trailingAttached) {
912 UCListItemActionsPrivate::get(d->trailingActions)->panelItem->setVisible(true);
913 }
914 }
915 }
916 }
917}
918
919bool UCListItem::eventFilter(QObject *target, QEvent *event)
920{
921 QPointF myPos;
922 // only filter press events, and rebound when pressed outside
923 if (event->type() == QEvent::MouseButtonPress) {
924 QMouseEvent *mouse = static_cast<QMouseEvent*>(event);
925 QQuickWindow *window = qobject_cast<QQuickWindow*>(target);
926 if (window) {
927 myPos = window->contentItem()->mapToItem(this, mouse->localPos());
928 }
929 } else if (event->type() == QEvent::TouchBegin) {
930 QTouchEvent *touch = static_cast<QTouchEvent*>(event);
931 QQuickWindow *window = qobject_cast<QQuickWindow*>(target);
932 if (window) {
933 myPos = window->contentItem()->mapToItem(this, touch->touchPoints()[0].pos());
934 }
935 }
936 if (!myPos.isNull() && !contains(myPos)) {
937 Q_D(UCListItem);
938 d->_q_rebound();
939 // only accept event, but let it be handled by the underlying or surrounding Flickables
940 event->accept();
941 }
942 return UCStyledItemBase::eventFilter(target, event);
943}
944
604/*!945/*!
605 * \qmlproperty ListItemActions ListItem::leadingActions946 * \qmlproperty ListItemActions ListItem::leadingActions
606 *947 *
@@ -771,7 +1112,7 @@
771 }1112 }
772 d->highlightColor = color;1113 d->highlightColor = color;
773 // no more theme change watch1114 // no more theme change watch
774 disconnect(&UCTheme::instance(), SIGNAL(paletteChanged()), this, SLOT(_q_updateColors()));1115 d->customColor = true;
775 update();1116 update();
776 Q_EMIT highlightColorChanged();1117 Q_EMIT highlightColorChanged();
777}1118}
@@ -789,6 +1130,7 @@
7891130
790/*!1131/*!
791 * \qmlproperty list<Item> ListItem::children1132 * \qmlproperty list<Item> ListItem::children
1133 * \internal
792 * Overloaded default property containing all the visible children of the item.1134 * Overloaded default property containing all the visible children of the item.
793 */1135 */
794QQmlListProperty<QQuickItem> UCListItem::children()1136QQmlListProperty<QQuickItem> UCListItem::children()
7951137
=== modified file 'modules/Ubuntu/Components/plugin/uclistitem.h'
--- modules/Ubuntu/Components/plugin/uclistitem.h 2014-11-21 14:40:26 +0000
+++ modules/Ubuntu/Components/plugin/uclistitem.h 2014-11-21 14:40:28 +0000
@@ -39,6 +39,9 @@
39 Q_PROPERTY(QColor highlightColor READ highlightColor WRITE setHighlightColor NOTIFY highlightColorChanged)39 Q_PROPERTY(QColor highlightColor READ highlightColor WRITE setHighlightColor NOTIFY highlightColorChanged)
40 Q_PROPERTY(QQmlListProperty<QObject> data READ data DESIGNABLE false)40 Q_PROPERTY(QQmlListProperty<QObject> data READ data DESIGNABLE false)
41 Q_PROPERTY(QQmlListProperty<QQuickItem> children READ children NOTIFY childrenChanged DESIGNABLE false)41 Q_PROPERTY(QQmlListProperty<QQuickItem> children READ children NOTIFY childrenChanged DESIGNABLE false)
42 // FIXME move these to StyledItemBase with subtheming
43 Q_PRIVATE_PROPERTY(UCListItem::d_func(), QQmlComponent *style READ style WRITE setStyle NOTIFY styleChanged)
44 Q_PRIVATE_PROPERTY(UCListItem::d_func(), QQuickItem *__styleInstance READ styleInstance NOTIFY __styleInstanceChanged)
42 Q_CLASSINFO("DefaultProperty", "data")45 Q_CLASSINFO("DefaultProperty", "data")
43public:46public:
44 explicit UCListItem(QQuickItem *parent = 0);47 explicit UCListItem(QQuickItem *parent = 0);
@@ -65,6 +68,8 @@
65 void geometryChanged(const QRectF &newGeometry, const QRectF &oldGeometry);68 void geometryChanged(const QRectF &newGeometry, const QRectF &oldGeometry);
66 void mousePressEvent(QMouseEvent *event);69 void mousePressEvent(QMouseEvent *event);
67 void mouseReleaseEvent(QMouseEvent *event);70 void mouseReleaseEvent(QMouseEvent *event);
71 void mouseMoveEvent(QMouseEvent *event);
72 bool eventFilter(QObject *, QEvent *);
6873
69Q_SIGNALS:74Q_SIGNALS:
70 void leadingActionsChanged();75 void leadingActionsChanged();
@@ -77,6 +82,9 @@
7782
78 void clicked();83 void clicked();
7984
85 void styleChanged();
86 void __styleInstanceChanged();
87
80 void contentMovementStarted();88 void contentMovementStarted();
81 void contentMovementEnded();89 void contentMovementEnded();
8290
@@ -86,7 +94,7 @@
86 Q_DECLARE_PRIVATE(UCListItem)94 Q_DECLARE_PRIVATE(UCListItem)
87 QQmlListProperty<QObject> data();95 QQmlListProperty<QObject> data();
88 QQmlListProperty<QQuickItem> children();96 QQmlListProperty<QQuickItem> children();
89 Q_PRIVATE_SLOT(d_func(), void _q_updateColors())97 Q_PRIVATE_SLOT(d_func(), void _q_updateThemedData())
90 Q_PRIVATE_SLOT(d_func(), void _q_rebound())98 Q_PRIVATE_SLOT(d_func(), void _q_rebound())
91 Q_PRIVATE_SLOT(d_func(), void _q_updateSize())99 Q_PRIVATE_SLOT(d_func(), void _q_updateSize())
92};100};
93101
=== modified file 'modules/Ubuntu/Components/plugin/uclistitem_p.h'
--- modules/Ubuntu/Components/plugin/uclistitem_p.h 2014-11-21 14:40:26 +0000
+++ modules/Ubuntu/Components/plugin/uclistitem_p.h 2014-11-21 14:40:28 +0000
@@ -23,10 +23,12 @@
23#include <QtQuick/private/qquickrectangle_p.h>23#include <QtQuick/private/qquickrectangle_p.h>
2424
25class QQuickFlickable;25class QQuickFlickable;
26class QQuickPropertyAnimation;
26class UCListItemContent;27class UCListItemContent;
27class UCListItemDivider;28class UCListItemDivider;
28class UCListItemActions;29class UCListItemActions;
29class UCListItemSnapAnimator;30class UCListItemSnapAnimator;
31class UCListItemStyle;
30class UCListItemPrivate : public UCStyledItemBasePrivate32class UCListItemPrivate : public UCStyledItemBasePrivate
31{33{
32 Q_DECLARE_PUBLIC(UCListItem)34 Q_DECLARE_PUBLIC(UCListItem)
@@ -41,36 +43,55 @@
41 return that->d_func();43 return that->d_func();
42 }44 }
4345
44 void _q_updateColors();46 void _q_updateThemedData();
45 void _q_rebound();47 void _q_rebound();
46 void promptRebound();48 void promptRebound();
47 void _q_updateSize();49 void _q_updateSize();
48 int index();50 int index();
49 void setPressed(bool pressed);51 void setPressed(bool pressed);
52 void setSwiped(bool tugged);
53 bool grabPanel(UCListItemActions *optionList, bool isTugged);
50 void listenToRebind(bool listen);54 void listenToRebind(bool listen);
51 void resize();55 void resize();
52 void update();56 void update();
57 void clampAndMoveX(qreal &x, qreal dx);
5358
54 bool pressed:1;59 bool pressed:1;
55 bool contentMoved:1;60 bool contentMoved:1;
56 bool highlightColorChanged:1;61 bool highlightColorChanged:1;
62 bool swiped:1;
63 bool suppressClick:1;
57 bool ready:1;64 bool ready:1;
65 bool customStyle:1;
66 bool customColor:1;
67 qreal xAxisMoveThresholdGU;
58 qreal overshoot;68 qreal overshoot;
69 QPointF lastPos;
70 QPointF pressedPos;
59 QColor color;71 QColor color;
60 QColor highlightColor;72 QColor highlightColor;
61 QPointer<QQuickFlickable> flickable;73 QPointer<QQuickFlickable> flickable;
62 UCListItemAttached *attachedProperties;74 QPointer<UCListItemAttached> attachedProperties;
63 QQuickItem *contentItem;75 QQuickItem *contentItem;
64 UCListItemDivider *divider;76 UCListItemDivider *divider;
65 UCListItemActions *leadingActions;77 UCListItemActions *leadingActions;
66 UCListItemActions *trailingActions;78 UCListItemActions *trailingActions;
67 UCListItemSnapAnimator *animator;79 UCListItemSnapAnimator *animator;
6880
81 // FIXME move these to StyledItemBase togehther with subtheming.
82 QQmlComponent *styleComponent;
83 UCListItemStyle *styleItem;
84
69 // getter/setters85 // getter/setters
70 bool contentMoving() const;86 bool contentMoving() const;
71 void setContentMoving(bool moved);87 void setContentMoving(bool moved);
72 QQuickPropertyAnimation *snapAnimation() const;88 QQuickPropertyAnimation *snapAnimation() const;
73 void setSnapAnimation(QQuickPropertyAnimation *animation);89 void setSnapAnimation(QQuickPropertyAnimation *animation);
90 QQmlComponent *style() const;
91 void setStyle(QQmlComponent *delegate);
92 bool loadStyle();
93 void initStyleItem();
94 QQuickItem *styleInstance() const;
74};95};
7596
76class PropertyChange;97class PropertyChange;
@@ -115,7 +136,7 @@
115 void colorToChanged();136 void colorToChanged();
116137
117protected:138protected:
118 QSGNode *paint(const QRectF &rect);139 QSGNode *paint(QSGNode *node, const QRectF &rect);
119140
120private Q_SLOTS:141private Q_SLOTS:
121 void unitsChanged();142 void unitsChanged();
122143
=== modified file 'modules/Ubuntu/Components/plugin/uclistitemactions.cpp'
--- modules/Ubuntu/Components/plugin/uclistitemactions.cpp 2014-11-21 14:40:26 +0000
+++ modules/Ubuntu/Components/plugin/uclistitemactions.cpp 2014-11-21 14:40:28 +0000
@@ -19,13 +19,17 @@
19#include "uclistitem_p.h"19#include "uclistitem_p.h"
20#include "quickutils.h"20#include "quickutils.h"
21#include "i18n.h"21#include "i18n.h"
22#include "plugin.h"
22#include <QtQml/QQmlInfo>23#include <QtQml/QQmlInfo>
24#include "ucaction.h"
25#include "uclistitemstyle.h"
2326
24UCListItemActionsPrivate::UCListItemActionsPrivate()27UCListItemActionsPrivate::UCListItemActionsPrivate()
25 : QObjectPrivate()28 : QObjectPrivate()
26 , status(UCListItemActions::Disconnected)29 , status(UCListItemActions::Disconnected)
27 , offsetDragged(0)30 , offsetDragged(0)
28 , delegate(0)31 , delegate(0)
32 , panelDelegate(0)
29 , panelItem(0)33 , panelItem(0)
30{34{
31}35}
@@ -33,7 +37,157 @@
33{37{
34}38}
3539
36// FIXME - fis ListItemStyle::snapAnimation to a link when property available40void UCListItemActionsPrivate::_q_updateDraggedOffset()
41{
42 UCListItem *listItem = qobject_cast<UCListItem*>(panelItem->parentItem());
43 if (!listItem) {
44 return;
45 }
46
47 Q_Q(UCListItemActions);
48 offsetDragged = (status == UCListItemActions::Leading) ? panelItem->width() + panelItem->x() :
49 listItem->width() - panelItem->x();
50 if (offsetDragged < 0.0) {
51 offsetDragged = 0.0;
52 }
53}
54
55UCListItemActionsAttached *UCListItemActionsPrivate::attachedObject()
56{
57 if (!panelItem) {
58 return 0;
59 }
60 return static_cast<UCListItemActionsAttached*>(
61 qmlAttachedPropertiesObject<UCListItemActions>(panelItem, false));
62}
63
64/*
65 * Connects a ListItem to the ListItemActions' panel and returns true upon successful connection.
66 * Connection may fail if there is a different ListItem connected. In this case the new ListItem
67 * will be queued and automatically connected when the previous ListItem disconnects.
68 * The panel is only re-created when a different Component is used to create it.
69 * FIXME - despite each ListItem uses the same document to create the panel, theming engine
70 * provides different Component objects for each, due to not caching the components created.
71 * This must be fixed to optimize memory usage.
72 */
73bool UCListItemActionsPrivate::connectToListItem(UCListItemActions *actions, UCListItem *listItem, bool leading)
74{
75 UCListItemActionsPrivate *_this = get(actions);
76 if (!_this) {
77 return false;
78 }
79 // do we have a panel created already?
80 if (_this->panelItem) {
81 if (isConnectedTo(actions, listItem)) {
82 return true;
83 }
84 if (_this->panelItem->parentItem() && _this->panelItem->parentItem() != listItem) {
85 // set the requesting listItem as queuedItem
86 _this->queuedItem = listItem;
87 return false;
88 }
89 }
90 // no parent set or panelItem yet, proceed with panel creation
91 UCListItemPrivate *pItem = UCListItemPrivate::get(listItem);
92 if (!pItem->styleItem && pItem->loadStyle()) {
93 pItem->initStyleItem();
94 }
95 if (pItem->styleItem && !_this->createPanelItem(pItem->styleItem->m_actionsDelegate)) {
96 return false;
97 }
98
99 // check if the panel is still connected to a ListItem
100 // this may happen if there is a swipe over an other item while the previous
101 // one is rebounding
102 _this->panelItem->setParentItem(listItem);
103 if (_this->attachedObject()) {
104 _this->attachedObject()->connectListItem(listItem, true);
105 }
106 _this->offsetDragged = 0.0;
107 _this->status = leading ? UCListItemActions::Leading : UCListItemActions::Trailing;
108 Q_EMIT actions->statusChanged(_this->status);
109 return true;
110}
111
112void UCListItemActionsPrivate::disconnectFromListItem(UCListItemActions *actions)
113{
114 UCListItemActionsPrivate *_this = get(actions);
115 if (!_this || !_this->panelItem || !_this->panelItem->parentItem()) {
116 return;
117 }
118
119 if (_this->attachedObject()) {
120 _this->attachedObject()->connectListItem(static_cast<UCListItem*>(_this->panelItem->parentItem()), false);
121 }
122 _this->panelItem->setParentItem(0);
123 _this->status = UCListItemActions::Disconnected;
124 Q_EMIT actions->statusChanged(_this->status);
125 // if there was a queuedItem, make it grab the actions list
126 if (_this->queuedItem) {
127 UCListItemPrivate::get(_this->queuedItem.data())->grabPanel(actions, true);
128 // remove item from queue
129 _this->queuedItem.clear();
130 }
131}
132
133bool UCListItemActionsPrivate::isConnectedTo(UCListItemActions *actions, UCListItem *listItem)
134{
135 UCListItemActionsPrivate *_this = get(actions);
136 return _this && _this->panelItem &&
137 (_this->status != UCListItemActions::Disconnected) &&
138 (_this->panelItem->parentItem() == listItem);
139}
140
141QQuickItem *UCListItemActionsPrivate::createPanelItem(QQmlComponent *panel)
142{
143 if (panelItem && panelDelegate == panel) {
144 return panelItem;
145 }
146 // delete the panel if the next item's actionsDelegate differs from the
147 // one this panel was created from
148 if (panelDelegate != panel) {
149 delete panelItem;
150 panelItem = 0;
151 }
152
153 Q_Q(UCListItemActions);
154 if (!panel) {
155 qmlInfo(q) << UbuntuI18n::instance().tr("actionsDelegate not set!");
156 return 0;
157 }
158
159 panelDelegate = panel;
160 if (!panelDelegate->isError()) {
161 panelItem = qobject_cast<QQuickItem*>(panelDelegate->beginCreate(qmlContext(q)));
162 if (panelItem) {
163 QQml_setParent_noEvent(panelItem, q);
164 // add panelItem to data so we can access it in case is needed (i.e. tests)
165 data.append(panelItem);
166 // create attached property!
167 UCListItemActionsAttached *attached = static_cast<UCListItemActionsAttached*>(
168 qmlAttachedPropertiesObject<UCListItemActions>(panelItem));
169 if (!attached->container()) {
170 attached->setList(q);
171 } else {
172 // container is set, but we need to emit the signal again so we get the
173 // attached props updated for those cases when the attached property is
174 // created before the statement above
175 Q_EMIT attached->containerChanged();
176 }
177 panelDelegate->completeCreate();
178
179 // calculate option's slot size
180 offsetDragged = 0.0;
181 // connect to panel to catch dragging
182 QObject::connect(panelItem, SIGNAL(xChanged()), q, SLOT(_q_updateDraggedOffset()));
183 }
184 } else {
185 qmlInfo(q) << panelDelegate->errorString();
186 }
187
188 return panelItem;
189}
190
37/*!191/*!
38 * \qmltype ListItemActions192 * \qmltype ListItemActions
39 * \instantiates UCListItemActions193 * \instantiates UCListItemActions
@@ -111,7 +265,7 @@
111 * However, this implies that swiping a new ListItem content while another one is265 * However, this implies that swiping a new ListItem content while another one is
112 * swiped will result in showing the newly swiped item's panel delayed, as the266 * swiped will result in showing the newly swiped item's panel delayed, as the
113 * panel can be shown only after the previous item's snapping is completed. Depending267 * panel can be shown only after the previous item's snapping is completed. Depending
114 * on the \c ListItemStyle::snapAnimation duration, this may take some time, and the268 * on the \l {ListItemStyle::snapAnimation}{snapAnimation} duration, this may take some time, and the
115 * response time of the UI can become unacceptable.269 * response time of the UI can become unacceptable.
116 *270 *
117 * Having individual ListItemActions instances increases the memory footprint,271 * Having individual ListItemActions instances increases the memory footprint,
@@ -261,7 +415,6 @@
261415
262/*!416/*!
263 * \qmlproperty list<Action> ListItemActions::actions417 * \qmlproperty list<Action> ListItemActions::actions
264 * \default
265 * The property holds the actions to be displayed. It can hold instances cached or418 * The property holds the actions to be displayed. It can hold instances cached or
266 * declared in place. An example of cached actions:419 * declared in place. An example of cached actions:
267 * \qml420 * \qml
@@ -290,3 +443,5 @@
290 Q_D(UCListItemActions);443 Q_D(UCListItemActions);
291 return QQmlListProperty<QObject>(this, d->data);444 return QQmlListProperty<QObject>(this, d->data);
292}445}
446
447#include "moc_uclistitemactions.cpp"
293448
=== modified file 'modules/Ubuntu/Components/plugin/uclistitemactions.h'
--- modules/Ubuntu/Components/plugin/uclistitemactions.h 2014-11-21 14:40:26 +0000
+++ modules/Ubuntu/Components/plugin/uclistitemactions.h 2014-11-21 14:40:28 +0000
@@ -54,6 +54,7 @@
5454
55private:55private:
56 Q_DECLARE_PRIVATE(UCListItemActions)56 Q_DECLARE_PRIVATE(UCListItemActions)
57 Q_PRIVATE_SLOT(d_func(), void _q_updateDraggedOffset())
57};58};
5859
59class UCListItemActionsAttached : public QObject60class UCListItemActionsAttached : public QObject
6061
=== modified file 'modules/Ubuntu/Components/plugin/uclistitemactions_p.h'
--- modules/Ubuntu/Components/plugin/uclistitemactions_p.h 2014-11-21 14:40:26 +0000
+++ modules/Ubuntu/Components/plugin/uclistitemactions_p.h 2014-11-21 14:40:28 +0000
@@ -20,6 +20,7 @@
20#include "uclistitemactions.h"20#include "uclistitemactions.h"
21#include "QtCore/private/qobject_p.h"21#include "QtCore/private/qobject_p.h"
2222
23class UCListItem;
23class UCListItemActionsPrivate : public QObjectPrivate {24class UCListItemActionsPrivate : public QObjectPrivate {
24 Q_DECLARE_PUBLIC(UCListItemActions)25 Q_DECLARE_PUBLIC(UCListItemActions)
25public:26public:
@@ -27,16 +28,27 @@
27 ~UCListItemActionsPrivate();28 ~UCListItemActionsPrivate();
28 static UCListItemActionsPrivate* get(UCListItemActions *actions)29 static UCListItemActionsPrivate* get(UCListItemActions *actions)
29 {30 {
30 Q_ASSERT(actions);31 return actions ? actions->d_func() : 0;
31 return actions->d_func();
32 }32 }
3333
34 UCListItemActions::Status status;34 UCListItemActions::Status status;
35 qreal offsetDragged;35 qreal offsetDragged;
36
36 QQmlComponent *delegate;37 QQmlComponent *delegate;
38 QQmlComponent *panelDelegate;
37 QQuickItem *panelItem;39 QQuickItem *panelItem;
38 QList<UCAction*> actions;40 QList<UCAction*> actions;
39 QList<QObject*> data;41 QList<QObject*> data;
42 QPointer<UCListItem> queuedItem;
43
44 void _q_updateDraggedOffset();
45 UCListItemActionsAttached *attachedObject();
46
47 static bool connectToListItem(UCListItemActions *options, UCListItem *listItem, bool leading);
48 static void disconnectFromListItem(UCListItemActions *options);
49 static bool isConnectedTo(UCListItemActions *options, UCListItem *listItem);
50
51 QQuickItem *createPanelItem(QQmlComponent *delegate);
40};52};
4153
42#endif // UCLISTITEMACTIONS_P_H54#endif // UCLISTITEMACTIONS_P_H
4355
=== modified file 'modules/Ubuntu/Components/plugin/uclistitemactionsattached.cpp'
--- modules/Ubuntu/Components/plugin/uclistitemactionsattached.cpp 2014-11-21 14:40:26 +0000
+++ modules/Ubuntu/Components/plugin/uclistitemactionsattached.cpp 2014-11-21 14:40:28 +0000
@@ -121,7 +121,7 @@
121}121}
122122
123/*!123/*!
124 * \qmlproperty list<Action> ListItemActions::visibleActions124 * \qmlattachedproperty list<Action> ListItemActions::visibleActions
125 * Holds the list of visible actions. This is a convenience property to help action125 * Holds the list of visible actions. This is a convenience property to help action
126 * visualization panel implementations to consider only visible actions.126 * visualization panel implementations to consider only visible actions.
127 */127 */
@@ -259,8 +259,11 @@
259 if (position == 0.0) {259 if (position == 0.0) {
260 listItem->_q_rebound();260 listItem->_q_rebound();
261 } else {261 } else {
262 // FIXME: implement snaping262 if (listItem->animator) {
263 listItem->contentItem->setX(position);263 listItem->animator->snap(position);
264 } else {
265 listItem->contentItem->setX(position);
266 }
264 }267 }
265}268}
266269
267270
=== added file 'modules/Ubuntu/Components/plugin/uclistitemstyle.cpp'
--- modules/Ubuntu/Components/plugin/uclistitemstyle.cpp 1970-01-01 00:00:00 +0000
+++ modules/Ubuntu/Components/plugin/uclistitemstyle.cpp 2014-11-21 14:40:28 +0000
@@ -0,0 +1,92 @@
1/*
2 * Copyright 2014 Canonical Ltd.
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU Lesser General Public License as published by
6 * the Free Software Foundation; version 3.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU Lesser General Public License for more details.
12 *
13 * You should have received a copy of the GNU Lesser General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 */
16
17#include "uclistitemstyle.h"
18
19/*!
20 * \qmltype ListItemStyle
21 * \instantiates UCListItemStyle
22 * \inqmlmodule Ubuntu.Components.Styles 1.2
23 * \ingroup style-api
24 * \since Ubuntu.Components.Styles 1.2
25 * \brief Style API for ListItem component.
26 *
27 * Style API for the ListItem component which provides actions, select and
28 * drag handler delegates, and snap animation via its properties.
29 * ListItem treats the style differently compared to the other components,
30 * as it:
31 * \list
32 * \li - loads the style only when needed
33 * \li - gets delegates and snap animation from the style properties
34 * \li - ignores any other visuals defined in the style.
35 * \endlist
36 */
37UCListItemStyle::UCListItemStyle(QQuickItem *parent) :
38 QQuickItem(parent)
39{
40}
41
42/*!
43 * \qmlproperty Component ListItemStyle::actionsDelegate
44 * Specifies the component visualizing the leading/trailing actions.
45 */
46void UCListItemStyle::setActionsDelegate(QQmlComponent *delegate)
47{
48 if (m_actionsDelegate == delegate) {
49 return;
50 }
51 m_actionsDelegate = delegate;
52 Q_EMIT actionsDelegateChanged();
53}
54
55/*!
56 * \qmlproperty Component ListItemStyle::selectionDelegate
57 * Holds the component handling the selection mode.
58 */
59void UCListItemStyle::setSelectionDelegate(QQmlComponent *delegate)
60{
61 if (m_selectionDelegate == delegate) {
62 return;
63 }
64 m_selectionDelegate = delegate;
65 Q_EMIT selectionDelegateChanged();
66}
67
68/*!
69 * \qmlproperty Component ListItemStyle::dragHandlerDelegate
70 * Holds the component shown when dragging mode is enabled.
71 */
72void UCListItemStyle::setDragHandlerDelegate(QQmlComponent *delegate)
73{
74 if (m_dragHandlerDelegate == delegate) {
75 return;
76 }
77 m_dragHandlerDelegate = delegate;
78 Q_EMIT dragHandlerDelegateChanged();
79}
80
81/*!
82 * \qmlproperty PropertyAnimation ListItemStyle::snapAnimation
83 * Holds the animation used in animating when snapped in or out.
84 */
85void UCListItemStyle::setSnapAnimation(QQuickPropertyAnimation *animation)
86{
87 if (m_snapAnimation == animation) {
88 return;
89 }
90 m_snapAnimation = animation;
91 Q_EMIT snapAnimationChanged();
92}
093
=== added file 'modules/Ubuntu/Components/plugin/uclistitemstyle.h'
--- modules/Ubuntu/Components/plugin/uclistitemstyle.h 1970-01-01 00:00:00 +0000
+++ modules/Ubuntu/Components/plugin/uclistitemstyle.h 2014-11-21 14:40:28 +0000
@@ -0,0 +1,54 @@
1/*
2 * Copyright 2014 Canonical Ltd.
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU Lesser General Public License as published by
6 * the Free Software Foundation; version 3.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU Lesser General Public License for more details.
12 *
13 * You should have received a copy of the GNU Lesser General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 */
16#ifndef UCLISTITEMSTYLE_H
17#define UCLISTITEMSTYLE_H
18
19#include <QtQuick/QQuickItem>
20
21class QQmlComponent;
22class QQuickPropertyAnimation;
23class UCListItemStyle : public QQuickItem
24{
25 Q_OBJECT
26 Q_PROPERTY(QQmlComponent *actionsDelegate MEMBER m_actionsDelegate WRITE setActionsDelegate NOTIFY actionsDelegateChanged)
27 Q_PROPERTY(QQmlComponent *selectionDelegate MEMBER m_selectionDelegate WRITE setSelectionDelegate NOTIFY selectionDelegateChanged)
28 Q_PROPERTY(QQmlComponent *dragHandlerDelegate MEMBER m_dragHandlerDelegate WRITE setDragHandlerDelegate NOTIFY dragHandlerDelegateChanged)
29 Q_PROPERTY(QQuickPropertyAnimation *snapAnimation MEMBER m_snapAnimation WRITE setSnapAnimation NOTIFY snapAnimationChanged)
30public:
31 explicit UCListItemStyle(QQuickItem *parent = 0);
32
33 void setActionsDelegate(QQmlComponent *delegate);
34 void setSelectionDelegate(QQmlComponent *delegate);
35 void setDragHandlerDelegate(QQmlComponent *delegate);
36 void setSnapAnimation(QQuickPropertyAnimation *animation);
37
38Q_SIGNALS:
39 void actionsDelegateChanged();
40 void selectionDelegateChanged();
41 void dragHandlerDelegateChanged();
42 void snapAnimationChanged();
43
44private:
45 QQmlComponent *m_actionsDelegate;
46 QQmlComponent *m_selectionDelegate;
47 QQmlComponent *m_dragHandlerDelegate;
48 QQuickPropertyAnimation *m_snapAnimation;
49
50 friend class UCListItemActionsPrivate;
51 friend class UCListItemSnapAnimator;
52};
53
54#endif // UCLISTITEMSTYLE_H
055
=== modified file 'tests/qmlapicheck.sh'
--- tests/qmlapicheck.sh 2014-10-30 10:44:19 +0000
+++ tests/qmlapicheck.sh 2014-11-21 14:40:28 +0000
@@ -33,7 +33,7 @@
33 # https://bugs.launchpad.net/ubuntu-ui-toolkit/+bug/125699933 # https://bugs.launchpad.net/ubuntu-ui-toolkit/+bug/1256999
34 # https://bugreports.qt-project.org/browse/QTBUG-3624334 # https://bugreports.qt-project.org/browse/QTBUG-36243
35 env UBUNTU_UI_TOOLKIT_THEMES_PATH=$SRCDIR/modules ALARM_BACKEND=memory \35 env UBUNTU_UI_TOOLKIT_THEMES_PATH=$SRCDIR/modules ALARM_BACKEND=memory \
36 qmlplugindump $i 0.1 $SRCDIR/modules 1>> $BLDDIR/plugins.qmltypes36 qmlplugindump -noinstantiate $i 0.1 $SRCDIR/modules 1>> $BLDDIR/plugins.qmltypes
37 test $? != 0 && ERRORS=137 test $? != 0 && ERRORS=1
38done38done
39test $ERRORS = 1 && echo Error: qmlplugindump failed && exit 139test $ERRORS = 1 && echo Error: qmlplugindump failed && exit 1
4040
=== modified file 'tests/resources/listitems/ListItemTest.qml'
--- tests/resources/listitems/ListItemTest.qml 2014-11-21 14:40:26 +0000
+++ tests/resources/listitems/ListItemTest.qml 2014-11-21 14:40:28 +0000
@@ -31,6 +31,7 @@
3131
32 ListItemActions {32 ListItemActions {
33 id: leading33 id: leading
34 objectName: "StockLeading"
34 actions: [35 actions: [
35 Action {36 Action {
36 },37 },
@@ -41,6 +42,23 @@
41 ]42 ]
42 }43 }
4344
45 property list<Action> leadingArray: [
46 Action {
47 iconName: "delete"
48 }
49 ]
50 property list<Action> trailingArray: [
51 Action {
52 iconName: "search"
53 },
54 Action {
55 iconName: "edit"
56 },
57 Action {
58 iconName: "copy"
59 }
60 ]
61
44 Column {62 Column {
45 anchors {63 anchors {
46 left: parent.left64 left: parent.left
@@ -49,6 +67,7 @@
4967
50 ListItem {68 ListItem {
51 id: testItem69 id: testItem
70 objectName: "single"
52 color: "lime"71 color: "lime"
53 onClicked: {72 onClicked: {
54 print("click")73 print("click")
@@ -59,6 +78,7 @@
59 text: units.gridUnit + "PX/unit"78 text: units.gridUnit + "PX/unit"
60 }79 }
61 leadingActions: ListItemActions {80 leadingActions: ListItemActions {
81 objectName: "InlineLeading"
62 actions: [stock]82 actions: [stock]
63 }83 }
64 trailingActions: leading84 trailingActions: leading
@@ -72,6 +92,7 @@
72 model: 10092 model: 100
73 pressDelay: 093 pressDelay: 0
74 delegate: ListItem {94 delegate: ListItem {
95 objectName: "ListItem" + index
75 id: listItem96 id: listItem
76 onClicked: print(" clicked")97 onClicked: print(" clicked")
77 leadingActions: leading98 leadingActions: leading
@@ -100,10 +121,18 @@
100 Repeater {121 Repeater {
101 model: 100122 model: 100
102 ListItem {123 ListItem {
124 objectName: "InFlickable"+index
103 color: "red"125 color: "red"
104 highlightColor: "lime"126 highlightColor: "lime"
105 divider.colorFrom: UbuntuColors.green127 divider.colorFrom: UbuntuColors.green
106128
129 leadingActions: ListItemActions {
130 actions: leadingArray
131 }
132 trailingActions: ListItemActions {
133 actions: trailingArray
134 }
135
107 Label {136 Label {
108 text: modelData + " Flickable item"137 text: modelData + " Flickable item"
109 }138 }
110139
=== renamed file 'tests/unit/tst_performance/ListItemWithOptionsList.qml' => 'tests/unit/tst_performance/ListItemWithActionsList.qml'
--- tests/unit/tst_performance/ListItemWithOptionsList.qml 2014-11-21 14:40:26 +0000
+++ tests/unit/tst_performance/ListItemWithActionsList.qml 2014-11-21 14:40:28 +0000
@@ -22,9 +22,15 @@
22 height: 60022 height: 600
23 ListItemActions {23 ListItemActions {
24 id: actions124 id: actions1
25 actions: [Action {}]
25 }26 }
26 ListItemActions {27 ListItemActions {
27 id: actions228 id: actions2
29 actions: [
30 Action {},
31 Action {},
32 Action {}
33 ]
28 }34 }
2935
30 Repeater {36 Repeater {
3137
=== added file 'tests/unit/tst_performance/ListItemWithInlineActionsList.qml'
--- tests/unit/tst_performance/ListItemWithInlineActionsList.qml 1970-01-01 00:00:00 +0000
+++ tests/unit/tst_performance/ListItemWithInlineActionsList.qml 2014-11-21 14:40:28 +0000
@@ -0,0 +1,41 @@
1/*
2 * Copyright 2014 Canonical Ltd.
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU Lesser General Public License as published by
6 * the Free Software Foundation; version 3.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU Lesser General Public License for more details.
12 *
13 * You should have received a copy of the GNU Lesser General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 */
16
17import QtQuick 2.0
18import Ubuntu.Components 1.2
19
20Column {
21 width: 800
22 height: 600
23
24 Repeater {
25 model: 5000
26 ListItem {
27 trailingActions: ListItemActions {
28 actions: [
29 Action {}
30 ]
31 }
32 leadingActions: ListItemActions {
33 actions: [
34 Action {},
35 Action {},
36 Action {}
37 ]
38 }
39 }
40 }
41}
042
=== modified file 'tests/unit/tst_performance/tst_performance.cpp'
--- tests/unit/tst_performance/tst_performance.cpp 2014-11-21 14:40:26 +0000
+++ tests/unit/tst_performance/tst_performance.cpp 2014-11-21 14:40:28 +0000
@@ -78,7 +78,8 @@
78 QTest::newRow("grid with Slider") << "SliderGrid.qml" << QUrl();78 QTest::newRow("grid with Slider") << "SliderGrid.qml" << QUrl();
79 QTest::newRow("list with QtQuick Item") << "ItemList.qml" << QUrl();79 QTest::newRow("list with QtQuick Item") << "ItemList.qml" << QUrl();
80 QTest::newRow("list with new ListItem") << "ListItemList.qml" << QUrl();80 QTest::newRow("list with new ListItem") << "ListItemList.qml" << QUrl();
81 QTest::newRow("list with new ListItem with options") << "ListItemWithOptionsList.qml" << QUrl();81 QTest::newRow("list with new ListItem with actions") << "ListItemWithActionsList.qml" << QUrl();
82 QTest::newRow("list with new ListItem with inline actions") << "ListItemWithInlineActionsList.qml" << QUrl();
82 QTest::newRow("list with ListItems.Empty (equivalent to the new ListItem") << "ListItemsEmptyList.qml" << QUrl();83 QTest::newRow("list with ListItems.Empty (equivalent to the new ListItem") << "ListItemsEmptyList.qml" << QUrl();
83 // disable this test as it takes >20 seconds. Kept still for measurements to be done during development84 // disable this test as it takes >20 seconds. Kept still for measurements to be done during development
84// QTest::newRow("list with ListItems.Base (one icon, one label and one chevron)") << "ListItemsBaseList.qml" << QUrl();85// QTest::newRow("list with ListItems.Base (one icon, one label and one chevron)") << "ListItemsBaseList.qml" << QUrl();
8586
=== modified file 'tests/unit/tst_performance/tst_performance.pro'
--- tests/unit/tst_performance/tst_performance.pro 2014-11-21 14:40:26 +0000
+++ tests/unit/tst_performance/tst_performance.pro 2014-11-21 14:40:28 +0000
@@ -22,6 +22,7 @@
22 TextWithImportPopups.qml \22 TextWithImportPopups.qml \
23 ItemList.qml \23 ItemList.qml \
24 ListItemList.qml \24 ListItemList.qml \
25 ListItemWithOptionsList.qml \
26 ListItemsEmptyList.qml \25 ListItemsEmptyList.qml \
27 ListItemsBaseList.qml26 ListItemsBaseList.qml \
27 ListItemWithInlineActionsList.qml \
28 ListItemWithActionsList.qml
2829
=== modified file 'tests/unit_x11/tst_components/tst_listitem.qml'
--- tests/unit_x11/tst_components/tst_listitem.qml 2014-11-21 14:40:26 +0000
+++ tests/unit_x11/tst_components/tst_listitem.qml 2014-11-21 14:40:28 +0000
@@ -58,6 +58,8 @@
58 id: testItem58 id: testItem
59 width: parent.width59 width: parent.width
60 color: "blue"60 color: "blue"
61 leadingActions: leading
62 trailingActions: trailing
61 Item {63 Item {
62 id: bodyItem64 id: bodyItem
63 anchors.fill: parent65 anchors.fill: parent
@@ -71,7 +73,10 @@
71 model: 1073 model: 10
72 delegate: ListItem {74 delegate: ListItem {
73 objectName: "listItem" + index75 objectName: "listItem" + index
76 color: "lightgray"
74 width: parent.width77 width: parent.width
78 leadingActions: leading
79 trailingActions: trailing
75 }80 }
76 }81 }
77 }82 }
@@ -81,6 +86,11 @@
81 when: windowShown86 when: windowShown
8287
83 SignalSpy {88 SignalSpy {
89 id: movingSpy
90 signalName: "contentMovementEnded"
91 }
92
93 SignalSpy {
84 id: pressedSpy94 id: pressedSpy
85 signalName: "pressedChanged"95 signalName: "pressedChanged"
86 target: testItem96 target: testItem
@@ -92,8 +102,24 @@
92 target: testItem;102 target: testItem;
93 }103 }
94104
95 function centerOf(item) {105 SignalSpy {
96 return Qt.point(item.width / 2, item.height / 2);106 id: interactiveSpy
107 signalName: "interactiveChanged"
108 }
109
110 function rebound(item, watchTarget) {
111 if (watchTarget === undefined) {
112 watchTarget = item;
113 }
114
115 movingSpy.target = null;
116 movingSpy.target = watchTarget;
117 movingSpy.clear();
118 mouseClick(item, centerOf(item).x, centerOf(item).y);
119 if (watchTarget.contentMoving) {
120 movingSpy.wait();
121 }
122 movingSpy.target = null;
97 }123 }
98124
99 function initTestCase() {125 function initTestCase() {
@@ -102,10 +128,16 @@
102 }128 }
103129
104 function cleanup() {130 function cleanup() {
131 movingSpy.clear();
105 pressedSpy.clear();132 pressedSpy.clear();
106 clickSpy.clear();133 clickSpy.clear();
107 // make sure all events are processed134 listView.interactive = true;
108 wait(200);135 // make sure we collapse
136 mouseClick(defaults, 0, 0)
137 movingSpy.target = null;
138 movingSpy.clear();
139 interactiveSpy.target = null;
140 interactiveSpy.clear();
109 }141 }
110142
111 function test_0_defaults() {143 function test_0_defaults() {
@@ -120,6 +152,9 @@
120 fuzzyCompare(defaults.divider.colorFrom.a, 0.14, 0.01, "colorFrom alpha differs");152 fuzzyCompare(defaults.divider.colorFrom.a, 0.14, 0.01, "colorFrom alpha differs");
121 compare(defaults.divider.colorTo, "#ffffff", "colorTo differs.");153 compare(defaults.divider.colorTo, "#ffffff", "colorTo differs.");
122 fuzzyCompare(defaults.divider.colorTo.a, 0.07, 0.01, "colorTo alpha differs");154 fuzzyCompare(defaults.divider.colorTo.a, 0.07, 0.01, "colorTo alpha differs");
155 compare(defaults.contentMoving, false, "default is not moving");
156 compare(defaults.style, null, "Style is loaded upon first use.");
157 compare(defaults.__styleInstance, null, "__styleInstance must be null.");
123158
124 compare(actionsDefault.delegate, null, "ListItemActions has no delegate set by default.");159 compare(actionsDefault.delegate, null, "ListItemActions has no delegate set by default.");
125 compare(actionsDefault.actions.length, 0, "ListItemActions has no options set.");160 compare(actionsDefault.actions.length, 0, "ListItemActions has no options set.");
@@ -179,6 +214,7 @@
179 TestExtras.touchMove(0, listItem, Qt.point(listItem.width / 2, dy));214 TestExtras.touchMove(0, listItem, Qt.point(listItem.width / 2, dy));
180 }215 }
181 compare(listItem.pressed, false, "Item is pressed still!");216 compare(listItem.pressed, false, "Item is pressed still!");
217 // cleanup, wait few milliseconds to avoid dbl-click collision
182 TestExtras.touchRelease(0, listItem, Qt.point(listItem.width / 2, dy));218 TestExtras.touchRelease(0, listItem, Qt.point(listItem.width / 2, dy));
183 }219 }
184220
@@ -190,5 +226,90 @@
190 compare(testItem.contentItem.height, testItem.height, "ListItem's background height must be the same as the item itself.");226 compare(testItem.contentItem.height, testItem.height, "ListItem's background height must be the same as the item itself.");
191 testItem.divider.visible = true;227 testItem.divider.visible = true;
192 }228 }
229
230 function test_touch_tug_options_data() {
231 var item = findChild(listView, "listItem0");
232 return [
233 {tag: "Trailing, mouse", item: item, pos: centerOf(item), dx: -units.gu(20), positiveDirection: false, mouse: true},
234 {tag: "Leading, mouse", item: item, pos: centerOf(item), dx: units.gu(20), positiveDirection: true, mouse: true},
235 {tag: "Trailing, touch", item: item, pos: centerOf(item), dx: -units.gu(20), positiveDirection: false, mouse: false},
236 {tag: "Leading, touch", item: item, pos: centerOf(item), dx: units.gu(20), positiveDirection: true, mouse: false},
237 ];
238 }
239 function test_touch_tug_options(data) {
240 listView.positionViewAtBeginning();
241 movingSpy.target = data.item;
242 if (data.mouse) {
243 flick(data.item, data.pos.x, data.pos.y, data.dx, 0);
244 } else {
245 TestExtras.touchDrag(0, data.item, data.pos, Qt.point(data.dx, 0));
246 }
247 movingSpy.wait();
248 if (data.positiveDirection) {
249 verify(data.item.contentItem.x > 0, data.tag + " options did not show up");
250 } else {
251 verify(data.item.contentItem.x < 0, data.tag + " options did not show up");
252 }
253
254 // dismiss
255 rebound(data.item);
256 }
257
258 function test_rebound_when_pressed_outside_or_clicked_data() {
259 var item0 = findChild(listView, "listItem0");
260 var item1 = findChild(listView, "listItem1");
261 return [
262 {tag: "Click on an other Item", item: item0, pos: centerOf(item0), dx: -units.gu(20), clickOn: item1, mouse: true},
263 {tag: "Click on the same Item", item: item0, pos: centerOf(item0), dx: -units.gu(20), clickOn: item0.contentItem, mouse: true},
264 {tag: "Tap on an other Item", item: item0, pos: centerOf(item0), dx: -units.gu(20), clickOn: item1, mouse: false},
265 {tag: "Tap on the same Item", item: item0, pos: centerOf(item0), dx: -units.gu(20), clickOn: item0.contentItem, mouse: false},
266 ];
267 }
268 function test_rebound_when_pressed_outside_or_clicked(data) {
269 listView.positionViewAtBeginning();
270 movingSpy.target = data.item;
271 if (data.mouse) {
272 flick(data.item, data.pos.x, data.pos.y, data.dx, 0);
273 } else {
274 TestExtras.touchDrag(0, data.item, data.pos, Qt.point(data.dx, 0));
275 }
276 movingSpy.wait();
277 verify(data.item.contentItem.x != 0, "The component wasn't tugged!");
278 // dismiss
279 rebound(data.clickOn, data.item)
280 }
281
282 function test_listview_not_interactive_while_tugged_data() {
283 var item0 = findChild(listView, "listItem0");
284 var item1 = findChild(listView, "listItem1");
285 return [
286 {tag: "Trailing", item: item0, pos: centerOf(item0), dx: -units.gu(20), clickOn: item1, mouse: true},
287 {tag: "Leading", item: item0, pos: centerOf(item0), dx: units.gu(20), clickOn: item0.contentItem, mouse: true},
288 {tag: "Trailing", item: item0, pos: centerOf(item0), dx: -units.gu(20), clickOn: item1, mouse: false},
289 {tag: "Leading", item: item0, pos: centerOf(item0), dx: units.gu(20), clickOn: item0.contentItem, mouse: false},
290 ];
291 }
292 function test_listview_not_interactive_while_tugged(data) {
293 listView.positionViewAtBeginning();
294 movingSpy.target = data.item;
295 interactiveSpy.target = listView;
296 if (data.mouse) {
297 flick(data.item, data.pos.x, data.pos.y, data.dx, 0);
298 } else {
299 TestExtras.touchDrag(0, data.item, data.pos, Qt.point(data.dx, 0));
300 }
301 movingSpy.wait();
302 // animation should no longer be running!
303 verify(!data.item.__styleInstance.snapAnimation.running, "Animation is still running!");
304 compare(listView.interactive, true, "The ListView is still non-interactive!");
305 compare(interactiveSpy.count, 2, "Less/more times changed!");
306 // check if it snapped in
307 verify(data.item.contentItem.x != 0.0, "Not snapped in!!");
308 // dismiss
309 rebound(data.clickOn, data.item);
310 // animation should no longer be running!
311 verify(!data.item.__styleInstance.snapAnimation.running, "Animation is still running!");
312 fuzzyCompare(data.item.contentItem.x, 0.0, 0.1, "Not snapped out!!");
313 }
193 }314 }
194}315}

Subscribers

People subscribed via source and target branches

to all changes: