Merge lp:~zsombi/ubuntu-ui-toolkit/combobutton into lp:ubuntu-ui-toolkit

Proposed by Zsombor Egri
Status: Superseded
Proposed branch: lp:~zsombi/ubuntu-ui-toolkit/combobutton
Merge into: lp:ubuntu-ui-toolkit
Diff against target: 1652 lines (+1381/-24)
19 files modified
components.api (+12/-0)
examples/ubuntu-ui-toolkit-gallery/Buttons.qml (+64/-0)
modules/Ubuntu/Components/Button.qml (+5/-0)
modules/Ubuntu/Components/ComboButton.qml (+383/-0)
modules/Ubuntu/Components/Themes/Ambiance/ButtonForeground.qml (+1/-0)
modules/Ubuntu/Components/Themes/Ambiance/ButtonStyle.qml (+14/-5)
modules/Ubuntu/Components/Themes/Ambiance/ComboButtonStyle.qml (+251/-0)
modules/Ubuntu/Components/Themes/Ambiance/qmldir (+1/-0)
modules/Ubuntu/Components/qmldir (+1/-0)
modules/Ubuntu/Test/UbuntuTestCase.qml (+69/-1)
modules/Ubuntu/Test/deployment.pri (+6/-1)
tests/autopilot/ubuntuuitoolkit/emulators.py (+26/-0)
tests/autopilot/ubuntuuitoolkit/tests/test_emulators.py (+45/-0)
tests/resources/buttons/ComboTest.qml (+147/-0)
tests/unit/runtest.sh (+1/-1)
tests/unit/tst_components/tst_button.qml (+4/-0)
tests/unit_x11/tst_components/tst_combobutton.qml (+246/-0)
tests/unit_x11/tst_components/tst_components.pro (+2/-1)
tests/unit_x11/tst_test/tst_ubuntutestcase.qml (+103/-15)
To merge this branch: bzr merge lp:~zsombi/ubuntu-ui-toolkit/combobutton
Reviewer Review Type Date Requested Status
PS Jenkins bot continuous-integration Approve
Tim Peeters Needs Fixing
Nekhelesh Ramananthan (community) Needs Information
Review via email: mp+207598@code.launchpad.net

This proposal has been superseded by a proposal from 2014-04-10.

Commit message

ComboButton component

To post a comment you must log in.
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
956. By Zsombor Egri

license added to test app

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
Revision history for this message
Nekhelesh Ramananthan (nik90) wrote :

Is there a design document describing the combo button behaviour and appearance?

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

> Is there a design document describing the combo button behaviour and
> appearance?

The design is here http://design.ubuntu.com/apps/building-blocks/buttons, but the combo button design had been updated, and the site does not have the updated layouts yet.

957. By Zsombor Egri

trunk merge

958. By Zsombor Egri

use artworks instead of system icons

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
959. By Zsombor Egri

trunk merge

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

I think the blue contents for the combobutton in the gallery is quite ugly:
http://ubuntuone.com/4jy8WPRYPLbLTez89wzqRh
also it does not really show how it should be used, with listitems that have alternative options to click on. Please change the example in the gallery.

I also don't really like the colors used in the button itself, but I guess we need design input for that.

Finally, the ^/V just "flips" when you click it, a rotation animation such as the ValueSelector has looks more sleek.

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

