Merge lp:~zsombi/ubuntu-ui-toolkit/20-divider into lp:~bzoltan/ubuntu-ui-toolkit/new_list_item

Proposed by Zsombor Egri
Status: Superseded
Proposed branch: lp:~zsombi/ubuntu-ui-toolkit/20-divider
Merge into: lp:~bzoltan/ubuntu-ui-toolkit/new_list_item
Prerequisite: lp:~zsombi/ubuntu-ui-toolkit/10-viewitem
Diff against target: 551 lines (+332/-11)
7 files modified
components.api (+8/-0)
modules/Ubuntu/Components/plugin/plugin.cpp (+1/-0)
modules/Ubuntu/Components/plugin/uclistitem.cpp (+231/-9)
modules/Ubuntu/Components/plugin/uclistitem.h (+5/-0)
modules/Ubuntu/Components/plugin/uclistitem_p.h (+58/-0)
tests/resources/listitems/ListItemTest.qml (+13/-2)
tests/unit_x11/tst_components/tst_listitem.qml (+16/-0)
To merge this branch: bzr merge lp:~zsombi/ubuntu-ui-toolkit/20-divider
Reviewer Review Type Date Requested Status
PS Jenkins bot continuous-integration Pending
Tim Peeters Pending
MichaƂ Sawicz Pending
Review via email: mp+234630@code.launchpad.net

Commit message

Adding divider to ListItem.

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

prereq

1221. By Zsombor Egri

prereq merge

1222. By Zsombor Egri

prereq updated

1223. By Zsombor Egri

prereq merge

1224. By Zsombor Egri

divider paint fixed

1225. By Zsombor Egri

prereq

1226. By Zsombor Egri

colroFrom and colorTo documented

1227. By Zsombor Egri

background colored only on the contentItem area

1228. By Zsombor Egri

divider to paint edge-to-edge when pressed

1229. By Zsombor Egri

prereq sync

1230. By Zsombor Egri

prereq sync

1231. By Zsombor Egri

prereq sync

1232. By Zsombor Egri

prereq sync

1233. By Zsombor Egri

prereq sync

1234. By Zsombor Egri

2GU to 2DP teft and rigth margins on divider

1235. By Zsombor Egri

prereq sync

1236. By Zsombor Egri

prereq sync

1237. By Zsombor Egri

prereq sync

1238. By Zsombor Egri

prereq sync

Unmerged revisions

1238. By Zsombor Egri

prereq sync

1237. By Zsombor Egri

prereq sync

1236. By Zsombor Egri

prereq sync

1235. By Zsombor Egri

prereq sync

1234. By Zsombor Egri

2GU to 2DP teft and rigth margins on divider

1233. By Zsombor Egri

prereq sync

1232. By Zsombor Egri

prereq sync

1231. By Zsombor Egri

prereq sync

1230. By Zsombor Egri

prereq sync

1229. By Zsombor Egri

