1 /****************************************************************************
3 ** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
4 ** All rights reserved.
5 ** Contact: Nokia Corporation (qt-info@nokia.com)
7 ** This file is part of the Qt Components project.
9 ** $QT_BEGIN_LICENSE:BSD$
10 ** You may use this file under the terms of the BSD license as follows:
12 ** "Redistribution and use in source and binary forms, with or without
13 ** modification, are permitted provided that the following conditions are
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
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
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."
39 ****************************************************************************/
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
57 // Symbian specific signals and properties
58 signal platformReleased
59 signal platformPressAndHold
62 property bool platformInverted: false
63 property bool platformAutoRepeat: true
65 implicitWidth: Math.max(container.contentWidth + 2 * internal.horizontalPadding, privateStyle.buttonSize)
66 implicitHeight: Math.max(container.contentHeight + 2 * internal.verticalPadding, privateStyle.buttonSize)
70 objectName: "internal"
72 property int autoRepeatInterval: 60
73 property int verticalPadding: (privateStyle.buttonSize - platformStyle.graphicSizeSmall) / 2
74 property int horizontalPadding: label.text ? platformStyle.paddingLarge : verticalPadding
76 // "pressed" is a transient state, see press() function
78 if (belongsToButtonRow())
79 return parent.privateModeName(button, 0)
80 else if (!button.enabled)
82 else if (button.checked)
88 function toggleChecked() {
94 if (!belongsToButtonGroup()) {
95 if (checkable && checked)
96 privateStyle.play(Android.SensitiveButton)
98 privateStyle.play(Android.BasicButton)
99 } else if (checkable && !checked) {
100 privateStyle.play(Android.BasicButton)
102 highlight.source = privateStyle.imagePath(internal.imageName() + "pressed",
103 button.platformInverted)
104 container.scale = 0.95
105 highlight.opacity = 1
110 highlight.opacity = 0
111 if (tapRepeatTimer.running)
112 tapRepeatTimer.stop()
113 button.platformReleased()
117 if ((checkable && checked && !belongsToButtonGroup()) || !checkable)
118 privateStyle.play(Android.BasicButton)
119 internal.toggleChecked()
120 clickedEffect.restart()
126 privateStyle.play(Android.SensitiveButton)
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_"
140 function belongsToButtonGroup() {
142 && button.parent.hasOwnProperty("checkedButton")
143 && button.parent.exclusive
146 function belongsToButtonRow() {
148 && button.parent.hasOwnProperty("checkedButton")
149 && button.parent.hasOwnProperty("privateDirection")
150 && button.parent.privateDirection == Qt.Horizontal
151 && button.parent.children.length > 1
159 State { name: "Pressed" },
160 State { name: "AutoRepeating" },
161 State { name: "Canceled" }
167 ScriptAction { script: internal.press() }
172 ScriptAction { script: tapRepeatTimer.start() }
177 ScriptAction { script: internal.release() }
178 ScriptAction { script: internal.click() }
183 ScriptAction { script: internal.release() }
186 from: "AutoRepeating"
187 ScriptAction { script: internal.release() }
193 source: privateStyle.imagePath(internal.imageName() + internal.modeName(),
194 button.platformInverted)
195 border { left: 20; top: 20; right: 20; bottom: 20 }
200 border { left: 20; top: 20; right: 20; bottom: 20 }
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
214 width: Math.min(contentWidth, button.width - 2 * internal.horizontalPadding)
215 height: Math.min(contentHeight, button.height - 2 * internal.verticalPadding)
217 anchors.centerIn: parent
221 sourceSize.width: platformStyle.graphicSizeSmall
222 sourceSize.height: platformStyle.graphicSizeSmall
224 anchors.top: parent.top
225 anchors.horizontalCenter: parent.horizontalCenter
229 elide: Text.ElideRight
230 property int textWidth: text ? privateStyle.textWidth(text, font) : 0
233 topMargin: parent.spacing
237 height: text ? privateStyle.fontHeight(font) : 0
238 horizontalAlignment: Text.AlignHCenter
239 verticalAlignment: Text.AlignVCenter
240 font { family: platformStyle.fontFamilyRegular; pixelSize: platformStyle.fontSizeLarge }
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
252 return button.platformInverted ? platformStyle.colorNormalLightInverted
253 : platformStyle.colorNormalLight
263 onPressed: stateGroup.state = "Pressed"
265 onReleased: stateGroup.state = ""
269 stateGroup.state = "Canceled"
270 // Reset state. Can't expect a release since mouse was ungrabbed
271 stateGroup.state = ""
275 if (stateGroup.state != "Canceled" && platformAutoRepeat)
276 stateGroup.state = "AutoRepeating"
277 button.platformPressAndHold()
280 onExited: stateGroup.state = "Canceled"
286 interval: internal.autoRepeatInterval; running: false; repeat: true
287 onTriggered: internal.repeat()
297 easing.type: Easing.Linear
305 easing.type: Easing.Linear
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
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