Merge lp:~zsombi/ubuntu-ui-toolkit/bottomEdge into lp:ubuntu-ui-toolkit/staging
- bottomEdge
- Merge into staging
Status: | Merged | ||||
---|---|---|---|---|---|
Approved by: | Tim Peeters | ||||
Approved revision: | 1781 | ||||
Merged at revision: | 1731 | ||||
Proposed branch: | lp:~zsombi/ubuntu-ui-toolkit/bottomEdge | ||||
Merge into: | lp:ubuntu-ui-toolkit/staging | ||||
Diff against target: |
4292 lines (+3826/-40) 47 files modified
components.api (+48/-0) examples/ubuntu-ui-toolkit-gallery/BottomEdgePage.qml (+177/-14) examples/ubuntu-ui-toolkit-gallery/Template.qml (+1/-0) examples/ubuntu-ui-toolkit-gallery/TemplateRow.qml (+1/-1) examples/ubuntu-ui-toolkit-gallery/gallery-logging.config (+1/-0) src/Ubuntu/Components/1.3/AdaptivePageLayout.qml (+0/-2) src/Ubuntu/Components/1.3/PageTreeNode.qml (+0/-4) src/Ubuntu/Components/ComponentModule.pro (+1/-1) src/Ubuntu/Components/Themes/Ambiance/1.3/BottomEdgeStyle.qml (+125/-0) src/Ubuntu/Components/Themes/Ambiance/Ambiance.pro (+2/-1) src/Ubuntu/Components/Themes/Ambiance/qmldir (+2/-0) src/Ubuntu/Components/plugin/plugin.cpp (+6/-0) src/Ubuntu/Components/plugin/plugin.pri (+9/-2) src/Ubuntu/Components/plugin/ucaction.h (+6/-5) src/Ubuntu/Components/plugin/ucbottomedge.cpp (+1059/-0) src/Ubuntu/Components/plugin/ucbottomedge.h (+120/-0) src/Ubuntu/Components/plugin/ucbottomedge_p.h (+111/-0) src/Ubuntu/Components/plugin/ucbottomedgehint.cpp (+1/-1) src/Ubuntu/Components/plugin/ucbottomedgehint.h (+2/-0) src/Ubuntu/Components/plugin/ucbottomedgeregion.cpp (+253/-0) src/Ubuntu/Components/plugin/ucbottomedgeregion.h (+78/-0) src/Ubuntu/Components/plugin/ucbottomedgestyle.cpp (+65/-0) src/Ubuntu/Components/plugin/ucbottomedgestyle.h (+60/-0) src/Ubuntu/Components/plugin/ucstyleditembase.cpp (+21/-5) src/Ubuntu/Components/plugin/ucstyleditembase.h (+1/-0) src/Ubuntu/Components/plugin/ucstyleditembase_p.h (+2/-0) src/Ubuntu/Test/plugin/uctestextras.cpp (+136/-3) src/Ubuntu/Test/plugin/uctestextras.h (+6/-0) tests/unit_x11/tst_bottomedge/AddCustomRegionOnCompleted.qml (+41/-0) tests/unit_x11/tst_bottomedge/AddCustomRegionOwnedByOtherBottomEdge.qml (+39/-0) tests/unit_x11/tst_bottomedge/AddCustomRegionUsingDataProperty.qml (+33/-0) tests/unit_x11/tst_bottomedge/AddCustomRegionUsingRegionsProperty.qml (+33/-0) tests/unit_x11/tst_bottomedge/AlternateDefaultRegionContent.qml (+53/-0) tests/unit_x11/tst_bottomedge/AlternateRegionContent.qml (+47/-0) tests/unit_x11/tst_bottomedge/AutoCollapseInPageHeader.qml (+45/-0) tests/unit_x11/tst_bottomedge/AutoCollapseInPageWithPageHeader.qml (+44/-0) tests/unit_x11/tst_bottomedge/BottomEdgeInItem.qml (+36/-0) tests/unit_x11/tst_bottomedge/ClearCustomRegions.qml (+42/-0) tests/unit_x11/tst_bottomedge/Defaults.qml (+28/-0) tests/unit_x11/tst_bottomedge/DifferentSizes.qml (+34/-0) tests/unit_x11/tst_bottomedge/LastItem.qml (+46/-0) tests/unit_x11/tst_bottomedge/LeanActiveRegionChange.qml (+45/-0) tests/unit_x11/tst_bottomedge/OverlappingRegions.qml (+46/-0) tests/unit_x11/tst_bottomedge/ShorterBottomEdge.qml (+39/-0) tests/unit_x11/tst_bottomedge/tst_bottomedge.cpp (+856/-0) tests/unit_x11/tst_bottomedge/tst_bottomedge.pro (+23/-0) tests/unit_x11/unit_x11.pro (+2/-1) |
||||
To merge this branch: | bzr merge lp:~zsombi/ubuntu-ui-toolkit/bottomEdge | ||||
Related bugs: |
|
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
PS Jenkins bot | continuous-integration | Approve | |
Tim Peeters | Approve | ||
Review via email: mp+278336@code.launchpad.net |
Commit message
BottomEdge component
Description of the change
PS Jenkins bot (ps-jenkins) wrote : | # |
Tim Peeters (tpeeters) wrote : | # |
In the gallery, I can over-drag the bottom edge a bit, which puts the app in a weird state until it pops back to a closed bottom edge in about 500ms. See https:/
I think instead of this, the contents should snap to open fully instead of being able to drag it too far.
Tim Peeters (tpeeters) wrote : | # |
qml: WARNING! Do not put Page/Tabs/PageStack inside another Page because that causes confusion which is the active page that sets the title and actions.
This is a bit annoying. I think we can remove this warning now. With the new header, it is no longer a problem to define a Page inside another Page.
Tim Peeters (tpeeters) wrote : | # |
> qml: WARNING! Do not put Page/Tabs/PageStack inside another Page because that
> causes confusion which is the active page that sets the title and actions.
>
> This is a bit annoying. I think we can remove this warning now. With the new
> header, it is no longer a problem to define a Page inside another Page.
better to do that in another MR, so just leave it here.
Tim Peeters (tpeeters) wrote : | # |
I find the line on top of the bottom edge when it is open ugly.
https:/
Also, see the comments I added to the API doc, and one diff comment below (more to follow).
Tim Peeters (tpeeters) wrote : | # |
I don't understand what "push content into the layout" does, and why when I open the bottom edge with that checkbox checked, it says state: hidden in the header: https:/
Tim Peeters (tpeeters) wrote : | # |
See more inline comments.
Since the BottomEdgeRegions are (at the moment) mainly used in the browser, perhaps we should ask the browser guys to test this MR (ideally to have a prototype browser that uses this) to see if it fulfills all their requirements.
Zsombor Egri (zsombi) wrote : | # |
> See more inline comments.
>
>
> Since the BottomEdgeRegions are (at the moment) mainly used in the browser,
> perhaps we should ask the browser guys to test this MR (ideally to have a
> prototype browser that uses this) to see if it fulfills all their
> requirements.
It is not only in the Browser, there can be many other use cases for it. And then the whole logic is implemented using that. We talked about this in Berlin with mzanetti while going to the hotel from airport that he'd need such a functionality in his apps. And honestly I would not spend time to add it later when we have it right away.
Zsombor Egri (zsombi) wrote : | # |
Replied to the inline comments, and pushed the changes I had so far. Revisions starting 1740 are for tests, please check them one by one to see the progress.
There are more tests to come. Will keep you posted.
- 1740. By Zsombor Egri
-
implicit height fix
- 1741. By Zsombor Egri
-
implicit height fix
- 1742. By Zsombor Egri
-
complete default check
- 1743. By Zsombor Egri
-
fix reparenting
- 1744. By Zsombor Egri
-
adding remaining test skeletons
- 1745. By Zsombor Egri
-
test that BottomEdgeStyle instance is always the last child
- 1746. By Zsombor Egri
-
test commit on click
- 1747. By Zsombor Egri
-
touch-click commits
- 1748. By Zsombor Egri
-
rename state into status, content into contentUrl
- 1749. By Zsombor Egri
-
verifying state transition when the bottom edge is swiped for a short time
- 1750. By Zsombor Egri
-
verifying state transition when the bottom edge is swiped for a short time
- 1751. By Zsombor Egri
-
add some threshold and extra steps especially for touch to properly produce a swipe
- 1752. By Zsombor Egri
-
drag downwards after dragged upwards collapses
- 1753. By Zsombor Egri
-
bottomedge height is less than the parent's height
- 1754. By Zsombor Egri
-
do not overshoot; API fix
- 1755. By Zsombor Egri
-
commit signals test
- 1756. By Zsombor Egri
-
collapse signals test
- 1757. By Zsombor Egri
-
collapse signals test
- 1758. By Zsombor Egri
-
fixing doc for contentUrl and contentComponent
- 1759. By Zsombor Egri
-
wording fix
- 1760. By Zsombor Egri
-
wording fix
- 1761. By Zsombor Egri
-
typo fix
- 1762. By Zsombor Egri
-
property fix
- 1763. By Zsombor Egri
-
qdoc tag fix
PS Jenkins bot (ps-jenkins) wrote : | # |
PASSED: Continuous integration, rev:1763
http://
Executed test runs:
SUCCESS: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
Tim Peeters (tpeeters) wrote : | # |
The hint text is not centered any more (in gallery), see https:/
Tim Peeters (tpeeters) wrote : | # |
> > 304 - // we need to clip because the header does not have a background
> > 305 - clip: true
> > we shouldn't just remove this. It is no longer needed with the new PageHeader,
> > but apps may still > use the old AppHeader (by configuring Page.head, instead of
> > using Page.header).
> If we have this clip set, the bottom edge content header will always be clipped. I am open
> for solutions.
Removing it will break current apps. The solution for UITK 1.4/2.0 will come easy, because there we will remove the old AppHeader.
For now, we could add a solid background to the AppHeader that is the same color as the MainView.
- 1764. By Zsombor Egri
-
commit on collapse test case
- 1765. By Zsombor Egri
-
region operation tests
- 1766. By Zsombor Egri
-
alternate default region content
- 1767. By Zsombor Egri
-
rest order reshufled, covered tests removed
- 1768. By Zsombor Egri
-
dragEnded test
- 1769. By Zsombor Egri
-
end drag in region commits to teh region top
- 1770. By Zsombor Egri
-
collapse when the drag ends in an area that is not covered by any region
- 1771. By Zsombor Egri
-
remove tests covered by default check
- 1772. By Zsombor Egri
-
validate and warn on overlapping regions
- 1773. By Zsombor Egri
-
refining region validation
- 1774. By Zsombor Egri
-
auto-collapse added if content has PageHeader; remove warning about nesting page
- 1775. By Zsombor Egri
-
remove style specific test
- 1776. By Zsombor Egri
-
remove fill reset as it destroys the style overriden one, causing the nint to be mislocated
- 1777. By Zsombor Egri
-
change default region limits in gallery
- 1778. By Zsombor Egri
-
redo validation to validate runtime too
- 1779. By Zsombor Egri
-
remove comments, tweaking done meantime seemed to help
- 1780. By Zsombor Egri
-
staging sync
Zsombor Egri (zsombi) wrote : | # |
> > > 304 - // we need to clip because the header does not have a background
> > > 305 - clip: true
> > > we shouldn't just remove this. It is no longer needed with the new
> PageHeader,
> > > but apps may still > use the old AppHeader (by configuring Page.head,
> instead of
> > > using Page.header).
>
> > If we have this clip set, the bottom edge content header will always be
> clipped. I am open
> > for solutions.
>
> Removing it will break current apps. The solution for UITK 1.4/2.0 will come
> easy, because there we will remove the old AppHeader.
No, we cannot. That's the problem. We announce the deprecation 1.3, which means we have to keep it one more version and then remove it. So as long as 1.4 will have the AppHeader, it will cause trouble, because people will still use it.
>
> For now, we could add a solid background to the AppHeader that is the same
> color as the MainView.
> texture or gradient (old designs), the header does not match any more, so it
> may mess up existing apps. An alternative is to force people to switch to the
> new header when they use APL.
What if we do it in a separate MR? Like immediately after this...
Zsombor Egri (zsombi) wrote : | # |
> The hint text is not centered any more (in gallery), see https:/
> om/s/uvwzak5eum
Fixed, it was the anchor.fill introduced by the style overridden by the cpp resetFill() :/
PS Jenkins bot (ps-jenkins) wrote : | # |
PASSED: Continuous integration, rev:1780
http://
Executed test runs:
SUCCESS: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
- 1781. By Zsombor Egri
-
activeRegion changes optimized
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:1781
http://
Executed test runs:
SUCCESS: http://
SUCCESS: http://
deb: http://
FAILURE: http://
Click here to trigger a rebuild:
http://
Tim Peeters (tpeeters) wrote : | # |
> > > > 304 - // we need to clip because the header does not have a background
> > > > 305 - clip: true
> > > > we shouldn't just remove this. It is no longer needed with the new
> > PageHeader,
> > > > but apps may still > use the old AppHeader (by configuring Page.head,
> > instead of
> > > > using Page.header).
> >
> > > If we have this clip set, the bottom edge content header will always be
> > clipped. I am open
> > > for solutions.
> >
> > Removing it will break current apps. The solution for UITK 1.4/2.0 will come
> > easy, because there we will remove the old AppHeader.
>
> No, we cannot. That's the problem. We announce the deprecation 1.3, which
> means we have to keep it one more version and then remove it. So as long as
> 1.4 will have the AppHeader, it will cause trouble, because people will still
> use it.
>
> >
> > For now, we could add a solid background to the AppHeader that is the same
> > color as the MainView.
> > texture or gradient (old designs), the header does not match any more, so it
> > may mess up existing apps. An alternative is to force people to switch to
> the
> > new header when they use APL.
>
> What if we do it in a separate MR? Like immediately after this...
If we do it *after*, then we have the header+APL broken until that next MR lands...
Tim Peeters (tpeeters) wrote : | # |
looks good. But we MUST give the AppHeader a background in a separate MR before landing this in trunk.
PS Jenkins bot (ps-jenkins) : | # |
Tim Peeters (tpeeters) wrote : | # |
The desire to give the AppHeader a background as stated above, was reported in this bug: https:/
Preview Diff
1 | === modified file 'components.api' |
2 | --- components.api 2015-11-20 07:47:08 +0000 |
3 | +++ components.api 2015-11-27 10:36:32 +0000 |
4 | @@ -175,6 +175,36 @@ |
5 | property var icon |
6 | property bool iconFrame |
7 | property bool progression |
8 | +Ubuntu.Components.BottomEdge 1.3: StyledItem |
9 | + readonly property BottomEdgeRegion activeRegion |
10 | + property Component contentComponent |
11 | + readonly property Item contentItem |
12 | + property url contentUrl |
13 | + readonly property DragDirection dragDirection |
14 | + readonly property double dragProgress |
15 | + readonly property BottomEdgeHint hint |
16 | + signal dragProgressChanged(double dragProgress) |
17 | + signal dragDirectionChanged(BottomEdge.DragDirection direction) |
18 | + signal statusChanged(BottomEdge.Status status) |
19 | + signal contentChanged(url url) |
20 | + signal contentComponentChanged(Component component) |
21 | + signal activeRegionChanged(BottomEdgeRegion activeRegion) |
22 | + signal commitStarted() |
23 | + signal commitCompleted() |
24 | + signal collapseStarted() |
25 | + signal collapseCompleted() |
26 | + function commit() |
27 | + function collapse() |
28 | + property list<BottomEdgeRegion> regions |
29 | + readonly property Status status |
30 | +Ubuntu.Components.BottomEdge.DragDirection: Enum |
31 | + Downwards |
32 | + Undefined |
33 | + Upwards |
34 | +Ubuntu.Components.BottomEdge.Status: Enum |
35 | + Committed |
36 | + Hidden |
37 | + Revealed |
38 | Ubuntu.Components.BottomEdgeHint 1.3: ActionItem |
39 | property int deactivateTimeout |
40 | property Flickable flickable |
41 | @@ -186,6 +216,20 @@ |
42 | Hidden |
43 | Inactive |
44 | Locked |
45 | +Ubuntu.Components.BottomEdgeRegion 1.3: QtObject |
46 | + property Component contentComponent |
47 | + property url contentUrl |
48 | + property bool enabled |
49 | + property double from |
50 | + signal entered() |
51 | + signal exited() |
52 | + signal dragEnded() |
53 | + property double to |
54 | +Ubuntu.Components.Styles.BottomEdgeStyle 1.3: Item |
55 | + property Item contentItem |
56 | + property Item panel |
57 | + property Animation panelAnimation |
58 | + property double revealThreshold |
59 | Ubuntu.Components.Button 1.0 0.1: AbstractButton |
60 | property color color |
61 | property QFont font |
62 | @@ -1131,6 +1175,10 @@ |
63 | function touchMove(int touchId, Item item, Qt.point point) |
64 | function touchDrag(int touchId, Item item, Qt.point from, Qt.point delta, int steps) |
65 | function touchDrag(int touchId, Item item, Qt.point from, Qt.point delta) |
66 | + function mouseDrag(Item item, Qt.point from, Qt.point delta, Qt.MouseButton button, Qt.KeyboardModifiers stateKey, int steps, int delay) |
67 | + function mouseDrag(Item item, Qt.point from, Qt.point delta, Qt.MouseButton button, Qt.KeyboardModifiers stateKey, int steps) |
68 | + function mouseDrag(Item item, Qt.point from, Qt.point delta, Qt.MouseButton button, Qt.KeyboardModifiers stateKey) |
69 | + function mouseDrag(Item item, Qt.point from, Qt.point delta, Qt.MouseButton button) |
70 | readonly property bool touchPresent |
71 | Ubuntu.Components.TextArea 1.0 0.1: StyledItem |
72 | property bool autoExpand |
73 | |
74 | === modified file 'examples/ubuntu-ui-toolkit-gallery/BottomEdgePage.qml' |
75 | --- examples/ubuntu-ui-toolkit-gallery/BottomEdgePage.qml 2015-11-05 14:28:58 +0000 |
76 | +++ examples/ubuntu-ui-toolkit-gallery/BottomEdgePage.qml 2015-11-27 10:36:32 +0000 |
77 | @@ -17,22 +17,185 @@ |
78 | import QtQuick 2.4 |
79 | import Ubuntu.Components 1.3 |
80 | |
81 | -Page { |
82 | +Template { |
83 | + id: page |
84 | + header: PageHeader { |
85 | + title: i18n.tr("Bottom Edge") |
86 | + trailingActionBar.actions: [ |
87 | + bottomEdge.hint.action |
88 | + ] |
89 | + } |
90 | + |
91 | TemplateSection { |
92 | - title: "Bottom Edge Hint" |
93 | + title: "BottomEdgeHint" |
94 | className: "BottomEdgeHint" |
95 | |
96 | - anchors { |
97 | - top: parent.top |
98 | - left: parent.left |
99 | - right: parent.right |
100 | - margins: units.gu(2) |
101 | - } |
102 | - } |
103 | - |
104 | - BottomEdgeHint { |
105 | - iconName: "stock_message" |
106 | - text: "Compose a new message" |
107 | - onClicked: state = "Hidden" |
108 | + TemplateRow { |
109 | + title: i18n.tr("On clicked") |
110 | + Row { |
111 | + spacing: units.gu(1) |
112 | + CheckBox { |
113 | + id: contentToLayout |
114 | + text: i18n.tr("push content into the layout") |
115 | + enabled: bottomEdge.hint.status >= BottomEdgeHint.Active |
116 | + } |
117 | + Label { |
118 | + text: contentToLayout.text |
119 | + anchors.verticalCenter: contentToLayout.verticalCenter |
120 | + } |
121 | + } |
122 | + } |
123 | + } |
124 | + |
125 | + TemplateSection { |
126 | + title: "BottomEdge" |
127 | + className: "BottomEdge" |
128 | + |
129 | + TemplateRow { |
130 | + title: i18n.tr("Top") |
131 | + Slider { |
132 | + id: bottomEdgeHeight |
133 | + maximumValue: page.height |
134 | + value: bottomEdge.height |
135 | + onValueChanged: bottomEdge.height = value |
136 | + } |
137 | + } |
138 | + |
139 | + TemplateRow { |
140 | + title: i18n.tr("Hint") |
141 | + Row { |
142 | + spacing: units.gu(1) |
143 | + CheckBox { |
144 | + id: attachHintToContent |
145 | + text: i18n.tr("attach hint to content") |
146 | + } |
147 | + Label { |
148 | + text: attachHintToContent.text |
149 | + anchors.verticalCenter: attachHintToContent.verticalCenter |
150 | + } |
151 | + } |
152 | + } |
153 | + |
154 | + TemplateRow { |
155 | + title: i18n.tr("Regions") |
156 | + Slider { |
157 | + id: regionCount |
158 | + width: units.gu(20) |
159 | + maximumValue: 3.0 |
160 | + live: true |
161 | + } |
162 | + } |
163 | + Repeater { |
164 | + id: regionConfig |
165 | + model: regionCount.value.toFixed(0) |
166 | + TemplateRow { |
167 | + title: i18n.tr("Region #%1").arg(index) |
168 | + property int regionIndex: index |
169 | + Repeater { |
170 | + model: ["from", "to"] |
171 | + Row { |
172 | + spacing: units.gu(2) |
173 | + Label { |
174 | + text: i18n.tr(modelData) |
175 | + } |
176 | + TextField { |
177 | + id: regionFrom |
178 | + text: bottomEdge.regions[regionIndex][modelData] |
179 | + validator: DoubleValidator {bottom: 0.0; top: 1.0; decimals: 2; locale: "d.d"} |
180 | + inputMethodHints: Qt.ImhPreferNumbers | Qt.ImhFormattedNumbersOnly |
181 | + width: units.gu(7) |
182 | + hasClearButton: false |
183 | + errorHighlight: true |
184 | + onAccepted: bottomEdge.regions[regionIndex][modelData] = text |
185 | + onTextChanged: { |
186 | + if (regionFrom.acceptableInput) { |
187 | + bottomEdge.regions[regionIndex][modelData] = parseFloat(text); |
188 | + } |
189 | + } |
190 | + onActiveFocusChanged: if (activeFocus) selectAll() |
191 | + } |
192 | + } |
193 | + } |
194 | + } |
195 | + } |
196 | + } |
197 | + |
198 | + BottomEdge { |
199 | + id: bottomEdge |
200 | + // make sure it doesn't land inside the flickable |
201 | + parent: page |
202 | + // hint |
203 | + hint { |
204 | + action: Action { |
205 | + text: "Demo content" |
206 | + iconName: "stock_message" |
207 | + onTriggered: bottomEdge.commit() |
208 | + } |
209 | + flickable: page.flickable |
210 | + } |
211 | + contentComponent: bottomEdgeContent |
212 | + |
213 | + StyleHints { |
214 | + attachHintToContent: attachHintToContent.checked |
215 | + } |
216 | + |
217 | + onCommitCompleted: { |
218 | + if (contentToLayout.checked && contentToLayout.enabled) { |
219 | + page.pageStack.addPageToCurrentColumn(page, contentComponent); |
220 | + collapse(); |
221 | + } |
222 | + } |
223 | + |
224 | + regions: [ |
225 | + BottomEdgeRegion { |
226 | + objectName: "CustomRegion1" |
227 | + enabled: regionConfig.model >= 1 |
228 | + to: 0.3 |
229 | + property color baseColor: UbuntuColors.lightGrey |
230 | + }, |
231 | + BottomEdgeRegion { |
232 | + objectName: "CustomRegion2" |
233 | + enabled: regionConfig.model >= 2 |
234 | + from: 0.3 |
235 | + to: 0.6 |
236 | + }, |
237 | + BottomEdgeRegion { |
238 | + objectName: "CustomRegion3" |
239 | + enabled: regionConfig.model >= 3 |
240 | + from: 0.6 |
241 | + }, |
242 | + // default region, mimics the default setup |
243 | + BottomEdgeRegion { |
244 | + objectName: "DefaultRegion" |
245 | + enabled: regionConfig.model <= 0 |
246 | + from: 0.3 |
247 | + } |
248 | + ] |
249 | + |
250 | + Component { |
251 | + id: bottomEdgeContent |
252 | + Page { |
253 | + height: bottomEdge.height |
254 | + header: PageHeader { |
255 | + title: { |
256 | + var state = "UNDEFINED"; |
257 | + switch (bottomEdge.status) { |
258 | + case BottomEdge.Hidden: state = "Hidden"; break; |
259 | + case BottomEdge.Revealed: state = "Revealed"; break; |
260 | + case BottomEdge.Committed: state = "Committed"; break; |
261 | + } |
262 | + return bottomEdge.activeRegion |
263 | + ? i18n.tr("Within region '%1', status: %2").arg(bottomEdge.activeRegion.objectName).arg(state) |
264 | + : i18n.tr("Not in any active region, status: %1").arg(state); |
265 | + } |
266 | + } |
267 | + Rectangle { |
268 | + anchors.fill: parent |
269 | + anchors.margins: units.gu(1) |
270 | + color: bottomEdge.activeRegion && bottomEdge.activeRegion.hasOwnProperty("baseColor") ? |
271 | + bottomEdge.activeRegion.baseColor : Qt.rgba(0.5, 1, bottomEdge.dragProgress, 1) |
272 | + } |
273 | + } |
274 | + } |
275 | } |
276 | } |
277 | |
278 | === modified file 'examples/ubuntu-ui-toolkit-gallery/Template.qml' |
279 | --- examples/ubuntu-ui-toolkit-gallery/Template.qml 2015-11-09 07:35:14 +0000 |
280 | +++ examples/ubuntu-ui-toolkit-gallery/Template.qml 2015-11-27 10:36:32 +0000 |
281 | @@ -23,6 +23,7 @@ |
282 | default property alias content: column.children |
283 | property alias spacing: column.spacing |
284 | property alias scrollable: flickable.interactive |
285 | + readonly property alias flickable: flickable |
286 | |
287 | header: PageHeader { |
288 | title: template.title |
289 | |
290 | === modified file 'examples/ubuntu-ui-toolkit-gallery/TemplateRow.qml' |
291 | --- examples/ubuntu-ui-toolkit-gallery/TemplateRow.qml 2015-04-25 08:18:45 +0000 |
292 | +++ examples/ubuntu-ui-toolkit-gallery/TemplateRow.qml 2015-11-27 10:36:32 +0000 |
293 | @@ -26,7 +26,7 @@ |
294 | default property alias content: contentRow.children |
295 | |
296 | height: Math.max(contentRow.height, label.height) |
297 | - width: parent.width |
298 | + width: parent ? parent.width : 0 |
299 | |
300 | Label { |
301 | id: label |
302 | |
303 | === modified file 'examples/ubuntu-ui-toolkit-gallery/gallery-logging.config' |
304 | --- examples/ubuntu-ui-toolkit-gallery/gallery-logging.config 2015-11-17 11:48:09 +0000 |
305 | +++ examples/ubuntu-ui-toolkit-gallery/gallery-logging.config 2015-11-27 10:36:32 +0000 |
306 | @@ -2,3 +2,4 @@ |
307 | libubuntugestures.TouchRegistry.debug=false |
308 | ubuntu.components.SwipeArea.debug=false |
309 | ubuntu.components.SwipeArea.ActiveTouchInfo.debug=false |
310 | +ubuntu.components.BottomEdge.debug=false |
311 | |
312 | === modified file 'src/Ubuntu/Components/1.3/AdaptivePageLayout.qml' |
313 | --- src/Ubuntu/Components/1.3/AdaptivePageLayout.qml 2015-10-22 20:09:56 +0000 |
314 | +++ src/Ubuntu/Components/1.3/AdaptivePageLayout.qml 2015-11-27 10:36:32 +0000 |
315 | @@ -743,8 +743,6 @@ |
316 | right: parent.right |
317 | rightMargin: dividerThickness |
318 | } |
319 | - // we need to clip because the header does not have a background |
320 | - clip: true |
321 | Item { |
322 | id: hiddenItem |
323 | anchors.fill: parent |
324 | |
325 | === modified file 'src/Ubuntu/Components/1.3/PageTreeNode.qml' |
326 | --- src/Ubuntu/Components/1.3/PageTreeNode.qml 2015-10-20 11:05:53 +0000 |
327 | +++ src/Ubuntu/Components/1.3/PageTreeNode.qml 2015-11-27 10:36:32 +0000 |
328 | @@ -125,10 +125,6 @@ |
329 | if (i.isLeaf) { |
330 | // children of a leaf are not part of the tree |
331 | node = null; |
332 | - print("WARNING! " + |
333 | - "Do not put Page/Tabs/PageStack inside another "+ |
334 | - "Page because that causes confusion which is the "+ |
335 | - "active page that sets the title and actions."); |
336 | } else { |
337 | // current node is part of the tree with i as its parent. |
338 | node = i; |
339 | |
340 | === modified file 'src/Ubuntu/Components/ComponentModule.pro' |
341 | --- src/Ubuntu/Components/ComponentModule.pro 2015-11-18 15:07:15 +0000 |
342 | +++ src/Ubuntu/Components/ComponentModule.pro 2015-11-27 10:36:32 +0000 |
343 | @@ -132,7 +132,7 @@ |
344 | 1.3/PageColumn.qml \ |
345 | 1.3/PageColumnsLayout.qml \ |
346 | 1.3/ProgressionSlot.qml \ |
347 | - 1.3/PageHeader.qml \ |
348 | + 1.3/PageHeader.qml \ |
349 | |
350 | OTHER_FILES+= qmldir \ |
351 | 1.3/CrossFadeImage.qdoc \ |
352 | |
353 | === added file 'src/Ubuntu/Components/Themes/Ambiance/1.3/BottomEdgeStyle.qml' |
354 | --- src/Ubuntu/Components/Themes/Ambiance/1.3/BottomEdgeStyle.qml 1970-01-01 00:00:00 +0000 |
355 | +++ src/Ubuntu/Components/Themes/Ambiance/1.3/BottomEdgeStyle.qml 2015-11-27 10:36:32 +0000 |
356 | @@ -0,0 +1,125 @@ |
357 | +/* |
358 | + * Copyright (C) 2015 Canonical, Ltd. |
359 | + * |
360 | + * This program is free software; you can redistribute it and/or modify |
361 | + * it under the terms of the GNU General Public License as published by |
362 | + * the Free Software Foundation; version 3. |
363 | + * |
364 | + * This program is distributed in the hope that it will be useful, |
365 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
366 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
367 | + * GNU General Public License for more details. |
368 | + * |
369 | + * You should have received a copy of the GNU General Public License |
370 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
371 | + */ |
372 | +import QtQuick 2.4 |
373 | +import Ubuntu.Components 1.3 |
374 | +import Ubuntu.Components.Styles 1.3 |
375 | + |
376 | +BottomEdgeStyle { |
377 | + id: bottomEdgeStyle |
378 | + //setup properties |
379 | + property BottomEdge bottomEdge: styledItem |
380 | + panel: panelItem |
381 | + contentItem: loader.item |
382 | + panelAnimation: panelBehavior |
383 | + revealThreshold: bottomEdge.hint.height + units.gu(2) |
384 | + |
385 | + // own styling properties |
386 | + property color backgroundColor: "transparent" |
387 | + property color panelColor: theme.palette.normal.background |
388 | + property color shadowColor: theme.palette.selected.background |
389 | + property bool attachHintToContent: false |
390 | + |
391 | + anchors.fill: parent |
392 | + |
393 | + Rectangle { |
394 | + id: background |
395 | + anchors.fill: parent |
396 | + color: backgroundColor |
397 | + z: -1 |
398 | + } |
399 | + |
400 | + states: State { |
401 | + name: "reparentedHint" |
402 | + when: attachHintToContent |
403 | + AnchorChanges { |
404 | + target: bottomEdge.hint |
405 | + anchors.bottom: panelItem.top |
406 | + } |
407 | + } |
408 | + |
409 | + Rectangle { |
410 | + id: panelItem |
411 | + objectName: "bottomedge_panel" |
412 | + anchors { |
413 | + left: parent.left |
414 | + right: parent.right |
415 | + top: parent.bottom |
416 | + topMargin: bottomEdge.status >= BottomEdge.Revealed |
417 | + ? -(bottomEdge.height * bottomEdge.dragProgress) |
418 | + : 0 |
419 | + } |
420 | + height: loader.item ? loader.item.height : 0 |
421 | + color: panelColor |
422 | + opacity: bottomEdge.status >= BottomEdge.Revealed ? 1.0 : 0.0 |
423 | + |
424 | + Behavior on anchors.topMargin { UbuntuNumberAnimation { id: panelBehavior } } |
425 | + |
426 | + state: bottomEdge.status > BottomEdge.Hidden ? "lock-hint" : "" |
427 | + states: [ |
428 | + State { |
429 | + name: "lock-hint" |
430 | + PropertyChanges { |
431 | + target: bottomEdge.hint |
432 | + status: BottomEdgeHint.Locked |
433 | + } |
434 | + } |
435 | + ] |
436 | + |
437 | + // shadows |
438 | + Rectangle { |
439 | + id: topShadow |
440 | + anchors { |
441 | + bottom: parent.top |
442 | + left: parent.left |
443 | + right: parent.right |
444 | + } |
445 | + height: units.gu(1) |
446 | + gradient: Gradient { |
447 | + GradientStop { position: 0.0; color: Qt.rgba(shadowColor.r, shadowColor.g, shadowColor.b, 0.0) } |
448 | + GradientStop { position: 1.0; color: Qt.rgba(shadowColor.r, shadowColor.g, shadowColor.b, 0.3) } |
449 | + } |
450 | + } |
451 | + Rectangle { |
452 | + id: bottomShadow |
453 | + anchors { |
454 | + top: parent.bottom |
455 | + left: parent.left |
456 | + right: parent.right |
457 | + } |
458 | + height: units.gu(1) |
459 | + rotation: 180 |
460 | + gradient: Gradient { |
461 | + GradientStop { position: 0.0; color: Qt.rgba(shadowColor.r, shadowColor.g, shadowColor.b, 0.0) } |
462 | + GradientStop { position: 1.0; color: Qt.rgba(shadowColor.r, shadowColor.g, shadowColor.b, 0.3) } |
463 | + } |
464 | + } |
465 | + |
466 | + // content |
467 | + Loader { |
468 | + id: loader |
469 | + anchors.horizontalCenter: parent.horizontalCenter |
470 | + asynchronous: true |
471 | + source: bottomEdge.status > BottomEdge.Hidden ? bottomEdge.contentUrl : "" |
472 | + sourceComponent: bottomEdge.status > BottomEdge.Hidden ? bottomEdge.contentComponent : null |
473 | + onItemChanged: { |
474 | + if (item) { |
475 | + item.parent = panelItem; |
476 | + item.anchors.horizontalCenter = panelItem.horizontalCenter; |
477 | + } |
478 | + } |
479 | + } |
480 | + } |
481 | +} |
482 | |
483 | === modified file 'src/Ubuntu/Components/Themes/Ambiance/Ambiance.pro' |
484 | --- src/Ubuntu/Components/Themes/Ambiance/Ambiance.pro 2015-10-23 05:42:14 +0000 |
485 | +++ src/Ubuntu/Components/Themes/Ambiance/Ambiance.pro 2015-11-27 10:36:32 +0000 |
486 | @@ -114,7 +114,8 @@ |
487 | 1.3/IconButtonStyle.qml \ |
488 | 1.3/PageHeaderStyle.qml \ |
489 | 1.3/BottomEdgeHintStyle.qml \ |
490 | - $$ARTWORK_FILES |
491 | + 1.3/BottomEdgeStyle.qml \ |
492 | + $$ARTWORK_FILES |
493 | |
494 | load(ubuntu_qml_module) |
495 | |
496 | |
497 | === modified file 'src/Ubuntu/Components/Themes/Ambiance/qmldir' |
498 | --- src/Ubuntu/Components/Themes/Ambiance/qmldir 2015-11-18 15:07:15 +0000 |
499 | +++ src/Ubuntu/Components/Themes/Ambiance/qmldir 2015-11-27 10:36:32 +0000 |
500 | @@ -84,3 +84,5 @@ |
501 | internal SliderUtils 1.3/sliderUtils.js |
502 | internal ColorUtils 1.3/colorUtils.js |
503 | PageHeaderStyle 1.3 ./1.3/PageHeaderStyle.qml |
504 | +BottomEdgeHintStyle 1.3 ./1.3/BottomEdgeHintStyle.qml |
505 | +BottomEdgeStyle 1.3 ./1.3/BottomEdgeStyle.qml |
506 | |
507 | === modified file 'src/Ubuntu/Components/plugin/plugin.cpp' |
508 | --- src/Ubuntu/Components/plugin/plugin.cpp 2015-11-19 09:05:19 +0000 |
509 | +++ src/Ubuntu/Components/plugin/plugin.cpp 2015-11-27 10:36:32 +0000 |
510 | @@ -73,6 +73,9 @@ |
511 | #include "ucbottomedgehint.h" |
512 | #include "gestures/ucswipearea.h" |
513 | #include "ucmathutils.h" |
514 | +#include "ucbottomedge.h" |
515 | +#include "ucbottomedgeregion.h" |
516 | +#include "ucbottomedgestyle.h" |
517 | |
518 | #include <sys/types.h> |
519 | #include <unistd.h> |
520 | @@ -254,6 +257,8 @@ |
521 | qmlRegisterType<UCLabel>(uri, 1, 3, "Label"); |
522 | qmlRegisterType<UCBottomEdgeHint>(uri, 1, 3, "BottomEdgeHint"); |
523 | qmlRegisterType<UCSwipeArea>(uri, 1, 3, "SwipeArea"); |
524 | + qmlRegisterType<UCBottomEdge>(uri, 1, 3, "BottomEdge"); |
525 | + qmlRegisterType<UCBottomEdgeRegion>(uri, 1, 3, "BottomEdgeRegion"); |
526 | } |
527 | |
528 | void UbuntuComponentsPlugin::initializeEngine(QQmlEngine *engine, const char *uri) |
529 | @@ -265,6 +270,7 @@ |
530 | const char *styleUri = "Ubuntu.Components.Styles"; |
531 | qmlRegisterType<UCListItemStyle>(styleUri, 1, 2, "ListItemStyle"); |
532 | qmlRegisterType<UCListItemStyle, 1>(styleUri, 1, 3, "ListItemStyle"); |
533 | + qmlRegisterType<UCBottomEdgeStyle>(styleUri, 1, 3, "BottomEdgeStyle"); |
534 | |
535 | QQmlExtensionPlugin::initializeEngine(engine, uri); |
536 | QQmlContext* context = engine->rootContext(); |
537 | |
538 | === modified file 'src/Ubuntu/Components/plugin/plugin.pri' |
539 | --- src/Ubuntu/Components/plugin/plugin.pri 2015-11-20 07:47:08 +0000 |
540 | +++ src/Ubuntu/Components/plugin/plugin.pri 2015-11-27 10:36:32 +0000 |
541 | @@ -98,7 +98,11 @@ |
542 | $$PWD/gestures/ucswipearea_p.h \ |
543 | $$PWD/gestures/damper.h \ |
544 | $$PWD/gestures/ubuntugesturesqmlglobal.h \ |
545 | - $$PWD/ucmathutils.h |
546 | + $$PWD/ucmathutils.h \ |
547 | + $$PWD/ucbottomedge.h \ |
548 | + $$PWD/ucbottomedge_p.h \ |
549 | + $$PWD/ucbottomedgestyle.h \ |
550 | + $$PWD/ucbottomedgeregion.h |
551 | |
552 | SOURCES += $$PWD/plugin.cpp \ |
553 | $$PWD/uctheme.cpp \ |
554 | @@ -164,7 +168,10 @@ |
555 | $$PWD/ucimportversionchecker_p.cpp \ |
556 | $$PWD/ucbottomedgehint.cpp \ |
557 | $$PWD/gestures/ucswipearea.cpp \ |
558 | - $$PWD/ucmathutils.cpp |
559 | + $$PWD/ucmathutils.cpp \ |
560 | + $$PWD/ucbottomedge.cpp \ |
561 | + $$PWD/ucbottomedgestyle.cpp \ |
562 | + $$PWD/ucbottomedgeregion.cpp |
563 | |
564 | # adapters |
565 | SOURCES += $$PWD/adapters/alarmsadapter_organizer.cpp |
566 | |
567 | === modified file 'src/Ubuntu/Components/plugin/ucaction.h' |
568 | --- src/Ubuntu/Components/plugin/ucaction.h 2015-09-01 08:44:11 +0000 |
569 | +++ src/Ubuntu/Components/plugin/ucaction.h 2015-11-27 10:36:32 +0000 |
570 | @@ -60,6 +60,12 @@ |
571 | return m_published; |
572 | } |
573 | |
574 | + void setName(const QString &name); |
575 | + void setIconName(const QString &name); |
576 | + void setIconSource(const QUrl &url); |
577 | + void setItemHint(QQmlComponent *); |
578 | + void setShortcut(const QVariant&); |
579 | + |
580 | Q_SIGNALS: |
581 | void nameChanged(); |
582 | void textChanged(); |
583 | @@ -99,11 +105,6 @@ |
584 | |
585 | bool isValidType(QVariant::Type valueType); |
586 | void generateName(); |
587 | - void setName(const QString &name); |
588 | - void setIconName(const QString &name); |
589 | - void setIconSource(const QUrl &url); |
590 | - void setItemHint(QQmlComponent *); |
591 | - void setShortcut(const QVariant&); |
592 | bool event(QEvent *event); |
593 | }; |
594 | |
595 | |
596 | === added file 'src/Ubuntu/Components/plugin/ucbottomedge.cpp' |
597 | --- src/Ubuntu/Components/plugin/ucbottomedge.cpp 1970-01-01 00:00:00 +0000 |
598 | +++ src/Ubuntu/Components/plugin/ucbottomedge.cpp 2015-11-27 10:36:32 +0000 |
599 | @@ -0,0 +1,1059 @@ |
600 | +/* |
601 | + * Copyright 2015 Canonical Ltd. |
602 | + * |
603 | + * This program is free software; you can redistribute it and/or modify |
604 | + * it under the terms of the GNU Lesser General Public License as published by |
605 | + * the Free Software Foundation; version 3. |
606 | + * |
607 | + * This program is distributed in the hope that it will be useful, |
608 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
609 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
610 | + * GNU Lesser General Public License for more details. |
611 | + * |
612 | + * You should have received a copy of the GNU Lesser General Public License |
613 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
614 | + * |
615 | + * Author: Zsombor Egri <zsombor.egri@canonical.com> |
616 | + */ |
617 | + |
618 | +#include "ucbottomedge_p.h" |
619 | +#include "ucbottomedgestyle.h" |
620 | +#include "ucbottomedgeregion.h" |
621 | +#include "ucbottomedgehint.h" |
622 | +#include "ucstyleditembase_p.h" |
623 | +#include <QtQml/QQmlEngine> |
624 | +#include <QtGui/QScreen> |
625 | +#include <QtQml/QQmlProperty> |
626 | +#include <QtGui/QGuiApplication> |
627 | +#include <QtGui/QStyleHints> |
628 | +#include <QtQuick/private/qquickitem_p.h> |
629 | +#include <QtQuick/private/qquickflickable_p.h> |
630 | + |
631 | +#include "plugin.h" |
632 | +#include "ucnamespace.h" |
633 | +#include "ucheader.h" |
634 | +#include "ucaction.h" |
635 | +#include "quickutils.h" |
636 | +#include "gestures/ucswipearea.h" |
637 | +#include <QtQuick/private/qquickanimation_p.h> |
638 | + |
639 | +Q_LOGGING_CATEGORY(ucBottomEdge, "ubuntu.components.BottomEdge", QtMsgType::QtWarningMsg) |
640 | + |
641 | +#define LOG qCDebug(ucBottomEdge) << "[BottomEdge]" |
642 | + |
643 | +UCBottomEdgePrivate::UCBottomEdgePrivate() |
644 | + : UCStyledItemBasePrivate() |
645 | + , activeRegion(Q_NULLPTR) |
646 | + , hint(new UCBottomEdgeHint) |
647 | + , contentComponent(Q_NULLPTR) |
648 | + , bottomPanel(Q_NULLPTR) |
649 | + , previousDistance(0.0) |
650 | + , dragProgress(0.) |
651 | + , status(UCBottomEdge::Hidden) |
652 | + , operationStatus(Idle) |
653 | + , dragDirection(UCBottomEdge::Undefined) |
654 | + , defaultRegionsReset(false) |
655 | + , mousePressed(false) |
656 | +{ |
657 | +} |
658 | + |
659 | +void UCBottomEdgePrivate::init() |
660 | +{ |
661 | + Q_Q(UCBottomEdge); |
662 | + // initialize hint |
663 | + QQml_setParent_noEvent(hint, q); |
664 | + hint->setParentItem(q); |
665 | + |
666 | + // create default regions |
667 | + createDefaultRegions(); |
668 | + |
669 | + // set the style name |
670 | + styleDocument = QStringLiteral("BottomEdgeStyle"); |
671 | +} |
672 | + |
673 | +// overload default data property so we can filter out the regions declared |
674 | +// in the body of the component as resources |
675 | +QQmlListProperty<QObject> UCBottomEdgePrivate::data() |
676 | +{ |
677 | + return QQmlListProperty<QObject>(q_func(), 0, UCBottomEdgePrivate::overload_data_append, |
678 | + QQuickItemPrivate::data_count, |
679 | + QQuickItemPrivate::data_at, |
680 | + UCBottomEdgePrivate::overload_data_clear); |
681 | +} |
682 | + |
683 | +void UCBottomEdgePrivate::overload_data_append(QQmlListProperty<QObject> *data, QObject *object) |
684 | +{ |
685 | + QQuickItemPrivate::data_append(data, object); |
686 | + // if the object is a region, add to the regions as well |
687 | + UCBottomEdgeRegion *region = qobject_cast<UCBottomEdgeRegion*>(object); |
688 | + if (region) { |
689 | + UCBottomEdgePrivate *bottomEdge = UCBottomEdgePrivate::get(static_cast<UCBottomEdge*>(data->object)); |
690 | + bottomEdge->appendRegion(region); |
691 | + } |
692 | +} |
693 | + |
694 | +void UCBottomEdgePrivate::overload_data_clear(QQmlListProperty<QObject> *data) |
695 | +{ |
696 | + // clear regions as well |
697 | + UCBottomEdgePrivate *bottomEdge = UCBottomEdgePrivate::get(static_cast<UCBottomEdge*>(data->object)); |
698 | + bottomEdge->clearRegions(false); |
699 | + QQuickItemPrivate::data_clear(data); |
700 | +} |
701 | + |
702 | +// appends a BottomEdgeRegion to the list; clears the default regions before appending the |
703 | +// custom ones |
704 | +void UCBottomEdgePrivate::appendRegion(UCBottomEdgeRegion *region) |
705 | +{ |
706 | + Q_Q(UCBottomEdge); |
707 | + Q_ASSERT(region); |
708 | + // the region must be owned by other non-BottomEdge component, |
709 | + // otherwise we cannot "reuse" the region |
710 | + if (region->parent() != q && qobject_cast<UCBottomEdge*>(region->parent())) { |
711 | + qmlInfo(q) << "Cannot reuse region owned by other BottomEdge components"; |
712 | + return; |
713 | + } |
714 | + |
715 | + // make sure we own the region! |
716 | + QQml_setParent_noEvent(region, q); |
717 | + // take ownership! |
718 | + QQmlEngine::setObjectOwnership(region, QQmlEngine::CppOwnership); |
719 | + region->attachToBottomEdge(q); |
720 | + |
721 | + if (!defaultRegionsReset) { |
722 | + defaultRegionsReset = true; |
723 | + qDeleteAll(regions); |
724 | + regions.clear(); |
725 | + } |
726 | + |
727 | + // validate the region before we append |
728 | + validateRegion(region); |
729 | + |
730 | + // append region definition |
731 | + regions.append(region); |
732 | +} |
733 | + |
734 | +// clears the custom regions list and restores the default ones |
735 | +void UCBottomEdgePrivate::clearRegions(bool destroy) |
736 | +{ |
737 | + if (!defaultRegionsReset) { |
738 | + return; |
739 | + } |
740 | + if (destroy) { |
741 | + qDeleteAll(regions); |
742 | + } |
743 | + regions.clear(); |
744 | + defaultRegionsReset = false; |
745 | + createDefaultRegions(); |
746 | +} |
747 | + |
748 | +// validates an added region |
749 | +void UCBottomEdgePrivate::validateRegion(UCBottomEdgeRegion *region, int regionsSize) |
750 | +{ |
751 | + // we should not validate unti the bottom edge is not completed, |
752 | + // property changes may invalidate the result of the validation |
753 | + // also leave if the region is disabled |
754 | + if (!componentComplete || !region->m_enabled) { |
755 | + return; |
756 | + } |
757 | + Q_Q(UCBottomEdge); |
758 | + // use QRectF to help on finding the intersection |
759 | + QRectF boundingRect = q->boundingRect(); |
760 | + if (boundingRect.isNull()) { |
761 | + boundingRect = QRectF(0, 0, 1, 1); |
762 | + } |
763 | + if (regionsSize < 0 || regionsSize > regions.size()) { |
764 | + regionsSize = regions.size(); |
765 | + } |
766 | + const QRectF regionRect(region->rect(boundingRect)); |
767 | + for (int i = 0; i < regionsSize; ++i) { |
768 | + UCBottomEdgeRegion *stackedRegion = regions[i]; |
769 | + if (region == stackedRegion || !stackedRegion->m_enabled) { |
770 | + continue; |
771 | + } |
772 | + QRectF rect(stackedRegion->rect(boundingRect)); |
773 | + if (rect.contains(regionRect)) { |
774 | + qmlInfo(region) << QString("Region at index %1 contains this region. This region will never activate.").arg(i); |
775 | + } else { |
776 | + QRectF intersect = regionRect.intersected(stackedRegion->rect(boundingRect)); |
777 | + if (!intersect.isNull()) { |
778 | + qmlInfo(region) << QString("Region intersects the one from index %1 having from: %2 and to: %3") |
779 | + .arg(i).arg(stackedRegion->m_from).arg(stackedRegion->m_to); |
780 | + } |
781 | + } |
782 | + } |
783 | +} |
784 | + |
785 | +// creates the default region(s) |
786 | +void UCBottomEdgePrivate::createDefaultRegions() |
787 | +{ |
788 | + Q_Q(UCBottomEdge); |
789 | + // add the default stages |
790 | + UCBottomEdgeRegion *commitRegion = new UCBottomEdgeRegion(q); |
791 | + // for testing purposes |
792 | + commitRegion->setObjectName("default_BottomEdgeRegion"); |
793 | + // enters in this stage when drag ratio reaches 30% of the area |
794 | + commitRegion->m_from = 0.33; |
795 | + commitRegion->m_to = 1.0; |
796 | + |
797 | + regions.append(commitRegion); |
798 | +} |
799 | + |
800 | +// update status, drag direction and activeRegion during drag |
801 | +void UCBottomEdgePrivate::updateProgressionStates(qreal distance) |
802 | +{ |
803 | + Q_Q(UCBottomEdge); |
804 | + |
805 | + // refresh drag progress |
806 | + setDragProgress(distance / q->height()); |
807 | + |
808 | + detectDirection(distance); |
809 | + if (isLocked()) { |
810 | + // there is an operation ongoing, do not update drag and activeRegion |
811 | + return; |
812 | + } |
813 | + if (distance >= bottomPanel->m_revealThreshold) { |
814 | + // the content can be revealed |
815 | + setStatus(UCBottomEdge::Revealed); |
816 | + } |
817 | + |
818 | + // go through the regions and spot the active region |
819 | + UCBottomEdgeRegion *newActive = Q_NULLPTR; |
820 | + Q_FOREACH(UCBottomEdgeRegion *region, regions) { |
821 | + if (region->contains(dragProgress)) { |
822 | + newActive = region; |
823 | + break; |
824 | + } |
825 | + } |
826 | + if (newActive != activeRegion) { |
827 | + setActiveRegion(newActive); |
828 | + } |
829 | +} |
830 | + |
831 | +// set the active region |
832 | +bool UCBottomEdgePrivate::setActiveRegion(UCBottomEdgeRegion *region) |
833 | +{ |
834 | + if (activeRegion == region) { |
835 | + return false; |
836 | + } |
837 | + if (activeRegion) { |
838 | + activeRegion->exit(); |
839 | + } |
840 | + activeRegion = region; |
841 | + if (activeRegion) { |
842 | + activeRegion->enter(); |
843 | + } |
844 | + Q_EMIT q_func()->activeRegionChanged(activeRegion); |
845 | + return true; |
846 | +} |
847 | + |
848 | +// updates the dragDirection property |
849 | +void UCBottomEdgePrivate::detectDirection(qreal currentDistance) |
850 | +{ |
851 | + if (!previousDistance) { |
852 | + previousDistance = currentDistance; |
853 | + } |
854 | + |
855 | + UCBottomEdge::DragDirection newDirection = dragDirection; |
856 | + qreal delta = previousDistance - currentDistance; |
857 | + bool deltaPassed = abs(delta) >= qApp->styleHints()->startDragDistance(); |
858 | + if (!deltaPassed) { |
859 | + return; |
860 | + } |
861 | + |
862 | + previousDistance = currentDistance; |
863 | + newDirection = (delta < 0) ? UCBottomEdge::Upwards : UCBottomEdge::Downwards; |
864 | + setDragDirection(newDirection); |
865 | +} |
866 | + |
867 | +// internal dragDirection property setter |
868 | +void UCBottomEdgePrivate::setDragDirection(UCBottomEdge::DragDirection direction) |
869 | +{ |
870 | + if (dragDirection != direction) { |
871 | + dragDirection = direction; |
872 | + switch (dragDirection) { |
873 | + case UCBottomEdge::Undefined: LOG << "direction: Undefined"; break; |
874 | + case UCBottomEdge::Upwards: LOG << "direction: Upwards"; break; |
875 | + case UCBottomEdge::Downwards: LOG << "direction: Downwards"; break; |
876 | + } |
877 | + Q_EMIT q_func()->dragDirectionChanged(dragDirection); |
878 | + } |
879 | +} |
880 | + |
881 | +// proceed with drag completion action |
882 | +void UCBottomEdgePrivate::onDragEnded() |
883 | +{ |
884 | + if (!activeRegion || (dragDirection == UCBottomEdge::Downwards)) { |
885 | + q_func()->collapse(); |
886 | + } else { |
887 | + // emit region's dragEnded first |
888 | + Q_EMIT activeRegion->dragEnded(); |
889 | + commit(activeRegion->m_to); |
890 | + } |
891 | +} |
892 | + |
893 | +void UCBottomEdgePrivate::commit(qreal to) |
894 | +{ |
895 | + if (operationStatus == CommitToTop |
896 | + || operationStatus == CommitToRegion |
897 | + || status == UCBottomEdge::Committed) { |
898 | + LOG << "redundant commit call"; |
899 | + return; |
900 | + } |
901 | + Q_Q(UCBottomEdge); |
902 | + setOperationStatus(qFuzzyCompare(to, 1.0) ? CommitToTop : CommitToRegion); |
903 | + if (operationStatus == CommitToTop) { |
904 | + LOG << "emit commitStarted()"; |
905 | + Q_EMIT q->commitStarted(); |
906 | + } |
907 | + // make sure the status is set to revealed first |
908 | + bool animated = bottomPanel && bottomPanel->m_panelAnimation; |
909 | + if (animated) { |
910 | + QObject::connect(bottomPanel->m_panelAnimation, &QQuickAbstractAnimation::runningChanged, |
911 | + q, &UCBottomEdge::unlockOperation, Qt::UniqueConnection); |
912 | + } |
913 | + // make sure the setStatus is set to Revealed first |
914 | + if (status == UCBottomEdge::Hidden) { |
915 | + setStatus(UCBottomEdge::Revealed); |
916 | + } |
917 | + setDragProgress(to); |
918 | + if (!animated) { |
919 | + q->unlockOperation(false); |
920 | + } |
921 | +} |
922 | + |
923 | +// common handler to complete the operations |
924 | +void UCBottomEdge::unlockOperation(bool running) |
925 | +{ |
926 | + if (running) { |
927 | + return; |
928 | + } |
929 | + Q_D(UCBottomEdge); |
930 | + if (d->bottomPanel && d->bottomPanel->m_panelAnimation) { |
931 | + disconnect(d->bottomPanel->m_panelAnimation, &QQuickAbstractAnimation::runningChanged, |
932 | + 0, 0); |
933 | + } |
934 | + |
935 | + UCBottomEdgePrivate::OperationStatus oldStatus = d->operationStatus; |
936 | + switch (d->operationStatus) { |
937 | + case UCBottomEdgePrivate::CommitToTop: |
938 | + case UCBottomEdgePrivate::CommitToRegion: |
939 | + d->setStatus(UCBottomEdge::Committed); |
940 | + d->patchContentItemHeader(); |
941 | + if (d->operationStatus == UCBottomEdgePrivate::CommitToTop) { |
942 | + LOG << "emit commitCompleted()"; |
943 | + Q_EMIT commitCompleted(); |
944 | + } |
945 | + break; |
946 | + case UCBottomEdgePrivate::Collapsing: |
947 | + d->setStatus(UCBottomEdge::Hidden); |
948 | + Q_EMIT collapseCompleted(); |
949 | + break; |
950 | + default: break; |
951 | + } |
952 | + |
953 | + // the operation status may got changed due to a new operation being |
954 | + // initiated from the previosu one (e.g.collapse from commitCompleted, etc |
955 | + if (oldStatus == d->operationStatus) { |
956 | + d->setDragDirection(Undefined); |
957 | + d->setOperationStatus(UCBottomEdgePrivate::Idle); |
958 | + } |
959 | +} |
960 | + |
961 | +// positions the bottom edge panel holding the content to the given height percentage |
962 | +void UCBottomEdgePrivate::setDragProgress(qreal position) |
963 | +{ |
964 | + if (dragProgress == position || (position < 0.0) || position > 1.0) { |
965 | + return; |
966 | + } |
967 | + dragProgress = position; |
968 | + Q_EMIT q_func()->dragProgressChanged(dragProgress); |
969 | +} |
970 | + |
971 | +// separated in a derived class to ease testing |
972 | +UCCollapseAction::UCCollapseAction(QObject *parent) |
973 | + : UCAction(parent) |
974 | +{ |
975 | + QQmlEngine::setObjectOwnership(this, QQmlEngine::objectOwnership(parent)); |
976 | + setIconName("down"); |
977 | +} |
978 | + |
979 | +// inject collapse action into the content if the content has a PageHeader |
980 | +void UCBottomEdgePrivate::patchContentItemHeader() |
981 | +{ |
982 | + // ugly, as it can be, as we don't have the PageHeader in cpp to detect the type |
983 | + UCHeader *header = bottomPanel->m_contentItem ? bottomPanel->m_contentItem->findChild<UCHeader*>() : Q_NULLPTR; |
984 | + if (!header || !QuickUtils::inherits(header, "PageHeader") || status != UCBottomEdge::Committed) { |
985 | + return; |
986 | + } |
987 | + |
988 | + // get the navigationActions and inject an action there |
989 | + QVariant list(header->property("navigationActions")); |
990 | + QQmlListProperty<UCAction> actions = list.value< QQmlListProperty<UCAction> >(); |
991 | + QList<UCAction*> *navigationActions = reinterpret_cast<QList<UCAction*>*>(actions.data); |
992 | + |
993 | + // clear the actions first |
994 | + navigationActions->clear(); |
995 | + |
996 | + // inject the action |
997 | + UCAction *collapse = new UCCollapseAction(header); |
998 | + QObject::connect(collapse, &UCAction::triggered, q_func(), &UCBottomEdge::collapse, Qt::DirectConnection); |
999 | + navigationActions->append(collapse); |
1000 | + |
1001 | + // invoke PageHeader.navigationActionsChanged signal |
1002 | + int signal = header->metaObject()->indexOfSignal("navigationActionsChanged()"); |
1003 | + if (signal >= 0) { |
1004 | + header->metaObject()->invokeMethod(header, "navigationActionsChanged"); |
1005 | + } |
1006 | +} |
1007 | + |
1008 | +bool UCBottomEdgePrivate::loadStyleItem(bool animated) |
1009 | +{ |
1010 | + // fix styleVersion |
1011 | + Q_Q(UCBottomEdge); |
1012 | + if (!styleVersion) { |
1013 | + styleVersion = BUILD_VERSION(1, 3); |
1014 | + } |
1015 | + bool result = UCStyledItemBasePrivate::loadStyleItem(animated); |
1016 | + bottomPanel = qobject_cast<UCBottomEdgeStyle*>(styleItem); |
1017 | + if (bottomPanel) { |
1018 | + // reparent style item to the BottomEdge's parent |
1019 | + bottomPanel->setParentItem(parentItem); |
1020 | + // bring style item in front |
1021 | + bottomPanel->setZ(std::numeric_limits<qreal>::max()); |
1022 | + // anchor to the bottom of the BottomEdge |
1023 | + QQuickAnchors *styleAnchors = QQuickItemPrivate::get(bottomPanel)->anchors(); |
1024 | + styleAnchors->setBottom(anchors()->bottom()); |
1025 | + |
1026 | + // move hint under the panel |
1027 | + hint->setParentItem(bottomPanel); |
1028 | + // and stack it before the panel, so it is covered by the panel when revealed |
1029 | + hint->stackBefore(bottomPanel->m_panel); |
1030 | + |
1031 | + // connect style stuff |
1032 | + QObject::connect(bottomPanel, &UCBottomEdgeStyle::contentItemChanged, |
1033 | + q, &UCBottomEdge::contentItemChanged, Qt::DirectConnection); |
1034 | + // follow contentItem change to patch the header |
1035 | + QObject::connect(bottomPanel, &UCBottomEdgeStyle::contentItemChanged, [=]() { |
1036 | + patchContentItemHeader(); |
1037 | + }); |
1038 | + } |
1039 | + return result; |
1040 | +} |
1041 | + |
1042 | +// make sure the bottom edge panel is always the last one |
1043 | +void UCBottomEdgePrivate::itemChildAdded(QQuickItem *item, QQuickItem *) |
1044 | +{ |
1045 | + // make sure the BottomEdge's panel is the last one |
1046 | + QQuickItem *last = item->childItems().last(); |
1047 | + if (bottomPanel && last != bottomPanel) { |
1048 | + bottomPanel->stackAfter(last); |
1049 | + } |
1050 | +} |
1051 | + |
1052 | +// remove this to be change listener from the previous parent |
1053 | +void UCBottomEdgePrivate::itemChildRemoved(QQuickItem *item, QQuickItem *child) |
1054 | +{ |
1055 | + Q_Q(UCBottomEdge); |
1056 | + if (child == q) { |
1057 | + QQuickItemPrivate::get(item)->removeItemChangeListener(this, QQuickItemPrivate::Children); |
1058 | + } |
1059 | +} |
1060 | + |
1061 | +void UCBottomEdgePrivate::setOperationStatus(OperationStatus s) |
1062 | +{ |
1063 | + operationStatus = s; |
1064 | + switch (s) { |
1065 | + case Idle: LOG << "OP" << "Idle"; break; |
1066 | + case CommitToTop: LOG << "OP" << "CommitToTop"; break; |
1067 | + case CommitToRegion: LOG << "OP" << "CommitToRegion"; break; |
1068 | + case Collapsing: LOG << "OP" << "Collapsing"; break; |
1069 | + } |
1070 | +} |
1071 | + |
1072 | +/*! |
1073 | + * \qmltype BottomEdge |
1074 | + * \instantiates UCBottomEdge |
1075 | + * \inqmlmodule Ubuntu.Components 1.3 |
1076 | + * \inherits StyledItem |
1077 | + * \ingroup ubuntu |
1078 | + * \since Ubuntu.Components 1.3 |
1079 | + * \brief A component to handle bottom edge gesture and content. |
1080 | + * |
1081 | + * The component provides bottom edge content handling. The bottom egde feature |
1082 | + * is typically composed of a hint and some content. The contentUrl is committed |
1083 | + * (i.e. fully shown) when the drag is completed after it has been dragged for |
1084 | + * a certain amount, that is 30% of the height of the BottomEdge. The contentUrl |
1085 | + * can be anything, defined by \l contentUrl or \l contentComponent. |
1086 | + * |
1087 | + * As the name suggests, the component automatically anchors to the bottom of its |
1088 | + * parent and takes the width of the parent. The drag is detected within the parent |
1089 | + * area, and the height drives till what extent the bottom edge content should be |
1090 | + * exposed on \l commit call. The content is centered into a panel which is dragged from |
1091 | + * the bottom of the BottomEdge. The content must specify its width and height. |
1092 | + * \qml |
1093 | + * import QtQuick 2.4 |
1094 | + * import Ubuntu.Components 1.3 |
1095 | + * |
1096 | + * MainView { |
1097 | + * width: units.gu(40) |
1098 | + * height: units.gu(70) |
1099 | + * |
1100 | + * Page { |
1101 | + * id: page |
1102 | + * title: "BottomEdge" |
1103 | + * |
1104 | + * BottomEdge { |
1105 | + * height: parent.height - units.gu(20) |
1106 | + * hint.text: "My bottom edge" |
1107 | + * contentComponent: Rectangle { |
1108 | + * width: page.width |
1109 | + * height: page.height |
1110 | + * color: UbuntuColors.green |
1111 | + * } |
1112 | + * } |
1113 | + * } |
1114 | + * } |
1115 | + * \endqml |
1116 | + * |
1117 | + * \note The content is specified either through \l contentUrl or \l contentComponent, |
1118 | + * where \l contentComponent has precedence over \l contentUrl. |
1119 | + * |
1120 | + * There can be situations when the content depends on the progress of the drag. |
1121 | + * There are two possibilities to follow this, depending on the use case. The |
1122 | + * \l dragProgress provides live updates about the fraction of the drag. |
1123 | + * \qml |
1124 | + * BottomEdge { |
1125 | + * id: bottomEdge |
1126 | + * height: parent.height |
1127 | + * hint.text: "progression" |
1128 | + * contentComponent: Rectangle { |
1129 | + * width: bottomEdge.width |
1130 | + * height: bottomEdge.height |
1131 | + * color: Qt.rgba(0.5, 1, bottomEdge.dragProgress, 1); |
1132 | + * } |
1133 | + * } |
1134 | + * \endqml |
1135 | + * |
1136 | + * The other use case is when the content needs to be completely different in certain |
1137 | + * regions of the area. These regions can be defined through BottomEdgeRegion elements |
1138 | + * listed in the \l regions property. |
1139 | + * \qml |
1140 | + * import QtQuick 2.4 |
1141 | + * import Ubuntu.Components 1.3 |
1142 | + * |
1143 | + * MainView { |
1144 | + * width: units.gu(40) |
1145 | + * height: units.gu(70) |
1146 | + * |
1147 | + * Page { |
1148 | + * title: "BottomEdge" |
1149 | + * |
1150 | + * BottomEdge { |
1151 | + * id: bottomEdge |
1152 | + * height: parent.height - units.gu(20) |
1153 | + * hint.text: "My bottom edge" |
1154 | + * contentComponent: Rectangle { |
1155 | + * width: bottomEdge.width |
1156 | + * height: bottomEdge.height |
1157 | + * color: bottomEdge.activeRegion ? |
1158 | + * bottomEdge.activeRegion.color : UbuntuColors.green |
1159 | + * } |
1160 | + * regions: [ |
1161 | + * BottomEdgeRegion { |
1162 | + * from: 0.4 |
1163 | + * to: 0.6 |
1164 | + * property color color: UbuntuColors.red |
1165 | + * }, |
1166 | + * BottomEdgeRegion { |
1167 | + * from: 0.6 |
1168 | + * to: 1.0 |
1169 | + * property color color: UbuntuColors.lightGrey |
1170 | + * } |
1171 | + * ] |
1172 | + * } |
1173 | + * } |
1174 | + * } |
1175 | + * \endqml |
1176 | + * \note Custom regions override the default declared ones. Therefore there must |
1177 | + * be one region which has its \l {BottomEdgeRegion::to}{to} limit set to 1.0 |
1178 | + * otherwise the content will not be committed at all. |
1179 | + * \note Regions can also be declared as child elements the same way as resources. |
1180 | + * |
1181 | + * The BottomEdge takes ownership over the custom BottomEdgeRegions, therefore |
1182 | + * we cannot 'reuse' regions declared in other BottomEdge components, as those |
1183 | + * will be destroyed together with the reusing BottomEdge component. The following |
1184 | + * scenario only works if the \e customRegion is not used in any other regions. |
1185 | + * \qml |
1186 | + * Page { |
1187 | + * BottomEdge { |
1188 | + * id: bottomEdge |
1189 | + * hint.text: "reusing regions" |
1190 | + * // put your content and setup here |
1191 | + * |
1192 | + * regions: [customRegion] |
1193 | + * } |
1194 | + * |
1195 | + * BottomEdgeRegion { |
1196 | + * id: customRegion |
1197 | + * from: 0.2 |
1198 | + * } |
1199 | + * } |
1200 | + * \endqml |
1201 | + * \sa BottomEdgeRegion |
1202 | + * |
1203 | + * \section2 Page As Content |
1204 | + * BottomEdge accepts any component to be set as content. Also it can detect |
1205 | + * whether the content has a PageHeader component declared, and will inject a |
1206 | + * collapse navigation action automatically. In case the content has no header, |
1207 | + * the collapse must be provided by the content itself by calling the \l collapse |
1208 | + * function. |
1209 | + * \qml |
1210 | + * BottomEdge { |
1211 | + * id: bottomEdge |
1212 | + * height: parent.height |
1213 | + * hint.text: "Sample collapse" |
1214 | + * contentComponent: Rectangle { |
1215 | + * width: bottomEdge.width |
1216 | + * height: bottomEdge.height |
1217 | + * color: Qt.rgba(0.5, 1, bottomEdge.dragProgress, 1); |
1218 | + * Button { |
1219 | + * text: "Collapse" |
1220 | + * onClicked: bottomEdge.collapse() |
1221 | + * } |
1222 | + * } |
1223 | + * } |
1224 | + * \endqml |
1225 | + * Alternatively you can put a PageHeader component in your custom content |
1226 | + * as follows: |
1227 | + * \qml |
1228 | + * BottomEdge { |
1229 | + * id: bottomEdge |
1230 | + * height: parent.height |
1231 | + * hint.text: "Injected collapse" |
1232 | + * contentComponent: Rectangle { |
1233 | + * width: bottomEdge.width |
1234 | + * height: bottomEdge.height |
1235 | + * color: Qt.rgba(0.5, 1, bottomEdge.dragProgress, 1); |
1236 | + * PageHeader { |
1237 | + * title: "Fancy content" |
1238 | + * } |
1239 | + * } |
1240 | + * } |
1241 | + * \endqml |
1242 | + * |
1243 | + * \section2 Styling |
1244 | + * Similar to the other components the default style is expected to be defined |
1245 | + * in the theme's \e BottomEdgeStyle. However the style is not parented to the |
1246 | + * BottomEdge itself, but to the BottomEdge's parent item. When loaded, the style |
1247 | + * does not fill the parent but its bottom anchor is set to the bottom of the |
1248 | + * BottomEdge. Beside this the hint is also parented to the style instance. Custom |
1249 | + * styles are expected to implement the BottomEgdeStyle API. |
1250 | + */ |
1251 | + |
1252 | +/*! |
1253 | + * \qmlsignal BottomEdge::commitStarted() |
1254 | + * Signal emitted when the content commit is started. |
1255 | + */ |
1256 | + |
1257 | +/*! |
1258 | + * \qmlsignal BottomEdge::commitCompleted() |
1259 | + * Signal emitted when the content commit is completed. |
1260 | + */ |
1261 | + |
1262 | +/*! |
1263 | + * \qmlsignal BottomEdge::collapseStarted() |
1264 | + * Signal emitted when the content collapse is started. |
1265 | + */ |
1266 | + |
1267 | +/*! |
1268 | + * \qmlsignal BottomEdge::collapseCompleted() |
1269 | + * Signal emitted when the content collapse is completed. |
1270 | + */ |
1271 | + |
1272 | +UCBottomEdge::UCBottomEdge(QQuickItem *parent) |
1273 | + : UCStyledItemBase(*(new UCBottomEdgePrivate), parent) |
1274 | +{ |
1275 | + Q_D(UCBottomEdge); |
1276 | + d->init(); |
1277 | +} |
1278 | +UCBottomEdge::~UCBottomEdge() |
1279 | +{ |
1280 | +} |
1281 | + |
1282 | +void UCBottomEdge::initializeComponent() |
1283 | +{ |
1284 | + Q_D(UCBottomEdge); |
1285 | + // initialize hint |
1286 | + d->hint->init(); |
1287 | + |
1288 | + // hint click() always commits |
1289 | + connect(d->hint, SIGNAL(clicked()), this, SLOT(commit()), Qt::DirectConnection); |
1290 | + |
1291 | + // follow drag progress |
1292 | + connect(d->hint->swipeArea(), &UCSwipeArea::distanceChanged, [=](qreal distance) { |
1293 | + d->updateProgressionStates(distance); |
1294 | + }); |
1295 | + |
1296 | + // follow swipe end |
1297 | + connect(d->hint->swipeArea(), &UCSwipeArea::draggingChanged, [=](bool dragging) { |
1298 | + if (!dragging) { |
1299 | + d->onDragEnded(); |
1300 | + } |
1301 | + }); |
1302 | + |
1303 | + // filter hint for mouse events |
1304 | + d->hint->installEventFilter(this); |
1305 | +} |
1306 | + |
1307 | +void UCBottomEdge::onParentHeightChanged() |
1308 | +{ |
1309 | + Q_D(UCBottomEdge); |
1310 | + if (d->parentItem) { |
1311 | + setImplicitHeight(d->parentItem->height()); |
1312 | + } |
1313 | +} |
1314 | + |
1315 | +void UCBottomEdge::classBegin() |
1316 | +{ |
1317 | + UCStyledItemBase::classBegin(); |
1318 | + initializeComponent(); |
1319 | +} |
1320 | + |
1321 | +void UCBottomEdge::componentComplete() |
1322 | +{ |
1323 | + UCStyledItemBase::componentComplete(); |
1324 | + Q_D(UCBottomEdge); |
1325 | + // fix the hint's style version as that has no qmlContext of its own |
1326 | + // and thus import version check will fail; setting the context for |
1327 | + // the hint using this component's hint won't work either as this |
1328 | + // component's context does not contain the properties from the hint. |
1329 | + UCStyledItemBasePrivate *hintPrivate = UCStyledItemBasePrivate::get(d->hint); |
1330 | + hintPrivate->styleVersion = d->styleVersion; |
1331 | + // also set the qml data as hitn does not have that either |
1332 | + QQmlData::get(d->hint, true); |
1333 | + QQmlEngine::setContextForObject(d->hint, new QQmlContext(qmlContext(this), d->hint)); |
1334 | + // finally complete hint creation |
1335 | + hintPrivate->completeStyledItem(); |
1336 | + // and validate regions, leave out the first one as that supposed to be added first |
1337 | + // mimic the top limit of the regions list like we would add them one by one |
1338 | + for (int i = 1; i < d->regions.size(); ++i) { |
1339 | + UCBottomEdgeRegion *region = d->regions[i]; |
1340 | + d->validateRegion(region, i); |
1341 | + } |
1342 | +} |
1343 | + |
1344 | +void UCBottomEdge::itemChange(ItemChange change, const ItemChangeData &data) |
1345 | +{ |
1346 | + if (change == ItemParentHasChanged) { |
1347 | + Q_D(UCBottomEdge); |
1348 | + // disconnect from old parent |
1349 | + if (d->oldParentItem) { |
1350 | + disconnect(d->oldParentItem, &QQuickItem::heightChanged, |
1351 | + this, &UCBottomEdge::onParentHeightChanged); |
1352 | + } |
1353 | + QQuickAnchors *anchors = QQuickItemPrivate::get(this)->anchors(); |
1354 | + if (data.item) { |
1355 | + const QQuickAnchorLine left = QQuickItemPrivate::get(data.item)->left(); |
1356 | + const QQuickAnchorLine right = QQuickItemPrivate::get(data.item)->right(); |
1357 | + const QQuickAnchorLine bottom = QQuickItemPrivate::get(data.item)->bottom(); |
1358 | + anchors->setLeft(left); |
1359 | + anchors->setRight(right); |
1360 | + anchors->setBottom(bottom); |
1361 | + QQuickItemPrivate::get(data.item)->addItemChangeListener(d, QQuickItemPrivate::Children); |
1362 | + // follow implicitHeight |
1363 | + connect(data.item, &QQuickItem::heightChanged, |
1364 | + this, &UCBottomEdge::onParentHeightChanged); |
1365 | + onParentHeightChanged(); |
1366 | + } else { |
1367 | + anchors->resetLeft(); |
1368 | + anchors->resetRight(); |
1369 | + anchors->resetBottom(); |
1370 | + } |
1371 | + if (d->bottomPanel) { |
1372 | + d->bottomPanel->setParentItem(data.item); |
1373 | + } |
1374 | + } |
1375 | + UCStyledItemBase::itemChange(change, data); |
1376 | +} |
1377 | + |
1378 | +bool UCBottomEdge::eventFilter(QObject *target, QEvent *event) |
1379 | +{ |
1380 | + Q_D(UCBottomEdge); |
1381 | + |
1382 | + switch (event->type()) { |
1383 | + case QEvent::MouseButtonPress: |
1384 | + { |
1385 | + QMouseEvent *mouse = static_cast<QMouseEvent*>(event); |
1386 | + d->mousePressed = d->hint->contains(mouse->localPos()); |
1387 | + LOG << "drag with mouse"; |
1388 | + break; |
1389 | + } |
1390 | + case QEvent::MouseButtonRelease: |
1391 | + if (d->mousePressed) { |
1392 | + d->onDragEnded(); |
1393 | + } |
1394 | + d->mousePressed = false; |
1395 | + break; |
1396 | + case QEvent::MouseMove: |
1397 | + { |
1398 | + if (d->mousePressed) { |
1399 | + QMouseEvent *mouse = static_cast<QMouseEvent*>(event); |
1400 | + qreal mouseItemY = mapFromScene(mouse->windowPos()).y(); |
1401 | + qreal distance = abs(height() - mouseItemY); |
1402 | + d->updateProgressionStates(distance); |
1403 | + } |
1404 | + break; |
1405 | + } |
1406 | + default: break; |
1407 | + } |
1408 | + return UCStyledItemBase::eventFilter(target, event); |
1409 | +} |
1410 | + |
1411 | +/*! |
1412 | + * \qmlproperty BottomEdgeHint BottomEdge::hint |
1413 | + * The property holds the component to display the hint for the bottom edge element. |
1414 | + */ |
1415 | +UCBottomEdgeHint *UCBottomEdge::hint() const |
1416 | +{ |
1417 | + Q_D(const UCBottomEdge); |
1418 | + return d->hint; |
1419 | +} |
1420 | + |
1421 | +/*! |
1422 | + * \qmlproperty real BottomEdge::dragProgress |
1423 | + * \readonly |
1424 | + * The property specifies the proggress of the drag within [0..1] interval. |
1425 | + */ |
1426 | +qreal UCBottomEdge::dragProgress() |
1427 | +{ |
1428 | + Q_D(UCBottomEdge); |
1429 | + return d->dragProgress; |
1430 | +} |
1431 | + |
1432 | +/*! |
1433 | + * \qmlproperty DragDirection BottomEdge::dragDirection |
1434 | + * \readonly |
1435 | + * The property reports the current direction of the drag. The direction is flipped |
1436 | + * when the drag passes the drag threshold. |
1437 | + * \table |
1438 | + * \header |
1439 | + * \li DragDirection |
1440 | + * \li Description |
1441 | + * \row |
1442 | + * \li Undefined |
1443 | + * \li Default. The drag is not performed or the direction is not detected. |
1444 | + * \row |
1445 | + * \li Upwards |
1446 | + * \li The drag is performed from bottom up or it passed the drag threshold from |
1447 | + * from the last point the drag was going downwards. |
1448 | + * \row |
1449 | + * \li Downwards |
1450 | + * \li The drag is performed from up to bottom or it passed the drag threshold from |
1451 | + * from the last point the drag was going upwards. |
1452 | + * \endtable |
1453 | + * |
1454 | + * Defaults to \e Undefined |
1455 | + */ |
1456 | +UCBottomEdge::DragDirection UCBottomEdge::dragDirection() const |
1457 | +{ |
1458 | + Q_D(const UCBottomEdge); |
1459 | + return d->dragDirection; |
1460 | +} |
1461 | + |
1462 | +/*! |
1463 | + * \qmlproperty Status BottomEdge::status |
1464 | + * \readonly |
1465 | + * The property reports the actual state of the bottom edge. It can have the |
1466 | + * following values: |
1467 | + * \table |
1468 | + * \header |
1469 | + * \li Status |
1470 | + * \li Description |
1471 | + * \row |
1472 | + * \li Hidden |
1473 | + * \li The bottom edge is hidden. This does not contain the hint states. |
1474 | + * \row |
1475 | + * \li Revealed |
1476 | + * \li The Bottom edge content is revealed. The state can be reached only if the |
1477 | + * \l hint is in "Active" state. |
1478 | + * \row |
1479 | + * \li Committed |
1480 | + * \li The bottom edge content is fully exposed. |
1481 | + * \endtable |
1482 | + * \note Once \e Commited status is set, no further draging is possible on the content. |
1483 | + */ |
1484 | +UCBottomEdge::Status UCBottomEdge::status() const |
1485 | +{ |
1486 | + Q_D(const UCBottomEdge); |
1487 | + return d->status; |
1488 | +} |
1489 | +void UCBottomEdgePrivate::setStatus(UCBottomEdge::Status status) |
1490 | +{ |
1491 | + if (status == this->status) { |
1492 | + return; |
1493 | + } |
1494 | + this->status = status; |
1495 | + // logging |
1496 | + switch (status) { |
1497 | + case UCBottomEdge::Hidden: LOG << "STATUS" << "Hidden"; break; |
1498 | + case UCBottomEdge::Revealed: LOG << "STATUS" << "Revealed"; break; |
1499 | + case UCBottomEdge::Committed: LOG << "STATUS" << "Committed"; break; |
1500 | + } |
1501 | + |
1502 | + if (bottomPanel) { |
1503 | + bottomPanel->setConsumeMouse(status > UCBottomEdge::Hidden); |
1504 | + } |
1505 | + |
1506 | + Q_EMIT q_func()->statusChanged(this->status); |
1507 | +} |
1508 | + |
1509 | +/*! |
1510 | + * \qmlproperty url BottomEdge::contentUrl |
1511 | + * The property holds the url to the document defining the content of the bottom |
1512 | + * edge. The property behaves the same way as Loader's \e source property. |
1513 | + */ |
1514 | +QUrl UCBottomEdge::contentUrl() const |
1515 | +{ |
1516 | + Q_D(const UCBottomEdge); |
1517 | + return d->contentUrl; |
1518 | +} |
1519 | +void UCBottomEdge::setContent(const QUrl &url) |
1520 | +{ |
1521 | + Q_D(UCBottomEdge); |
1522 | + if (d->contentUrl == url) { |
1523 | + return; |
1524 | + } |
1525 | + |
1526 | + d->contentUrl = url; |
1527 | + Q_EMIT contentChanged(d->contentUrl); |
1528 | +} |
1529 | + |
1530 | +/*! |
1531 | + * \qmlproperty Component BottomEdge::contentComponent |
1532 | + * The property holds the component defining the content of the bottom edge. The |
1533 | + * property behaves the same way as Loader's \e sourceComponent property. |
1534 | + */ |
1535 | +QQmlComponent *UCBottomEdge::contentComponent() const |
1536 | +{ |
1537 | + Q_D(const UCBottomEdge); |
1538 | + return d->contentComponent; |
1539 | +} |
1540 | +void UCBottomEdge::setContentComponent(QQmlComponent *component) |
1541 | +{ |
1542 | + Q_D(UCBottomEdge); |
1543 | + if (d->contentComponent == component) { |
1544 | + return; |
1545 | + } |
1546 | + d->contentComponent = component; |
1547 | + Q_EMIT contentComponentChanged(d->contentComponent); |
1548 | +} |
1549 | + |
1550 | +/*! |
1551 | + * \qmlproperty Item BottomEdge::contentItem |
1552 | + * \readonly |
1553 | + * The property holds the item created either from \l contentUrl or \l contentComponent |
1554 | + * properties. |
1555 | + */ |
1556 | +QQuickItem *UCBottomEdge::contentItem() const |
1557 | +{ |
1558 | + Q_D(const UCBottomEdge); |
1559 | + return d->bottomPanel ? d->bottomPanel->m_contentItem : Q_NULLPTR; |
1560 | +} |
1561 | + |
1562 | +/*! |
1563 | + * \qmlmethod void BottomEdge::commit() |
1564 | + * The function forces the bottom edge content to be fully exposed. Emits |
1565 | + * \l commitStarted and \l commitCompleted signals to notify the start and the |
1566 | + * completion of the commit operation. It is safe to call commit() multiple times. |
1567 | + */ |
1568 | +void UCBottomEdge::commit() |
1569 | +{ |
1570 | + Q_D(UCBottomEdge); |
1571 | + d->commit(1.0); |
1572 | +} |
1573 | + |
1574 | +/*! |
1575 | + * \qmlmethod void BottomEdge::collapse() |
1576 | + * The function forces the bottom edge content to be hidden. Emits \l collapseStarted |
1577 | + * and \l collapseCompleted signals to notify the start and the completion of the |
1578 | + * collapse operation. |
1579 | + */ |
1580 | +void UCBottomEdge::collapse() |
1581 | +{ |
1582 | + Q_D(UCBottomEdge); |
1583 | + if (d->operationStatus == UCBottomEdgePrivate::Collapsing || d->status == UCBottomEdge::Hidden) { |
1584 | + LOG << "redundant collapse call"; |
1585 | + return; |
1586 | + } |
1587 | + d->setOperationStatus(UCBottomEdgePrivate::Collapsing); |
1588 | + Q_EMIT collapseStarted(); |
1589 | + bool animated = d->bottomPanel && d->bottomPanel->m_panelAnimation; |
1590 | + if (animated) { |
1591 | + connect(d->bottomPanel->m_panelAnimation, &QQuickAbstractAnimation::runningChanged, |
1592 | + this, &UCBottomEdge::unlockOperation, Qt::UniqueConnection); |
1593 | + } |
1594 | + // set the setStatus first to Revealed |
1595 | + if (d->status == UCBottomEdge::Committed) { |
1596 | + d->setStatus(Revealed); |
1597 | + } |
1598 | + d->setDragProgress(0.0); |
1599 | + if (!animated) { |
1600 | + unlockOperation(false); |
1601 | + } |
1602 | +} |
1603 | + |
1604 | +/*! |
1605 | + * \qmlproperty list<BottomEdgeRegion> BottomEdge::regions |
1606 | + * The property holds the custom regions configured for the BottomEdge. The default |
1607 | + * configuration contains one region, which commits the content when reached. The |
1608 | + * defaults can be restored by setting an empty list to the property or by |
1609 | + * calling regions.clear(). |
1610 | + * See \l BottomEdgeRegion. |
1611 | + */ |
1612 | +QQmlListProperty<UCBottomEdgeRegion> UCBottomEdge::regions() |
1613 | +{ |
1614 | + Q_D(UCBottomEdge); |
1615 | + return QQmlListProperty<UCBottomEdgeRegion>(this, &d->regions, |
1616 | + regions_append, |
1617 | + regions_count, |
1618 | + regions_at, |
1619 | + regions_clear); |
1620 | +} |
1621 | + |
1622 | +void UCBottomEdge::regions_append(QQmlListProperty<UCBottomEdgeRegion> *regions, UCBottomEdgeRegion *region) |
1623 | +{ |
1624 | + UCBottomEdgePrivate *bottomEdge = UCBottomEdgePrivate::get(static_cast<UCBottomEdge*>(regions->object)); |
1625 | + bottomEdge->appendRegion(region); |
1626 | +} |
1627 | + |
1628 | +int UCBottomEdge::regions_count(QQmlListProperty<UCBottomEdgeRegion> *regions) |
1629 | +{ |
1630 | + UCBottomEdgePrivate *bottomEdge = UCBottomEdgePrivate::get(static_cast<UCBottomEdge*>(regions->object)); |
1631 | + return bottomEdge->regions.size(); |
1632 | +} |
1633 | + |
1634 | +UCBottomEdgeRegion *UCBottomEdge::regions_at(QQmlListProperty<UCBottomEdgeRegion> *regions, int index) |
1635 | +{ |
1636 | + UCBottomEdgePrivate *bottomEdge = UCBottomEdgePrivate::get(static_cast<UCBottomEdge*>(regions->object)); |
1637 | + Q_ASSERT((index >= 0) && (index < bottomEdge->regions.size())); |
1638 | + return bottomEdge->regions.at(index); |
1639 | +} |
1640 | + |
1641 | +void UCBottomEdge::regions_clear(QQmlListProperty<UCBottomEdgeRegion> *regions) |
1642 | +{ |
1643 | + UCBottomEdgePrivate *bottomEdge = UCBottomEdgePrivate::get(static_cast<UCBottomEdge*>(regions->object)); |
1644 | + bottomEdge->clearRegions(true); |
1645 | +} |
1646 | + |
1647 | +/*! |
1648 | + * \qmlproperty BottomEdgeRegion BottomEdge::activeRegion |
1649 | + * \readonly |
1650 | + * Specifies the current active region. |
1651 | + */ |
1652 | +UCBottomEdgeRegion *UCBottomEdge::activeRegion() |
1653 | +{ |
1654 | + Q_D(UCBottomEdge); |
1655 | + return d->activeRegion; |
1656 | +} |
1657 | + |
1658 | +#include "moc_ucbottomedge.cpp" |
1659 | |
1660 | === added file 'src/Ubuntu/Components/plugin/ucbottomedge.h' |
1661 | --- src/Ubuntu/Components/plugin/ucbottomedge.h 1970-01-01 00:00:00 +0000 |
1662 | +++ src/Ubuntu/Components/plugin/ucbottomedge.h 2015-11-27 10:36:32 +0000 |
1663 | @@ -0,0 +1,120 @@ |
1664 | +/* |
1665 | + * Copyright 2015 Canonical Ltd. |
1666 | + * |
1667 | + * This program is free software; you can redistribute it and/or modify |
1668 | + * it under the terms of the GNU Lesser General Public License as published by |
1669 | + * the Free Software Foundation; version 3. |
1670 | + * |
1671 | + * This program is distributed in the hope that it will be useful, |
1672 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
1673 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
1674 | + * GNU Lesser General Public License for more details. |
1675 | + * |
1676 | + * You should have received a copy of the GNU Lesser General Public License |
1677 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
1678 | + * |
1679 | + * Author: Zsombor Egri <zsombor.egri@canonical.com> |
1680 | + */ |
1681 | + |
1682 | +#ifndef UCBOTTOMEDGE_H |
1683 | +#define UCBOTTOMEDGE_H |
1684 | + |
1685 | +#include "ucstyleditembase.h" |
1686 | +#include <QtCore/QPointer> |
1687 | +#include <QtQuick/private/qquickitemchangelistener_p.h> |
1688 | +#include <QtCore/QLoggingCategory> |
1689 | + |
1690 | +class UCBottomEdgeHint; |
1691 | +class UCBottomEdgeRegion; |
1692 | +class QQuickAbstractAnimation; |
1693 | +class UCBottomEdgePrivate; |
1694 | +class UCBottomEdge : public UCStyledItemBase |
1695 | +{ |
1696 | + Q_OBJECT |
1697 | + Q_ENUMS(Status DragDirection) |
1698 | + |
1699 | + Q_PROPERTY(UCBottomEdgeHint* hint READ hint CONSTANT FINAL) |
1700 | + Q_PROPERTY(qreal dragProgress READ dragProgress NOTIFY dragProgressChanged FINAL) |
1701 | + Q_PROPERTY(DragDirection dragDirection READ dragDirection NOTIFY dragDirectionChanged FINAL) |
1702 | + Q_PROPERTY(Status status READ status NOTIFY statusChanged FINAL) |
1703 | + Q_PROPERTY(QUrl contentUrl READ contentUrl WRITE setContent NOTIFY contentChanged FINAL) |
1704 | + Q_PROPERTY(QQmlComponent *contentComponent READ contentComponent WRITE setContentComponent NOTIFY contentComponentChanged FINAL) |
1705 | + Q_PROPERTY(QQuickItem* contentItem READ contentItem NOTIFY contentItemChanged FINAL) |
1706 | + Q_PROPERTY(QQmlListProperty<UCBottomEdgeRegion> regions READ regions NOTIFY regionsChanged FINAL) |
1707 | + Q_PROPERTY(UCBottomEdgeRegion* activeRegion READ activeRegion NOTIFY activeRegionChanged FINAL) |
1708 | + |
1709 | + // overloaded data property to catch regions |
1710 | + Q_PRIVATE_PROPERTY(UCBottomEdge::d_func(), QQmlListProperty<QObject> data READ data DESIGNABLE false) |
1711 | + Q_CLASSINFO("DefaultProperty", "data") |
1712 | +public: |
1713 | + enum Status { |
1714 | + Hidden, |
1715 | + Revealed, |
1716 | + Committed |
1717 | + }; |
1718 | + enum DragDirection { |
1719 | + Undefined, |
1720 | + Upwards, |
1721 | + Downwards |
1722 | + }; |
1723 | + |
1724 | + explicit UCBottomEdge(QQuickItem *parent = 0); |
1725 | + virtual ~UCBottomEdge(); |
1726 | + |
1727 | + UCBottomEdgeHint *hint() const; |
1728 | + qreal dragProgress(); |
1729 | + DragDirection dragDirection() const; |
1730 | + Status status() const; |
1731 | + QUrl contentUrl() const; |
1732 | + void setContent(const QUrl &url); |
1733 | + QQmlComponent *contentComponent() const; |
1734 | + void setContentComponent(QQmlComponent *component); |
1735 | + QQuickItem *contentItem() const; |
1736 | + void setFillWindow(bool fill); |
1737 | + QQmlListProperty<UCBottomEdgeRegion> regions(); |
1738 | + UCBottomEdgeRegion *activeRegion(); |
1739 | + |
1740 | +Q_SIGNALS: |
1741 | + void dragProgressChanged(qreal dragProgress); |
1742 | + void dragDirectionChanged(UCBottomEdge::DragDirection direction); |
1743 | + void statusChanged(UCBottomEdge::Status status); |
1744 | + void contentChanged(const QUrl url); |
1745 | + void contentComponentChanged(QQmlComponent *component); |
1746 | + void contentItemChanged(); |
1747 | + void regionsChanged(); |
1748 | + void activeRegionChanged(UCBottomEdgeRegion *activeRegion); |
1749 | + |
1750 | + void commitStarted(); |
1751 | + void commitCompleted(); |
1752 | + void collapseStarted(); |
1753 | + void collapseCompleted(); |
1754 | + |
1755 | +public Q_SLOTS: |
1756 | + void commit(); |
1757 | + void collapse(); |
1758 | + |
1759 | +protected: |
1760 | + static void regions_append(QQmlListProperty<UCBottomEdgeRegion> *sections, UCBottomEdgeRegion *section); |
1761 | + static int regions_count(QQmlListProperty<UCBottomEdgeRegion> *sections); |
1762 | + static UCBottomEdgeRegion *regions_at(QQmlListProperty<UCBottomEdgeRegion> *sections, int index); |
1763 | + static void regions_clear(QQmlListProperty<UCBottomEdgeRegion> *sections); |
1764 | + |
1765 | + void initializeComponent(); |
1766 | + void classBegin(); |
1767 | + void componentComplete(); |
1768 | + void itemChange(ItemChange change, const ItemChangeData &data); |
1769 | + bool eventFilter(QObject *target, QEvent *event) override; |
1770 | + |
1771 | + void unlockOperation(bool running); |
1772 | + void onParentHeightChanged(); |
1773 | + |
1774 | + Q_DECLARE_PRIVATE(UCBottomEdge) |
1775 | + |
1776 | + friend class tst_BottomEdge; |
1777 | +}; |
1778 | +Q_DECLARE_METATYPE(UCBottomEdge::Status) |
1779 | +Q_DECLARE_METATYPE(UCBottomEdge::DragDirection) |
1780 | + |
1781 | +Q_DECLARE_LOGGING_CATEGORY(ucBottomEdge) |
1782 | + |
1783 | +#endif // UCBOTTOMEDGE_H |
1784 | |
1785 | === added file 'src/Ubuntu/Components/plugin/ucbottomedge_p.h' |
1786 | --- src/Ubuntu/Components/plugin/ucbottomedge_p.h 1970-01-01 00:00:00 +0000 |
1787 | +++ src/Ubuntu/Components/plugin/ucbottomedge_p.h 2015-11-27 10:36:32 +0000 |
1788 | @@ -0,0 +1,111 @@ |
1789 | +/* |
1790 | + * Copyright 2015 Canonical Ltd. |
1791 | + * |
1792 | + * This program is free software; you can redistribute it and/or modify |
1793 | + * it under the terms of the GNU Lesser General Public License as published by |
1794 | + * the Free Software Foundation; version 3. |
1795 | + * |
1796 | + * This program is distributed in the hope that it will be useful, |
1797 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
1798 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
1799 | + * GNU Lesser General Public License for more details. |
1800 | + * |
1801 | + * You should have received a copy of the GNU Lesser General Public License |
1802 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
1803 | + * |
1804 | + * Author: Zsombor Egri <zsombor.egri@canonical.com> |
1805 | + */ |
1806 | + |
1807 | +#ifndef UCBOTTOMEDGE_P_H |
1808 | +#define UCBOTTOMEDGE_P_H |
1809 | + |
1810 | +#include "ucbottomedge.h" |
1811 | +#include "ucstyleditembase_p.h" |
1812 | +#include "ucaction.h" |
1813 | + |
1814 | +class UCBottomEdgeStyle; |
1815 | +class UCBottomEdgePrivate : public UCStyledItemBasePrivate, protected QQuickItemChangeListener |
1816 | +{ |
1817 | + Q_DECLARE_PUBLIC(UCBottomEdge) |
1818 | + |
1819 | +public: |
1820 | + UCBottomEdgePrivate(); |
1821 | + |
1822 | + static UCBottomEdgePrivate *get(UCBottomEdge *item) |
1823 | + { |
1824 | + return item->d_func(); |
1825 | + } |
1826 | + void init(); |
1827 | + |
1828 | + // data property |
1829 | + QQmlListProperty<QObject> data(); |
1830 | + static void overload_data_append(QQmlListProperty<QObject> *, QObject *); |
1831 | + static void overload_data_clear(QQmlListProperty<QObject> *); |
1832 | + |
1833 | + // range funcs |
1834 | + void appendRegion(UCBottomEdgeRegion *range); |
1835 | + void clearRegions(bool destroy); |
1836 | + void validateRegion(UCBottomEdgeRegion *region, int regionsSize = -1); |
1837 | + |
1838 | + // page header manipulation |
1839 | + void patchContentItemHeader(); |
1840 | + void createDefaultRegions(); |
1841 | + void updateProgressionStates(qreal distance); |
1842 | + bool setActiveRegion(UCBottomEdgeRegion *range); |
1843 | + void detectDirection(qreal currentDistance); |
1844 | + void setDragDirection(UCBottomEdge::DragDirection direction); |
1845 | + void onDragEnded(); |
1846 | + void commit(qreal to); |
1847 | + |
1848 | + // panel positioning |
1849 | + void setDragProgress(qreal position); |
1850 | + // internal setters |
1851 | + void setStatus(UCBottomEdge::Status status); |
1852 | + |
1853 | + // from UCStyledItemBase |
1854 | + bool loadStyleItem(bool animated = true) override; |
1855 | + // from QQuickItemChangeListener |
1856 | + void itemChildAdded(QQuickItem *item, QQuickItem *child); |
1857 | + void itemChildRemoved(QQuickItem *item, QQuickItem *child); |
1858 | + |
1859 | + // members |
1860 | + QUrl contentUrl; |
1861 | + QList<UCBottomEdgeRegion*> regions; |
1862 | + UCBottomEdgeRegion *activeRegion; |
1863 | + UCBottomEdgeHint *hint; |
1864 | + QQmlComponent *contentComponent; |
1865 | + UCBottomEdgeStyle *bottomPanel; |
1866 | + |
1867 | + qreal previousDistance; |
1868 | + qreal dragProgress; |
1869 | + UCBottomEdge::Status status; |
1870 | + |
1871 | + enum OperationStatus { |
1872 | + Idle, |
1873 | + CommitToTop, |
1874 | + CommitToRegion, |
1875 | + Collapsing |
1876 | + }; |
1877 | + OperationStatus operationStatus; |
1878 | + UCBottomEdge::DragDirection dragDirection; |
1879 | + |
1880 | + bool defaultRegionsReset:1; |
1881 | + bool mousePressed:1; |
1882 | + |
1883 | + // status management |
1884 | + void setOperationStatus(OperationStatus s); |
1885 | + bool isLocked() |
1886 | + { |
1887 | + return operationStatus > Idle; |
1888 | + } |
1889 | +}; |
1890 | + |
1891 | +class UCCollapseAction : public UCAction |
1892 | +{ |
1893 | + Q_OBJECT |
1894 | +public: |
1895 | + UCCollapseAction(QObject *parent = 0); |
1896 | +}; |
1897 | +Q_DECLARE_METATYPE(QQmlListProperty<UCAction>) |
1898 | + |
1899 | +#endif // UCBOTTOMEDGE_P_H |
1900 | |
1901 | === modified file 'src/Ubuntu/Components/plugin/ucbottomedgehint.cpp' |
1902 | --- src/Ubuntu/Components/plugin/ucbottomedgehint.cpp 2015-11-19 10:04:28 +0000 |
1903 | +++ src/Ubuntu/Components/plugin/ucbottomedgehint.cpp 2015-11-27 10:36:32 +0000 |
1904 | @@ -169,7 +169,7 @@ |
1905 | } |
1906 | void UCBottomEdgeHint::mouseReleaseEvent(QMouseEvent *event) |
1907 | { |
1908 | - if (m_pressed && (m_status >= Active)) { |
1909 | + if (m_pressed && (m_status >= Active) && contains(event->localPos())) { |
1910 | Q_EMIT clicked(); |
1911 | event->accept(); |
1912 | } else { |
1913 | |
1914 | === modified file 'src/Ubuntu/Components/plugin/ucbottomedgehint.h' |
1915 | --- src/Ubuntu/Components/plugin/ucbottomedgehint.h 2015-11-17 13:45:25 +0000 |
1916 | +++ src/Ubuntu/Components/plugin/ucbottomedgehint.h 2015-11-27 10:36:32 +0000 |
1917 | @@ -87,6 +87,8 @@ |
1918 | int m_deactivateTimeout; |
1919 | Status m_status; |
1920 | bool m_pressed:1; |
1921 | + |
1922 | + friend class UCBottomEdge; |
1923 | }; |
1924 | |
1925 | #endif // UCBOTTOMEDGEHINT_H |
1926 | |
1927 | === added file 'src/Ubuntu/Components/plugin/ucbottomedgeregion.cpp' |
1928 | --- src/Ubuntu/Components/plugin/ucbottomedgeregion.cpp 1970-01-01 00:00:00 +0000 |
1929 | +++ src/Ubuntu/Components/plugin/ucbottomedgeregion.cpp 2015-11-27 10:36:32 +0000 |
1930 | @@ -0,0 +1,253 @@ |
1931 | +/* |
1932 | + * Copyright 2015 Canonical Ltd. |
1933 | + * |
1934 | + * This program is free software; you can redistribute it and/or modify |
1935 | + * it under the terms of the GNU Lesser General Public License as published by |
1936 | + * the Free Software Foundation; version 3. |
1937 | + * |
1938 | + * This program is distributed in the hope that it will be useful, |
1939 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
1940 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
1941 | + * GNU Lesser General Public License for more details. |
1942 | + * |
1943 | + * You should have received a copy of the GNU Lesser General Public License |
1944 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
1945 | + * |
1946 | + * Author: Zsombor Egri <zsombor.egri@canonical.com> |
1947 | + */ |
1948 | + |
1949 | +#include "ucbottomedge.h" |
1950 | +#include "ucbottomedge_p.h" |
1951 | +#include "ucbottomedgeregion.h" |
1952 | +#include "propertychange_p.h" |
1953 | +#include <QtQml/private/qqmlproperty_p.h> |
1954 | + |
1955 | +/*! |
1956 | + * \qmltype BottomEdgeRegion |
1957 | + * \instantiates UCBottomEdgeRegion |
1958 | + * \inherits QtObject |
1959 | + * \inmodule Ubuntu.Components 1.3 |
1960 | + * \since Ubuntu.Components 1.3 |
1961 | + * \ingroup ubuntu |
1962 | + * \brief Defines an active region within the BottomEdge component. |
1963 | + * |
1964 | + * Bottom edge regions are portions within the bottom edge area which can define |
1965 | + * different content or action whenever the drag enters in the area. The area is |
1966 | + * defined by \l from and \l to properties vertically, whereas horizontally is |
1967 | + * stretched across bottom edge width. Custom content can be defined through |
1968 | + * \l contentUrl or \l contentComponent properties, which will override the |
1969 | + * \l BottomEdge::contentUrl and \l BottomEdge::contentComponent properties for the |
1970 | + * time the gesture is in the section area. |
1971 | + * \qml |
1972 | + * import QtQuick 2.4 |
1973 | + * import Ubuntu.Components 1.3 |
1974 | + * |
1975 | + * MainView { |
1976 | + * width: units.gu(40) |
1977 | + * height: units.gu(70) |
1978 | + * |
1979 | + * Page { |
1980 | + * header: PageHeader { |
1981 | + * title: "BottomEdge regions" |
1982 | + * } |
1983 | + * |
1984 | + * BottomEdge { |
1985 | + * id: bottomEdge |
1986 | + * height: parent.height - units.gu(20) |
1987 | + * hint: BottomEdgeHint { |
1988 | + * text: "My bottom edge" |
1989 | + * } |
1990 | + * // a fake content till we reach the committable area |
1991 | + * contentComponent: Rectangle { |
1992 | + * width: bottomEdge.width |
1993 | + * height: bottomEdge.height |
1994 | + * color: UbuntuColors.green |
1995 | + * } |
1996 | + * // override bottom edge sections to switch to real content |
1997 | + * BottomEdgeRegion { |
1998 | + * from: 0.33 |
1999 | + * contentComponent: Page { |
2000 | + * width: bottomEdge.width |
2001 | + * height: bottomEdge.height |
2002 | + * header: PageHeader { |
2003 | + * title: "BottomEdge Content" |
2004 | + * } |
2005 | + * } |
2006 | + * } |
2007 | + * } |
2008 | + * } |
2009 | + * } |
2010 | + * \endqml |
2011 | + * |
2012 | + * Entering into the section area is signalled by the \l entered signal and when |
2013 | + * drag leaves the area the \l exited signal is emitted. If the drag ends within |
2014 | + * the section area, the \l dragEnded signal is emitted. In case the section's |
2015 | + * \l to property is less than 1.0, the bottom edge content will only be exposed |
2016 | + * to that value, and the \l BottomEdge::status will get the \e Committed value. |
2017 | + * No further drag is possible after reaching \e Commited state. |
2018 | + * |
2019 | + * \note Whereas there is no restriction on making overlapping sections, beware that |
2020 | + * overlapping sections changing the content through the \l contentUrl or \l contentComponent |
2021 | + * properties will cause unpredictable results. |
2022 | + */ |
2023 | + |
2024 | +UCBottomEdgeRegion::UCBottomEdgeRegion(QObject *parent) |
2025 | + : QObject(parent) |
2026 | + , m_bottomEdge(qobject_cast<UCBottomEdge*>(parent)) |
2027 | + , m_component(Q_NULLPTR) |
2028 | + , m_urlBackup(Q_NULLPTR) |
2029 | + , m_componentBackup(Q_NULLPTR) |
2030 | + , m_from(0.0) |
2031 | + , m_to(-1.0) |
2032 | + , m_enabled(true) |
2033 | +{ |
2034 | +} |
2035 | + |
2036 | +void UCBottomEdgeRegion::attachToBottomEdge(UCBottomEdge *bottomEdge) |
2037 | +{ |
2038 | + QQml_setParent_noEvent(this, bottomEdge); |
2039 | + m_bottomEdge = bottomEdge; |
2040 | + // adjust to property value if not set yet |
2041 | + if (m_to <= 0.0) { |
2042 | + m_to = 1.0; |
2043 | + Q_EMIT toChanged(); |
2044 | + } |
2045 | +} |
2046 | + |
2047 | +bool UCBottomEdgeRegion::contains(qreal dragRatio) |
2048 | +{ |
2049 | + return (m_enabled && (m_from < m_to) && dragRatio >= m_from && dragRatio <= m_to); |
2050 | +} |
2051 | + |
2052 | +void UCBottomEdgeRegion::enter() |
2053 | +{ |
2054 | + Q_EMIT entered(); |
2055 | + // backup url |
2056 | + if (m_url.isValid()) { |
2057 | + m_urlBackup = new PropertyChange(m_bottomEdge, "contentUrl"); |
2058 | + QQmlProperty property(this, "contentUrl", qmlContext(this)); |
2059 | + QQmlAbstractBinding *binding = QQmlPropertyPrivate::binding(property); |
2060 | + if (binding) { |
2061 | + PropertyChange::setBinding(m_urlBackup, binding); |
2062 | + } else { |
2063 | + PropertyChange::setValue(m_urlBackup, m_url); |
2064 | + } |
2065 | + } |
2066 | + if (m_component) { |
2067 | + m_componentBackup = new PropertyChange(m_bottomEdge, "contentComponent"); |
2068 | + QQmlProperty property(this, "contentComponent", qmlContext(this)); |
2069 | + QQmlAbstractBinding *binding = QQmlPropertyPrivate::binding(property); |
2070 | + if (binding) { |
2071 | + PropertyChange::setBinding(m_componentBackup, binding); |
2072 | + } else { |
2073 | + PropertyChange::setValue(m_componentBackup, QVariant::fromValue<QQmlComponent*>(m_component)); |
2074 | + } |
2075 | + } |
2076 | +} |
2077 | + |
2078 | +void UCBottomEdgeRegion::exit() |
2079 | +{ |
2080 | + if (m_componentBackup) { |
2081 | + delete m_componentBackup; |
2082 | + m_componentBackup = Q_NULLPTR; |
2083 | + } |
2084 | + if (m_urlBackup) { |
2085 | + delete m_urlBackup; |
2086 | + m_urlBackup = Q_NULLPTR; |
2087 | + } |
2088 | + Q_EMIT exited(); |
2089 | +} |
2090 | + |
2091 | +const QRectF UCBottomEdgeRegion::rect(const QRectF &bottomEdgeRect) |
2092 | +{ |
2093 | + QRectF regionRect( |
2094 | + bottomEdgeRect.topLeft() + QPointF(0, bottomEdgeRect.height() * (1.0 - m_to)), |
2095 | + QSizeF(bottomEdgeRect.width(), bottomEdgeRect.height() * (m_to - m_from))); |
2096 | + return regionRect; |
2097 | +} |
2098 | + |
2099 | +/*! |
2100 | + * \qmlproperty bool BottomEdgeRegion::enabled |
2101 | + * Enables the section. Disabled sections do not trigger nor change the BottomEdge |
2102 | + * content. Defaults to false. |
2103 | + */ |
2104 | +void UCBottomEdgeRegion::setEnabled(bool enabled) |
2105 | +{ |
2106 | + if (enabled == m_enabled) { |
2107 | + return; |
2108 | + } |
2109 | + m_enabled = enabled; |
2110 | + if (m_bottomEdge) { |
2111 | + UCBottomEdgePrivate::get(m_bottomEdge)->validateRegion(this); |
2112 | + } |
2113 | + Q_EMIT enabledChanged(); |
2114 | +} |
2115 | + |
2116 | +/*! |
2117 | + * \qmlproperty real BottomEdgeRegion::from |
2118 | + * Specifies the starting ratio of the bottom erge area. The value must be bigger |
2119 | + * or equal to 0 but strictly smaller than \l to. Defaults to 0.0. |
2120 | + */ |
2121 | +void UCBottomEdgeRegion::setFrom(qreal from) |
2122 | +{ |
2123 | + if (from == m_from) { |
2124 | + return; |
2125 | + } |
2126 | + m_from = from; |
2127 | + if (m_bottomEdge) { |
2128 | + UCBottomEdgePrivate::get(m_bottomEdge)->validateRegion(this); |
2129 | + } |
2130 | + Q_EMIT fromChanged(); |
2131 | +} |
2132 | + |
2133 | +/*! |
2134 | + * \qmlproperty real BottomEdgeRegion::to |
2135 | + * Specifies the ending ratio of the bottom edge area. The value must be bigger |
2136 | + * than \l from and smaller or equal to 1.0. |
2137 | + * \note If the end point is less than 1.0, ending the drag within the section |
2138 | + * will result in exposing the bottom edge content only till the ration specified |
2139 | + * by this property. |
2140 | + */ |
2141 | +void UCBottomEdgeRegion::setTo(qreal to) |
2142 | +{ |
2143 | + if (to == m_to) { |
2144 | + return; |
2145 | + } |
2146 | + m_to = to; |
2147 | + if (m_bottomEdge) { |
2148 | + UCBottomEdgePrivate::get(m_bottomEdge)->validateRegion(this); |
2149 | + } |
2150 | + Q_EMIT toChanged(); |
2151 | +} |
2152 | + |
2153 | +/*! |
2154 | + * \qmlproperty url BottomEdgeRegion::contentUrl |
2155 | + * Specifies the url to the document defining the section specific content. This |
2156 | + * propery will temporarily override the \l BottomEdge::contentUrl property value |
2157 | + * when the drag gesture enters the section area. The orginal value will be restored |
2158 | + * once the gesture leaves the section area. |
2159 | + */ |
2160 | + |
2161 | +/*! |
2162 | + * \qmlproperty Component BottomEdgeRegion::contentComponent |
2163 | + * Specifies the component defining the section specific content. This propery |
2164 | + * will temporarily override the \l BottomEdge::contentComponent property value |
2165 | + * when the drag gesture enters the section area. The orginal value will be restored |
2166 | + * once the gesture leaves the section area. |
2167 | + */ |
2168 | + |
2169 | +/*! |
2170 | + * \qmlsignal void BottomEdgeRegion::entered() |
2171 | + * Signal triggered when the drag enters into the area defined by the bottom edge |
2172 | + * section. |
2173 | + */ |
2174 | + |
2175 | +/*! |
2176 | + * \qmlsignal void BottomEdgeRegion::exited() |
2177 | + * Signal triggered when the drag leaves the area defined by the bottom edge section. |
2178 | + */ |
2179 | + |
2180 | +/*! |
2181 | + * \qmlsignal void BottomEdgeRegion::dragEnded() |
2182 | + * Signal triggered when the drag ends within the active bottom edge section area. |
2183 | + */ |
2184 | |
2185 | === added file 'src/Ubuntu/Components/plugin/ucbottomedgeregion.h' |
2186 | --- src/Ubuntu/Components/plugin/ucbottomedgeregion.h 1970-01-01 00:00:00 +0000 |
2187 | +++ src/Ubuntu/Components/plugin/ucbottomedgeregion.h 2015-11-27 10:36:32 +0000 |
2188 | @@ -0,0 +1,78 @@ |
2189 | +/* |
2190 | + * Copyright 2015 Canonical Ltd. |
2191 | + * |
2192 | + * This program is free software; you can redistribute it and/or modify |
2193 | + * it under the terms of the GNU Lesser General Public License as published by |
2194 | + * the Free Software Foundation; version 3. |
2195 | + * |
2196 | + * This program is distributed in the hope that it will be useful, |
2197 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
2198 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
2199 | + * GNU Lesser General Public License for more details. |
2200 | + * |
2201 | + * You should have received a copy of the GNU Lesser General Public License |
2202 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
2203 | + * |
2204 | + * Author: Zsombor Egri <zsombor.egri@canonical.com> |
2205 | + */ |
2206 | + |
2207 | +#ifndef UCBOTTOMEDGEREGION_H |
2208 | +#define UCBOTTOMEDGEREGION_H |
2209 | + |
2210 | +#include <QtCore/QObject> |
2211 | +#include <QtQml/QQmlParserStatus> |
2212 | +#include <QtCore/QUrl> |
2213 | +#include <QtCore/QPointer> |
2214 | + |
2215 | +class UCBottomEdge; |
2216 | +class QQmlComponent; |
2217 | +class PropertyChange; |
2218 | +class UCBottomEdgeRegion : public QObject |
2219 | +{ |
2220 | + Q_OBJECT |
2221 | + |
2222 | + Q_PROPERTY(bool enabled MEMBER m_enabled WRITE setEnabled NOTIFY enabledChanged FINAL) |
2223 | + Q_PROPERTY(qreal from MEMBER m_from WRITE setFrom NOTIFY fromChanged FINAL) |
2224 | + Q_PROPERTY(qreal to MEMBER m_to WRITE setTo NOTIFY toChanged FINAL) |
2225 | + Q_PROPERTY(QUrl contentUrl MEMBER m_url NOTIFY contentChanged FINAL) |
2226 | + Q_PROPERTY(QQmlComponent* contentComponent MEMBER m_component NOTIFY contentComponentChanged FINAL) |
2227 | +public: |
2228 | + explicit UCBottomEdgeRegion(QObject *parent = 0); |
2229 | + void attachToBottomEdge(UCBottomEdge *bottomEdge); |
2230 | + |
2231 | + // used internally |
2232 | + void setFrom(qreal from); |
2233 | + void setTo(qreal to); |
2234 | + void setEnabled(bool enabled); |
2235 | + bool contains(qreal dragRatio); |
2236 | + void enter(); |
2237 | + void exit(); |
2238 | + const QRectF rect(const QRectF &bottomEdgeRect); |
2239 | + |
2240 | +Q_SIGNALS: |
2241 | + void enabledChanged(); |
2242 | + void fromChanged(); |
2243 | + void toChanged(); |
2244 | + void contentChanged(); |
2245 | + void contentComponentChanged(); |
2246 | + |
2247 | + void entered(); |
2248 | + void exited(); |
2249 | + void dragEnded(); |
2250 | + |
2251 | +protected: |
2252 | + QUrl m_url; |
2253 | + QPointer<UCBottomEdge> m_bottomEdge; |
2254 | + QQmlComponent *m_component; |
2255 | + PropertyChange *m_urlBackup; |
2256 | + PropertyChange *m_componentBackup; |
2257 | + qreal m_from; |
2258 | + qreal m_to; |
2259 | + bool m_enabled:1; |
2260 | + |
2261 | + friend class UCBottomEdge; |
2262 | + friend class UCBottomEdgePrivate; |
2263 | + friend class tst_BottomEdge; |
2264 | +}; |
2265 | + |
2266 | +#endif // UCBOTTOMEDGEREGION_H |
2267 | |
2268 | === added file 'src/Ubuntu/Components/plugin/ucbottomedgestyle.cpp' |
2269 | --- src/Ubuntu/Components/plugin/ucbottomedgestyle.cpp 1970-01-01 00:00:00 +0000 |
2270 | +++ src/Ubuntu/Components/plugin/ucbottomedgestyle.cpp 2015-11-27 10:36:32 +0000 |
2271 | @@ -0,0 +1,65 @@ |
2272 | +/* |
2273 | + * Copyright 2015 Canonical Ltd. |
2274 | + * |
2275 | + * This program is free software; you can redistribute it and/or modify |
2276 | + * it under the terms of the GNU Lesser General Public License as published by |
2277 | + * the Free Software Foundation; version 3. |
2278 | + * |
2279 | + * This program is distributed in the hope that it will be useful, |
2280 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
2281 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
2282 | + * GNU Lesser General Public License for more details. |
2283 | + * |
2284 | + * You should have received a copy of the GNU Lesser General Public License |
2285 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
2286 | + * |
2287 | + * Author: Zsombor Egri <zsombor.egri@canonical.com> |
2288 | + */ |
2289 | + |
2290 | +#include "ucbottomedgestyle.h" |
2291 | +#include "ucbottomedge_p.h" |
2292 | + |
2293 | +/*! |
2294 | + * \qmltype BottomEdgeStyle |
2295 | + * \instantiates UCBottomEdgeStyle |
2296 | + * \inqmlmodule Ubuntu.Components.Styles 1.3 |
2297 | + * \since Ubuntu.Components.Styles 1.3 |
2298 | + * \ingroup style-api |
2299 | + * \brief Style API for BottomEdge content holder panel. |
2300 | + */ |
2301 | + |
2302 | +void UCBottomEdgeStyle::setConsumeMouse(bool consume) |
2303 | +{ |
2304 | + if (consume) { |
2305 | + setAcceptedMouseButtons(Qt::AllButtons); |
2306 | + } else { |
2307 | + setAcceptedMouseButtons(Qt::NoButton); |
2308 | + } |
2309 | +} |
2310 | + |
2311 | +void UCBottomEdgeStyle::mousePressEvent(QMouseEvent *event) |
2312 | +{ |
2313 | + event->accept(); |
2314 | +} |
2315 | + |
2316 | +/*! |
2317 | + * \qmlproperty Item BottomEdgeStyle::panel |
2318 | + * Represents the item holding the bottom edge content. |
2319 | + */ |
2320 | + |
2321 | +/*! |
2322 | + * \qmlproperty Item BottomEdgeStyle::contentItem |
2323 | + * Holds the current content item created from \l BottomEdge::contentUrl or \l BottomEdge::contentComponent. |
2324 | + */ |
2325 | + |
2326 | +/*! |
2327 | + * \qmlproperty Animation BottomEdgeStyle::panelAnimation |
2328 | + * Holds the animation of the panel. BottomEdge requires this property to know |
2329 | + * when the bottom edge is fully committed or collapsed. |
2330 | + */ |
2331 | + |
2332 | +/*! |
2333 | + * \qmlproperty real BottomEdgeStyle::revealThreshold |
2334 | + * Holds the style configured value which drives when the bottom edge content |
2335 | + * should be exposed. |
2336 | + */ |
2337 | |
2338 | === added file 'src/Ubuntu/Components/plugin/ucbottomedgestyle.h' |
2339 | --- src/Ubuntu/Components/plugin/ucbottomedgestyle.h 1970-01-01 00:00:00 +0000 |
2340 | +++ src/Ubuntu/Components/plugin/ucbottomedgestyle.h 2015-11-27 10:36:32 +0000 |
2341 | @@ -0,0 +1,60 @@ |
2342 | +/* |
2343 | + * Copyright 2015 Canonical Ltd. |
2344 | + * |
2345 | + * This program is free software; you can redistribute it and/or modify |
2346 | + * it under the terms of the GNU Lesser General Public License as published by |
2347 | + * the Free Software Foundation; version 3. |
2348 | + * |
2349 | + * This program is distributed in the hope that it will be useful, |
2350 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
2351 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
2352 | + * GNU Lesser General Public License for more details. |
2353 | + * |
2354 | + * You should have received a copy of the GNU Lesser General Public License |
2355 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
2356 | + * |
2357 | + * Author: Zsombor Egri <zsombor.egri@canonical.com> |
2358 | + */ |
2359 | + |
2360 | +#ifndef UCBOTTOMEDGESTYLE_H |
2361 | +#define UCBOTTOMEDGESTYLE_H |
2362 | + |
2363 | +#include <QtQuick/QQuickItem> |
2364 | + |
2365 | +class QQuickItem; |
2366 | +class QQuickAbstractAnimation; |
2367 | +class UCBottomEdge; |
2368 | +class UCBottomEdgeStyle : public QQuickItem |
2369 | +{ |
2370 | + Q_OBJECT |
2371 | + Q_PROPERTY(QQuickItem* panel MEMBER m_panel NOTIFY panelChanged FINAL) |
2372 | + Q_PROPERTY(QQuickItem* contentItem MEMBER m_contentItem NOTIFY contentItemChanged FINAL) |
2373 | + Q_PROPERTY(QQuickAbstractAnimation *panelAnimation MEMBER m_panelAnimation NOTIFY panelAnimationChanged FINAL) |
2374 | + Q_PROPERTY(qreal revealThreshold MEMBER m_revealThreshold NOTIFY revealThresholdChanged FINAL) |
2375 | +public: |
2376 | + explicit UCBottomEdgeStyle(QQuickItem *parent = 0) |
2377 | + : QQuickItem(parent) |
2378 | + {} |
2379 | + |
2380 | + void setConsumeMouse(bool consume); |
2381 | + |
2382 | +Q_SIGNALS: |
2383 | + void panelChanged(); |
2384 | + void contentItemChanged(); |
2385 | + void panelAnimationChanged(); |
2386 | + void revealThresholdChanged(); |
2387 | + |
2388 | +protected: |
2389 | + void mousePressEvent(QMouseEvent *event); |
2390 | + |
2391 | +private: |
2392 | + QQuickItem *m_panel = nullptr; |
2393 | + QQuickItem *m_contentItem = nullptr; |
2394 | + QQuickAbstractAnimation *m_panelAnimation = nullptr; |
2395 | + qreal m_revealThreshold = 0.; |
2396 | + |
2397 | + friend class UCBottomEdge; |
2398 | + friend class UCBottomEdgePrivate; |
2399 | +}; |
2400 | + |
2401 | +#endif // UCBOTTOMEDGESTYLE_H |
2402 | |
2403 | === modified file 'src/Ubuntu/Components/plugin/ucstyleditembase.cpp' |
2404 | --- src/Ubuntu/Components/plugin/ucstyleditembase.cpp 2015-10-20 11:32:09 +0000 |
2405 | +++ src/Ubuntu/Components/plugin/ucstyleditembase.cpp 2015-11-27 10:36:32 +0000 |
2406 | @@ -26,7 +26,8 @@ |
2407 | #include <QtQuick/private/qquickanchors_p.h> |
2408 | |
2409 | UCStyledItemBasePrivate::UCStyledItemBasePrivate() |
2410 | - : styleComponent(Q_NULLPTR) |
2411 | + : oldParentItem(Q_NULLPTR) |
2412 | + , styleComponent(Q_NULLPTR) |
2413 | , styleItem(Q_NULLPTR) |
2414 | , styleVersion(0) |
2415 | , activeFocusOnPress(false) |
2416 | @@ -469,6 +470,15 @@ |
2417 | } |
2418 | } |
2419 | |
2420 | +void UCStyledItemBasePrivate::completeStyledItem() |
2421 | +{ |
2422 | + Q_Q(UCStyledItemBase); |
2423 | + // no animation at this time |
2424 | + // prepare style context if not been done yet |
2425 | + postStyleChanged(); |
2426 | + loadStyleItem(false); |
2427 | +} |
2428 | + |
2429 | void UCStyledItemBase::componentComplete() |
2430 | { |
2431 | QQuickItem::componentComplete(); |
2432 | @@ -476,10 +486,16 @@ |
2433 | // make sure the theme version is up to date |
2434 | d->styleVersion = d->importVersion(this); |
2435 | UCTheme::checkMixedVersionImports(this, d->styleVersion); |
2436 | - // no animation at this time |
2437 | - // prepare style context if not been done yet |
2438 | - d->postStyleChanged(); |
2439 | - d->loadStyleItem(false); |
2440 | + d->completeStyledItem(); |
2441 | +} |
2442 | + |
2443 | +void UCStyledItemBase::itemChange(ItemChange change, const ItemChangeData &data) |
2444 | +{ |
2445 | + QQuickItem::itemChange(change, data); |
2446 | + if (change == ItemParentHasChanged) { |
2447 | + // update parentItem |
2448 | + d_func()->oldParentItem = data.item; |
2449 | + } |
2450 | } |
2451 | |
2452 | // grab pressed state and focus if it can be |
2453 | |
2454 | === modified file 'src/Ubuntu/Components/plugin/ucstyleditembase.h' |
2455 | --- src/Ubuntu/Components/plugin/ucstyleditembase.h 2015-10-20 10:19:10 +0000 |
2456 | +++ src/Ubuntu/Components/plugin/ucstyleditembase.h 2015-11-27 10:36:32 +0000 |
2457 | @@ -60,6 +60,7 @@ |
2458 | virtual void postThemeChanged(); |
2459 | |
2460 | void componentComplete(); |
2461 | + void itemChange(ItemChange change, const ItemChangeData &data); |
2462 | void mousePressEvent(QMouseEvent *event); |
2463 | bool childMouseEventFilter(QQuickItem *child, QEvent *event); |
2464 | |
2465 | |
2466 | === modified file 'src/Ubuntu/Components/plugin/ucstyleditembase_p.h' |
2467 | --- src/Ubuntu/Components/plugin/ucstyleditembase_p.h 2015-10-20 11:05:53 +0000 |
2468 | +++ src/Ubuntu/Components/plugin/ucstyleditembase_p.h 2015-11-27 10:36:32 +0000 |
2469 | @@ -56,6 +56,7 @@ |
2470 | virtual void preStyleChanged(); |
2471 | virtual void postStyleChanged() {} |
2472 | virtual bool loadStyleItem(bool animated = true); |
2473 | + virtual void completeStyledItem(); |
2474 | |
2475 | // from UCImportVersionChecker |
2476 | virtual QString propertyForVersion(quint16 version) const; |
2477 | @@ -64,6 +65,7 @@ |
2478 | |
2479 | QPointer<QQmlContext> styleItemContext; |
2480 | QString styleDocument; |
2481 | + QQuickItem *oldParentItem; |
2482 | QQmlComponent *styleComponent; |
2483 | QQuickItem *styleItem; |
2484 | quint16 styleVersion; |
2485 | |
2486 | === modified file 'src/Ubuntu/Test/plugin/uctestextras.cpp' |
2487 | --- src/Ubuntu/Test/plugin/uctestextras.cpp 2015-11-04 10:56:03 +0000 |
2488 | +++ src/Ubuntu/Test/plugin/uctestextras.cpp 2015-11-27 10:36:32 +0000 |
2489 | @@ -227,18 +227,151 @@ |
2490 | steps = 5; |
2491 | } |
2492 | touchPress(touchId, item, from); |
2493 | - QTest::qWait(10); |
2494 | + QTest::qWait(20); |
2495 | touchMove(touchId, item, from); |
2496 | QPoint movePoint(from); |
2497 | qreal stepDx = delta.x() / steps; |
2498 | qreal stepDy = delta.y() / steps; |
2499 | if (!delta.isNull()) { |
2500 | for (int i = 0; i < steps - 1; i++) { |
2501 | - QTest::qWait(10); |
2502 | + QTest::qWait(20); |
2503 | movePoint += QPoint(stepDx, stepDy); |
2504 | touchMove(touchId, item, movePoint); |
2505 | } |
2506 | } |
2507 | - QTest::qWait(10); |
2508 | + QTest::qWait(20); |
2509 | touchRelease(touchId, item, from + delta); |
2510 | } |
2511 | + |
2512 | +/*! |
2513 | + * \qmlmethod void TestExtras::mouseDrag(touchId, item, from, delta, button, stateKey, steps = 5, delay = 20) |
2514 | + * The function performs a drag with a mouse over an \a item from the starting |
2515 | + * point \a from with a \a delta. The gesture is realized with a mouse press, |
2516 | + * \a step moves and a release event, with a \e delay in between each mouse event. |
2517 | + * |
2518 | + * By default the function uses 5 steps to produce the drag. This value can be any |
2519 | + * positive number, driving the gesture appliance to be faster (less than 5 moves) or |
2520 | + * slower (more than 5 moves). If a negative or 0 value is given, the function will |
2521 | + * use the default 5 steps to produce the gesture. |
2522 | + */ |
2523 | + |
2524 | +void UCTestExtras::mouseDrag(QQuickItem *item, const QPoint &from, const QPoint &delta, Qt::MouseButton button, Qt::KeyboardModifiers stateKey, int steps, int delay) |
2525 | +{ |
2526 | + if (delta.isNull()) { |
2527 | + qWarning() << "delta point is invalid"; |
2528 | + return; |
2529 | + } |
2530 | + if (steps <= 0) { |
2531 | + steps = 5; |
2532 | + } |
2533 | + if (delay < 20) { |
2534 | + delay = 20; |
2535 | + } |
2536 | + QTest::mousePress(item->window(), button, stateKey, from, delay); |
2537 | + QPoint movePoint(from); |
2538 | + qreal stepDx = delta.x() / steps; |
2539 | + qreal stepDy = delta.y() / steps; |
2540 | + if (!delta.isNull()) { |
2541 | + for (int i = 0; i < steps; i++) { |
2542 | + QTest::mouseMove(item->window(), movePoint, delay); |
2543 | + movePoint += QPoint(stepDx, stepDy); |
2544 | + } |
2545 | + } |
2546 | + QTest::mouseRelease(item->window(), button, stateKey, movePoint, delay); |
2547 | +} |
2548 | + |
2549 | +/* |
2550 | + * void TestExtras::touchDragWithPoints(touchId, item, list<point> ponts, delay = 20) |
2551 | + * Similar to \l touchDrag function, but here the points must be specified in \e points property. |
2552 | + * The first point is expected to be the starting position, after which each point is a relative |
2553 | + * point defining the move. A minimum of 5 points are needed to properly produce a drag. |
2554 | + * \qml |
2555 | + * import Qt.Test 1.0 |
2556 | + * import Ubuntu.Test 1.0 |
2557 | + * Item { |
2558 | + * id: testItem |
2559 | + * UbuntuTestCase { |
2560 | + * |
2561 | + * function test_vertical_drag_upwards() { |
2562 | + * var points = []; |
2563 | + * points.push(centerOf(testItem)); |
2564 | + * points.push(Qt.point(0, -1)); |
2565 | + * points.push(Qt.point(0, -3)); |
2566 | + * points.push(Qt.point(0, -6)); |
2567 | + * points.push(Qt.point(0, -5)); |
2568 | + * points.push(Qt.point(0, -2)); |
2569 | + * TestExtras.touchDragWithPoints(0, testItem, points); |
2570 | + * } |
2571 | + * } |
2572 | + * } |
2573 | + * \endqml |
2574 | + * The delay must be a minimum of 20 milliseconds. |
2575 | + */ |
2576 | +void UCTestExtras::touchDragWithPoints(int touchId, QQuickItem *item, QList<QPoint> points, int delay) |
2577 | +{ |
2578 | + if (points.size() < 5) { |
2579 | + qWarning() << "minimum 5 points are needed."; |
2580 | + return; |
2581 | + } |
2582 | + if (delay < 20) { |
2583 | + delay = 20; |
2584 | + } |
2585 | + |
2586 | + QPoint movePoint(points[0]); |
2587 | + touchPress(touchId, item, movePoint); |
2588 | + QTest::qWait(delay); |
2589 | + touchMove(touchId, item, movePoint); |
2590 | + for (int i = 1; i < points.size(); ++i) { |
2591 | + QTest::qWait(delay); |
2592 | + movePoint += points[i]; |
2593 | + touchMove(touchId, item, movePoint); |
2594 | + } |
2595 | + QTest::qWait(delay); |
2596 | + touchRelease(touchId, item, movePoint); |
2597 | +} |
2598 | + |
2599 | +/* |
2600 | + * void TestExtras::mouseDragWithPoints(item, button, list<point> ponts, stateKey = 0, delay = 20) |
2601 | + * Similar to \l mouseDrag function, but here the points must be specified in \e points property. |
2602 | + * The first point is expected to be the starting position, after which each point is a relative |
2603 | + * point defining the move. A minimum of 5 points are needed to properly produce a drag. |
2604 | + * \qml |
2605 | + * import Qt.Test 1.0 |
2606 | + * import Ubuntu.Test 1.0 |
2607 | + * Item { |
2608 | + * id: testItem |
2609 | + * UbuntuTestCase { |
2610 | + * |
2611 | + * function test_vertical_drag_upwards() { |
2612 | + * var points = []; |
2613 | + * points.push(centerOf(testItem)); |
2614 | + * points.push(Qt.point(0, -1)); |
2615 | + * points.push(Qt.point(0, -3)); |
2616 | + * points.push(Qt.point(0, -6)); |
2617 | + * points.push(Qt.point(0, -5)); |
2618 | + * points.push(Qt.point(0, -2)); |
2619 | + * TestExtras.mouseDragWithPoints(testItem, Qt.LeftButton, points); |
2620 | + * } |
2621 | + * } |
2622 | + * } |
2623 | + * \endqml |
2624 | + * The delay must be a minimum of 20 milliseconds. |
2625 | + */ |
2626 | +void UCTestExtras::mouseDragWithPoints(QQuickItem *item, QList<QPoint> points, Qt::MouseButton button, Qt::KeyboardModifiers stateKey, int delay) |
2627 | +{ |
2628 | + if (points.size() < 5) { |
2629 | + qWarning() << "minimum 5 points are needed."; |
2630 | + return; |
2631 | + } |
2632 | + if (delay < 20) { |
2633 | + delay = 20; |
2634 | + } |
2635 | + QTest::mousePress(item->window(), button, stateKey, item->mapToScene(points[0]).toPoint(), delay); |
2636 | + QPoint movePoint(item->mapToScene(points[0]).toPoint()); |
2637 | + QTest::mouseMove(item->window(), movePoint, delay); |
2638 | + for (int i = 1; i < points.size(); ++i) { |
2639 | + movePoint += points[i]; |
2640 | + QTest::mouseMove(item->window(), movePoint, delay); |
2641 | + } |
2642 | + QTest::mouseRelease(item->window(), button, stateKey, movePoint, delay); |
2643 | +} |
2644 | |
2645 | === modified file 'src/Ubuntu/Test/plugin/uctestextras.h' |
2646 | --- src/Ubuntu/Test/plugin/uctestextras.h 2015-11-10 14:42:20 +0000 |
2647 | +++ src/Ubuntu/Test/plugin/uctestextras.h 2015-11-27 10:36:32 +0000 |
2648 | @@ -44,6 +44,12 @@ |
2649 | static void touchMove(int touchId, QQuickItem *item, const QPoint &point); |
2650 | static void touchDrag(int touchId, QQuickItem *item, const QPoint &from, const QPoint &delta, int steps = 5); |
2651 | |
2652 | + static void mouseDrag(QQuickItem *item, const QPoint &from, const QPoint &delta, Qt::MouseButton button, Qt::KeyboardModifiers stateKey = 0, int steps = -1, int delay = -1); |
2653 | + |
2654 | +public: // yet for cpp use |
2655 | + static void touchDragWithPoints(int touchId, QQuickItem *item, QList<QPoint> points, int delay = -1); |
2656 | + static void mouseDragWithPoints(QQuickItem *item, QList<QPoint> points, Qt::MouseButton button, Qt::KeyboardModifiers stateKey = 0, int delay = -1); |
2657 | + |
2658 | private: |
2659 | static QTouchDevice *m_touchDevice; |
2660 | static UCTestExtras *m_testExtras; |
2661 | |
2662 | === added directory 'tests/unit_x11/tst_bottomedge' |
2663 | === added file 'tests/unit_x11/tst_bottomedge/AddCustomRegionOnCompleted.qml' |
2664 | --- tests/unit_x11/tst_bottomedge/AddCustomRegionOnCompleted.qml 1970-01-01 00:00:00 +0000 |
2665 | +++ tests/unit_x11/tst_bottomedge/AddCustomRegionOnCompleted.qml 2015-11-27 10:36:32 +0000 |
2666 | @@ -0,0 +1,41 @@ |
2667 | +/* |
2668 | + * Copyright 2015 Canonical Ltd. |
2669 | + * |
2670 | + * This program is free software; you can redistribute it and/or modify |
2671 | + * it under the terms of the GNU Lesser General Public License as published by |
2672 | + * the Free Software Foundation; version 3. |
2673 | + * |
2674 | + * This program is distributed in the hope that it will be useful, |
2675 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
2676 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
2677 | + * GNU Lesser General Public License for more details. |
2678 | + * |
2679 | + * You should have received a copy of the GNU Lesser General Public License |
2680 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
2681 | + * |
2682 | + */ |
2683 | + |
2684 | +import QtQuick 2.4 |
2685 | +import Ubuntu.Components 1.3 |
2686 | + |
2687 | +Item { |
2688 | + id: holder |
2689 | + width: units.gu(40) |
2690 | + height: units.gu(71) |
2691 | + |
2692 | + BottomEdge { |
2693 | + hint.text: "Test" |
2694 | + objectName: "testItem" |
2695 | + |
2696 | + Component.onCompleted: { |
2697 | + var v = []; |
2698 | + v.push(customRegion); |
2699 | + regions = v; |
2700 | + } |
2701 | + } |
2702 | + BottomEdgeRegion { |
2703 | + id: customRegion |
2704 | + objectName: "customRegion" |
2705 | + } |
2706 | +} |
2707 | + |
2708 | |
2709 | === added file 'tests/unit_x11/tst_bottomedge/AddCustomRegionOwnedByOtherBottomEdge.qml' |
2710 | --- tests/unit_x11/tst_bottomedge/AddCustomRegionOwnedByOtherBottomEdge.qml 1970-01-01 00:00:00 +0000 |
2711 | +++ tests/unit_x11/tst_bottomedge/AddCustomRegionOwnedByOtherBottomEdge.qml 2015-11-27 10:36:32 +0000 |
2712 | @@ -0,0 +1,39 @@ |
2713 | +/* |
2714 | + * Copyright 2015 Canonical Ltd. |
2715 | + * |
2716 | + * This program is free software; you can redistribute it and/or modify |
2717 | + * it under the terms of the GNU Lesser General Public License as published by |
2718 | + * the Free Software Foundation; version 3. |
2719 | + * |
2720 | + * This program is distributed in the hope that it will be useful, |
2721 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
2722 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
2723 | + * GNU Lesser General Public License for more details. |
2724 | + * |
2725 | + * You should have received a copy of the GNU Lesser General Public License |
2726 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
2727 | + * |
2728 | + */ |
2729 | + |
2730 | +import QtQuick 2.4 |
2731 | +import Ubuntu.Components 1.3 |
2732 | + |
2733 | +Item { |
2734 | + id: holder |
2735 | + width: units.gu(40) |
2736 | + height: units.gu(71) |
2737 | + |
2738 | + BottomEdge { |
2739 | + hint.text: "Test" |
2740 | + objectName: "testItem" |
2741 | + regions: [customRegion] |
2742 | + } |
2743 | + BottomEdge { |
2744 | + hint.text: "Other" |
2745 | + BottomEdgeRegion { |
2746 | + id: customRegion |
2747 | + objectName: "customRegion" |
2748 | + } |
2749 | + } |
2750 | +} |
2751 | + |
2752 | |
2753 | === added file 'tests/unit_x11/tst_bottomedge/AddCustomRegionUsingDataProperty.qml' |
2754 | --- tests/unit_x11/tst_bottomedge/AddCustomRegionUsingDataProperty.qml 1970-01-01 00:00:00 +0000 |
2755 | +++ tests/unit_x11/tst_bottomedge/AddCustomRegionUsingDataProperty.qml 2015-11-27 10:36:32 +0000 |
2756 | @@ -0,0 +1,33 @@ |
2757 | +/* |
2758 | + * Copyright 2015 Canonical Ltd. |
2759 | + * |
2760 | + * This program is free software; you can redistribute it and/or modify |
2761 | + * it under the terms of the GNU Lesser General Public License as published by |
2762 | + * the Free Software Foundation; version 3. |
2763 | + * |
2764 | + * This program is distributed in the hope that it will be useful, |
2765 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
2766 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
2767 | + * GNU Lesser General Public License for more details. |
2768 | + * |
2769 | + * You should have received a copy of the GNU Lesser General Public License |
2770 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
2771 | + * |
2772 | + */ |
2773 | + |
2774 | +import QtQuick 2.4 |
2775 | +import Ubuntu.Components 1.3 |
2776 | + |
2777 | +Item { |
2778 | + id: holder |
2779 | + width: units.gu(40) |
2780 | + height: units.gu(71) |
2781 | + |
2782 | + BottomEdge { |
2783 | + hint.text: "Test" |
2784 | + objectName: "testItem" |
2785 | + |
2786 | + BottomEdgeRegion { objectName: "customRegion" } |
2787 | + } |
2788 | +} |
2789 | + |
2790 | |
2791 | === added file 'tests/unit_x11/tst_bottomedge/AddCustomRegionUsingRegionsProperty.qml' |
2792 | --- tests/unit_x11/tst_bottomedge/AddCustomRegionUsingRegionsProperty.qml 1970-01-01 00:00:00 +0000 |
2793 | +++ tests/unit_x11/tst_bottomedge/AddCustomRegionUsingRegionsProperty.qml 2015-11-27 10:36:32 +0000 |
2794 | @@ -0,0 +1,33 @@ |
2795 | +/* |
2796 | + * Copyright 2015 Canonical Ltd. |
2797 | + * |
2798 | + * This program is free software; you can redistribute it and/or modify |
2799 | + * it under the terms of the GNU Lesser General Public License as published by |
2800 | + * the Free Software Foundation; version 3. |
2801 | + * |
2802 | + * This program is distributed in the hope that it will be useful, |
2803 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
2804 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
2805 | + * GNU Lesser General Public License for more details. |
2806 | + * |
2807 | + * You should have received a copy of the GNU Lesser General Public License |
2808 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
2809 | + * |
2810 | + */ |
2811 | + |
2812 | +import QtQuick 2.4 |
2813 | +import Ubuntu.Components 1.3 |
2814 | + |
2815 | +Item { |
2816 | + id: holder |
2817 | + width: units.gu(40) |
2818 | + height: units.gu(71) |
2819 | + |
2820 | + BottomEdge { |
2821 | + hint.text: "Test" |
2822 | + objectName: "testItem" |
2823 | + |
2824 | + regions: BottomEdgeRegion { objectName: "customRegion" } |
2825 | + } |
2826 | +} |
2827 | + |
2828 | |
2829 | === added file 'tests/unit_x11/tst_bottomedge/AlternateDefaultRegionContent.qml' |
2830 | --- tests/unit_x11/tst_bottomedge/AlternateDefaultRegionContent.qml 1970-01-01 00:00:00 +0000 |
2831 | +++ tests/unit_x11/tst_bottomedge/AlternateDefaultRegionContent.qml 2015-11-27 10:36:32 +0000 |
2832 | @@ -0,0 +1,53 @@ |
2833 | +/* |
2834 | + * Copyright 2015 Canonical Ltd. |
2835 | + * |
2836 | + * This program is free software; you can redistribute it and/or modify |
2837 | + * it under the terms of the GNU Lesser General Public License as published by |
2838 | + * the Free Software Foundation; version 3. |
2839 | + * |
2840 | + * This program is distributed in the hope that it will be useful, |
2841 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
2842 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
2843 | + * GNU Lesser General Public License for more details. |
2844 | + * |
2845 | + * You should have received a copy of the GNU Lesser General Public License |
2846 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
2847 | + * |
2848 | + */ |
2849 | + |
2850 | +import QtQuick 2.4 |
2851 | +import Ubuntu.Components 1.3 |
2852 | + |
2853 | +Item { |
2854 | + id: holder |
2855 | + width: units.gu(40) |
2856 | + height: units.gu(71) |
2857 | + |
2858 | + BottomEdge { |
2859 | + id: bottomEdge |
2860 | + hint.text: "Test" |
2861 | + objectName: "testItem" |
2862 | + contentComponent: Rectangle { |
2863 | + objectName: "defaultContent" |
2864 | + width: holder.width |
2865 | + height: holder.height |
2866 | + color: UbuntuColors.green |
2867 | + } |
2868 | + |
2869 | + Component { |
2870 | + id: altContent |
2871 | + Rectangle { |
2872 | + objectName: "regionContent" |
2873 | + width: holder.width - units.gu(20) |
2874 | + height: holder.height |
2875 | + color: UbuntuColors.red |
2876 | + } |
2877 | + } |
2878 | + } |
2879 | + |
2880 | + Component.onCompleted: { |
2881 | + var defaultRegion = bottomEdge.regions[0]; |
2882 | + defaultRegion.contentComponent = altContent; |
2883 | + } |
2884 | +} |
2885 | + |
2886 | |
2887 | === added file 'tests/unit_x11/tst_bottomedge/AlternateRegionContent.qml' |
2888 | --- tests/unit_x11/tst_bottomedge/AlternateRegionContent.qml 1970-01-01 00:00:00 +0000 |
2889 | +++ tests/unit_x11/tst_bottomedge/AlternateRegionContent.qml 2015-11-27 10:36:32 +0000 |
2890 | @@ -0,0 +1,47 @@ |
2891 | +/* |
2892 | + * Copyright 2015 Canonical Ltd. |
2893 | + * |
2894 | + * This program is free software; you can redistribute it and/or modify |
2895 | + * it under the terms of the GNU Lesser General Public License as published by |
2896 | + * the Free Software Foundation; version 3. |
2897 | + * |
2898 | + * This program is distributed in the hope that it will be useful, |
2899 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
2900 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
2901 | + * GNU Lesser General Public License for more details. |
2902 | + * |
2903 | + * You should have received a copy of the GNU Lesser General Public License |
2904 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
2905 | + * |
2906 | + */ |
2907 | + |
2908 | +import QtQuick 2.4 |
2909 | +import Ubuntu.Components 1.3 |
2910 | + |
2911 | +Item { |
2912 | + id: holder |
2913 | + width: units.gu(40) |
2914 | + height: units.gu(71) |
2915 | + |
2916 | + BottomEdge { |
2917 | + hint.text: "Test" |
2918 | + objectName: "testItem" |
2919 | + contentComponent: Rectangle { |
2920 | + objectName: "defaultContent" |
2921 | + width: holder.width |
2922 | + height: holder.height |
2923 | + color: UbuntuColors.green |
2924 | + } |
2925 | + |
2926 | + regions: BottomEdgeRegion { |
2927 | + from: 0.2 |
2928 | + contentComponent: Rectangle { |
2929 | + objectName: "regionContent" |
2930 | + width: holder.width - units.gu(20) |
2931 | + height: holder.height |
2932 | + color: UbuntuColors.red |
2933 | + } |
2934 | + } |
2935 | + } |
2936 | +} |
2937 | + |
2938 | |
2939 | === added file 'tests/unit_x11/tst_bottomedge/AutoCollapseInPageHeader.qml' |
2940 | --- tests/unit_x11/tst_bottomedge/AutoCollapseInPageHeader.qml 1970-01-01 00:00:00 +0000 |
2941 | +++ tests/unit_x11/tst_bottomedge/AutoCollapseInPageHeader.qml 2015-11-27 10:36:32 +0000 |
2942 | @@ -0,0 +1,45 @@ |
2943 | +/* |
2944 | + * Copyright 2015 Canonical Ltd. |
2945 | + * |
2946 | + * This program is free software; you can redistribute it and/or modify |
2947 | + * it under the terms of the GNU Lesser General Public License as published by |
2948 | + * the Free Software Foundation; version 3. |
2949 | + * |
2950 | + * This program is distributed in the hope that it will be useful, |
2951 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
2952 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
2953 | + * GNU Lesser General Public License for more details. |
2954 | + * |
2955 | + * You should have received a copy of the GNU Lesser General Public License |
2956 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
2957 | + * |
2958 | + */ |
2959 | + |
2960 | +import QtQuick 2.4 |
2961 | +import Ubuntu.Components 1.3 |
2962 | + |
2963 | +MainView { |
2964 | + width: units.gu(40) |
2965 | + height: units.gu(71) |
2966 | + |
2967 | + Page { |
2968 | + title: "Main page" |
2969 | + |
2970 | + BottomEdge { |
2971 | + id: bottomEdge |
2972 | + objectName: "testItem" |
2973 | + hint.text: "Bottom edge" |
2974 | + |
2975 | + contentComponent: Rectangle { |
2976 | + width: bottomEdge.width |
2977 | + height: bottomEdge.height |
2978 | + color: UbuntuColors.green |
2979 | + PageHeader { |
2980 | + title: "Bottom edge content" |
2981 | + objectName: "bottomEdgeHeader" |
2982 | + } |
2983 | + } |
2984 | + } |
2985 | + } |
2986 | +} |
2987 | + |
2988 | |
2989 | === added file 'tests/unit_x11/tst_bottomedge/AutoCollapseInPageWithPageHeader.qml' |
2990 | --- tests/unit_x11/tst_bottomedge/AutoCollapseInPageWithPageHeader.qml 1970-01-01 00:00:00 +0000 |
2991 | +++ tests/unit_x11/tst_bottomedge/AutoCollapseInPageWithPageHeader.qml 2015-11-27 10:36:32 +0000 |
2992 | @@ -0,0 +1,44 @@ |
2993 | +/* |
2994 | + * Copyright 2015 Canonical Ltd. |
2995 | + * |
2996 | + * This program is free software; you can redistribute it and/or modify |
2997 | + * it under the terms of the GNU Lesser General Public License as published by |
2998 | + * the Free Software Foundation; version 3. |
2999 | + * |
3000 | + * This program is distributed in the hope that it will be useful, |
3001 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
3002 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
3003 | + * GNU Lesser General Public License for more details. |
3004 | + * |
3005 | + * You should have received a copy of the GNU Lesser General Public License |
3006 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
3007 | + * |
3008 | + */ |
3009 | + |
3010 | +import QtQuick 2.4 |
3011 | +import Ubuntu.Components 1.3 |
3012 | + |
3013 | +MainView { |
3014 | + width: units.gu(40) |
3015 | + height: units.gu(71) |
3016 | + |
3017 | + Page { |
3018 | + title: "Main page" |
3019 | + |
3020 | + BottomEdge { |
3021 | + id: bottomEdge |
3022 | + objectName: "testItem" |
3023 | + hint.text: "Bottom edge" |
3024 | + |
3025 | + contentComponent: Page { |
3026 | + width: bottomEdge.width |
3027 | + height: bottomEdge.height |
3028 | + header: PageHeader { |
3029 | + title: "Bottom edge content" |
3030 | + objectName: "bottomEdgeHeader" |
3031 | + } |
3032 | + } |
3033 | + } |
3034 | + } |
3035 | +} |
3036 | + |
3037 | |
3038 | === added file 'tests/unit_x11/tst_bottomedge/BottomEdgeInItem.qml' |
3039 | --- tests/unit_x11/tst_bottomedge/BottomEdgeInItem.qml 1970-01-01 00:00:00 +0000 |
3040 | +++ tests/unit_x11/tst_bottomedge/BottomEdgeInItem.qml 2015-11-27 10:36:32 +0000 |
3041 | @@ -0,0 +1,36 @@ |
3042 | +/* |
3043 | + * Copyright 2015 Canonical Ltd. |
3044 | + * |
3045 | + * This program is free software; you can redistribute it and/or modify |
3046 | + * it under the terms of the GNU Lesser General Public License as published by |
3047 | + * the Free Software Foundation; version 3. |
3048 | + * |
3049 | + * This program is distributed in the hope that it will be useful, |
3050 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
3051 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
3052 | + * GNU Lesser General Public License for more details. |
3053 | + * |
3054 | + * You should have received a copy of the GNU Lesser General Public License |
3055 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
3056 | + * |
3057 | + */ |
3058 | + |
3059 | +import QtQuick 2.4 |
3060 | +import Ubuntu.Components 1.3 |
3061 | + |
3062 | +Item { |
3063 | + id: holder |
3064 | + width: units.gu(40) |
3065 | + height: units.gu(71) |
3066 | + |
3067 | + BottomEdge { |
3068 | + hint.text: "Test" |
3069 | + objectName: "testItem" |
3070 | + contentComponent: Rectangle { |
3071 | + width: holder.width |
3072 | + height: holder.height |
3073 | + color: UbuntuColors.green |
3074 | + } |
3075 | + } |
3076 | +} |
3077 | + |
3078 | |
3079 | === added file 'tests/unit_x11/tst_bottomedge/ClearCustomRegions.qml' |
3080 | --- tests/unit_x11/tst_bottomedge/ClearCustomRegions.qml 1970-01-01 00:00:00 +0000 |
3081 | +++ tests/unit_x11/tst_bottomedge/ClearCustomRegions.qml 2015-11-27 10:36:32 +0000 |
3082 | @@ -0,0 +1,42 @@ |
3083 | +/* |
3084 | + * Copyright 2015 Canonical Ltd. |
3085 | + * |
3086 | + * This program is free software; you can redistribute it and/or modify |
3087 | + * it under the terms of the GNU Lesser General Public License as published by |
3088 | + * the Free Software Foundation; version 3. |
3089 | + * |
3090 | + * This program is distributed in the hope that it will be useful, |
3091 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
3092 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
3093 | + * GNU Lesser General Public License for more details. |
3094 | + * |
3095 | + * You should have received a copy of the GNU Lesser General Public License |
3096 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
3097 | + * |
3098 | + */ |
3099 | + |
3100 | +import QtQuick 2.4 |
3101 | +import Ubuntu.Components 1.3 |
3102 | + |
3103 | +Item { |
3104 | + id: holder |
3105 | + width: units.gu(40) |
3106 | + height: units.gu(71) |
3107 | + |
3108 | + BottomEdge { |
3109 | + hint.text: "Test" |
3110 | + objectName: "testItem" |
3111 | + |
3112 | + BottomEdgeRegion { |
3113 | + to: 0.5 |
3114 | + } |
3115 | + BottomEdgeRegion { |
3116 | + from: 0.5 |
3117 | + } |
3118 | + |
3119 | + Component.onCompleted: { |
3120 | + regions = []; |
3121 | + } |
3122 | + } |
3123 | +} |
3124 | + |
3125 | |
3126 | === added file 'tests/unit_x11/tst_bottomedge/Defaults.qml' |
3127 | --- tests/unit_x11/tst_bottomedge/Defaults.qml 1970-01-01 00:00:00 +0000 |
3128 | +++ tests/unit_x11/tst_bottomedge/Defaults.qml 2015-11-27 10:36:32 +0000 |
3129 | @@ -0,0 +1,28 @@ |
3130 | +/* |
3131 | + * Copyright 2015 Canonical Ltd. |
3132 | + * |
3133 | + * This program is free software; you can redistribute it and/or modify |
3134 | + * it under the terms of the GNU Lesser General Public License as published by |
3135 | + * the Free Software Foundation; version 3. |
3136 | + * |
3137 | + * This program is distributed in the hope that it will be useful, |
3138 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
3139 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
3140 | + * GNU Lesser General Public License for more details. |
3141 | + * |
3142 | + * You should have received a copy of the GNU Lesser General Public License |
3143 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
3144 | + * |
3145 | + */ |
3146 | + |
3147 | +import QtQuick 2.4 |
3148 | +import Ubuntu.Components 1.3 |
3149 | + |
3150 | +Item { |
3151 | + width: 100 |
3152 | + height: 100 |
3153 | + BottomEdge { |
3154 | + objectName: "testItem" |
3155 | + } |
3156 | +} |
3157 | + |
3158 | |
3159 | === added file 'tests/unit_x11/tst_bottomedge/DifferentSizes.qml' |
3160 | --- tests/unit_x11/tst_bottomedge/DifferentSizes.qml 1970-01-01 00:00:00 +0000 |
3161 | +++ tests/unit_x11/tst_bottomedge/DifferentSizes.qml 2015-11-27 10:36:32 +0000 |
3162 | @@ -0,0 +1,34 @@ |
3163 | +/* |
3164 | + * Copyright 2015 Canonical Ltd. |
3165 | + * |
3166 | + * This program is free software; you can redistribute it and/or modify |
3167 | + * it under the terms of the GNU Lesser General Public License as published by |
3168 | + * the Free Software Foundation; version 3. |
3169 | + * |
3170 | + * This program is distributed in the hope that it will be useful, |
3171 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
3172 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
3173 | + * GNU Lesser General Public License for more details. |
3174 | + * |
3175 | + * You should have received a copy of the GNU Lesser General Public License |
3176 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
3177 | + * |
3178 | + */ |
3179 | + |
3180 | +import QtQuick 2.4 |
3181 | +import Ubuntu.Components 1.3 |
3182 | + |
3183 | +Item { |
3184 | + width: 100 |
3185 | + height: 100 |
3186 | + |
3187 | + Item { |
3188 | + objectName: "oldParent" |
3189 | + width: 100 |
3190 | + height: 50 |
3191 | + BottomEdge { |
3192 | + objectName: "testItem" |
3193 | + } |
3194 | + } |
3195 | +} |
3196 | + |
3197 | |
3198 | === added file 'tests/unit_x11/tst_bottomedge/LastItem.qml' |
3199 | --- tests/unit_x11/tst_bottomedge/LastItem.qml 1970-01-01 00:00:00 +0000 |
3200 | +++ tests/unit_x11/tst_bottomedge/LastItem.qml 2015-11-27 10:36:32 +0000 |
3201 | @@ -0,0 +1,46 @@ |
3202 | +/* |
3203 | + * Copyright 2015 Canonical Ltd. |
3204 | + * |
3205 | + * This program is free software; you can redistribute it and/or modify |
3206 | + * it under the terms of the GNU Lesser General Public License as published by |
3207 | + * the Free Software Foundation; version 3. |
3208 | + * |
3209 | + * This program is distributed in the hope that it will be useful, |
3210 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
3211 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
3212 | + * GNU Lesser General Public License for more details. |
3213 | + * |
3214 | + * You should have received a copy of the GNU Lesser General Public License |
3215 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
3216 | + * |
3217 | + */ |
3218 | + |
3219 | +import QtQuick 2.4 |
3220 | +import Ubuntu.Components 1.3 |
3221 | + |
3222 | +Item { |
3223 | + width: 100 |
3224 | + height: 100 |
3225 | + |
3226 | + Item { |
3227 | + id: holder |
3228 | + width: 100 |
3229 | + height: 50 |
3230 | + BottomEdge { |
3231 | + objectName: "testItem" |
3232 | + contentComponent: Item { |
3233 | + width: holder.width |
3234 | + height: holder.height |
3235 | + } |
3236 | + } |
3237 | + |
3238 | + Item { |
3239 | + anchors.fill: parent |
3240 | + } |
3241 | + } |
3242 | + Item { |
3243 | + objectName: "dynamicItem" |
3244 | + anchors.fill: parent |
3245 | + } |
3246 | +} |
3247 | + |
3248 | |
3249 | === added file 'tests/unit_x11/tst_bottomedge/LeanActiveRegionChange.qml' |
3250 | --- tests/unit_x11/tst_bottomedge/LeanActiveRegionChange.qml 1970-01-01 00:00:00 +0000 |
3251 | +++ tests/unit_x11/tst_bottomedge/LeanActiveRegionChange.qml 2015-11-27 10:36:32 +0000 |
3252 | @@ -0,0 +1,45 @@ |
3253 | +/* |
3254 | + * Copyright 2015 Canonical Ltd. |
3255 | + * |
3256 | + * This program is free software; you can redistribute it and/or modify |
3257 | + * it under the terms of the GNU Lesser General Public License as published by |
3258 | + * the Free Software Foundation; version 3. |
3259 | + * |
3260 | + * This program is distributed in the hope that it will be useful, |
3261 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
3262 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
3263 | + * GNU Lesser General Public License for more details. |
3264 | + * |
3265 | + * You should have received a copy of the GNU Lesser General Public License |
3266 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
3267 | + * |
3268 | + */ |
3269 | + |
3270 | +import QtQuick 2.4 |
3271 | +import Ubuntu.Components 1.3 |
3272 | + |
3273 | +Item { |
3274 | + id: holder |
3275 | + width: units.gu(40) |
3276 | + height: units.gu(71) |
3277 | + |
3278 | + BottomEdge { |
3279 | + id: bottomEdge |
3280 | + hint.text: "Test" |
3281 | + objectName: "testItem" |
3282 | + contentComponent: Rectangle { |
3283 | + width: bottomEdge.width |
3284 | + height: bottomEdge.height |
3285 | + color: UbuntuColors.lightGrey |
3286 | + } |
3287 | + |
3288 | + BottomEdgeRegion { |
3289 | + from: 0.2 |
3290 | + to: 0.5 |
3291 | + } |
3292 | + BottomEdgeRegion { |
3293 | + from: 0.5 |
3294 | + to: 0.7 |
3295 | + } |
3296 | + } |
3297 | +} |
3298 | |
3299 | === added file 'tests/unit_x11/tst_bottomedge/OverlappingRegions.qml' |
3300 | --- tests/unit_x11/tst_bottomedge/OverlappingRegions.qml 1970-01-01 00:00:00 +0000 |
3301 | +++ tests/unit_x11/tst_bottomedge/OverlappingRegions.qml 2015-11-27 10:36:32 +0000 |
3302 | @@ -0,0 +1,46 @@ |
3303 | +/* |
3304 | + * Copyright 2015 Canonical Ltd. |
3305 | + * |
3306 | + * This program is free software; you can redistribute it and/or modify |
3307 | + * it under the terms of the GNU Lesser General Public License as published by |
3308 | + * the Free Software Foundation; version 3. |
3309 | + * |
3310 | + * This program is distributed in the hope that it will be useful, |
3311 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
3312 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
3313 | + * GNU Lesser General Public License for more details. |
3314 | + * |
3315 | + * You should have received a copy of the GNU Lesser General Public License |
3316 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
3317 | + * |
3318 | + */ |
3319 | + |
3320 | +import QtQuick 2.4 |
3321 | +import Ubuntu.Components 1.3 |
3322 | + |
3323 | +Item { |
3324 | + id: holder |
3325 | + width: units.gu(40) |
3326 | + height: units.gu(71) |
3327 | + |
3328 | + BottomEdge { |
3329 | + hint.text: "Test" |
3330 | + objectName: "testItem" |
3331 | + |
3332 | + BottomEdgeRegion { |
3333 | + from: 0.2 |
3334 | + to: 0.5 |
3335 | + } |
3336 | + BottomEdgeRegion { |
3337 | + from: 0.4 |
3338 | + } |
3339 | + BottomEdgeRegion { |
3340 | + from: 0.4 |
3341 | + to: 0.6 |
3342 | + } |
3343 | + BottomEdgeRegion { |
3344 | + from: 0.6 |
3345 | + } |
3346 | + } |
3347 | +} |
3348 | + |
3349 | |
3350 | === added file 'tests/unit_x11/tst_bottomedge/ShorterBottomEdge.qml' |
3351 | --- tests/unit_x11/tst_bottomedge/ShorterBottomEdge.qml 1970-01-01 00:00:00 +0000 |
3352 | +++ tests/unit_x11/tst_bottomedge/ShorterBottomEdge.qml 2015-11-27 10:36:32 +0000 |
3353 | @@ -0,0 +1,39 @@ |
3354 | +/* |
3355 | + * Copyright 2015 Canonical Ltd. |
3356 | + * |
3357 | + * This program is free software; you can redistribute it and/or modify |
3358 | + * it under the terms of the GNU Lesser General Public License as published by |
3359 | + * the Free Software Foundation; version 3. |
3360 | + * |
3361 | + * This program is distributed in the hope that it will be useful, |
3362 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
3363 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
3364 | + * GNU Lesser General Public License for more details. |
3365 | + * |
3366 | + * You should have received a copy of the GNU Lesser General Public License |
3367 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
3368 | + * |
3369 | + */ |
3370 | + |
3371 | +import QtQuick 2.4 |
3372 | +import Ubuntu.Components 1.3 |
3373 | + |
3374 | +Item { |
3375 | + id: holder |
3376 | + width: units.gu(40) |
3377 | + height: units.gu(71) |
3378 | + |
3379 | + BottomEdge { |
3380 | + id: bottomEdge |
3381 | + objectName: "testItem" |
3382 | + hint.text: "Test" |
3383 | + height: holder.height - units.gu(20) |
3384 | + |
3385 | + contentComponent: Rectangle { |
3386 | + width: holder.width |
3387 | + height: bottomEdge.height |
3388 | + color: UbuntuColors.green |
3389 | + } |
3390 | + } |
3391 | +} |
3392 | + |
3393 | |
3394 | === added file 'tests/unit_x11/tst_bottomedge/tst_bottomedge.cpp' |
3395 | --- tests/unit_x11/tst_bottomedge/tst_bottomedge.cpp 1970-01-01 00:00:00 +0000 |
3396 | +++ tests/unit_x11/tst_bottomedge/tst_bottomedge.cpp 2015-11-27 10:36:32 +0000 |
3397 | @@ -0,0 +1,856 @@ |
3398 | +/* |
3399 | + * Copyright 2015 Canonical Ltd. |
3400 | + * |
3401 | + * This program is free software; you can redistribute it and/or modify |
3402 | + * it under the terms of the GNU Lesser General Public License as published by |
3403 | + * the Free Software Foundation; version 3. |
3404 | + * |
3405 | + * This program is distributed in the hope that it will be useful, |
3406 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
3407 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
3408 | + * GNU Lesser General Public License for more details. |
3409 | + * |
3410 | + * You should have received a copy of the GNU Lesser General Public License |
3411 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
3412 | + * |
3413 | + */ |
3414 | + |
3415 | +#include <QtTest/QtTest> |
3416 | +#include "ucbottomedge.h" |
3417 | +#include "ucbottomedgeregion.h" |
3418 | +#include "ucbottomedge_p.h" |
3419 | +#include "ucbottomedgehint.h" |
3420 | +#include "gestures/ucswipearea.h" |
3421 | +#include "ucunits.h" |
3422 | +#include "ucheader.h" |
3423 | +#include "ucaction.h" |
3424 | +#include "uctestcase.h" |
3425 | +#include "uctestextras.h" |
3426 | +#define private public |
3427 | +#include "quickutils.h" |
3428 | +#include "ucbottomedgestyle.h" |
3429 | +#undef private |
3430 | + |
3431 | +#define QVERIFY_RETURN(statement, returnValue) \ |
3432 | +do {\ |
3433 | + if (!QTest::qVerify((statement), #statement, "", __FILE__, __LINE__))\ |
3434 | + return returnValue;\ |
3435 | +} while (0) |
3436 | + |
3437 | +class BottomEdgeTestCase : public UbuntuTestCase |
3438 | +{ |
3439 | + Q_OBJECT |
3440 | +public: |
3441 | + BottomEdgeTestCase(const QString& file, ResizeMode resize = SizeViewToRootObject, bool assertOnFailure = true, QWindow* parent = 0) |
3442 | + : UbuntuTestCase(file, resize, assertOnFailure, parent) |
3443 | + { |
3444 | + // patch all BottomEdges' SwipeArea gesture recognition timer |
3445 | + QList<UCBottomEdge*> list = findChildren<UCBottomEdge*>(); |
3446 | + for (int i = 0; i < list.size(); ++i) { |
3447 | + UCBottomEdge *bottomEdge = list[i]; |
3448 | + UCSwipeArea *swipeArea = bottomEdge->hint()->swipeArea(); |
3449 | + swipeArea->setImmediateRecognition(true); |
3450 | + } |
3451 | + } |
3452 | + ~BottomEdgeTestCase() |
3453 | + { |
3454 | + // add a small timeout after each run to have a proper cleanup |
3455 | + QTest::qWait(400); |
3456 | + } |
3457 | + |
3458 | + UCBottomEdge *testItem(const QString &objectName = "testItem") |
3459 | + { |
3460 | + return findItem<UCBottomEdge*>(objectName); |
3461 | + } |
3462 | + |
3463 | + typedef QList<UCBottomEdgeRegion*> RegionList; |
3464 | + RegionList *regions(const QString &testItem) |
3465 | + { |
3466 | + QQmlListProperty<UCBottomEdgeRegion> qmlRegions(this->testItem(testItem)->regions()); |
3467 | + return reinterpret_cast<RegionList*>(qmlRegions.data); |
3468 | + } |
3469 | + |
3470 | + UCBottomEdgeRegion *regionAt(const QString &testItem, int index) |
3471 | + { |
3472 | + QVERIFY_RETURN(regions(testItem), nullptr); |
3473 | + QVERIFY_RETURN(regions(testItem)->size() > index, nullptr); |
3474 | + return regions(testItem)->at(index); |
3475 | + } |
3476 | + |
3477 | + bool hasContentAutoCollapse(const QString &testItem = "testItem") |
3478 | + { |
3479 | + UCBottomEdge *bottomEdge = this->testItem(testItem); |
3480 | + QQuickItem *contentItem = bottomEdge->contentItem(); |
3481 | + if (!contentItem) { |
3482 | + return false; |
3483 | + } |
3484 | + // we do not have the PageHeader in cpp, therefore we need the same workaround we have in the code |
3485 | + UCHeader *header = contentItem->findChild<UCHeader*>(); |
3486 | + if (!QuickUtils::inherits(header, "PageHeader")) { |
3487 | + return false; |
3488 | + } |
3489 | + |
3490 | + QVariant list(header->property("navigationActions")); |
3491 | + QQmlListProperty<UCAction> actions = list.value< QQmlListProperty<UCAction> >(); |
3492 | + QList<UCAction*> *navigationActions = reinterpret_cast<QList<UCAction*>*>(actions.data); |
3493 | + if (navigationActions->size() <= 0) { |
3494 | + return false; |
3495 | + } |
3496 | + return (qobject_cast<UCCollapseAction*>(navigationActions->at(0)) != Q_NULLPTR); |
3497 | + } |
3498 | +}; |
3499 | + |
3500 | + |
3501 | +class tst_BottomEdge : public QObject |
3502 | +{ |
3503 | + Q_OBJECT |
3504 | +private Q_SLOTS: |
3505 | + |
3506 | + void initTestCase() |
3507 | + { |
3508 | + UCTestExtras::registerTouchDevice(); |
3509 | + // make sure we disable the mouse |
3510 | + QuickUtils::instance().m_mouseAttached = false; |
3511 | + } |
3512 | + |
3513 | + void test_defaults() |
3514 | + { |
3515 | + QScopedPointer<BottomEdgeTestCase> test(new BottomEdgeTestCase("Defaults.qml")); |
3516 | + QCOMPARE(test->testItem()->height(), test->rootObject()->height()); |
3517 | + QCOMPARE(test->testItem()->dragProgress(), 0.0); |
3518 | + QCOMPARE(test->testItem()->dragDirection(), UCBottomEdge::Undefined); |
3519 | + QCOMPARE(test->testItem()->status(), UCBottomEdge::Hidden); |
3520 | + QCOMPARE(test->testItem()->contentUrl(), QUrl()); |
3521 | + QVERIFY(!test->testItem()->contentComponent()); |
3522 | + QVERIFY(!test->testItem()->contentItem()); |
3523 | + QVERIFY(test->regions("testItem")); |
3524 | + QCOMPARE(test->regions("testItem")->size(), 1); |
3525 | + QCOMPARE(test->regionAt("testItem", 0)->objectName(), QString("default_BottomEdgeRegion")); |
3526 | + QCOMPARE(test->regionAt("testItem", 0)->m_from, 0.33); |
3527 | + QCOMPARE(test->regionAt("testItem", 0)->m_to, 1.0); |
3528 | + QVERIFY(!test->testItem()->activeRegion()); |
3529 | + } |
3530 | + |
3531 | + void test_height_moves_when_reparented() |
3532 | + { |
3533 | + QScopedPointer<BottomEdgeTestCase> test(new BottomEdgeTestCase("DifferentSizes.qml")); |
3534 | + QQuickItem *newParent = test->rootObject(); |
3535 | + QQuickItem *oldParent = test->findItem<QQuickItem*>("oldParent"); |
3536 | + UCBottomEdge *testItem = test->testItem(); |
3537 | + |
3538 | + QSignalSpy spy(testItem, SIGNAL(implicitHeightChanged())); |
3539 | + testItem->setParentItem(newParent); |
3540 | + UbuntuTestCase::waitForSignal(&spy); |
3541 | + |
3542 | + // change the implicit height so we are sure we don't get the height change triggered |
3543 | + testItem->setImplicitHeight(0); |
3544 | + spy.clear(); |
3545 | + oldParent->setHeight(20); |
3546 | + QEXPECT_FAIL(0, "no implicitHeight change is expected", Continue); |
3547 | + QVERIFY(spy.wait(400)); |
3548 | + } |
3549 | + |
3550 | + void test_panel_is_last_item_of_parent() |
3551 | + { |
3552 | + QScopedPointer<BottomEdgeTestCase> test(new BottomEdgeTestCase("LastItem.qml")); |
3553 | + QQuickItem *bottomEdgeParent = test->testItem()->parentItem(); |
3554 | + UCBottomEdgePrivate *privateTestItem = UCBottomEdgePrivate::get(test->testItem()); |
3555 | + QCOMPARE(bottomEdgeParent->childItems().last(), privateTestItem->styleItem); |
3556 | + |
3557 | + QQuickItem *dynamicItem = test->findItem<QQuickItem*>("dynamicItem"); |
3558 | + dynamicItem->setParentItem(bottomEdgeParent); |
3559 | + // still the last one |
3560 | + QCOMPARE(bottomEdgeParent->childItems().last(), privateTestItem->styleItem); |
3561 | + } |
3562 | + |
3563 | + void test_commit_when_clicked() |
3564 | + { |
3565 | + QScopedPointer<BottomEdgeTestCase> test(new BottomEdgeTestCase("BottomEdgeInItem.qml")); |
3566 | + test->testItem()->hint()->setStatus(UCBottomEdgeHint::Locked); |
3567 | + UCBottomEdgeHint *hint = test->testItem()->hint(); |
3568 | + QTest::mouseClick(test->testItem()->hint()->window(), Qt::LeftButton, 0, UbuntuTestCase::centerOf(hint, true).toPoint()); |
3569 | + QTRY_COMPARE_WITH_TIMEOUT(test->testItem()->status(), UCBottomEdge::Committed, 1000); |
3570 | + } |
3571 | + |
3572 | + void test_commit_when_touch_clicked() |
3573 | + { |
3574 | + QScopedPointer<BottomEdgeTestCase> test(new BottomEdgeTestCase("BottomEdgeInItem.qml")); |
3575 | + UCBottomEdgeHint *hint = test->testItem()->hint(); |
3576 | + // swipe a bit to reveal |
3577 | + |
3578 | + UCTestExtras::touchDrag(0, hint, QPoint(hint->width() / 2, hint->height()), QPoint(0, -hint->height())); |
3579 | + QTRY_COMPARE_WITH_TIMEOUT(hint->status(), UCBottomEdgeHint::Active, 1000); |
3580 | + |
3581 | + UCTestExtras::touchClick(0, hint, UbuntuTestCase::centerOf(hint).toPoint()); |
3582 | + QTRY_COMPARE_WITH_TIMEOUT(test->testItem()->status(), UCBottomEdge::Committed, 1000); |
3583 | + } |
3584 | + |
3585 | + void test_revealed_when_hint_threshold_passed_data() |
3586 | + { |
3587 | + QTest::addColumn<bool>("withMouse"); |
3588 | + QTest::addColumn<bool>("lockHint"); |
3589 | + QTest::addColumn<bool>("xfail"); |
3590 | + |
3591 | + QTest::newRow("drag with mouse, unlocked hint") << true << false << true; |
3592 | + QTest::newRow("drag with mouse, locked hint") << true << true << false; |
3593 | + QTest::newRow("drag with touch, unlocked hint") << false << false << false; |
3594 | + QTest::newRow("drag with touch, locked hint") << false << true << false; |
3595 | + } |
3596 | + void test_revealed_when_hint_threshold_passed() |
3597 | + { |
3598 | + QFETCH(bool, withMouse); |
3599 | + QFETCH(bool, lockHint); |
3600 | + QFETCH(bool, xfail); |
3601 | + |
3602 | + QScopedPointer<BottomEdgeTestCase> test(new BottomEdgeTestCase("BottomEdgeInItem.qml")); |
3603 | + UCBottomEdge *bottomEdge = test->testItem(); |
3604 | + UCBottomEdgeStyle *style = UCBottomEdgePrivate::get(bottomEdge)->bottomPanel; |
3605 | + QSignalSpy spy(bottomEdge, SIGNAL(statusChanged(UCBottomEdge::Status))); |
3606 | + |
3607 | + // swipe till we reveal it |
3608 | + QPoint from(bottomEdge->width() / 2.0f, bottomEdge->height() - 1); |
3609 | + QPoint delta(0, -(2 * style->m_revealThreshold)); |
3610 | + if (lockHint) { |
3611 | + bottomEdge->hint()->setStatus(UCBottomEdgeHint::Locked); |
3612 | + } |
3613 | + if (withMouse) { |
3614 | + UCTestExtras::mouseDrag(bottomEdge, from, delta, Qt::LeftButton); |
3615 | + } else { |
3616 | + UCTestExtras::touchDrag(0, bottomEdge, from, delta, 8); |
3617 | + } |
3618 | + if (xfail) { |
3619 | + QEXPECT_FAIL(0, "failure expected", Continue); |
3620 | + } |
3621 | + QVERIFY(spy.wait(500)); |
3622 | + if (xfail) { |
3623 | + QCOMPARE(spy.count(), 0); |
3624 | + } else { |
3625 | + // there must be two state changes here, one Hidden->Revealed, and one Revealed->Hidden |
3626 | + QCOMPARE(spy.count(), 2); |
3627 | + QList<QVariant> state1 = spy.at(0); |
3628 | + QCOMPARE(state1[0].value<int>(), (int)UCBottomEdge::Revealed); |
3629 | + QList<QVariant> state2 = spy.at(1); |
3630 | + QCOMPARE(state2[0].value<int>(), (int)UCBottomEdge::Hidden); |
3631 | + } |
3632 | + } |
3633 | + |
3634 | + void test_commit_when_onethird_passed_data() |
3635 | + { |
3636 | + QTest::addColumn<bool>("withMouse"); |
3637 | + |
3638 | + QTest::newRow("with mouse") << true; |
3639 | + QTest::newRow("with touch") << false; |
3640 | + } |
3641 | + void test_commit_when_onethird_passed() |
3642 | + { |
3643 | + QFETCH(bool, withMouse); |
3644 | + |
3645 | + QScopedPointer<BottomEdgeTestCase> test(new BottomEdgeTestCase("BottomEdgeInItem.qml")); |
3646 | + UCBottomEdge *bottomEdge = test->testItem(); |
3647 | + |
3648 | + QPoint from(bottomEdge->width() / 2.0f, bottomEdge->height() - 1); |
3649 | + // add some extra space for the touch |
3650 | + QPoint delta(0, -(bottomEdge->height() / 3 + UCUnits::instance().gu(6))); |
3651 | + |
3652 | + if (withMouse) { |
3653 | + bottomEdge->hint()->setStatus(UCBottomEdgeHint::Locked); |
3654 | + } |
3655 | + // we need to do the swipe in more steps |
3656 | + if (withMouse) { |
3657 | + UCTestExtras::mouseDrag(bottomEdge, from, delta, Qt::LeftButton, 0, 20); |
3658 | + } else { |
3659 | + UCTestExtras::touchDrag(0, bottomEdge, from, delta, 20); |
3660 | + } |
3661 | + QTRY_COMPARE_WITH_TIMEOUT(bottomEdge->status(), UCBottomEdge::Committed, 1000); |
3662 | + } |
3663 | + |
3664 | + void test_collapse_before_onethird_data() |
3665 | + { |
3666 | + QTest::addColumn<bool>("withMouse"); |
3667 | + |
3668 | + QTest::newRow("with mouse") << true; |
3669 | + QTest::newRow("with touch") << false; |
3670 | + } |
3671 | + void test_collapse_before_onethird() |
3672 | + { |
3673 | + QFETCH(bool, withMouse); |
3674 | + |
3675 | + QScopedPointer<BottomEdgeTestCase> test(new BottomEdgeTestCase("BottomEdgeInItem.qml")); |
3676 | + UCBottomEdge *bottomEdge = test->testItem(); |
3677 | + |
3678 | + QPoint from(bottomEdge->width() / 2.0f, bottomEdge->height() - 1); |
3679 | + QPoint delta(0, -(bottomEdge->height() / 4)); |
3680 | + |
3681 | + if (withMouse) { |
3682 | + bottomEdge->hint()->setStatus(UCBottomEdgeHint::Locked); |
3683 | + } |
3684 | + // we need to do the swipe in more steps |
3685 | + if (withMouse) { |
3686 | + UCTestExtras::mouseDrag(bottomEdge, from, delta, Qt::LeftButton, 0, 20); |
3687 | + } else { |
3688 | + UCTestExtras::touchDrag(0, bottomEdge, from, delta, 20); |
3689 | + } |
3690 | + QTRY_COMPARE_WITH_TIMEOUT(bottomEdge->status(), UCBottomEdge::Hidden, 1000); |
3691 | + } |
3692 | + |
3693 | + void test_collapse_when_dragged_downwards_data() |
3694 | + { |
3695 | + // when onethird not passed |
3696 | + // when onethird was passed |
3697 | + QTest::addColumn<bool>("withMouse"); |
3698 | + QTest::addColumn< QList<QPoint> >("moves"); |
3699 | + |
3700 | + QList<QPoint> shortPath, longPath; |
3701 | + // upwards |
3702 | + for (int i = 0; i < 10; i++) { |
3703 | + shortPath << QPointF(0, -UCUnits::instance().gu(3)).toPoint(); |
3704 | + longPath << QPointF(0, -UCUnits::instance().gu(7)).toPoint(); |
3705 | + } |
3706 | + // downwards |
3707 | + for (int i = 0; i < 5; i++) { |
3708 | + shortPath << QPointF(0, UCUnits::instance().gu(2)).toPoint(); |
3709 | + longPath << QPointF(0, UCUnits::instance().gu(2)).toPoint(); |
3710 | + } |
3711 | + |
3712 | + QTest::newRow("with mouse, onethird not passed") |
3713 | + << true << shortPath; |
3714 | + QTest::newRow("with touch, onethird not passed") |
3715 | + << false << shortPath; |
3716 | + QTest::newRow("with mouse, onethird passed") |
3717 | + << true << longPath; |
3718 | + QTest::newRow("with touch, onethird passed") |
3719 | + << false << longPath; |
3720 | + } |
3721 | + void test_collapse_when_dragged_downwards() |
3722 | + { |
3723 | + QFETCH(bool, withMouse); |
3724 | + QFETCH(QList<QPoint>, moves); |
3725 | + |
3726 | + QScopedPointer<BottomEdgeTestCase> test(new BottomEdgeTestCase("BottomEdgeInItem.qml")); |
3727 | + UCBottomEdge *bottomEdge = test->testItem(); |
3728 | + |
3729 | + QPoint from(bottomEdge->width() / 2.0f, bottomEdge->height() - 1); |
3730 | + moves.prepend(from); |
3731 | + |
3732 | + if (withMouse) { |
3733 | + bottomEdge->hint()->setStatus(UCBottomEdgeHint::Locked); |
3734 | + } |
3735 | + if (withMouse) { |
3736 | + UCTestExtras::mouseDragWithPoints(bottomEdge, moves, Qt::LeftButton); |
3737 | + } else { |
3738 | + UCTestExtras::touchDragWithPoints(0, bottomEdge, moves); |
3739 | + } |
3740 | + QTRY_COMPARE_WITH_TIMEOUT(bottomEdge->status(), UCBottomEdge::Hidden, 1000); |
3741 | + } |
3742 | + |
3743 | + void test_height_less_than_parent() |
3744 | + { |
3745 | + QScopedPointer<BottomEdgeTestCase> test(new BottomEdgeTestCase("ShorterBottomEdge.qml")); |
3746 | + UCBottomEdge *bottomEdge = test->testItem(); |
3747 | + UCBottomEdgeStyle *style = UCBottomEdgePrivate::get(bottomEdge)->bottomPanel; |
3748 | + bottomEdge->commit(); |
3749 | + QTRY_COMPARE_WITH_TIMEOUT(bottomEdge->status(), UCBottomEdge::Committed, 1000); |
3750 | + QCOMPARE(style->m_panel->y(), bottomEdge->y()); |
3751 | + } |
3752 | + |
3753 | + void test_do_not_overshoot_data() |
3754 | + { |
3755 | + QTest::addColumn<bool>("withMouse"); |
3756 | + |
3757 | + QTest::newRow("with touch") << false; |
3758 | + QTest::newRow("with mouse") << true; |
3759 | + } |
3760 | + void test_do_not_overshoot() |
3761 | + { |
3762 | + QFETCH(bool, withMouse); |
3763 | + |
3764 | + QScopedPointer<BottomEdgeTestCase> test(new BottomEdgeTestCase("ShorterBottomEdge.qml")); |
3765 | + UCBottomEdge *bottomEdge = test->testItem(); |
3766 | + UCBottomEdgeStyle *style = UCBottomEdgePrivate::get(bottomEdge)->bottomPanel; |
3767 | + |
3768 | + QPoint from(bottomEdge->width() / 2.0f, bottomEdge->height() - 1); |
3769 | + QPoint to = from + QPoint(0, -(bottomEdge->parentItem()->height() - 1)); |
3770 | + |
3771 | + if (withMouse) { |
3772 | + bottomEdge->hint()->setStatus(UCBottomEdgeHint::Locked); |
3773 | + from = bottomEdge->mapToScene(from).toPoint(); |
3774 | + to = bottomEdge->mapToScene(to).toPoint(); |
3775 | + QTest::mousePress(bottomEdge->window(), Qt::LeftButton, 0, from, 20); |
3776 | + QPoint movePos(from); |
3777 | + while (movePos.y() > to.y()) { |
3778 | + QTest::mouseMove(bottomEdge->window(), movePos, 20); |
3779 | + movePos += QPoint(0, -10); |
3780 | + QVERIFY(style->m_panel->y() >= bottomEdge->y()); |
3781 | + } |
3782 | + QTest::mouseRelease(bottomEdge->window(),Qt::LeftButton, 0, movePos, 20); |
3783 | + } else { |
3784 | + UCTestExtras::touchPress(0, bottomEdge, from); |
3785 | + QPoint movePos(from); |
3786 | + while (movePos.y() > to.y()) { |
3787 | + QTest::qWait(20); |
3788 | + UCTestExtras::touchMove(0, bottomEdge, movePos); |
3789 | + movePos += QPoint(0, -10); |
3790 | + QVERIFY(style->m_panel->y() >= bottomEdge->y()); |
3791 | + } |
3792 | + QTest::qWait(20); |
3793 | + UCTestExtras::touchRelease(0, bottomEdge, movePos); |
3794 | + } |
3795 | + } |
3796 | + |
3797 | + void test_commitStarted_commitCompleted_emitted() |
3798 | + { |
3799 | + QScopedPointer<BottomEdgeTestCase> test(new BottomEdgeTestCase("BottomEdgeInItem.qml")); |
3800 | + UCBottomEdge *bottomEdge = test->testItem(); |
3801 | + |
3802 | + QSignalSpy commitStartedSpy(bottomEdge, SIGNAL(commitStarted())); |
3803 | + QSignalSpy commitCompletedSpy(bottomEdge, SIGNAL(commitCompleted())); |
3804 | + bottomEdge->commit(); |
3805 | + QTRY_COMPARE_WITH_TIMEOUT(commitStartedSpy.count(), 1, 1000); |
3806 | + QTRY_COMPARE_WITH_TIMEOUT(commitCompletedSpy.count(), 1, 1000); |
3807 | + } |
3808 | + |
3809 | + void test_collapseStarted_collapseCompleted_emitted() |
3810 | + { |
3811 | + QScopedPointer<BottomEdgeTestCase> test(new BottomEdgeTestCase("BottomEdgeInItem.qml")); |
3812 | + UCBottomEdge *bottomEdge = test->testItem(); |
3813 | + bottomEdge->commit(); |
3814 | + QTRY_COMPARE_WITH_TIMEOUT(bottomEdge->status(), UCBottomEdge::Committed, 1000); |
3815 | + // wait few milliseconds before we initiate collapse |
3816 | + QTest::qWait(200); |
3817 | + |
3818 | + QSignalSpy collapseStartedSpy(bottomEdge, SIGNAL(collapseStarted())); |
3819 | + QSignalSpy collapseCompletedSpy(bottomEdge, SIGNAL(collapseCompleted())); |
3820 | + bottomEdge->collapse(); |
3821 | + QTRY_COMPARE_WITH_TIMEOUT(collapseStartedSpy.count(), 1, 1000); |
3822 | + QTRY_COMPARE_WITH_TIMEOUT(collapseCompletedSpy.count(), 1, 1000); |
3823 | + } |
3824 | + |
3825 | + void test_collapse_during_commit() |
3826 | + { |
3827 | + QScopedPointer<BottomEdgeTestCase> test(new BottomEdgeTestCase("BottomEdgeInItem.qml")); |
3828 | + UCBottomEdge *bottomEdge = test->testItem(); |
3829 | + |
3830 | + QSignalSpy commitStartedSpy(bottomEdge, SIGNAL(commitStarted())); |
3831 | + QSignalSpy commitCompletedSpy(bottomEdge, SIGNAL(commitCompleted())); |
3832 | + QSignalSpy collapseStartedSpy(bottomEdge, SIGNAL(collapseStarted())); |
3833 | + QSignalSpy collapseCompletedSpy(bottomEdge, SIGNAL(collapseCompleted())); |
3834 | + |
3835 | + connect(bottomEdge, SIGNAL(commitStarted()), bottomEdge, SLOT(collapse()), Qt::QueuedConnection); |
3836 | + |
3837 | + bottomEdge->commit(); |
3838 | + |
3839 | + QTRY_COMPARE_WITH_TIMEOUT(commitStartedSpy.count(), 1, 1000); |
3840 | + QTRY_COMPARE_WITH_TIMEOUT(commitCompletedSpy.count(), 0, 1000); |
3841 | + QTRY_COMPARE_WITH_TIMEOUT(collapseStartedSpy.count(), 1, 1000); |
3842 | + QTRY_COMPARE_WITH_TIMEOUT(collapseCompletedSpy.count(), 1, 1000); |
3843 | + } |
3844 | + |
3845 | + void test_commit_during_collapse() |
3846 | + { |
3847 | + QScopedPointer<BottomEdgeTestCase> test(new BottomEdgeTestCase("BottomEdgeInItem.qml")); |
3848 | + UCBottomEdge *bottomEdge = test->testItem(); |
3849 | + bottomEdge->commit(); |
3850 | + |
3851 | + QSignalSpy commitStartedSpy(bottomEdge, SIGNAL(commitStarted())); |
3852 | + QSignalSpy commitCompletedSpy(bottomEdge, SIGNAL(commitCompleted())); |
3853 | + QSignalSpy collapseStartedSpy(bottomEdge, SIGNAL(collapseStarted())); |
3854 | + QSignalSpy collapseCompletedSpy(bottomEdge, SIGNAL(collapseCompleted())); |
3855 | + |
3856 | + connect(bottomEdge, SIGNAL(collapseStarted()), bottomEdge, SLOT(commit()), Qt::QueuedConnection); |
3857 | + |
3858 | + bottomEdge->collapse(); |
3859 | + QTRY_COMPARE_WITH_TIMEOUT(collapseStartedSpy.count(), 1, 1000); |
3860 | + QTRY_COMPARE_WITH_TIMEOUT(collapseCompletedSpy.count(), 0, 1000); |
3861 | + QTRY_COMPARE_WITH_TIMEOUT(commitStartedSpy.count(), 1, 1000); |
3862 | + QTRY_COMPARE_WITH_TIMEOUT(commitCompletedSpy.count(), 1, 1000); |
3863 | + } |
3864 | + |
3865 | + // region tests |
3866 | + |
3867 | + void test_region_operations_data() |
3868 | + { |
3869 | + QTest::addColumn<QString>("document"); |
3870 | + QTest::addColumn<QString>("warning"); |
3871 | + QTest::addColumn<qreal>("xFrom"); |
3872 | + QTest::addColumn<qreal>("xTo"); |
3873 | + QTest::addColumn<QString>("xName"); |
3874 | + |
3875 | + QTest::newRow("add through regions property") |
3876 | + << "AddCustomRegionUsingRegionsProperty.qml" |
3877 | + << QString() |
3878 | + << 0.0 << 1.0 << QString("customRegion"); |
3879 | + QTest::newRow("add through data property") |
3880 | + << "AddCustomRegionUsingDataProperty.qml" |
3881 | + << QString() |
3882 | + << 0.0 << 1.0 << QString("customRegion"); |
3883 | + QTest::newRow("add through Component.onCompleted") |
3884 | + << "AddCustomRegionOnCompleted.qml" |
3885 | + << QString() |
3886 | + << 0.0 << 1.0 << QString("customRegion"); |
3887 | + QTest::newRow("add owned by other BottomEdge") |
3888 | + << "AddCustomRegionOwnedByOtherBottomEdge.qml" |
3889 | + << "QML BottomEdge: Cannot reuse region owned by other BottomEdge components" |
3890 | + // we should have the default region still |
3891 | + << 0.33 << 1.0 << "default_BottomEdgeRegion"; |
3892 | + QTest::newRow("clear") |
3893 | + << "ClearCustomRegions.qml" |
3894 | + << QString() |
3895 | + // we should have the default region back |
3896 | + << 0.33 << 1.0 << "default_BottomEdgeRegion"; |
3897 | + } |
3898 | + |
3899 | + void test_region_operations() |
3900 | + { |
3901 | + QFETCH(QString, document); |
3902 | + QFETCH(QString, warning); |
3903 | + QFETCH(qreal, xFrom); |
3904 | + QFETCH(qreal, xTo); |
3905 | + QFETCH(QString, xName); |
3906 | + |
3907 | + if (!warning.isEmpty()) { |
3908 | + UbuntuTestCase::ignoreWarning(document, 26, 5, warning, 1); |
3909 | + } |
3910 | + QScopedPointer<BottomEdgeTestCase> test(new BottomEdgeTestCase(document)); |
3911 | + UCBottomEdge *bottomEdge = test->testItem(); |
3912 | + UCBottomEdgePrivate *privateBottomEdge = UCBottomEdgePrivate::get(bottomEdge); |
3913 | + |
3914 | + // the regions has the custom one |
3915 | + QCOMPARE(privateBottomEdge->regions.size(), 1); |
3916 | + UCBottomEdgeRegion *region = privateBottomEdge->regions[0]; |
3917 | + QVERIFY(region); |
3918 | + QCOMPARE(region->m_from, xFrom); |
3919 | + QCOMPARE(region->m_to, xTo); |
3920 | + QCOMPARE(region->objectName(), xName); |
3921 | + } |
3922 | + |
3923 | + void test_active_region_changes() |
3924 | + { |
3925 | + QScopedPointer<BottomEdgeTestCase> test(new BottomEdgeTestCase("LeanActiveRegionChange.qml")); |
3926 | + UCBottomEdge *bottomEdge = test->testItem(); |
3927 | + |
3928 | + QPoint from(bottomEdge->width() / 2.0f, bottomEdge->height() - 5); |
3929 | + QPoint to = from + QPoint(0, -(bottomEdge->parentItem()->height() - 1)); |
3930 | + QSignalSpy spy(bottomEdge, SIGNAL(activeRegionChanged(UCBottomEdgeRegion*))); |
3931 | + |
3932 | + UCTestExtras::touchPress(0, bottomEdge, from); |
3933 | + QPoint movePos(from); |
3934 | + while (movePos.y() > to.y()) { |
3935 | + QTest::qWait(20); |
3936 | + UCTestExtras::touchMove(0, bottomEdge, movePos); |
3937 | + movePos += QPoint(0, -10); |
3938 | + } |
3939 | + QTest::qWait(20); |
3940 | + UCTestExtras::touchRelease(0, bottomEdge, movePos); |
3941 | + // we should have had 3 active region changes by now |
3942 | + // null -> region #0 -> region #1 -> null |
3943 | + QCOMPARE(spy.count(), 3); |
3944 | + } |
3945 | + |
3946 | + void test_region_signals_emitted_data() |
3947 | + { |
3948 | + QTest::addColumn<bool>("withMouse"); |
3949 | + |
3950 | + QTest::newRow("with mouse") << true; |
3951 | + QTest::newRow("with touch") << false; |
3952 | + } |
3953 | + void test_region_signals_emitted() |
3954 | + { |
3955 | + QFETCH(bool, withMouse); |
3956 | + |
3957 | + QScopedPointer<BottomEdgeTestCase> test(new BottomEdgeTestCase("BottomEdgeInItem.qml")); |
3958 | + UCBottomEdge *bottomEdge = test->testItem(); |
3959 | + UCBottomEdgePrivate *privateBottomEdge = UCBottomEdgePrivate::get(bottomEdge); |
3960 | + UCBottomEdgeRegion *region = privateBottomEdge->regions[0]; |
3961 | + |
3962 | + // change the region so we can get the signals while dragged |
3963 | + region->m_from = 0.1; |
3964 | + region->m_to = 0.2; |
3965 | + |
3966 | + QPoint from(bottomEdge->width() / 2.0f, bottomEdge->height() - 5); |
3967 | + QPoint delta(0, -(bottomEdge->height() / 3 + UCUnits::instance().gu(6))); |
3968 | + QSignalSpy entered(region, SIGNAL(entered())); |
3969 | + QSignalSpy exited(region, SIGNAL(exited())); |
3970 | + |
3971 | + if (withMouse) { |
3972 | + bottomEdge->hint()->setStatus(UCBottomEdgeHint::Locked); |
3973 | + } |
3974 | + if (withMouse) { |
3975 | + UCTestExtras::mouseDrag(bottomEdge, from, delta, Qt::LeftButton, 0); |
3976 | + } else { |
3977 | + UCTestExtras::touchDrag(0, bottomEdge, from, delta); |
3978 | + } |
3979 | + QTRY_COMPARE_WITH_TIMEOUT(entered.count(), 1, 500); |
3980 | + QTRY_COMPARE_WITH_TIMEOUT(exited.count(), 1, 500); |
3981 | + } |
3982 | + |
3983 | + void test_region_dragEnded_emitted_data() |
3984 | + { |
3985 | + QTest::addColumn<bool>("withMouse"); |
3986 | + |
3987 | + QTest::newRow("with mouse") << true; |
3988 | + QTest::newRow("with touch") << false; |
3989 | + } |
3990 | + void test_region_dragEnded_emitted() |
3991 | + { |
3992 | + QFETCH(bool, withMouse); |
3993 | + |
3994 | + QScopedPointer<BottomEdgeTestCase> test(new BottomEdgeTestCase("BottomEdgeInItem.qml")); |
3995 | + UCBottomEdge *bottomEdge = test->testItem(); |
3996 | + UCBottomEdgePrivate *privateBottomEdge = UCBottomEdgePrivate::get(bottomEdge); |
3997 | + UCBottomEdgeRegion *region = privateBottomEdge->regions[0]; |
3998 | + |
3999 | + QSignalSpy dragEnded(region, SIGNAL(dragEnded())); |
4000 | + QPoint from(bottomEdge->width() / 2.0f, bottomEdge->height() - 5); |
4001 | + QPoint delta(0, -(bottomEdge->height() / 2.0f)); |
4002 | + if (withMouse) { |
4003 | + bottomEdge->hint()->setStatus(UCBottomEdgeHint::Locked); |
4004 | + UCTestExtras::mouseDrag(bottomEdge, from, delta, Qt::LeftButton, 0); |
4005 | + } else { |
4006 | + UCTestExtras::touchDrag(0, bottomEdge, from, delta); |
4007 | + } |
4008 | + UbuntuTestCase::waitForSignal(&dragEnded); |
4009 | + } |
4010 | + |
4011 | + void test_alternative_content_for_default_commit_region() |
4012 | + { |
4013 | + QScopedPointer<BottomEdgeTestCase> test(new BottomEdgeTestCase("AlternateDefaultRegionContent.qml")); |
4014 | + UCBottomEdge *bottomEdge = test->testItem(); |
4015 | + |
4016 | + QPoint from(bottomEdge->width() / 2.0f, bottomEdge->height() - 5); |
4017 | + QPoint delta(0, -(bottomEdge->height() / 2)); |
4018 | + |
4019 | + UCTestExtras::touchDrag(0, bottomEdge, from, delta, 20); |
4020 | + QTRY_COMPARE_WITH_TIMEOUT(bottomEdge->status(), UCBottomEdge::Committed, 1000); |
4021 | + QCOMPARE(bottomEdge->contentItem()->objectName(), QString("regionContent")); |
4022 | + } |
4023 | + |
4024 | + void test_end_drag_in_region_commits_to_the_region_data() |
4025 | + { |
4026 | + QTest::addColumn<bool>("withMouse"); |
4027 | + |
4028 | + QTest::newRow("with mouse") << true; |
4029 | + QTest::newRow("with touch") << false; |
4030 | + } |
4031 | + void test_end_drag_in_region_commits_to_the_region() |
4032 | + { |
4033 | + QFETCH(bool, withMouse); |
4034 | + |
4035 | + QScopedPointer<BottomEdgeTestCase> test(new BottomEdgeTestCase("AlternateDefaultRegionContent.qml")); |
4036 | + UCBottomEdge *bottomEdge = test->testItem(); |
4037 | + UCBottomEdgePrivate *privateBottomEdge = UCBottomEdgePrivate::get(bottomEdge); |
4038 | + UCBottomEdgeRegion *region = privateBottomEdge->regions[0]; |
4039 | + UCBottomEdgeStyle *style = UCBottomEdgePrivate::get(bottomEdge)->bottomPanel; |
4040 | + |
4041 | + // alter default region for testing |
4042 | + region->m_from = 0.1; |
4043 | + region->m_to = 0.8; |
4044 | + |
4045 | + QPoint from(bottomEdge->width() / 2.0f, bottomEdge->height() - 5); |
4046 | + QPoint to = from + QPoint(0, -(bottomEdge->parentItem()->height() - 1)); |
4047 | + |
4048 | + if (withMouse) { |
4049 | + bottomEdge->hint()->setStatus(UCBottomEdgeHint::Locked); |
4050 | + from = bottomEdge->mapToScene(from).toPoint(); |
4051 | + to = bottomEdge->mapToScene(to).toPoint(); |
4052 | + QTest::mousePress(bottomEdge->window(), Qt::LeftButton, 0, from, 20); |
4053 | + QPoint movePos(from); |
4054 | + while (movePos.y() > to.y() && !bottomEdge->activeRegion()) { |
4055 | + QTest::mouseMove(bottomEdge->window(), movePos, 20); |
4056 | + movePos += QPoint(0, -10); |
4057 | + } |
4058 | + QTest::mouseRelease(bottomEdge->window(),Qt::LeftButton, 0, movePos, 20); |
4059 | + } else { |
4060 | + UCTestExtras::touchPress(0, bottomEdge, from); |
4061 | + QPoint movePos(from); |
4062 | + while (movePos.y() > to.y() && !bottomEdge->activeRegion()) { |
4063 | + QTest::qWait(20); |
4064 | + UCTestExtras::touchMove(0, bottomEdge, movePos); |
4065 | + movePos += QPoint(0, -10); |
4066 | + } |
4067 | + QTest::qWait(20); |
4068 | + UCTestExtras::touchRelease(0, bottomEdge, movePos); |
4069 | + } |
4070 | + |
4071 | + QVERIFY(bottomEdge->activeRegion()); |
4072 | + // the top of the committed content should not be the top of the bottom edge |
4073 | + QVERIFY(style->m_panel->y() > bottomEdge->y()); |
4074 | + QCOMPARE(bottomEdge->status(), UCBottomEdge::Revealed); |
4075 | + } |
4076 | + |
4077 | + void test_drag_ends_in_uncovered_region_collapses_data() |
4078 | + { |
4079 | + QTest::addColumn<bool>("withMouse"); |
4080 | + |
4081 | + QTest::newRow("with mouse") << true; |
4082 | + QTest::newRow("with touch") << false; |
4083 | + } |
4084 | + void test_drag_ends_in_uncovered_region_collapses() |
4085 | + { |
4086 | + QFETCH(bool, withMouse); |
4087 | + |
4088 | + QScopedPointer<BottomEdgeTestCase> test(new BottomEdgeTestCase("AlternateDefaultRegionContent.qml")); |
4089 | + UCBottomEdge *bottomEdge = test->testItem(); |
4090 | + UCBottomEdgePrivate *privateBottomEdge = UCBottomEdgePrivate::get(bottomEdge); |
4091 | + UCBottomEdgeRegion *region = privateBottomEdge->regions[0]; |
4092 | + |
4093 | + // alter region values to adjust to the test |
4094 | + region->m_from = 0.1; |
4095 | + region->m_to = 0.5; |
4096 | + |
4097 | + QPoint from(bottomEdge->width() / 2.0f, bottomEdge->height() - 5); |
4098 | + QPoint to = from + QPoint(0, -(bottomEdge->parentItem()->height() - 1)); |
4099 | + // let us know when we are out of the region |
4100 | + QSignalSpy exitRegion(region, SIGNAL(exited())); |
4101 | + |
4102 | + if (withMouse) { |
4103 | + bottomEdge->hint()->setStatus(UCBottomEdgeHint::Locked); |
4104 | + from = bottomEdge->mapToScene(from).toPoint(); |
4105 | + to = bottomEdge->mapToScene(to).toPoint(); |
4106 | + QTest::mousePress(bottomEdge->window(), Qt::LeftButton, 0, from, 20); |
4107 | + QPoint movePos(from); |
4108 | + while (movePos.y() > to.y() && !exitRegion.count()) { |
4109 | + QTest::mouseMove(bottomEdge->window(), movePos, 20); |
4110 | + movePos += QPoint(0, -10); |
4111 | + } |
4112 | + QTest::mouseRelease(bottomEdge->window(),Qt::LeftButton, 0, movePos, 20); |
4113 | + } else { |
4114 | + UCTestExtras::touchPress(0, bottomEdge, from); |
4115 | + QPoint movePos(from); |
4116 | + while (movePos.y() > to.y() && !exitRegion.count()) { |
4117 | + QTest::qWait(20); |
4118 | + UCTestExtras::touchMove(0, bottomEdge, movePos); |
4119 | + movePos += QPoint(0, -10); |
4120 | + } |
4121 | + QTest::qWait(20); |
4122 | + UCTestExtras::touchRelease(0, bottomEdge, movePos); |
4123 | + } |
4124 | + |
4125 | + QVERIFY(!bottomEdge->activeRegion()); |
4126 | + // we should be collapsing! |
4127 | + QTRY_COMPARE_WITH_TIMEOUT(bottomEdge->status(), UCBottomEdge::Hidden, 1000); |
4128 | + } |
4129 | + |
4130 | + void test_commit_region_content_data() |
4131 | + { |
4132 | + QTest::addColumn<bool>("withMouse"); |
4133 | + |
4134 | + QTest::newRow("with mouse") << true; |
4135 | + QTest::newRow("with touch") << false; |
4136 | + } |
4137 | + void test_commit_region_content() |
4138 | + { |
4139 | + QFETCH(bool, withMouse); |
4140 | + |
4141 | + QScopedPointer<BottomEdgeTestCase> test(new BottomEdgeTestCase("AlternateRegionContent.qml")); |
4142 | + UCBottomEdge *bottomEdge = test->testItem(); |
4143 | + UCBottomEdgePrivate *privateBottomEdge = UCBottomEdgePrivate::get(bottomEdge); |
4144 | + UCBottomEdgeRegion *region = privateBottomEdge->regions[0]; |
4145 | + |
4146 | + // alter region for testing |
4147 | + region->m_from = 0.1; |
4148 | + region->m_to = 0.8; |
4149 | + // and connect commit to dragEnded |
4150 | + connect(region, &UCBottomEdgeRegion::dragEnded, bottomEdge, &UCBottomEdge::commit); |
4151 | + |
4152 | + QPoint from(bottomEdge->width() / 2.0f, bottomEdge->height() - 5); |
4153 | + QPoint to = from + QPoint(0, -(bottomEdge->parentItem()->height() - 1)); |
4154 | + |
4155 | + if (withMouse) { |
4156 | + bottomEdge->hint()->setStatus(UCBottomEdgeHint::Locked); |
4157 | + from = bottomEdge->mapToScene(from).toPoint(); |
4158 | + to = bottomEdge->mapToScene(to).toPoint(); |
4159 | + QTest::mousePress(bottomEdge->window(), Qt::LeftButton, 0, from, 20); |
4160 | + QPoint movePos(from); |
4161 | + while (movePos.y() > to.y() && !bottomEdge->activeRegion()) { |
4162 | + QTest::mouseMove(bottomEdge->window(), movePos, 20); |
4163 | + movePos += QPoint(0, -10); |
4164 | + } |
4165 | + QTest::mouseRelease(bottomEdge->window(),Qt::LeftButton, 0, movePos, 20); |
4166 | + } else { |
4167 | + UCTestExtras::touchPress(0, bottomEdge, from); |
4168 | + QPoint movePos(from); |
4169 | + while (movePos.y() > to.y() && !bottomEdge->activeRegion()) { |
4170 | + QTest::qWait(20); |
4171 | + UCTestExtras::touchMove(0, bottomEdge, movePos); |
4172 | + movePos += QPoint(0, -10); |
4173 | + } |
4174 | + QTest::qWait(20); |
4175 | + UCTestExtras::touchRelease(0, bottomEdge, movePos); |
4176 | + } |
4177 | + QTRY_COMPARE_WITH_TIMEOUT(bottomEdge->status(), UCBottomEdge::Committed, 1000); |
4178 | + QCOMPARE(bottomEdge->contentItem()->objectName(), QString("regionContent")); |
4179 | + } |
4180 | + |
4181 | + void test_overlapping_regions() |
4182 | + { |
4183 | + QString document("OverlappingRegions.qml"); |
4184 | + UbuntuTestCase::ignoreWarning(document, 34, 9, "QML BottomEdgeRegion: Region intersects the one from index 0 having from: 0.2 and to: 0.5", 1); |
4185 | + UbuntuTestCase::ignoreWarning(document, 37, 9, "QML BottomEdgeRegion: Region intersects the one from index 0 having from: 0.2 and to: 0.5", 1); |
4186 | + UbuntuTestCase::ignoreWarning(document, 37, 9, "QML BottomEdgeRegion: Region at index 1 contains this region. This region will never activate.", 1); |
4187 | + UbuntuTestCase::ignoreWarning(document, 41, 9, "QML BottomEdgeRegion: Region at index 1 contains this region. This region will never activate.", 1); |
4188 | + QScopedPointer<BottomEdgeTestCase> test(new BottomEdgeTestCase(document)); |
4189 | + } |
4190 | + |
4191 | + void test_region_does_not_activate_when_from_greater_than_to_data() |
4192 | + { |
4193 | + QTest::addColumn<bool>("withMouse"); |
4194 | + |
4195 | + QTest::newRow("with mouse") << true; |
4196 | + QTest::newRow("with touch") << false; |
4197 | + } |
4198 | + void test_region_does_not_activate_when_from_greater_than_to() |
4199 | + { |
4200 | + QFETCH(bool, withMouse); |
4201 | + |
4202 | + QScopedPointer<BottomEdgeTestCase> test(new BottomEdgeTestCase("AlternateRegionContent.qml")); |
4203 | + UCBottomEdge *bottomEdge = test->testItem(); |
4204 | + UCBottomEdgePrivate *privateBottomEdge = UCBottomEdgePrivate::get(bottomEdge); |
4205 | + UCBottomEdgeRegion *region = privateBottomEdge->regions[0]; |
4206 | + |
4207 | + // adjust region data for the test |
4208 | + region->m_from = 0.4; |
4209 | + region->m_to = 0.2; |
4210 | + QPoint from(bottomEdge->width() / 2.0f, bottomEdge->height() - 5); |
4211 | + QPoint delta(0, -(bottomEdge->height() / 2.0f)); |
4212 | + QSignalSpy activeRegion(bottomEdge, SIGNAL(activeRegionChanged(UCBottomEdgeRegion*))); |
4213 | + if (withMouse) { |
4214 | + bottomEdge->hint()->setStatus(UCBottomEdgeHint::Locked); |
4215 | + UCTestExtras::mouseDrag(bottomEdge, from, delta, Qt::LeftButton, 0, 10); |
4216 | + } else { |
4217 | + UCTestExtras::touchDrag(0, bottomEdge, from, delta, 10); |
4218 | + } |
4219 | + QEXPECT_FAIL(0, "region should not activate", Continue); |
4220 | + QVERIFY(activeRegion.wait(400)); |
4221 | + } |
4222 | + |
4223 | + void test_autocollapse_navigation_action_on_commit_completed_data() |
4224 | + { |
4225 | + QTest::addColumn<QString>("document"); |
4226 | + |
4227 | + QTest::newRow("content has PageHeader") << "AutoCollapseInPageHeader.qml"; |
4228 | + QTest::newRow("content is Page with PageHeader") << "AutoCollapseInPageWithPageHeader.qml"; |
4229 | + } |
4230 | + void test_autocollapse_navigation_action_on_commit_completed() |
4231 | + { |
4232 | + QFETCH(QString, document); |
4233 | + |
4234 | + QScopedPointer<BottomEdgeTestCase> test(new BottomEdgeTestCase(document)); |
4235 | + UCBottomEdge *bottomEdge = test->testItem(); |
4236 | + |
4237 | + BottomEdgeTestCase *testCase = test.data(); |
4238 | + connect(bottomEdge, &UCBottomEdge::contentItemChanged, [=]() { |
4239 | + QVERIFY(!testCase->hasContentAutoCollapse()); |
4240 | + }); |
4241 | + connect(bottomEdge, &UCBottomEdge::commitCompleted, [=]() { |
4242 | + QVERIFY(testCase->hasContentAutoCollapse()); |
4243 | + }); |
4244 | + // drag slowly |
4245 | + QPoint from(bottomEdge->width() / 2.0f, bottomEdge->height() - 5); |
4246 | + QPoint delta(0, -bottomEdge->height()); |
4247 | + UCTestExtras::touchDrag(0, bottomEdge, from, delta, 20); |
4248 | + } |
4249 | +}; |
4250 | + |
4251 | +QTEST_MAIN(tst_BottomEdge) |
4252 | + |
4253 | +#include "tst_bottomedge.moc" |
4254 | |
4255 | === added file 'tests/unit_x11/tst_bottomedge/tst_bottomedge.pro' |
4256 | --- tests/unit_x11/tst_bottomedge/tst_bottomedge.pro 1970-01-01 00:00:00 +0000 |
4257 | +++ tests/unit_x11/tst_bottomedge/tst_bottomedge.pro 2015-11-27 10:36:32 +0000 |
4258 | @@ -0,0 +1,23 @@ |
4259 | +include(../test-include.pri) |
4260 | +QT += core-private qml-private quick-private gui-private UbuntuGestures |
4261 | + |
4262 | +SOURCES += \ |
4263 | + tst_bottomedge.cpp |
4264 | + |
4265 | +DISTFILES += \ |
4266 | + Defaults.qml \ |
4267 | + DifferentSizes.qml \ |
4268 | + LastItem.qml \ |
4269 | + BottomEdgeInItem.qml \ |
4270 | + ShorterBottomEdge.qml \ |
4271 | + AlternateRegionContent.qml \ |
4272 | + AddCustomRegionUsingRegionsProperty.qml \ |
4273 | + AddCustomRegionUsingDataProperty.qml \ |
4274 | + AddCustomRegionOnCompleted.qml \ |
4275 | + AddCustomRegionOwnedByOtherBottomEdge.qml \ |
4276 | + ClearCustomRegions.qml \ |
4277 | + AlternateDefaultRegionContent.qml \ |
4278 | + OverlappingRegions.qml \ |
4279 | + AutoCollapseInPageHeader.qml \ |
4280 | + AutoCollapseInPageWithPageHeader.qml \ |
4281 | + LeanActiveRegionChange.qml |
4282 | |
4283 | === modified file 'tests/unit_x11/unit_x11.pro' |
4284 | --- tests/unit_x11/unit_x11.pro 2015-11-09 15:46:45 +0000 |
4285 | +++ tests/unit_x11/unit_x11.pro 2015-11-27 10:36:32 +0000 |
4286 | @@ -16,4 +16,5 @@ |
4287 | tst_serviceproperties \ |
4288 | tst_subtheming \ |
4289 | tst_swipearea \ |
4290 | - tst_touchregistry |
4291 | + tst_touchregistry \ |
4292 | + tst_bottomedge |
PASSED: Continuous integration, rev:1739 jenkins. qa.ubuntu. com/job/ ubuntu- sdk-team- ubuntu- ui-toolkit- staging- ci/2524/ jenkins. qa.ubuntu. com/job/ ubuntu- sdk-team- ubuntu- ui-toolkit- staging- vivid-amd64- ci/1252 jenkins. qa.ubuntu. com/job/ ubuntu- sdk-team- ubuntu- ui-toolkit- staging- vivid-armhf- ci/1254 jenkins. qa.ubuntu. com/job/ ubuntu- sdk-team- ubuntu- ui-toolkit- staging- vivid-armhf- ci/1254/ artifact/ work/output/ *zip*/output. zip jenkins. qa.ubuntu. com/job/ ubuntu- sdk-team- ubuntu- ui-toolkit- staging- vivid-i386- ci/1251
http://
Executed test runs:
SUCCESS: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
Click here to trigger a rebuild: s-jenkins. ubuntu- ci:8080/ job/ubuntu- sdk-team- ubuntu- ui-toolkit- staging- ci/2524/ rebuild
http://