libandroidplugin added
[mardrone] / mardrone / imports / com / nokia / android.1.1 / Button.qml
1 /****************************************************************************
2 **
3 ** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
4 ** All rights reserved.
5 ** Contact: Nokia Corporation (qt-info@nokia.com)
6 **
7 ** This file is part of the Qt Components project.
8 **
9 ** $QT_BEGIN_LICENSE:BSD$
10 ** You may use this file under the terms of the BSD license as follows:
11 **
12 ** "Redistribution and use in source and binary forms, with or without
13 ** modification, are permitted provided that the following conditions are
14 ** met:
15 **   * Redistributions of source code must retain the above copyright
16 **     notice, this list of conditions and the following disclaimer.
17 **   * Redistributions in binary form must reproduce the above copyright
18 **     notice, this list of conditions and the following disclaimer in
19 **     the documentation and/or other materials provided with the
20 **     distribution.
21 **   * Neither the name of Nokia Corporation and its Subsidiary(-ies) nor
22 **     the names of its contributors may be used to endorse or promote
23 **     products derived from this software without specific prior written
24 **     permission.
25 **
26 ** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
27 ** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
28 ** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
29 ** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
30 ** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
31 ** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
32 ** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
33 ** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
34 ** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
35 ** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
36 ** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
37 ** $QT_END_LICENSE$
38 **
39 ****************************************************************************/
40
41 import QtQuick 1.1
42 import "." 1.1
43
44 Item {
45     id: button
46
47     // Common Public API
48     property bool checked: false
49     property bool checkable: false
50     property bool pressed: (stateGroup.state == "Pressed" || stateGroup.state == "AutoRepeating") && mouseArea.containsMouse
51     property alias text: label.text
52     property alias iconSource: icon.source
53     property alias font: label.font
54
55     signal clicked
56
57     // Symbian specific signals and properties
58     signal platformReleased
59     signal platformPressAndHold
60
61     // specific API
62     property bool platformInverted: false
63     property bool platformAutoRepeat: true
64
65     implicitWidth: Math.max(container.contentWidth + 2 * internal.horizontalPadding, privateStyle.buttonSize)
66     implicitHeight: Math.max(container.contentHeight + 2 * internal.verticalPadding, privateStyle.buttonSize)
67
68     QtObject {
69         id: internal
70         objectName: "internal"
71
72         property int autoRepeatInterval: 60
73         property int verticalPadding: (privateStyle.buttonSize - platformStyle.graphicSizeSmall) / 2
74         property int horizontalPadding: label.text ? platformStyle.paddingLarge : verticalPadding
75
76         // "pressed" is a transient state, see press() function
77         function modeName() {
78             if (belongsToButtonRow())
79                 return parent.privateModeName(button, 0)
80             else if (!button.enabled)
81                 return "disabled"
82             else if (button.checked)
83                 return "latched"
84             else
85                 return "normal"
86         }
87
88         function toggleChecked() {
89             if (checkable)
90                 checked = !checked
91         }
92
93         function press() {
94             if (!belongsToButtonGroup()) {
95                 if (checkable && checked)
96                     privateStyle.play(Android.SensitiveButton)
97                 else
98                     privateStyle.play(Android.BasicButton)
99             } else if (checkable && !checked) {
100                 privateStyle.play(Android.BasicButton)
101             }
102             highlight.source = privateStyle.imagePath(internal.imageName() + "pressed",
103                                                       button.platformInverted)
104             container.scale = 0.95
105             highlight.opacity = 1
106         }
107
108         function release() {
109             container.scale = 1
110             highlight.opacity = 0
111             if (tapRepeatTimer.running)
112                 tapRepeatTimer.stop()
113             button.platformReleased()
114         }
115
116         function click() {
117             if ((checkable && checked && !belongsToButtonGroup()) || !checkable)
118                 privateStyle.play(Android.BasicButton)
119             internal.toggleChecked()
120             clickedEffect.restart()
121             button.clicked()
122         }
123
124         function repeat() {
125             if (!checkable)
126                 privateStyle.play(Android.SensitiveButton)
127             button.clicked()
128         }
129
130         // The function imageName() handles fetching correct graphics for the Button.
131         // If the parent of a Button is ButtonRow, segmented-style graphics are used to create a
132         // seamless row of buttons. Otherwise normal Button graphics are utilized.
133         function imageName() {
134             var mirror = button.LayoutMirroring.enabled // To create binding
135             if (belongsToButtonRow())
136                 return parent.privateGraphicsName(button, 0)
137             return "qtg_fr_pushbutton_"
138         }
139
140         function belongsToButtonGroup() {
141             return button.parent
142                    && button.parent.hasOwnProperty("checkedButton")
143                    && button.parent.exclusive
144         }
145
146         function belongsToButtonRow() {
147             return button.parent
148                     && button.parent.hasOwnProperty("checkedButton")
149                     && button.parent.hasOwnProperty("privateDirection")
150                     && button.parent.privateDirection == Qt.Horizontal
151                     && button.parent.children.length > 1
152         }
153     }
154
155     StateGroup {
156         id: stateGroup
157
158         states: [
159             State { name: "Pressed" },
160             State { name: "AutoRepeating" },
161             State { name: "Canceled" }
162         ]
163
164         transitions: [
165             Transition {
166                 to: "Pressed"
167                 ScriptAction { script: internal.press() }
168             },
169             Transition {
170                 from: "Pressed"
171                 to: "AutoRepeating"
172                 ScriptAction { script: tapRepeatTimer.start() }
173             },
174             Transition {
175                 from: "Pressed"
176                 to: ""
177                 ScriptAction { script: internal.release() }
178                 ScriptAction { script: internal.click() }
179             },
180             Transition {
181                 from: "Pressed"
182                 to: "Canceled"
183                 ScriptAction { script: internal.release() }
184             },
185             Transition {
186                 from: "AutoRepeating"
187                 ScriptAction { script: internal.release() }
188             }
189         ]
190     }
191
192     BorderImage {
193         source: privateStyle.imagePath(internal.imageName() + internal.modeName(),
194                                        button.platformInverted)
195         border { left: 20; top: 20; right: 20; bottom: 20 }
196         anchors.fill: parent
197
198         BorderImage {
199             id: highlight
200             border { left: 20; top: 20; right: 20; bottom: 20 }
201             opacity: 0
202             anchors.fill: parent
203         }
204     }
205
206     Item {
207         id: container
208
209         // Having both icon and text simultaneously is unspecified but supported by implementation
210         property int spacing: (icon.height && label.text) ? platformStyle.paddingSmall : 0
211         property int contentWidth: Math.max(icon.width, label.textWidth)
212         property int contentHeight: icon.height + spacing + label.height
213
214         width: Math.min(contentWidth, button.width - 2 * internal.horizontalPadding)
215         height: Math.min(contentHeight, button.height - 2 * internal.verticalPadding)
216         clip: true
217         anchors.centerIn: parent
218
219         Image {
220             id: icon
221             sourceSize.width: platformStyle.graphicSizeSmall
222             sourceSize.height: platformStyle.graphicSizeSmall
223             smooth: true
224             anchors.top: parent.top
225             anchors.horizontalCenter: parent.horizontalCenter
226         }
227         Text {
228             id: label
229             elide: Text.ElideRight
230             property int textWidth: text ? privateStyle.textWidth(text, font) : 0
231             anchors {
232                 top: icon.bottom
233                 topMargin: parent.spacing
234                 left: parent.left
235                 right: parent.right
236             }
237             height: text ? privateStyle.fontHeight(font) : 0
238             horizontalAlignment: Text.AlignHCenter
239             verticalAlignment: Text.AlignVCenter
240             font { family: platformStyle.fontFamilyRegular; pixelSize: platformStyle.fontSizeLarge }
241             color: {
242                 if (!button.enabled)
243                     return button.platformInverted ? platformStyle.colorDisabledLightInverted
244                                                    : platformStyle.colorDisabledLight
245                 else if (button.pressed)
246                     return button.platformInverted ? platformStyle.colorPressedInverted
247                                                    : platformStyle.colorPressed
248                 else if (button.checked)
249                     return button.platformInverted ? platformStyle.colorLatchedInverted
250                                                    : platformStyle.colorLatched
251                 else
252                     return button.platformInverted ? platformStyle.colorNormalLightInverted
253                                                    : platformStyle.colorNormalLight
254             }
255         }
256     }
257
258     MouseArea {
259         id: mouseArea
260
261         anchors.fill: parent
262
263         onPressed: stateGroup.state = "Pressed"
264
265         onReleased: stateGroup.state = ""
266
267         onCanceled: {
268             // Mark as canceled
269             stateGroup.state = "Canceled"
270             // Reset state. Can't expect a release since mouse was ungrabbed
271             stateGroup.state = ""
272         }
273
274         onPressAndHold: {
275             if (stateGroup.state != "Canceled" && platformAutoRepeat)
276                 stateGroup.state = "AutoRepeating"
277             button.platformPressAndHold()
278         }
279
280         onExited: stateGroup.state = "Canceled"
281     }
282
283     Timer {
284         id: tapRepeatTimer
285
286         interval: internal.autoRepeatInterval; running: false; repeat: true
287         onTriggered: internal.repeat()
288     }
289
290     ParallelAnimation {
291         id: clickedEffect
292         PropertyAnimation {
293             target: container
294             property: "scale"
295             from: 0.95
296             to: 1.0
297             easing.type: Easing.Linear
298             duration: 100
299         }
300         PropertyAnimation {
301             target: highlight
302             property: "opacity"
303             from: 1
304             to: 0
305             easing.type: Easing.Linear
306             duration: 150
307         }
308     }
309
310     Keys.onPressed: {
311         if ((!event.isAutoRepeat || platformAutoRepeat)
312             && (event.key == Qt.Key_Select || event.key == Qt.Key_Return || event.key == Qt.Key_Enter)) {
313             stateGroup.state = "Pressed"
314             event.accepted = true
315         }
316     }
317
318     Keys.onReleased: {
319         if ((!event.isAutoRepeat || platformAutoRepeat)
320             && (event.key == Qt.Key_Select || event.key == Qt.Key_Return || event.key == Qt.Key_Enter)) {
321             stateGroup.state = ""
322             event.accepted = true
323         }
324     }
325 }