added android components
[mardrone] / mardrone / imports / com / nokia / android.1.1 / ToolBarLayout.qml
diff --git a/mardrone/imports/com/nokia/android.1.1/ToolBarLayout.qml b/mardrone/imports/com/nokia/android.1.1/ToolBarLayout.qml
new file mode 100644 (file)
index 0000000..49dfa0d
--- /dev/null
@@ -0,0 +1,314 @@
+/****************************************************************************
+**
+** 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()
+}