--- /dev/null
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the Qt Components project.
+**
+** $QT_BEGIN_LICENSE:BSD$
+** You may use this file under the terms of the BSD license as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions and the following disclaimer in
+** the documentation and/or other materials provided with the
+** distribution.
+** * Neither the name of Nokia Corporation and its Subsidiary(-ies) nor
+** the names of its contributors may be used to endorse or promote
+** products derived from this software without specific prior written
+** permission.
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+function rootObject() {
+ var next = parent
+ while (next && next.parent)
+ next = next.parent
+ return next
+}
+
+function findParent(child, propertyName) {
+ if (!child)
+ return null
+ var next = child.parent
+ while (next && !next.hasOwnProperty(propertyName))
+ next = next.parent
+ return next
+}
+
+function sceneX(item) {
+ // Binding may cause that this function is evaluated even when item is undefined,
+ // but in that case the Binding isn't active however so we can safely return 0
+ var x = 0
+ if (item) {
+ x = item.x
+ var p = item.parent
+ while (p) {
+ x += p.x
+ p = p.parent
+ }
+ }
+ return x
+}
+
+function sceneY(item) {
+ // Binding may cause that this function is evaluated even when item is undefined,
+ // but in that case the Binding isn't active however so we can safely return 0
+ var y = 0
+ if (item) {
+ y = item.y
+ var p = item.parent
+ while (p) {
+ y += p.y
+ p = p.parent
+ }
+ }
+ return y
+}
--- /dev/null
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the Qt Components project.
+**
+** $QT_BEGIN_LICENSE:BSD$
+** You may use this file under the terms of the BSD license as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions and the following disclaimer in
+** the documentation and/or other materials provided with the
+** distribution.
+** * Neither the name of Nokia Corporation and its Subsidiary(-ies) nor
+** the names of its contributors may be used to endorse or promote
+** products derived from this software without specific prior written
+** permission.
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick 1.1
+import "." 1.1
+
+Window {
+ id: root
+
+ property bool fullScreen: false
+ default property alias content: contentItem.data
+ property alias pageStack: stack
+ property variant initialPage
+ property bool softwareInputPanelEnabled: false
+
+ onInitialPageChanged: {
+ if (initialPage && contentArea.initialized) {
+ if (stack.depth == 0)
+ stack.push(initialPage, null, true)
+ else if (stack.depth == 1)
+ stack.replace(initialPage, null, true)
+ else
+ console.log("Cannot update ApplicationWindow.initialPage")
+ }
+ }
+
+ Component.onCompleted: {
+ console.log("warning: ApplicationWindow is an experimental component. Use Window instead.")
+ contentArea.initialized = true
+ if (initialPage && stack.depth == 0)
+ stack.push(initialPage, null, true)
+ }
+
+ Item {
+ id: contentArea
+
+ property bool initialized: false
+
+ anchors.top: sbar.bottom
+ anchors.bottom: sip.top
+ anchors.left: parent.left
+ anchors.right: parent.right
+ Item {
+ id: contentItem
+ anchors.fill: parent
+ PageStack {
+ id: stack
+ anchors.fill: parent
+ toolBar: tbar
+ }
+ }
+ }
+
+ StatusBar {
+ id: sbar
+
+ width: parent.width
+ state: root.fullScreen ? "Hidden" : "Visible"
+ platformInverted: root.platformInverted
+
+ states: [
+ State {
+ name: "Visible"
+ PropertyChanges { target: sbar; y: 0; opacity: 1 }
+ },
+ State {
+ name: "Hidden"
+ PropertyChanges { target: sbar; y: -height; opacity: 0 }
+ }
+ ]
+
+ transitions: [
+ Transition {
+ from: "Hidden"; to: "Visible"
+ ParallelAnimation {
+ NumberAnimation { target: sbar; properties: "y"; duration: 200; easing.type: Easing.OutQuad }
+ NumberAnimation { target: sbar; properties: "opacity"; duration: 200; easing.type: Easing.Linear }
+ }
+ },
+ Transition {
+ from: "Visible"; to: "Hidden"
+ ParallelAnimation {
+ NumberAnimation { target: sbar; properties: "y"; duration: 200; easing.type: Easing.Linear }
+ NumberAnimation { target: sbar; properties: "opacity"; duration: 200; easing.type: Easing.Linear }
+ }
+ }
+ ]
+ }
+
+ Item {
+ id: sip
+
+ anchors { bottom: parent.bottom; left: parent.left; right: parent.right }
+
+ Behavior on height { PropertyAnimation { duration: 200 } }
+
+ states: [
+ State {
+ name: "Visible"; when: inputContext.visible && softwareInputPanelEnabled
+ PropertyChanges { target: sip; height: inputContext.height }
+ },
+
+ State {
+ name: "Hidden"; when: !root.fullScreen
+ PropertyChanges { target: sip; height: tbar.height }
+ },
+
+ State {
+ name: "HiddenInFullScreen"; when: root.fullScreen
+ PropertyChanges { target: sip; height: 0 }
+ }
+ ]
+ }
+
+ ToolBar {
+ id: tbar
+
+ width: parent.width
+ state: root.fullScreen ? "Hidden" : "Visible"
+ platformInverted: root.platformInverted
+
+ states: [
+ State {
+ name: "Visible"
+ PropertyChanges { target: tbar; y: parent.height - height; opacity: 1 }
+ },
+ State {
+ name: "Hidden"
+ PropertyChanges { target: tbar; y: parent.height; opacity: 0 }
+ }
+ ]
+
+ transitions: [
+ Transition {
+ from: "Hidden"; to: "Visible"
+ ParallelAnimation {
+ NumberAnimation { target: tbar; properties: "y"; duration: 200; easing.type: Easing.OutQuad }
+ NumberAnimation { target: tbar; properties: "opacity"; duration: 200; easing.type: Easing.Linear }
+ }
+ },
+ Transition {
+ from: "Visible"; to: "Hidden"
+ ParallelAnimation {
+ NumberAnimation { target: tbar; properties: "y"; duration: 200; easing.type: Easing.Linear }
+ NumberAnimation { target: tbar; properties: "opacity"; duration: 200; easing.type: Easing.Linear }
+ }
+ }
+ ]
+ }
+
+ // event preventer when page transition is active
+ MouseArea {
+ anchors.fill: parent
+ enabled: pageStack.busy
+ }
+}
--- /dev/null
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the Qt Components project.
+**
+** $QT_BEGIN_LICENSE:BSD$
+** You may use this file under the terms of the BSD license as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions and the following disclaimer in
+** the documentation and/or other materials provided with the
+** distribution.
+** * Neither the name of Nokia Corporation and its Subsidiary(-ies) nor
+** the names of its contributors may be used to endorse or promote
+** products derived from this software without specific prior written
+** permission.
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick 1.1
+import com.nokia.android 1.1
+import "." 1.1
+
+Item {
+ id: root
+
+ property bool running: false
+
+ // Symbian specific API
+ property bool platformInverted: false
+
+ implicitWidth: platformStyle.graphicSizeSmall
+ implicitHeight: platformStyle.graphicSizeSmall
+
+ Image {
+ id: spinner
+ property int index: 1
+
+ // cannot use anchors.fill here because the size will be 0 during
+ // construction and that gives out nasty debug warnings
+ width: parent.width
+ height: parent.height
+ sourceSize.width: width
+ sourceSize.height: height
+ source: privateStyle.imagePath("qtg_anim_spinner_large_" + index,
+ root.platformInverted)
+ smooth: true
+
+ NumberAnimation on index {
+ id: numAni
+ from: 1; to: 10
+ duration: 1000
+ running: root.visible
+ // QTBUG-19080 is preventing the following line from working
+ // We will have to use workaround for now
+ // http://bugreports.qt.nokia.com/browse/QTBUG-19080
+ // paused: !root.running || !android.foreground
+ loops: Animation.Infinite
+ }
+
+ // START workaround for QTBUG-19080
+ Component {
+ id: bindingCom
+ Binding {
+ target: numAni
+ property: "paused"
+ value: numAni.running ? (!root.running || !android.foreground) : false
+ }
+ }
+ Component.onCompleted: bindingCom.createObject(numAni)
+ // END workaround
+ }
+}
--- /dev/null
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the Qt Components project.
+**
+** $QT_BEGIN_LICENSE:BSD$
+** You may use this file under the terms of the BSD license as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions and the following disclaimer in
+** the documentation and/or other materials provided with the
+** distribution.
+** * Neither the name of Nokia Corporation and its Subsidiary(-ies) nor
+** the names of its contributors may be used to endorse or promote
+** products derived from this software without specific prior written
+** permission.
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick 1.1
+import "." 1.1
+
+Item {
+ id: button
+
+ // Common Public API
+ property bool checked: false
+ property bool checkable: false
+ property bool pressed: (stateGroup.state == "Pressed" || stateGroup.state == "AutoRepeating") && mouseArea.containsMouse
+ property alias text: label.text
+ property alias iconSource: icon.source
+ property alias font: label.font
+
+ signal clicked
+
+ // Symbian specific signals and properties
+ signal platformReleased
+ signal platformPressAndHold
+
+ // specific API
+ property bool platformInverted: false
+ property bool platformAutoRepeat: true
+
+ implicitWidth: Math.max(container.contentWidth + 2 * internal.horizontalPadding, privateStyle.buttonSize)
+ implicitHeight: Math.max(container.contentHeight + 2 * internal.verticalPadding, privateStyle.buttonSize)
+
+ QtObject {
+ id: internal
+ objectName: "internal"
+
+ property int autoRepeatInterval: 60
+ property int verticalPadding: (privateStyle.buttonSize - platformStyle.graphicSizeSmall) / 2
+ property int horizontalPadding: label.text ? platformStyle.paddingLarge : verticalPadding
+
+ // "pressed" is a transient state, see press() function
+ function modeName() {
+ if (belongsToButtonRow())
+ return parent.privateModeName(button, 0)
+ else if (!button.enabled)
+ return "disabled"
+ else if (button.checked)
+ return "latched"
+ else
+ return "normal"
+ }
+
+ function toggleChecked() {
+ if (checkable)
+ checked = !checked
+ }
+
+ function press() {
+ if (!belongsToButtonGroup()) {
+ if (checkable && checked)
+ privateStyle.play(Android.SensitiveButton)
+ else
+ privateStyle.play(Android.BasicButton)
+ } else if (checkable && !checked) {
+ privateStyle.play(Android.BasicButton)
+ }
+ highlight.source = privateStyle.imagePath(internal.imageName() + "pressed",
+ button.platformInverted)
+ container.scale = 0.95
+ highlight.opacity = 1
+ }
+
+ function release() {
+ container.scale = 1
+ highlight.opacity = 0
+ if (tapRepeatTimer.running)
+ tapRepeatTimer.stop()
+ button.platformReleased()
+ }
+
+ function click() {
+ if ((checkable && checked && !belongsToButtonGroup()) || !checkable)
+ privateStyle.play(Android.BasicButton)
+ internal.toggleChecked()
+ clickedEffect.restart()
+ button.clicked()
+ }
+
+ function repeat() {
+ if (!checkable)
+ privateStyle.play(Android.SensitiveButton)
+ button.clicked()
+ }
+
+ // The function imageName() handles fetching correct graphics for the Button.
+ // If the parent of a Button is ButtonRow, segmented-style graphics are used to create a
+ // seamless row of buttons. Otherwise normal Button graphics are utilized.
+ function imageName() {
+ var mirror = button.LayoutMirroring.enabled // To create binding
+ if (belongsToButtonRow())
+ return parent.privateGraphicsName(button, 0)
+ return "qtg_fr_pushbutton_"
+ }
+
+ function belongsToButtonGroup() {
+ return button.parent
+ && button.parent.hasOwnProperty("checkedButton")
+ && button.parent.exclusive
+ }
+
+ function belongsToButtonRow() {
+ return button.parent
+ && button.parent.hasOwnProperty("checkedButton")
+ && button.parent.hasOwnProperty("privateDirection")
+ && button.parent.privateDirection == Qt.Horizontal
+ && button.parent.children.length > 1
+ }
+ }
+
+ StateGroup {
+ id: stateGroup
+
+ states: [
+ State { name: "Pressed" },
+ State { name: "AutoRepeating" },
+ State { name: "Canceled" }
+ ]
+
+ transitions: [
+ Transition {
+ to: "Pressed"
+ ScriptAction { script: internal.press() }
+ },
+ Transition {
+ from: "Pressed"
+ to: "AutoRepeating"
+ ScriptAction { script: tapRepeatTimer.start() }
+ },
+ Transition {
+ from: "Pressed"
+ to: ""
+ ScriptAction { script: internal.release() }
+ ScriptAction { script: internal.click() }
+ },
+ Transition {
+ from: "Pressed"
+ to: "Canceled"
+ ScriptAction { script: internal.release() }
+ },
+ Transition {
+ from: "AutoRepeating"
+ ScriptAction { script: internal.release() }
+ }
+ ]
+ }
+
+ BorderImage {
+ source: privateStyle.imagePath(internal.imageName() + internal.modeName(),
+ button.platformInverted)
+ border { left: 20; top: 20; right: 20; bottom: 20 }
+ anchors.fill: parent
+
+ BorderImage {
+ id: highlight
+ border { left: 20; top: 20; right: 20; bottom: 20 }
+ opacity: 0
+ anchors.fill: parent
+ }
+ }
+
+ Item {
+ id: container
+
+ // Having both icon and text simultaneously is unspecified but supported by implementation
+ property int spacing: (icon.height && label.text) ? platformStyle.paddingSmall : 0
+ property int contentWidth: Math.max(icon.width, label.textWidth)
+ property int contentHeight: icon.height + spacing + label.height
+
+ width: Math.min(contentWidth, button.width - 2 * internal.horizontalPadding)
+ height: Math.min(contentHeight, button.height - 2 * internal.verticalPadding)
+ clip: true
+ anchors.centerIn: parent
+
+ Image {
+ id: icon
+ sourceSize.width: platformStyle.graphicSizeSmall
+ sourceSize.height: platformStyle.graphicSizeSmall
+ smooth: true
+ anchors.top: parent.top
+ anchors.horizontalCenter: parent.horizontalCenter
+ }
+ Text {
+ id: label
+ elide: Text.ElideRight
+ property int textWidth: text ? privateStyle.textWidth(text, font) : 0
+ anchors {
+ top: icon.bottom
+ topMargin: parent.spacing
+ left: parent.left
+ right: parent.right
+ }
+ height: text ? privateStyle.fontHeight(font) : 0
+ horizontalAlignment: Text.AlignHCenter
+ verticalAlignment: Text.AlignVCenter
+ font { family: platformStyle.fontFamilyRegular; pixelSize: platformStyle.fontSizeLarge }
+ color: {
+ if (!button.enabled)
+ return button.platformInverted ? platformStyle.colorDisabledLightInverted
+ : platformStyle.colorDisabledLight
+ else if (button.pressed)
+ return button.platformInverted ? platformStyle.colorPressedInverted
+ : platformStyle.colorPressed
+ else if (button.checked)
+ return button.platformInverted ? platformStyle.colorLatchedInverted
+ : platformStyle.colorLatched
+ else
+ return button.platformInverted ? platformStyle.colorNormalLightInverted
+ : platformStyle.colorNormalLight
+ }
+ }
+ }
+
+ MouseArea {
+ id: mouseArea
+
+ anchors.fill: parent
+
+ onPressed: stateGroup.state = "Pressed"
+
+ onReleased: stateGroup.state = ""
+
+ onCanceled: {
+ // Mark as canceled
+ stateGroup.state = "Canceled"
+ // Reset state. Can't expect a release since mouse was ungrabbed
+ stateGroup.state = ""
+ }
+
+ onPressAndHold: {
+ if (stateGroup.state != "Canceled" && platformAutoRepeat)
+ stateGroup.state = "AutoRepeating"
+ button.platformPressAndHold()
+ }
+
+ onExited: stateGroup.state = "Canceled"
+ }
+
+ Timer {
+ id: tapRepeatTimer
+
+ interval: internal.autoRepeatInterval; running: false; repeat: true
+ onTriggered: internal.repeat()
+ }
+
+ ParallelAnimation {
+ id: clickedEffect
+ PropertyAnimation {
+ target: container
+ property: "scale"
+ from: 0.95
+ to: 1.0
+ easing.type: Easing.Linear
+ duration: 100
+ }
+ PropertyAnimation {
+ target: highlight
+ property: "opacity"
+ from: 1
+ to: 0
+ easing.type: Easing.Linear
+ duration: 150
+ }
+ }
+
+ Keys.onPressed: {
+ if ((!event.isAutoRepeat || platformAutoRepeat)
+ && (event.key == Qt.Key_Select || event.key == Qt.Key_Return || event.key == Qt.Key_Enter)) {
+ stateGroup.state = "Pressed"
+ event.accepted = true
+ }
+ }
+
+ Keys.onReleased: {
+ if ((!event.isAutoRepeat || platformAutoRepeat)
+ && (event.key == Qt.Key_Select || event.key == Qt.Key_Return || event.key == Qt.Key_Enter)) {
+ stateGroup.state = ""
+ event.accepted = true
+ }
+ }
+}
--- /dev/null
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the Qt Components project.
+**
+** $QT_BEGIN_LICENSE:BSD$
+** You may use this file under the terms of the BSD license as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions and the following disclaimer in
+** the documentation and/or other materials provided with the
+** distribution.
+** * Neither the name of Nokia Corporation and its Subsidiary(-ies) nor
+** the names of its contributors may be used to endorse or promote
+** products derived from this software without specific prior written
+** permission.
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick 1.1
+import "ButtonGroup.js" as Engine
+
+Column {
+ id: root
+
+ // Common public API
+ property bool exclusive: true
+ property Item checkedButton
+
+ property int privateDirection: Qt.Vertical
+
+ Component.onCompleted: Engine.create(root)
+ Component.onDestruction: Engine.destroy()
+}
--- /dev/null
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the Qt Components project.
+**
+** $QT_BEGIN_LICENSE:BSD$
+** You may use this file under the terms of the BSD license as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions and the following disclaimer in
+** the documentation and/or other materials provided with the
+** distribution.
+** * Neither the name of Nokia Corporation and its Subsidiary(-ies) nor
+** the names of its contributors may be used to endorse or promote
+** products derived from this software without specific prior written
+** permission.
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+var self
+var clickHandlers = []
+var visibleButtons = []
+var resizing = false
+var checkingOverallExclusivity = false
+var checkedBtn
+
+function create(that) {
+ destroy()
+ self = that
+
+ // If the item is not visible at this stage, we store the value of the property
+ // checkedButton to ensure a proper initialization. The value is restored in
+ // initCheckedButton().
+ if (!self.visible)
+ checkedBtn = self.checkedButton
+
+ buildItems()
+ self.childrenChanged.connect(buildItems)
+ self.widthChanged.connect(resizeButtons)
+ self.exclusiveChanged.connect(checkOverallExclusivity)
+ self.checkedButtonChanged.connect(checkOverallExclusivity)
+ self.visibleChanged.connect(initCheckedButton)
+}
+
+function destroy() {
+ if (self !== undefined) {
+ self.childrenChanged.disconnect(buildItems)
+ self.widthChanged.disconnect(resizeButtons)
+ self.exclusiveChanged.disconnect(checkOverallExclusivity)
+ self.checkedButtonChanged.disconnect(checkOverallExclusivity)
+ self.visibleChanged.disconnect(initCheckedButton)
+ releaseItemConnections()
+ self = undefined
+ }
+}
+
+function initCheckedButton() {
+ // When the item becomes visible, restore the value of checkedButton property
+ // that was stored in the create function.
+ if (self.visible && checkedBtn !== null) {
+ self.checkedButton = checkedBtn
+ checkedBtn = null
+ }
+}
+
+function buildItems() {
+ releaseItemConnections()
+ visibleButtons = []
+ for (var i = 0; i < self.children.length; i++) {
+ var item = self.children[i]
+
+ // set up item connections
+ clickHandlers[i] = checkExclusive(item)
+ item.clicked.connect(clickHandlers[i])
+ item.visibleChanged.connect(buildItems)
+
+ // update visibleButtons array
+ if (item.visible)
+ visibleButtons.push(item)
+ }
+ checkOverallExclusivity()
+ resizeButtons()
+}
+
+function releaseItemConnections() {
+ for (var i = 0; i < self.children.length; i++) {
+ self.children[i].clicked.disconnect(clickHandlers[i])
+ self.children[i].visibleChanged.disconnect(buildItems)
+ }
+ clickHandlers = []
+}
+
+function checkOverallExclusivity() {
+ if (!checkingOverallExclusivity && self.exclusive) {
+ // prevent re-entrant calls
+ checkingOverallExclusivity = true
+ if (visibleButtons.length > 0) {
+ if ((self.checkedButton === null || !self.checkedButton.visible))
+ self.checkedButton = visibleButtons[0]
+ self.checkedButton.checked = true
+ }
+ else {
+ self.checkedButton = null
+ }
+
+ for (var i = 0; i < self.children.length; i++) {
+ var item = self.children[i]
+ // e.g CheckBox can be added to ButtonGroup but doesn't have "checkable" property
+ if (self.exclusive && item.hasOwnProperty("checkable"))
+ item.checkable = true
+ if (item !== self.checkedButton)
+ item.checked = false
+ }
+ checkingOverallExclusivity = false
+ }
+}
+
+function checkExclusive(item) {
+ var button = item
+ return function() {
+ if (self.exclusive) {
+ for (var i = 0, ref; (ref = visibleButtons[i]); i++)
+ ref.checked = button === ref
+ }
+ self.checkedButton = button
+ }
+}
+
+function resizeButtons() {
+ if (!resizing && visibleButtons.length && self.privateDirection == Qt.Horizontal) {
+ // if ButtonRow has implicit size, a loop may occur where resizing individual
+ // Button affects ButtonRow size, which triggers again resizing...
+ // therefore we prevent re-entrant resizing attempts
+ resizing = true
+ var buttonWidth = self.width / visibleButtons.length
+ for (var i = 0; i < self.children.length; i++) {
+ self.children[i].width = self.children[i].visible ? buttonWidth : 0
+ }
+ resizing = false
+ }
+}
+
+// Binding would not work properly if visibleButtons would just be returned,
+// it would miss visibility changes. In the long run ButtonGroup.js could be
+// refactored.
+function visibleItems(item) {
+ var visibleChildren = []
+ for (var i = 0; i < item.children.length; i++) {
+ if (item.children[i].visible)
+ visibleChildren.push(item.children[i])
+ }
+ return visibleChildren
+}
--- /dev/null
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the Qt Components project.
+**
+** $QT_BEGIN_LICENSE:BSD$
+** You may use this file under the terms of the BSD license as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions and the following disclaimer in
+** the documentation and/or other materials provided with the
+** distribution.
+** * Neither the name of Nokia Corporation and its Subsidiary(-ies) nor
+** the names of its contributors may be used to endorse or promote
+** products derived from this software without specific prior written
+** permission.
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick 1.1
+import "ButtonGroup.js" as Engine
+
+Row {
+ id: root
+
+ // Common public API
+ property bool exclusive: true
+ property Item checkedButton
+
+ property int privateDirection: Qt.Horizontal
+
+ function privateGraphicsName(button, buttonType) {
+ var siblingButtons = Engine.visibleItems(root)
+ var imageName = ""
+ var rightToLeft = root.LayoutMirroring.enabled
+ ? (root.layoutDirection == Qt.LeftToRight)
+ : (root.layoutDirection == Qt.RightToLeft)
+ if (siblingButtons.length > 1) {
+ if (buttonType == 0)
+ imageName = "qtg_fr_pushbutton_segmented"
+ else if (buttonType == 1)
+ imageName = "qtg_fr_toolbutton_segmented"
+
+ if (button === siblingButtons[0])
+ imageName += rightToLeft ? "_r_" : "_l_"
+ else if (button === siblingButtons[siblingButtons.length - 1])
+ imageName += rightToLeft ? "_l_" : "_r_"
+ else
+ imageName += "_c_"
+ }
+ else if (buttonType == 0)
+ imageName = "qtg_fr_pushbutton_"
+ else if (buttonType == 1)
+ imageName = "qtg_fr_toolbutton_text_"
+
+ return imageName
+ }
+
+ function privateModeName(button, buttonType) {
+ var siblingButtons = Engine.visibleItems(root)
+ if (!button.enabled)
+ return "disabled"
+ else if (button.checked && siblingButtons.length > 1)
+ return "latched"
+ else
+ return "normal"
+ }
+
+ Component.onCompleted: Engine.create(root)
+ Component.onDestruction: Engine.destroy()
+}
--- /dev/null
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the Qt Components project.
+**
+** $QT_BEGIN_LICENSE:BSD$
+** You may use this file under the terms of the BSD license as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions and the following disclaimer in
+** the documentation and/or other materials provided with the
+** distribution.
+** * Neither the name of Nokia Corporation and its Subsidiary(-ies) nor
+** the names of its contributors may be used to endorse or promote
+** products derived from this software without specific prior written
+** permission.
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick 1.1
+import "." 1.1
+
+Item {
+ id: root
+
+ // Common Public API
+ property bool checked: false
+ property bool pressed: stateGroup.state == "Pressed" || stateGroup.state == "KeyPressed"
+
+ signal clicked
+
+ property alias text: label.text
+
+ // Symbian specific API
+ property bool platformInverted: false
+
+ // Performance optimization:
+ // Use value assignment when property changes instead of binding to js function
+ onCheckedChanged: { contentIcon.source = internal.iconSource() }
+ onPressedChanged: { contentIcon.source = internal.iconSource() }
+ onEnabledChanged: { contentIcon.source = internal.iconSource() }
+ onPlatformInvertedChanged: { contentIcon.source = internal.iconSource() }
+
+ QtObject {
+ id: internal
+ objectName: "internal"
+ property color disabledColor: root.platformInverted ? platformStyle.colorDisabledLightInverted
+ : platformStyle.colorDisabledLight
+ property color pressedColor: root.platformInverted ? platformStyle.colorPressedInverted
+ : platformStyle.colorPressed
+ property color normalColor: root.platformInverted ? platformStyle.colorNormalLightInverted
+ : platformStyle.colorNormalLight
+
+ function iconSource() {
+ var id
+ if (!root.enabled) {
+ if (root.checked)
+ id = "disabled_selected"
+ else
+ id = "disabled_unselected"
+ } else {
+ if (root.pressed)
+ id = "pressed"
+ else if (root.checked)
+ id = "normal_selected"
+ else
+ id = "normal_unselected"
+ }
+ return privateStyle.imagePath("qtg_graf_checkbox_" + id, root.platformInverted)
+ }
+
+ function toggle() {
+ clickedEffect.restart()
+ root.checked = !root.checked
+ root.clicked()
+ }
+ }
+
+ StateGroup {
+ id: stateGroup
+
+ states: [
+ State { name: "Pressed" },
+ State { name: "KeyPressed" },
+ State { name: "Canceled" }
+ ]
+
+ transitions: [
+ Transition {
+ to: "Pressed"
+ ScriptAction { script: privateStyle.play(Android.BasicItem) }
+ },
+ Transition {
+ from: "Pressed"
+ to: ""
+ ScriptAction { script: privateStyle.play(Android.CheckBox) }
+ ScriptAction { script: internal.toggle() }
+ },
+ Transition {
+ from: "KeyPressed"
+ to: ""
+ ScriptAction { script: internal.toggle() }
+ }
+
+ ]
+ }
+
+ implicitWidth: label.text ? privateStyle.buttonSize + platformStyle.paddingMedium + privateStyle.textWidth(label.text, label.font)
+ : privateStyle.buttonSize
+ implicitHeight: privateStyle.buttonSize
+
+ Image {
+ id: contentIcon
+ source: privateStyle.imagePath("qtg_graf_checkbox_normal_unselected", root.platformInverted);
+ anchors.left: parent.left
+ anchors.verticalCenter: parent.verticalCenter
+ sourceSize.width: privateStyle.buttonSize
+ sourceSize.height: privateStyle.buttonSize
+ smooth: true
+
+ MouseArea {
+ id: mouseArea
+ anchors.fill: parent
+
+ onPressed: stateGroup.state = "Pressed"
+ onReleased: stateGroup.state = ""
+ onClicked: stateGroup.state = ""
+ onExited: stateGroup.state = "Canceled"
+ onCanceled: {
+ // Mark as canceled
+ stateGroup.state = "Canceled"
+ // Reset state. Can't expect a release since mouse was ungrabbed
+ stateGroup.state = ""
+ }
+ }
+ }
+
+ Text {
+ id: label
+ anchors.left: contentIcon.right
+ anchors.leftMargin: text ? platformStyle.paddingMedium : 0
+ anchors.right: parent.right
+ anchors.verticalCenter: parent.verticalCenter
+ elide: Text.ElideRight
+ horizontalAlignment: Text.AlignLeft
+ font { family: platformStyle.fontFamilyRegular; pixelSize: platformStyle.fontSizeMedium }
+ color: root.enabled ? (root.pressed ? internal.pressedColor : internal.normalColor)
+ : internal.disabledColor
+ }
+
+ SequentialAnimation {
+ id: clickedEffect
+ PropertyAnimation {
+ target: contentIcon
+ property: "scale"
+ from: 1.0
+ to: 0.8
+ easing.type: Easing.Linear
+ duration: 50
+ }
+ PropertyAnimation {
+ target: contentIcon
+ property: "scale"
+ from: 0.8
+ to: 1.0
+ easing.type: Easing.OutQuad
+ duration: 170
+ }
+ }
+
+ Keys.onPressed: {
+ if (!event.isAutoRepeat && (event.key == Qt.Key_Select
+ || event.key == Qt.Key_Return
+ || event.key == Qt.Key_Enter)) {
+ stateGroup.state = "KeyPressed"
+ event.accepted = true
+ }
+ }
+
+ Keys.onReleased: {
+ if (!event.isAutoRepeat && (event.key == Qt.Key_Select
+ || event.key == Qt.Key_Return
+ || event.key == Qt.Key_Enter)) {
+ stateGroup.state = ""
+ event.accepted = true
+ }
+ }
+}
--- /dev/null
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the Qt Components project.
+**
+** $QT_BEGIN_LICENSE:BSD$
+** You may use this file under the terms of the BSD license as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions and the following disclaimer in
+** the documentation and/or other materials provided with the
+** distribution.
+** * Neither the name of Nokia Corporation and its Subsidiary(-ies) nor
+** the names of its contributors may be used to endorse or promote
+** products derived from this software without specific prior written
+** permission.
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick 1.1
+import "." 1.1
+
+Dialog {
+ id: root
+
+ property alias titleText: titleAreaText.text
+ property url titleIcon
+ property variant buttonTexts: []
+ property bool privateCloseIcon: false
+
+ signal buttonClicked(int index)
+
+ onButtonTextsChanged: {
+ for (var i = buttonRow.children.length; i > 0; --i) {
+ buttonRow.children[i - 1].destroy()
+ }
+ for (var j = 0; j < buttonTexts.length; ++j) {
+ var button = buttonComponent.createObject(buttonRow)
+ button.text = buttonTexts[j]
+ button.index = j
+ }
+ }
+
+ Component {
+ id: buttonComponent
+ ToolButton {
+ property int index
+
+ width: internal.buttonWidth()
+ height: privateStyle.toolBarHeightLandscape
+ platformInverted: root.platformInverted
+
+ onClicked: {
+ if (root.status == DialogStatus.Open) {
+ root.buttonClicked(index)
+ root.close()
+ }
+ }
+ }
+ }
+
+ QtObject {
+ id: internal
+
+ function buttonWidth() {
+ switch (buttonTexts.length) {
+ case 0: return 0
+ case 1: return Math.round((privateStyle.dialogMaxSize - 3 * platformStyle.paddingMedium) / 2)
+ default: return (buttonContainer.width - (buttonTexts.length + 1) *
+ platformStyle.paddingMedium) / buttonTexts.length
+ }
+ }
+
+ function iconSource() {
+ if (privateCloseIcon) {
+ return privateStyle.imagePath((iconMouseArea.pressed && !iconMouseArea.pressCancelled
+ ? "qtg_graf_popup_close_pressed"
+ : "qtg_graf_popup_close_normal"),
+ root.platformInverted)
+ } else {
+ return root.titleIcon
+ }
+ }
+ }
+
+ title: Item {
+ anchors.left: parent.left
+ anchors.right: parent.right
+ height: platformStyle.graphicSizeSmall + 2 * platformStyle.paddingLarge
+
+ LayoutMirroring.enabled: privateCloseIcon ? false : undefined
+ LayoutMirroring.childrenInherit: true
+
+ Item {
+ id: titleLayoutHelper // needed to make the text mirror correctly
+
+ anchors.left: parent.left
+ anchors.right: titleAreaIcon.source == "" ? parent.right : titleAreaIcon.left
+ anchors.top: parent.top
+ anchors.bottom: parent.bottom
+ anchors.margins: platformStyle.paddingLarge
+
+ Text {
+ id: titleAreaText
+
+ LayoutMirroring.enabled: root.LayoutMirroring.enabled
+
+ anchors.fill: parent
+ font { family: platformStyle.fontFamilyRegular; pixelSize: platformStyle.fontSizeLarge }
+ color: root.platformInverted ? platformStyle.colorNormalLinkInverted
+ : platformStyle.colorNormalLink
+ elide: Text.ElideRight
+ horizontalAlignment: Text.AlignLeft
+ verticalAlignment: Text.AlignVCenter
+ }
+ }
+
+ Image {
+ id: titleAreaIcon
+
+ anchors.right: parent.right
+ anchors.rightMargin: platformStyle.paddingLarge
+ anchors.verticalCenter: parent.verticalCenter
+ source: internal.iconSource()
+ sourceSize.height: platformStyle.graphicSizeSmall
+ sourceSize.width: platformStyle.graphicSizeSmall
+
+ MouseArea {
+ id: iconMouseArea
+
+ property bool pressCancelled
+
+ anchors.centerIn: parent
+ width: parent.width + 2 * platformStyle.paddingLarge
+ height: parent.height + 2 * platformStyle.paddingLarge
+ enabled: privateCloseIcon && root.status == DialogStatus.Open
+
+ onPressed: {
+ pressCancelled = false
+ privateStyle.play(Android.BasicButton)
+ }
+ onClicked: {
+ if (!pressCancelled)
+ root.reject()
+ }
+ onReleased: {
+ if (!pressCancelled)
+ privateStyle.play(Android.PopupClose)
+ }
+ onExited: pressCancelled = true
+ }
+ }
+ }
+
+ buttons: Item {
+ id: buttonContainer
+
+ LayoutMirroring.enabled: false
+ LayoutMirroring.childrenInherit: true
+
+ width: parent.width
+ height: buttonTexts.length ? privateStyle.toolBarHeightLandscape + 2 * platformStyle.paddingSmall : 0
+
+ Row {
+ id: buttonRow
+ objectName: "buttonRow"
+ anchors.centerIn: parent
+ spacing: platformStyle.paddingMedium
+ }
+ }
+}
--- /dev/null
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the Qt Components project.
+**
+** $QT_BEGIN_LICENSE:BSD$
+** You may use this file under the terms of the BSD license as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions and the following disclaimer in
+** the documentation and/or other materials provided with the
+** distribution.
+** * Neither the name of Nokia Corporation and its Subsidiary(-ies) nor
+** the names of its contributors may be used to endorse or promote
+** products derived from this software without specific prior written
+** permission.
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick 1.1
+import "." 1.1
+
+Item {
+ id: root
+
+ default property alias content: menu.content
+ property Item visualParent: null
+ property alias status: popup.status
+
+ // Symbian specific API
+ property bool platformInverted: false
+
+ function open() {
+ popup.open()
+ }
+
+ function close() {
+ popup.close()
+ }
+
+ visible: false
+ implicitWidth: {
+ if (screen.width < screen.height)
+ screen.width - 2 * platformStyle.paddingLarge
+ else
+ privateStyle.dialogMaxSize
+ }
+
+ Popup {
+ id: popup
+
+ animationDuration: 250
+ state: "Hidden"
+ anchors.centerIn: parent
+ visible: status != DialogStatus.Closed
+ enabled: status == DialogStatus.Open
+ width: root.width
+ height: menu.height
+ platformInverted: root.platformInverted
+
+ onFaderClicked: {
+ privateStyle.play(Android.PopupClose)
+ close()
+ }
+
+ MenuContent {
+ id: menu
+ containingPopup: popup
+ width: parent.width
+ platformInverted: root.platformInverted
+ onItemClicked: popup.close()
+ }
+
+ states: [
+ State {
+ name: "Hidden"
+ when: status == DialogStatus.Closing || status == DialogStatus.Closed
+ PropertyChanges { target: popup; opacity: 0 }
+ },
+ State {
+ name: "Visible"
+ when: status == DialogStatus.Opening || status == DialogStatus.Open
+ PropertyChanges { target: popup; opacity: 1 }
+ }
+ ]
+
+ transitions: [
+ Transition {
+ from: "Visible"; to: "Hidden"
+ SequentialAnimation {
+ NumberAnimation { properties: "opacity"; duration: popup.animationDuration; easing.type: Easing.Linear }
+ PropertyAction { target: popup; property: "status"; value: DialogStatus.Closed }
+ }
+ },
+ Transition {
+ from: "Hidden"; to: "Visible"
+ SequentialAnimation {
+ NumberAnimation { properties: "opacity"; duration: popup.animationDuration; easing.type: Easing.Linear }
+ PropertyAction { target: popup; property: "status"; value: DialogStatus.Open }
+ }
+ }
+ ]
+ }
+}
--- /dev/null
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the Qt Components project.
+**
+** $QT_BEGIN_LICENSE:BSD$
+** You may use this file under the terms of the BSD license as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions and the following disclaimer in
+** the documentation and/or other materials provided with the
+** distribution.
+** * Neither the name of Nokia Corporation and its Subsidiary(-ies) nor
+** the names of its contributors may be used to endorse or promote
+** products derived from this software without specific prior written
+** permission.
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick 1.1
+import "." 1.1
+
+Item {
+ id: root
+
+ property alias title: titleItem.children
+ property alias content: contentItem.children
+ property alias buttons: buttonItem.children
+ property alias visualParent: dialog.visualParent
+ property alias status: dialog.status
+
+ // Symbian specific API
+ property bool platformInverted: false
+ // read-only
+ property int platformContentMaximumWidth: dialog.width
+ // read-only
+ property int platformContentMaximumHeight:
+ dialog.maxHeight() - titleBar.height - buttonItem.height
+
+ property alias privateTitleHeight: titleBar.height
+ property alias privateButtonsHeight: buttonItem.height
+
+ signal accepted
+ signal rejected
+ signal clickedOutside
+
+ function open() {
+ dialog.open()
+ dialog.focus = true
+ }
+
+ function accept() {
+ if (status == DialogStatus.Open) {
+ dialog.close()
+ accepted()
+ }
+ }
+
+ function reject() {
+ if (status == DialogStatus.Open) {
+ dialog.close()
+ rejected()
+ }
+ }
+
+ function close() {
+ dialog.close()
+ }
+
+ visible: false
+
+ Popup {
+ id: dialog
+
+ function defaultHeight() {
+ if (root.height > 0)
+ return root.height
+ else
+ return titleBar.height + contentItem.childrenRect.height + buttonItem.height
+ }
+
+ function defaultWidth() {
+ return root.width > 0 ? root.width : maxWidth()
+ }
+
+ function maxWidth() {
+ return Math.min(screen.width - 2 * platformStyle.paddingMedium, privateStyle.dialogMaxSize)
+ }
+
+ function maxHeight() {
+ return inputContext.visible
+ ? Math.min(privateStyle.dialogMaxSize, screen.height-inputContext.height)
+ : Math.min(privateStyle.dialogMaxSize, screen.height-2*platformStyle.paddingMedium);
+ }
+
+ function minWidth() {
+ return Math.min(screen.displayWidth, screen.displayHeight) - 2 * platformStyle.paddingMedium
+ }
+
+ function minHeight() {
+ return inputContext.visible
+ ? Math.min(privateStyle.dialogMinSize, screen.height-inputContext.height)
+ : Math.min(privateStyle.dialogMinSize, screen.height-2*platformStyle.paddingMedium);
+ }
+
+ function updateSize() {
+ width = Math.max(Math.min(defaultWidth(), maxWidth()), minWidth())
+ height = Math.max(Math.min(defaultHeight(), maxHeight()), minHeight())
+ }
+
+ Connections { target: inputContext; onVisibleChanged: updateTimer.start() }
+ Connections { target: screen; onHeightChanged: updateTimer.start(); onWidthChanged: updateTimer.start() }
+ Connections { target: root; onHeightChanged: updateTimer.start(); onWidthChanged: updateTimer.start() }
+
+ Component.onCompleted: updateTimer.start()
+
+ Timer {
+ id: updateTimer
+ interval: 1; repeat: false
+ onTriggered: dialog.updateSize()
+ }
+
+ onFaderClicked: root.clickedOutside()
+
+ width: 0 // Defined in updateSize()
+ height: 0 // Defined in updateSize()
+
+ state: "Hidden"
+ visible: true
+ anchors.centerIn: parent
+ animationDuration: 250
+ platformInverted: root.platformInverted
+
+ // Consume all key events that are not processed by children
+ Keys.onPressed: event.accepted = true
+ Keys.onReleased: event.accepted = true
+
+ BorderImage {
+ source: privateStyle.imagePath("qtg_fr_popup", root.platformInverted)
+ border { left: 20; top: 20; right: 20; bottom: 20 }
+ anchors.fill: parent
+ }
+
+ Item {
+ id: titleBar
+
+ height: platformStyle.graphicSizeSmall + 2 * platformStyle.paddingLarge
+ anchors {
+ top: parent.top
+ left: parent.left
+ right: parent.right
+ }
+
+ BorderImage {
+ source: privateStyle.imagePath("qtg_fr_popup_heading", root.platformInverted)
+ border { left: 40; top: 0; right: 40; bottom: 0 }
+ anchors.fill: parent
+ }
+
+ Item {
+ id: titleItem
+
+ clip: true
+ anchors {
+ fill: parent
+ }
+ }
+ }
+
+ Item {
+ id: contentItem
+
+ clip: true
+ anchors {
+ top: titleBar.bottom
+ left: parent.left
+ right: parent.right
+ bottom: buttonItem.top
+ }
+ }
+
+ Item {
+ id: buttonItem
+
+ height: childrenRect.height
+ clip: true
+ anchors {
+ left: parent.left
+ right: parent.right
+ bottom: parent.bottom
+ }
+ }
+
+ states: [
+ State {
+ name: "Visible"
+ when: status == DialogStatus.Opening || status == DialogStatus.Open
+ PropertyChanges { target: dialog; opacity: 1.0; scale: 1; }
+ },
+ State {
+ name: "Hidden"
+ when: status == DialogStatus.Closing || status == DialogStatus.Closed
+ PropertyChanges { target: dialog; opacity: 0.0; scale: 0.9; }
+ }
+ ]
+
+ transitions: [
+ Transition {
+ from: "Visible"; to: "Hidden"
+ SequentialAnimation {
+ ScriptAction {script: status = DialogStatus.Closing }
+ ParallelAnimation {
+ NumberAnimation {
+ properties: "opacity"
+ duration: dialog.animationDuration
+ easing.type: Easing.Linear
+ }
+ NumberAnimation {
+ property: "scale"
+ duration: dialog.animationDuration
+ easing.type: Easing.InQuad
+ }
+ }
+ ScriptAction {script: status = DialogStatus.Closed }
+ }
+ },
+ Transition {
+ from: "Hidden"; to: "Visible"
+ SequentialAnimation {
+ ScriptAction { script: status = DialogStatus.Opening }
+ PropertyAction { target: dialog; property: "visible"; value: true}
+ ParallelAnimation {
+ NumberAnimation {
+ properties: "opacity"
+ duration: dialog.animationDuration
+ easing.type: Easing.Linear
+ }
+ NumberAnimation {
+ property: "scale"
+ duration: dialog.animationDuration
+ easing.type: Easing.OutQuad
+ }
+ }
+ ScriptAction { script: status = DialogStatus.Open }
+ }
+ }
+ ]
+ }
+}
--- /dev/null
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the Qt Components project.
+**
+** $QT_BEGIN_LICENSE:BSD$
+** You may use this file under the terms of the BSD license as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions and the following disclaimer in
+** the documentation and/or other materials provided with the
+** distribution.
+** * Neither the name of Nokia Corporation and its Subsidiary(-ies) nor
+** the names of its contributors may be used to endorse or promote
+** products derived from this software without specific prior written
+** permission.
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick 1.1
+
+Item {
+ id: root
+
+ property real dimm: 0.8
+ property int animationDuration: 500
+ property Item visualParent: null
+ property bool platformInverted: false // supports inverted, but looks the same
+
+ signal clicked
+
+ anchors.fill: parent
+ anchors.bottomMargin: inputContext.visible ? inputContext.height : 0
+ state: "Hidden"
+
+ Rectangle {
+ id: fader
+
+ anchors { top: parent.top; left: parent.left; right: parent.right }
+ height: parent.height + parent.anchors.bottomMargin
+ opacity: 0.0
+ color: "black"
+
+ //eat mouse events
+ MouseArea {
+ id: mouseEventEater
+ anchors.fill: parent
+ enabled: fader.opacity != 0.0
+ onClicked: root.clicked()
+ }
+ }
+
+ states: [
+ State {
+ name: "Visible"
+ PropertyChanges { target: fader; opacity: dimm }
+ },
+ State {
+ name: "Hidden"
+ PropertyChanges { target: fader; opacity: 0.0 }
+ }
+ ]
+
+ transitions: [
+ Transition {
+ from: "Hidden"; to: "Visible"
+ NumberAnimation { properties: "opacity"; duration: animationDuration; easing.type: Easing.Linear }
+ },
+ Transition {
+ from: "Visible"; to: "Hidden"
+ NumberAnimation { properties: "opacity"; duration: animationDuration; easing.type: Easing.Linear }
+ }
+ ]
+}
--- /dev/null
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the Qt Components project.
+**
+** $QT_BEGIN_LICENSE:BSD$
+** You may use this file under the terms of the BSD license as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions and the following disclaimer in
+** the documentation and/or other materials provided with the
+** distribution.
+** * Neither the name of Nokia Corporation and its Subsidiary(-ies) nor
+** the names of its contributors may be used to endorse or promote
+** products derived from this software without specific prior written
+** permission.
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick 1.1
+
+Text {
+ property bool platformInverted: false
+ color: platformInverted ? platformStyle.colorNormalLightInverted
+ : platformStyle.colorNormalLight
+ font.family: platformStyle.fontFamilyRegular
+ font.pixelSize: platformStyle.fontSizeMedium
+}
--- /dev/null
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the Qt Components project.
+**
+** $QT_BEGIN_LICENSE:BSD$
+** You may use this file under the terms of the BSD license as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions and the following disclaimer in
+** the documentation and/or other materials provided with the
+** distribution.
+** * Neither the name of Nokia Corporation and its Subsidiary(-ies) nor
+** the names of its contributors may be used to endorse or promote
+** products derived from this software without specific prior written
+** permission.
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick 1.1
+import "." 1.1
+
+Item {
+ id: root
+ property alias paddingItem: paddingItem // Read-only
+ property bool platformInverted: false
+
+ implicitWidth: ListView.view ? ListView.view.width : screen.width
+ implicitHeight: platformStyle.graphicSizeSmall
+
+ BorderImage {
+ source: privateStyle.imagePath("qtg_fr_list_heading_normal", root.platformInverted)
+ border { left: 28; top: 0; right: 28; bottom: 0 }
+ smooth: true
+ anchors.fill: parent
+ }
+
+ Item {
+ // non-visible item to create a padding boundary that content items can bind to
+ id: paddingItem
+ anchors {
+ fill: parent
+ leftMargin: platformStyle.paddingLarge
+ rightMargin: privateStyle.scrollBarThickness
+ topMargin: platformStyle.paddingSmall
+ bottomMargin: platformStyle.paddingSmall
+ }
+ }
+}
--- /dev/null
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the Qt Components project.
+**
+** $QT_BEGIN_LICENSE:BSD$
+** You may use this file under the terms of the BSD license as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions and the following disclaimer in
+** the documentation and/or other materials provided with the
+** distribution.
+** * Neither the name of Nokia Corporation and its Subsidiary(-ies) nor
+** the names of its contributors may be used to endorse or promote
+** products derived from this software without specific prior written
+** permission.
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick 1.1
+import "." 1.1
+
+Item {
+ id: root
+ property string mode: "normal" // Read-only
+ property alias paddingItem: paddingItem // Read-only
+
+ property bool enabled: true
+ property bool subItemIndicator: false
+ property bool platformInverted: false
+
+ signal clicked
+ signal pressAndHold
+
+ implicitWidth: ListView.view ? ListView.view.width : screen.width
+ implicitHeight: platformStyle.graphicSizeLarge
+
+ Item {
+ id: background
+ anchors.fill: parent
+
+ Rectangle {
+ height: 1
+ color: root.platformInverted ? platformStyle.colorDisabledLightInverted
+ : platformStyle.colorDisabledMid
+ anchors {
+ bottom: parent.bottom
+ left: parent.left
+ right: parent.right
+ }
+ }
+ Loader {
+ id: faderLoader
+ opacity: 0
+ anchors.fill: background
+ sourceComponent: root.mode != "normal" && root.mode != "pressed" ? fader : undefined
+ }
+
+ BorderImage {
+ id: highlight
+ border {
+ left: platformStyle.borderSizeMedium
+ top: platformStyle.borderSizeMedium
+ right: platformStyle.borderSizeMedium
+ bottom: platformStyle.borderSizeMedium
+ }
+ opacity: 0
+ anchors.fill: background
+ }
+ }
+
+ Component {
+ id: fader
+
+ BorderImage {
+ source: privateStyle.imagePath("qtg_fr_list_" + mode, root.platformInverted)
+ border {
+ left: platformStyle.borderSizeMedium
+ top: platformStyle.borderSizeMedium
+ right: platformStyle.borderSizeMedium
+ bottom: platformStyle.borderSizeMedium
+ }
+ }
+ }
+
+ MouseArea {
+ id: mouseArea
+ anchors.fill: parent
+ enabled: root.enabled
+ onPressed: {
+ android.listInteractionMode = Android.TouchInteraction
+ internal.state = "Pressed"
+ }
+ onClicked: {
+ internal.state = ""
+ root.clicked()
+ }
+ onCanceled: {
+ internal.state = "Canceled"
+ }
+ onPressAndHold: {
+ internal.state = "PressAndHold"
+ }
+ onReleased: {
+ internal.state = ""
+ }
+ onExited: {
+ internal.state = ""
+ }
+ }
+
+ Loader {
+ id: iconLoader
+ sourceComponent: root.subItemIndicator ? subItemIcon : undefined
+ anchors {
+ right: parent.right
+ rightMargin: privateStyle.scrollBarThickness
+ verticalCenter: parent.verticalCenter
+ }
+ }
+
+ Component {
+ id: subItemIcon
+
+ Image {
+ source: privateStyle.imagePath(
+ root.enabled ? "qtg_graf_drill_down_indicator"
+ : "qtg_graf_drill_down_indicator_disabled",
+ root.platformInverted)
+ mirror: LayoutMirroring.enabled
+ sourceSize.width: platformStyle.graphicSizeSmall
+ sourceSize.height: platformStyle.graphicSizeSmall
+ }
+ }
+
+ Keys.onReleased: {
+ if (!event.isAutoRepeat && root.enabled) {
+ if (event.key == Qt.Key_Select || event.key == Qt.Key_Return || event.key == Qt.Key_Enter) {
+ event.accepted = true
+ internal.state = "Focused"
+ }
+ }
+ }
+
+ Keys.onPressed: {
+ if (!event.isAutoRepeat) {
+ switch (event.key) {
+ case Qt.Key_Select:
+ case Qt.Key_Enter:
+ case Qt.Key_Return: {
+ if (android.listInteractionMode != Android.KeyNavigation)
+ android.listInteractionMode = Android.KeyNavigation
+ else
+ if (root.enabled) {
+ highlight.source = privateStyle.imagePath("qtg_fr_list_pressed",
+ root.platformInverted)
+ highlight.opacity = 1
+ releasedEffect.restart()
+ root.clicked()
+ }
+ event.accepted = true
+ break
+ }
+
+ case Qt.Key_Up: {
+ if (android.listInteractionMode != Android.KeyNavigation) {
+ android.listInteractionMode = Android.KeyNavigation
+ internal.state = "Focused"
+ ListView.view.positionViewAtIndex(index, ListView.Beginning)
+ } else
+ ListView.view.decrementCurrentIndex()
+ event.accepted = true
+ break
+ }
+
+ case Qt.Key_Down: {
+ if (android.listInteractionMode != Android.KeyNavigation) {
+ android.listInteractionMode = Android.KeyNavigation
+ ListView.view.positionViewAtIndex(index, ListView.Beginning)
+ internal.state = "Focused"
+ } else
+ ListView.view.incrementCurrentIndex()
+ event.accepted = true
+ break
+ }
+ default: {
+ event.accepted = false
+ break
+ }
+ }
+ }
+
+ if (event.key == Qt.Key_Up || event.key == Qt.Key_Down)
+ android.privateListItemKeyNavigation(ListView.view)
+ }
+
+ ListView.onRemove: SequentialAnimation {
+ PropertyAction { target: root; property: "ListView.delayRemove"; value: true }
+ ParallelAnimation {
+ SequentialAnimation {
+ PauseAnimation { duration: 50 }
+ NumberAnimation {
+ target: root
+ property: "height"
+ to: 0
+ duration: 200
+ easing.type: Easing.OutQuad
+ }
+ }
+ NumberAnimation {
+ target: root
+ property: "opacity"
+ from: 1
+ to: 0
+ duration: 200
+ easing.type: Easing.Linear
+ }
+ }
+ PropertyAction { target: root; property: "ListView.delayRemove"; value: false }
+ }
+
+ ListView.onAdd: SequentialAnimation {
+ PropertyAction { target: root; property: "height"; value: 0 }
+ ParallelAnimation {
+ NumberAnimation {
+ target: root
+ property: "height"
+ to: root.height
+ duration: 250
+ easing.type: Easing.OutQuad
+ }
+ NumberAnimation {
+ target: root
+ property: "opacity"
+ from: 0
+ to: 1
+ duration: 250
+ easing.type: Easing.Linear
+ }
+ }
+ }
+
+ SequentialAnimation {
+ id: releasedEffect
+ PropertyAnimation {
+ target: highlight
+ property: "opacity"
+ to: 0
+ easing.type: Easing.Linear
+ duration: 150
+ }
+ }
+
+ Item {
+ // non-visible item to create a padding boundary that content items can bind to
+ id: paddingItem
+ anchors {
+ fill: parent
+ leftMargin: platformStyle.paddingLarge
+ rightMargin: iconLoader.status == Loader.Ready ?
+ privateStyle.scrollBarThickness + iconLoader.width + platformStyle.paddingMedium :
+ privateStyle.scrollBarThickness
+ topMargin: platformStyle.paddingLarge
+ bottomMargin: platformStyle.paddingLarge
+ }
+ }
+
+ StateGroup {
+ id: internal
+
+ function getMode() {
+ if (internal.state == "Pressed" || internal.state == "PressAndHold")
+ return "pressed"
+ else if (internal.state == "Focused")
+ return "highlighted"
+ else if (internal.state == "Disabled")
+ return "disabled"
+ else
+ return "normal"
+ }
+
+ // Performance optimization:
+ // Use value assignment when property changes instead of binding to js function
+ onStateChanged: { root.mode = internal.getMode() }
+
+ function press() {
+ privateStyle.play(Android.BasicItem)
+ highlight.source = privateStyle.imagePath("qtg_fr_list_pressed", root.platformInverted)
+ highlight.opacity = 1
+ if (root.ListView.view)
+ root.ListView.view.currentIndex = index
+ }
+
+ function release() {
+ if (android.listInteractionMode != Android.KeyNavigation)
+ privateStyle.play(Android.BasicItem)
+ releasedEffect.restart()
+ }
+
+ function releaseHold() {
+ releasedEffect.restart()
+ }
+
+ function hold() {
+ root.pressAndHold()
+ }
+
+ function disable() {
+ faderLoader.opacity = 1
+ }
+
+ function focus() {
+ faderLoader.opacity = 1
+ }
+
+ function canceled() {
+ releasedEffect.restart()
+ }
+
+ states: [
+ State { name: "Pressed" },
+ State { name: "PressAndHold" },
+ State { name: "Disabled"; when: !root.enabled },
+ State { name: "Focused"; when: (root.ListView.isCurrentItem &&
+ android.listInteractionMode == Android.KeyNavigation) },
+ State { name: "Canceled" },
+ State { name: "" }
+ ]
+
+ transitions: [
+ Transition {
+ to: "Pressed"
+ ScriptAction { script: internal.press() }
+ },
+ Transition {
+ from: "Pressed"
+ to: "PressAndHold"
+ ScriptAction { script: internal.hold() }
+ },
+ Transition {
+ from: "PressAndHold"
+ to: ""
+ ScriptAction { script: internal.releaseHold() }
+ },
+ Transition {
+ to: ""
+ ScriptAction { script: internal.release() }
+ },
+ Transition {
+ to: "Disabled"
+ ScriptAction { script: internal.disable() }
+ },
+ Transition {
+ to: "Focused"
+ ScriptAction { script: internal.focus() }
+ },
+ Transition {
+ to: "Canceled"
+ ScriptAction { script: internal.canceled() }
+ }
+ ]
+ }
+}
--- /dev/null
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the Qt Components project.
+**
+** $QT_BEGIN_LICENSE:BSD$
+** You may use this file under the terms of the BSD license as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions and the following disclaimer in
+** the documentation and/or other materials provided with the
+** distribution.
+** * Neither the name of Nokia Corporation and its Subsidiary(-ies) nor
+** the names of its contributors may be used to endorse or promote
+** products derived from this software without specific prior written
+** permission.
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick 1.1
+
+Text {
+ id: root
+ property string mode: "normal"
+ property string role: "Title"
+ property bool platformInverted: false
+
+ // Also role "Heading" taken into account although not explicitely used in evaluations below
+ font {
+ family: platformStyle.fontFamilyRegular
+ pixelSize: (role == "Title" || role == "SelectionTitle") ? platformStyle.fontSizeLarge : platformStyle.fontSizeSmall
+ weight: (role == "SubTitle" || role == "SelectionSubTitle") ? Font.Light : Font.Normal
+ }
+ color: internal.normalColor
+ elide: Text.ElideRight
+ horizontalAlignment: root.role != "Heading" ? Text.AlignLeft : Text.AlignRight
+
+ // Performance optimization:
+ // Use value assignment when property changes instead of binding to js function
+ onModeChanged: { color = internal.getColor() }
+
+ QtObject {
+ id: internal
+
+ // Performance optmization:
+ // Use tertiary operations even though it doesn't look that good
+ property color colorMid: root.platformInverted ? platformStyle.colorNormalMidInverted
+ : platformStyle.colorNormalMid
+ property color colorLight: root.platformInverted ? platformStyle.colorNormalLightInverted
+ : platformStyle.colorNormalLight
+ property color normalColor: (root.role == "SelectionSubTitle" || root.role == "SubTitle")
+ ? colorMid : colorLight
+
+ function getColor() {
+ if (root.mode == "pressed")
+ return root.platformInverted ? platformStyle.colorPressedInverted
+ : platformStyle.colorPressed
+ else if (root.mode == "highlighted")
+ return root.platformInverted ? platformStyle.colorHighlightedInverted
+ : platformStyle.colorHighlighted
+ else if (root.mode == "disabled")
+ return root.platformInverted ? platformStyle.colorDisabledLightInverted
+ : platformStyle.colorDisabledLight
+ else
+ return normalColor
+ }
+ }
+}
--- /dev/null
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the Qt Components project.
+**
+** $QT_BEGIN_LICENSE:BSD$
+** You may use this file under the terms of the BSD license as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions and the following disclaimer in
+** the documentation and/or other materials provided with the
+** distribution.
+** * Neither the name of Nokia Corporation and its Subsidiary(-ies) nor
+** the names of its contributors may be used to endorse or promote
+** products derived from this software without specific prior written
+** permission.
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick 1.1
+import "." 1.1
+
+Item {
+ id: root
+
+ default property alias content: menu.content
+ property Item visualParent: null
+ property alias status: popup.status
+ property bool platformInverted: false
+
+ function open() {
+ popup.open()
+ }
+
+ function close() {
+ popup.close()
+ }
+
+ visible: false
+
+ Popup {
+ id: popup
+ objectName: "OptionsMenu"
+
+ y: screen.height - popup.height
+ animationDuration: 200
+ state: "Hidden"
+ visible: status != DialogStatus.Closed
+ enabled: status == DialogStatus.Open
+ width: screen.width
+ height: menuContainer.height
+ clip: true
+ platformInverted: root.platformInverted
+
+ onFaderClicked: {
+ privateStyle.play(Android.PopupClose)
+ close()
+ }
+
+ BorderImage {
+ id: menuContainer
+
+ property int borderSize: Math.round(platformStyle.borderSizeMedium * 1.5)
+
+ source: privateStyle.imagePath("qtg_fr_popup_options", root.platformInverted)
+ border { left: borderSize; top: borderSize; right: borderSize; bottom: borderSize }
+
+ width: parent.width
+ height: menu.height + 2 * platformStyle.paddingLarge
+
+ MenuContent {
+ id: menu
+ containingPopup: popup
+ anchors { top: parent.top; left: parent.left; right: parent.right
+ topMargin: platformStyle.paddingLarge
+ leftMargin: platformStyle.paddingLarge
+ rightMargin: platformStyle.paddingLarge }
+ platformInverted: root.platformInverted
+ onItemClicked: popup.close()
+ }
+
+ BorderImage {
+ source: privateStyle.imagePath("qtg_fr_popup_options_overlay", root.platformInverted)
+ anchors.fill: parent
+ border { left: menuContainer.borderSize; top: menuContainer.borderSize
+ right: menuContainer.borderSize; bottom: menuContainer.borderSize }
+ }
+ }
+
+ states: [
+ State {
+ name: "Hidden"
+ when: status == DialogStatus.Closing || status == DialogStatus.Closed
+ PropertyChanges { target: menuContainer; y: menuContainer.height; opacity: 0 }
+ },
+ State {
+ name: "Visible"
+ when: status == DialogStatus.Opening || status == DialogStatus.Open
+ PropertyChanges { target: menuContainer; y: 0; opacity: 1 }
+ }
+ ]
+
+ transitions: [
+ Transition {
+ from: "Visible"; to: "Hidden"
+ SequentialAnimation {
+ ParallelAnimation {
+ NumberAnimation {
+ target: menuContainer
+ property: "y"
+ duration: popup.animationDuration
+ easing.type: Easing.Linear
+ }
+ NumberAnimation {
+ target: menuContainer
+ property: "opacity"
+ duration: popup.animationDuration
+ easing.type: Easing.Linear
+ }
+ }
+ PropertyAction { target: popup; property: "status"; value: DialogStatus.Closed }
+ }
+ },
+ Transition {
+ from: "Hidden"; to: "Visible"
+ SequentialAnimation {
+ ParallelAnimation {
+ NumberAnimation {
+ target: menuContainer
+ property: "y"
+ duration: popup.animationDuration
+ easing.type: Easing.OutQuad
+ }
+ NumberAnimation {
+ target: menuContainer
+ property: "opacity"
+ duration: popup.animationDuration
+ easing.type: Easing.Linear
+ }
+ }
+ PropertyAction { target: popup; property: "status"; value: DialogStatus.Open }
+ }
+ }
+ ]
+ }
+}
--- /dev/null
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the Qt Components project.
+**
+** $QT_BEGIN_LICENSE:BSD$
+** You may use this file under the terms of the BSD license as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions and the following disclaimer in
+** the documentation and/or other materials provided with the
+** distribution.
+** * Neither the name of Nokia Corporation and its Subsidiary(-ies) nor
+** the names of its contributors may be used to endorse or promote
+** products derived from this software without specific prior written
+** permission.
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick 1.1
+import "." 1.1
+
+Item {
+ id: root
+
+ property alias content: contentArea.children
+ property Popup containingPopup: null
+ property bool platformInverted: false
+
+ signal itemClicked()
+
+ height: flickableArea.height
+
+ QtObject {
+ id: internal
+ // Add padding to align content area top and bottom with rounded background graphics.
+ // Optionsmenu uses mask, thus no padding needed
+ property int clipMargin: containingPopup.objectName == "OptionsMenu" ? 0 : platformStyle.paddingSmall
+ property int preferredHeight: privateStyle.menuItemHeight * ((screen.width < screen.height) ? 5 : 3)
+ }
+
+ BorderImage {
+ source: containingPopup.objectName == "OptionsMenu"
+ ? privateStyle.imagePath("qtg_fr_popup_options", root.platformInverted)
+ : privateStyle.imagePath("qtg_fr_popup", root.platformInverted)
+ border { left: 20; top: 20; right: 20; bottom: 20 }
+ anchors.fill: parent
+ }
+
+ Item {
+ id: clipItem
+ y: internal.clipMargin
+ height: flickableArea.height - 2 * internal.clipMargin
+ width: root.width
+ clip: true
+ Flickable {
+ id: flickableArea
+
+ property int index: 0
+ property bool itemAvailable: (contentArea.children[0] != undefined) && (contentArea.children[0].children[0] != undefined)
+ property int itemHeight: itemAvailable ? Math.max(1, contentArea.children[0].children[0].height) : 1
+ property int itemsHidden: Math.floor(contentY / itemHeight)
+ property int interactionMode: android.listInteractionMode
+
+ y: -internal.clipMargin
+ height: contentArea.height; width: root.width
+ clip: true
+ contentHeight: (contentArea.children[0] != undefined) ? contentArea.children[0].height : 0
+ contentWidth: width
+
+ Item {
+ id: contentArea
+
+ width: flickableArea.width
+ height: flickableArea.contentHeight > internal.preferredHeight
+ ? internal.preferredHeight - (internal.preferredHeight % flickableArea.itemHeight)
+ : flickableArea.contentHeight
+
+ function setChildrenWidths() {
+ for (var i = 0; i < children.length; ++i)
+ children[i].width = width
+ }
+
+ function connectChildren() {
+ for (var i = 0; i < children.length; ++i) {
+ if (children[i].clicked != undefined)
+ children[i].clicked.connect(root.itemClicked)
+ }
+ }
+
+ onWidthChanged: setChildrenWidths()
+ onChildrenChanged: {
+ setChildrenWidths()
+ connectChildren()
+ }
+ }
+
+ onVisibleChanged: {
+ enabled = visible
+ if (itemAvailable)
+ contentArea.children[0].children[0].focus = visible
+ contentY = 0
+ index = 0
+ }
+
+ onItemsHiddenChanged: {
+ // Check that popup is really open in order to prevent unnecessary feedback
+ if (containingPopup.status == DialogStatus.Open
+ && android.listInteractionMode == Android.TouchInteraction)
+ privateStyle.play(Android.ItemScroll)
+ }
+
+ onInteractionModeChanged: {
+ if (android.listInteractionMode == Android.KeyNavigation) {
+ contentY = 0
+ scrollBar.flash(Android.FadeOut)
+ if (itemAvailable)
+ contentArea.children[0].children[index].focus = true
+ } else if (android.listInteractionMode == Android.TouchInteraction) {
+ index = 0
+ }
+ }
+
+ Keys.onPressed: {
+ if (itemAvailable && (event.key == Qt.Key_Down || event.key == Qt.Key_Up)) {
+ if (event.key == Qt.Key_Down && index < contentArea.children[0].children.length - 1) {
+ index++
+ if (index * itemHeight > contentY + height - itemHeight) {
+ contentY = index * itemHeight - height + itemHeight
+ }
+ } else if (event.key == Qt.Key_Up && index > 0) {
+ index--
+ if (index * itemHeight < contentY) {
+ contentY = index * itemHeight
+ }
+ }
+ scrollBar.flash(Android.FadeOut)
+ contentArea.children[0].children[index].focus = true
+ event.accepted = true
+ }
+ }
+ }
+ }
+
+ ScrollBar {
+ id: scrollBar
+ objectName: "scrollBar"
+ flickableItem: flickableArea
+ interactive: false
+ visible: flickableArea.height < flickableArea.contentHeight
+ anchors {
+ top: clipItem.top
+ bottom: clipItem.bottom
+ right: clipItem.right
+ }
+ platformInverted: root.platformInverted
+ }
+
+ Connections {
+ target: containingPopup
+ onStatusChanged: {
+ if (containingPopup.status == DialogStatus.Open)
+ scrollBar.flash(Android.FadeInFadeOut)
+ }
+ }
+}
--- /dev/null
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the Qt Components project.
+**
+** $QT_BEGIN_LICENSE:BSD$
+** You may use this file under the terms of the BSD license as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions and the following disclaimer in
+** the documentation and/or other materials provided with the
+** distribution.
+** * Neither the name of Nokia Corporation and its Subsidiary(-ies) nor
+** the names of its contributors may be used to endorse or promote
+** products derived from this software without specific prior written
+** permission.
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick 1.1
+import "." 1.1
+
+Item {
+ id: root
+
+ property alias text: textArea.text
+
+ // Symbian specific API
+ property bool platformInverted: false
+ property bool platformSubItemIndicator: false
+ property real platformLeftMargin: platformStyle.paddingLarge
+
+ signal clicked
+
+ width: parent.width; height: privateStyle.menuItemHeight
+
+ QtObject {
+ id: internal
+
+ function bg_postfix() {
+ if (activeFocus && android.listInteractionMode == Android.KeyNavigation)
+ return "highlighted"
+ else if (mouseArea.pressed && mouseArea.containsMouse && !mouseArea.canceled)
+ return "pressed"
+ else
+ return "popup_normal"
+ }
+
+ function textColor() {
+ if (!enabled)
+ return root.platformInverted ? platformStyle.colorDisabledLightInverted
+ : platformStyle.colorDisabledLight
+ else if (activeFocus && android.listInteractionMode == Android.KeyNavigation)
+ return root.platformInverted ? platformStyle.colorHighlightedInverted
+ : platformStyle.colorHighlighted
+ else if (mouseArea.pressed && mouseArea.containsMouse)
+ return root.platformInverted ? platformStyle.colorPressedInverted
+ : platformStyle.colorPressed
+ else
+ return root.platformInverted ? platformStyle.colorNormalLightInverted
+ : platformStyle.colorNormalLight
+ }
+ }
+
+ BorderImage {
+ source: privateStyle.imagePath("qtg_fr_list_" + internal.bg_postfix(), root.platformInverted)
+ border { left: 20; top: 20; right: 20; bottom: 20 }
+ anchors.fill: parent
+ }
+
+ Text {
+ id: textArea
+ anchors {
+ verticalCenter: parent.verticalCenter
+ left: parent.left
+ leftMargin: platformLeftMargin
+ right: iconLoader.status == Loader.Ready ? iconLoader.left : parent.right
+ rightMargin: iconLoader.status == Loader.Ready ? platformStyle.paddingMedium : privateStyle.scrollBarThickness
+ }
+ font { family: platformStyle.fontFamilyRegular; pixelSize: platformStyle.fontSizeMedium }
+ color: internal.textColor()
+ horizontalAlignment: Text.AlignLeft
+ elide: Text.ElideRight
+ }
+
+ Loader {
+ id: iconLoader
+ sourceComponent: root.platformSubItemIndicator ? subItemIcon : undefined
+ anchors {
+ right: parent.right
+ rightMargin: privateStyle.scrollBarThickness
+ verticalCenter: parent.verticalCenter
+ }
+ }
+
+ Component {
+ id: subItemIcon
+
+ Image {
+ source: privateStyle.imagePath("qtg_graf_drill_down_indicator", platformInverted)
+ sourceSize.width: platformStyle.graphicSizeSmall
+ sourceSize.height: platformStyle.graphicSizeSmall
+ mirror: LayoutMirroring.enabled
+ }
+ }
+
+
+ MouseArea {
+ id: mouseArea
+
+ property bool canceled: false
+
+ anchors.fill: parent
+
+ onPressed: {
+ canceled = false
+ android.listInteractionMode = Android.TouchInteraction
+ privateStyle.play(Android.BasicItem)
+ }
+ onClicked: {
+ if (!canceled)
+ root.clicked()
+ }
+ onReleased: {
+ if (!canceled)
+ privateStyle.play(Android.PopupClose)
+ }
+ onExited: canceled = true
+ }
+
+ Keys.onPressed: {
+ event.accepted = true
+ switch (event.key) {
+ case Qt.Key_Select:
+ case Qt.Key_Enter:
+ case Qt.Key_Return: {
+ if (!event.isAutoRepeat) {
+ if (android.listInteractionMode != Android.KeyNavigation)
+ android.listInteractionMode = Android.KeyNavigation
+ else
+ root.clicked()
+ }
+ break
+ }
+
+ case Qt.Key_Up: {
+ if (android.listInteractionMode != Android.KeyNavigation) {
+ android.listInteractionMode = Android.KeyNavigation
+ if (ListView.view != null)
+ ListView.view.positionViewAtIndex(index, ListView.Beginning)
+ } else {
+ if (ListView.view != null)
+ ListView.view.decrementCurrentIndex()
+ else
+ event.accepted = false
+ }
+ break
+ }
+
+ case Qt.Key_Down: {
+ if (android.listInteractionMode != Android.KeyNavigation) {
+ android.listInteractionMode = Android.KeyNavigation
+ if (ListView.view != null)
+ ListView.view.positionViewAtIndex(index, ListView.Beginning)
+ } else {
+ if (ListView.view != null)
+ ListView.view.incrementCurrentIndex()
+ else
+ event.accepted = false
+ }
+ break
+ }
+ case Qt.Key_Left:
+ case Qt.Key_Right: {
+ // If this MenuItem belongs to Menu invoke highlight
+ // in other cases consume event but do nothing
+ if (ListView.view == null && android.listInteractionMode != Android.KeyNavigation)
+ android.listInteractionMode = Android.KeyNavigation
+ break
+ }
+ default: {
+ event.accepted = false
+ break
+ }
+ }
+ }
+}
--- /dev/null
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the Qt Components project.
+**
+** $QT_BEGIN_LICENSE:BSD$
+** You may use this file under the terms of the BSD license as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions and the following disclaimer in
+** the documentation and/or other materials provided with the
+** distribution.
+** * Neither the name of Nokia Corporation and its Subsidiary(-ies) nor
+** the names of its contributors may be used to endorse or promote
+** products derived from this software without specific prior written
+** permission.
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick 1.1
+
+Column {
+ signal clicked
+
+ Component.onCompleted: {
+ for (var i = 0; i < children.length; ++i) {
+ if (children[i].clicked != undefined)
+ children[i].clicked.connect(clicked)
+ }
+ }
+}
--- /dev/null
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the Qt Components project.
+**
+** $QT_BEGIN_LICENSE:BSD$
+** You may use this file under the terms of the BSD license as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions and the following disclaimer in
+** the documentation and/or other materials provided with the
+** distribution.
+** * Neither the name of Nokia Corporation and its Subsidiary(-ies) nor
+** the names of its contributors may be used to endorse or promote
+** products derived from this software without specific prior written
+** permission.
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick 1.1
+import "." 1.1
+
+Item {
+ id: root
+
+ // The status of the page. One of the following:
+ // PageStatus.Inactive - the page is not visible
+ // PageStatus.Activating - the page is transitioning into becoming the active page
+ // PageStatus.Active - the page is the current active page
+ // PageStatus.Deactivating - the page is transitioning into becoming inactive
+ property int status: PageStatus.Inactive
+
+ property PageStack pageStack
+
+ // Defines orientation lock for a page
+ property int orientationLock: PageOrientation.Automatic
+
+ property Item tools: null
+
+ visible: false
+
+ width: visible && parent ? parent.width : internal.previousWidth
+ height: visible && parent ? parent.height : internal.previousHeight
+
+ onWidthChanged: internal.previousWidth = visible ? width : internal.previousWidth
+ onHeightChanged: internal.previousHeight = visible ? height : internal.previousHeight
+
+ onStatusChanged: {
+ if (status == PageStatus.Activating)
+ internal.orientationLockCheck();
+ }
+
+ onOrientationLockChanged: {
+ if (status == PageStatus.Activating || status == PageStatus.Active)
+ internal.orientationLockCheck();
+ }
+
+ // This is needed to make a parentless Page component visible in the Designer of QtCreator.
+ // It's done here instead of binding the visible property because binding it to a script
+ // block returning false would cause an element on the Page not to end up focused despite
+ // specifying focus=true inside the active focus scope. The focus would be gained and lost
+ // in createObject.
+ Component.onCompleted: if (!parent) visible = true
+
+ QtObject {
+ id: internal
+ property int previousWidth: 0
+ property int previousHeight: 0
+
+ function isScreenInPortrait() {
+ return screen.currentOrientation == Screen.Portrait || screen.currentOrientation == Screen.PortraitInverted;
+ }
+
+ function isScreenInLandscape() {
+ return screen.currentOrientation == Screen.Landscape || screen.currentOrientation == Screen.LandscapeInverted;
+ }
+
+ function orientationLockCheck() {
+ switch (orientationLock) {
+ case PageOrientation.Automatic:
+ screen.allowedOrientations = Screen.Default
+ break
+ case PageOrientation.LockPortrait:
+ screen.allowedOrientations = Screen.Portrait
+ break
+ case PageOrientation.LockLandscape:
+ screen.allowedOrientations = Screen.Landscape
+ break
+ case PageOrientation.LockPrevious:
+ screen.allowedOrientations = screen.currentOrientation
+ break
+ case PageOrientation.Manual:
+ default:
+ // Do nothing
+ // In manual mode it is expected that orientation is set
+ // explicitly to "screen.allowedOrientations" by the user.
+ break
+ }
+ }
+ }
+}
--- /dev/null
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the Qt Components project.
+**
+** $QT_BEGIN_LICENSE:BSD$
+** You may use this file under the terms of the BSD license as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions and the following disclaimer in
+** the documentation and/or other materials provided with the
+** distribution.
+** * Neither the name of Nokia Corporation and its Subsidiary(-ies) nor
+** the names of its contributors may be used to endorse or promote
+** products derived from this software without specific prior written
+** permission.
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+// Page stack - items are page containers.
+var pageStack = [];
+
+// Returns the page stack depth.
+function getDepth() {
+ return pageStack.length;
+}
+
+// Pushes a page on the stack.
+function push(page, properties, replace, immediate) {
+ // page order sanity check
+ if ((!replace && page == currentPage)
+ || (replace && pageStack.length > 1
+ && page == pageStack[pageStack.length - 2].page)) {
+ throw new Error("Cannot navigate so that the resulting page stack has two consecutive entries of the same page instance.");
+ }
+
+ // figure out if more than one page is being pushed
+ var pages;
+ if (page instanceof Array) {
+ pages = page;
+ page = pages.pop();
+ if (page.createObject === undefined && page.parent === undefined && typeof page != "string") {
+ properties = properties || page.properties;
+ page = page.page;
+ }
+ }
+
+ // get the current container
+ var oldContainer = pageStack[pageStack.length - 1];
+
+ // pop the old container off the stack if this is a replace
+ if (oldContainer && replace) {
+ pageStack.pop();
+ }
+
+ // push any extra defined pages onto the stack
+ if (pages) {
+ var i;
+ for (i = 0; i < pages.length; i++) {
+ var tPage = pages[i];
+ var tProps;
+ if (tPage.createObject === undefined && tPage.parent === undefined && typeof tPage != "string") {
+ tProps = tPage.properties;
+ tPage = tPage.page;
+ }
+ pageStack.push(initPage(tPage, tProps));
+ }
+ }
+
+ // initialize the page
+ var container = initPage(page, properties);
+
+ // push the page container onto the stack
+ pageStack.push(container);
+
+ depth = pageStack.length;
+ currentPage = container.page;
+
+ // perform page transition
+ immediate = immediate || !oldContainer;
+ var orientationChange = false;
+ if (oldContainer) {
+ orientationChange = orientationChanges(oldContainer.page, container.page);
+ oldContainer.pushExit(replace, immediate, orientationChange);
+ }
+
+ // sync tool bar
+ var tools = container.page.tools || null;
+ if (toolBar) {
+ toolBar.setTools(tools, immediate ? "set" : replace ? "replace" : "push");
+ }
+
+ container.pushEnter(immediate, orientationChange);
+ return container.page;
+}
+
+// Initializes a page and its container.
+function initPage(page, properties) {
+ var container = containerComponent.createObject(root);
+
+ var pageComp;
+ if (page.createObject) {
+ // page defined as component
+ pageComp = page;
+ } else if (typeof page == "string") {
+ // page defined as string (a url)
+ pageComp = Qt.createComponent(page);
+ }
+ if (pageComp) {
+ if (pageComp.status == Component.Error) {
+ throw new Error("Error while loading page: " + pageComp.errorString());
+ } else {
+ // instantiate page from component
+ page = pageComp.createObject(container);
+ }
+ }
+
+ container.page = page;
+ container.owner = page.parent;
+
+ // the page has to be reparented if
+ if (page.parent != container) {
+ page.parent = container;
+ }
+
+ if (page.pageStack !== undefined) {
+ page.pageStack = root;
+ }
+
+ // copy properties to the page
+ for (var prop in properties) {
+ page[prop] = properties[prop];
+ }
+
+ return container;
+}
+
+// Pops a page off the stack.
+function pop(page, immediate) {
+ // make sure there are enough pages in the stack to pop
+ if (pageStack.length > 1) {
+ // pop the current container off the stack and get the next container
+ var oldContainer = pageStack.pop();
+ var container = pageStack[pageStack.length - 1];
+ if (page !== undefined) {
+ // an unwind target has been specified - pop until we find it
+ while (page != container.page && pageStack.length > 1) {
+ container.cleanup();
+ pageStack.pop();
+ container = pageStack[pageStack.length - 1];
+ }
+ }
+
+ depth = pageStack.length;
+ currentPage = container.page;
+
+ // perform page transition
+ var orientationChange = orientationChanges(oldContainer.page, container.page);
+ oldContainer.popExit(immediate, orientationChange);
+ container.popEnter(immediate, orientationChange);
+
+ // sync tool bar
+ var tools = container.page.tools || null;
+ if (toolBar) {
+ toolBar.setTools(tools, immediate ? "set" : "pop");
+ }
+ return oldContainer.page;
+ } else {
+ return null;
+ }
+}
+
+// Checks if the orientation changes between oldPage and newPage
+function orientationChanges(oldPage, newPage) {
+ return newPage.orientationLock != PageOrientation.Automatic
+ && newPage.orientationLock != PageOrientation.LockPrevious
+ && newPage.orientationLock != oldPage.orientationLock
+}
+
+// Clears the page stack.
+function clear() {
+ var container;
+ while (container = pageStack.pop()) {
+ container.cleanup();
+ }
+ depth = 0;
+ currentPage = null;
+}
+
+// Iterates through all pages in the stack (top to bottom) to find a page.
+function find(func) {
+ for (var i = pageStack.length - 1; i >= 0; i--) {
+ var page = pageStack[i].page;
+ if (func(page)) {
+ return page;
+ }
+ }
+ return null;
+}
+
--- /dev/null
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the Qt Components project.
+**
+** $QT_BEGIN_LICENSE:BSD$
+** You may use this file under the terms of the BSD license as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions and the following disclaimer in
+** the documentation and/or other materials provided with the
+** distribution.
+** * Neither the name of Nokia Corporation and its Subsidiary(-ies) nor
+** the names of its contributors may be used to endorse or promote
+** products derived from this software without specific prior written
+** permission.
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+// The PageStack item defines a container for pages and a stack-based
+// navigation model. Pages can be defined as QML items or components.
+
+import QtQuick 1.1
+import "." 1.1
+
+import "PageStack.js" as Engine
+
+Item {
+ id: root
+
+ width: parent ? parent.width : 0
+ height: parent ? parent.height : 0
+
+ property int depth: Engine.getDepth()
+ property Item currentPage: null
+ property ToolBar toolBar
+ property variant initialPage
+
+ // Indicates whether there is an ongoing page transition.
+ property bool busy: internal.ongoingTransitionCount > 0
+
+ // Pushes a page on the stack.
+ // The page can be defined as a component, item or string.
+ // If an item is used then the page will get re-parented.
+ // If a string is used then it is interpreted as a url that is used to load a page component.
+ //
+ // The page can also be given as an array of pages. In this case all those pages will be pushed
+ // onto the stack. The items in the stack can be components, items or strings just like for single
+ // pages. Additionally an object can be used, which specifies a page and an optional properties
+ // property. This can be used to push multiple pages while still giving each of them properties.
+ // When an array is used the transition animation will only be to the last page.
+ //
+ // The properties argument is optional and allows defining a map of properties to set on the page.
+ // If the immediate argument is true then no transition animation is performed.
+ // Returns the page instance.
+ function push(page, properties, immediate) {
+ return Engine.push(page, properties, false, immediate);
+ }
+
+ // Pops a page off the stack.
+ // If page is specified then the stack is unwound to that page, to unwind to the first page specify
+ // page as null. If the immediate argument is true then no transition animation is performed.
+ // Returns the page instance that was popped off the stack.
+ function pop(page, immediate) {
+ return Engine.pop(page, immediate);
+ }
+
+ // Replaces a page on the stack.
+ // See push() for details.
+ function replace(page, properties, immediate) {
+ return Engine.push(page, properties, true, immediate);
+ }
+
+ // Clears the page stack.
+ function clear() {
+ return Engine.clear();
+ }
+
+ // Iterates through all pages (top to bottom) and invokes the specified function.
+ // If the specified function returns true the search stops and the find function
+ // returns the page that the iteration stopped at. If the search doesn't result
+ // in any page being found then null is returned.
+ function find(func) {
+ return Engine.find(func);
+ }
+
+ // Called when the page stack visibility changes.
+ onVisibleChanged: {
+ if (currentPage) {
+ internal.setPageStatus(currentPage, visible ? PageStatus.Active : PageStatus.Inactive);
+ if (visible)
+ currentPage.visible = currentPage.parent.visible = true;
+ }
+ }
+
+ onInitialPageChanged: {
+ if (initialPage) {
+ if (depth == 0)
+ push(initialPage, null, true)
+ else if (depth == 1)
+ replace(initialPage, null, true)
+ else
+ console.log("Cannot update PageStack.initialPage")
+ }
+ }
+
+ Component.onCompleted: {
+ if (initialPage && depth == 0)
+ push(initialPage, null, true)
+ }
+
+ QtObject {
+ id: internal
+
+ // The number of ongoing transitions.
+ property int ongoingTransitionCount: 0
+
+ // Sets the page status.
+ function setPageStatus(page, status) {
+ if (page != null) {
+ if (page.status !== undefined) {
+ if (status == PageStatus.Active && page.status == PageStatus.Inactive)
+ page.status = PageStatus.Activating;
+ else if (status == PageStatus.Inactive && page.status == PageStatus.Active)
+ page.status = PageStatus.Deactivating;
+
+ page.status = status;
+ }
+ }
+ }
+ }
+
+ // Component for page containers.
+ Component {
+ id: containerComponent
+
+ Item {
+ id: container
+
+ width: parent ? parent.width : 0
+ height: parent ? parent.height : 0
+
+ // The states correspond to the different possible positions of the container.
+ state: "Hidden"
+
+ // The page held by this container.
+ property Item page: null
+
+ // The owner of the page.
+ property Item owner: null
+
+ // The width of the longer screen dimension
+ property int screenWidth: Math.max(screen.width, screen.height)
+
+ // Duration of transition animation (in ms)
+ property int transitionDuration: 200
+
+ // Flag that indicates the container should be cleaned up after the transition has ended.
+ property bool cleanupAfterTransition: false
+
+ // Flag that indicates if page transition animation is running
+ property bool transitionAnimationRunning: false
+
+ // State to be set after previous state change animation has finished
+ property string pendingState: "none"
+
+ // Ensures that transition finish actions are executed
+ // in case the object is destroyed before reaching the
+ // end state of an ongoing transition
+ Component.onDestruction: {
+ if (transitionAnimationRunning)
+ transitionEnded();
+ }
+
+ // Sets pending state as current if state change is delayed
+ onTransitionAnimationRunningChanged: {
+ if (!transitionAnimationRunning && pendingState != "none") {
+ state = pendingState;
+ pendingState = "none";
+ }
+ }
+
+ // Handles state change depening on transition animation status
+ function setState(newState) {
+ if (transitionAnimationRunning)
+ pendingState = newState;
+ else
+ state = newState;
+ }
+
+ // Performs a push enter transition.
+ function pushEnter(immediate, orientationChanges) {
+ if (!immediate) {
+ if (orientationChanges)
+ setState("LandscapeRight");
+ else
+ setState("Right");
+ }
+ setState("");
+ page.visible = true;
+ if (root.visible && immediate)
+ internal.setPageStatus(page, PageStatus.Active);
+ }
+
+ // Performs a push exit transition.
+ function pushExit(replace, immediate, orientationChanges) {
+ if (orientationChanges)
+ setState(immediate ? "Hidden" : "LandscapeLeft");
+ else
+ setState(immediate ? "Hidden" : "Left");
+ if (root.visible && immediate)
+ internal.setPageStatus(page, PageStatus.Inactive);
+ if (replace) {
+ if (immediate)
+ cleanup();
+ else
+ cleanupAfterTransition = true;
+ }
+ }
+
+ // Performs a pop enter transition.
+ function popEnter(immediate, orientationChanges) {
+ if (!immediate)
+ state = orientationChanges ? "LandscapeLeft" : "Left";
+ setState("");
+ page.visible = true;
+ if (root.visible && immediate)
+ internal.setPageStatus(page, PageStatus.Active);
+ }
+
+ // Performs a pop exit transition.
+ function popExit(immediate, orientationChanges) {
+ if (orientationChanges)
+ setState(immediate ? "Hidden" : "LandscapeRight");
+ else
+ setState(immediate ? "Hidden" : "Right");
+
+ if (root.visible && immediate)
+ internal.setPageStatus(page, PageStatus.Inactive);
+ if (immediate)
+ cleanup();
+ else
+ cleanupAfterTransition = true;
+ }
+
+ // Called when a transition has started.
+ function transitionStarted() {
+ transitionAnimationRunning = true;
+ internal.ongoingTransitionCount++;
+ if (root.visible)
+ internal.setPageStatus(page, (state == "") ? PageStatus.Activating : PageStatus.Deactivating);
+ }
+
+ // Called when a transition has ended.
+ function transitionEnded() {
+ if (state != "")
+ state = "Hidden";
+ if (root.visible)
+ internal.setPageStatus(page, (state == "") ? PageStatus.Active : PageStatus.Inactive);
+
+ internal.ongoingTransitionCount--;
+ transitionAnimationRunning = false;
+ if (cleanupAfterTransition)
+ cleanup();
+ }
+
+ states: [
+ // Explicit properties for default state.
+ State {
+ name: ""
+ PropertyChanges { target: container; visible: true; opacity: 1 }
+ },
+ // Start state for pop entry, end state for push exit.
+ State {
+ name: "Left"
+ PropertyChanges { target: container; x: -width / 2; opacity: 0 }
+ },
+ // Start state for pop entry, end state for push exit
+ // when exiting portrait and entering landscape.
+ State {
+ name: "LandscapeLeft"
+ PropertyChanges { target: container; x: -screenWidth / 2; opacity: 0 }
+ },
+ // Start state for push entry, end state for pop exit.
+ State {
+ name: "Right"
+ PropertyChanges { target: container; x: width / 2; opacity: 0 }
+ },
+ // Start state for push entry, end state for pop exit
+ // when exiting portrait and entering landscape.
+ State {
+ name: "LandscapeRight"
+ PropertyChanges { target: container; x: screenWidth / 2; opacity: 0 }
+ },
+ // Inactive state.
+ State {
+ name: "Hidden"
+ PropertyChanges { target: container; visible: false }
+ }
+ ]
+
+ transitions: [
+ // Push exit transition
+ Transition {
+ from: ""; to: "Left"
+ SequentialAnimation {
+ ScriptAction { script: transitionStarted() }
+ ParallelAnimation {
+ PropertyAnimation { properties: "x"; easing.type: Easing.InQuad; duration: transitionDuration }
+ PropertyAnimation { properties: "opacity"; easing.type: Easing.Linear; duration: transitionDuration }
+ }
+ ScriptAction { script: transitionEnded() }
+ }
+ },
+ // Pop entry transition
+ Transition {
+ from: "Left"; to: ""
+ SequentialAnimation {
+ ScriptAction { script: transitionStarted() }
+ ParallelAnimation {
+ PropertyAnimation { properties: "x"; easing.type: Easing.OutQuad; duration: transitionDuration }
+ PropertyAnimation { properties: "opacity"; easing.type: Easing.Linear; duration: transitionDuration }
+ }
+ ScriptAction { script: transitionEnded() }
+ }
+ },
+ // Push exit transition landscape
+ Transition {
+ from: ""; to: "LandscapeLeft"
+ SequentialAnimation {
+ ScriptAction { script: transitionStarted() }
+ ParallelAnimation {
+ PropertyAnimation { properties: "x"; easing.type: Easing.InQuad; duration: transitionDuration }
+ PropertyAnimation { properties: "opacity"; easing.type: Easing.Linear; duration: transitionDuration }
+ }
+ ScriptAction { script: transitionEnded() }
+ }
+ },
+ // Pop entry transition landscape
+ Transition {
+ from: "LandscapeLeft"; to: ""
+ SequentialAnimation {
+ ScriptAction { script: transitionStarted() }
+ ParallelAnimation {
+ PropertyAnimation { properties: "x"; easing.type: Easing.OutQuad; duration: transitionDuration }
+ PropertyAnimation { properties: "opacity"; easing.type: Easing.Linear; duration: transitionDuration }
+ }
+ ScriptAction { script: transitionEnded() }
+ }
+ },
+ // Pop exit transition
+ Transition {
+ from: ""; to: "Right"
+ SequentialAnimation {
+ ScriptAction { script: transitionStarted() }
+ ParallelAnimation {
+ PropertyAnimation { properties: "x"; easing.type: Easing.InQuad; duration: transitionDuration }
+ PropertyAnimation { properties: "opacity"; easing.type: Easing.Linear; duration: transitionDuration }
+ }
+ // Workaround for transition animation bug causing ghost view with page pop transition animation
+ // TODO: Root cause still unknown
+ PropertyAnimation {}
+ ScriptAction { script: transitionEnded() }
+ }
+ },
+ // Push entry transition
+ Transition {
+ from: "Right"; to: ""
+ SequentialAnimation {
+ ScriptAction { script: transitionStarted() }
+ ParallelAnimation {
+ PropertyAnimation { properties: "x"; easing.type: Easing.OutQuad; duration: transitionDuration }
+ PropertyAnimation { properties: "opacity"; easing.type: Easing.Linear; duration: transitionDuration }
+ }
+ ScriptAction { script: transitionEnded() }
+ }
+ },
+ // Pop exit transition landscape
+ Transition {
+ from: ""; to: "LandscapeRight"
+ SequentialAnimation {
+ ScriptAction { script: transitionStarted() }
+ ParallelAnimation {
+ PropertyAnimation { properties: "x"; easing.type: Easing.InQuad; duration: transitionDuration }
+ PropertyAnimation { properties: "opacity"; easing.type: Easing.Linear; duration: transitionDuration }
+ }
+ // Workaround for transition animation bug causing ghost view with page pop transition animation
+ // TODO: Root cause still unknown
+ PropertyAnimation {}
+ ScriptAction { script: transitionEnded() }
+ }
+ },
+ // Push entry transition landscape
+ Transition {
+ from: "LandscapeRight"; to: ""
+ SequentialAnimation {
+ ScriptAction { script: transitionStarted() }
+ ParallelAnimation {
+ PropertyAnimation { properties: "x"; easing.type: Easing.OutQuad; duration: transitionDuration }
+ PropertyAnimation { properties: "opacity"; easing.type: Easing.Linear; duration: transitionDuration }
+ }
+ ScriptAction { script: transitionEnded() }
+ }
+ }
+ ]
+
+ // Cleans up the container and then destroys it.
+ function cleanup() {
+ if (page != null) {
+ if (page.status == PageStatus.Active)
+ internal.setPageStatus(page, PageStatus.Inactive);
+ if (owner != container) {
+ // container is not the owner of the page - re-parent back to original owner
+ page.visible = false;
+ page.parent = owner;
+ }
+ }
+ container.destroy();
+ }
+ }
+ }
+}
+
--- /dev/null
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the Qt Components project.
+**
+** $QT_BEGIN_LICENSE:BSD$
+** You may use this file under the terms of the BSD license as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions and the following disclaimer in
+** the documentation and/or other materials provided with the
+** distribution.
+** * Neither the name of Nokia Corporation and its Subsidiary(-ies) nor
+** the names of its contributors may be used to endorse or promote
+** products derived from this software without specific prior written
+** permission.
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick 1.1
+import "." 1.1
+
+Window {
+ id: root
+
+ property bool showStatusBar: true
+ property bool showToolBar: true
+ property variant initialPage
+ property alias pageStack: stack
+
+ property bool platformSoftwareInputPanelEnabled: false
+
+ Component.onCompleted: {
+ contentArea.initialized = true
+ if (initialPage && stack.depth == 0)
+ stack.push(initialPage, null, true)
+ }
+
+ onInitialPageChanged: {
+ if (initialPage && contentArea.initialized) {
+ if (stack.depth == 0)
+ stack.push(initialPage, null, true)
+ else if (stack.depth == 1)
+ stack.replace(initialPage, null, true)
+ }
+ }
+
+ onOrientationChangeStarted: {
+ statusBar.orientation = screen.currentOrientation
+ }
+
+ Item {
+ id: contentArea
+
+ property bool initialized: false
+
+ anchors {
+ top: sbar.bottom; bottom: sip.top;
+ left: parent.left; right: parent.right;
+ }
+
+ PageStack {
+ id: stack
+ anchors.fill: parent
+ toolBar: tbar
+ }
+ }
+
+ StatusBar {
+ id: sbar
+
+ width: parent.width
+ state: root.showStatusBar ? "Visible" : "Hidden"
+ platformInverted: root.platformInverted
+
+ states: [
+ State {
+ name: "Visible"
+ PropertyChanges { target: sbar; y: 0; opacity: 1 }
+ },
+ State {
+ name: "Hidden"
+ PropertyChanges { target: sbar; y: -height; opacity: 0 }
+ }
+ ]
+
+ transitions: [
+ Transition {
+ from: "Hidden"; to: "Visible"
+ ParallelAnimation {
+ NumberAnimation { target: sbar; properties: "y"; duration: 200; easing.type: Easing.OutQuad }
+ NumberAnimation { target: sbar; properties: "opacity"; duration: 200; easing.type: Easing.Linear }
+ }
+ },
+ Transition {
+ from: "Visible"; to: "Hidden"
+ ParallelAnimation {
+ NumberAnimation { target: sbar; properties: "y"; duration: 200; easing.type: Easing.Linear }
+ NumberAnimation { target: sbar; properties: "opacity"; duration: 200; easing.type: Easing.Linear }
+ }
+ }
+ ]
+ }
+
+ Item {
+ id: sip
+
+ anchors { bottom: parent.bottom; left: parent.left; right: parent.right }
+
+ Behavior on height { PropertyAnimation { duration: 200 } }
+
+ states: [
+ State {
+ name: "Visible"; when: inputContext.visible && root.platformSoftwareInputPanelEnabled
+ PropertyChanges { target: sip; height: inputContext.height }
+ },
+
+ State {
+ name: "Hidden"; when: root.showToolBar
+ PropertyChanges { target: sip; height: tbar.height }
+ },
+
+ State {
+ name: "HiddenInFullScreen"; when: !root.showToolBar
+ PropertyChanges { target: sip; height: 0 }
+ }
+ ]
+ }
+
+ ToolBar {
+ id: tbar
+
+ width: parent.width
+ state: root.showToolBar ? "Visible" : "Hidden"
+ platformInverted: root.platformInverted
+
+ states: [
+ State {
+ name: "Visible"
+ PropertyChanges { target: tbar; y: parent.height - height; opacity: 1 }
+ },
+ State {
+ name: "Hidden"
+ PropertyChanges { target: tbar; y: parent.height; opacity: 0 }
+ }
+ ]
+
+ transitions: [
+ Transition {
+ from: "Hidden"; to: "Visible"
+ ParallelAnimation {
+ NumberAnimation { target: tbar; properties: "y"; duration: 200; easing.type: Easing.OutQuad }
+ NumberAnimation { target: tbar; properties: "opacity"; duration: 200; easing.type: Easing.Linear }
+ }
+ },
+ Transition {
+ from: "Visible"; to: "Hidden"
+ ParallelAnimation {
+ NumberAnimation { target: tbar; properties: "y"; duration: 200; easing.type: Easing.Linear }
+ NumberAnimation { target: tbar; properties: "opacity"; duration: 200; easing.type: Easing.Linear }
+ }
+ }
+ ]
+ }
+
+ // event preventer when page transition is active
+ MouseArea {
+ anchors.fill: parent
+ enabled: pageStack.busy
+ }
+}
--- /dev/null
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the Qt Components project.
+**
+** $QT_BEGIN_LICENSE:BSD$
+** You may use this file under the terms of the BSD license as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions and the following disclaimer in
+** the documentation and/or other materials provided with the
+** distribution.
+** * Neither the name of Nokia Corporation and its Subsidiary(-ies) nor
+** the names of its contributors may be used to endorse or promote
+** products derived from this software without specific prior written
+** permission.
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick 1.1
+import "." 1.1
+import "AppManager.js" as Utils
+
+Item {
+ id: root
+
+ property Item visualParent
+ property int status: DialogStatus.Closed
+ property int animationDuration: 500
+ property Item fader
+ property bool platformInverted: false
+
+ signal faderClicked
+
+ function open() {
+ if (status == DialogStatus.Open || status == DialogStatus.Opening)
+ return
+
+ var notify = false
+ if (!fader) {
+ fader = faderComponent.createObject(visualParent ? visualParent : Utils.rootObject())
+ notify = true
+ }
+
+ fader.animationDuration = root.animationDuration
+ root.parent = fader
+ status = DialogStatus.Opening
+ fader.state = "Visible"
+
+ if (notify)
+ platformPopupManager.privateNotifyPopupOpen()
+ }
+
+ function close() {
+ if (status != DialogStatus.Closed) {
+ status = DialogStatus.Closing
+ if (fader)
+ fader.state = "Hidden"
+ }
+ }
+
+ onStatusChanged: {
+ if (status == DialogStatus.Closed && fader) {
+ // Temporarily setting root window as parent
+ // otherwise transition animation jams
+ root.parent = null
+ fader.destroy()
+ fader = null // Prevent reuse in open()
+ root.parent = parentCache.oldParent
+ platformPopupManager.privateNotifyPopupClose()
+ }
+ }
+
+ Component.onCompleted: {
+ parentCache.oldParent = parent
+ }
+
+ //if this is not given, application may crash in some cases
+ Component.onDestruction: {
+ if (parentCache.oldParent != null) {
+ parent = parentCache.oldParent
+ }
+ }
+
+ QtObject {
+ id: parentCache
+ property QtObject oldParent: null
+ }
+
+ //This eats mouse events when popup area is clicked
+ MouseArea {
+ anchors.fill: parent
+ }
+
+ Component {
+ id: faderComponent
+
+ Fader {
+ platformInverted: root.platformInverted
+ onClicked: root.faderClicked()
+ }
+ }
+}
--- /dev/null
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the Qt Components project.
+**
+** $QT_BEGIN_LICENSE:BSD$
+** You may use this file under the terms of the BSD license as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions and the following disclaimer in
+** the documentation and/or other materials provided with the
+** distribution.
+** * Neither the name of Nokia Corporation and its Subsidiary(-ies) nor
+** the names of its contributors may be used to endorse or promote
+** products derived from this software without specific prior written
+** permission.
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick 1.1
+import Qt.labs.components 1.1
+import "." 1.1
+
+Item {
+ id: root
+
+ // Common Public API
+ property alias minimumValue: model.minimumValue
+ property alias maximumValue: model.maximumValue
+ property alias value: model.value
+ property bool indeterminate: false
+
+ // Symbian specific API
+ property bool platformInverted: false
+
+ implicitWidth: Math.max(50, screen.width / 2) // TODO: use screen.displayWidth
+ implicitHeight: privateStyle.sliderThickness
+
+ BorderImage {
+ id: background
+
+ source: privateStyle.imagePath("qtg_fr_progressbar_track", root.platformInverted)
+ border { left: platformStyle.borderSizeMedium; top: 0; right: platformStyle.borderSizeMedium; bottom: 0 }
+ anchors.fill: parent
+ }
+
+ Loader {
+ id: progressBarContent
+
+ LayoutMirroring.enabled: false
+ LayoutMirroring.childrenInherit: true
+
+ states: [
+ State {
+ name: "indeterminate"
+ when: root.indeterminate
+ PropertyChanges { target: progressBarContent; sourceComponent: indeterminateContent; anchors.fill: parent }
+ },
+ State {
+ name: "determinate"
+ when: !root.indeterminate
+ PropertyChanges { target: progressBarContent; sourceComponent: determinateContent }
+ AnchorChanges {
+ target: progressBarContent
+ anchors.top: parent.top
+ anchors.bottom: parent.bottom
+ anchors.left: parent.left
+ }
+ }
+ ]
+ }
+
+
+ Component {
+ id: indeterminateContent
+
+ Item {
+ anchors.fill: parent
+
+ Item {
+ id: indeterminateImageMask
+
+ // Mask margins prevent indeterminateImage to appear outside the rounded
+ // frame corners, hardcoded 3 has been instructed by UX
+ anchors { fill: parent; leftMargin: 3; rightMargin: 3 }
+ clip: true
+
+ Image {
+ id: indeterminateImage
+
+ x: parent.x
+ height: parent.height
+ width: parent.width + height // height is the amount of horizontal movement
+ fillMode: Image.TileHorizontally
+ source: privateStyle.imagePath(root.platformInverted ? "qtg_graf_progressbar_wait_inverse"
+ : "qtg_graf_progressbar_wait")
+
+ NumberAnimation on x {
+ loops: Animation.Infinite
+ running: true
+ from: 0
+ to: -indeterminateImage.height // see indeterminateImage.width
+ easing.type: Easing.Linear
+ duration: privateStyle.sliderThickness * 30
+ }
+ }
+ }
+
+ BorderImage {
+ id: indeterminateOverlay
+
+ anchors.fill: parent
+ source: privateStyle.imagePath("qtg_fr_progressbar_overlay", root.platformInverted)
+ border {
+ left: platformStyle.borderSizeMedium
+ right: platformStyle.borderSizeMedium
+ top: 0
+ bottom: 0
+ }
+ }
+ }
+ }
+
+ Component {
+ id: determinateContent
+
+ Item {
+ id: progressMask
+
+ width: model.position
+ clip: true
+
+ BorderImage {
+ id: progress
+
+ source: privateStyle.imagePath("qtg_fr_progressbar_fill", root.platformInverted)
+ border {
+ left: platformStyle.borderSizeMedium
+ right: platformStyle.borderSizeMedium
+ top: 0
+ bottom: 0
+ }
+ height: parent.height
+ width: root.width
+ }
+ }
+ }
+
+ RangeModel {
+ id: model
+ minimumValue: 0.0
+ maximumValue: 1.0
+ positionAtMinimum: 0.0
+ positionAtMaximum: background.width
+ }
+}
+
--- /dev/null
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the Qt Components project.
+**
+** $QT_BEGIN_LICENSE:BSD$
+** You may use this file under the terms of the BSD license as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions and the following disclaimer in
+** the documentation and/or other materials provided with the
+** distribution.
+** * Neither the name of Nokia Corporation and its Subsidiary(-ies) nor
+** the names of its contributors may be used to endorse or promote
+** products derived from this software without specific prior written
+** permission.
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick 1.1
+import "." 1.1
+
+CommonDialog {
+ id: root
+ objectName: "root"
+
+ property string message
+ property string acceptButtonText
+ property string rejectButtonText
+ property alias icon: root.titleIcon // for backwards compatibility
+
+ onAcceptButtonTextChanged: internal.updateButtonTexts()
+ onRejectButtonTextChanged: internal.updateButtonTexts()
+
+ onStatusChanged: {
+ if (status == DialogStatus.Open)
+ scrollBar.flash()
+ }
+
+ onButtonClicked: {
+ if (acceptButtonText && index == 0)
+ accepted()
+ else
+ rejected()
+ }
+
+ content: Item {
+ height: {
+ if (root.height > 0)
+ return Math.min(Math.max(privateStyle.dialogMinSize, root.height) - privateTitleHeight - privateButtonsHeight, root.platformContentMaximumHeight)
+ else
+ return Math.min(label.paintedHeight, root.platformContentMaximumHeight)
+ }
+ width: parent.width
+
+ Item {
+ anchors {
+ top: parent.top; topMargin: platformStyle.paddingLarge
+ bottom: parent.bottom; bottomMargin: platformStyle.paddingLarge
+ left: parent.left; leftMargin: platformStyle.paddingLarge
+ right: parent.right
+ }
+
+ Flickable {
+ id: flickable
+ width: parent.width
+ height: parent.height
+ anchors { left: parent.left; top: parent.top }
+ contentHeight: label.paintedHeight
+ flickableDirection: Flickable.VerticalFlick
+ clip: true
+ interactive: contentHeight > height
+
+ Text {
+ id: label
+ anchors { right: parent.right; rightMargin: privateStyle.scrollBarThickness }
+ width: flickable.width - privateStyle.scrollBarThickness
+ font { family: platformStyle.fontFamilyRegular; pixelSize: platformStyle.fontSizeMedium }
+ color: root.platformInverted ? platformStyle.colorNormalLightInverted
+ : platformStyle.colorNormalLight
+ wrapMode: Text.WordWrap
+ text: root.message
+ horizontalAlignment: Text.AlignLeft
+ }
+ }
+
+ ScrollBar {
+ id: scrollBar
+ height: parent.height
+ anchors { top: flickable.top; right: flickable.right }
+ flickableItem: flickable
+ interactive: false
+ orientation: Qt.Vertical
+ platformInverted: root.platformInverted
+ }
+ }
+ }
+
+ QtObject {
+ id: internal
+
+ function updateButtonTexts() {
+ var newButtonTexts = []
+ if (acceptButtonText)
+ newButtonTexts.push(acceptButtonText)
+ if (rejectButtonText)
+ newButtonTexts.push(rejectButtonText)
+ root.buttonTexts = newButtonTexts
+ }
+ }
+}
--- /dev/null
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the Qt Components project.
+**
+** $QT_BEGIN_LICENSE:BSD$
+** You may use this file under the terms of the BSD license as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions and the following disclaimer in
+** the documentation and/or other materials provided with the
+** distribution.
+** * Neither the name of Nokia Corporation and its Subsidiary(-ies) nor
+** the names of its contributors may be used to endorse or promote
+** products derived from this software without specific prior written
+** permission.
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick 1.1
+import Qt.labs.components 1.1
+import "." 1.1
+
+Item {
+ id: root
+
+ // Common Public API
+ property alias checked: checkable.checked
+ property bool pressed: stateGroup.state == "Pressed" || stateGroup.state == "KeyPressed"
+ signal clicked
+ property alias text: label.text
+
+ // Symbian specific API
+ property alias platformExclusiveGroup: checkable.exclusiveGroup
+ property bool platformInverted: false
+
+ QtObject {
+ id: internal
+ objectName: "internal"
+ property color disabledColor: root.platformInverted ? platformStyle.colorDisabledLightInverted
+ : platformStyle.colorDisabledLight
+ property color pressedColor: root.platformInverted ? platformStyle.colorPressedInverted
+ : platformStyle.colorPressed
+ property color normalColor: root.platformInverted ? platformStyle.colorNormalLightInverted
+ : platformStyle.colorNormalLight
+
+ function toggle() {
+ clickedEffect.restart()
+ checkable.toggle()
+ root.clicked()
+ }
+
+ function icon_postfix() {
+ if (pressed)
+ return "pressed"
+ else if (root.checked) {
+ if (!root.enabled)
+ return "disabled_selected"
+ else
+ return "normal_selected"
+ } else {
+ if (!root.enabled)
+ return "disabled_unselected"
+ else
+ return "normal_unselected"
+ }
+ }
+ }
+
+ StateGroup {
+ id: stateGroup
+
+ states: [
+ State { name: "Pressed" },
+ State { name: "KeyPressed" },
+ State { name: "Canceled" }
+ ]
+
+ transitions: [
+ Transition {
+ to: "Pressed"
+ ScriptAction { script: privateStyle.play(Android.BasicItem) }
+ },
+ Transition {
+ from: "Pressed"
+ to: ""
+ ScriptAction { script: privateStyle.play(Android.CheckBox) }
+ ScriptAction { script: internal.toggle() }
+ },
+ Transition {
+ from: "KeyPressed"
+ to: ""
+ ScriptAction { script: internal.toggle() }
+ }
+ ]
+ }
+
+ implicitWidth: privateStyle.textWidth(label.text, label.font) + platformStyle.paddingMedium + privateStyle.buttonSize
+ implicitHeight: privateStyle.buttonSize
+
+ Image {
+ id: image
+ source: privateStyle.imagePath("qtg_graf_radiobutton_" + internal.icon_postfix(),
+ root.platformInverted)
+ anchors.left: parent.left
+ anchors.verticalCenter: parent.verticalCenter
+ sourceSize.width: privateStyle.buttonSize
+ sourceSize.height: privateStyle.buttonSize
+
+ MouseArea {
+ id: mouseArea
+ anchors.fill: parent
+
+ onPressed: stateGroup.state = "Pressed"
+ onReleased: stateGroup.state = ""
+ onClicked: stateGroup.state = ""
+ onExited: stateGroup.state = "Canceled"
+ onCanceled: {
+ // Mark as canceled
+ stateGroup.state = "Canceled"
+ // Reset state. Can't expect a release since mouse was ungrabbed
+ stateGroup.state = ""
+ }
+ }
+ }
+
+ Text {
+ id: label
+ elide: Text.ElideRight
+ anchors.left: image.right
+ anchors.leftMargin: platformStyle.paddingMedium
+ anchors.verticalCenter: parent.verticalCenter
+ anchors.right: parent.right
+ horizontalAlignment: Text.AlignLeft
+
+ font { family: platformStyle.fontFamilyRegular; pixelSize: platformStyle.fontSizeMedium }
+ color: root.enabled ? (root.pressed ? internal.pressedColor : internal.normalColor)
+ : internal.disabledColor
+ }
+
+ ParallelAnimation {
+ id: clickedEffect
+ SequentialAnimation {
+ PropertyAnimation {
+ target: image
+ property: "scale"
+ from: 1.0
+ to: 0.8
+ easing.type: Easing.Linear
+ duration: 50
+ }
+ PropertyAnimation {
+ target: image
+ property: "scale"
+ from: 0.8
+ to: 1.0
+ easing.type: Easing.OutQuad
+ duration: 170
+ }
+ }
+ }
+
+ Keys.onPressed: {
+ if (!event.isAutoRepeat && (event.key == Qt.Key_Select
+ || event.key == Qt.Key_Return
+ || event.key == Qt.Key_Enter)) {
+ stateGroup.state = "KeyPressed"
+ event.accepted = true
+ }
+ }
+
+ Keys.onReleased: {
+ if (!event.isAutoRepeat && (event.key == Qt.Key_Select
+ || event.key == Qt.Key_Return
+ || event.key == Qt.Key_Enter)) {
+ stateGroup.state = ""
+ event.accepted = true
+ }
+ }
+
+ Checkable {
+ id: checkable
+ value: root.text
+ enabled: true
+ }
+}
--- /dev/null
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the Qt Components project.
+**
+** $QT_BEGIN_LICENSE:BSD$
+** You may use this file under the terms of the BSD license as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions and the following disclaimer in
+** the documentation and/or other materials provided with the
+** distribution.
+** * Neither the name of Nokia Corporation and its Subsidiary(-ies) nor
+** the names of its contributors may be used to endorse or promote
+** products derived from this software without specific prior written
+** permission.
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+.pragma library
+
+function rectContainsPoint(rect, x, y) {
+ return rect.x < x
+ && x < rect.x + rect.width
+ && rect.y < y
+ && y < rect.y + rect.height;
+}
+
+function rectIntersectsRect(rect1, rect2) {
+ return !(rect2.x > rect1.x + rect1.width || rect2.x + rect2.width < rect1.x ||
+ rect2.y > rect1.y + rect1.height || rect2.y + rect2.height < rect1.y);
+}
+
+// returns true if rect1 contains rect2
+function rectContainsRect(rect1, rect2) {
+ return (rect1.x < rect2.x && rect2.x + rect2.width < rect1.x + rect1.width &&
+ rect1.y < rect2.y && rect2.y + rect2.height < rect1.y + rect1.height);
+}
+
+function manhattan(point1, point2) {
+ return Math.abs(point1.x - point2.x) + Math.abs(point1.y - point2.y)
+}
--- /dev/null
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the Qt Components project.
+**
+** $QT_BEGIN_LICENSE:BSD$
+** You may use this file under the terms of the BSD license as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions and the following disclaimer in
+** the documentation and/or other materials provided with the
+** distribution.
+** * Neither the name of Nokia Corporation and its Subsidiary(-ies) nor
+** the names of its contributors may be used to endorse or promote
+** products derived from this software without specific prior written
+** permission.
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick 1.1
+import "SectionScroller.js" as Sections
+import "." 1.1
+
+Item {
+ id: root
+
+ property Flickable flickableItem: null
+ property int orientation: Qt.Vertical
+ property bool interactive: true
+ property int policy: Android.ScrollBarWhenScrolling
+ property bool privateSectionScroller: false
+ property bool platformInverted: false
+
+ //implicit values for qml designer when no Flickable is present
+ implicitHeight: privateStyle.scrollBarThickness * (orientation == Qt.Vertical ? 3 : 1)
+ implicitWidth: privateStyle.scrollBarThickness * (orientation == Qt.Horizontal ? 3 : 1)
+ height: {
+ if (flickableItem && orientation == Qt.Vertical)
+ return Math.floor(Math.round(flickableItem.height) - anchors.topMargin - anchors.bottomMargin)
+ return undefined
+ }
+ width: {
+ if (flickableItem && orientation == Qt.Horizontal)
+ return Math.floor(Math.round(flickableItem.width) - anchors.leftMargin - anchors.rightMargin)
+ return undefined
+ }
+ opacity: internal.rootOpacity
+
+ onFlickableItemChanged: internal.initSectionScroller();
+ onPrivateSectionScrollerChanged: internal.initSectionScroller();
+
+ //For showing explicitly a ScrollBar if policy is Android.ScrollBarWhenScrolling
+ function flash(type) {
+ if (policy == Android.ScrollBarWhenScrolling && internal.scrollBarNeeded) {
+ flashEffect.type = (type == undefined) ? Android.FadeOut : type
+ flashEffect.restart()
+ }
+ }
+
+ Connections {
+ target: screen
+ onCurrentOrientationChanged: flash()
+ }
+
+ Connections {
+ target: root.privateSectionScroller ? flickableItem : null
+ onModelChanged: internal.initSectionScroller()
+ }
+
+ Loader {
+ id: listItemInteraction
+ sourceComponent: flickableItem && flickableItem.hasOwnProperty("currentIndex") && flickableItem.activeFocus ? listItemInteractionComponent : undefined
+ }
+
+ Component {
+ id: listItemInteractionComponent
+ Item {
+ Connections {
+ target: symbian
+ onListInteractionModeChanged: flash()
+ onPrivateListItemKeyNavigation: flash()
+ }
+ }
+ }
+
+ QtObject {
+ id: internal
+ property int hideTimeout: 500
+ property int pageStepY: flickableItem ? Math.floor(flickableItem.visibleArea.heightRatio * flickableItem.contentHeight) : NaN
+ property int pageStepX: flickableItem ? Math.floor(flickableItem.visibleArea.widthRatio * flickableItem.contentWidth) : NaN
+ property int handleY: flickableItem ? Math.floor(handle.y / flickableItem.height * flickableItem.contentHeight) : NaN
+ property int handleX: flickableItem ? Math.floor(handle.x / flickableItem.width * flickableItem.contentWidth) : NaN
+ property int maximumY: flickableItem ? Math.floor(Math.min(flickableItem.contentHeight - root.height, flickableItem.contentY)) : NaN
+ property int maximumX: flickableItem ? Math.floor(Math.min(flickableItem.contentWidth - root.width, flickableItem.contentX)) : NaN
+ property bool scrollBarNeeded: root.visible && hasScrollableContent()
+ //Sets currentSection to empty string when flickableItem.currentSection is null
+ property string currentSection: flickableItem ? flickableItem.currentSection || "" : ""
+ //To be able to pressed on trackMouseArea, opacity needs to be greater than 0
+ property real rootOpacity: root.privateSectionScroller ? 0.01 : 0
+
+ // The following properties are used for calculating handle position and size:
+ // Minimum allowed handle length
+ property real minHandleLength: 3 * Math.floor(privateStyle.scrollBarThickness)
+ // Scroll bar "container" length
+ property real totalLength: !flickableItem ? NaN : (orientation == Qt.Vertical ? root.height : root.width)
+ property real relativeHandlePosition: !flickableItem ? NaN : (orientation == Qt.Vertical
+ ? flickableItem.visibleArea.yPosition
+ : flickableItem.visibleArea.xPosition)
+ property real lengthRatio: !flickableItem ? NaN : (orientation == Qt.Vertical
+ ? flickableItem.visibleArea.heightRatio
+ : flickableItem.visibleArea.widthRatio)
+ // Scroll bar handle length under normal circumstances
+ property real staticHandleLength: Math.max(minHandleLength, lengthRatio * totalLength)
+ // Adjustment factor needed to calculate correct position, which is needed because
+ // relativeHandlePosition and lengthRatio are assuming default handle length. Dividend is
+ // the maximum handle position taking into account restricted minimum handle length, whereas
+ // divisor is the maximum handle position if default handle size would be used.
+ property real handlePositionAdjustment: (totalLength - staticHandleLength) / (totalLength * (1 - lengthRatio))
+ property real handlePosition
+ handlePosition: {
+ // handle's position, which is adjusted to take into account non-default handle
+ // length and restricted never to exceed flickable boundaries
+ var pos = totalLength * relativeHandlePosition * handlePositionAdjustment
+ return Math.min(Math.max(0, pos), totalLength - minHandleLength)
+ }
+ property real dynamicHandleLength
+ dynamicHandleLength: {
+ // dynamic handle length, which may differ from static due to bounds behavior, i.e.
+ // handle gets shorter when content exceeds flickable boundaries
+ var length = 0
+ if (relativeHandlePosition >= 1 - lengthRatio) // overflow
+ length = 1 - relativeHandlePosition
+ else if (relativeHandlePosition < 0) // underflow
+ length = lengthRatio + relativeHandlePosition
+ else
+ length = lengthRatio
+ return Math.max(minHandleLength, length * totalLength)
+ }
+
+ // Show flash effect in case if no flicking (flickableItem.moving) has occured
+ // but there is a need to indicate scrollable content.
+ onScrollBarNeededChanged: {
+ if (stateGroup.state == "") {
+ if (scrollBarNeeded)
+ flash()
+ else
+ idleEffect.restart()
+ }
+ }
+
+ /**
+ * Checks whether ScrollBar is needed or not
+ * based on Flickable visibleArea height and width ratios
+ */
+ function hasScrollableContent() {
+ if (!flickableItem)
+ return false
+ var ratio = orientation == Qt.Vertical ? flickableItem.visibleArea.heightRatio : flickableItem.visibleArea.widthRatio
+ return ratio < 1.0 && ratio > 0
+ }
+ /**
+ * Does Page by Page movement of flickableItem
+ * when ScrollBar Track is being clicked/pressed
+ *
+ * @see #moveToLongTapPosition
+ */
+ function doPageStep() {
+ if (orientation == Qt.Vertical) {
+ if (trackMouseArea.mouseY > (handle.height / 2 + handle.y)) {
+ flickableItem.contentY += pageStepY
+ flickableItem.contentY = maximumY
+ }
+ else if (trackMouseArea.mouseY < (handle.height / 2 + handle.y)) {
+ flickableItem.contentY -= pageStepY
+ flickableItem.contentY = Math.max(0, flickableItem.contentY)
+ }
+ } else {
+ if (trackMouseArea.mouseX > (handle.width / 2 + handle.x)) {
+ flickableItem.contentX += pageStepX
+ flickableItem.contentX = maximumX
+ }
+ else if (trackMouseArea.mouseX < (handle.width / 2 + handle.x)) {
+ flickableItem.contentX -= pageStepX
+ flickableItem.contentX = Math.max(0, flickableItem.contentX)
+ }
+ }
+ }
+ /**
+ * Does movement of flickableItem
+ * when ScrollBar Handle is being dragged
+ */
+ function moveToHandlePosition() {
+ if (orientation == Qt.Vertical)
+ flickableItem.contentY = handleY
+ else
+ flickableItem.contentX = handleX
+ }
+ /**
+ * Moves flickableItem's content according to given mouseArea movement
+ * when mouseArea is pressed long
+ * Tries to position the handle and content in center of mouse position enough
+ *
+ * @see #doPageStep
+ */
+ function moveToLongTapPosition(mouseArea) {
+ if (orientation == Qt.Vertical) {
+ if (Math.abs(mouseArea.mouseY - (handle.height / 2 + handle.y)) < privateStyle.scrollBarThickness)
+ return //if change is not remarkable enough, do nothing otherwise it would cause annoying flickering effect
+ if (mouseArea.mouseY > (handle.height / 2 + handle.y)) {
+ flickableItem.contentY += Math.floor(privateStyle.scrollBarThickness)
+ flickableItem.contentY = maximumY
+ }
+ else if (mouseArea.mouseY < (handle.height / 2 + handle.y)) {
+ flickableItem.contentY -= Math.floor(privateStyle.scrollBarThickness)
+ flickableItem.contentY = Math.floor(Math.max(0, flickableItem.contentY))
+ }
+ } else {
+ if (Math.abs(mouseArea.mouseX - (handle.width / 2 + handle.x)) < privateStyle.scrollBarThickness)
+ return //if change is not remarkable enough, do nothing otherwise it would cause annoying flickering effect
+ if (mouseArea.mouseX > (handle.width / 2 + handle.x)) {
+ flickableItem.contentX += Math.floor(privateStyle.scrollBarThickness)
+ flickableItem.contentX = maximumX
+ }
+ else if (mouseArea.mouseX < (handle.width / 2 + handle.x)) {
+ flickableItem.contentX -= Math.floor(privateStyle.scrollBarThickness)
+ flickableItem.contentX = Math.floor(Math.max(0, flickableItem.contentX))
+ }
+ }
+ }
+
+ function adjustContentPosition(y) {
+ if (y < 0 || y > trackMouseArea.height)
+ return;
+
+ var sect = Sections.closestSection(y / trackMouseArea.height);
+ var idx = Sections.indexOf(sect);
+ currentSection = sect;
+ flickableItem.positionViewAtIndex(idx, ListView.Beginning);
+ }
+
+ function initSectionScroller() {
+ if (root.privateSectionScroller && flickableItem && flickableItem.model)
+ Sections.initSectionData(flickableItem);
+ }
+ }
+
+ BorderImage {
+ id: track
+ objectName: "track"
+ source: privateStyle.imagePath((orientation == Qt.Vertical
+ ? "qtg_fr_scrollbar_v_track_normal"
+ : "qtg_fr_scrollbar_h_track_normal"),
+ root.platformInverted)
+ visible: interactive
+ anchors.fill: parent
+ border.right: orientation == Qt.Horizontal ? 7 : 0
+ border.left: orientation == Qt.Horizontal ? 7 : 0
+ border.top: orientation == Qt.Vertical ? 7 : 0
+ border.bottom: orientation == Qt.Vertical ? 7 : 0
+ onVisibleChanged: { idleEffect.complete(); flashEffect.complete() }
+ }
+
+ Loader {
+ id: sectionScrollBackground
+ anchors.right: trackMouseArea.right
+ width: flickableItem ? flickableItem.width : 0
+ height: platformStyle.fontSizeMedium * 5
+ sourceComponent: root.privateSectionScroller ? sectionScrollComponent : null
+ }
+
+ Component {
+ id: sectionScrollComponent
+ BorderImage {
+ id: indexFeedbackBackground
+ objectName: "indexFeedbackBackground"
+ source: privateStyle.imagePath("qtg_fr_popup_transparent", root.platformInverted)
+ border { left: platformStyle.borderSizeMedium; top: platformStyle.borderSizeMedium; right: platformStyle.borderSizeMedium; bottom: platformStyle.borderSizeMedium }
+ visible: trackMouseArea.pressed
+ anchors.fill: parent
+ Text {
+ id: indexFeedbackText
+ objectName: "indexFeedbackText"
+ color: root.platformInverted ? platformStyle.colorNormalDarkInverted // intentionally dark inverted
+ : platformStyle.colorNormalLight
+ anchors {
+ left: parent.left;
+ leftMargin: platformStyle.paddingLarge;
+ right: parent.right;
+ rightMargin: platformStyle.paddingLarge;
+ verticalCenter: parent.verticalCenter
+ }
+ font {
+ family: platformStyle.fontFamilyRegular;
+ pixelSize: indexFeedbackText.text.length == 1 ? platformStyle.fontSizeMedium * 4 : platformStyle.fontSizeMedium * 2;
+ capitalization: indexFeedbackText.text.length == 1 ? Font.AllUppercase : Font.MixedCase
+ }
+ text: internal.currentSection
+ horizontalAlignment: Text.AlignLeft
+ elide: Text.ElideRight
+ }
+ states: [
+ State {
+ when: (handle.y + (handle.height / 2)) - (sectionScrollBackground.height / 2) < 0
+ AnchorChanges {
+ target: sectionScrollBackground
+ anchors { verticalCenter: undefined; top: track.top; bottom: undefined }
+ }
+ },
+ State {
+ when: (handle.y + (handle.height / 2)) + (sectionScrollBackground.height / 2) >= track.height
+ AnchorChanges {
+ target: sectionScrollBackground
+ anchors { verticalCenter: undefined; top: undefined; bottom: track.bottom }
+ }
+ },
+ State {
+ when: (handle.y + (handle.height / 2)) - (sectionScrollBackground.height / 2) >= 0
+ AnchorChanges {
+ target: sectionScrollBackground
+ anchors { verticalCenter: handle.verticalCenter; top: undefined; bottom: undefined }
+ }
+ }
+ ]
+ }
+ }
+
+ // MouseArea for the move content "page by page" by tapping and scroll to press-and-hold position
+ MouseArea {
+ id: trackMouseArea
+ objectName: "trackMouseArea"
+ property bool longPressed: false
+ enabled: root.privateSectionScroller || interactive
+ anchors {
+ top: root.privateSectionScroller ? parent.top : undefined;
+ bottom: root.privateSectionScroller ? parent.bottom : undefined;
+ right: root.privateSectionScroller ? parent.right : undefined;
+ fill: root.privateSectionScroller ? undefined : (flickableItem ? track : undefined)
+ }
+ width: root.privateSectionScroller ? privateStyle.scrollBarThickness * 3 : undefined
+ drag {
+ target: root.privateSectionScroller ? sectionScrollBackground : undefined
+ // axis is set XandY to prevent flickable from stealing the mouse event
+ // SectionScroller is anchored to the right side of the mouse area so the user
+ // won't be able to drag it along the X axis
+ axis: root.privateSectionScroller ? Drag.XandYAxis : 0
+ minimumY: root.privateSectionScroller ? (flickableItem ? flickableItem.y : 0) : 0
+ maximumY: root.privateSectionScroller ? (flickableItem ? (trackMouseArea.height - sectionScrollBackground.height) : 0) : 0
+ }
+
+ onPressAndHold: {
+ if (!root.privateSectionScroller)
+ longPressed = true
+ }
+
+ onReleased: longPressed = false
+
+ onPositionChanged: {
+ if (root.privateSectionScroller)
+ internal.adjustContentPosition(trackMouseArea.mouseY);
+ }
+
+ onPressedChanged: {
+ if (root.privateSectionScroller && trackMouseArea.pressed)
+ internal.adjustContentPosition(trackMouseArea.mouseY);
+ }
+ }
+ Timer {
+ id: pressAndHoldTimer
+ running: trackMouseArea.longPressed
+ interval: 50
+ repeat: true
+ onTriggered: { internal.moveToLongTapPosition(trackMouseArea); privateStyle.play(Android.SensitiveSlider) }
+ }
+
+ BorderImage {
+ id: handle
+ objectName: "handle"
+ source: privateStyle.imagePath(handleFileName(), root.platformInverted)
+ x: orientation == Qt.Horizontal ? internal.handlePosition : NaN
+ y: orientation == Qt.Vertical ? internal.handlePosition : NaN
+ height: orientation == Qt.Vertical ? internal.dynamicHandleLength : root.height
+ width: orientation == Qt.Horizontal ? internal.dynamicHandleLength : root.width
+ border.right: orientation == Qt.Horizontal ? 7 : 0
+ border.left: orientation == Qt.Horizontal ? 7 : 0
+ border.top: orientation == Qt.Vertical ? 7 : 0
+ border.bottom: orientation == Qt.Vertical ? 7 : 0
+
+ function handleFileName() {
+ var fileName = (orientation == Qt.Vertical ? "qtg_fr_scrollbar_v_handle_" :
+ "qtg_fr_scrollbar_h_handle_")
+ if (!interactive)
+ fileName += "indicative"
+ else if (handleMouseArea.pressed)
+ fileName += "pressed"
+ else
+ fileName += "normal"
+ return fileName
+ }
+ }
+
+ MouseArea {
+ id: handleMouseArea
+ objectName: "handleMouseArea"
+ property real maxDragY: flickableItem ? flickableItem.height - handle.height - root.anchors.topMargin - root.anchors.bottomMargin : NaN
+ property real maxDragX: flickableItem ? flickableItem.width - handle.width - root.anchors.leftMargin - root.anchors.rightMargin : NaN
+ enabled: interactive && !root.privateSectionScroller
+ width: orientation == Qt.Vertical ? 3 * privateStyle.scrollBarThickness : handle.width
+ height: orientation == Qt.Horizontal ? 3 * privateStyle.scrollBarThickness : handle.height
+ anchors {
+ verticalCenter: flickableItem ? handle.verticalCenter : undefined
+ horizontalCenter: flickableItem ? handle.horizontalCenter : undefined
+ }
+ drag {
+ target: handle
+ axis: orientation == Qt.Vertical ? Drag.YAxis : Drag.XAxis
+ minimumY: 0
+ maximumY: maxDragY
+ minimumX: 0
+ maximumX: maxDragX
+ }
+ onPositionChanged: internal.moveToHandlePosition()
+ }
+
+ PropertyAnimation {
+ id: indicateEffect
+
+ function play() {
+ flashEffect.stop()
+ idleEffect.stop()
+ restart()
+ }
+
+ target: root
+ property: "opacity"
+ to: 1
+ duration: 0
+ }
+ SequentialAnimation {
+ id: idleEffect
+
+ function play() {
+ indicateEffect.stop()
+ if (internal.scrollBarNeeded && root.policy == Android.ScrollBarWhenScrolling)
+ restart()
+ }
+
+ PauseAnimation { duration: root.interactive ? 1500 : 0 }
+ PropertyAnimation {
+ target: root
+ property: "opacity"
+ to: internal.rootOpacity
+ duration: internal.hideTimeout
+ }
+ }
+ SequentialAnimation {
+ id: flashEffect
+ property int type: Android.FadeOut
+
+ PropertyAnimation {
+ target: root
+ property: "opacity"
+ to: 1
+ duration: (flashEffect.type == Android.FadeInFadeOut) ? internal.hideTimeout : 0
+ }
+ PropertyAnimation {
+ target: root
+ property: "opacity"
+ to: internal.rootOpacity
+ duration: internal.hideTimeout
+ }
+ }
+ StateGroup {
+ id: stateGroup
+ states: [
+ State {
+ name: "Move"
+ when: handleMouseArea.pressed
+ },
+ State {
+ name: "Stepping"
+ when: trackMouseArea.longPressed
+ },
+ State {
+ name: "Step"
+ when: trackMouseArea.pressed && !trackMouseArea.longPressed && !root.privateSectionScroller
+ },
+ State {
+ name: "Indicate"
+ when: (internal.scrollBarNeeded && flickableItem.moving) ||
+ (trackMouseArea.pressed && root.privateSectionScroller)
+ },
+ State {
+ name: ""
+ }
+ ]
+ transitions: [
+ Transition {
+ to: "Move"
+ ScriptAction { script: privateStyle.play(Android.BasicSlider) }
+ ScriptAction { script: indicateEffect.play() }
+ },
+ Transition {
+ to: "Step"
+ ScriptAction { script: internal.doPageStep() }
+ ScriptAction { script: privateStyle.play(Android.BasicSlider) }
+ ScriptAction { script: indicateEffect.play() }
+ },
+ Transition {
+ from: "Step"
+ to: "Stepping"
+ ScriptAction { script: indicateEffect.play() }
+ },
+ Transition {
+ from: "Move"
+ to: "Indicate"
+ ScriptAction { script: privateStyle.play(Android.BasicSlider) }
+ ScriptAction { script: indicateEffect.play() }
+ },
+ Transition {
+ to: "Indicate"
+ ScriptAction { script: indicateEffect.play() }
+ },
+ Transition {
+ from: "Move"
+ to: ""
+ ScriptAction { script: privateStyle.play(Android.BasicSlider) }
+ ScriptAction { script: idleEffect.play() }
+ },
+ Transition {
+ to: ""
+ ScriptAction { script: idleEffect.play() }
+ }
+ ]
+ }
+}
--- /dev/null
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the Qt Components project.
+**
+** $QT_BEGIN_LICENSE:BSD$
+** You may use this file under the terms of the BSD license as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions and the following disclaimer in
+** the documentation and/or other materials provided with the
+** distribution.
+** * Neither the name of Nokia Corporation and its Subsidiary(-ies) nor
+** the names of its contributors may be used to endorse or promote
+** products derived from this software without specific prior written
+** permission.
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick 1.1
+import "." 1.1
+
+Item {
+ id: root
+
+ //Common Public API
+ property Flickable flickableItem: null
+
+ // Symbian specific API
+ property bool platformInverted: false
+
+ Item {
+ id: decorators
+ property bool completed: false
+
+ Loader {
+ sourceComponent: decorators.completed ? vertical : undefined
+ }
+ Loader {
+ sourceComponent: decorators.completed ? horizontal : undefined
+ }
+ Component {
+ id: horizontal
+ ScrollBar {
+ parent: flickableItem
+ flickableItem: root.flickableItem
+ orientation: Qt.Horizontal
+ interactive: false
+ platformInverted: root.platformInverted
+ anchors {
+ left: flickableItem.left
+ bottom: flickableItem.bottom
+ rightMargin: height
+ }
+ }
+ }
+ Component {
+ id: vertical
+ ScrollBar {
+ parent: flickableItem
+ flickableItem: root.flickableItem
+ orientation: Qt.Vertical
+ interactive: false
+ platformInverted: root.platformInverted
+ anchors { top: flickableItem.top; right: flickableItem.right }
+ }
+ }
+ Component.onDestruction: {
+ decorators.completed = false
+ }
+ }
+ onFlickableItemChanged: {
+ decorators.completed = flickableItem ? true : false
+ }
+}
--- /dev/null
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the Qt Components project.
+**
+** $QT_BEGIN_LICENSE:BSD$
+** You may use this file under the terms of the BSD license as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions and the following disclaimer in
+** the documentation and/or other materials provided with the
+** distribution.
+** * Neither the name of Nokia Corporation and its Subsidiary(-ies) nor
+** the names of its contributors may be used to endorse or promote
+** products derived from this software without specific prior written
+** permission.
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+var _sectionData = [];
+var _sections = [];
+
+function initSectionData(list) {
+ if (!list || !list.model) return;
+ _sectionData = [];
+ _sections = [];
+ var current = "";
+ var prop = list.section.property;
+
+ for (var i = 0, count = list.model.count; i < count; i++) {
+ var item = list.model.get(i);
+ if (item[prop] !== current) {
+ current = item[prop];
+ _sections.push(current);
+ _sectionData.push({ index: i, header: current });
+ }
+ }
+}
+
+function closestSection(pos) {
+ var tmp = (_sections.length) * pos;
+ var val = Math.ceil(tmp) // TODO: better algorithm
+ val = val < 2 ? 1 : val;
+ return _sections[val-1];
+}
+
+function indexOf(sectionName) {
+ var val = _sectionData[_sections.indexOf(sectionName)].index;
+ return val === 0 || val > 0 ? val : -1;
+}
--- /dev/null
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the Qt Components project.
+**
+** $QT_BEGIN_LICENSE:BSD$
+** You may use this file under the terms of the BSD license as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions and the following disclaimer in
+** the documentation and/or other materials provided with the
+** distribution.
+** * Neither the name of Nokia Corporation and its Subsidiary(-ies) nor
+** the names of its contributors may be used to endorse or promote
+** products derived from this software without specific prior written
+** permission.
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick 1.1
+import "SectionScroller.js" as Sections
+import "." 1.1
+
+Item {
+ id: root
+
+ property ListView listView
+ property bool platformInverted: false
+
+ onListViewChanged: {
+ if (listView && listView.model)
+ internal.initDirtyObserver();
+ }
+
+ Connections {
+ target: listView
+ onModelChanged: {
+ if (listView && listView.model)
+ internal.initDirtyObserver();
+ }
+ }
+
+ ScrollBar {
+ id: scrollBar
+ parent: listView
+ flickableItem: listView
+ privateSectionScroller: true
+ platformInverted: root.platformInverted
+ anchors {
+ top: parent ? parent.top : undefined
+ right: parent ? parent.right : undefined
+ }
+ }
+
+ QtObject {
+ id: internal
+
+ function initDirtyObserver() {
+ Sections.initSectionData(listView);
+ function dirtyObserver() {
+ if (!internal.modelDirty) {
+ internal.modelDirty = true;
+ dirtyTimer.running = true;
+ }
+ }
+
+ if (listView.model.countChanged)
+ listView.model.countChanged.connect(dirtyObserver);
+
+ if (listView.model.itemsChanged)
+ listView.model.itemsChanged.connect(dirtyObserver);
+
+ if (listView.model.itemsInserted)
+ listView.model.itemsInserted.connect(dirtyObserver);
+
+ if (listView.model.itemsMoved)
+ listView.model.itemsMoved.connect(dirtyObserver);
+
+ if (listView.model.itemsRemoved)
+ listView.model.itemsRemoved.connect(dirtyObserver);
+ }
+ }
+}
--- /dev/null
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the Qt Components project.
+**
+** $QT_BEGIN_LICENSE:BSD$
+** You may use this file under the terms of the BSD license as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions and the following disclaimer in
+** the documentation and/or other materials provided with the
+** distribution.
+** * Neither the name of Nokia Corporation and its Subsidiary(-ies) nor
+** the names of its contributors may be used to endorse or promote
+** products derived from this software without specific prior written
+** permission.
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick 1.1
+import "." 1.1
+
+CommonDialog {
+ id: root
+
+ // Common API
+ property alias model: listView.model
+ property int selectedIndex: -1
+ property Component delegate: defaultDelegate
+
+ privateCloseIcon: true
+
+ Component {
+ id: defaultDelegate
+
+ MenuItem {
+ platformInverted: root.platformInverted
+ text: modelData
+ onClicked: {
+ selectedIndex = index
+ root.accept()
+ }
+
+ Keys.onPressed: {
+ if (event.key == Qt.Key_Up || event.key == Qt.Key_Down)
+ scrollBar.flash()
+ }
+ }
+ }
+
+ content: Item {
+ id: contentItem
+
+ function preferredHeight() {
+ // Need to create artifical binding to listView.delegate because of QTBUG-19037
+ var dummy = listView.delegate
+ var multiplier = screen.height > screen.width ? 0.45 : 0.6
+ var maxHeight = Math.floor(multiplier * screen.height / privateStyle.menuItemHeight)
+ * privateStyle.menuItemHeight
+ return Math.min(maxHeight, listView.count * privateStyle.menuItemHeight)
+ }
+
+ height: preferredHeight()
+ width: root.platformContentMaximumWidth
+
+ Item {
+ // Clipping item with bottom margin added to align content with rounded background graphics
+ id: clipItem
+ anchors.fill: parent
+ anchors.bottomMargin: platformStyle.paddingSmall
+ clip: true
+ ListView {
+ id: listView
+
+ currentIndex : -1
+ width: contentItem.width
+ height: contentItem.height
+ delegate: root.delegate
+ clip: true
+
+ Keys.onPressed: {
+ if (event.key == Qt.Key_Up || event.key == Qt.Key_Down
+ || event.key == Qt.Key_Left || event.key == Qt.Key_Right
+ || event.key == Qt.Key_Select || event.key == Qt.Key_Enter
+ || event.key == Qt.Key_Return) {
+ android.listInteractionMode = Android.KeyNavigation
+ listView.currentIndex = 0
+ event.accepted = true
+ }
+ }
+ }
+ }
+ ScrollBar {
+ id: scrollBar
+ flickableItem: listView
+ interactive: false
+ visible: listView.contentHeight > contentItem.height
+ platformInverted: root.platformInverted
+ anchors { top: clipItem.top; right: clipItem.right }
+ }
+ }
+
+ onClickedOutside: {
+ privateStyle.play(Android.PopupClose)
+ reject()
+ }
+
+ onStatusChanged: {
+ if (status == DialogStatus.Opening) {
+ if (listView.currentItem != null) {
+ listView.currentItem.focus = false
+ }
+ listView.currentIndex = -1
+ listView.positionViewAtIndex(0, ListView.Beginning)
+ }
+ else if (status == DialogStatus.Open) {
+ listView.focus = true
+ if (listView.contentHeight > contentItem.height)
+ scrollBar.flash(Android.FadeInFadeOut)
+ }
+ }
+}
--- /dev/null
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the Qt Components project.
+**
+** $QT_BEGIN_LICENSE:BSD$
+** You may use this file under the terms of the BSD license as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions and the following disclaimer in
+** the documentation and/or other materials provided with the
+** distribution.
+** * Neither the name of Nokia Corporation and its Subsidiary(-ies) nor
+** the names of its contributors may be used to endorse or promote
+** products derived from this software without specific prior written
+** permission.
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick 1.1
+import "." 1.1
+
+ListItem {
+ id: root
+ property string title: ""
+ property string subTitle: ""
+
+ implicitHeight: background.height + 2 * platformStyle.paddingLarge
+
+ onModeChanged: {
+ if (root.mode == "pressed") {
+ pressed.source = privateStyle.imagePath("qtg_fr_choice_list_pressed", root.platformInverted)
+ pressed.opacity = 1
+ } else {
+ releasedEffect.restart()
+ }
+ }
+
+ BorderImage {
+ id: background
+ height: privateStyle.menuItemHeight - platformStyle.paddingSmall // from layout spec.
+ anchors {
+ left: parent.left
+ leftMargin: platformStyle.paddingLarge
+ right: parent.right
+ rightMargin: privateStyle.scrollBarThickness
+ verticalCenter: parent.verticalCenter
+ }
+ border {
+ left: platformStyle.borderSizeMedium
+ top: platformStyle.borderSizeMedium
+ right: platformStyle.borderSizeMedium
+ bottom: platformStyle.borderSizeMedium
+ }
+ source: privateStyle.imagePath("qtg_fr_choice_list_" + internal.getBackground(),
+ root.platformInverted)
+
+ BorderImage {
+ id: pressed
+ border {
+ left: platformStyle.borderSizeMedium
+ top: platformStyle.borderSizeMedium
+ right: platformStyle.borderSizeMedium
+ bottom: platformStyle.borderSizeMedium
+ }
+ opacity: 0
+ anchors.fill: parent
+ }
+
+ Column {
+ anchors {
+ verticalCenter: background.verticalCenter
+ right: indicator.left
+ rightMargin: platformStyle.paddingMedium
+ left: background.left
+ leftMargin: platformStyle.paddingLarge
+ }
+
+ Loader {
+ anchors.left: parent.left
+ sourceComponent: title != "" ? titleText : undefined
+ width: parent.width // elide requires explicit width
+ }
+
+ Loader {
+ anchors.left: parent.left
+ sourceComponent: subTitle != "" ? subTitleText : undefined
+ width: parent.width // elide requires explicit width
+ }
+ }
+ Image {
+ id: indicator
+ source: root.mode == "disabled" ? privateStyle.imagePath("qtg_graf_choice_list_indicator_disabled",
+ root.platformInverted)
+ : privateStyle.imagePath("qtg_graf_choice_list_indicator",
+ root.platformInverted)
+ sourceSize.width: platformStyle.graphicSizeSmall
+ sourceSize.height: platformStyle.graphicSizeSmall
+ anchors {
+ right: background.right
+ rightMargin: platformStyle.paddingSmall
+ verticalCenter: parent.verticalCenter
+ }
+ }
+ }
+
+ Component {
+ id: titleText
+ ListItemText {
+ mode: root.mode
+ role: "SelectionTitle"
+ text: root.title
+ platformInverted: root.platformInverted
+ }
+ }
+ Component {
+ id: subTitleText
+ ListItemText {
+ mode: root.mode
+ role: "SelectionSubTitle"
+ text: root.subTitle
+ platformInverted: root.platformInverted
+ }
+ }
+
+ QtObject {
+ id: internal
+ function getBackground() {
+ if (root.mode == "highlighted")
+ return "highlighted"
+ else if (root.mode == "disabled")
+ return "disabled"
+ else
+ return "normal"
+ }
+ }
+
+ SequentialAnimation {
+ id: releasedEffect
+ PropertyAnimation {
+ target: pressed
+ property: "opacity"
+ to: 0
+ easing.type: Easing.Linear
+ duration: 150
+ }
+ }
+}
--- /dev/null
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the Qt Components project.
+**
+** $QT_BEGIN_LICENSE:BSD$
+** You may use this file under the terms of the BSD license as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions and the following disclaimer in
+** the documentation and/or other materials provided with the
+** distribution.
+** * Neither the name of Nokia Corporation and its Subsidiary(-ies) nor
+** the names of its contributors may be used to endorse or promote
+** products derived from this software without specific prior written
+** permission.
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick 1.1
+import "." 1.1
+import Qt.labs.components 1.1 as QtComponents
+
+Item {
+ id: root
+
+ // Common Public API
+ property alias stepSize: model.stepSize
+ property alias minimumValue: model.minimumValue
+ property alias maximumValue: model.maximumValue
+ property alias value: model.value
+ property int orientation: Qt.Horizontal
+ property bool pressed: track.inputActive
+ property bool valueIndicatorVisible: false
+ property string valueIndicatorText: ""
+ property alias inverted: model.inverted
+
+ LayoutMirroring.enabled: false
+ LayoutMirroring.childrenInherit: true
+
+ // Symbian specific
+ property bool platformInverted: false
+ signal valueChanged(real value)
+ implicitWidth: orientation == Qt.Horizontal ? 150 : privateStyle.menuItemHeight
+ implicitHeight: orientation == Qt.Horizontal ? privateStyle.menuItemHeight : 150
+
+ onActiveFocusChanged: {
+ if (!root.activeFocus)
+ track.activeKey = undefined
+ }
+
+ QtComponents.RangeModel {
+ id: model
+ value: 0.0
+ stepSize: 0.0
+ minimumValue: 0.0
+ maximumValue: 1.0
+ positionAtMinimum: 0
+ positionAtMaximum: orientation == Qt.Horizontal ? track.width - handle.width : track.height - handle.height
+ onValueChanged: root.valueChanged(value)
+ }
+
+ BorderImage {
+ id: track
+ objectName: "track"
+ property bool tapOnTrack: false
+ property variant activeKey
+ property bool inputActive: handleMouseArea.pressed || !!track.activeKey
+ onInputActiveChanged: {
+ if (!valueIndicatorVisible)
+ return
+ if (inputActive)
+ valueIndicator.show = true
+ else
+ indicatorTimer.restart()
+ }
+
+ states: [
+ State {
+ name: "Horizontal"
+ when: orientation == Qt.Horizontal
+
+ PropertyChanges {
+ target: track
+ height: privateStyle.sliderThickness
+ width: undefined
+ source: privateStyle.imagePath("qtg_fr_slider_h_track_normal", root.platformInverted)
+ border {
+ left: 20
+ right: 20
+ top: 0
+ bottom: 0
+ }
+ smooth: true
+ }
+
+ AnchorChanges {
+ target: track
+ anchors {
+ left: root.left
+ right: root.right
+ top: undefined
+ bottom: undefined
+ horizontalCenter: undefined
+ verticalCenter: root.verticalCenter
+ }
+ }
+ },
+ State {
+ name: "Vertical"
+ when: orientation == Qt.Vertical
+
+ PropertyChanges {
+ target: track
+ height: undefined
+ width: privateStyle.sliderThickness
+ source: privateStyle.imagePath("qtg_fr_slider_v_track_normal", root.platformInverted)
+ border {
+ left: 0
+ right: 0
+ top: 20
+ bottom: 20
+ }
+ smooth: true
+ }
+
+ AnchorChanges {
+ target: track
+ anchors {
+ left: undefined
+ right: undefined
+ top: root.top
+ bottom: root.bottom
+ horizontalCenter: root.horizontalCenter
+ verticalCenter: undefined
+ }
+ }
+ }
+ ]
+
+ anchors.leftMargin: platformStyle.paddingMedium
+ anchors.rightMargin: platformStyle.paddingMedium
+ anchors.topMargin: platformStyle.paddingMedium
+ anchors.bottomMargin: platformStyle.paddingMedium
+
+ MouseArea {
+ id: trackMouseArea
+ objectName: "trackMouseArea"
+
+ anchors.fill: parent
+
+ onClicked: {
+ if (track.tapOnTrack) {
+ if (orientation == Qt.Horizontal) {
+ if (handle.x > (mouseX - handle.width / 2)) {
+ model.value = inverted ? model.value + model.stepSize : model.value - model.stepSize
+ handle.x = model.position
+ } else {
+ model.value = inverted ? model.value - model.stepSize : model.value + model.stepSize
+ handle.x = model.position
+ }
+ } else {
+ if (handle.y > (mouseY - handle.height / 2)) {
+ model.value = inverted ? model.value + model.stepSize : model.value - model.stepSize
+ handle.y = model.position
+ } else {
+ model.value = inverted ? model.value - model.stepSize : model.value + model.stepSize
+ handle.y = model.position
+ }
+ }
+ }
+ }
+
+ Image {
+ id: handle
+ objectName: "handle"
+ x: orientation == Qt.Horizontal ? (handleMouseArea.pressed ? x : model.position) : 0
+ y: orientation == Qt.Horizontal ? 0 : (handleMouseArea.pressed ? y : model.position)
+
+ sourceSize.height: platformStyle.graphicSizeSmall
+ sourceSize.width: platformStyle.graphicSizeSmall
+
+ anchors.verticalCenter: orientation == Qt.Horizontal ? parent.verticalCenter : undefined
+ anchors.horizontalCenter: orientation == Qt.Horizontal ? undefined : parent.horizontalCenter
+
+ source: {
+ var handleIcon = "qtg_graf_slider_"
+ + (orientation == Qt.Horizontal ? "h" : "v")
+ + "_handle_"
+ + (handleMouseArea.pressed ? "pressed" : "normal")
+ privateStyle.imagePath(handleIcon, root.platformInverted)
+ }
+
+ onXChanged: valueIndicator.position()
+ onYChanged: valueIndicator.position()
+
+ MouseArea {
+ id: handleMouseArea
+ objectName: "handleMouseArea"
+
+ height: platformStyle.graphicSizeMedium
+ width: platformStyle.graphicSizeMedium
+ anchors.verticalCenter: orientation == Qt.Horizontal ? parent.verticalCenter : undefined
+ anchors.horizontalCenter: orientation == Qt.Horizontal ? undefined : parent.horizontalCenter
+
+ drag.target: handle
+ drag.axis: Drag.XandYAxis
+ drag.minimumX: orientation == Qt.Horizontal ? model.positionAtMinimum : 0
+ drag.maximumX: orientation == Qt.Horizontal ? model.positionAtMaximum : 0
+ drag.minimumY: orientation == Qt.Horizontal ? 0 : model.positionAtMinimum
+ drag.maximumY: orientation == Qt.Horizontal ? 0 : model.positionAtMaximum
+
+ onPositionChanged: model.position = orientation == Qt.Horizontal ? handle.x : handle.y
+ onPressed: privateStyle.play(Android.BasicSlider)
+ onReleased: privateStyle.play(Android.BasicSlider)
+ }
+ }
+ }
+ }
+
+ Keys.onPressed: {
+ internal.handleKeyPressEvent(event)
+ }
+
+ Keys.onReleased: {
+ internal.handleKeyReleaseEvent(event)
+ }
+
+ Component {
+ id: valueIndicatorComponent
+ ToolTip {
+ text: root.valueIndicatorText == "" ? model.value : root.valueIndicatorText
+ platformInverted: root.platformInverted
+ }
+ }
+
+ Loader {
+ id: valueIndicator
+
+ property int spacing: 2 * platformStyle.paddingLarge
+ // Must match with the "maxWidth" padding defined in ToolTip
+ property int toolTipPadding: platformStyle.paddingLarge
+ property bool show: false
+ sourceComponent: valueIndicator.show ? valueIndicatorComponent : undefined
+ onLoaded: position()
+
+ function position() {
+ if (!valueIndicatorVisible || status != Loader.Ready)
+ return
+
+ var point = null
+ if (orientation == Qt.Horizontal) {
+ point = root.mapFromItem(track, handle.x + handle.width / 2 - valueIndicator.item.width / 2, 0)
+
+ // Check if valueIndicator will be positioned beyond the right or
+ // left boundaries and adjust if needed to keep it fully
+ // visible on screen. In case the valueIndicator is so wide that it
+ // does not fit the screen, it's positioned to left of the screen.
+ var rightStop = screen.width - toolTipPadding
+ var valueIndicatorLeftEdge = root.mapToItem(null, point.x, 0)
+ var valueIndicatorRightEdge = root.mapToItem(null, point.x + valueIndicator.item.width, 0)
+
+ if (valueIndicatorLeftEdge.x < toolTipPadding)
+ point.x = root.mapFromItem(null, toolTipPadding, 0).x
+ else if (valueIndicatorRightEdge.x > rightStop)
+ point.x = root.mapFromItem(null, rightStop - valueIndicator.item.width, 0).x
+
+ valueIndicator.item.x = point.x
+ valueIndicator.item.y = point.y - valueIndicator.spacing - valueIndicator.item.height
+ } else {
+ point = root.mapFromItem(track, 0, handle.y + handle.height / 2 - valueIndicator.item.height / 2)
+ valueIndicator.item.x = point.x - valueIndicator.spacing - valueIndicator.item.width
+ valueIndicator.item.y = point.y
+ }
+ }
+
+ Timer {
+ id: indicatorTimer
+ interval: 750
+ onTriggered: {
+ if (!track.inputActive)
+ valueIndicator.show = false
+ }
+ }
+ }
+
+ QtObject {
+ id: internal
+
+ function handleKeyPressEvent(keyEvent) {
+ var oldValue = model.value
+ if (orientation == Qt.Horizontal) {
+ if (keyEvent.key == Qt.Key_Left) {
+ model.value = inverted ? model.value + model.stepSize : model.value - model.stepSize
+ } else if (keyEvent.key == Qt.Key_Right) {
+ model.value = inverted ? model.value - model.stepSize : model.value + model.stepSize
+ }
+ } else { //Vertical
+ if (keyEvent.key == Qt.Key_Up) {
+ model.value = inverted ? model.value + model.stepSize : model.value - model.stepSize
+ } else if (keyEvent.key == Qt.Key_Down) {
+ model.value = inverted ? model.value - model.stepSize : model.value + model.stepSize
+ }
+ }
+ if (oldValue != model.value)
+ keyEvent.accepted = true
+
+ if (keyEvent.accepted ||
+ keyEvent.key == Qt.Key_Select ||
+ keyEvent.key == Qt.Key_Return ||
+ keyEvent.key == Qt.Key_Enter)
+ track.activeKey = keyEvent.key
+ }
+
+ function handleKeyReleaseEvent(keyEvent) {
+ if (track.activeKey == keyEvent.key) {
+ if (!keyEvent.isAutoRepeat)
+ track.activeKey = undefined
+ keyEvent.accepted = true
+ }
+ }
+ }
+}
--- /dev/null
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the Qt Components project.
+**
+** $QT_BEGIN_LICENSE:BSD$
+** You may use this file under the terms of the BSD license as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions and the following disclaimer in
+** the documentation and/or other materials provided with the
+** distribution.
+** * Neither the name of Nokia Corporation and its Subsidiary(-ies) nor
+** the names of its contributors may be used to endorse or promote
+** products derived from this software without specific prior written
+** permission.
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick 1.1
+import "." 1.1
+
+Item {
+ id: root
+
+ implicitWidth: screen.width
+ implicitHeight: privateStyle.statusBarHeight
+ property bool platformInverted: false
+
+// QtObject {
+// id: priv
+// objectName: "priv"
+
+// property bool clickedOpensStatusPanel: android.s60Version == Android.SV_S60_5_2 ? true : false
+// property int contentHeight: Math.round(privateStyle.statusBarHeight * 18 / 26)
+// property int paddingSmallOneQuarter: Math.round(platformStyle.paddingSmall / 4)
+// property int paddingSmallThreeQuarters: Math.round(platformStyle.paddingSmall * 3 / 4)
+
+// function signalWidthPercentage(signalStrength) {
+// if (signalStrength < 10)
+// return 0;
+// else if (signalStrength < 20)
+// return 1/5;
+// else if (signalStrength < 30)
+// return 2/5;
+// else if (signalStrength < 60)
+// return 3/5;
+// else if (signalStrength < 100)
+// return 4/5;
+// else
+// return 1;
+// }
+// }
+
+// MouseArea {
+// id: mouseArea
+// anchors.fill: parent
+
+// onClicked: {
+// if (priv.clickedOpensStatusPanel) {
+// privateStyle.play(Android.PopUp)
+// platformPopupManager.privateShowIndicatorPopup()
+// }
+// }
+// onPressed: {
+// if (!priv.clickedOpensStatusPanel) {
+// privateStyle.play(Android.PopUp)
+// platformPopupManager.privateShowIndicatorPopup()
+// // reset MouseArea state since status panel window eats the release event
+// android.privateSendMouseRelease(mouseArea)
+// }
+// }
+// }
+
+// BorderImage {
+// source: privateStyle.imagePath("qtg_fr_statusbar", root.platformInverted)
+// anchors.fill: parent
+// width: parent.width
+
+// UniversalIndicators {
+// height: indicatorHeight
+// anchors {
+// right: networkMode.left
+// rightMargin: priv.paddingSmallOneQuarter
+// verticalCenter: parent.verticalCenter
+// }
+
+// width: priv.paddingSmallOneQuarter * 2 + 3 * indicatorWidth
+
+// indicatorColor: root.platformInverted ? platformStyle.colorNormalDarkInverted
+// : platformStyle.colorNormalLight
+// indicatorWidth: priv.contentHeight // same as height
+// indicatorHeight: priv.contentHeight
+// indicatorPadding: priv.paddingSmallOneQuarter
+// maxIndicatorCount: 3
+// }
+
+// // icon for network signal type e.g. 3G, GPRS etc
+// NetworkIndicator {
+// id: networkMode
+// height: priv.contentHeight
+// width: priv.contentHeight // same as height
+// anchors.verticalCenter: parent.verticalCenter
+// anchors.right: offline ? batteryBackground.left : signalBackground.left
+// anchors.rightMargin: priv.paddingSmallThreeQuarters
+// color: root.platformInverted ? platformStyle.colorNormalDarkInverted
+// : platformStyle.colorNormalLight
+// }
+// // signal strength
+// Image {
+// id: signalBackground
+// visible: !networkMode.offline
+// sourceSize.height: priv.contentHeight
+// sourceSize.width: Math.round(privateStyle.statusBarHeight * 19 / 26)
+// anchors.verticalCenter: parent.verticalCenter
+// anchors.right: batteryBackground.left
+// anchors.rightMargin: priv.paddingSmallThreeQuarters
+// fillMode: Image.PreserveAspectFit
+// source: privateStyle.imagePath("qtg_graf_signal_level_bg", root.platformInverted)
+// Item {
+// id: signalLevelItem
+// anchors.left: parent.left
+// anchors.top: parent.top
+// height: parent.height
+// width: priv.signalWidthPercentage(privateNetworkInfo.networkSignalStrength) * parent.width
+// clip: true
+// LayoutMirroring.enabled: false
+
+// Image {
+// sourceSize.width: signalBackground.sourceSize.width
+// sourceSize.height: signalBackground.sourceSize.height
+// fillMode: Image.PreserveAspectFit
+// source: privateStyle.imagePath("qtg_graf_signal_level_full", root.platformInverted)
+// }
+// }
+// }
+// // battery indicator
+// Image {
+// id: batteryBackground
+// anchors.verticalCenter: parent.verticalCenter
+// anchors.right: timeItem.left
+// anchors.rightMargin: priv.paddingSmallThreeQuarters
+// sourceSize.height: priv.contentHeight
+// sourceSize.width: Math.round(privateStyle.statusBarHeight * 24 / 26)
+// fillMode: Image.PreserveAspectFit
+// source: privateStyle.imagePath((privateBatteryInfo.powerSaveModeEnabled ?
+// "qtg_graf_battery_level_psm_bg" :
+// "qtg_graf_battery_level_bg"), root.platformInverted)
+
+// Item {
+// id: batteryLevel
+
+// property int animatedLevel
+
+// anchors.left: parent.left
+// anchors.top: parent.top
+// width: Math.round(privateStyle.statusBarHeight
+// * ((privateBatteryInfo.charging ? Math.floor(animatedLevel / 100) :
+// privateBatteryInfo.batteryLevel) + 2) / 13)
+// height: parent.height
+// clip: true
+// LayoutMirroring.enabled: false
+
+// Image {
+// sourceSize.width: batteryBackground.sourceSize.width
+// sourceSize.height: batteryBackground.sourceSize.height
+
+// fillMode: Image.PreserveAspectFit
+
+// // Battery state mappings: Levels 0 and 1 are low, 2-4 are medium, 5-7 are full.
+// // Currently all levels use same graphics with white color.
+
+// source: privateStyle.imagePath((privateBatteryInfo.powerSaveModeEnabled ?
+// "qtg_graf_battery_level_psm_full" :
+// "qtg_graf_battery_level_full"), root.platformInverted)
+// }
+// }
+
+// Image {
+// // power save mode indicator
+// anchors.fill: parent
+// sourceSize.width: parent.sourceSize.width
+// sourceSize.height: parent.sourceSize.height
+// source: privateStyle.imagePath("qtg_graf_battery_psm")
+// visible: privateBatteryInfo.powerSaveModeEnabled
+// }
+
+// NumberAnimation {
+// id: batteryChargingAnimation
+// loops: Animation.Infinite
+// running: privateBatteryInfo.charging
+// target: batteryLevel
+// property: "animatedLevel"
+// // Use bigger range (compared to 0-7) in order to make the animation smoother.
+// from: 0
+// to: 799
+// duration: 3500
+// }
+// }
+// // clock
+// Text {
+// id: timeItem
+// width: Math.round(privateStyle.statusBarHeight * 44 / 26)
+// color: root.platformInverted ? platformStyle.colorNormalDarkInverted
+// : platformStyle.colorNormalLight
+// anchors.verticalCenter: parent.verticalCenter
+// anchors.right: parent.right
+// anchors.rightMargin: platformStyle.paddingSmall
+// horizontalAlignment: Text.AlignRight
+// text: android.currentTime
+// font {
+// family: platformStyle.fontFamilyRegular;
+// pixelSize: priv.contentHeight
+// weight: Font.Light
+// }
+// }
+// }
+}
+
--- /dev/null
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the Qt Components project.
+**
+** $QT_BEGIN_LICENSE:BSD$
+** You may use this file under the terms of the BSD license as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions and the following disclaimer in
+** the documentation and/or other materials provided with the
+** distribution.
+** * Neither the name of Nokia Corporation and its Subsidiary(-ies) nor
+** the names of its contributors may be used to endorse or promote
+** products derived from this software without specific prior written
+** permission.
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick 1.1
+import "." 1.1
+
+Item {
+// id: root
+
+// implicitWidth: screen.width
+// implicitHeight: privateStyle.statusBarHeight
+ property bool platformInverted: false
+
+// QtObject {
+// id: priv
+// objectName: "priv"
+
+// property bool clickedOpensStatusPanel: android.s60Version == Android.SV_S60_5_2 ? true : false
+// property int contentHeight: Math.round(privateStyle.statusBarHeight * 18 / 26)
+// property int paddingSmallOneQuarter: Math.round(platformStyle.paddingSmall / 4)
+// property int paddingSmallThreeQuarters: Math.round(platformStyle.paddingSmall * 3 / 4)
+
+// function signalWidthPercentage(signalStrength) {
+// if (signalStrength < 10)
+// return 0;
+// else if (signalStrength < 20)
+// return 1/5;
+// else if (signalStrength < 30)
+// return 2/5;
+// else if (signalStrength < 60)
+// return 3/5;
+// else if (signalStrength < 100)
+// return 4/5;
+// else
+// return 1;
+// }
+// }
+
+// MouseArea {
+// id: mouseArea
+// anchors.fill: parent
+
+// onClicked: {
+// if (priv.clickedOpensStatusPanel) {
+// privateStyle.play(Android.PopUp)
+// platformPopupManager.privateShowIndicatorPopup()
+// }
+// }
+// onPressed: {
+// if (!priv.clickedOpensStatusPanel) {
+// privateStyle.play(Android.PopUp)
+// platformPopupManager.privateShowIndicatorPopup()
+// // reset MouseArea state since status panel window eats the release event
+// android.privateSendMouseRelease(mouseArea)
+// }
+// }
+// }
+
+// BorderImage {
+// source: privateStyle.imagePath("qtg_fr_statusbar", root.platformInverted)
+// anchors.fill: parent
+// width: parent.width
+
+// UniversalIndicators {
+// height: indicatorHeight
+// anchors {
+// right: networkMode.left
+// rightMargin: priv.paddingSmallOneQuarter
+// verticalCenter: parent.verticalCenter
+// }
+
+// width: priv.paddingSmallOneQuarter * 2 + 3 * indicatorWidth
+
+// indicatorColor: root.platformInverted ? platformStyle.colorNormalDarkInverted
+// : platformStyle.colorNormalLight
+// indicatorWidth: priv.contentHeight // same as height
+// indicatorHeight: priv.contentHeight
+// indicatorPadding: priv.paddingSmallOneQuarter
+// maxIndicatorCount: 3
+// }
+
+// // icon for network signal type e.g. 3G, GPRS etc
+// NetworkIndicator {
+// id: networkMode
+// height: priv.contentHeight
+// width: priv.contentHeight // same as height
+// anchors.verticalCenter: parent.verticalCenter
+// anchors.right: offline ? batteryBackground.left : signalBackground.left
+// anchors.rightMargin: priv.paddingSmallThreeQuarters
+// color: root.platformInverted ? platformStyle.colorNormalDarkInverted
+// : platformStyle.colorNormalLight
+// }
+// // signal strength
+// Image {
+// id: signalBackground
+// visible: !networkMode.offline
+// sourceSize.height: priv.contentHeight
+// sourceSize.width: Math.round(privateStyle.statusBarHeight * 19 / 26)
+// anchors.verticalCenter: parent.verticalCenter
+// anchors.right: batteryBackground.left
+// anchors.rightMargin: priv.paddingSmallThreeQuarters
+// fillMode: Image.PreserveAspectFit
+// source: privateStyle.imagePath("qtg_graf_signal_level_bg", root.platformInverted)
+// Item {
+// id: signalLevelItem
+// anchors.left: parent.left
+// anchors.top: parent.top
+// height: parent.height
+// width: priv.signalWidthPercentage(privateNetworkInfo.networkSignalStrength) * parent.width
+// clip: true
+// LayoutMirroring.enabled: false
+
+// Image {
+// sourceSize.width: signalBackground.sourceSize.width
+// sourceSize.height: signalBackground.sourceSize.height
+// fillMode: Image.PreserveAspectFit
+// source: privateStyle.imagePath("qtg_graf_signal_level_full", root.platformInverted)
+// }
+// }
+// }
+// // battery indicator
+// Image {
+// id: batteryBackground
+// anchors.verticalCenter: parent.verticalCenter
+// anchors.right: timeItem.left
+// anchors.rightMargin: priv.paddingSmallThreeQuarters
+// sourceSize.height: priv.contentHeight
+// sourceSize.width: Math.round(privateStyle.statusBarHeight * 24 / 26)
+// fillMode: Image.PreserveAspectFit
+// source: privateStyle.imagePath((privateBatteryInfo.powerSaveModeEnabled ?
+// "qtg_graf_battery_level_psm_bg" :
+// "qtg_graf_battery_level_bg"), root.platformInverted)
+
+// Item {
+// id: batteryLevel
+
+// property int animatedLevel
+
+// anchors.left: parent.left
+// anchors.top: parent.top
+// width: Math.round(privateStyle.statusBarHeight
+// * ((privateBatteryInfo.charging ? Math.floor(animatedLevel / 100) :
+// privateBatteryInfo.batteryLevel) + 2) / 13)
+// height: parent.height
+// clip: true
+// LayoutMirroring.enabled: false
+
+// Image {
+// sourceSize.width: batteryBackground.sourceSize.width
+// sourceSize.height: batteryBackground.sourceSize.height
+
+// fillMode: Image.PreserveAspectFit
+
+// // Battery state mappings: Levels 0 and 1 are low, 2-4 are medium, 5-7 are full.
+// // Currently all levels use same graphics with white color.
+
+// source: privateStyle.imagePath((privateBatteryInfo.powerSaveModeEnabled ?
+// "qtg_graf_battery_level_psm_full" :
+// "qtg_graf_battery_level_full"), root.platformInverted)
+// }
+// }
+
+// Image {
+// // power save mode indicator
+// anchors.fill: parent
+// sourceSize.width: parent.sourceSize.width
+// sourceSize.height: parent.sourceSize.height
+// source: privateStyle.imagePath("qtg_graf_battery_psm")
+// visible: privateBatteryInfo.powerSaveModeEnabled
+// }
+
+// NumberAnimation {
+// id: batteryChargingAnimation
+// loops: Animation.Infinite
+// running: privateBatteryInfo.charging
+// target: batteryLevel
+// property: "animatedLevel"
+// // Use bigger range (compared to 0-7) in order to make the animation smoother.
+// from: 0
+// to: 799
+// duration: 3500
+// }
+// }
+// // clock
+// Text {
+// id: timeItem
+// width: Math.round(privateStyle.statusBarHeight * 44 / 26)
+// color: root.platformInverted ? platformStyle.colorNormalDarkInverted
+// : platformStyle.colorNormalLight
+// anchors.verticalCenter: parent.verticalCenter
+// anchors.right: parent.right
+// anchors.rightMargin: platformStyle.paddingSmall
+// horizontalAlignment: Text.AlignRight
+// text: android.currentTime
+// font {
+// family: platformStyle.fontFamilyRegular;
+// pixelSize: priv.contentHeight
+// weight: Font.Light
+// }
+// }
+// }
+}
+
--- /dev/null
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the Qt Components project.
+**
+** $QT_BEGIN_LICENSE:BSD$
+** You may use this file under the terms of the BSD license as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions and the following disclaimer in
+** the documentation and/or other materials provided with the
+** distribution.
+** * Neither the name of Nokia Corporation and its Subsidiary(-ies) nor
+** the names of its contributors may be used to endorse or promote
+** products derived from this software without specific prior written
+** permission.
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick 1.1
+import "." 1.1
+
+Item {
+ id: root
+
+ // Common Public API
+ property bool checked: false
+ property bool pressed: stateGroup.state == "Pressed" || stateGroup.state == "KeyPressed"
+ || stateGroup.state == "Dragging"
+
+ // Symbian specific API
+ property bool platformInverted: false
+
+ signal clicked
+
+ QtObject {
+ id: internal
+ objectName: "internal"
+
+ function toggle() {
+ root.checked = !root.checked
+ root.clicked()
+ }
+ }
+
+ StateGroup {
+ id: stateGroup
+
+ states: [
+ State { name: "Pressed" },
+ State { name: "Released" },
+ State { name: "KeyPressed" },
+ State { name: "Dragging" },
+ State { name: "Canceled" }
+ ]
+
+ transitions: [
+ Transition {
+ to: "Pressed"
+ ScriptAction { script: privateStyle.play(Android.BasicItem) }
+ },
+ Transition {
+ from: "Released, Dragging"
+ to: ""
+ ScriptAction { script: privateStyle.play(Android.CheckBox) }
+ ScriptAction { script: internal.toggle() }
+ },
+ Transition {
+ from: "KeyPressed"
+ to: ""
+ ScriptAction { script: internal.toggle() }
+ }
+ ]
+ }
+
+ implicitWidth: track.width
+ implicitHeight: privateStyle.switchButtonHeight
+
+ Image {
+ id: track
+
+ function trackPostfix() {
+ if (!root.enabled && root.checked)
+ return "disabled_on"
+ else if (!root.enabled && !root.checked)
+ return "disabled_off"
+ else
+ return "track"
+ }
+
+ source: privateStyle.imagePath("qtg_graf_switchbutton_" + track.trackPostfix(),
+ root.platformInverted)
+ anchors.left: parent.left
+ anchors.verticalCenter: parent.verticalCenter
+ sourceSize.width: Android.UndefinedSourceDimension
+ sourceSize.height: privateStyle.switchButtonHeight
+ scale: root.LayoutMirroring.enabled ? -1 : 1
+ }
+
+ MouseArea {
+ id: mouseArea
+
+ property real lastX
+
+ function isChecked() {
+ if (root.LayoutMirroring.enabled)
+ return (handle.x + handle.width / 2 < track.x + (track.width / 2))
+ else
+ return (handle.x + handle.width / 2 > track.x + (track.width / 2))
+ }
+ function updateHandlePos() {
+ // The middle of the handle follows mouse, the handle is bound to the track
+ handle.x = Math.max(track.x, Math.min(mouseArea.lastX - handle.width / 2,
+ track.x + track.width - handle.width))
+ }
+
+ anchors.fill: track
+ onPressed: stateGroup.state = "Pressed"
+ onReleased: stateGroup.state = "Released" // releasing doesn't toggle yet, it is intermediate state
+ onClicked: stateGroup.state = ""
+ onCanceled: stateGroup.state = "Canceled"
+ onPositionChanged: {
+ mouseArea.lastX = mouse.x
+ if (mouseArea.drag.active)
+ updateHandlePos()
+ }
+ drag {
+ // The handle is moved manually but MouseArea can be used to decide when dragging
+ // should start (QApplication::startDragDistance). A dummy target needs to be bound or
+ // dragging won't get activated.
+ target: Item { visible: false }
+
+ axis: Drag.XandYAxis
+ minimumY: 0; maximumY: 0 // keep dragging active eventhough only x axis switches
+ minimumX: track.x; maximumX: mouseArea.drag.minimumX + track.width - handle.width
+ onActiveChanged: {
+ if (mouseArea.drag.active) {
+ updateHandlePos()
+ stateGroup.state = "Dragging"
+ }
+ else {
+ stateGroup.state = (root.checked != isChecked()) ? "" : "Canceled"
+ }
+ }
+ }
+ }
+
+ Item {
+ id: fill
+
+ clip: true
+ anchors.left: track.left
+ anchors.right: handle.horizontalCenter
+ anchors.verticalCenter: parent.verticalCenter
+ height: privateStyle.switchButtonHeight
+ visible: root.enabled
+
+ Image {
+ source: privateStyle.imagePath("qtg_graf_switchbutton_fill",
+ root.platformInverted)
+ anchors.left: parent.left
+ anchors.top: parent.top
+ height: parent.height
+ }
+ }
+
+ Image {
+ id: handle
+
+ source: privateStyle.imagePath("qtg_graf_switchbutton_"
+ + (root.pressed ? "handle_pressed" : "handle_normal"),
+ root.platformInverted)
+ anchors.verticalCenter: root.verticalCenter
+ sourceSize.width: privateStyle.switchButtonHeight
+ sourceSize.height: privateStyle.switchButtonHeight
+ visible: root.enabled
+
+ states: [
+ State {
+ name: "Off"
+ when: !mouseArea.drag.active && !checked
+ PropertyChanges {
+ target: handle
+ restoreEntryValues: false
+ x: root.LayoutMirroring.enabled ? mouseArea.drag.maximumX : mouseArea.drag.minimumX
+ }
+ },
+ State {
+ name: "On"
+ when: !mouseArea.drag.active && checked
+ PropertyChanges {
+ target: handle
+ restoreEntryValues: false
+ x: root.LayoutMirroring.enabled ? mouseArea.drag.minimumX : mouseArea.drag.maximumX
+ }
+ }
+ ]
+
+ transitions: [
+ Transition {
+ to: "Off"
+ SmoothedAnimation {properties: "x"; easing.type: Easing.InOutQuad; duration: 200 }
+ },
+ Transition {
+ to: "On"
+ SmoothedAnimation {properties: "x"; easing.type: Easing.InOutQuad; duration: 200 }
+ }
+ ]
+ }
+
+ Keys.onPressed: {
+ if (!event.isAutoRepeat && (event.key == Qt.Key_Select
+ || event.key == Qt.Key_Return
+ || event.key == Qt.Key_Enter)) {
+ stateGroup.state = "KeyPressed"
+ event.accepted = true
+ }
+ }
+
+
+ Keys.onReleased: {
+ if (!event.isAutoRepeat && (event.key == Qt.Key_Select
+ || event.key == Qt.Key_Return
+ || event.key == Qt.Key_Enter)) {
+ stateGroup.state = ""
+ event.accepted = true
+ }
+ }
+}
--- /dev/null
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the Qt Components project.
+**
+** $QT_BEGIN_LICENSE:BSD$
+** You may use this file under the terms of the BSD license as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions and the following disclaimer in
+** the documentation and/or other materials provided with the
+** distribution.
+** * Neither the name of Nokia Corporation and its Subsidiary(-ies) nor
+** the names of its contributors may be used to endorse or promote
+** products derived from this software without specific prior written
+** permission.
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick 1.1
+import "." 1.1
+
+Item {
+ id: root
+ default property alias content: tabBarLayout.data
+ property alias layout: tabBarLayout
+ property bool platformInverted: false
+
+ implicitWidth: Math.max(50, screen.width)
+ implicitHeight: screen.width < screen.height ? privateStyle.tabBarHeightPortrait : privateStyle.tabBarHeightLandscape
+
+ BorderImage {
+ anchors.fill: parent
+ source: privateStyle.imagePath("qtg_fr_tab_bar", root.platformInverted)
+ border { left: 20; top: 20; right: 20; bottom: 20 }
+ }
+
+ TabBarLayout {
+ id: tabBarLayout
+ anchors.fill: parent
+ }
+}
--- /dev/null
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the Qt Components project.
+**
+** $QT_BEGIN_LICENSE:BSD$
+** You may use this file under the terms of the BSD license as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions and the following disclaimer in
+** the documentation and/or other materials provided with the
+** distribution.
+** * Neither the name of Nokia Corporation and its Subsidiary(-ies) nor
+** the names of its contributors may be used to endorse or promote
+** products derived from this software without specific prior written
+** permission.
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick 1.1
+import "." 1.1
+
+Item {
+ id: root
+
+ Component.onCompleted: priv.layoutChildren()
+ onChildrenChanged: priv.layoutChildren()
+ onWidthChanged: priv.layoutChildren()
+ onHeightChanged: priv.layoutChildren()
+
+ Keys.onPressed: {
+ if (event.key == Qt.Key_Right || event.key == Qt.Key_Left) {
+ if (event.key == Qt.Key_Right || priv.mirrored) {
+ var oldIndex = priv.currentButtonIndex()
+ if (oldIndex != root.children.length - 1) {
+ priv.tabGroup.currentTab = root.children[oldIndex + 1].tab
+ event.accepted = true
+ }
+ } else if (event.key == Qt.Key_Left || priv.mirrored) {
+ var oldIndex = priv.currentButtonIndex()
+ if (oldIndex != 0) {
+ priv.tabGroup.currentTab = root.children[oldIndex - 1].tab
+ event.accepted = true
+ }
+ }
+ }
+ }
+
+ focus: true
+
+ QtObject {
+ id: priv
+ property Item firstButton: root.children.length > 0 ? root.children[0] : null
+ property Item firstTab: firstButton ? (firstButton.tab != null ? firstButton.tab : null) : null
+ property Item tabGroup: firstTab ? (firstTab.parent ? firstTab.parent.parent : null) : null
+ property bool mirrored: root.LayoutMirroring.enabled
+
+ onMirroredChanged: layoutChildren()
+
+ function currentButtonIndex() {
+ for (var i = 0; i < root.children.length; ++i) {
+ if (root.children[i].tab == tabGroup.currentTab)
+ return i
+ }
+ return -1
+ }
+
+ function layoutChildren() {
+ var childCount = root.children.length
+ var contentWidth = 0
+ var contentHeight = 0
+ if (childCount != 0) {
+ var itemWidth = root.width / childCount
+ var itemIndex = mirrored ? childCount - 1 : 0
+ var increment = mirrored ? - 1 : 1
+
+ for (var i = 0; i < childCount; ++i, itemIndex += increment) {
+ var child = root.children[itemIndex]
+ child.x = i * itemWidth
+ child.y = 0
+ child.width = itemWidth
+ child.height = root.height
+
+ if (child.implicitWidth != undefined) {
+ contentWidth = Math.max(contentWidth, child.implicitWidth * childCount)
+ contentHeight = Math.max(contentHeight, child.implicitHeight)
+ }
+ }
+ }
+ root.implicitWidth = contentWidth
+ root.implicitHeight = contentHeight
+ }
+ }
+}
--- /dev/null
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the Qt Components project.
+**
+** $QT_BEGIN_LICENSE:BSD$
+** You may use this file under the terms of the BSD license as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions and the following disclaimer in
+** the documentation and/or other materials provided with the
+** distribution.
+** * Neither the name of Nokia Corporation and its Subsidiary(-ies) nor
+** the names of its contributors may be used to endorse or promote
+** products derived from this software without specific prior written
+** permission.
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick 1.1
+import "." 1.1
+import "AppManager.js" as Utils
+
+Item {
+ id: root
+
+ // Common Public API
+ property Item tab
+ property bool checked: internal.tabGroup != null && internal.tabGroup.currentTab == tab
+ property bool pressed: stateGroup.state == "Pressed" && mouseArea.containsMouse
+ property alias text: label.text
+ property alias iconSource: imageLoader.source
+
+ signal clicked
+
+ // Symbian specific API
+ property bool platformInverted: false
+
+ implicitWidth: Math.max(2 * imageLoader.width, 2 * platformStyle.paddingMedium + privateStyle.textWidth(label.text, label.font))
+ implicitHeight: internal.portrait ? privateStyle.tabBarHeightPortrait : privateStyle.tabBarHeightLandscape
+
+ QtObject {
+ id: internal
+
+ property Item tabGroup: Utils.findParent(tab, "currentTab")
+ property bool portrait: screen.currentOrientation == Screen.Portrait || screen.currentOrientation == Screen.PortraitInverted
+
+ function press() {
+ privateStyle.play(Android.BasicButton)
+ }
+ function click() {
+ root.clicked()
+ privateStyle.play(Android.BasicButton)
+ if (internal.tabGroup)
+ internal.tabGroup.currentTab = tab
+ }
+
+ function isButtonRow(item) {
+ return (item &&
+ item.hasOwnProperty("checkedButton") &&
+ item.hasOwnProperty("privateDirection") &&
+ item.privateDirection == Qt.Horizontal)
+ }
+
+ function imageName() {
+ // If the parent of a TabButton is ButtonRow, segmented-style graphics
+ // are used to create a seamless row of buttons. Otherwise normal
+ // TabButton graphics are utilized.
+ var mirror = root.LayoutMirroring.enabled // To create binding
+ if (isButtonRow(parent))
+ return parent.privateGraphicsName(root, 1)
+ else
+ return "qtg_fr_tab_"
+ }
+
+ function modeName() {
+ if (isButtonRow(parent)) {
+ return parent.privateModeName(root, 1)
+ } else {
+ return root.checked ? "active" : "passive_normal"
+ }
+ }
+
+ function modeNamePressed() {
+ if (isButtonRow(parent)) {
+ return "pressed"
+ } else {
+ return "passive_pressed"
+ }
+ }
+ }
+
+ StateGroup {
+ id: stateGroup
+
+ states: [
+ State {
+ name: "Pressed"
+ PropertyChanges { target: pressedGraphics; opacity: 1 }
+ },
+ State { name: "Canceled" }
+ ]
+ transitions: [
+ Transition {
+ to: "Pressed"
+ ScriptAction { script: internal.press() }
+ },
+ Transition {
+ from: "Pressed"
+ to: ""
+ NumberAnimation {
+ target: pressedGraphics
+ property: "opacity"
+ to: 0
+ duration: 150
+ easing.type: Easing.Linear
+ }
+ ScriptAction { script: internal.click() }
+ }
+ ]
+ }
+
+ BorderImage {
+ id: background
+
+ source: privateStyle.imagePath(internal.imageName() + internal.modeName(), root.platformInverted)
+ anchors.fill: parent
+ border {
+ left: platformStyle.borderSizeMedium
+ top: platformStyle.borderSizeMedium
+ right: platformStyle.borderSizeMedium
+ bottom: platformStyle.borderSizeMedium
+ }
+ }
+
+ BorderImage {
+ id: pressedGraphics
+
+ source: privateStyle.imagePath(internal.imageName() + internal.modeNamePressed(), root.platformInverted)
+ anchors.fill: parent
+ opacity: 0
+
+ border {
+ left: platformStyle.borderSizeMedium
+ top: platformStyle.borderSizeMedium
+ right: platformStyle.borderSizeMedium
+ bottom: platformStyle.borderSizeMedium
+ }
+ }
+
+ Text {
+ id: label
+
+ objectName: "label"
+ // hide in landscape if icon is present
+ visible: !(iconSource.toString() && !internal.portrait)
+ anchors {
+ left: parent.left
+ right: parent.right
+ bottom: parent.bottom
+ leftMargin: platformStyle.paddingMedium
+ rightMargin: platformStyle.paddingMedium
+ bottomMargin: iconSource.toString()
+ ? platformStyle.paddingSmall
+ : Math.ceil((parent.height - label.height) / 2.0)
+ }
+ elide: Text.ElideRight
+ horizontalAlignment: Text.AlignHCenter
+ font {
+ family: platformStyle.fontFamilyRegular;
+ pixelSize: platformStyle.fontSizeSmall
+ weight: Font.Light
+ }
+ color: {
+ if (root.pressed)
+ root.platformInverted ? platformStyle.colorPressedInverted
+ : platformStyle.colorPressed
+ else if (root.checked)
+ root.platformInverted ? platformStyle.colorNormalLightInverted
+ : platformStyle.colorNormalLight
+ else
+ root.platformInverted ? platformStyle.colorNormalMidInverted
+ : platformStyle.colorNormalMid
+ }
+ }
+
+ Loader {
+ // imageLoader acts as wrapper for Image and Icon items. The Image item is
+ // shown when the source points to a image (jpg, png). Icon item is used for
+ // locigal theme icons which are colorised.
+ id: imageLoader
+
+ property url source
+ property string iconId: privateStyle.isTabBarIcon(source) ? source.toString() : ""
+
+ width : platformStyle.graphicSizeSmall
+ height : platformStyle.graphicSizeSmall
+ sourceComponent: {
+ if (iconId)
+ return iconComponent
+ if (source.toString())
+ return imageComponent
+ return undefined
+ }
+ anchors {
+ top: parent.top
+ topMargin : !parent.text || !internal.portrait
+ ? Math.floor((parent.height - imageLoader.height) / 2.0)
+ : platformStyle.paddingSmall
+ horizontalCenter: parent.horizontalCenter
+ }
+
+ Component {
+ id: imageComponent
+
+ Image {
+ id: image
+
+ objectName: "image"
+ source: imageLoader.iconId ? "" : imageLoader.source
+ sourceSize.width: width
+ sourceSize.height: height
+ fillMode: Image.PreserveAspectFit
+ smooth: true
+ anchors.fill: parent
+ }
+ }
+
+ Component {
+ id: iconComponent
+
+ Icon {
+ id: icon
+
+ objectName: "icon"
+ anchors.fill: parent
+ iconColor: label.color
+ iconName: imageLoader.iconId
+ }
+ }
+ }
+
+ MouseArea {
+ id: mouseArea
+
+ onPressed: stateGroup.state = "Pressed"
+ onReleased: stateGroup.state = ""
+ onCanceled: {
+ // Mark as canceled
+ stateGroup.state = "Canceled"
+ // Reset state
+ stateGroup.state = ""
+ }
+ onExited: {
+ if (pressed)
+ stateGroup.state = "Canceled"
+ }
+
+ anchors.fill: parent
+ }
+}
--- /dev/null
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the Qt Components project.
+**
+** $QT_BEGIN_LICENSE:BSD$
+** You may use this file under the terms of the BSD license as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions and the following disclaimer in
+** the documentation and/or other materials provided with the
+** distribution.
+** * Neither the name of Nokia Corporation and its Subsidiary(-ies) nor
+** the names of its contributors may be used to endorse or promote
+** products derived from this software without specific prior written
+** permission.
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+var allContainers = []
+var allContents = []
+
+function hasContainer(content) {
+ for (var i = 0; i < allContainers.length; ++i) {
+ if (allContainers[i].children[0] == content)
+ return true
+ }
+ return false
+}
+
+function addContent(content) {
+ for (var i = 0; i < allContents.length; ++i) {
+ if (allContents[i] == content)
+ return false
+ }
+ allContents.push(content)
+ return true
+}
+
+function ensureContainers() {
+ var somethingChanged = false
+
+ // check if we need to create a container
+ for (var i = 0; i < root.privateContents.length; ++i) {
+ var content = root.privateContents[i]
+ addContent(content)
+ if (!hasContainer(content)) {
+ var newContainer = tabContainerComponent.createObject(containerHost)
+ content.parent = newContainer
+ allContainers.push(newContainer)
+ somethingChanged = true
+ }
+ }
+ return somethingChanged
+}
+
+function addTab(content) {
+ if (addContent(content)) {
+ var newContainer = tabContainerComponent.createObject(containerHost)
+ content.parent = newContainer
+ allContainers.push(newContainer)
+ }
+}
+
+function removeTab(content) {
+ var foundIndex = -1
+ for (var i = 0; i < allContents.length && foundIndex == -1; ++i) {
+ if (allContents[i] == content)
+ foundIndex = i
+ }
+
+ if (foundIndex != -1)
+ allContents.splice(foundIndex, 1)
+
+ if (hasContainer(content))
+ content.parent = null // this causes deletion of container
+}
+
+function removeContainer(container) {
+ var foundIndex = -1
+ for (var i = 0; i < allContainers.length && foundIndex == -1; ++i) {
+ if (allContainers[i] == container)
+ foundIndex = i
+ }
+
+ if (foundIndex != -1) {
+ var deletedContainer = allContainers[foundIndex]
+ if (deletedContainer.children.length > 0)
+ removeTab(deletedContainer.children[0])
+ allContainers.splice(foundIndex, 1)
+ deletedContainer.destroy()
+ }
+}
+
--- /dev/null
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the Qt Components project.
+**
+** $QT_BEGIN_LICENSE:BSD$
+** You may use this file under the terms of the BSD license as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions and the following disclaimer in
+** the documentation and/or other materials provided with the
+** distribution.
+** * Neither the name of Nokia Corporation and its Subsidiary(-ies) nor
+** the names of its contributors may be used to endorse or promote
+** products derived from this software without specific prior written
+** permission.
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick 1.1
+import "." 1.1
+import "TabGroup.js" as Engine
+
+Item {
+ id: root
+ property Item currentTab
+
+ property list<Item> privateContents
+ // Qt defect: cannot have list as default property
+ default property alias privateContentsDefault: root.privateContents
+ property bool platformAnimated: true
+
+ onChildrenChanged: {
+ // [0] is containerHost
+ if (children.length > 1)
+ Engine.addTab(children[1])
+ }
+
+ onPrivateContentsChanged: {
+ Engine.ensureContainers()
+ }
+
+ Component.onCompleted: {
+ // Set first tabs as current if currentTab is not set by application
+ if (currentTab == null && containerHost.children[0] && containerHost.children[0].children[0])
+ currentTab = containerHost.children[0].children[0]
+ priv.complete = true;
+ }
+
+ Item {
+ id: containerHost
+ objectName: "containerHost"
+ anchors.fill: parent
+ }
+
+ Component {
+ id: tabContainerComponent
+ Item {
+ id: tabContainerItem
+
+ onChildrenChanged: {
+ if (children.length == 0)
+ Engine.removeContainer(tabContainerItem)
+
+ else if (children.length == 1) {
+ children[0].width = width
+ children[0].height = height
+ // tab content created. set the first tab as current (if not set before, and if
+ // child is added after TabGroup has completed)
+ if (priv.complete && root.currentTab == null)
+ root.currentTab = children[0]
+ }
+ }
+
+ onWidthChanged: {
+ if (children.length > 0)
+ children[0].width = width
+ }
+
+ onHeightChanged: {
+ if (children.length > 0)
+ children[0].height = height
+ }
+
+ Component.onDestruction: {
+ if (typeof(root) != "undefined" && !root.currentTab) {
+ // selected one deleted. try to activate the neighbour
+ var removedIndex = -1
+ for (var i = 0; i < containerHost.children.length; i++) {
+ if (containerHost.children[i] == tabContainerItem) {
+ removedIndex = i
+ break
+ }
+ }
+ var newIndex = -1
+ if (removedIndex != -1) {
+ if (removedIndex != containerHost.children.length - 1)
+ newIndex = removedIndex + 1
+ else if (removedIndex != 0)
+ newIndex = removedIndex - 1
+ }
+
+ if (newIndex != -1)
+ root.currentTab = containerHost.children[newIndex].children[0]
+ else
+ root.currentTab = null
+ }
+ }
+
+ function incomingDone() {
+ state = ""
+ if (priv.incomingPage) {
+ priv.incomingPage.status = PageStatus.Active
+ priv.incomingPage = null
+ }
+ }
+
+ function outgoingDone() {
+ if (priv.outgoingPage) {
+ priv.outgoingPage.status = PageStatus.Inactive
+ priv.outgoingPage.visible = false
+ priv.outgoingPage = null
+ }
+ state = "Hidden"
+ }
+
+ width: parent ? parent.width : 0
+ height: parent ? parent.height : 0
+ state: "Hidden"
+
+ states: [
+ State { name: ""; PropertyChanges { target: tabContainerItem; opacity: 1.0 } },
+ State { name: "Incoming"; PropertyChanges { target: tabContainerItem; opacity: 1.0 } },
+ State { name: "Outgoing"; PropertyChanges { target: tabContainerItem; opacity: 0.0 } },
+ State { name: "Hidden"; PropertyChanges { target: tabContainerItem; opacity: 0.0 } }
+ ]
+
+ transitions: [
+ Transition {
+ to: "Incoming"
+ SequentialAnimation {
+ PropertyAnimation { properties: "opacity"; easing.type: Easing.Linear; duration: 250 }
+ ScriptAction { script: incomingDone() }
+ }
+ },
+ Transition {
+ to: "Outgoing"
+ SequentialAnimation {
+ PropertyAnimation { properties: "opacity"; easing.type: Easing.Linear; duration: 250 }
+ ScriptAction { script: outgoingDone() }
+ }
+ }
+ ]
+ }
+ }
+
+ QtObject {
+ id: priv
+ property bool reparenting: false
+ property bool complete: false
+ property Item currentTabContainer: root.currentTab ? root.currentTab.parent : null
+ property Item incomingPage
+ property Item outgoingPage
+ property bool animate
+
+ function disableAnimations() {
+ animate = false
+
+ // outgoingPage might have been found before the incomingPage changes the orientation
+ if (outgoingPage)
+ outgoingPage.parent.outgoingDone()
+ }
+
+ onCurrentTabContainerChanged: {
+ animate = platformAnimated // updated on orientation change
+ screen.currentOrientationChanged.connect(priv.disableAnimations)
+ for (var i = 0; i < containerHost.children.length; i++) {
+ var tabContainer = containerHost.children[i]
+ var isNewTab = (tabContainer == currentTabContainer)
+ if (isNewTab) {
+ if (tabContainer.state != "") {
+ if (tabContainer.children[0].status != undefined) {
+ incomingPage = tabContainer.children[0]
+ incomingPage.status = PageStatus.Activating // triggers the orientation change
+ incomingPage.visible = true
+ if (incomingPage == outgoingPage)
+ outgoingPage = null
+ }
+ if (animate)
+ tabContainer.state = "Incoming"
+ else
+ tabContainer.incomingDone()
+ }
+ } else {
+ if (tabContainer.state != "Hidden") {
+ if (tabContainer.children.length > 0 && tabContainer.children[0].status != undefined) {
+ outgoingPage = tabContainer.children[0]
+ outgoingPage.status = PageStatus.Deactivating
+ if (incomingPage == outgoingPage)
+ incomingPage = null
+ }
+ if (animate)
+ tabContainer.state = "Outgoing"
+ else
+ tabContainer.outgoingDone()
+ }
+ }
+ }
+ screen.currentOrientationChanged.disconnect(priv.disableAnimations)
+ }
+ }
+}
--- /dev/null
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the Qt Components project.
+**
+** $QT_BEGIN_LICENSE:BSD$
+** You may use this file under the terms of the BSD license as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions and the following disclaimer in
+** the documentation and/or other materials provided with the
+** distribution.
+** * Neither the name of Nokia Corporation and its Subsidiary(-ies) nor
+** the names of its contributors may be used to endorse or promote
+** products derived from this software without specific prior written
+** permission.
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick 1.1
+import "." 1.1
+
+FocusScopeItem {
+ id: root
+
+ // Common public API
+ property alias font: textEdit.font
+ property alias cursorPosition: textEdit.cursorPosition
+ property alias horizontalAlignment: textEdit.horizontalAlignment
+ property alias inputMethodHints: textEdit.inputMethodHints
+ property alias verticalAlignment: textEdit.verticalAlignment
+ property alias readOnly: textEdit.readOnly
+ property alias selectedText: textEdit.selectedText
+ property alias selectionEnd: textEdit.selectionEnd
+ property alias selectionStart: textEdit.selectionStart
+ property alias text: textEdit.text
+ property alias textFormat: textEdit.textFormat
+ property alias wrapMode: textEdit.wrapMode
+ property bool errorHighlight: false
+
+ function copy() {
+ textEdit.copy()
+ }
+
+ function paste() {
+ textEdit.paste()
+ }
+
+ function cut() {
+ textEdit.cut()
+ }
+
+ function select(start, end) {
+ textEdit.select(start, end)
+ }
+
+ function selectAll() {
+ textEdit.selectAll()
+ }
+
+ function selectWord() {
+ textEdit.selectWord()
+ }
+
+ function positionAt(x, y) {
+ var p = mapToItem(textEdit, x, y);
+ return textEdit.positionAt(p.x, p.y)
+ }
+
+ function positionToRectangle(pos) {
+ var rect = textEdit.positionToRectangle(pos)
+ var point = mapFromItem(textEdit, rect.x, rect.y)
+ rect.x = point.x; rect.y = point.y
+ return rect;
+ }
+
+ function openSoftwareInputPanel() {
+ textEdit.openSoftwareInputPanel()
+ }
+
+ function closeSoftwareInputPanel() {
+ textEdit.closeSoftwareInputPanel()
+ }
+
+ // API extensions
+ property alias placeholderText: placeholder.text
+ // TODO: Refactor implicit size when following bugs are resolved
+ // http://bugreports.qt.nokia.com/browse/QTBUG-14957
+ // http://bugreports.qt.nokia.com/browse/QTBUG-16665
+ // http://bugreports.qt.nokia.com/browse/QTBUG-16710 (fixed in Qt 4.7.2)
+ // http://bugreports.qt.nokia.com/browse/QTBUG-12305 (fixed in QtQuick1.1)
+ property real platformMaxImplicitWidth: -1
+ property real platformMaxImplicitHeight: -1
+ property bool platformInverted: false
+ property bool enabled: true // overriding due to QTBUG-15797 and related bugs
+
+ implicitWidth: {
+ var preferredWidth = placeholder.visible ? placeholder.model.paintedWidth
+ : flick.contentWidth
+ preferredWidth = Math.max(preferredWidth, privy.minImplicitWidth)
+ preferredWidth += container.horizontalMargins
+ if (root.platformMaxImplicitWidth >= 0)
+ return Math.min(preferredWidth, root.platformMaxImplicitWidth)
+ return preferredWidth
+ }
+
+ implicitHeight: {
+ var preferredHeight = placeholder.visible ? placeholder.model.paintedHeight
+ : flick.contentHeight
+ preferredHeight += container.verticalMargins
+ // layout spec gives minimum height (textFieldHeight) which includes required padding
+ preferredHeight = Math.max(privateStyle.textFieldHeight, preferredHeight)
+ if (root.platformMaxImplicitHeight >= 0)
+ return Math.min(preferredHeight, root.platformMaxImplicitHeight)
+ return preferredHeight
+ }
+
+ onWidthChanged: {
+ // Detect when a width has been explicitly set. Needed to determine if the TextEdit should
+ // grow horizontally or wrap. I.e. in determining the model's width. There's no way to get
+ // notified of having an explicit width set. Therefore it's polled in widthChanged.
+ privy.widthExplicit = root.widthExplicit()
+ }
+
+ Connections {
+ target: screen
+ onCurrentOrientationChanged: {
+ delayedEnsureVisible.start()
+ fade.start()
+ scroll.start()
+ }
+ }
+
+ QtObject {
+ id: privy
+ // TODO: More consistent minimum width for empty TextArea than 20 * " " on current font?
+ property real minImplicitWidth: privateStyle.textWidth(" ", textEdit.font)
+ property bool widthExplicit: false
+ property bool wrap: privy.widthExplicit || root.platformMaxImplicitWidth >= 0
+ property real wrapWidth: privy.widthExplicit ? root.width - container.horizontalMargins
+ : root.platformMaxImplicitWidth - container.horizontalMargins
+ function bg_postfix() {
+ if (root.errorHighlight)
+ return "error"
+ else if (root.readOnly || !root.enabled)
+ return "uneditable"
+ else if (textEdit.activeFocus)
+ return "highlighted"
+ else
+ return "editable"
+ }
+ }
+
+ BorderImage {
+ id: background
+ anchors.fill: parent
+ source: privateStyle.imagePath("qtg_fr_textfield_" + privy.bg_postfix(), root.platformInverted)
+ border {
+ left: platformStyle.borderSizeMedium
+ top: platformStyle.borderSizeMedium
+ right: platformStyle.borderSizeMedium
+ bottom: platformStyle.borderSizeMedium
+ }
+ smooth: true
+ }
+
+ Item {
+ id: container
+
+ property real horizontalMargins: container.anchors.leftMargin
+ + container.anchors.rightMargin
+ + flick.anchors.leftMargin
+ + flick.anchors.rightMargin
+
+ property real verticalMargins: container.anchors.topMargin
+ + container.anchors.bottomMargin
+ + flick.anchors.topMargin
+ + flick.anchors.bottomMargin
+
+ anchors {
+ fill: parent
+ leftMargin: platformStyle.paddingSmall; rightMargin: platformStyle.paddingSmall
+ topMargin: platformStyle.paddingMedium; bottomMargin: platformStyle.paddingMedium
+ }
+
+ clip: true
+
+ // TODO: Should placeholder also be scrollable?
+ Text {
+ id: placeholder
+ objectName: "placeholder"
+
+ // TODO: See TODO: Refactor implicit size...
+ property variant model: Text {
+ font: textEdit.font
+ text: placeholder.text
+ visible: false
+ wrapMode: textEdit.wrapMode
+ horizontalAlignment: textEdit.horizontalAlignment
+ verticalAlignment: textEdit.verticalAlignment
+ opacity: 0
+
+ Binding {
+ when: privy.wrap
+ target: placeholder.model
+ property: "width"
+ value: privy.wrapWidth
+ }
+ }
+
+ color: root.platformInverted ? platformStyle.colorNormalMidInverted
+ : platformStyle.colorNormalMid
+ font: textEdit.font
+ horizontalAlignment: textEdit.horizontalAlignment
+ verticalAlignment: textEdit.verticalAlignment
+ visible: {
+ if (text && (textEdit.model.paintedWidth == 0 && textEdit.model.paintedHeight <= textEdit.cursorRectangle.height))
+ return (readOnly || !textEdit.activeFocus)
+ else
+ return false
+ }
+ wrapMode: textEdit.wrapMode
+ x: flick.x; y: flick.y
+ height: flick.height; width: flick.width
+ }
+
+ Flickable {
+ id: flick
+
+ property real tiny: Math.round(platformStyle.borderSizeMedium / 2)
+
+ function ensureVisible(rect) {
+ if (Math.round(contentX) > Math.round(rect.x))
+ contentX = rect.x
+ else if (Math.round(contentX + width) < Math.round(rect.x + rect.width))
+ contentX = rect.x + rect.width - width
+
+ if (Math.round(contentY) > Math.round(rect.y))
+ contentY = rect.y
+ else if (Math.round(contentY + height) < Math.round(rect.y + rect.height))
+ contentY = rect.y + rect.height - height
+ }
+
+ anchors {
+ fill: parent
+ leftMargin: tiny
+ rightMargin: tiny
+ topMargin: tiny / 2
+ bottomMargin: tiny / 2
+ }
+
+ boundsBehavior: Flickable.StopAtBounds
+ contentHeight: textEdit.model.paintedHeight
+ contentWidth: textEdit.model.paintedWidth +
+ (textEdit.wrapMode == TextEdit.NoWrap ? textEdit.cursorRectangle.width : 0)
+ interactive: root.enabled
+
+ onHeightChanged: {
+ if(textEdit.cursorVisible || textEdit.cursorPosition == textEdit.selectionEnd)
+ ensureVisible(textEdit.cursorRectangle)
+ }
+
+ onWidthChanged: {
+ if(textEdit.cursorVisible || textEdit.cursorPosition == textEdit.selectionEnd)
+ ensureVisible(textEdit.cursorRectangle)
+ }
+
+ TextEdit {
+ id: textEdit
+ objectName: "textEdit"
+
+ // TODO: See TODO: Refactor implicit size...
+ property variant model: TextEdit {
+ font: textEdit.font
+ text: textEdit.text
+ horizontalAlignment: textEdit.horizontalAlignment
+ verticalAlignment: textEdit.verticalAlignment
+ wrapMode: textEdit.wrapMode
+ visible: false
+ opacity: 0
+
+ // In Wrap mode, if the width is bound the text will always get wrapped at the
+ // set width. If the width is not bound the text won't get wrapped but
+ // paintedWidth will increase.
+ Binding {
+ when: privy.wrap
+ target: textEdit.model
+ property: "width"
+ value: privy.wrapWidth
+ }
+ }
+ activeFocusOnPress: false
+ enabled: root.enabled
+ focus: true
+ font { family: platformStyle.fontFamilyRegular; pixelSize: platformStyle.fontSizeMedium }
+ color: root.platformInverted ? platformStyle.colorNormalLightInverted
+ : platformStyle.colorNormalDark
+ cursorVisible: activeFocus && !selectedText
+ selectedTextColor: root.platformInverted ? platformStyle.colorNormalDarkInverted
+ : platformStyle.colorNormalLight
+ selectionColor: root.platformInverted ? platformStyle.colorTextSelectionInverted
+ : platformStyle.colorTextSelection
+ textFormat: TextEdit.AutoText
+ wrapMode: TextEdit.Wrap
+ height: flick.height
+ width: flick.width
+ // TODO: Make bug report?
+ // Called too early (before TextEdit size is adjusted) delay ensureVisible call a bit
+ onCursorRectangleChanged: delayedEnsureVisible.start()
+ onActiveFocusChanged: {
+ if (activeFocus) {
+ horizontal.flash()
+ vertical.flash()
+ }
+ }
+ onEnabledChanged: {
+ if (!enabled) {
+ deselect()
+ // De-focusing requires setting focus elsewhere, in this case editor's parent
+ if (root.parent)
+ root.parent.forceActiveFocus()
+ }
+ }
+
+ Keys.forwardTo: touchController
+
+ TextTouchController {
+ id: touchController
+
+ // selection handles require touch area geometry to differ from TextEdit's geometry
+ anchors {
+ top: editor.top; topMargin: -container.verticalMargins / 2
+ left: editor.left; leftMargin: -container.horizontalMargins / 2
+ }
+ height: Math.max(root.height, flick.contentHeight + container.verticalMargins * 2)
+ width: Math.max(root.width, flick.contentWidth + container.horizontalMargins * 2)
+ editorScrolledX: flick.contentX - (container.horizontalMargins / 2)
+ editorScrolledY: flick.contentY - (container.verticalMargins / 2)
+ copyEnabled: textEdit.selectedText
+ cutEnabled: !textEdit.readOnly && textEdit.selectedText
+ platformInverted: root.platformInverted
+ Component.onCompleted: flick.movementEnded.connect(touchController.flickEnded)
+ Connections { target: screen; onCurrentOrientationChanged: touchController.updateGeometry() }
+ Connections {
+ target: textEdit
+ onHeightChanged: touchController.updateGeometry()
+ onWidthChanged: touchController.updateGeometry()
+ onHorizontalAlignmentChanged: touchController.updateGeometry()
+ onVerticalAlignmentChanged: touchController.updateGeometry()
+ onWrapModeChanged: touchController.updateGeometry()
+ onFontChanged: touchController.updateGeometry()
+ }
+ }
+ }
+
+ PropertyAnimation { id: fade; target: textEdit; property: "opacity"; from: 0; to: 1; duration: 250 }
+ PropertyAnimation { id: scroll; target: flick; property: "contentY"; duration: 250 }
+ }
+
+ ScrollBar {
+ id: vertical
+ anchors {
+ top: flick.top;
+ topMargin: -flick.tiny / 2;
+ left: flick.right;
+ }
+ flickableItem: flick
+ interactive: false
+ orientation: Qt.Vertical
+ height: container.height
+ platformInverted: root.platformInverted
+ }
+
+ ScrollBar {
+ id: horizontal
+ anchors {
+ left: flick.left;
+ leftMargin: -flick.tiny;
+ bottom: container.bottom;
+ bottomMargin: -flick.tiny / 2
+ rightMargin: vertical.opacity ? vertical.width : 0
+ }
+ flickableItem: flick
+ interactive: false
+ orientation: Qt.Horizontal
+ width: container.width
+ platformInverted: root.platformInverted
+ }
+
+ Timer {
+ id: delayedEnsureVisible
+ interval: 1
+ onTriggered: flick.ensureVisible(textEdit.cursorRectangle)
+ }
+ }
+}
--- /dev/null
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the Qt Components project.
+**
+** $QT_BEGIN_LICENSE:BSD$
+** You may use this file under the terms of the BSD license as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions and the following disclaimer in
+** the documentation and/or other materials provided with the
+** distribution.
+** * Neither the name of Nokia Corporation and its Subsidiary(-ies) nor
+** the names of its contributors may be used to endorse or promote
+** products derived from this software without specific prior written
+** permission.
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+import QtQuick 1.1
+import "." 1.1
+import "AppManager.js" as AppManager
+
+Item {
+ id: root
+
+ property Item editor: null
+ property bool copyEnabled: false
+ property bool cutEnabled: false
+ property bool platformInverted: false
+
+ function show() {
+ // Show menu only if some of the options is available
+ if(root.copyEnabled || root.cutEnabled || editor.canPaste) {
+ parent = AppManager.rootObject();
+ root.visible = true;
+ calculatePosition();
+ }
+ }
+
+ function hide() {
+ root.visible = false;
+ }
+
+ function calculatePosition() {
+ if (editor && root.visible) {
+ var rectStart = editor.positionToRectangle(editor.selectionStart);
+ var rectEnd = editor.positionToRectangle(editor.selectionEnd);
+
+ var posStart = editor.mapToItem(parent, rectStart.x, rectStart.y);
+ var posEnd = editor.mapToItem(parent, rectEnd.x, rectEnd.y);
+
+ var selectionCenterX = (posEnd.x + posStart.x) / 2;
+ if (posStart.y != posEnd.y)
+ // we have multiline selection so center to the screen
+ selectionCenterX = parent.width / 2;
+
+ var contextMenuMargin = 10; // the space between the context menu and the line above/below
+ var contextMenuAdjustedRowHeight = row.height + contextMenuMargin;
+ var tempY = posStart.y - contextMenuAdjustedRowHeight;
+ var minVerticalPos = internal.textArea ? internal.textArea.mapToItem(parent, 0, 0).y - row.height : 0
+
+ if (tempY < minVerticalPos)
+ tempY = minVerticalPos
+
+ if (tempY < 0)
+ tempY = 0
+
+ root.x = Math.max(0, Math.min(selectionCenterX - row.width / 2, parent.width - row.width));
+ root.y = tempY;
+ }
+ }
+
+ onVisibleChanged: {
+ if (visible) {
+ internal.editorSceneXChanged.connect(internal.editorMoved)
+ internal.editorSceneYChanged.connect(internal.editorMoved)
+ } else {
+ internal.editorSceneXChanged.disconnect(internal.editorMoved)
+ internal.editorSceneYChanged.disconnect(internal.editorMoved)
+ }
+ }
+
+ x: 0; y: 0
+ visible: false
+
+ Binding { target: internal; property: "editorSceneX"; value: AppManager.sceneX(root.editor); when: root.visible && (root.editor != null) }
+ Binding { target: internal; property: "editorSceneY"; value: AppManager.sceneY(root.editor); when: root.visible && (root.editor != null) }
+
+ QtObject {
+ id: internal
+
+ property real editorSceneX
+ property real editorSceneY
+ property Item textArea: null
+
+ function editorMoved() {
+ root.calculatePosition()
+ }
+
+ Component.onCompleted: textArea = AppManager.findParent(editor, "errorHighlight")
+ }
+
+ ButtonRow {
+ id: row
+
+ function visibleButtonCount() {
+ var count = 0
+ if (copyButton.visible) ++count
+ if (cutButton.visible) ++count
+ if (pasteButton.visible) ++count
+ return count
+ }
+
+ exclusive: false
+ width: Math.round(privateStyle.buttonSize * 1.5) * visibleButtonCount()
+
+ onWidthChanged: calculatePosition()
+ onHeightChanged: calculatePosition()
+
+ Button {
+ id: copyButton
+ iconSource: privateStyle.imagePath("qtg_toolbar_copy", root.platformInverted)
+ visible: root.copyEnabled
+ platformInverted: root.platformInverted
+ onClicked: editor.copy()
+ }
+ Button {
+ id: cutButton
+ iconSource: privateStyle.imagePath("qtg_toolbar_cut", root.platformInverted)
+ visible: root.cutEnabled
+ platformInverted: root.platformInverted
+ onClicked: {
+ editor.cut()
+ root.visible = false
+ }
+ }
+ Button {
+ id: pasteButton
+ iconSource: privateStyle.imagePath("qtg_toolbar_paste", root.platformInverted)
+ visible: editor.canPaste
+ platformInverted: root.platformInverted
+ onClicked: {
+ editor.paste()
+ root.visible = false
+ }
+ }
+ }
+}
--- /dev/null
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the Qt Components project.
+**
+** $QT_BEGIN_LICENSE:BSD$
+** You may use this file under the terms of the BSD license as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions and the following disclaimer in
+** the documentation and/or other materials provided with the
+** distribution.
+** * Neither the name of Nokia Corporation and its Subsidiary(-ies) nor
+** the names of its contributors may be used to endorse or promote
+** products derived from this software without specific prior written
+** permission.
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick 1.1
+import "." 1.1
+
+FocusScope {
+ id: root
+
+ // Common Public API
+ property alias placeholderText: placeholder.text
+ property alias inputMethodHints: textInput.inputMethodHints
+ property alias font: textInput.font
+ property alias cursorPosition: textInput.cursorPosition
+ property alias readOnly: textInput.readOnly
+ property alias echoMode: textInput.echoMode
+ property alias acceptableInput: textInput.acceptableInput
+ property alias inputMask: textInput.inputMask
+ property alias validator: textInput.validator
+ property alias selectedText: textInput.selectedText
+ property alias selectionEnd: textInput.selectionEnd
+ property alias selectionStart: textInput.selectionStart
+ property alias text: textInput.text
+ property bool errorHighlight: !acceptableInput
+ property alias maximumLength: textInput.maximumLength
+
+ function copy() {
+ textInput.copy()
+ }
+
+ function paste() {
+ textInput.paste()
+ }
+
+ function cut() {
+ textInput.cut()
+ }
+
+ function select(start, end) {
+ textInput.select(start, end)
+ }
+
+ function selectAll() {
+ textInput.selectAll()
+ }
+
+ function selectWord() {
+ textInput.selectWord()
+ }
+
+ function positionAt(x) {
+ return textInput.positionAt(mapToItem(textInput, x, 0).x)
+ }
+
+ function positionToRectangle(pos) {
+ var rect = textInput.positionToRectangle(pos)
+ rect.x = mapFromItem(textInput, rect.x, 0).x
+ return rect;
+ }
+
+ function openSoftwareInputPanel() {
+ textInput.openSoftwareInputPanel()
+ }
+
+ function closeSoftwareInputPanel() {
+ textInput.closeSoftwareInputPanel()
+ }
+
+ // API extensions
+ implicitWidth: platformLeftMargin + platformRightMargin + flick.tiny * 2 +
+ Math.max(privateStyle.textWidth(text, textInput.font), priv.minWidth)
+ implicitHeight: Math.max(privateStyle.textFieldHeight,
+ 2 * platformStyle.paddingMedium + privateStyle.fontHeight(textInput.font))
+
+ property bool enabled: true // overriding due to QTBUG-15797 and related bugs
+
+ property real platformLeftMargin: platformStyle.paddingSmall
+ property real platformRightMargin: platformStyle.paddingSmall
+ property bool platformInverted: false
+
+ // Private data
+ QtObject {
+ id: priv
+ // Minimum width is either placeholder text lenght or 5 spaces on current font.
+ // Using placeholder text lenght as minimum width prevents implicit sized item from
+ // shrinking on focus gain.
+ property real minWidth: placeholder.text ? privateStyle.textWidth(placeholder.text, textInput.font)
+ : privateStyle.textWidth(" ", textInput.font)
+
+ function bg_postfix() {
+ if (root.errorHighlight)
+ return "error"
+ else if (root.readOnly || !root.enabled)
+ return "uneditable"
+ else if (textInput.activeFocus)
+ return "highlighted"
+ else
+ return "editable"
+ }
+ }
+
+ BorderImage {
+ id: frame
+ anchors.fill: parent
+ source: privateStyle.imagePath("qtg_fr_textfield_" + priv.bg_postfix(), root.platformInverted)
+ border {
+ left: platformStyle.borderSizeMedium
+ top: platformStyle.borderSizeMedium
+ right: platformStyle.borderSizeMedium
+ bottom: platformStyle.borderSizeMedium
+ }
+ smooth: true
+ }
+
+ Item {
+ id: container
+
+ anchors {
+ left: root.left; leftMargin: root.platformLeftMargin
+ right: root.right; rightMargin: root.platformRightMargin
+ verticalCenter : root.verticalCenter
+ }
+ clip: true
+ height: root.height
+
+ Flickable {
+ id: flick
+
+ property real tiny: Math.round(platformStyle.borderSizeMedium / 2)
+
+ function ensureVisible(rect) {
+ if (rect.x >= 0 && Math.round(contentX) > Math.round(rect.x))
+ contentX = rect.x
+ else if (Math.round(contentX + width) < Math.round(rect.x + rect.width))
+ contentX = rect.x + rect.width - width
+ }
+
+ anchors {
+ left: parent.left; leftMargin: tiny
+ right: parent.right; rightMargin: tiny
+ verticalCenter : parent.verticalCenter
+ }
+
+ boundsBehavior: Flickable.StopAtBounds
+ contentWidth: textInput.paintedWidth
+ height: textInput.paintedHeight
+
+ onWidthChanged: ensureVisible(textInput.cursorRectangle)
+
+ TextInput {
+ id: textInput; objectName: "textInput"
+
+ property real paintedWidth: textInput.model.paintedWidth
+ property real paintedHeight: textInput.model.paintedHeight
+
+ // TODO: See TODO: Refactor implicit size...
+ property variant model: Text {
+ font: textInput.font
+ text: textInput.text
+ horizontalAlignment: textInput.horizontalAlignment
+ visible: false
+ opacity: 0
+ }
+
+ activeFocusOnPress: false
+ cursorVisible: activeFocus && !selectedText
+ enabled: root.enabled
+ color: root.platformInverted ? platformStyle.colorNormalLightInverted
+ : platformStyle.colorNormalDark
+ focus: true
+ font { family: platformStyle.fontFamilyRegular; pixelSize: platformStyle.fontSizeMedium }
+ selectedTextColor: root.platformInverted ? platformStyle.colorNormalDarkInverted
+ : platformStyle.colorNormalLight
+ selectionColor: root.platformInverted ? platformStyle.colorTextSelectionInverted
+ : platformStyle.colorTextSelection
+ width: Math.max(flick.width, paintedWidth)
+
+ onEnabledChanged: {
+ if (!enabled) {
+ deselect()
+ // De-focusing requires setting focus elsewhere, in this case editor's parent
+ if (root.parent)
+ root.parent.forceActiveFocus()
+ }
+ }
+
+ onCursorPositionChanged: flick.ensureVisible(textInput.cursorRectangle)
+
+ Keys.forwardTo: touchController
+
+ TextTouchController {
+ id: touchController
+
+ // selection handles require touch area geometry to differ from TextInput's geometry
+ anchors {
+ left: parent.left;
+ leftMargin: -flick.tiny
+ verticalCenter : parent.verticalCenter
+ }
+ height: root.height
+ width: Math.max(root.width, flick.contentWidth + flick.tiny * 2)
+ editorScrolledX: flick.contentX - container.anchors.leftMargin - flick.tiny
+ editorScrolledY: 0
+ copyEnabled: textInput.selectedText
+ cutEnabled: !textInput.readOnly && textInput.selectedText
+ platformInverted: root.platformInverted
+ Component.onCompleted: flick.movementEnded.connect(touchController.flickEnded)
+ Connections { target: screen; onCurrentOrientationChanged: touchController.updateGeometry() }
+ Connections {
+ target: textInput
+ onHeightChanged: touchController.updateGeometry()
+ onWidthChanged: touchController.updateGeometry()
+ onHorizontalAlignmentChanged: touchController.updateGeometry()
+ onFontChanged: touchController.updateGeometry()
+ }
+ }
+ }
+ }
+
+ Text {
+ id: placeholder; objectName: "placeholder"
+ anchors {
+ left: parent.left; leftMargin: flick.tiny
+ right: parent.right; rightMargin: flick.tiny
+ verticalCenter : parent.verticalCenter
+ }
+ color: root.platformInverted ? platformStyle.colorNormalMidInverted
+ : platformStyle.colorNormalMid
+ font: textInput.font
+ visible: (!textInput.activeFocus || readOnly) && !textInput.text && text
+ }
+
+ }
+}
--- /dev/null
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the Qt Components project.
+**
+** $QT_BEGIN_LICENSE:BSD$
+** You may use this file under the terms of the BSD license as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions and the following disclaimer in
+** the documentation and/or other materials provided with the
+** distribution.
+** * Neither the name of Nokia Corporation and its Subsidiary(-ies) nor
+** the names of its contributors may be used to endorse or promote
+** products derived from this software without specific prior written
+** permission.
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick 1.1
+import "AppManager.js" as AppManager
+
+Magnifier {
+ id: root
+
+ property Item editor: parent.editor
+ // Defines the center of the content to be magnified in X axis
+ // Note: the center of the content to be magnified in Y axis is determined by the cursor position.
+ property variant contentCenter: Qt.point(0, 0) //editor's coordinate system
+ property bool platformInverted: false
+
+ function show() {
+ parent = AppManager.rootObject();
+ sourceRect = internal.calculateSourceGeometry();
+ internal.calculatePosition();
+ root.visible = true;
+ }
+
+ function hide() {
+ root.visible = false;
+ }
+
+ sourceRect: Qt.rect(0, 0, 0, 0)
+ visible: false
+ scaleFactor: 1.5
+ maskFileName: root.platformInverted ? ":/graphics_1_1/qtg_graf_magnifier_mask_inverse.svg"
+ : ":/graphics_1_1/qtg_graf_magnifier_mask.svg"
+ overlayFileName: root.platformInverted ? ":/graphics_1_1/qtg_graf_magnifier_inverse.svg"
+ : ":/graphics_1_1/qtg_graf_magnifier.svg"
+
+ onContentCenterChanged: internal.updateSourceRect()
+
+ onSourceRectChanged: if (visible) internal.calculatePosition()
+
+ Connections {
+ target: editor
+ onCursorPositionChanged: internal.updateSourceRect
+ }
+
+ // Private
+ QtObject {
+ id: internal
+
+ function updateSourceRect () {
+ if (visible)
+ sourceRect = internal.calculateSourceGeometry();
+ }
+
+ function calculatePosition() {
+ width = sourceRect.width * scaleFactor;
+ height = sourceRect.height * scaleFactor;
+
+ var magnifierMargin = -platformStyle.paddingLarge; // the offset between the magnifier and top of the line
+ var pos = parent.mapFromItem(editor,
+ contentCenter.x - width/2,
+ contentCenter.y - sourceRect.height/2 - height - magnifierMargin);
+
+ root.x = pos.x;
+ root.y = pos.y;
+ }
+
+ // Calculates and returns the source geometry of the content to be magnified in scene coordinates
+ function calculateSourceGeometry() {
+ var magniferSize = Qt.size(platformStyle.graphicSizeMedium * 2, platformStyle.graphicSizeMedium * 2);
+ var sourceSize = Qt.size(magniferSize.width / scaleFactor, magniferSize.height / scaleFactor);
+ var contentCenterScene = editor.mapToItem(null, contentCenter.x, contentCenter.y);
+
+ var rect = Qt.rect(contentCenterScene.x - sourceSize.width / 2,
+ contentCenterScene.y - sourceSize.height / 2,
+ sourceSize.width, sourceSize.height);
+ return rect;
+ }
+ }
+}
--- /dev/null
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the Qt Components project.
+**
+** $QT_BEGIN_LICENSE:BSD$
+** You may use this file under the terms of the BSD license as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions and the following disclaimer in
+** the documentation and/or other materials provided with the
+** distribution.
+** * Neither the name of Nokia Corporation and its Subsidiary(-ies) nor
+** the names of its contributors may be used to endorse or promote
+** products derived from this software without specific prior written
+** permission.
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick 1.1
+import "RectUtils.js" as Utils
+
+Item {
+ id: root
+
+ property alias imageSource: image.source
+ property int editorPos: 0 //character position of the handle in the editor document
+ property Item editor
+ // the default size of the touch area should come from some style constant
+ property variant touchAreaSize: Qt.size(platformStyle.graphicSizeMedium, platformStyle.graphicSizeMedium)
+ property alias showImage: image.visible
+ property variant viewPortRect: Qt.rect(0, 0, 0, 0) // item's coordinates
+ //parent's coordinate system
+ property variant center: Qt.point(root.x + root.width / 2, root.y + root.height / 2)
+
+ // Point is in Item's coordinate system
+ function containsPoint(point) {
+ var touchAreaRect = Qt.rect(touchArea.x, touchArea.y, touchArea.width, touchArea.height);
+
+ if (!Utils.rectContainsRect(viewPortRect, touchAreaRect)
+ && Utils.rectIntersectsRect(viewPortRect, touchAreaRect)) {
+ touchAreaRect.x = Math.max(touchAreaRect.x, viewPortRect.x);
+ touchAreaRect.x = Math.min(touchAreaRect.x, viewPortRect.x + viewPortRect.width - touchAreaRect.width);
+ touchAreaRect.y = Math.max(touchAreaRect.y, viewPortRect.y);
+ touchAreaRect.y = Math.min(touchAreaRect.y, viewPortRect.y + viewPortRect.height - touchAreaRect.height);
+ }
+
+ effectiveTouchArea.x = touchAreaRect.x;
+ effectiveTouchArea.y = touchAreaRect.y;
+
+ if (Utils.rectContainsPoint(touchAreaRect, point.x, point.y))
+ return true;
+
+ return false;
+ }
+
+ // Point is in parent's coordinate system
+ function pointDistanceFromCenter(point) {
+ return Utils.manhattan(point, root.center);
+ }
+
+ function updateGeometry() {
+ var rect = root.editor.positionToRectangle(editorPos);
+ var pos = root.editor.mapToItem(root.parent, rect.x, rect.y);
+ root.x = pos.x;
+ root.y = pos.y;
+ root.width = rect.width;
+ root.height = rect.height;
+ }
+
+ onEditorPosChanged: root.updateGeometry()
+
+ Item {
+ id: touchArea
+
+ visible: false
+ anchors.centerIn: root
+ width: root.touchAreaSize.width
+ height: Math.max(root.touchAreaSize.height, root.height)
+ }
+
+ Item {
+ id: effectiveTouchArea
+
+ visible: false
+ width: root.touchAreaSize.width
+ height: Math.max(root.touchAreaSize.height, root.height)
+ }
+
+ BorderImage {
+ id: image
+
+ property real tiny: Math.round(platformStyle.borderSizeMedium / 2)
+
+ anchors {
+ left: root.objectName == "SelectionEnd" ? root.right : undefined
+ right: root.objectName == "SelectionBegin" ? root.left : undefined
+ leftMargin: root.objectName == "SelectionEnd" ? -editor.cursorRectangle.width : 0
+ top: root.top
+ topMargin: -tiny / 2 + 1
+ bottom: root.bottom
+ bottomMargin: -tiny / 2
+ }
+
+ border {
+ left: 0
+ top: tiny
+ right: 0
+ bottom: tiny
+ }
+ }
+}
--- /dev/null
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the Qt Components project.
+**
+** $QT_BEGIN_LICENSE:BSD$
+** You may use this file under the terms of the BSD license as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions and the following disclaimer in
+** the documentation and/or other materials provided with the
+** distribution.
+** * Neither the name of Nokia Corporation and its Subsidiary(-ies) nor
+** the names of its contributors may be used to endorse or promote
+** products derived from this software without specific prior written
+** permission.
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick 1.1
+import "." 1.1
+import "RectUtils.js" as Utils
+
+
+MouseArea {
+ id: root
+
+ property Item editor: parent
+ property alias touchTools: touchToolsLoader.item
+ property real editorScrolledX: 0
+ property real editorScrolledY: 0
+ property bool copyEnabled: false
+ property bool cutEnabled: false
+ property bool platformInverted: false
+
+ enabled: !editor.inputMethodComposing
+
+ LayoutMirroring.enabled: false
+ LayoutMirroring.childrenInherit: true
+
+ function updateGeometry() {
+ if (touchTools) {
+ touchTools.handleBegin.updateGeometry();
+ touchTools.handleEnd.updateGeometry();
+ touchTools.contextMenu.calculatePosition(); // Update context menu position
+ }
+ }
+
+ function flickEnded() {
+ if (internal.editorHasSelection && internal.selectionVisible())
+ touchTools.contextMenu.show();
+ else
+ touchTools.contextMenu.hide();
+ }
+
+ onPressed: {
+ if (!touchTools)
+ touchToolsLoader.sourceComponent = touchToolsComponent
+
+ internal.currentTouchPoint = root.mapToItem(editor, mouse.x, mouse.y);
+
+ if (internal.currentTouchPoint.x < 0)
+ internal.currentTouchPoint.x = 0
+
+ if (internal.currentTouchPoint.y < 0)
+ internal.currentTouchPoint.y = 0
+
+ if (internal.tapCounter == 0)
+ internal.touchPoint = internal.currentTouchPoint;
+
+ editor.forceActiveFocus();
+ touchTools.contextMenu.hide();
+ internal.handleMoved = false;
+
+ touchTools.handleBegin.viewPortRect = internal.mapViewPortRectToHandle(touchTools.handleBegin);
+ touchTools.handleEnd.viewPortRect = internal.mapViewPortRectToHandle(touchTools.handleEnd);
+
+ internal.pressedHandle = internal.handleForPoint({x: internal.currentTouchPoint.x, y: internal.currentTouchPoint.y});
+
+ if (internal.pressedHandle != null) {
+ internal.handleGrabbed();
+ // Position cursor at the pressed selection handle
+ // TODO: Add bug ID!!
+ var tempStart = editor.selectionStart
+ var tempEnd = editor.selectionEnd
+ if (internal.pressedHandle == touchTools.handleBegin) {
+ editor.cursorPosition = editor.selectionStart
+ editor.select(tempEnd, tempStart);
+ } else {
+ editor.cursorPosition = editor.selectionEnd
+ editor.select(tempStart, tempEnd);
+ }
+ }
+ }
+
+ onClicked: {
+ ++internal.tapCounter;
+ if (internal.tapCounter == 1) {
+ internal.onSingleTap();
+ clickTimer.start();
+ } else if (internal.tapCounter == 2 && clickTimer.running) {
+ internal.onDoubleTap();
+ clickTimer.restart();
+ } else if (internal.tapCounter == 3 && clickTimer.running)
+ internal.onTripleTap();
+ }
+
+ onPressAndHold: {
+ clickTimer.stop();
+ internal.tapCounter = 0;
+ internal.longTap = true
+ if (!internal.handleMoved) {
+ if (internal.pressedHandle == null) {
+ // position the cursor under the long tap and make the cursor handle grabbed
+ editor.select(editor.cursorPosition, editor.cursorPosition);
+ editor.cursorPosition = editor.positionAt(internal.touchPoint.x,internal.touchPoint.y);
+ internal.pressedHandle = touchTools.handleEnd;
+ if (editor.readOnly)
+ touchTools.magnifier.hide();
+ internal.handleGrabbed();
+ }
+ touchTools.contextMenu.hide();
+ }
+
+ if (!editor.readOnly || internal.editorHasSelection)
+ touchTools.magnifier.show();
+ }
+
+ onReleased: {
+ touchTools.magnifier.hide();
+
+ mouseGrabDisabler.setKeepMouseGrab(root, false);
+ internal.forcedSelection = false;
+
+ if ((internal.pressedHandle != null && internal.handleMoved) ||
+ (internal.longTap && !editor.readOnly) ||
+ (internal.pressedHandle != null && internal.longTap))
+ touchTools.contextMenu.show();
+ internal.longTap = false;
+ }
+
+ onPositionChanged: {
+
+ internal.currentTouchPoint = root.mapToItem(editor, mouse.x, mouse.y);
+
+ if (internal.pressedHandle != null) {
+ internal.hitTestPoint = {x:internal.currentTouchPoint.x, y:internal.currentTouchPoint.y};
+
+ var newPosition = editor.positionAt(internal.hitTestPoint.x, internal.hitTestPoint.y);
+ if (newPosition >= 0 && newPosition != editor.cursorPosition) {
+ if (internal.hasSelection) {
+ var anchorPos = internal.pressedHandle == touchTools.handleBegin ? editor.selectionEnd
+ : editor.selectionStart
+ if (editor.selectionStart == editor.cursorPosition)
+ anchorPos = editor.selectionEnd;
+ else if (editor.selectionEnd == editor.cursorPosition)
+ anchorPos = editor.selectionStart;
+ editor.select(anchorPos, newPosition);
+ } else {
+ editor.cursorPosition = newPosition;
+ }
+ if (!editor.readOnly || internal.editorHasSelection)
+ touchTools.magnifier.show();
+ internal.handleMoved = true;
+ }
+ }
+ }
+
+ Connections {
+ target: editor
+ onTextChanged: internal.onEditorTextChanged
+ }
+
+ // Private
+ QtObject {
+ id: internal
+
+ property bool forcedSelection: false
+ property bool hasSelection: editorHasSelection || forcedSelection
+ property bool editorHasSelection: editor.selectionStart != editor.selectionEnd
+ property bool handleMoved: false
+ property bool longTap: false
+ property int tapCounter: 0
+ property variant pressedHandle: null
+ property variant hitTestPoint: Qt.point(0, 0)
+ property variant touchPoint: Qt.point(0, 0)
+ property variant currentTouchPoint: Qt.point(0, 0)
+
+ function onSingleTap() {
+ if (!internal.handleMoved) {
+ // need to deselect, because if the cursor position doesn't change the selection remains
+ // even after setting to cursorPosition
+ editor.deselect();
+ editor.cursorPosition = editor.positionAt(internal.touchPoint.x, internal.touchPoint.y);
+ touchTools.contextMenu.hide();
+ if (!editor.readOnly)
+ editor.openSoftwareInputPanel()
+ }
+ }
+
+ function onDoubleTap() {
+ // assume that the 1st click positions the cursor
+ editor.selectWord();
+ touchTools.contextMenu.show();
+ }
+
+ function onTripleTap() {
+ editor.selectAll();
+ touchTools.contextMenu.show();
+ }
+
+ function onEditorTextChanged() {
+ if (touchTools && !internal.editorHasSelection)
+ touchTools.contextMenu.hide();
+ }
+
+ function handleGrabbed() {
+ mouseGrabDisabler.setKeepMouseGrab(root, true);
+ internal.hitTestPoint = {x:internal.currentTouchPoint.x, y:internal.currentTouchPoint.y};
+
+ internal.forcedSelection = internal.editorHasSelection;
+ }
+
+ function mapViewPortRectToHandle(handle) {
+ var position = editor.mapToItem(handle, root.editorScrolledX, root.editorScrolledY);
+ var rect = Qt.rect(position.x, position.y, root.width, root.height);
+ return rect;
+ }
+
+ // point is in Editor's coordinate system
+ function handleForPoint(point) {
+ var pressed = null;
+
+ if (!editor.readOnly || editorHasSelection) { // to avoid moving the cursor handle in read only editor
+ // Find out which handle is being moved
+ if (touchTools.handleBegin.visible &&
+ touchTools.handleBegin.containsPoint(editor.mapToItem(touchTools.handleBegin, point.x, point.y))) {
+ pressed = touchTools.handleBegin;
+ }
+ if (touchTools.handleEnd.containsPoint(editor.mapToItem(touchTools.handleEnd, point.x, point.y))) {
+ var useArea = true;
+ if (pressed != null) {
+ var distance1 = touchTools.handleBegin.pointDistanceFromCenter(point);
+ var distance2 = touchTools.handleEnd.pointDistanceFromCenter(point);
+
+ if (distance1 < distance2)
+ useArea = false;
+ }
+ if (useArea)
+ pressed = touchTools.handleEnd;
+ }
+ }
+ return pressed;
+ }
+
+ function selectionVisible() {
+ var startRect = editor.positionToRectangle(editor.selectionStart);
+ var endRect = editor.positionToRectangle(editor.selectionEnd);
+ var selectionRect = Qt.rect(startRect.x, startRect.y, endRect.x - startRect.x + endRect.width, endRect.y - startRect.y + endRect.height);
+ var viewPortRect = Qt.rect(editorScrolledX, editorScrolledY, editor.width, editor.height);
+
+ return Utils.rectIntersectsRect(selectionRect, viewPortRect) ||
+ Utils.rectContainsRect(viewPortRect, selectionRect) ||
+ Utils.rectContainsRect(selectionRect, viewPortRect);
+ }
+ }
+
+ Loader {
+ id: touchToolsLoader
+ }
+
+ Component {
+ id: touchToolsComponent
+
+ Item {
+ id: touchTools
+ property alias handleBegin: selBegin
+ property alias handleEnd: selEnd
+ property alias contextMenu: cxtMenu
+ property alias magnifier: magnif
+
+ TextSelectionHandle {
+ id: selBegin
+
+ objectName: "SelectionBegin"
+ editor: root.editor
+ imageSource: privateStyle.imagePath("qtg_fr_textfield_handle_start", root.platformInverted)
+ editorPos: editor.selectionStart
+ visible: editor.selectionStart != editor.selectionEnd
+ }
+
+ TextSelectionHandle { // also acts as the cursor handle when no selection
+ id: selEnd
+
+ objectName: "SelectionEnd"
+ editor: root.editor
+ imageSource: privateStyle.imagePath("qtg_fr_textfield_handle_end", root.platformInverted)
+ editorPos: editor.selectionEnd
+ visible: true
+ showImage: internal.hasSelection //show image only in selection mode
+ }
+
+ TextContextMenu {
+ id: cxtMenu
+
+ editor: root.editor
+ platformInverted: root.platformInverted
+ copyEnabled: root.copyEnabled
+ cutEnabled: root.cutEnabled
+ }
+
+ TextMagnifier {
+ id: magnif
+
+ editor: root.editor
+ contentCenter: internal.hitTestPoint
+ platformInverted: root.platformInverted
+
+ }
+ }
+
+ }
+
+ MouseGrabDisabler {
+ id: mouseGrabDisabler
+ }
+
+ Timer {
+ id: clickTimer
+
+ interval: 400; repeat: false
+ onTriggered: {
+ running = false;
+ internal.tapCounter = 0;
+ }
+ }
+
+ Connections {
+ target: root.editor
+ onActiveFocusChanged: {
+ // On focus loss dismiss menu, selection and VKB
+ if (!root.editor.activeFocus) {
+ if (touchTools)
+ touchTools.contextMenu.hide()
+ root.editor.select(root.editor.cursorPosition, root.editor.cursorPosition)
+ root.editor.closeSoftwareInputPanel()
+ }
+ }
+ }
+
+ Keys.onPressed: {
+ if (!touchTools)
+ touchToolsLoader.sourceComponent = touchToolsComponent
+
+ if (internal.editorHasSelection && event.modifiers & Qt.ShiftModifier
+ && (event.key == Qt.Key_Left || event.key == Qt.Key_Right
+ || event.key == Qt.Key_Up || event.key == Qt.Key_Down))
+ touchTools.contextMenu.show()
+ }
+}
--- /dev/null
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the Qt Components project.
+**
+** $QT_BEGIN_LICENSE:BSD$
+** You may use this file under the terms of the BSD license as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions and the following disclaimer in
+** the documentation and/or other materials provided with the
+** distribution.
+** * Neither the name of Nokia Corporation and its Subsidiary(-ies) nor
+** the names of its contributors may be used to endorse or promote
+** products derived from this software without specific prior written
+** permission.
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick 1.1
+import "." 1.1
+
+Item {
+ id: root
+
+ property Item tools: null
+
+ // The transition type. One of the following:
+ // set an instantaneous change (default)
+ // push follows page stack push animation
+ // pop follows page stack pop animation
+ // replace follows page stack replace animation
+ property string transition: "set"
+
+ // Symbian specific API
+ property bool platformInverted: false
+
+ // Sets the tools with a transition.
+ function setTools(tools, transition) {
+ stateGroup.state = tools ? "" : "Hidden"
+ if (tools)
+ tools.height = root.height
+ priv.transition = transition
+ root.tools = tools
+ }
+
+ LayoutMirroring.enabled: false
+ LayoutMirroring.childrenInherit: true
+
+ implicitWidth: Math.max(50, screen.width)
+ implicitHeight: (screen.width < screen.height)
+ ? privateStyle.toolBarHeightPortrait
+ : privateStyle.toolBarHeightLandscape
+
+ BorderImage {
+ id: background
+ anchors.fill: parent
+ source: privateStyle.imagePath("qtg_fr_toolbar", root.platformInverted)
+ border { left: 20; top: 20; right: 20; bottom: 20 }
+ }
+
+ //Prevents mouse events from propagating to elements below the ToolBar
+ MouseArea {
+ anchors.fill: parent
+ }
+
+ Item {
+ id: container
+ anchors.fill: parent
+ }
+
+ onToolsChanged: {
+ priv.performTransition(priv.transition || transition)
+ priv.transition = undefined
+ }
+
+ Component {
+ id: containerComponent
+
+ Item {
+ id: item
+
+ anchors.fill: parent
+
+ // The states correspond to the different possible positions of the item.
+ state: "Hidden"
+
+ // The tools held by this item.
+ property Item tools: null
+ // The owner of the tools.
+ property Item owner: null
+
+ states: [
+
+ // Active state
+ State {
+ name: ""
+ PropertyChanges { target: item; visible: true; opacity: 1 }
+ },
+
+ // Start state for pop entry, end state for push exit.
+ State {
+ name: "Prev"
+ PropertyChanges { target: item; opacity: 0.0 }
+ },
+ // Start state for push entry, end state for pop exit.
+ State {
+ name: "Next"
+ PropertyChanges { target: item; opacity: 0.0 }
+ },
+ // Start state for replace entry.
+ State {
+ name: "Front"
+ PropertyChanges { target: item; opacity: 0.0 }
+ },
+ // End state for replace exit.
+ State {
+ name: "Back"
+ PropertyChanges { target: item; opacity: 0.0 }
+ },
+ // Inactive state.
+ State {
+ name: "Hidden"
+ PropertyChanges { target: item; visible: false }
+ StateChangeScript {
+ script: {
+ if (item.tools) {
+ // re-parent back to original owner
+ tools.visible = false
+ tools.parent = owner
+
+ // reset item
+ item.tools = item.owner = null
+ }
+ }
+ }
+ }
+ ]
+
+ transitions: [
+ // Pop entry and push exit transition.
+ Transition {
+ from: ""; to: "Prev"; reversible: true
+ SequentialAnimation {
+ PropertyAnimation { properties: "opacity"; easing.type: Easing.InCubic; duration: priv.transitionDuration / 2 }
+ PauseAnimation { duration: priv.transitionDuration / 2 }
+ ScriptAction { script: if (state == "Prev") state = "Hidden" }
+ }
+ },
+ // Push entry and pop exit transition.
+ Transition {
+ from: ""; to: "Next"; reversible: true
+ SequentialAnimation {
+ PropertyAnimation { properties: "opacity"; easing.type: Easing.InCubic; duration: priv.transitionDuration / 2 }
+ PauseAnimation { duration: priv.transitionDuration / 2 }
+ ScriptAction { script: if (state == "Next") state = "Hidden" }
+ }
+ },
+ Transition {
+ // Replace entry transition.
+ from: "Front"; to: ""
+ SequentialAnimation {
+ PropertyAnimation { properties: "opacity"; easing.type: Easing.InOutExpo; duration: priv.transitionDuration }
+ }
+ },
+ Transition {
+ // Replace exit transition.
+ from: ""; to: "Back"
+ SequentialAnimation {
+ PropertyAnimation { properties: "opacity"; easing.type: Easing.InOutExpo; duration: priv.transitionDuration }
+ ScriptAction { script: if (state == "Back") state = "Hidden" }
+ }
+ }
+ ]
+ }
+ }
+
+ QtObject {
+ id: priv
+
+ property Item currentComponent: null
+
+ // Alternating components used for transitions.
+ property Item compA: null
+ property Item compB: null
+
+ // The transition to perform next.
+ property variant transition
+
+ // Duration of transition animation (in ms)
+ property int transitionDuration: 500
+
+ // Performs a transition between tools in the toolbar.
+ function performTransition(transition) {
+ // lazily create components if they have not been created
+ if (!priv.currentComponent) {
+ priv.compA = containerComponent.createObject(container)
+ priv.compB = containerComponent.createObject(container)
+ priv.currentComponent = priv.compB
+ }
+
+ // no transition if the tools are unchanged
+ if (priv.currentComponent.tools == tools)
+ return
+
+ // select component states based on the transition animation
+ var transitions = {
+ "set": { "new": "", "old": "Hidden" },
+ "push": { "new": "Next", "old": "Prev" },
+ "pop": { "new": "Prev", "old": "Next" },
+ "replace": { "new": "Front", "old": "Back" }
+ }
+
+ var animation = transitions[transition]
+ // initialize the free component
+ var component = priv.currentComponent == priv.compA ? priv.compB : priv.compA
+ component.state = "Hidden"
+ if (tools) {
+ component.tools = tools
+ component.owner = tools.parent
+ tools.parent = component
+ tools.visible = true
+ if (tools.layoutChildren != undefined && typeof tools.layoutChildren == 'function' )
+ tools.layoutChildren()
+ }
+
+ // perform transition
+ priv.currentComponent.state = animation["old"]
+ if (tools) {
+ component.state = animation["new"]
+ component.state = ""
+ }
+ priv.currentComponent = component
+ }
+ }
+
+ StateGroup {
+ id: stateGroup
+ states: [
+ // Inactive state.
+ State {
+ name: "Hidden"
+ PropertyChanges { target: root; height: 0; opacity: 0.0 }
+ }
+ ]
+
+ transitions: [
+ // Transition between active and inactive states.
+ Transition {
+ from: ""; to: "Hidden"; reversible: true
+ SequentialAnimation {
+ PropertyAnimation { properties: "opacity"; easing.type: Easing.InOutExpo; duration: priv.transitionDuration }
+ PropertyAnimation { properties: "height"; duration: 10 }
+ }
+ }
+ ]
+ }
+}
--- /dev/null
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the Qt Components project.
+**
+** $QT_BEGIN_LICENSE:BSD$
+** You may use this file under the terms of the BSD license as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions and the following disclaimer in
+** the documentation and/or other materials provided with the
+** distribution.
+** * Neither the name of Nokia Corporation and its Subsidiary(-ies) nor
+** the names of its contributors may be used to endorse or promote
+** products derived from this software without specific prior written
+** permission.
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+// ToolBarLayout is a container for items on a toolbar that automatically
+// implements an appropriate layout for its children.
+
+import QtQuick 1.1
+import "." 1.1
+
+Item {
+ id: root
+
+ property bool backButton: true // deprecated
+ onBackButtonChanged: { console.log("warning: ToolBarLayout.backButton is deprecated.") }
+
+ implicitWidth: screen.width
+ implicitHeight: internal.defaultHeightToolBar
+
+ visible: false
+
+ Connections {
+ target: privateStyle
+ onLayoutParametersChanged: internal.layoutChildren()
+ }
+ Connections {
+ target: screen
+ onCurrentOrientationChanged: internal.layoutChildren()
+ }
+
+ QtObject {
+ id: internal
+ objectName: "internal"
+
+ property bool portrait: screen.width < screen.height
+
+ // These are the dynamic layout parameters used by the toolbar layout.
+ property real defaultHeightToolBar: portrait ?
+ privateStyle.toolBarHeightPortrait : privateStyle.toolBarHeightLandscape
+ property real defaultHeightToolButton: privateStyle.toolBarHeightLandscape
+ property real outerMarginHorizontal: portrait ?
+ 0 : (2 * platformStyle.paddingLarge)
+ property real outerMarginButtonRowLong: portrait ?
+ platformStyle.paddingLarge : (3 * platformStyle.paddingLarge)
+ property real innerSpacingTextButtonSingle: portrait ?
+ platformStyle.paddingMedium + (3 * platformStyle.paddingLarge) : (3 * platformStyle.paddingLarge)
+ property real innerSpacingTextButtonDouble: portrait ?
+ platformStyle.paddingSmall : (3 * platformStyle.paddingLarge)
+ property real innerSpacingButtonRowTwoChildren: portrait ?
+ platformStyle.paddingMedium : (3 * platformStyle.paddingLarge)
+ property real innerSpacingButtonRowLong: portrait ?
+ platformStyle.paddingMedium : platformStyle.paddingLarge
+ property real centerSpacingTextButtonDouble: platformStyle.paddingLarge
+
+ function isIconButton(item) {
+ return item.hasOwnProperty("iconSource")
+ && item.hasOwnProperty("text")
+ && item.text == ""
+ }
+
+ function isTextToolButton(item) {
+ // ToolButton has both iconSource and flat property,
+ // Button only has iconSource
+ return (item.hasOwnProperty("iconSource")
+ && item.iconSource == ""
+ && item.hasOwnProperty("flat"))
+ }
+
+ function isButtonRow(item) {
+ return item.hasOwnProperty("checkedButton")
+ }
+
+ function buttonWidth(child) {
+ if ((isTextToolButton(child)) || !(child.hasOwnProperty("implicitWidth"))) {
+ // ImplicitWidth for the ToolButton returns wrong value right after
+ // orientation change, and also we want to override its own
+ // layout width calculation, so use the actual width
+ return child.width
+ }
+ return child.implicitWidth
+ }
+
+ function centerOffset(outerLength, innerLength) {
+ // calculate the offset of the leading edge of a centered child item
+ return Math.floor((outerLength - innerLength) / 2.0)
+ }
+
+ function widthTextButtonSingle(leftMargin, innerSpacing) {
+ // calculate the remaining width for a centered item
+ var outerContents = leftMargin + innerSpacing
+ return root.width - (outerContents * 2)
+ }
+
+ function widthTextButtonDouble(leftMargin, innerSpacing, centerSpacing) {
+ // calculate the space available when there are two items with a center
+ // margin, and share it between the two
+ var outerContents = leftMargin + innerSpacing
+ return Math.round((root.width - (outerContents * 2) - centerSpacing) / 2.0)
+ }
+
+ function widthButtonRowLong(leftButton, rightButton, itemMargin, innerSpacing, outerMargin) {
+ // calculate the width of a long button row, which is used in the case that there are more
+ // than three icons. If either left or right button is present, allocate the itemMargin to
+ // ensure that there is sufficient space; otherwise we can use the special
+ // outerMargin value
+ var leftContents = leftButton ? itemMargin + innerSpacing : outerMargin
+ var rightContents = rightButton ? itemMargin + innerSpacing : outerMargin
+ return root.width - leftContents - rightContents
+ }
+
+ function layoutChildren() {
+ var numChildren = children.length
+ if (parent == null || root.width == 0 || numChildren == 0)
+ return
+
+ for (var i = 0; i < numChildren; ++i) {
+ // make sure all the children have correct parent, height, and y
+ children[i].parent = root
+ if (isButtonRow(children[i])) {
+ var buttonRow = children[i]
+ // ButtonRow frame height is always tool bar's height in
+ // landscape, regardless of the current orientation, so we need
+ // to override the heights of the buttons within (because it's a
+ // Row, so its height is based on its children)
+ for (var j = 0; j < buttonRow.children.length; ++j) {
+ buttonRow.children[j].implicitHeight = defaultHeightToolButton
+ }
+ }
+ // child's vertical center always goes to middle of the toolbar
+ var childHeight = children[i].hasOwnProperty("implicitHeight") ?
+ children[i].implicitHeight : children[i].height
+ children[i].y = root.y + centerOffset(root.implicitHeight, childHeight)
+ }
+
+ // detect whether we have left and or right items. we need to lay out
+ // the remaining children (that are not left or right items) whether they
+ // are tool buttons, text buttons or a button row
+ var leftItem = isIconButton(children[0]) ?
+ children[0] : undefined
+ var rightItem = isIconButton(children[numChildren-1]) ?
+ children[numChildren-1] : undefined
+ var childrenRemaining = numChildren - (leftItem != undefined ? 1 : 0) - (rightItem != undefined ? 1 : 0)
+ var firstRemainingIndex = leftItem != undefined ? 1 : 0
+ var lastRemainingIndex = rightItem != undefined ? (numChildren - 2) : (numChildren - 1)
+
+ // precalculate the margins for the left and right items, we will work
+ // out child sizes assuming they are present
+ var leftMargin = outerMarginHorizontal + defaultHeightToolBar
+ var rightMargin = root.width - leftMargin
+
+ // In the case of a lone remaining chlld, or in the case of 2 text
+ // buttons, we need to override the width
+ var overrideChildWidth = 0
+ for (var p = firstRemainingIndex; p <= lastRemainingIndex; p++) {
+ var child = children[p]
+ overrideChildWidth = buttonWidth(child)
+
+ // If necessary, we calculate and override the width first before we
+ // can calculate the x positions
+ if ((isTextToolButton(child) && childrenRemaining == 1)
+ || (isButtonRow(child) && child.children.length == 1)) {
+ // we treat a button row with a single item like a single tool button,
+ // but in landscape, calculate size as if there were two buttons
+ overrideChildWidth = portrait ?
+ widthTextButtonSingle(leftMargin, innerSpacingTextButtonSingle) :
+ widthTextButtonDouble(leftMargin, innerSpacingTextButtonDouble, innerSpacingTextButtonDouble)
+
+ } else if (isTextToolButton(child) && childrenRemaining == 2) {
+ // special case of margins for two text buttons
+ overrideChildWidth = widthTextButtonDouble(
+ leftMargin, innerSpacingTextButtonDouble, centerSpacingTextButtonDouble)
+
+ } else if (isButtonRow(child) && ((child.children.length == 2)
+ || (child.children.length > 2 && leftItem != undefined && rightItem != undefined))) {
+ // there are special margins if the button row has two children,
+ // or if it has more than two children and there is a left and
+ // a right item
+ overrideChildWidth = widthTextButtonSingle(
+ leftMargin, innerSpacingButtonRowTwoChildren)
+
+ } else if (isButtonRow(child) && child.children.length > 2) {
+ // the long button row has special margins, which are used on
+ // either side if the side icon button is missing on that side. If the item is present,
+ // the leftMargin can be used on either side to leave space for either icon button
+ overrideChildWidth = widthButtonRowLong(
+ leftItem != undefined,
+ rightItem != undefined,
+ leftMargin,
+ innerSpacingButtonRowLong,
+ outerMarginButtonRowLong)
+ }
+
+ child.width = overrideChildWidth
+ }
+
+ if (numChildren == 1) {
+ var loneChild = children[0]
+ var loneChildWidth = buttonWidth(loneChild)
+ if (isButtonRow(loneChild)) {
+ loneChildWidth = overrideChildWidth
+ }
+ if (isIconButton(loneChild))
+ loneChild.x = outerMarginHorizontal
+ else
+ loneChild.x = centerOffset(root.width, loneChildWidth)
+ return
+ }
+
+ // we can easily calculate the positions of the left and right items,
+ // but if they are missing then correct the margins
+ if (leftItem != undefined){
+ leftItem.x = outerMarginHorizontal
+ } else {
+ leftMargin = 0
+ }
+ if (rightItem != undefined){
+ rightItem.x = root.width - defaultHeightToolBar - outerMarginHorizontal
+ } else {
+ rightMargin = root.width
+ }
+
+ if (!childrenRemaining)
+ return;
+
+ if (childrenRemaining == 1) {
+ var loneChild = children[firstRemainingIndex]
+ var loneChildWidth = buttonWidth(loneChild)
+ if (isButtonRow(loneChild)) {
+ // ButtonRow should have the override width (but it won't have
+ // been updated yet)
+ loneChildWidth = overrideChildWidth
+ }
+ // lone child is always centered, unless it's a long button row on
+ // one side only
+ if (isButtonRow(loneChild) && loneChild.children.length >= 3
+ && ((leftItem == undefined) != (rightItem == undefined))) {
+ loneChild.x = (leftItem != undefined) ?
+ (leftMargin + innerSpacingButtonRowLong) : outerMarginButtonRowLong
+ } else {
+ loneChild.x = centerOffset(root.width, loneChildWidth)
+ }
+ } else if (childrenRemaining == 2 && isTextToolButton(children[firstRemainingIndex])) {
+ // text buttons are distributed around the center with a center spacing
+ var midPoint = Math.floor(root.width / 2.0)
+ var halfSpacing = Math.round(platformStyle.paddingLarge / 2.0)
+ children[firstRemainingIndex].x = midPoint - halfSpacing - buttonWidth(children[firstRemainingIndex])
+ children[firstRemainingIndex + 1].x = midPoint + halfSpacing
+ } else {
+ // icon buttons are deployed evenly in the remaining space,
+ // but we need to ensure that the spacings are integer values,
+ // and share the rounding error to ensure that they are centered
+ var remainingSpace = rightMargin - leftMargin
+ var spacingNotRounded = remainingSpace
+ for (var p = 0; p < childrenRemaining; p++) {
+ var nextChild = children[leftItem != undefined ? p + 1 : p]
+ spacingNotRounded -= buttonWidth(nextChild)
+ }
+ spacingNotRounded /= (childrenRemaining + 1)
+ var spacing = Math.floor(spacingNotRounded)
+ var totalRoundingError = (spacingNotRounded - spacing) * (childrenRemaining + 1)
+ var curPos = leftMargin + Math.floor(totalRoundingError / 2.0)
+
+ for (var p = 0; p < childrenRemaining; p++) {
+ var nextChild = children[leftItem != undefined ? p + 1 : p]
+ curPos += spacing
+ nextChild.x = curPos
+ curPos += buttonWidth(nextChild)
+ }
+ }
+ }
+ }
+
+ Component.onCompleted: internal.layoutChildren()
+ onParentChanged: internal.layoutChildren()
+ onChildrenChanged: internal.layoutChildren()
+ onImplicitWidthChanged: internal.layoutChildren()
+ onImplicitHeightChanged: internal.layoutChildren()
+}
--- /dev/null
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the Qt Components project.
+**
+** $QT_BEGIN_LICENSE:BSD$
+** You may use this file under the terms of the BSD license as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions and the following disclaimer in
+** the documentation and/or other materials provided with the
+** distribution.
+** * Neither the name of Nokia Corporation and its Subsidiary(-ies) nor
+** the names of its contributors may be used to endorse or promote
+** products derived from this software without specific prior written
+** permission.
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick 1.1
+import Qt.labs.components 1.1
+import "." 1.1
+
+Item {
+ id: root
+
+ // Common API
+ property alias checkable: checkableItem.enabled
+ property alias checked: checkableItem.checked
+ property bool enabled: true // overridden from base class
+ property alias text: label.text
+ property url iconSource
+ property bool flat: (!text && iconSource != "" && parent && !internal.isButtonRow(parent))
+ property bool pressed: mouseArea.containsMouse && (stateGroup.state == "Pressed" || stateGroup.state == "PressAndHold")
+
+ // Platform API
+ property alias platformExclusiveGroup: checkableItem.exclusiveGroup
+ property bool platformInverted: false
+
+ // Common API
+ signal clicked
+
+ // Platform API
+ signal platformReleased
+ signal platformPressAndHold
+
+ onFlatChanged: {
+ background.visible = !flat || (checkableItem.enabled && checkableItem.checked && !internal.isButtonRow(parent))
+ }
+
+ implicitWidth: {
+ if (!text)
+ return internal.iconButtonWidth()
+ else if (iconSource == "")
+ return Math.max(internal.iconButtonWidth(), internal.textButtonWidth())
+ else
+ return internal.iconButtonWidth() + internal.textButtonWidth()
+ }
+ implicitHeight: {
+ if ((iconSource != "") && !text)
+ // if there is just an icon, then it's full button height
+ return internal.iconButtonWidth()
+ else
+ // Otherwise frame height is always tool bar's height in landscape, regardless of the current orientation
+ return privateStyle.toolBarHeightLandscape
+ }
+
+ BorderImage {
+ id: background
+
+ source: privateStyle.imagePath(internal.imageName() + internal.modeName(), root.platformInverted)
+ border {
+ left: internal.isFrameGraphic ? platformStyle.borderSizeMedium : 0;
+ top: internal.isFrameGraphic ? platformStyle.borderSizeMedium : 0;
+ right: internal.isFrameGraphic ? platformStyle.borderSizeMedium : 0;
+ bottom: internal.isFrameGraphic ? platformStyle.borderSizeMedium : 0;
+ }
+ smooth: true
+ anchors.fill: parent
+ visible: !flat
+
+ BorderImage {
+ id: highlight
+ border {
+ left: internal.isFrameGraphic ? platformStyle.borderSizeMedium : 0;
+ top: internal.isFrameGraphic ? platformStyle.borderSizeMedium : 0;
+ right: internal.isFrameGraphic ? platformStyle.borderSizeMedium : 0;
+ bottom: internal.isFrameGraphic ? platformStyle.borderSizeMedium : 0;
+ }
+ smooth: true
+ anchors.fill: background
+ opacity: 0
+ }
+ }
+
+ Image {
+ id: contentIcon
+ source: privateStyle.toolBarIconPath(iconSource, root.platformInverted)
+ visible: iconSource != ""
+ sourceSize.width: platformStyle.graphicSizeSmall
+ sourceSize.height: platformStyle.graphicSizeSmall
+ anchors {
+ centerIn: !text ? parent : undefined
+ verticalCenter: !text ? undefined : parent.verticalCenter
+ left: !text ? undefined : parent.left
+ leftMargin: !text ? 0 : 2 * platformStyle.paddingMedium
+ }
+ smooth: true
+ }
+
+ Text {
+ id: label
+ clip: true
+ horizontalAlignment: Text.AlignHCenter
+ verticalAlignment: Text.AlignVCenter
+ elide: Text.ElideRight
+ font { family: platformStyle.fontFamilyRegular; pixelSize: platformStyle.fontSizeLarge }
+ color: {
+ if (!root.enabled)
+ return root.platformInverted ? platformStyle.colorDisabledLightInverted
+ : platformStyle.colorDisabledLight
+ else if (stateGroup.state == "Pressed" || stateGroup.state == "PressAndHold")
+ return root.platformInverted ? platformStyle.colorPressedInverted
+ : platformStyle.colorPressed
+ else
+ return root.platformInverted ? platformStyle.colorNormalLightInverted
+ : platformStyle.colorNormalLight
+ }
+ visible: text
+ anchors {
+ top: parent.top; bottom: parent.bottom
+ left: iconSource != "" ? contentIcon.right : parent.left; right: parent.right
+ leftMargin: iconSource != "" ? platformStyle.paddingSmall : platformStyle.paddingMedium
+ rightMargin: platformStyle.paddingMedium
+ }
+ smooth: true
+ }
+
+ MouseArea {
+ id: mouseArea
+ anchors.fill: parent
+
+ onPressed: if (root.enabled) stateGroup.state = "Pressed"
+ onReleased: if (root.enabled) stateGroup.state = ""
+ onCanceled: {
+ if (root.enabled) {
+ // Mark as canceled
+ stateGroup.state = "Canceled"
+ // Reset state. Can't expect a release since mouse was ungrabbed
+ stateGroup.state = ""
+ }
+ }
+ onPressAndHold: if (stateGroup.state != "Canceled" && root.enabled) stateGroup.state = "PressAndHold"
+ onExited: if (root.enabled) stateGroup.state = "Canceled"
+ }
+
+ QtObject {
+ id: internal
+
+ property bool isFrameGraphic : imageName().search("_fr") > 0
+
+ function belongsToExclusiveGroup() {
+ return checkableItem.exclusiveGroup
+ || (root.parent
+ && root.parent.hasOwnProperty("checkedButton")
+ && root.parent.exclusive)
+ }
+
+ function modeName() {
+ if (isButtonRow(parent))
+ return parent.privateModeName(root, 1)
+ else if (!enabled)
+ return "disabled"
+ else if (flat && checkableItem.checked && !internal.isButtonRow(parent))
+ return "latched"
+ else
+ return "normal"
+ }
+
+ function iconButtonWidth() {
+ return (screen.width < screen.height) ? privateStyle.toolBarHeightPortrait : privateStyle.toolBarHeightLandscape
+ }
+
+ function textButtonWidth() {
+ return platformStyle.paddingMedium * ((screen.width < screen.height) ? 15 : 25)
+ }
+
+ function press() {
+ if (!belongsToExclusiveGroup()) {
+ if (checkableItem.enabled && checkableItem.checked)
+ privateStyle.play(Android.SensitiveButton)
+ else
+ privateStyle.play(Android.BasicButton)
+ } else if (checkableItem.enabled && !checkableItem.checked) {
+ privateStyle.play(Android.BasicButton)
+ }
+
+ if (flat)
+ background.visible = true
+ highlight.source = privateStyle.imagePath(internal.imageName() + "pressed", root.platformInverted)
+ label.scale = 0.95
+ contentIcon.scale = 0.95
+ highlight.opacity = 1
+ }
+
+ function release() {
+ label.scale = 1
+ contentIcon.scale = 1
+ highlight.opacity = 0
+
+ if (((checkableItem.enabled && checkableItem.checked && !belongsToExclusiveGroup())
+ || !checkableItem.enabled) && stateGroup.state != "Canceled")
+ privateStyle.play(Android.BasicButton)
+
+ if (flat && isButtonRow(parent))
+ visibleEffect.restart() //Background invisible
+ else if (flat && !checkableItem.enabled)
+ visibleEffect.restart() //Background invisible
+ else
+ clickedEffect.restart() //Background stays visible
+
+ root.platformReleased()
+ }
+
+ function click() {
+ checkableItem.toggle()
+ root.clicked()
+ }
+
+ function hold() {
+ root.platformPressAndHold()
+ }
+
+ function isButtonRow(item) {
+ return (item &&
+ item.hasOwnProperty("checkedButton") &&
+ item.hasOwnProperty("privateDirection") &&
+ item.privateDirection == Qt.Horizontal)
+ }
+
+ // The function imageName() handles fetching correct graphics for the ToolButton.
+ // If the parent of a ToolButton is ButtonRow, segmented-style graphics are used to create a
+ // seamless row of buttons. Otherwise normal ToolButton graphics are utilized.
+ function imageName() {
+ var mirror = root.LayoutMirroring.enabled // To create binding
+ if (isButtonRow(parent))
+ return parent.privateGraphicsName(root, 1)
+ else
+ return (!flat || text || iconSource == "") ? "qtg_fr_toolbutton_text_" : "qtg_graf_toolbutton_"
+ }
+ }
+
+ StateGroup {
+ id: stateGroup
+
+ states: [
+ State { name: "Pressed" },
+ State { name: "PressAndHold" },
+ State { name: "Canceled" }
+ ]
+
+ transitions: [
+ Transition {
+ to: "Pressed"
+ ScriptAction { script: internal.press() }
+ },
+ Transition {
+ from: "Pressed"
+ to: "PressAndHold"
+ ScriptAction { script: internal.hold() }
+ },
+ Transition {
+ from: "Pressed"
+ to: ""
+ ScriptAction { script: internal.release() }
+ ScriptAction { script: internal.click() }
+ },
+ Transition {
+ from: "PressAndHold"
+ to: ""
+ ScriptAction { script: internal.release() }
+ ScriptAction { script: internal.click() }
+ },
+ Transition {
+ from: "Pressed"
+ to: "Canceled"
+ ScriptAction { script: internal.release() }
+ },
+ Transition {
+ from: "PressAndHold"
+ to: "Canceled"
+ ScriptAction { script: internal.release() }
+ }
+ ]
+ }
+
+ ParallelAnimation {
+ id: clickedEffect
+ PropertyAnimation {
+ target: label
+ property: "scale"
+ from: 0.95
+ to: 1.0
+ easing.type: Easing.Linear
+ duration: 100
+ }
+ PropertyAnimation {
+ target: contentIcon
+ property: "scale"
+ from: 0.95
+ to: 1.0
+ easing.type: Easing.Linear
+ duration: 100
+ }
+ PropertyAnimation {
+ target: highlight
+ property: "opacity"
+ from: 1
+ to: 0
+ easing.type: Easing.Linear
+ duration: 150
+ }
+ }
+
+ SequentialAnimation {
+ id: visibleEffect
+ ParallelAnimation {
+ PropertyAnimation {
+ target: label
+ property: "scale"
+ from: 0.95
+ to: 1.0
+ easing.type: Easing.Linear
+ duration: 100
+ }
+ PropertyAnimation {
+ target: contentIcon
+ property: "scale"
+ from: 0.95
+ to: 1.0
+ easing.type: Easing.Linear
+ duration: 100
+ }
+ PropertyAnimation {
+ target: highlight
+ property: "opacity"
+ from: 1
+ to: 0
+ easing.type: Easing.Linear
+ duration: 150
+ }
+ }
+ PropertyAction {
+ target: background
+ property: "visible"
+ value: false
+ }
+ }
+
+ Checkable {
+ id: checkableItem
+ value: root.text
+ }
+}
--- /dev/null
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the Qt Components project.
+**
+** $QT_BEGIN_LICENSE:BSD$
+** You may use this file under the terms of the BSD license as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions and the following disclaimer in
+** the documentation and/or other materials provided with the
+** distribution.
+** * Neither the name of Nokia Corporation and its Subsidiary(-ies) nor
+** the names of its contributors may be used to endorse or promote
+** products derived from this software without specific prior written
+** permission.
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+import QtQuick 1.1
+import "." 1.1
+import "AppManager.js" as AppView
+
+Item {
+ id: root
+
+ // Public API
+ property alias font: label.font
+ property alias text: label.text
+ property variant target: null
+ property bool platformInverted: false
+
+ implicitWidth: Math.min(privy.maxWidth, (privateStyle.textWidth(text, font) + privy.hMargin * 2))
+ implicitHeight: privateStyle.fontHeight(font) + privy.vMargin * 2
+ opacity: 0
+
+ function show() {
+ opacity = 1
+ visible = true
+ }
+
+ function hide() {
+ opacity = 0
+ }
+
+ Behavior on opacity {
+ PropertyAnimation { duration: 100 }
+ }
+
+ Component.onCompleted: {
+ if (visible)
+ show()
+ }
+
+ onOpacityChanged: {
+ if (opacity == 0)
+ visible = false
+ else
+ visible = true
+ }
+
+ onVisibleChanged: {
+ if (visible) {
+ root.parent = AppView.rootObject()
+ privy.calculatePosition()
+ opacity = 1
+ privy.targetSceneXChanged.connect(privy.targetMoved)
+ privy.targetSceneYChanged.connect(privy.targetMoved)
+ } else {
+ privy.targetSceneXChanged.disconnect(privy.targetMoved)
+ privy.targetSceneYChanged.disconnect(privy.targetMoved)
+ }
+ }
+
+ Binding { target: privy; property: "targetSceneX"; value: AppView.sceneX(root.target); when: root.visible && (root.target != null) }
+ Binding { target: privy; property: "targetSceneY"; value: AppView.sceneY(root.target); when: root.visible && (root.target != null) }
+
+ QtObject {
+ id: privy
+
+ property real hMargin: platformStyle.paddingMedium * 2
+ property real vMargin: platformStyle.paddingMedium
+ property real spacing: platformStyle.paddingLarge
+ property real maxWidth: screen.width - spacing * 2
+ property real targetSceneX
+ property real targetSceneY
+
+ function targetMoved() {
+ if (root.opacity == 1)
+ hide()
+ }
+
+ function calculatePosition() {
+ if (!target)
+ return
+
+ // Determine and set the main position for the ToolTip, order: top, right, left, bottom
+ var targetPos = root.parent.mapFromItem(target, 0, 0)
+
+ // Top
+ if (targetPos.y >= (root.height + privy.vMargin + privy.spacing)) {
+ root.x = targetPos.x + (target.width / 2) - (root.width / 2)
+ root.y = targetPos.y - root.height - privy.vMargin
+
+ // Right
+ } else if (targetPos.x <= (screen.width - target.width - privy.hMargin - root.width - privy.spacing)) {
+ root.x = targetPos.x + target.width + privy.hMargin;
+ root.y = targetPos.y + (target.height / 2) - (root.height / 2)
+
+ // Left
+ } else if (targetPos.x >= (root.width + privy.hMargin + privy.spacing)) {
+ root.x = targetPos.x - root.width - privy.hMargin
+ root.y = targetPos.y + (target.height / 2) - (root.height / 2)
+
+ // Bottom
+ } else {
+ root.x = targetPos.x + (target.width / 2) - (root.width / 2)
+ root.y = targetPos.y + target.height + privy.vMargin
+ }
+
+ // Fine-tune the ToolTip position based on the screen borders
+ if (root.x > (screen.width - privy.spacing - root.width))
+ root.x = screen.width - root.width - privy.spacing
+
+ if (root.x < privy.spacing)
+ root.x = privy.spacing;
+
+ if (root.y > (screen.height - root.height - privy.spacing))
+ root.y = screen.height - root.height - privy.spacing
+
+ if (root.y < privy.spacing)
+ root.y = privy.spacing
+ }
+ }
+
+ BorderImage {
+ id: frame
+ anchors.fill: parent
+ source: privateStyle.imagePath("qtg_fr_tooltip", root.platformInverted)
+ border { left: 20; top: 20; right: 20; bottom: 20 }
+ }
+
+ Text {
+ id: label
+ clip: true
+ color: root.platformInverted ? platformStyle.colorNormalLightInverted
+ : platformStyle.colorNormalLight
+ elide: Text.ElideRight
+ font { family: platformStyle.fontFamilyRegular; pixelSize: platformStyle.fontSizeMedium }
+ verticalAlignment: Text.AlignVCenter
+ horizontalAlignment: Text.AlignHCenter
+ anchors {
+ fill: parent
+ leftMargin: privy.hMargin
+ rightMargin: privy.hMargin
+ topMargin: privy.vMargin
+ bottomMargin: privy.vMargin
+ }
+ }
+}
--- /dev/null
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the Qt Components project.
+**
+** $QT_BEGIN_LICENSE:BSD$
+** You may use this file under the terms of the BSD license as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions and the following disclaimer in
+** the documentation and/or other materials provided with the
+** distribution.
+** * Neither the name of Nokia Corporation and its Subsidiary(-ies) nor
+** the names of its contributors may be used to endorse or promote
+** products derived from this software without specific prior written
+** permission.
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick 1.1
+import "." 1.1
+
+Item {
+ id: root
+
+ property bool inPortrait: height > width
+
+ signal orientationChangeAboutToStart
+ signal orientationChangeStarted
+ signal orientationChangeFinished
+
+ // Symbian specific API
+ property bool platformInverted: false
+
+ width: screen.width > 0 ? screen.width : screen.displayWidth
+ height: screen.height > 0 ? screen.height : screen.displayHeight
+
+ Rectangle {
+ anchors.fill: parent
+ color: platformInverted ? platformStyle.colorBackgroundInverted
+ : platformStyle.colorBackground
+ }
+
+ Binding { target: root; property: "height"; value: screen.height; when: screen.height > 0 }
+ Binding { target: root; property: "width"; value: screen.width; when: screen.width > 0 }
+
+ Connections {
+ target: screen
+ onCurrentOrientationChanged: root.orientationChangeFinished()
+ onPrivateAboutToChangeOrientation: {
+ root.orientationChangeAboutToStart()
+ root.orientationChangeStarted()
+ }
+ }
+}
--- /dev/null
+plugin androidplugin_1_1
+ApplicationWindow 1.1 ApplicationWindow.qml
+BusyIndicator 1.1 BusyIndicator.qml
+Button 1.1 Button.qml
+ButtonColumn 1.1 ButtonColumn.qml
+ButtonRow 1.1 ButtonRow.qml
+CheckBox 1.1 CheckBox.qml
+CommonDialog 1.1 CommonDialog.qml
+ContextMenu 1.1 ContextMenu.qml
+Dialog 1.1 Dialog.qml
+Label 1.1 Label.qml
+ListHeading 1.1 ListHeading.qml
+ListItem 1.1 ListItem.qml
+ListItemText 1.1 ListItemText.qml
+Menu 1.1 Menu.qml
+MenuItem 1.1 MenuItem.qml
+MenuLayout 1.1 MenuLayout.qml
+Page 1.1 Page.qml
+PageStack 1.1 PageStack.qml
+PageStackWindow 1.1 PageStackWindow.qml
+ProgressBar 1.1 ProgressBar.qml
+QueryDialog 1.1 QueryDialog.qml
+RadioButton 1.1 RadioButton.qml
+ScrollBar 1.1 ScrollBar.qml
+ScrollDecorator 1.1 ScrollDecorator.qml
+SectionScroller 1.1 SectionScroller.qml
+SelectionDialog 1.1 SelectionDialog.qml
+SelectionListItem 1.1 SelectionListItem.qml
+Slider 1.1 Slider.qml
+StatusBar 1.1 StatusBar.qml
+Switch 1.1 Switch.qml
+TabBar 1.1 TabBar.qml
+TabBarLayout 1.1 TabBarLayout.qml
+TabButton 1.1 TabButton.qml
+TabGroup 1.1 TabGroup.qml
+TextArea 1.1 TextArea.qml
+TextField 1.1 TextField.qml
+ToolBar 1.1 ToolBar.qml
+ToolBarLayout 1.1 ToolBarLayout.qml
+ToolButton 1.1 ToolButton.qml
+ToolTip 1.1 ToolTip.qml
+Window 1.1 Window.qml