I added an icon to the combobutton example:

            ComboButton {
                text: "Press me"
                objectName: "combobutton_collapsed"
                comboList: Rectangle {
                    height: units.gu(20)
                    width: parent.width
                    color: "blue"
                }
                iconSource: "call.png"

the icon gets aligned wrong, see http://ubuntuone.com/3LHlrfUwFssHkbx00v33Br

review: Needs Fixing
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
Revision history for this message
Zsombor Egri (zsombi) wrote :

> I think the blue contents for the combobutton in the gallery is quite ugly:
> http://ubuntuone.com/4jy8WPRYPLbLTez89wzqRh
> also it does not really show how it should be used, with listitems that have
> alternative options to click on. Please change the example in the gallery.

Agreed. I'll add a Column with items into it.
>
>
> I also don't really like the colors used in the button itself, but I guess we
> need design input for that.

The colors I got from design. We were supposed to get UI facelift again for all the components. If they don't like the design, they can change it. Actually I was thinking to expose these colors/font properties so user can customize them freely.

>
> Finally, the ^/V just "flips" when you click it, a rotation animation such as
> the ValueSelector has looks more sleek.

That's the point. The chevron should not be animated while the dropdown toggles. The maximum we could do is to fade the image transition, however atm we don't have separate up/down chevrons. But we can make one, so I'll update the UI.

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

> I added an icon to the combobutton example:
>
> ComboButton {
> text: "Press me"
> objectName: "combobutton_collapsed"
> comboList: Rectangle {
> height: units.gu(20)
> width: parent.width
> color: "blue"
> }
> iconSource: "call.png"
>
> the icon gets aligned wrong, see http://ubuntuone.com/3LHlrfUwFssHkbx00v33Br

Fixed in revno 960

960. By Zsombor Egri

button face alignment when icon + text is present fixed; dropdown colors and button font properties exposed

961. By Zsombor Egri

fixing emulator errors

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
962. By Zsombor Egri

api file updated

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Approve (continuous-integration)
963. By Zsombor Egri

staging merge

964. By Zsombor Egri

remove accidentally added tst_combobutton.qml from pro file

965. By Zsombor Egri

staging merge

966. By Zsombor Egri

autopilot fixes

967. By Zsombor Egri

color fix

968. By Zsombor Egri

review comments applied

969. By Zsombor Egri

stage merge

970. By Zsombor Egri

prereq merge

971. By Zsombor Egri

moving component to version 1.1

972. By Zsombor Egri

style documentation linked

973. By Zsombor Egri

Style API headline

974. By Zsombor Egri

prereq merge

975. By Zsombor Egri

Ubuntu.Components evolved to version 1.1, the rest are kept on 1.0 till we introduce new features there

976. By Zsombor Egri

prereq merge

977. By Zsombor Egri

prereq merge

978. By Zsombor Egri

staging merge

979. By Zsombor Egri

fixing test case

980. By Zsombor Egri

staging merge

981. By Zsombor Egri

typo fixed

982. By Zsombor Egri

staging merge

983. By Zsombor Egri

rogue file removed

Unmerged revisions

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-04-01 12:57:27 +0000
3+++ components.api 2014-04-10 09:56:33 +0000
4@@ -45,6 +45,16 @@
5 readonly property color coolGrey
6 property Gradient orangeGradient
7 property Gradient greyGradient
8+modules/Ubuntu/Components/ComboButton.qml
9+Button
10+ property bool expanded
11+ property bool autoCollapse
12+ property real collapsedHeight
13+ property real expandedHeight
14+ readonly property real comboListHeight
15+ default property list<Item> comboList
16+ property color dropdownColorPressed
17+ property color dropdownColorReleased
18 modules/Ubuntu/Components/CrossFadeImage.qml
19 Item
20 property url source
21@@ -593,6 +603,8 @@
22 function findChild(obj,objectName)
23 function findInvisibleChild(obj,objectName)
24 function mouseMoveSlowly(item,x,y,dx,dy,steps,stepdelay)
25+ function flick(item, x, y, dx, dy, pressTimeout, steps, button, modifiers, delay)
26+ function mouseLongPress(item, x, y, button, modifiers, delay)
27 function tryCompareFunction(func, expectedResult, timeout)
28 plugins.qmltypes
29 name: "InverseMouseAreaType"
30
31=== modified file 'examples/ubuntu-ui-toolkit-gallery/Buttons.qml'
32--- examples/ubuntu-ui-toolkit-gallery/Buttons.qml 2014-03-04 12:16:38 +0000
33+++ examples/ubuntu-ui-toolkit-gallery/Buttons.qml 2014-04-10 09:56:33 +0000
34@@ -16,6 +16,7 @@
35
36 import QtQuick 2.0
37 import Ubuntu.Components 0.1
38+import Ubuntu.Components.ListItems 0.1
39
40 Template {
41 objectName: "buttonsTemplate"
42@@ -80,4 +81,67 @@
43 }
44 }
45 }
46+
47+ TemplateSection {
48+ className: "ComboButton"
49+
50+ TemplateRow {
51+ title: i18n.tr("Collapsed")
52+
53+ ComboButton {
54+ text: "Press me"
55+ objectName: "combobutton_collapsed"
56+ comboList: UbuntuListView {
57+ model: 10
58+ delegate: Standard {
59+ text: "item #" + modelData
60+ }
61+ }
62+ }
63+ }
64+
65+ TemplateRow {
66+ title: i18n.tr("Icon")
67+
68+ ComboButton {
69+ iconSource: "call.png"
70+ comboList: UbuntuListView {
71+ model: 10
72+ delegate: Standard {
73+ text: "item #" + modelData
74+ }
75+ }
76+ }
77+ }
78+
79+ TemplateRow {
80+ title: i18n.tr("Icon+Text")
81+
82+ ComboButton {
83+ text: "Answer"
84+ iconSource: "call.png"
85+ comboList: UbuntuListView {
86+ model: 10
87+ delegate: Standard {
88+ text: "item #" + modelData
89+ }
90+ }
91+ }
92+ }
93+ TemplateRow {
94+ title: i18n.tr("Expanded")
95+
96+ ComboButton {
97+ text: "Press me"
98+ objectName: "combobutton_expanded"
99+ expanded: true
100+ comboList: UbuntuListView {
101+ model: 10
102+ delegate: Standard {
103+ text: "item #" + modelData
104+ }
105+ }
106+ }
107+ }
108+ }
109 }
110
111=== modified file 'modules/Ubuntu/Components/Button.qml'
112--- modules/Ubuntu/Components/Button.qml 2013-11-06 22:52:15 +0000
113+++ modules/Ubuntu/Components/Button.qml 2014-04-10 09:56:33 +0000
114@@ -83,6 +83,11 @@
115 property Gradient gradient: __styleInstance.defaultGradient
116
117 /*!
118+ The font used for the button's text.
119+ */
120+ property font font: __styleInstance ? __styleInstance.defaultFont : Qt.font({family: "Ubuntu", pixelSize: FontUtils.sizeToPixels("medium")})
121+
122+ /*!
123 The source URL of the icon to display inside the button.
124 Leave this value blank for a text-only button.
125 If \l action is set, the default iconSource is that of the action.
126
127=== added file 'modules/Ubuntu/Components/ComboButton.qml'
128--- modules/Ubuntu/Components/ComboButton.qml 1970-01-01 00:00:00 +0000
129+++ modules/Ubuntu/Components/ComboButton.qml 2014-04-10 09:56:33 +0000
130@@ -0,0 +1,383 @@
131+/*
132+ * Copyright 2014 Canonical Ltd.
133+ *
134+ * This program is free software; you can redistribute it and/or modify
135+ * it under the terms of the GNU Lesser General Public License as published by
136+ * the Free Software Foundation; version 3.
137+ *
138+ * This program is distributed in the hope that it will be useful,
139+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
140+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
141+ * GNU Lesser General Public License for more details.
142+ *
143+ * You should have received a copy of the GNU Lesser General Public License
144+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
145+ */
146+
147+import QtQuick 2.0
148+import Ubuntu.Components.Popups 0.1
149+import "mathUtils.js" as MathUtils
150+
151+/*!
152+ \qmltype ComboButton
153+ \inqmlmodule Ubuntu.Components 0.1
154+ \ingroup ubuntu
155+ \brief Ubuntu button providing a drop-down panel visualizing custom options.
156+
157+ The component is composed of three main blocks: \b {main button}, \b {dropdown}
158+ and \b {combo list}.
159+
160+ The \a {main button} holds the main functionailty of the component, and it is
161+ located at the left-top side of the expanded button. The \a clicked() signal
162+ is triggered only when this button is pressed.
163+
164+ The \a {dropdown} is a button located on the top-right side of the expanded
165+ component. Its functionality is to drive the component's expanded state.
166+
167+ The \a {combo list} is a panel showing the content specified in \l comboList
168+ property when expanded. The content is stretched horizontally to the component's
169+ width, and its height is controlled by the \l expandedHeight property as follows:
170+ \list
171+ \li If the content height is smaller than the value of \l expandedHeight, the combo
172+ list will be expanded only to the height of the content.
173+ \qml
174+ import QtQuick 2.0
175+ import Ubuntu.Components 0.1
176+ ComboButton {
177+ text: "smaller content"
178+ Rectangle {
179+ height: units.gu(5) // smaller than the default expandedHeight
180+ color: "blue"
181+ }
182+ }
183+ \endqml
184+ \li If the content height is greater than \l expandedHeight, the combo list will
185+ expand till the height specified by the property and the content will be
186+ scrolled; in case the combo list content is one single Flickable, ListView,
187+ GridView or PathView, the content scrolling will be provided by the content
188+ itself.
189+ \qml
190+ import QtQuick 2.0
191+ import Ubuntu.Components 0.1
192+ ComboButton {
193+ text: "long scrolled content"
194+ Column {
195+ Repeater {
196+ model: 5
197+ spacing: units.gu(1)
198+ Rectangle {
199+ height: units.gu(5)
200+ color: "blue"
201+ }
202+ }
203+ }
204+ }
205+ \endqml
206+ \li In case the content is a single Flickable, ListView, GridView or PathView,
207+ the content will be filling the entire combo list area defined.
208+ \qml
209+ import QtQuick 2.0
210+ import Ubuntu.Components 0.1
211+ import Ubuntu.Components.ListItems 0.1
212+ ComboButton {
213+ text: "listview"
214+ ListView {
215+ model: 10
216+ delegate: Standard {
217+ text: "Item #" + modelData
218+ }
219+ }
220+ }
221+ \endqml
222+ \li Vertical anchoring of combo list content to its parent is not possible
223+ as the expansion calculation is done based on the combo list content height.
224+ If the content wants to take the size of the entire combo list, it should
225+ bind its height to the \l comboListHeight property.
226+ \qml
227+ import QtQuick 2.0
228+ import Ubuntu.Components 0.1
229+ ComboButton {
230+ id: combo
231+ text: "smaller content"
232+ Rectangle {
233+ height: combo.comboListHeight
234+ color: "blue"
235+ }
236+ }
237+ \endqml
238+ \li In case the expansion needs to be the size of the combo list content, the \l
239+ expandedHeight should be set to -1.
240+ \qml
241+ import QtQuick 2.0
242+ import Ubuntu.Components 0.1
243+ ComboButton {
244+ text: "auto-sized content"
245+ expandedHeight: -1
246+ Column {
247+ Repeater {
248+ model: 5
249+ spacing: units.gu(1)
250+ Rectangle {
251+ height: units.gu(5)
252+ color: "blue"
253+ }
254+ }
255+ }
256+ }
257+ \endqml
258+ \endlist
259+
260+ As combo list content is unknown for the component, eventual collapsing when
261+ an action selected from the combo list holder must be driven manually. Also,
262+ the default action of the main button can be changed in this way.
263+
264+ \qml
265+ import QtQuick 2.0
266+ import Ubuntu.Components 0.1
267+
268+ ComboButton {
269+ id: combo
270+ text: "Auto closing"
271+ expanded: true
272+ expandedHeight: units.gu(30)
273+ UbuntuListView {
274+ width: parent.width
275+ height: combo.comboListHeight
276+ model: 20
277+ delegate: Standard {
278+ text: "Action #" + modelData
279+ onClicked: {
280+ combo.text = text;
281+ combo.expanded = false;
282+ }
283+ }
284+ }
285+ }
286+ \endqml
287+
288+ The style of the component is defined in \l ComboButtonStyle.
289+ */
290+Button {
291+ id: combo
292+
293+ /*!
294+ Specifies whether the combo list is expanded or not. The default falue is
295+ false.
296+ */
297+ property bool expanded: false
298+
299+ /*!
300+ The property specifies whether to collapse the expanded combo list when
301+ the main button is clicked. The default value is true.
302+ */
303+ property bool autoCollapse: true
304+
305+ /*!
306+ The property holds the height of the component when collapsed. By default
307+ the value is the implicit height of the component.
308+ */
309+ property real collapsedHeight: implicitHeight
310+
311+ /*!
312+ The property holds the maximum height value the component should expand.
313+ When setting the property, remember to take into account the \l collapsedHeight
314+ value. The best practice is to use bind it with collapsedHeight.
315+ \qml
316+ ComboButton {
317+ text: "altered expandedHeight"
318+ expandedHeight: collapsedHeight + units.gu(25)
319+ }
320+ \endqml
321+
322+ A value of -1 will instruct the component to expand the combo list as
323+ much as its content height is.
324+
325+ The default value is \l collapsedHeight + 19.5 GU.
326+ \sa collapsedHeight
327+ */
328+ property real expandedHeight: collapsedHeight + units.gu(19.5)
329+
330+ /*!
331+ The property holds the maximum combo list height allowed based on the
332+ \l expandedHeight and \l collapsedHeight values. It is a convenience property
333+ that can be used to size the combo list content.
334+ \qml
335+ import QtQuick 2.0
336+ import Ubuntu.Components 0.1
337+ import Ubuntu.Components.ListItems 0.1
338+ ComboButton {
339+ id: combo
340+ text: "Full comboList size"
341+ ListView {
342+ anchors {
343+ left: parent.left
344+ right: parent.right
345+ }
346+ height: combo.comboListHeight
347+ model: 20
348+ delegate: Standard {
349+ text: "Action #" + modelData
350+ }
351+ }
352+ }
353+ \endqml
354+
355+ \sa collapsedHeight, expandedHeight
356+ */
357+ readonly property real comboListHeight: (expandedHeight < 0) ?
358+ comboListHolder.height :
359+ (expandedHeight - collapsedHeight -
360+ (combo.__styleInstance ? combo.__styleInstance.comboListMargin : 0))
361+
362+ /*!
363+ \qmlproperty list<Item> comboList
364+ \default
365+ Property holding the list of items to be shown in the combo list. Being
366+ a default property children items declared will land in the combo list.
367+ \note The component is not responsible for layouting the content. It only
368+ provides scrolling abilities for the case the content exceeds the defined
369+ expanded height.
370+ */
371+ default property alias comboList: comboListHolder.data
372+
373+ /* ----------------- Color and font configurations ----------------- */
374+ /*!
375+ The property specifies the color of the dropdown button when expanded.
376+ */
377+ property color dropdownColorPressed: __styleInstance ? __styleInstance.defaultDropdownColorPressed : color
378+
379+ /*!
380+ The property specifies the color of the dropdown button when collapsed.
381+ */
382+ property color dropdownColorReleased: __styleInstance ? __styleInstance.defaultDropdownColorReleased : color
383+
384+ style: Theme.createStyleComponent("ComboButtonStyle.qml", combo)
385+
386+ // auto-collapse
387+ /*! \internal */
388+ onClicked: {
389+ if (autoCollapse) {
390+ expanded = false;
391+ }
392+ }
393+
394+ Component.onCompleted: {
395+ // update mouse area to report clicks only on the main button area
396+ // area excluding dropDown button and combo list
397+ // we must do separate bindings as __mouseArea is a read-only property
398+ __mouseArea.anchors.fill = undefined;
399+ __mouseArea.anchors.left = Qt.binding(function() {return combo.left;});
400+ __mouseArea.anchors.top = Qt.binding(function() {return combo.top;});
401+ __mouseArea.anchors.right = Qt.binding(function() {return combo.right;});
402+ __mouseArea.anchors.rightMargin = Qt.binding(function() {return combo.__styleInstance.dropDownWidth + combo.__styleInstance.dropDownSeparatorWidth;});
403+ __mouseArea.height = Qt.binding(function() {return collapsedHeight;});
404+ // for autopilot, set the main button name
405+ __mouseArea.objectName = "combobutton_mainbutton";
406+
407+ // bind a height calculation to avoid unwanted change
408+ combo.height = Qt.binding(function() {return collapsedHeight + __styleInstance.comboListPanel.height});
409+ }
410+
411+ // dropdown button
412+ MouseArea {
413+ id: dropDown
414+ objectName: "combobutton_dropdown"
415+ anchors {
416+ right: parent.right
417+ top: parent.top
418+ }
419+ width: combo.__styleInstance ? combo.__styleInstance.dropDownWidth : 0
420+ height: combo.collapsedHeight
421+ // open dropdown when pressed, not when clicked
422+ onPressed: {
423+ // toggle expanded
424+ combo.expanded = !combo.expanded;
425+ }
426+ }
427+
428+ // expansion list
429+ Flickable {
430+ id: comboHolder
431+ parent: combo.__styleInstance ? combo.__styleInstance.comboList : combo
432+ anchors.fill: parent
433+ interactive: combo.expanded && !contentIsFlickable() && (combo.expandedHeight > 0)
434+ flickableDirection: Flickable.VerticalFlick
435+ contentHeight: comboListHolder.height
436+
437+ // consider PathView as Flickable in this case as well!
438+ function contentIsFlickable() {
439+ return (comboListHolder.children.length === 1) &&
440+ comboListHolder.children[0].hasOwnProperty("flicking");
441+ }
442+
443+ Item {
444+ id: comboListHolder
445+ objectName: "combobutton_combolist"
446+ anchors {
447+ left: parent.left
448+ right: parent.right
449+ }
450+
451+ // stretch children width to holder's width
452+ // must do binding to height manually to avoid binding loops caused
453+ // by the vertical stretching when the component is a single flickable
454+ property bool anchorFill: (combo.expandedHeight > 0 && comboHolder.contentIsFlickable())
455+ onAnchorFillChanged: stretchChildren()
456+ onChildrenChanged: stretchChildren()
457+ function stretchChildren() {
458+ for (var i in comboListHolder.children) {
459+ var child = comboListHolder.children[i];
460+ if (comboListHolder.anchorFill) {
461+ child.anchors.left = undefined;
462+ child.anchors.right = undefined;
463+ child.anchors.fill = comboListHolder;
464+ comboListHolder.height = Qt.binding(function() {
465+ return combo.comboListHeight;
466+ });
467+ } else {
468+ child.anchors.left = comboListHolder.left;
469+ child.anchors.right = comboListHolder.right;
470+ comboListHolder.height = Qt.binding(function() {
471+ return comboListHolder.childrenRect.height;
472+ });
473+ }
474+ }
475+ }
476+ }
477+ }
478+ Scrollbar {
479+ flickableItem: comboHolder
480+ }
481+
482+ // drive the expansion height of the combo list holder
483+ Binding {
484+ target: combo.__styleInstance.comboListPanel
485+ property: "height"
486+ value: {
487+ if (!expanded) {
488+ return 0;
489+ }
490+ if (comboListHolder.anchorFill) {
491+ return combo.comboListHeight + combo.__styleInstance.comboListMargin;
492+ }
493+
494+ var h = comboListHolder.height;
495+ var max = combo.comboListHeight + combo.__styleInstance.comboListMargin;
496+ if (combo.expandedHeight < 0) {
497+ return max;
498+ }
499+
500+ return MathUtils.clamp(h, 0, max);
501+ }
502+ }
503+ // for testing purposes only
504+ Binding {
505+ target: combo.__styleInstance.comboListPanel
506+ property: "objectName"
507+ value: "combobutton_combopanel"
508+ }
509+
510+ /*! \internal */
511+ // on style change, update the visual's names so we can access it when testing
512+ onStyleChanged: if (__styleInstance) __styleInstance.dropdownButtonVisuals.objectName = "combobutton_dropdow_visuals"
513+}
514
515=== modified file 'modules/Ubuntu/Components/Themes/Ambiance/ButtonForeground.qml'
516--- modules/Ubuntu/Components/Themes/Ambiance/ButtonForeground.qml 2013-07-01 22:26:49 +0000
517+++ modules/Ubuntu/Components/Themes/Ambiance/ButtonForeground.qml 2014-04-10 09:56:33 +0000
518@@ -30,6 +30,7 @@
519 property real spacing
520 property bool hasIcon: iconSource != ""
521 property bool hasText: text != ""
522+ property alias font: label.font
523
524 opacity: enabled ? 1.0 : 0.5
525 implicitHeight: Math.max(icon.height, label.height)
526
527=== modified file 'modules/Ubuntu/Components/Themes/Ambiance/ButtonStyle.qml'
528--- modules/Ubuntu/Components/Themes/Ambiance/ButtonStyle.qml 2014-02-04 22:07:10 +0000
529+++ modules/Ubuntu/Components/Themes/Ambiance/ButtonStyle.qml 2014-04-10 09:56:33 +0000
530@@ -26,7 +26,10 @@
531 property real minimumWidth: units.gu(10)
532 property real horizontalPadding: units.gu(1)
533 property color defaultColor: UbuntuColors.orange
534+ property font defaultFont: Qt.font({family: "Ubuntu", pixelSize: FontUtils.sizeToPixels("medium")})
535 property Gradient defaultGradient
536+ property real buttonFaceOffset: 0
537+ property Item backgroundSource: null
538
539 width: button.width
540 height: button.height
541@@ -40,8 +43,9 @@
542 non-NOTIFYable properties. They cannot be written to so it is fine but
543 the proxy avoids the warnings.
544 */
545+ property QtObject gradientProxy: gradientProxyObject
546 QtObject {
547- id: gradientProxy
548+ id: gradientProxyObject
549 property color topColor
550 property color bottomColor
551
552@@ -67,7 +71,8 @@
553 id: background
554 anchors.fill: parent
555 borderSource: "radius_idle.sci"
556- visible: color.a != 0.0
557+ visible: (color.a != 0.0) || backgroundSource
558+ image: backgroundSource
559
560 // Color properties in a JS ternary operator don't work as expected in
561 // QML because it overwrites alpha values with 1. A workaround is to use
562@@ -75,8 +80,8 @@
563 // https://bugs.launchpad.net/ubuntu-ui-toolkit/+bug/1197802 and
564 // https://bugreports.qt-project.org/browse/QTBUG-32238.
565 function colorHack(color) { return Qt.rgba(color.r, color.g, color.b, color.a); }
566- color: isGradient ? colorHack(gradientProxy.topColor) : colorHack(button.color)
567- gradientColor: isGradient ? colorHack(gradientProxy.bottomColor) : colorHack(button.color)
568+ color: backgroundSource ? "#00000000" : (isGradient ? colorHack(gradientProxy.topColor) : colorHack(button.color))
569+ gradientColor: backgroundSource ? "#00000000" : (isGradient ? colorHack(gradientProxy.bottomColor) : colorHack(button.color))
570 }
571
572 UbuntuShape {
573@@ -98,7 +103,10 @@
574 ButtonForeground {
575 id: foreground
576 width: parent.width - 2*horizontalPadding
577- anchors.centerIn: parent
578+ anchors {
579+ centerIn: parent
580+ horizontalCenterOffset: buttonFaceOffset
581+ }
582 text: button.text
583 /* Pick either a clear or dark text color depending on the luminance of the
584 background color to maintain good contrast (works in most cases)
585@@ -107,6 +115,7 @@
586 iconSource: button.iconSource
587 iconPosition: button.iconPosition
588 iconSize: units.gu(3)
589+ font: button.font
590 spacing: horizontalPadding
591 transformOrigin: Item.Top
592 scale: button.pressed ? 0.98 : 1.0
593
594=== added file 'modules/Ubuntu/Components/Themes/Ambiance/ComboButtonStyle.qml'
595--- modules/Ubuntu/Components/Themes/Ambiance/ComboButtonStyle.qml 1970-01-01 00:00:00 +0000
596+++ modules/Ubuntu/Components/Themes/Ambiance/ComboButtonStyle.qml 2014-04-10 09:56:33 +0000
597@@ -0,0 +1,251 @@
598+/*
599+ * Copyright 2014 Canonical Ltd.
600+ *
601+ * This program is free software; you can redistribute it and/or modify
602+ * it under the terms of the GNU Lesser General Public License as published by
603+ * the Free Software Foundation; version 3.
604+ *
605+ * This program is distributed in the hope that it will be useful,
606+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
607+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
608+ * GNU Lesser General Public License for more details.
609+ *
610+ * You should have received a copy of the GNU Lesser General Public License
611+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
612+ */
613+
614+import QtQuick 2.0
615+import Ubuntu.Components 0.1
616+
617+/*!
618+ The component defines the style of the ComboButton component.
619+ */
620+Item {
621+ id: comboStyle
622+
623+ /*!
624+ Width of the drop down button.
625+ */
626+ property real dropDownWidth: units.gu(5)
627+
628+ /*!
629+ Width of the dropdown button separator.
630+ */
631+ property real dropDownSeparatorWidth: units.dp(2)
632+
633+ /*!
634+ Distance between the combo list and the main button.
635+ */
636+ property real comboListMargin: units.gu(0.8)
637+
638+ /*!
639+ The item which will hold the combo list data.
640+ */
641+ property Item comboList: comboListContent
642+
643+ /*!
644+ The item pointing to the panel holding the combo list and additional design
645+ artifacts. It is used by the component to drive the expansion size.
646+ */
647+ property Item comboListPanel: panelItem
648+
649+ /*!
650+ \qmlproperty color defaultColor
651+ Default color for the main button.
652+ */
653+ property alias defaultColor: mainButton.defaultColor
654+
655+ /*!
656+ \qmlproperty Gradient defaultGradient
657+ Default gradient for the main button.
658+ */
659+ property alias defaultGradient: mainButton.defaultGradient
660+
661+ /*!
662+ Default color for the dropdown button when released.
663+ */
664+ property color defaultDropdownColorReleased: defaultColor
665+ /*!
666+ Default color for dropdown button when pressed.
667+ */
668+ property color defaultDropdownColorPressed: Qt.rgba(0, 0, 0, 0.05)
669+ /*!
670+ Default button face font.
671+ */
672+ property alias defaultFont: mainButton.defaultFont
673+
674+ /*!
675+ The property holds the Item implementing the visuals of the dropdown button.
676+ */
677+ property alias dropdownButtonVisuals: dropDownButton
678+
679+ width: combo.width
680+ height: combo.collapsedHeight
681+
682+ /*! \internal */
683+ property ComboButton combo: styledItem
684+
685+ implicitWidth: mainButton.implicitWidth
686+ implicitHeight: mainButton.implicitHeight
687+
688+ LayoutMirroring.enabled: Qt.application.layoutDirection == Qt.RightToLeft
689+ LayoutMirroring.childrenInherit: true
690+
691+ // Color properties in a JS ternary operator don't work as expected in
692+ // QML because it overwrites alpha values with 1. A workaround is to use
693+ // Qt.rgba(). For more information, see
694+ // https://bugs.launchpad.net/ubuntu-ui-toolkit/+bug/1197802 and
695+ // https://bugreports.qt-project.org/browse/QTBUG-32238.
696+ /*! \internal */
697+ function colorHack(color) { return Qt.rgba(color.r, color.g, color.b, color.a); }
698+
699+ ButtonStyle {
700+ id: mainButton
701+ anchors {
702+ left: parent.left
703+ top: parent.top
704+ right: parent.right
705+ }
706+ height: combo.collapsedHeight
707+ // overrides
708+ backgroundSource: comboFace
709+ buttonFaceOffset: -dropDownWidth/2 - dropDownSeparatorWidth
710+ horizontalPadding: units.gu(4) - dropDownSeparatorWidth
711+ minimumWidth: units.gu(36)
712+
713+ // FIXME: use hardcoded color while we get the theme palette updated
714+ defaultColor: "#b2b2b2"
715+ defaultGradient: null
716+
717+ // button face
718+ ShaderEffectSource {
719+ id: comboFace
720+ sourceItem: content
721+ hideSource: true
722+ // FIXME: visible: false prevents rendering so make it a nearly
723+ // transparent 1x1 pixel instead
724+ opacity: 0.01
725+ width: 1
726+ height: 1
727+ }
728+
729+ Item {
730+ id: content
731+ width: mainButton.width
732+ height: mainButton.height
733+
734+ Rectangle {
735+ anchors {
736+ fill: parent
737+ rightMargin: comboStyle.dropDownSeparatorWidth + comboStyle.dropDownWidth
738+ }
739+ color: combo.color
740+ gradient: mainButton.isGradient ? combo.gradient : null
741+ }
742+
743+ // distancer
744+ Item {
745+ anchors {
746+ right: dropDownButton.right
747+ top: parent.top
748+ bottom: parent.bottom
749+ }
750+ width: comboStyle.dropDownSeparatorWidth
751+ }
752+
753+ Rectangle {
754+ id: dropDownButton
755+ objectName: "combobutton_dropdown_visuals"
756+ anchors {
757+ right: parent.right
758+ top: parent.top
759+ bottom: parent.bottom
760+ }
761+ width: comboStyle.dropDownWidth
762+ color: combo.expanded ? comboStyle.colorHack(combo.dropdownColorPressed) : comboStyle.colorHack(combo.dropdownColorReleased)
763+ Image {
764+ source: "artwork/chevron.png"
765+ anchors.centerIn: parent
766+ rotation: combo.expanded ? -90 : 90
767+ }
768+ }
769+ }
770+ }
771+
772+ Item {
773+ id: panelItem
774+ anchors {
775+ left: parent.left
776+ top: mainButton.bottom
777+ right: parent.right
778+ }
779+ opacity: combo.expanded && (combo.comboList.length > 0)? 1.0 : 0.0
780+
781+ ShaderEffectSource {
782+ id: listContent
783+ sourceItem: comboListContent
784+ hideSource: true
785+ // FIXME: visible: false prevents rendering so make it a nearly
786+ // transparent 1x1 pixel instead
787+ opacity: 0.01
788+ width: 1
789+ height: 1
790+ }
791+ Rectangle {
792+ id: comboListContent
793+ anchors {
794+ fill: parent
795+ topMargin: comboListMargin
796+ }
797+ clip: true
798+ color: comboStyle.dropDownColorPressed
799+ }
800+
801+ BorderImage {
802+ id: shadow
803+ anchors {
804+ fill: parent
805+ leftMargin: -units.gu(0.5)
806+ topMargin: comboListMargin - units.gu(0.5)
807+ rightMargin: -units.gu(0.5)
808+ bottomMargin: -units.gu(0.5)
809+ }
810+ source: "artwork/bubble_shadow.sci"
811+ }
812+ UbuntuShape {
813+ id: shape
814+ anchors {
815+ fill: parent
816+ topMargin: comboListMargin
817+ }
818+ visible: true
819+ borderSource: "radius_idle.sci"
820+ image: listContent
821+ }
822+
823+ Image {
824+ source: "artwork/bubble_arrow.png"
825+ rotation: 180
826+ anchors {
827+ bottom: shape.top
828+ bottomMargin: -1
829+ right: parent.right
830+ rightMargin: dropDownWidth / 2 - units.gu(0.5)
831+ }
832+
833+ }
834+
835+ Behavior on height {
836+ NumberAnimation {
837+ duration: UbuntuAnimation.FastDuration
838+ easing: UbuntuAnimation.StandardEasing
839+ }
840+ }
841+ Behavior on opacity {
842+ NumberAnimation {
843+ duration: UbuntuAnimation.FastDuration
844+ easing: UbuntuAnimation.StandardEasing
845+ }
846+ }
847+ }
848+}
849
850=== modified file 'modules/Ubuntu/Components/Themes/Ambiance/qmldir'
851--- modules/Ubuntu/Components/Themes/Ambiance/qmldir 2013-12-04 10:47:19 +0000
852+++ modules/Ubuntu/Components/Themes/Ambiance/qmldir 2014-04-10 09:56:33 +0000
853@@ -26,3 +26,4 @@
854 DialerStyle 0.1 DialerStyle.qml
855 DialerHandStyle 0.1 DialerHandStyle.qml
856 internal HighlightMagnifier HighlightMagnifier.qml
857+ComboButtonStyle 0.1 ComboButtonStyle.qml
858
859=== modified file 'modules/Ubuntu/Components/qmldir'
860--- modules/Ubuntu/Components/qmldir 2014-02-13 11:48:38 +0000
861+++ modules/Ubuntu/Components/qmldir 2014-04-10 09:56:33 +0000
862@@ -44,6 +44,7 @@
863 ColorUtils 0.1 colorUtils.js
864 DateUtils 0.1 dateUtils.js
865 UbuntuListView 0.1 UbuntuListView.qml
866+ComboButton 0.1 ComboButton.qml
867
868 internal TextCursor TextCursor.qml
869 internal TextInputPopover TextInputPopover.qml
870
871=== modified file 'modules/Ubuntu/Test/UbuntuTestCase.qml'
872--- modules/Ubuntu/Test/UbuntuTestCase.qml 2014-02-25 12:36:27 +0000
873+++ modules/Ubuntu/Test/UbuntuTestCase.qml 2014-04-10 09:56:33 +0000
874@@ -87,7 +87,75 @@
875 }
876 }
877
878- /*!
879+ /*!
880+ \qmlmethod UbuntuTestCase::flick(item, x, y, dx, dy, pressTimeout = -1, steps = -1, button = Qt.LeftButton, modifiers = Qt.NoModifiers, delay = -1)
881+
882+ The function produces a flick event when executed on Flickables. When used
883+ on other components it provides the same functionality as \l mouseDrag()
884+ function. The optional \a pressTimeout parameter can be used to introduce
885+ a small delay between the mouse press and the first mouse move. Setting a
886+ negative or zero value will disable the timeout.
887+
888+ The default flick velocity is built up using 5 move points. This can be altered
889+ by setting a positive value to \a steps parameter. The bigger the number the
890+ longer the flick will be. When a negative or zero value is given, the default
891+ of 5 move points will be used.
892+
893+ \note The function can be used to select a text in a TextField or TextArea by
894+ specifying at least 400 millisecods to \a pressTimeout.
895+ */
896+ function flick(item, x, y, dx, dy, pressTimeout, steps, button, modifiers, delay) {
897+ if (item === undefined || item.x === undefined || item.y === undefined)
898+ return
899+ if (button === undefined)
900+ button = Qt.LeftButton
901+ if (modifiers === undefined)
902+ modifiers = Qt.NoModifier
903+ if (steps === undefined || steps <= 0)
904+ steps = 4;
905+ // make sure we have at least two move steps so the flick will be sensed
906+ steps += 1;
907+ if (delay === undefined)
908+ delay = -1;
909+
910+ var ddx = dx / steps;
911+ var ddy = dy / steps;
912+
913+ mousePress(item, x, y, button, modifiers, delay);
914+ if (pressTimeout !== undefined && pressTimeout > 0) {
915+ wait(pressTimeout);
916+ }
917+ for (var i = 1; i <= steps; i++) {
918+ // mouse moves are all processed immediately, without delay in between events
919+ mouseMove(item, x + i * ddx, y + i * ddy, -1, button);
920+ }
921+ mouseRelease(item, x + dx, y + dy, button, modifiers, delay);
922+ // empty event buffer
923+ wait(200);
924+ }
925+
926+ /*!
927+ \qmlmethod UbuntuTestCase::mouseLongPress(item, x, y, button = Qt.LeftButton, modifiers = Qt.NoModifiers, delay = -1)
928+
929+ Simulates a long press on a mouse \a button with an optional \a modifier
930+ on an \a item. The position is defined by \a x and \a y. If \a delay is
931+ specified, the test will wait the specified amount of milliseconds before
932+ the press.
933+
934+ The position given by \a x and \a y is transformed from the co-ordinate
935+ system of \a item into window co-ordinates and then delivered.
936+ If \a item is obscured by another item, or a child of \a item occupies
937+ that position, then the event will be delivered to the other item instead.
938+
939+ \sa mouseRelease(), mouseClick(), mouseDoubleClick(), mouseMove(), mouseDrag(), mouseWheel()
940+ */
941+ function mouseLongPress(item, x, y, button, modifiers, delay) {
942+ mousePress(item, x, y, button, modifiers, delay);
943+ // the delay is taken from QQuickMouseArea
944+ wait(800);
945+ }
946+
947+ /*!
948 Keeps executing a given parameter-less function until it returns the given
949 expected result or the timemout is reached (in which case a test failure
950 is generated)
951
952=== modified file 'modules/Ubuntu/Test/deployment.pri'
953--- modules/Ubuntu/Test/deployment.pri 2014-01-17 12:30:05 +0000
954+++ modules/Ubuntu/Test/deployment.pri 2014-04-10 09:56:33 +0000
955@@ -7,9 +7,14 @@
956 # make found deployables visible in Qt Creator
957 OTHER_FILES += $$QMLDIR_FILE
958
959+QML_FILES = $$system(ls *.qml)
960+JS_FILES = $$system(ls *.js)
961+
962 # define deployment for found deployables
963 qmldir_file.path = $$installPath
964 qmldir_file.files = $$QMLDIR_FILE
965+qml_files.path = $$installPath
966+qml_files.files = $$QML_FILES
967 js_files.path = $$installPath
968 js_files.files = $$JS_FILES
969
970@@ -20,4 +25,4 @@
971 # https://bugreports.qt-project.org/browse/QTBUG-36243
972 plugins_qmltypes.extra = $$[QT_INSTALL_BINS]/qmlplugindump -notrelocatable Ubuntu.Test 0.1 ../../ 2>/dev/null > $(INSTALL_ROOT)/$$installPath/plugins.qmltypes
973
974-INSTALLS += qmldir_file plugins_qmltypes
975+INSTALLS += qmldir_file plugins_qmltypes qml_files js_files
976
977=== modified file 'tests/autopilot/ubuntuuitoolkit/emulators.py'
978--- tests/autopilot/ubuntuuitoolkit/emulators.py 2014-04-08 14:46:25 +0000
979+++ tests/autopilot/ubuntuuitoolkit/emulators.py 2014-04-10 09:56:33 +0000
980@@ -470,6 +470,32 @@
981 self.checked.wait_for(not original_state, timeout)
982
983
984+class ComboButton(UbuntuUIToolkitEmulatorBase):
985+ """ComboButton Autopilot emulator."""
986+
987+ def press_mainbutton(self):
988+ """Presses the main button of the ComboBox."""
989+ main_button = self.select_single(objectName="combobutton_mainbutton")
990+ self.pointing_device.click_object(main_button)
991+
992+ def press_dropdown(self):
993+ """Presses the dropdown button to togle combo list expansion."""
994+ dropdown_button = self.select_single(objectName="combobutton_dropdown")
995+ self.pointing_device.click_object(dropdown_button)
996+
997+ def expand(self):
998+ """Expands a combo button by clicking on the dropdown button."""
999+ if self.expanded:
1000+ return
1001+ self.press_dropdown()
1002+
1003+ def collapse(self):
1004+ """Collapses a combo button by clicking on the dropdown button."""
1005+ if not self.expanded:
1006+ return
1007+ self.press_dropdown()
1008+
1009+
1010 class TextField(UbuntuUIToolkitEmulatorBase):
1011 """TextField Autopilot emulator."""
1012
1013
1014=== modified file 'tests/autopilot/ubuntuuitoolkit/tests/test_emulators.py'
1015--- tests/autopilot/ubuntuuitoolkit/tests/test_emulators.py 2014-03-22 06:53:24 +0000
1016+++ tests/autopilot/ubuntuuitoolkit/tests/test_emulators.py 2014-04-10 09:56:33 +0000
1017@@ -1079,3 +1079,48 @@
1018 self.composer_sheet.cancel()
1019 self.assertEqual(self.label.text, 'Cancel selected.')
1020 self._assert_composer_sheet_is_closed()
1021+
1022+
1023+class ComboButtonTestCase(tests.QMLStringAppTestCase):
1024+
1025+ test_qml = ("""
1026+import QtQuick 2.0
1027+import Ubuntu.Components 0.1
1028+import Ubuntu.Components.ListItems 0.1
1029+
1030+MainView {
1031+ width: units.gu(40)
1032+ height: units.gu(60)
1033+
1034+ Item {
1035+ ComboButton {
1036+ text: "main button"
1037+ objectName: "combo_button"
1038+ ListView {
1039+ model: 10
1040+ delegate: Standard {
1041+ text: "Item #" + modelData
1042+ }
1043+ }
1044+ }
1045+ }
1046+}
1047+""")
1048+
1049+ def setUp(self):
1050+ super(ComboButtonTestCase, self).setUp()
1051+ self.combo = self.main_view.select_single(
1052+ emulators.ComboButton, objectName="combo_button")
1053+ self.assertFalse(self.combo.expanded)
1054+
1055+ def test_expand_collapse_combo(self):
1056+ self.combo.expand()
1057+ self.assertTrue(self.combo.expanded)
1058+ self.combo.collapse()
1059+ self.assertFalse(self.combo.expanded)
1060+
1061+ def test_autocollapse(self):
1062+ self.combo.expand()
1063+ self.assertTrue(self.combo.expanded)
1064+ self.combo.press_mainbutton()
1065+ self.assertFalse(self.combo.expanded)
1066
1067=== added directory 'tests/resources/buttons'
1068=== added file 'tests/resources/buttons/ComboTest.qml'
1069--- tests/resources/buttons/ComboTest.qml 1970-01-01 00:00:00 +0000
1070+++ tests/resources/buttons/ComboTest.qml 2014-04-10 09:56:33 +0000
1071@@ -0,0 +1,147 @@
1072+/*
1073+ * Copyright 2014 Canonical Ltd.
1074+ *
1075+ * This program is free software; you can redistribute it and/or modify
1076+ * it under the terms of the GNU Lesser General Public License as published by
1077+ * the Free Software Foundation; version 3.
1078+ *
1079+ * This program is distributed in the hope that it will be useful,
1080+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
1081+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1082+ * GNU Lesser General Public License for more details.
1083+ *
1084+ * You should have received a copy of the GNU Lesser General Public License
1085+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
1086+ *
1087+ * Author: Zsombor Egri <zsombor.egri@canonical.com>
1088+ */
1089+import QtQuick 2.0
1090+import Ubuntu.Components 0.1
1091+import Ubuntu.Components.ListItems 0.1
1092+
1093+MainView {
1094+ width: units.gu(40)
1095+ height: units.gu(71)
1096+
1097+
1098+ Column {
1099+ anchors.fill: parent
1100+ spacing: units.gu(2)
1101+
1102+ ComboButton {
1103+ id: combo1
1104+ text: "collapsedHeight differs"
1105+ collapsedHeight: units.gu(6)
1106+ Rectangle {
1107+ color: "green"
1108+// height: combo1.comboListHeight
1109+ }
1110+ }
1111+
1112+ ComboButton {
1113+ text: "content is Rectangle > expanded"
1114+ Rectangle {
1115+ height: units.gu(40)
1116+ gradient: Gradient {
1117+ GradientStop {
1118+ position: 0.0
1119+ color: "red"
1120+ }
1121+ GradientStop {
1122+ position: 0.5
1123+ color: "green"
1124+ }
1125+ GradientStop {
1126+ position: 1.0
1127+ color: "blue"
1128+ }
1129+ }
1130+ }
1131+ }
1132+
1133+ ComboButton {
1134+ text: "comboList is Flickable"
1135+ Flickable {
1136+ id: flickable
1137+ objectName: "Flickable"
1138+ anchors {
1139+ left: parent.left
1140+ right: parent.right
1141+ top: parent.top
1142+ }
1143+ contentHeight: rect.height
1144+
1145+ Rectangle {
1146+ id: rect
1147+ width: parent.width
1148+ height: units.gu(40)
1149+ gradient: Gradient {
1150+ GradientStop {
1151+ position: 0.0
1152+ color: "red"
1153+ }
1154+ GradientStop {
1155+ position: 0.5
1156+ color: "green"
1157+ }
1158+ GradientStop {
1159+ position: 1.0
1160+ color: "blue"
1161+ }
1162+ }
1163+ }
1164+ }
1165+ }
1166+
1167+ ComboButton {
1168+ id: combo2
1169+ text: "comboList is ListView"
1170+ expanded: true
1171+ expandedHeight: units.gu(30)
1172+ UbuntuListView {
1173+ objectName: "ListView"
1174+ model: 20
1175+ delegate: Standard {
1176+ text: "Action #" + modelData
1177+ onClicked: {
1178+ combo2.text = text;
1179+ combo2.expanded = false
1180+ }
1181+ }
1182+ }
1183+ }
1184+
1185+ ComboButton {
1186+ id: combo3
1187+ text: "auto expandHeight"
1188+ expandedHeight: -1
1189+ Column {
1190+ id: column
1191+ anchors {
1192+ left: parent.left
1193+ right: parent.right
1194+ }
1195+ Rectangle {
1196+ width: parent.width
1197+ height: units.gu(6)
1198+ color: "red"
1199+ }
1200+ Rectangle {
1201+ width: parent.width
1202+ height: units.gu(6)
1203+ color: "green"
1204+ }
1205+ Rectangle {
1206+ width: parent.width
1207+ height: units.gu(6)
1208+ color: "blue"
1209+ }
1210+ Rectangle {
1211+ width: parent.width
1212+ height: units.gu(6)
1213+ color: "yellow"
1214+ }
1215+ }
1216+ }
1217+ }
1218+}
1219
1220=== modified file 'tests/unit/runtest.sh'
1221--- tests/unit/runtest.sh 2014-03-31 18:26:46 +0000
1222+++ tests/unit/runtest.sh 2014-04-10 09:56:33 +0000
1223@@ -33,7 +33,7 @@
1224 if [ $_TARGET != $_TESTFILE ]; then
1225 _CMD="$_CMD -input $_TESTFILE"
1226 fi
1227- _CMD="$_CMD -maxwarnings 4"
1228+ _CMD="$_CMD -maxwarnings 40"
1229 }
1230
1231 function execute_test_cmd {
1232
1233=== modified file 'tests/unit/tst_components/tst_button.qml'
1234--- tests/unit/tst_components/tst_button.qml 2013-05-28 12:37:56 +0000
1235+++ tests/unit/tst_components/tst_button.qml 2014-04-10 09:56:33 +0000
1236@@ -53,6 +53,10 @@
1237 compare(button.color,newColor,"Can set/get color")
1238 }
1239
1240+ function test_font() {
1241+ verify(button.font === Qt.font({family: "Ubuntu", pixelSize: FontUtils.sizeToPixels("medium")}), "Default font differs");
1242+ }
1243+
1244 function test_hovered() {
1245 compare(button.hovered,false,"Hovered is boolean and false by default")
1246 }
1247
1248=== added file 'tests/unit_x11/tst_components/tst_combobutton.qml'
1249--- tests/unit_x11/tst_components/tst_combobutton.qml 1970-01-01 00:00:00 +0000
1250+++ tests/unit_x11/tst_components/tst_combobutton.qml 2014-04-10 09:56:33 +0000
1251@@ -0,0 +1,246 @@
1252+/*
1253+ * Copyright 2014 Canonical Ltd.
1254+ *
1255+ * This program is free software; you can redistribute it and/or modify
1256+ * it under the terms of the GNU Lesser General Public License as published by
1257+ * the Free Software Foundation; version 3.
1258+ *
1259+ * This program is distributed in the hope that it will be useful,
1260+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
1261+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1262+ * GNU Lesser General Public License for more details.
1263+ *
1264+ * You should have received a copy of the GNU Lesser General Public License
1265+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
1266+ */
1267+
1268+import QtQuick 2.0
1269+import QtTest 1.0
1270+import Ubuntu.Test 0.1
1271+import Ubuntu.Components 0.1
1272+import Ubuntu.Components.ListItems 0.1
1273+
1274+Item {
1275+ width: units.gu(40)
1276+ height: units.gu(71)
1277+
1278+ Column {
1279+ ComboButton {
1280+ id: combo
1281+ }
1282+
1283+ ComboButton {
1284+ id: rectCombo
1285+
1286+ Rectangle {
1287+ id: rect
1288+ width: parent.width
1289+ height: units.gu(40)
1290+ gradient: Gradient {
1291+ GradientStop {
1292+ position: 0.0
1293+ color: "red"
1294+ }
1295+ GradientStop {
1296+ position: 0.5
1297+ color: "green"
1298+ }
1299+ GradientStop {
1300+ position: 1.0
1301+ color: "blue"
1302+ }
1303+ }
1304+ }
1305+ }
1306+
1307+ ComboButton {
1308+ id: columnCombo
1309+ expandedHeight: -1
1310+ Column {
1311+ id: column
1312+ anchors {
1313+ left: parent.left
1314+ right: parent.right
1315+ }
1316+ height: childrenRect.height
1317+ Repeater {
1318+ model: 5
1319+ Rectangle {
1320+ width: parent.width
1321+ height: units.gu(5)
1322+ color: Qt.rgba(Math.random(1), Math.random(1), Math.random(1), 1);
1323+ }
1324+ }
1325+ }
1326+ }
1327+
1328+ ComboButton {
1329+ id: longCombo
1330+ expandedHeight: units.gu(40)
1331+ Rectangle {
1332+ id: longRect
1333+ height: units.gu(10)
1334+ color: "cyan"
1335+ }
1336+ }
1337+
1338+ ComboButton {
1339+ id: listCombo
1340+ ListView {
1341+ id: list
1342+ model: 20
1343+ height: listCombo.comboListHeight
1344+ delegate: Standard {
1345+ text: modelData
1346+ }
1347+ }
1348+ }
1349+ }
1350+
1351+ SignalSpy { id: spy }
1352+
1353+ UbuntuTestCase {
1354+ name: "ComboButton"
1355+ when: windowShown
1356+
1357+ function cleanup() {
1358+ rectCombo.expanded =
1359+ columnCombo.expanded =
1360+ longCombo.expanded =
1361+ listCombo.expanded = false;
1362+ spy.clear();
1363+ spy.signalName = "";
1364+ spy.target = undefined;
1365+ }
1366+
1367+ function test_0_defaults() {
1368+ compare(combo.expanded, false, "not expanded by default");
1369+ compare(combo.autoCollapse, true, "automatically collapses");
1370+ compare(combo.collapsedHeight, combo.implicitHeight, "collapsedHeight is implicitHeight");
1371+ compare(combo.expandedHeight, combo.collapsedHeight + units.gu(19.5), "expanded height default");
1372+ var lheight = combo.expandedHeight - combo.collapsedHeight - combo.__styleInstance.comboListMargin;
1373+ compare(combo.comboListHeight, lheight, "comboListHeight default");
1374+ compare(combo.comboList.length, 0, "comboList is empty");
1375+ verify(combo.font === Qt.font({family: "Ubuntu", pixelSize: FontUtils.sizeToPixels("medium")}), "Default font differs.");
1376+ verify(combo.dropdownColorPressed === combo.__styleInstance.defaultDropdownColorPressed, "Default dropdown pressed color differs");
1377+ verify(combo.dropdownColorReleased === combo.__styleInstance.defaultDropdownColorReleased, "Default dropdown released color differs");
1378+ }
1379+
1380+ function test_dropdownColor() {
1381+ rectCombo.dropdownColorPressed = "red";
1382+ rectCombo.dropdownColorReleased = "green";
1383+ rectCombo.expanded = false;
1384+ var dropdownFace = findChild(rectCombo, "combobutton_dropdown_visuals");
1385+ verify(dropdownFace, "Dropdown button visuals cannot be reached");
1386+ verify(dropdownFace.color === rectCombo.dropdownColorReleased, "Dropdon color when collapsed wrong");
1387+ rectCombo.expanded = true;
1388+ waitForRendering(rectCombo);
1389+ verify(dropdownFace.color === rectCombo.dropdownColorPressed, "Dropdon color when expanded wrong");
1390+ }
1391+
1392+ function test_comboListWidth() {
1393+ var comboListHolder = findChild(rectCombo, "combobutton_combolist");
1394+ compare(rect.width, comboListHolder.width, "rectCombo list content width is not adjusted");
1395+ comboListHolder = findChild(columnCombo, "combobutton_combolist");
1396+ compare(column.width, comboListHolder.width, "columnCombo list content width is not adjusted");
1397+ comboListHolder = findChild(longCombo, "combobutton_combolist");
1398+ compare(longRect.width, comboListHolder.width, "longCombo list content width is not adjusted");
1399+ comboListHolder = findChild(listCombo, "combobutton_combolist");
1400+ compare(list.width, comboListHolder.width, "listCombo list content width is not adjusted");
1401+ }
1402+
1403+ function test_expandRectComboThroughProperty() {
1404+ rectCombo.expanded = true;
1405+ waitForRendering(rectCombo);
1406+ var comboListPanel = findChild(rectCombo, "combobutton_combopanel");
1407+ tryCompareFunction(function() { return comboListPanel.opacity}, 1.0);
1408+ }
1409+
1410+ function test_expandRectComboThroughClick() {
1411+ var dropDown = findChild(rectCombo, "combobutton_dropdown");
1412+ mouseClick(dropDown, dropDown.width / 2, dropDown.height / 2);
1413+ waitForRendering(rectCombo);
1414+ compare(rectCombo.expanded, true, "combo is not expanded");
1415+ var comboListPanel = findChild(rectCombo, "combobutton_combopanel");
1416+ tryCompareFunction(function() { return comboListPanel.opacity}, 1.0);
1417+ }
1418+
1419+ function test_autoCollapse() {
1420+ var dropDown = findChild(rectCombo, "combobutton_dropdown");
1421+ var comboListPanel = findChild(rectCombo, "combobutton_combopanel");
1422+ mouseClick(dropDown, dropDown.width / 2, dropDown.height / 2);
1423+ waitForRendering(rectCombo);
1424+ compare(rectCombo.expanded, true, "combo is not expanded");
1425+ tryCompareFunction(function() { return comboListPanel.opacity}, 1.0);
1426+
1427+ mouseClick(rectCombo, rectCombo.width / 2, rectCombo.collapsedHeight / 2);
1428+ waitForRendering(rectCombo);
1429+ compare(rectCombo.expanded, false, "combo is not collapsed");
1430+ tryCompareFunction(function() { return comboListPanel.opacity}, 0.0);
1431+ }
1432+
1433+ function test_flickRectCombo() {
1434+ var dropDown = findChild(rectCombo, "combobutton_dropdown");
1435+ var comboListPanel = findChild(rectCombo, "combobutton_combopanel");
1436+ var comboList = findChild(rectCombo, "combobutton_combolist");
1437+ mouseClick(dropDown, dropDown.width / 2, dropDown.height / 2);
1438+ waitForRendering(rectCombo);
1439+ tryCompareFunction(function() { return comboListPanel.opacity}, 1.0);
1440+ verify(comboList.height > rectCombo.expandedHeight);
1441+ // comboList flicker is the combolist parent's parent
1442+ var comboListFlicker = comboList.parent.parent;
1443+ compare(comboListFlicker.interactive, true, "combo list holder must be interactive");
1444+
1445+ // drag the rectangle, the Flickable should be moving
1446+ var x = comboListFlicker.width / 2;
1447+ var y = comboListFlicker.height / 2;
1448+ var dy = comboListFlicker.height / 6;
1449+ spy.target = comboListFlicker;
1450+ spy.signalName = "onMovementEnded";
1451+ mouseDrag(comboListFlicker, x, y, x, dy);
1452+ waitForRendering(comboListFlicker);
1453+ compare(spy.count, 1, "combo list content did not move");
1454+ }
1455+
1456+ function test_autoExpandHeight() {
1457+ var comboListPanel = findChild(columnCombo, "combobutton_combopanel");
1458+ var comboList = findChild(columnCombo, "combobutton_combolist");
1459+ columnCombo.expanded = true;
1460+ waitForRendering(columnCombo);
1461+ tryCompareFunction(function() { return comboListPanel.opacity}, 1.0);
1462+ var comboListFlicker = comboList.parent.parent;
1463+ compare(comboListFlicker.interactive, false, "combo list holder must not be interactive");
1464+ compare(comboListFlicker.height, columnCombo.comboListHeight, "combo list height differs from the holder height");
1465+ }
1466+
1467+ function test_emptyComboExpanded() {
1468+ var comboListPanel = findChild(combo, "combobutton_combopanel");
1469+ var comboList = findChild(combo, "combobutton_combolist");
1470+ combo.expanded = true;
1471+ waitForRendering(combo);
1472+ waitForRendering(comboListPanel);
1473+ tryCompareFunction(function() { return comboListPanel.opacity}, 0.0, 1000);
1474+ }
1475+
1476+ function test_longCombo() {
1477+ var comboListPanel = findChild(longCombo, "combobutton_combopanel");
1478+ var comboList = findChild(longCombo, "combobutton_combolist");
1479+ longCombo.expanded = true;
1480+ waitForRendering(longCombo);
1481+ waitForRendering(comboListPanel);
1482+ tryCompareFunction(function() { return comboListPanel.opacity}, 1.0);
1483+ verify(comboListPanel.height < longCombo.expandedHeight);
1484+ }
1485+
1486+ function test_listCombo() {
1487+ var comboListPanel = findChild(listCombo, "combobutton_combopanel");
1488+ var comboList = findChild(listCombo, "combobutton_combolist");
1489+ listCombo.expanded = true;
1490+ waitForRendering(listCombo);
1491+ waitForRendering(comboListPanel);
1492+ tryCompareFunction(function() { return comboListPanel.opacity}, 1.0);
1493+
1494+ compare(list.height, comboList.height, "list and comboList height differs");
1495+ }
1496+ }
1497+}
1498
1499=== modified file 'tests/unit_x11/tst_components/tst_components.pro'
1500--- tests/unit_x11/tst_components/tst_components.pro 2013-11-26 12:44:39 +0000
1501+++ tests/unit_x11/tst_components/tst_components.pro 2014-04-10 09:56:33 +0000
1502@@ -7,4 +7,5 @@
1503 SOURCES += tst_components.cpp tabsmodel.cpp
1504 HEADERS += tabsmodel.h
1505
1506-OTHER_FILES += $$system(ls *.qml)
1507+OTHER_FILES += $$system(ls *.qml) \
1508+ tst_combobutton.qml
1509
1510=== modified file 'tests/unit_x11/tst_test/tst_ubuntutestcase.qml'
1511--- tests/unit_x11/tst_test/tst_ubuntutestcase.qml 2014-02-13 10:27:14 +0000
1512+++ tests/unit_x11/tst_test/tst_ubuntutestcase.qml 2014-04-10 09:56:33 +0000
1513@@ -23,30 +23,57 @@
1514 width: 800
1515 height: 600
1516
1517- MouseArea {
1518- id: mouseArea
1519- objectName: "myMouseArea"
1520- anchors.fill: parent
1521- hoverEnabled: true
1522- property int testX : 0
1523- property int testY : 0
1524- property int steps : 0
1525+ Column {
1526+ anchors.fill: parent
1527+ MouseArea {
1528+ id: mouseArea
1529+ objectName: "myMouseArea"
1530+ width: parent.width
1531+ height: 300
1532+ hoverEnabled: true
1533+ acceptedButtons: Qt.LeftButton | Qt.MiddleButton | Qt.RightButton
1534+ property int testX : 0
1535+ property int testY : 0
1536+ property int steps : 0
1537
1538- onPositionChanged: {
1539- testX = mouseX;
1540- testY = mouseY;
1541- steps++;
1542- }
1543+ onPositionChanged: {
1544+ testX = mouseX;
1545+ testY = mouseY;
1546+ steps++;
1547+ }
1548+ }
1549+ Flickable {
1550+ id: flicker
1551+ width: parent.width
1552+ height: 400
1553+ contentWidth: rect.width
1554+ contentHeight: rect.height
1555+ clip: true
1556+ Rectangle {
1557+ id: rect
1558+ color: "blue"
1559+ width: 1000
1560+ height: 1000
1561+ }
1562+ }
1563 }
1564
1565 UbuntuTestCase {
1566 name: "TestTheUbuntuTestCase"
1567 when: windowShown
1568
1569+ function init() {
1570+ mouseArea.steps = 0;
1571+ }
1572+ function cleanup() {
1573+ movementSpy.clear();
1574+ longPressSpy.clear();
1575+ }
1576+
1577 function test_mouseMoveSlowly() {
1578- mouseMoveSlowly(root,0,0,800,600,10,100);
1579+ mouseMoveSlowly(root,0,0,800,300,10,100);
1580 compare(mouseArea.testX,800);
1581- compare(mouseArea.testY,600);
1582+ compare(mouseArea.testY,300);
1583 compare(mouseArea.steps,10);
1584 }
1585
1586@@ -58,5 +85,66 @@
1587 child = findChild(root,"NoSuchChildHere");
1588 compare(child===null,true,"When there is no child, function should return null");
1589 }
1590+
1591+ SignalSpy {
1592+ id: longPressSpy
1593+ target: mouseArea
1594+ signalName: "onPressAndHold"
1595+ }
1596+
1597+ function test_longPress_left() {
1598+ longPressSpy.clear();
1599+ mouseLongPress(mouseArea, mouseArea.width / 2, mouseArea.height / 2);
1600+ longPressSpy.wait();
1601+ // cleanup
1602+ mouseRelease(mouseArea, mouseArea.width / 2, mouseArea.height / 2);
1603+ }
1604+
1605+ function test_longPress_right() {
1606+ longPressSpy.clear();
1607+ mouseLongPress(mouseArea, mouseArea.width / 2, mouseArea.height / 2, Qt.RightButton);
1608+ longPressSpy.wait();
1609+ // cleanup
1610+ mouseRelease(mouseArea, mouseArea.width / 2, mouseArea.height / 2, Qt.RightButton);
1611+ }
1612+
1613+ function test_longPress_middle() {
1614+ longPressSpy.clear();
1615+ mouseLongPress(mouseArea, mouseArea.width / 2, mouseArea.height / 2, Qt.MiddleButton);
1616+ longPressSpy.wait();
1617+ // cleanup
1618+ mouseRelease(mouseArea, mouseArea.width / 2, mouseArea.height / 2, Qt.MiddleButton);
1619+ }
1620+
1621+ SignalSpy {
1622+ id: movementSpy
1623+ target: flicker
1624+ signalName: "onMovementEnded"
1625+ }
1626+
1627+ function test_flick_default() {
1628+ flick(flicker, 0, 0, flicker.width, flicker.height);
1629+ movementSpy.wait();
1630+ }
1631+ function test_flick_long() {
1632+ flick(flicker, 0, 0, flicker.width, flicker.height, -1, 10);
1633+ movementSpy.wait();
1634+ }
1635+ function test_flick_short() {
1636+ flick(flicker, 0, 0, flicker.width, flicker.height, -1, 1);
1637+ movementSpy.wait();
1638+ }
1639+ function test_flick_pressTimeout() {
1640+ flick(flicker, 0, 0, flicker.width, flicker.height, 400);
1641+ movementSpy.wait();
1642+ }
1643+ function test_flick_pressTimeout_short() {
1644+ flick(flicker, flicker.width, flicker.height, -flicker.width, -flicker.height, 400, 1);
1645+ movementSpy.wait();
1646+ }
1647+ function test_flick_pressTimeout_long() {
1648+ flick(flicker, flicker.width, flicker.height, -flicker.width, -flicker.height, 400, 100);
1649+ movementSpy.wait();
1650+ }
1651 }
1652 }

Subscribers

People subscribed via source and target branches

to status/vote changes: