Merge lp:~zsombi/ubuntu-ui-toolkit/increasedSensingArea into lp:ubuntu-ui-toolkit/staging

Proposed by Zsombor Egri
Status: Merged
Approved by: Tim Peeters
Approved revision: 1731
Merged at revision: 1866
Proposed branch: lp:~zsombi/ubuntu-ui-toolkit/increasedSensingArea
Merge into: lp:ubuntu-ui-toolkit/staging
Diff against target: 565 lines (+375/-0)
8 files modified
components.api (+7/-0)
src/Ubuntu/Components/plugin/plugin.cpp (+1/-0)
src/Ubuntu/Components/plugin/plugin.pri (+1/-0)
src/Ubuntu/Components/plugin/ucabstractbutton.cpp (+135/-0)
src/Ubuntu/Components/plugin/ucabstractbutton.h (+9/-0)
src/Ubuntu/Components/plugin/ucabstractbutton_p.h (+2/-0)
src/Ubuntu/Components/plugin/ucmargins.h (+76/-0)
tests/unit_x11/tst_components/tst_abstractbutton13.qml (+144/-0)
To merge this branch: bzr merge lp:~zsombi/ubuntu-ui-toolkit/increasedSensingArea
Reviewer Review Type Date Requested Status
ubuntu-sdk-build-bot continuous-integration Approve
Tim Peeters Approve
PS Jenkins bot continuous-integration Needs Fixing
Review via email: mp+277450@code.launchpad.net

Commit message

AbstractButton handles 4x4GU minimal sensing area, exposes sensingMargins to extend sensing area even further.

To post a comment you must log in.
Revision history for this message
Andrea Bernabei (faenil) wrote :

left some comments :)

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

> left some comments :)

See my replies inline.

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

> > left some comments :)
>
> See my replies inline.

Ehm... seems the comments got vanished :/

Anyways, the comments were applied, see below, except the 8mm not being 4GU, we measured it, it is approximately 4GU everywhere. Remember, the GU is chosen to show the same size everywhere. And N10 is NOT (and I really mean it!!!!) 90 GU for sure! N7 is, but N10 is NOT. Please!!! It's like Bq and Meizu having the same GU width/height!!! Forget that, it's bullshit!!!

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
Revision history for this message
ubuntu-sdk-build-bot (ubuntu-sdk-build-bot) wrote :
review: Approve (continuous-integration)
Revision history for this message
ubuntu-sdk-build-bot (ubuntu-sdk-build-bot) wrote :
review: Needs Fixing (continuous-integration)
Revision history for this message
ubuntu-sdk-build-bot (ubuntu-sdk-build-bot) wrote :
review: Approve (continuous-integration)
Revision history for this message
ubuntu-sdk-build-bot (ubuntu-sdk-build-bot) wrote :
review: Approve (continuous-integration)
Revision history for this message
ubuntu-sdk-build-bot (ubuntu-sdk-build-bot) wrote :
review: Needs Fixing (continuous-integration)
Revision history for this message
Tim Peeters (tpeeters) wrote :

         function cleanup() {
417 + buttonWithSensing.sensingMargins.left =
418 + buttonWithSensing.sensingMargins.top =
419 + buttonWithSensing.sensingMargins.right =
420 + buttonWithSensing.sensingMargins.bottom =
421 + buttonWithSensing.sensingMargins.all = 0;
422 + buttonWithSensing.width = 0;
423 + buttonWithSensing.height = 0;
424 + signalSpy.target = absButton;

I suggest to use some indentation here to make it not misleading for a human reader.

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

^or add 0; to each line.

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

There is no unit test for:
1. Negative sensing margins
2. Initializing a component with sensor margins (without setting them in JS afterwards)

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

> There is no unit test for:
> 1. Negative sensing margins

This makes sense. Will add a test case for that!

> 2. Initializing a component with sensor margins (without setting them in JS
> afterwards)

What is the difference? They both call the setters...

1728. By Zsombor Egri

more tests added

1729. By Zsombor Egri

getting branch head in sync

Revision history for this message
ubuntu-sdk-build-bot (ubuntu-sdk-build-bot) wrote :
review: Needs Fixing (continuous-integration)
Revision history for this message
ubuntu-sdk-build-bot (ubuntu-sdk-build-bot) wrote :
review: Needs Fixing (continuous-integration)
Revision history for this message
ubuntu-sdk-build-bot (ubuntu-sdk-build-bot) wrote :
review: Needs Fixing (continuous-integration)
Revision history for this message
ubuntu-sdk-build-bot (ubuntu-sdk-build-bot) wrote :
review: Approve (continuous-integration)
Revision history for this message
ubuntu-sdk-build-bot (ubuntu-sdk-build-bot) wrote :
review: Needs Fixing (continuous-integration)
1730. By Zsombor Egri

roll back a floating change

1731. By Zsombor Egri

staging sync

Revision history for this message
ubuntu-sdk-build-bot (ubuntu-sdk-build-bot) wrote :
review: Approve (continuous-integration)
Revision history for this message
ubuntu-sdk-build-bot (ubuntu-sdk-build-bot) wrote :
review: Approve (continuous-integration)
Revision history for this message
ubuntu-sdk-build-bot (ubuntu-sdk-build-bot) wrote :
review: Approve (continuous-integration)
Revision history for this message
ubuntu-sdk-build-bot (ubuntu-sdk-build-bot) wrote :
review: Approve (continuous-integration)
Revision history for this message
ubuntu-sdk-build-bot (ubuntu-sdk-build-bot) wrote :
review: Approve (continuous-integration)
Revision history for this message
Tim Peeters (tpeeters) wrote :

Looks good, thanks.

review: Approve
Revision history for this message
ubuntu-sdk-build-bot (ubuntu-sdk-build-bot) wrote :
review: Approve (continuous-integration)
Revision history for this message
ubuntu-sdk-build-bot (ubuntu-sdk-build-bot) wrote :
review: Approve (continuous-integration)
Revision history for this message
ubuntu-sdk-build-bot (ubuntu-sdk-build-bot) wrote :
review: Approve (continuous-integration)
Revision history for this message
ubuntu-sdk-build-bot (ubuntu-sdk-build-bot) wrote :
review: Approve (continuous-integration)

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file 'components.api'
--- components.api 2016-02-17 12:57:49 +0000
+++ components.api 2016-02-24 06:31:56 +0000
@@ -8,6 +8,7 @@
8 signal clicked()8 signal clicked()
9 signal pressAndHold()9 signal pressAndHold()
10 readonly property bool pressed10 readonly property bool pressed
11 readonly property UCMargins sensingMargins
11Ubuntu.Components.Action 1.3 1.0 0.1 UCAction: QtObject12Ubuntu.Components.Action 1.3 1.0 0.1 UCAction: QtObject
12 property string description13 property string description
13 property bool enabled14 property bool enabled
@@ -1557,6 +1558,12 @@
1557UCListItemExpansion: QtObject1558UCListItemExpansion: QtObject
1558 property bool expanded1559 property bool expanded
1559 property double height1560 property double height
1561UCMargins: QtObject
1562 property double all
1563 property double bottom
1564 property double left
1565 property double right
1566 property double top
1560UCStateSaverAttached: QtObject1567UCStateSaverAttached: QtObject
1561 property bool enabled1568 property bool enabled
1562 property string properties1569 property string properties
15631570
=== modified file 'src/Ubuntu/Components/plugin/plugin.cpp'
--- src/Ubuntu/Components/plugin/plugin.cpp 2016-02-12 13:46:51 +0000
+++ src/Ubuntu/Components/plugin/plugin.cpp 2016-02-24 06:31:56 +0000
@@ -222,6 +222,7 @@
222 qmlRegisterType<UCProportionalShape>(uri, 1, 3, "ProportionalShape");222 qmlRegisterType<UCProportionalShape>(uri, 1, 3, "ProportionalShape");
223 qmlRegisterType<LiveTimer>(uri, 1, 3, "LiveTimer");223 qmlRegisterType<LiveTimer>(uri, 1, 3, "LiveTimer");
224 qmlRegisterType<UCAbstractButton>(uri, 1, 3, "AbstractButton");224 qmlRegisterType<UCAbstractButton>(uri, 1, 3, "AbstractButton");
225 qmlRegisterType<UCMargins>();
225 qmlRegisterUncreatableType<UCSlotsAttached>(uri, 1, 3, "SlotsAttached", "Not instantiable");226 qmlRegisterUncreatableType<UCSlotsAttached>(uri, 1, 3, "SlotsAttached", "Not instantiable");
226 qmlRegisterUncreatableType<UCSlotsLayoutPadding>(uri, 1, 3, "SlotsLayoutPadding", "Not instantiable");227 qmlRegisterUncreatableType<UCSlotsLayoutPadding>(uri, 1, 3, "SlotsLayoutPadding", "Not instantiable");
227 qmlRegisterType<UCListItemLayout>(uri, 1, 3, "ListItemLayout");228 qmlRegisterType<UCListItemLayout>(uri, 1, 3, "ListItemLayout");
228229
=== modified file 'src/Ubuntu/Components/plugin/plugin.pri'
--- src/Ubuntu/Components/plugin/plugin.pri 2016-02-08 12:47:32 +0000
+++ src/Ubuntu/Components/plugin/plugin.pri 2016-02-24 06:31:56 +0000
@@ -90,6 +90,7 @@
90 $$PWD/uchaptics.h \90 $$PWD/uchaptics.h \
91 $$PWD/ucabstractbutton.h \91 $$PWD/ucabstractbutton.h \
92 $$PWD/ucabstractbutton_p.h \92 $$PWD/ucabstractbutton_p.h \
93 $$PWD/ucmargins.h \
93 $$PWD/ucthemingextension.h \94 $$PWD/ucthemingextension.h \
94 $$PWD/ucheader.h \95 $$PWD/ucheader.h \
95 $$PWD/uclabel.h \96 $$PWD/uclabel.h \
9697
=== modified file 'src/Ubuntu/Components/plugin/ucabstractbutton.cpp'
--- src/Ubuntu/Components/plugin/ucabstractbutton.cpp 2016-02-11 08:54:26 +0000
+++ src/Ubuntu/Components/plugin/ucabstractbutton.cpp 2016-02-24 06:31:56 +0000
@@ -17,11 +17,15 @@
17#include "ucabstractbutton.h"17#include "ucabstractbutton.h"
18#include "ucabstractbutton_p.h"18#include "ucabstractbutton_p.h"
19#include "uchaptics.h"19#include "uchaptics.h"
20#include "ucunits.h"
20#include "ucaction.h"21#include "ucaction.h"
21#include <QtQuick/private/qquickitem_p.h>22#include <QtQuick/private/qquickitem_p.h>
22#include <QtQuick/private/qquickmousearea_p.h>23#include <QtQuick/private/qquickmousearea_p.h>
23#include <QtQml/private/qqmlglobal_p.h>24#include <QtQml/private/qqmlglobal_p.h>
2425
26#define MIN_SENSING_WIDTH_GU 4
27#define MIN_SENSING_HEIGHT_GU 4
28
25UCAbstractButtonPrivate::UCAbstractButtonPrivate()29UCAbstractButtonPrivate::UCAbstractButtonPrivate()
26 : UCActionItemPrivate()30 : UCActionItemPrivate()
27 , mouseArea(new QQuickMouseArea)31 , mouseArea(new QQuickMouseArea)
@@ -39,6 +43,7 @@
39/*!43/*!
40 \qmltype AbstractButton44 \qmltype AbstractButton
41 \instantiates UCAbstractButton45 \instantiates UCAbstractButton
46 \inherits ActionItem
42 \inqmlmodule Ubuntu.Components 1.147 \inqmlmodule Ubuntu.Components 1.1
43 \ingroup ubuntu48 \ingroup ubuntu
44 \brief The AbstractButton class defines the behavior of the button.49 \brief The AbstractButton class defines the behavior of the button.
@@ -49,6 +54,34 @@
49 If an action is specified, the button's clicked signal will trigger the action.54 If an action is specified, the button's clicked signal will trigger the action.
50 Subclasses of AbstractButton can use other properties of action (for example55 Subclasses of AbstractButton can use other properties of action (for example
51 the text and iconName).56 the text and iconName).
57
58 \section2 Sensing area
59 It has been proven that, on touch devices in order to properly aim an active
60 component a minimum of 8x8 millimeters (i.e. 4x4 grid units) area has to be
61 provided. However not all the visuals are of that size, as Icons for example
62 are defaulted to be 2x2 grid units, but a component containing a single Icon
63 still has to be able to capture the press events. Therefore AbstractButton
64 makes sure this rule of 4x4 grid units for the sensing area is provided. In
65 addition it exposes the \l sensingMargins property which extends the component's
66 sensing area in all the directions, so other use cases when the sensing area
67 needs to be extended outside of the component's area, or restricted on a
68 given area of the component can be implemented. The following example extends
69 the sensing area on the left, top and bottom with 1 grid units, and on the
70 right with 10 grid units.
71 \qml
72 AbstractButton {
73 width: units.gu(2)
74 height: units.gu(2)
75 sensingMargins {
76 left: units.gu(1)
77 top: units.gu(1)
78 bottom: units.gu(1)
79 right: units.gu(10)
80 }
81 }
82 \endqml
83 \note Do not set clipping for the component as that will restrict the sensing
84 area to be available on the visual area only.
52*/85*/
5386
54/*!87/*!
@@ -111,6 +144,9 @@
111 UCActionItemPrivate::completeComponentInitialization();144 UCActionItemPrivate::completeComponentInitialization();
112 Q_Q(UCAbstractButton);145 Q_Q(UCAbstractButton);
113146
147 // adjust sensing area
148 _q_adjustSensingArea();
149
114 // bind mouse area150 // bind mouse area
115 QObject::connect(mouseArea, &QQuickMouseArea::pressedChanged, q, &UCAbstractButton::pressedChanged);151 QObject::connect(mouseArea, &QQuickMouseArea::pressedChanged, q, &UCAbstractButton::pressedChanged);
116 QObject::connect(mouseArea, &QQuickMouseArea::hoveredChanged, q, &UCAbstractButton::hoveredChanged);152 QObject::connect(mouseArea, &QQuickMouseArea::hoveredChanged, q, &UCAbstractButton::hoveredChanged);
@@ -122,6 +158,9 @@
122// may not be available on compoennt completion158// may not be available on compoennt completion
123void UCAbstractButtonPrivate::_q_mouseAreaPressed()159void UCAbstractButtonPrivate::_q_mouseAreaPressed()
124{160{
161 if (!mouseArea->pressed()) {
162 return;
163 }
125 bool longPressConnected = isPressAndHoldConnected();164 bool longPressConnected = isPressAndHoldConnected();
126 Q_Q(UCAbstractButton);165 Q_Q(UCAbstractButton);
127 if (longPressConnected && !pressAndHoldConnected) {166 if (longPressConnected && !pressAndHoldConnected) {
@@ -175,6 +214,48 @@
175 }214 }
176}215}
177216
217void UCAbstractButtonPrivate::_q_adjustSensingArea()
218{
219 Q_Q(UCAbstractButton);
220 if (!componentComplete) {
221 // we do not hammer the component until completion
222 return;
223 }
224 // use the sensingMargins in the minimum calculation
225 qreal minimumWidth = UCUnits::instance()->gu(MIN_SENSING_WIDTH_GU);
226 qreal minimumHeight = UCUnits::instance()->gu(MIN_SENSING_HEIGHT_GU);
227 qreal hDelta = minimumWidth
228 - (q->width() + (sensingMargins ? (sensingMargins->left() + sensingMargins->right()) : 0.0));
229 qreal vDelta = minimumHeight
230 - (q->height() + (sensingMargins ? (sensingMargins->top() + sensingMargins->bottom()) : 0.0));
231 // adjust the sensing area
232 QQuickAnchors *mouseAreaAnchors = QQuickItemPrivate::get(mouseArea)->anchors();
233 if (hDelta >= 0) {
234 // the horizontal size is still smaller than the minimum
235 mouseAreaAnchors->setLeftMargin(-(hDelta / 2 + (sensingMargins ? sensingMargins->left() : 0.0)));
236 mouseAreaAnchors->setRightMargin(-(hDelta / 2 + (sensingMargins ? sensingMargins->right() : 0.0)));
237 } else if (sensingMargins) {
238 mouseAreaAnchors->setLeftMargin(-sensingMargins->left());
239 mouseAreaAnchors->setRightMargin(-sensingMargins->right());
240 }
241 if (vDelta >= 0) {
242 // the vertical size is still smaller than the minimum
243 mouseAreaAnchors->setTopMargin(-(vDelta / 2 + (sensingMargins ? sensingMargins->top() : 0.0)));
244 mouseAreaAnchors->setBottomMargin(-(vDelta / 2 + (sensingMargins ? sensingMargins->bottom() : 0.0)));
245 } else if (sensingMargins) {
246 mouseAreaAnchors->setTopMargin(-sensingMargins->top());
247 mouseAreaAnchors->setBottomMargin(-sensingMargins->bottom());
248 }
249}
250
251void UCAbstractButton::geometryChanged(const QRectF &newGeometry, const QRectF &oldGeometry)
252{
253 UCActionItem::geometryChanged(newGeometry, oldGeometry);
254
255 // adjust internal mouse area's size
256 d_func()->_q_adjustSensingArea();
257}
258
178/*!259/*!
179 * \qmlproperty bool AbstractButton::pressed260 * \qmlproperty bool AbstractButton::pressed
180 * True if the user presses a mouse button in the button's mouse area.261 * True if the user presses a mouse button in the button's mouse area.
@@ -212,4 +293,58 @@
212 return d->mouseArea;293 return d->mouseArea;
213}294}
214295
296/*!
297 * \qmlpropertygroup ::AbstractButton::sensingMargins
298 * \qmlproperty real AbstractButton::sensingMargins.left
299 * \qmlproperty real AbstractButton::sensingMargins.right
300 * \qmlproperty real AbstractButton::sensingMargins.top
301 * \qmlproperty real AbstractButton::sensingMargins.bottom
302 * \qmlproperty real AbstractButton::sensingMargins.all
303 * The property group specifies the margins extending the visual area where the
304 * touch and mouse events are sensed. Positive values mean the area will be extended
305 * on the specified direction outside of the visual area, negative values mean
306 * the sensing will fall under the component's visual border.
307 * All values default to 0.
308 *
309 * \note If the visual area and the sensing margins are not reaching the 4x4 grid
310 * units limit, the component will fall back to these minimum limits.
311 * For example, extending a 2x2 grid unit visual component into 5x4 grid units
312 * sensing area would look as follows:
313 * \qml
314 * AbstractButton {
315 * width: units.gu(2)
316 * height: units.gu(2)
317 * Icon {
318 * name: "settings"
319 * }
320 * sensingArea {
321 * // no need to set the vertical direction as the minimum of
322 * // 4 grid units will be taken automatically
323 * leftMargin: units.gu(1)
324 * // we only have to add 2 grid units as the width + left margin
325 * // already gives us 3 grid units out of 5
326 * rightMargin: units.gu(2)
327 * }
328 * }
329 * \endqml
330 */
331UCMargins *UCAbstractButton::sensingMargins()
332{
333 Q_D(UCAbstractButton);
334 if (!d->sensingMargins) {
335 d->sensingMargins = new UCMargins(this);
336
337 // as this is the first time we create the sensing margins we only
338 // connect now to grid unit changes to keep sensing area size in sync
339 connect(UCUnits::instance(), SIGNAL(gridUnitChanged()), this, SLOT(_q_adjustSensingArea()));
340 // also connect to the margin changes
341 connect(d->sensingMargins, SIGNAL(leftChanged()), this, SLOT(_q_adjustSensingArea()));
342 connect(d->sensingMargins, SIGNAL(rightChanged()), this, SLOT(_q_adjustSensingArea()));
343 connect(d->sensingMargins, SIGNAL(topChanged()), this, SLOT(_q_adjustSensingArea()));
344 connect(d->sensingMargins, SIGNAL(bottomChanged()), this, SLOT(_q_adjustSensingArea()));
345 connect(d->sensingMargins, SIGNAL(allChanged()), this, SLOT(_q_adjustSensingArea()));
346 }
347 return d->sensingMargins;
348}
349
215#include "moc_ucabstractbutton.cpp"350#include "moc_ucabstractbutton.cpp"
216351
=== modified file 'src/Ubuntu/Components/plugin/ucabstractbutton.h'
--- src/Ubuntu/Components/plugin/ucabstractbutton.h 2015-12-17 13:00:10 +0000
+++ src/Ubuntu/Components/plugin/ucabstractbutton.h 2016-02-24 06:31:56 +0000
@@ -18,6 +18,8 @@
18#define UCABSTRACTBUTTON_H18#define UCABSTRACTBUTTON_H
1919
20#include "ucactionitem.h"20#include "ucactionitem.h"
21#include "ucmargins.h"
22#include <QtQuick/private/qquickevents_p_p.h>
2123
22class QQuickMouseArea;24class QQuickMouseArea;
23class QQuickMouseEvent;25class QQuickMouseEvent;
@@ -27,6 +29,7 @@
27 Q_OBJECT29 Q_OBJECT
28 Q_PROPERTY(bool pressed READ pressed NOTIFY pressedChanged)30 Q_PROPERTY(bool pressed READ pressed NOTIFY pressedChanged)
29 Q_PROPERTY(bool hovered READ hovered NOTIFY hoveredChanged)31 Q_PROPERTY(bool hovered READ hovered NOTIFY hoveredChanged)
32 Q_PROPERTY(UCMargins *sensingMargins READ sensingMargins CONSTANT FINAL)
3033
31 // internal, declared to support the deprecated ListItem module34 // internal, declared to support the deprecated ListItem module
32 Q_PROPERTY(bool __acceptEvents READ acceptEvents WRITE setAcceptEvents)35 Q_PROPERTY(bool __acceptEvents READ acceptEvents WRITE setAcceptEvents)
@@ -36,6 +39,7 @@
3639
37 bool pressed() const;40 bool pressed() const;
38 bool hovered() const;41 bool hovered() const;
42 UCMargins *sensingMargins();
3943
40 bool privateAcceptEvents() const;44 bool privateAcceptEvents() const;
41 void setPrivateAcceptEvents(bool accept);45 void setPrivateAcceptEvents(bool accept);
@@ -45,6 +49,8 @@
4549
46protected:50protected:
47 void classBegin();51 void classBegin();
52 virtual void geometryChanged(const QRectF &newGeometry,
53 const QRectF &oldGeometry);
48 void keyReleaseEvent(QKeyEvent *key);54 void keyReleaseEvent(QKeyEvent *key);
4955
50Q_SIGNALS:56Q_SIGNALS:
@@ -60,6 +66,9 @@
60 Q_PRIVATE_SLOT(d_func(), void _q_mouseAreaPressed())66 Q_PRIVATE_SLOT(d_func(), void _q_mouseAreaPressed())
61 Q_PRIVATE_SLOT(d_func(), void _q_mouseAreaClicked())67 Q_PRIVATE_SLOT(d_func(), void _q_mouseAreaClicked())
62 Q_PRIVATE_SLOT(d_func(), void _q_mouseAreaPressAndHold())68 Q_PRIVATE_SLOT(d_func(), void _q_mouseAreaPressAndHold())
69 Q_PRIVATE_SLOT(d_func(), void _q_adjustSensingArea())
63};70};
6471
72QML_DECLARE_TYPE(UCMargins)
73
65#endif // UCABSTRACTBUTTON_H74#endif // UCABSTRACTBUTTON_H
6675
=== modified file 'src/Ubuntu/Components/plugin/ucabstractbutton_p.h'
--- src/Ubuntu/Components/plugin/ucabstractbutton_p.h 2015-12-17 13:00:10 +0000
+++ src/Ubuntu/Components/plugin/ucabstractbutton_p.h 2016-02-24 06:31:56 +0000
@@ -41,8 +41,10 @@
41 void _q_mouseAreaPressed();41 void _q_mouseAreaPressed();
42 void _q_mouseAreaClicked();42 void _q_mouseAreaClicked();
43 void _q_mouseAreaPressAndHold();43 void _q_mouseAreaPressAndHold();
44 void _q_adjustSensingArea();
4445
45 QQuickMouseArea *mouseArea;46 QQuickMouseArea *mouseArea;
47 UCMargins *sensingMargins = nullptr;
46 bool acceptEvents:1;48 bool acceptEvents:1;
47 bool pressAndHoldConnected:1;49 bool pressAndHoldConnected:1;
48};50};
4951
=== added file 'src/Ubuntu/Components/plugin/ucmargins.h'
--- src/Ubuntu/Components/plugin/ucmargins.h 1970-01-01 00:00:00 +0000
+++ src/Ubuntu/Components/plugin/ucmargins.h 2016-02-24 06:31:56 +0000
@@ -0,0 +1,76 @@
1/*
2 * Copyright 2015 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#ifndef UCMARGINS_H
18#define UCMARGINS_H
19
20#include <QtCore/QObject>
21#include <QtQuick/QQuickItem>
22
23class UCMargins : public QObject
24{
25 Q_OBJECT
26 Q_PROPERTY(qreal left MEMBER m_left NOTIFY leftChanged FINAL)
27 Q_PROPERTY(qreal top MEMBER m_top NOTIFY topChanged FINAL)
28 Q_PROPERTY(qreal right MEMBER m_right NOTIFY rightChanged FINAL)
29 Q_PROPERTY(qreal bottom MEMBER m_bottom NOTIFY bottomChanged FINAL)
30 Q_PROPERTY(qreal all MEMBER m_all NOTIFY allChanged FINAL)
31public:
32 UCMargins(QObject *parent = 0);
33
34 qreal left() const;
35 qreal top() const;
36 qreal right() const;
37 qreal bottom() const;
38
39Q_SIGNALS:
40 void leftChanged();
41 void topChanged();
42 void rightChanged();
43 void bottomChanged();
44 void allChanged();
45
46private:
47 qreal m_left = 0.0;
48 qreal m_top = 0.0;
49 qreal m_right = 0.0;
50 qreal m_bottom = 0.0;
51 qreal m_all = 0.0;
52};
53
54inline UCMargins::UCMargins(QObject *parent) : QObject(parent) {}
55
56inline qreal UCMargins::left() const
57{
58 return qFuzzyIsNull(m_left) ? m_all : m_left;
59}
60
61inline qreal UCMargins::top() const
62{
63 return qFuzzyIsNull(m_top) ? m_all : m_top;
64}
65
66inline qreal UCMargins::right() const
67{
68 return qFuzzyIsNull(m_right) ? m_all : m_right;
69}
70
71inline qreal UCMargins::bottom() const
72{
73 return qFuzzyIsNull(m_bottom) ? m_all : m_bottom;
74}
75
76#endif // UCMARGINS_H
077
=== modified file 'tests/unit_x11/tst_components/tst_abstractbutton13.qml'
--- tests/unit_x11/tst_components/tst_abstractbutton13.qml 2015-12-12 07:22:08 +0000
+++ tests/unit_x11/tst_components/tst_abstractbutton13.qml 2016-02-24 06:31:56 +0000
@@ -41,6 +41,41 @@
41 height: width41 height: width
42 function trigger() {}42 function trigger() {}
43 }43 }
44 Item {
45 // have enough space for the test subject
46 width: units.gu(10)
47 height: units.gu(10)
48 AbstractButton {
49 id: buttonWithSensing
50 anchors.centerIn: parent
51 }
52 }
53 Rectangle {
54 color: "red"
55 width: units.gu(10)
56 height: units.gu(10)
57 AbstractButton {
58 id: increasedSensing
59 anchors.centerIn: parent
60 width: units.gu(4)
61 height: units.gu(4)
62 sensingMargins {
63 left: units.gu(2)
64 right: units.gu(2)
65 top: units.gu(2)
66 bottom: units.gu(2)
67 }
68 style: Item {
69 anchors.fill: parent
70 Rectangle {
71 color: "blue"
72 parent: styledItem.__mouseArea
73 anchors.fill: parent
74 }
75 }
76 }
77 }
78
44 AbstractButton {79 AbstractButton {
45 id: suppressTrigger280 id: suppressTrigger2
46 width: units.gu(10)81 width: units.gu(10)
@@ -53,6 +88,7 @@
53 height: width88 height: width
54 function trigger(v) { triggered(v) }89 function trigger(v) { triggered(v) }
55 }90 }
91
56 Loader {92 Loader {
57 id: loader93 id: loader
58 width: units.gu(10)94 width: units.gu(10)
@@ -103,6 +139,14 @@
103 when: windowShown139 when: windowShown
104140
105 function cleanup() {141 function cleanup() {
142 buttonWithSensing.sensingMargins.left = 0;
143 buttonWithSensing.sensingMargins.top = 0;
144 buttonWithSensing.sensingMargins.right = 0;
145 buttonWithSensing.sensingMargins.bottom = 0;
146 buttonWithSensing.sensingMargins.all = 0;
147 buttonWithSensing.width = 0;
148 buttonWithSensing.height = 0;
149 signalSpy.target = absButton;
106 signalSpy.clear();150 signalSpy.clear();
107 signalSpy.target = absButton;151 signalSpy.target = absButton;
108 triggeredSpy.clear();152 triggeredSpy.clear();
@@ -110,6 +154,14 @@
110 loader.longPress = false;154 loader.longPress = false;
111 }155 }
112156
157 function initTestCase() {
158 compare(buttonWithSensing.sensingMargins.left, 0);
159 compare(buttonWithSensing.sensingMargins.right, 0);
160 compare(buttonWithSensing.sensingMargins.top, 0);
161 compare(buttonWithSensing.sensingMargins.bottom, 0);
162 compare(buttonWithSensing.sensingMargins.all, 0);
163 }
164
113 function test_action() {165 function test_action() {
114 compare(absButton.action, null,"Action is null by default")166 compare(absButton.action, null,"Action is null by default")
115 absButton.action = action1167 absButton.action = action1
@@ -184,5 +236,97 @@
184 mouseClick(loader.item, centerOf(loader.item).x, centerOf(loader.item).y);236 mouseClick(loader.item, centerOf(loader.item).x, centerOf(loader.item).y);
185 compare(loader.click, true, "clicked not captured by Connection");237 compare(loader.click, true, "clicked not captured by Connection");
186 }238 }
239
240 function test_sensing_area_data() {
241 return [
242 // margins is [left, top, right, bottom]
243 {tag: "zero size, no margins, click in visual", sizeGU: [0, 0], clickGU: [0, 0], sensingGU: [4, 4]},
244 {tag: "zero size, no margins, click in sensing", sizeGU: [0, 0], clickGU: [4, 4], sensingGU: [4, 4]},
245 {tag: "zero size, 1GU margins, click in visual", sizeGU: [0, 0], marginsGU: [1, 1, 1, 1], clickGU: [0, 0], sensingGU: [4, 4]},
246 {tag: "zero size, 1GU margins, click in sensing", sizeGU: [0, 0], marginsGU: [1, 1, 1, 1], clickGU: [4, 4], sensingGU: [4, 4]},
247 {tag: "zero size, 3GU margins horizontal, click in sensing", sizeGU: [0, 0], marginsGU: [3, 0, 3, 0], clickGU: [4, 4], sensingGU: [6, 4]},
248 {tag: "zero size, 3GU margins vertical, click in sensing", sizeGU: [0, 0], marginsGU: [0, 3, 0, 3], clickGU: [4, 4], sensingGU: [4, 6]},
249 {tag: "zero size, 3GU margins around, click in sensing", sizeGU: [0, 0], marginsGU: [3, 3, 3, 3], clickGU: [4, 4], sensingGU: [6, 6]},
250
251 {tag: "3x3GU size, no margins, click in visual", sizeGU: [3, 3], clickGU: [0, 0], sensingGU: [4, 4]},
252 {tag: "3x3GU size, no margins, click in sensing", sizeGU: [3, 3], clickGU: [4, 4], sensingGU: [4, 4]},
253 {tag: "3x3GU size, 1GU margins, click in visual", sizeGU: [3, 3], marginsGU: [1, 1, 1, 1], clickGU: [0, 0], sensingGU: [5, 5]},
254 {tag: "3x3GU size, 1GU margins, click in sensing", sizeGU: [3, 3], marginsGU: [1, 1, 1, 1], clickGU: [4, 4], sensingGU: [5, 5]},
255 {tag: "3x3GU size, 3GU margins horizontal, click in sensing", sizeGU: [3, 3], marginsGU: [3, 0, 3, 0], clickGU: [4, 4], sensingGU: [9, 4]},
256 {tag: "3x3GU size, 3GU margins vertical, click in sensing", sizeGU: [3, 3], marginsGU: [0, 3, 0, 3], clickGU: [4, 4], sensingGU: [4, 9]},
257 {tag: "3x3GU size, 3GU margins around, click in sensing", sizeGU: [3, 3], marginsGU: [3, 3, 3, 3], clickGU: [4, 4], sensingGU: [9, 9]},
258
259 {tag: "5x5GU size, no margins, click in visual", sizeGU: [5, 5], clickGU: [0, 0], sensingGU: [5, 5]},
260 {tag: "5x5GU size, no margins, click in sensing", sizeGU: [5, 5], clickGU: [4, 4], sensingGU: [5, 5]},
261 {tag: "5x5GU size, 1GU margins, click in visual", sizeGU: [5, 5], marginsGU: [1, 1, 1, 1], clickGU: [0, 0], sensingGU: [7, 7]},
262 {tag: "5x5GU size, 1GU margins, click in sensing", sizeGU: [5, 5], marginsGU: [1, 1, 1, 1], clickGU: [4, 4], sensingGU: [7, 7]},
263 {tag: "5x5GU size, 3GU margins horizontal, click in sensing", sizeGU: [5, 5], marginsGU: [3, 0, 3, 0], clickGU: [4, 4], sensingGU: [11, 5]},
264 {tag: "5x5GU size, 3GU margins vertical, click in sensing", sizeGU: [5, 5], marginsGU: [0, 3, 0, 3], clickGU: [4, 4], sensingGU: [5, 11]},
265 {tag: "5x5GU size, 3GU margins around, click in sensing", sizeGU: [5, 5], marginsGU: [3, 3, 3, 3], clickGU: [4, 4], sensingGU: [11, 11]},
266
267 {tag: "zero size, no margins, click out of sensing area", sizeGU: [0, 0], clickGU: [5, 5], sensingGU: [4, 4], fail: true},
268 {tag: "2x2GU size, no margins, click out of sensing area", sizeGU: [2, 2], clickGU: [5, 5], sensingGU: [4, 4], fail: true},
269 {tag: "4x4GU size, no margins, click out of sensing area", sizeGU: [4, 4], clickGU: [5, 5], sensingGU: [4, 4], fail: true},
270 {tag: "2x2GU size, 1GU margins around, click out of sensing area", sizeGU: [2, 2], marginsGU: [1, 1, 1, 1], clickGU: [5, 5], sensingGU: [4, 4], fail: true},
271 {tag: "4x4GU size, 1GU margins around, click out of sensing area", sizeGU: [4, 4], marginsGU: [1, 1, 1, 1], clickGU: [6.1, 6.1], sensingGU: [6, 6], fail: true},
272
273 // test margins.all
274 {tag: "zero size, 5GU margins.all, click in sensing area", sizeGU: [0, 0], marginsAll: units.gu(5), clickGU: [5, 5], sensingGU: [10, 10]},
275 {tag: "2x2 size, 2GU margins.all, click in sensing area", sizeGU: [2, 2], marginsAll: units.gu(2), clickGU: [6, 6], sensingGU: [6, 6]},
276 {tag: "zero size, 5GU margins.all, click out of sensing area", sizeGU: [0, 0], marginsAll: units.gu(5), clickGU: [10.1, 10.1], sensingGU: [10, 10], fail: true},
277 {tag: "2x2 size, 2GU margins.all, click out of sensing area", sizeGU: [2, 2], marginsAll: units.gu(2), clickGU: [6.1, 6.1], sensingGU: [6, 6], fail: true},
278
279 // test negative margins
280 {tag: "zero size, -1GU margins.all, click in sensing area", sizeGU: [0, 0], marginsAll: -units.gu(1), clickGU: [4, 4], sensingGU: [4, 4]},
281 {tag: "2x2 size, -1GU margins.all, click in sensing area", sizeGU: [2, 2], marginsAll: -units.gu(1), clickGU: [4, 4], sensingGU: [4, 4]},
282 {tag: "zero size, -1GU margins horizontal, click in sensing area", sizeGU: [0, 0], marginsGU: [-1, 0, -1, 0], clickGU: [4, 4], sensingGU: [4, 4]},
283 {tag: "zero size, -1GU margins vertical, click in sensing area", sizeGU: [0, 0], marginsGU: [0, -1, 0, -1], clickGU: [4, 4], sensingGU: [4, 4]},
284 {tag: "2x2 size, -1GU margins horizontal, click in sensing area", sizeGU: [2, 2], marginsGU: [-1, 0, -1, 0], clickGU: [4, 4], sensingGU: [4, 4]},
285 {tag: "2x2 size, -1GU margins vertical, click in sensing area", sizeGU: [2, 2], marginsGU: [0, -1, 0, -1], clickGU: [4, 4], sensingGU: [4, 4]},
286 {tag: "4x4 size, -1GU margins.all, click in sensing area", sizeGU: [4, 4], marginsAll: -units.gu(1), clickGU: [4, 4], sensingGU: [4, 4]},
287 {tag: "4x4 size, -1GU margins horizontal, click in sensing area", sizeGU: [4, 4], marginsGU: [-1, 0, -1, 0], clickGU: [4, 4], sensingGU: [4, 4]},
288 {tag: "4x4 size, -1GU margins vertical, click in sensing area", sizeGU: [4, 4], marginsGU: [0, -1, 0, -1], clickGU: [4, 4], sensingGU: [4, 4]},
289
290 // bigger size than minimum, decrease sensing area
291 {tag: "5x5 size, -1GU margins.all, click in sensing area", sizeGU: [5, 5], marginsAll: -units.gu(1), clickGU: [4, 4], sensingGU: [4, 4]},
292 {tag: "5x5 size, -1GU margins horizontal, click in sensing area", sizeGU: [5, 5], marginsGU: [-1, 0, -1, 0], clickGU: [4, 5], sensingGU: [4, 5]},
293 {tag: "5x5 size, -1GU margins vertical, click in sensing area", sizeGU: [5, 5], marginsGU: [0, -1, 0, -1], clickGU: [5, 4], sensingGU: [5, 4]},
294 ];
295 }
296 function test_sensing_area(data) {
297 signalSpy.target = buttonWithSensing;
298 buttonWithSensing.objectName = data.tag;
299 buttonWithSensing.width = units.gu(data.sizeGU[0]);
300 buttonWithSensing.height = units.gu(data.sizeGU[1]);
301 if (data.marginsGU) {
302 buttonWithSensing.sensingMargins.left = units.gu(data.marginsGU[0]);
303 buttonWithSensing.sensingMargins.top = units.gu(data.marginsGU[1]);
304 buttonWithSensing.sensingMargins.right = units.gu(data.marginsGU[2]);
305 buttonWithSensing.sensingMargins.bottom = units.gu(data.marginsGU[3]);
306 } else if (data.marginsAll) {
307 buttonWithSensing.sensingMargins.all = data.marginsAll;
308 }
309
310 if (data.sensingGU) {
311 compare(buttonWithSensing.__mouseArea.width, units.gu(data.sensingGU[0]), "unexpected horizontal sensing size");
312 compare(buttonWithSensing.__mouseArea.height, units.gu(data.sensingGU[1]), "unexpected vertical sensing size");
313 }
314 if (data.fail) {
315 expectFailContinue(data.tag, "no signal");
316 }
317 mouseClick(buttonWithSensing.__mouseArea, units.gu(data.clickGU[0]), units.gu(data.clickGU[1]));
318 signalSpy.wait(500);
319 }
320
321 function test_predeclared_sensing_area() {
322 var point = centerOf(increasedSensing.parent);
323 // move the point to the edge of the sensing area
324 point.x -= increasedSensing.sensingMargins.left;
325 point.y -= increasedSensing.sensingMargins.top;
326 // click
327 signalSpy.target = increasedSensing;
328 mouseClick(increasedSensing.parent, point.x, point.y);
329 signalSpy.wait(500);
330 }
187 }331 }
188}332}

Subscribers

People subscribed via source and target branches