prereq sync

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'components.api'
2--- components.api 2014-09-15 08:22:13 +0000
3+++ components.api 2014-09-15 08:22:15 +0000
4@@ -818,6 +818,7 @@
5 prototype: "UCStyledItemBase"
6 exports: ["ListItem 1.1"]
7 Property { name: "contentItem"; type: "UCListItemContent"; isReadonly: true; isPointer: true }
8+ Property { name: "divider"; type: "UCListItemDivider"; isReadonly: true; isPointer: true }
9 Property { name: "pressed"; type: "bool"; isReadonly: true }
10 Property { name: "data"; type: "QObject"; isList: true; isReadonly: true }
11 Property { name: "children"; type: "QQuickItem"; isList: true; isReadonly: true }
12@@ -826,6 +827,13 @@
13 prototype: "QQuickItem"
14 Property { name: "color"; type: "QColor" }
15 Property { name: "pressedColor"; type: "QColor" }
16+ name: "UCListItemDivider"
17+ prototype: "QObject"
18+ Property { name: "visible"; type: "bool" }
19+ Property { name: "leftMargin"; type: "double" }
20+ Property { name: "rightMargin"; type: "double" }
21+ Property { name: "colorFrom"; type: "QColor" }
22+ Property { name: "colorTo"; type: "QColor" }
23 name: "UCMouse"
24 prototype: "QObject"
25 exports: ["Mouse 0.1", "Mouse 1.0"]
26
27=== modified file 'modules/Ubuntu/Components/plugin/plugin.cpp'
28--- modules/Ubuntu/Components/plugin/plugin.cpp 2014-09-15 08:22:13 +0000
29+++ modules/Ubuntu/Components/plugin/plugin.cpp 2014-09-15 08:22:15 +0000
30@@ -162,6 +162,7 @@
31 // ListItem and related types
32 qmlRegisterType<UCListItem, 1>(uri, 1, 1, "ListItem");
33 qmlRegisterType<UCListItemContent>();
34+ qmlRegisterType<UCListItemDivider>();
35 }
36
37 void UbuntuComponentsPlugin::initializeEngine(QQmlEngine *engine, const char *uri)
38
39=== modified file 'modules/Ubuntu/Components/plugin/uclistitem.cpp'
40--- modules/Ubuntu/Components/plugin/uclistitem.cpp 2014-09-15 08:22:13 +0000
41+++ modules/Ubuntu/Components/plugin/uclistitem.cpp 2014-09-15 08:22:15 +0000
42@@ -35,7 +35,155 @@
43 }
44 return result;
45 }
46-
47+/******************************************************************************
48+ * Divider
49+ */
50+UCListItemDivider::UCListItemDivider(QObject *parent)
51+ : QObject(parent)
52+ , m_visible(true)
53+ , m_leftMarginChanged(false)
54+ , m_rightMarginChanged(false)
55+ , m_colorFromChanged(false)
56+ , m_colorToChanged(false)
57+ , m_thickness(0)
58+ , m_leftMargin(0)
59+ , m_rightMargin(0)
60+ , m_listItem(0)
61+{
62+ connect(&UCUnits::instance(), &UCUnits::gridUnitChanged, this, &UCListItemDivider::unitsChanged);
63+ connect(&UCTheme::instance(), &UCTheme::paletteChanged, this, &UCListItemDivider::paletteChanged);
64+ unitsChanged();
65+ paletteChanged();
66+}
67+UCListItemDivider::~UCListItemDivider()
68+{
69+}
70+
71+void UCListItemDivider::init(UCListItem *listItem)
72+{
73+ QQml_setParent_noEvent(this, listItem);
74+ m_listItem = UCListItemPrivate::get(listItem);
75+}
76+
77+void UCListItemDivider::unitsChanged()
78+{
79+ m_thickness = UCUnits::instance().dp(2);
80+ if (!m_leftMarginChanged) {
81+ m_leftMargin = UCUnits::instance().gu(2);
82+ }
83+ if (!m_rightMarginChanged) {
84+ m_rightMargin = UCUnits::instance().gu(2);
85+ }
86+ if (m_listItem) {
87+ m_listItem->update();
88+ }
89+}
90+
91+void UCListItemDivider::paletteChanged()
92+{
93+ QColor background = getPaletteColor("normal", "background");
94+ if (!background.isValid()) {
95+ return;
96+ }
97+ // FIXME: we need a palette value for divider colors, till then base on the background
98+ // luminance
99+ if (!m_colorFromChanged || !m_colorToChanged) {
100+ qreal luminance = (background.red()*212 + background.green()*715 + background.blue()*73)/1000.0/255.0;
101+ bool lightBackground = (luminance > 0.85);
102+ if (!m_colorFromChanged) {
103+ m_colorFrom = lightBackground ? QColor("#26000000") : QColor("#26FFFFFF");
104+ }
105+ if (!m_colorToChanged) {
106+ m_colorTo = lightBackground ? QColor("#14FFFFFF") : QColor("#14000000");
107+ }
108+ updateGradient();
109+ }
110+}
111+
112+void UCListItemDivider::updateGradient()
113+{
114+ m_gradient.clear();
115+ m_gradient.append(QGradientStop(0.0, m_colorFrom));
116+ m_gradient.append(QGradientStop(0.49, m_colorFrom));
117+ m_gradient.append(QGradientStop(0.5, m_colorTo));
118+ m_gradient.append(QGradientStop(1.0, m_colorTo));
119+ if (m_listItem) {
120+ m_listItem->update();
121+ }
122+}
123+
124+QSGNode *UCListItemDivider::paint(QSGNode *paintNode, const QRectF &rect)
125+{
126+ if (m_visible && (m_gradient.size() > 0)) {
127+ QSGRectangleNode *rectNode = static_cast<QSGRectangleNode *>(paintNode);
128+ if (!rectNode) {
129+ rectNode = m_listItem->sceneGraphContext()->createRectangleNode();
130+ }
131+ rectNode->setRect(QRectF(m_leftMargin, rect.height() - m_thickness,
132+ rect.width() - m_leftMargin - m_rightMargin, m_thickness));
133+ rectNode->setGradientStops(m_gradient);
134+ rectNode->update();
135+ return rectNode;
136+ } else {
137+ delete paintNode;
138+ return 0;
139+ }
140+}
141+
142+void UCListItemDivider::setVisible(bool visible)
143+{
144+ if (m_visible == visible) {
145+ return;
146+ }
147+ m_visible = visible;
148+ m_listItem->resize();
149+ m_listItem->update();
150+ Q_EMIT visibleChanged();
151+}
152+
153+void UCListItemDivider::setLeftMargin(qreal leftMargin)
154+{
155+ if (m_leftMargin == leftMargin) {
156+ return;
157+ }
158+ m_leftMargin = leftMargin;
159+ m_leftMarginChanged = true;
160+ m_listItem->update();
161+ Q_EMIT leftMarginChanged();
162+}
163+
164+void UCListItemDivider::setRightMargin(qreal rightMargin)
165+{
166+ if (m_rightMargin == rightMargin) {
167+ return;
168+ }
169+ m_rightMargin = rightMargin;
170+ m_rightMarginChanged = true;
171+ m_listItem->update();
172+ Q_EMIT rightMarginChanged();
173+}
174+
175+void UCListItemDivider::setColorFrom(const QColor &color)
176+{
177+ if (m_colorFrom == color) {
178+ return;
179+ }
180+ m_colorFrom = color;
181+ m_colorFromChanged = true;
182+ updateGradient();
183+ Q_EMIT colorFromChanged();
184+}
185+
186+void UCListItemDivider::setColorTo(const QColor &color)
187+{
188+ if (m_colorTo == color) {
189+ return;
190+ }
191+ m_colorTo = color;
192+ m_colorToChanged = true;
193+ updateGradient();
194+ Q_EMIT colorToChanged();
195+}
196
197 /******************************************************************************
198 * ListItemContent
199@@ -114,10 +262,14 @@
200 }
201
202
203+/******************************************************************************
204+ * ListItemBasePrivate
205+ */
206 UCListItemPrivate::UCListItemPrivate()
207 : UCStyledItemBasePrivate()
208 , pressed(false)
209 , contentItem(new UCListItemContent)
210+ , divider(new UCListItemDivider)
211 {
212 }
213 UCListItemPrivate::~UCListItemPrivate()
214@@ -130,6 +282,7 @@
215 contentItem->setObjectName("ListItemHolder");
216 QQml_setParent_noEvent(contentItem, q);
217 contentItem->setParentItem(q);
218+ divider->init(q);
219 // content will be redirected to the contentItem, therefore we must report
220 // children changes as it would come from the main component
221 QObject::connect(contentItem, &UCListItemContent::childrenChanged,
222@@ -185,11 +338,31 @@
223 if (flickable.isNull()) {
224 return;
225 }
226+ Q_Q(UCListItem);
227 if (listen) {
228- QObject::connect(flickable.data(), SIGNAL(movementStarted()), q_ptr, SLOT(_q_rebound()));
229+ QObject::connect(flickable.data(), SIGNAL(movementStarted()), q, SLOT(_q_rebound()));
230 } else {
231- QObject::disconnect(flickable.data(), SIGNAL(movementStarted()), q_ptr, SLOT(_q_rebound()));
232- }
233+ QObject::disconnect(flickable.data(), SIGNAL(movementStarted()), q, SLOT(_q_rebound()));
234+ }
235+}
236+
237+void UCListItemPrivate::resize()
238+{
239+ Q_Q(UCListItem);
240+ QRectF rect(q->boundingRect());
241+ if (divider && divider->m_visible) {
242+ rect.setHeight(rect.height() - divider->m_thickness);
243+ }
244+ contentItem->setSize(rect.size());
245+}
246+
247+void UCListItemPrivate::update()
248+{
249+ if (!ready) {
250+ return;
251+ }
252+ Q_Q(UCListItem);
253+ q->update();
254 }
255
256 /*!
257@@ -218,6 +391,10 @@
258 * revealed and thus will destroy your logic
259 * \li never anchor left or right anchor lines as it will block revealing the options.
260 * \endlist
261+ *
262+ * Each ListItem has a thin divider shown on the bottom of the component. This
263+ * divider can be configured through the \l divider grouped property, which can
264+ * configure its margins from the edges of the ListItem as well as its visibility.
265 */
266
267 /*!
268@@ -238,6 +415,12 @@
269 {
270 }
271
272+void UCListItem::componentComplete()
273+{
274+ UCStyledItemBase::componentComplete();
275+ d_func()->ready = true;
276+}
277+
278 void UCListItem::itemChange(ItemChange change, const ItemChangeData &data)
279 {
280 UCStyledItemBase::itemChange(change, data);
281@@ -269,11 +452,23 @@
282 void UCListItem::geometryChanged(const QRectF &newGeometry, const QRectF &oldGeometry)
283 {
284 UCStyledItemBase::geometryChanged(newGeometry, oldGeometry);
285- // resize contentItem item
286- Q_D(UCListItem);
287- QRectF rect(boundingRect());
288- d->contentItem->setSize(rect.size());
289-}
290+ // resize background item
291+ Q_D(UCListItem);
292+ d->resize();
293+}
294+
295+QSGNode *UCListItem::updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData *data)
296+{
297+ Q_UNUSED(data);
298+ Q_D(UCListItem);
299+ if (width() <= 0 || height() <= 0 || !d->divider) {
300+ delete oldNode;
301+ return 0;
302+ }
303+ // paint divider
304+ return d->divider->paint(oldNode, boundingRect());
305+}
306+
307 void UCListItem::mousePressEvent(QMouseEvent *event)
308 {
309 UCStyledItemBase::mousePressEvent(event);
310@@ -319,6 +514,33 @@
311 }
312
313 /*!
314+ * \qmlpropertygroup ::ListItem::divider
315+ * \qmlproperty bool ListItem::divider.visible
316+ * \qmlproperty real ListItem::divider.leftMargin
317+ * \qmlproperty real ListItem::divider.rightMargin
318+ *
319+ * This grouped property configures the thin divider shown in the bottom of the
320+ * component. Configures the visibility and the margins from the left and right
321+ * of the ListItem. When tugged (swiped left or right to reveal the options),
322+ * it is not moved together with the content.
323+ *
324+ * When \c visible is true, the ListItem's content size gets thinner with the
325+ * divider's \c thickness.
326+ *
327+ * The default values for the properties are:
328+ * \list
329+ * \li \c visible: true
330+ * \li \c leftMargin: 2 GU
331+ * \li \c rightMargin: 2 GU
332+ * \endlist
333+ */
334+UCListItemDivider* UCListItem::divider() const
335+{
336+ Q_D(const UCListItem);
337+ return d->divider;
338+}
339+
340+/*!
341 * \qmlproperty bool ListItem::pressed
342 * True when the item is pressed. The items stays pressed when the mouse or touch
343 * is moved horizontally. When in Flickable (or ListView), the item gets un-pressed
344
345=== modified file 'modules/Ubuntu/Components/plugin/uclistitem.h'
346--- modules/Ubuntu/Components/plugin/uclistitem.h 2014-09-15 08:22:13 +0000
347+++ modules/Ubuntu/Components/plugin/uclistitem.h 2014-09-15 08:22:15 +0000
348@@ -21,11 +21,13 @@
349 #include "ucstyleditembase.h"
350
351 class UCListItemContent;
352+class UCListItemDivider;
353 class UCListItemPrivate;
354 class UCListItem : public UCStyledItemBase
355 {
356 Q_OBJECT
357 Q_PROPERTY(UCListItemContent *contentItem READ contentItem CONSTANT)
358+ Q_PROPERTY(UCListItemDivider *divider READ divider CONSTANT)
359 Q_PROPERTY(bool pressed READ pressed NOTIFY pressedChanged)
360 Q_PROPERTY(QQmlListProperty<QObject> data READ data DESIGNABLE false)
361 Q_PROPERTY(QQmlListProperty<QQuickItem> children READ children NOTIFY childrenChanged DESIGNABLE false)
362@@ -35,10 +37,13 @@
363 ~UCListItem();
364
365 UCListItemContent *contentItem() const;
366+ UCListItemDivider *divider() const;
367 bool pressed() const;
368
369 protected:
370+ void componentComplete();
371 void itemChange(ItemChange change, const ItemChangeData &data);
372+ QSGNode *updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData *data);
373 void geometryChanged(const QRectF &newGeometry, const QRectF &oldGeometry);
374 void mousePressEvent(QMouseEvent *event);
375 void mouseReleaseEvent(QMouseEvent *event);
376
377=== modified file 'modules/Ubuntu/Components/plugin/uclistitem_p.h'
378--- modules/Ubuntu/Components/plugin/uclistitem_p.h 2014-09-15 08:22:13 +0000
379+++ modules/Ubuntu/Components/plugin/uclistitem_p.h 2014-09-15 08:22:15 +0000
380@@ -20,9 +20,11 @@
381 #include "uclistitem.h"
382 #include "ucstyleditembase_p.h"
383 #include <QtCore/QPointer>
384+#include <QtQuick/private/qquickrectangle_p.h>
385
386 class QQuickFlickable;
387 class UCListItemContent;
388+class UCListItemDivider;
389 class UCListItemPrivate : public UCStyledItemBasePrivate
390 {
391 Q_DECLARE_PUBLIC(UCListItem)
392@@ -44,10 +46,14 @@
393 void _q_updateSize();
394 void setPressed(bool pressed);
395 void listenToRebind(bool listen);
396+ void resize();
397+ void update();
398
399 bool pressed:1;
400+ bool ready:1;
401 QPointer<QQuickFlickable> flickable;
402 UCListItemContent *contentItem;
403+ UCListItemDivider *divider;
404 };
405
406 class UCListItemContent : public QQuickItem
407@@ -80,8 +86,60 @@
408 bool m_pressedColorChanged:1;
409 };
410
411+class UCListItemDivider : public QObject
412+{
413+ Q_OBJECT
414+ Q_PROPERTY(bool visible MEMBER m_visible WRITE setVisible NOTIFY visibleChanged)
415+ Q_PROPERTY(qreal leftMargin MEMBER m_leftMargin WRITE setLeftMargin NOTIFY leftMarginChanged)
416+ Q_PROPERTY(qreal rightMargin MEMBER m_rightMargin WRITE setRightMargin NOTIFY rightMarginChanged)
417+ Q_PROPERTY(QColor colorFrom MEMBER m_colorFrom WRITE setColorFrom NOTIFY colorFromChanged)
418+ Q_PROPERTY(QColor colorTo MEMBER m_colorTo WRITE setColorTo NOTIFY colorToChanged)
419+public:
420+ explicit UCListItemDivider(QObject *parent = 0);
421+ ~UCListItemDivider();
422+ void init(UCListItem *listItem);
423+
424+Q_SIGNALS:
425+ void visibleChanged();
426+ void leftMarginChanged();
427+ void rightMarginChanged();
428+ void colorFromChanged();
429+ void colorToChanged();
430+
431+protected:
432+ QSGNode *paint(QSGNode *paintNode, const QRectF &rect);
433+
434+private Q_SLOTS:
435+ void unitsChanged();
436+ void paletteChanged();
437+
438+private:
439+ void updateGradient();
440+ void setVisible(bool visible);
441+ void setLeftMargin(qreal leftMargin);
442+ void setRightMargin(qreal rightMargin);
443+ void setColorFrom(const QColor &color);
444+ void setColorTo(const QColor &color);
445+
446+ bool m_visible:1;
447+ bool m_leftMarginChanged:1;
448+ bool m_rightMarginChanged:1;
449+ bool m_colorFromChanged:1;
450+ bool m_colorToChanged:1;
451+ qreal m_thickness;
452+ qreal m_leftMargin;
453+ qreal m_rightMargin;
454+ QColor m_colorFrom;
455+ QColor m_colorTo;
456+ QGradientStops m_gradient;
457+ UCListItemPrivate *m_listItem;
458+ friend class UCListItem;
459+ friend class UCListItemPrivate;
460+};
461+
462 QColor getPaletteColor(const char *profile, const char *color);
463
464 QML_DECLARE_TYPE(UCListItemContent)
465+QML_DECLARE_TYPE(UCListItemDivider)
466
467 #endif // UCVIEWITEM_P_H
468
469=== modified file 'tests/resources/listitems/ListItemTest.qml'
470--- tests/resources/listitems/ListItemTest.qml 2014-09-15 08:22:13 +0000
471+++ tests/resources/listitems/ListItemTest.qml 2014-09-15 08:22:15 +0000
472@@ -37,18 +37,23 @@
473 print("click")
474 main.override = !main.override
475 }
476+ Label {
477+ anchors.fill: parent
478+ text: units.gridUnit + "PX/unit"
479+ }
480 }
481
482 ListView {
483 id: view
484 clip: true
485 width: parent.width
486- height: units.gu(40)
487+ height: units.gu(20)
488 model: 100
489 pressDelay: 0
490 delegate: ListItem {
491 id: listItem
492 onClicked: print(" clicked")
493+
494 Label {
495 text: modelData + " item"
496 }
497@@ -65,7 +70,7 @@
498 Flickable {
499 id: flicker
500 width: parent.width
501- height: units.gu(40)
502+ height: units.gu(20)
503 clip: true
504 contentHeight: column.childrenRect.height
505 Column {
506@@ -78,6 +83,12 @@
507 color: "red"
508 pressedColor: "lime"
509 }
510+ divider.colorFrom: UbuntuColors.green
511+
512+ Label {
513+ text: modelData + " Flickable item"
514+ }
515+ onClicked: divider.visible = !divider.visible
516 }
517 }
518 }
519
520=== modified file 'tests/unit_x11/tst_components/tst_listitem.qml'
521--- tests/unit_x11/tst_components/tst_listitem.qml 2014-09-15 08:22:13 +0000
522+++ tests/unit_x11/tst_components/tst_listitem.qml 2014-09-15 08:22:15 +0000
523@@ -87,6 +87,13 @@
524 compare(defaults.contentItem.color, "#000000", "Transparent by default");
525 compare(defaults.contentItem.pressedColor, Theme.palette.selected.background, "Theme.palette.selected.background color by default")
526 compare(defaults.pressed, false, "Not pressed buy default");
527+ compare(defaults.divider.visible, true, "divider is visible by default");
528+ compare(defaults.divider.leftMargin, units.gu(2), "divider's left margin is 2GU");
529+ compare(defaults.divider.rightMargin, units.gu(2), "divider's right margin is 2GU");
530+ compare(defaults.divider.colorFrom, "#000000", "colorFrom differs.");
531+ fuzzyCompare(defaults.divider.colorFrom.a, 0.14, 0.01, "colorFrom alpha differs");
532+ compare(defaults.divider.colorTo, "#ffffff", "colorTo differs.");
533+ fuzzyCompare(defaults.divider.colorTo.a, 0.07, 0.01, "colorTo alpha differs");
534 }
535
536 function test_children_in_content_item() {
537@@ -145,5 +152,14 @@
538 compare(listItem.pressed, false, "Item is pressed still!");
539 TestExtras.touchRelease(0, listItem, Qt.point(listItem.width / 2, dy));
540 }
541+
542+ function test_background_height_change_on_divider_visible() {
543+ // make sure the testItem's divider is shown
544+ testItem.divider.visible = true;
545+ verify(testItem.contentItem.height < testItem.height, "ListItem's background height must be less than the item itself.");
546+ testItem.divider.visible = false;
547+ compare(testItem.contentItem.height, testItem.height, "ListItem's background height must be the same as the item itself.");
548+ testItem.divider.visible = true;
549+ }
550 }
551 }

Subscribers

People subscribed via source and target branches

to all changes: