Skip to content
DropButton.qml 8.83 KiB
Newer Older
Don Gagne's avatar
Don Gagne committed
import QtQuick                  2.2
import QtQuick.Controls         1.2
import QtQuick.Controls.Styles  1.2

import QGroundControl.ScreenTools   1.0
import QGroundControl.Palette       1.0

Item {
    id: _root

    property alias  buttonImage:        button.source
    property real   radius:             (ScreenTools.defaultFontPixelHeight * 3) / 2
Don Gagne's avatar
Don Gagne committed
    property int    dropDirection:      dropDown
    property alias  dropDownComponent:  dropDownLoader.sourceComponent
    property real   viewportMargins:    0

    width:  radius * 2
    height: radius * 2

    // Should be an enum but that get's into the whole problem of creating a singleton which isn't worth the effort
    readonly property int dropLeft:     1
    readonly property int dropRight:    2
    readonly property int dropUp:       3
    readonly property int dropDown:     4

    function hideDropDown() {
        _showDropDown = false
    }

    readonly property real _arrowBaseWidth:     (radius * 2) / 2    // Width of long side of arrow
    readonly property real _arrowPointHeight:   (radius * 2) / 3    // Height is long side to point
    readonly property real _dropCornerRadius:   ScreenTools.defaultFontPixelWidth / 2
    readonly property real _dropCornerRadiusX2: _dropCornerRadius * 2
    readonly property real _dropMargin:         _dropCornerRadius
    readonly property real _dropMarginX2:       _dropMargin * 2

    property real   _viewportMaxLeft:   -x + viewportMargins
    property real   _viewportMaxRight:  parent.width - (viewportMargins * 2) - x
    property real   _viewportMaxTop:    -y + viewportMargins
    property real   _viewportMaxBottom: parent.height - (viewportMargins * 2) - y

    property bool _showDropDown: false

    Component.onCompleted: _calcPositions()

    function _calcPositions() {
        var dropComponentWidth = dropDownLoader.item.width
        var dropComponentHeight = dropDownLoader.item.height
        var dropRectWidth = dropComponentWidth + _dropMarginX2
        var dropRectHeight = dropComponentHeight + _dropMarginX2

        dropItemHolderRect.width = dropRectWidth
        dropItemHolderRect.height = dropRectHeight

        dropDownItem.width = dropComponentWidth + _dropMarginX2
        dropDownItem.height = dropComponentHeight + _dropMarginX2

        if (dropDirection == dropUp || dropDirection == dropDown) {
            dropDownItem.height += _arrowPointHeight

            dropDownItem.x = -(dropDownItem.width / 2) + radius

            dropItemHolderRect.x = 0

            if (dropDirection == dropUp) {
                dropDownItem.y = -(dropDownItem.height + _dropMargin)

                dropItemHolderRect.y = 0
            } else {
                dropDownItem.y = button.height + _dropMargin

                dropItemHolderRect.y = _arrowPointHeight
            }

            // Validate that dropdown is within viewport
            dropDownItem.x = Math.max(dropDownItem.x, _viewportMaxLeft)
            dropDownItem.x = Math.min(dropDownItem.x + dropDownItem.width, _viewportMaxRight) - dropDownItem.width

            // Arrow points
            arrowCanvas.arrowPoint.x = (button.x + radius) - dropDownItem.x
            if (dropDirection == dropUp) {
                arrowCanvas.arrowPoint.y = dropDownItem.height
                arrowCanvas.arrowBase1.x = arrowCanvas.arrowPoint.x - (_arrowBaseWidth / 2)
                arrowCanvas.arrowBase1.y = arrowCanvas.arrowPoint.y - _arrowPointHeight
                arrowCanvas.arrowBase2.x = arrowCanvas.arrowBase1.x + _arrowBaseWidth
                arrowCanvas.arrowBase2.y = arrowCanvas.arrowBase1.y
            } else {
                arrowCanvas.arrowPoint.y = 0
                arrowCanvas.arrowBase1.x = arrowCanvas.arrowPoint.x + (_arrowBaseWidth / 2)
                arrowCanvas.arrowBase1.y = _arrowPointHeight
                arrowCanvas.arrowBase2.x = arrowCanvas.arrowBase1.x - _arrowBaseWidth
                arrowCanvas.arrowBase2.y = arrowCanvas.arrowBase1.y
            }
        } else {
            dropDownItem.width += _arrowPointHeight

            dropDownItem.y = -(dropDownItem.height / 2) + radius

            dropItemHolderRect.y = 0

            if (dropDirection == dropLeft) {
                dropDownItem.x = dropDownItem.width + _dropMargin

                dropItemHolderRect.x = 0
            } else {
                dropDownItem.x = button.width + _dropMargin

                dropItemHolderRect.x = _arrowPointHeight
            }

            // Validate that dropdown is within viewport
            dropDownItem.y = Math.max(dropDownItem.y, _viewportMaxTop)
            dropDownItem.y = Math.min(dropDownItem.y + dropDownItem.height, _viewportMaxBottom) - dropDownItem.height

            // Arrow points
            arrowCanvas.arrowPoint.y = (button.y + radius) - dropDownItem.y
            if (dropDirection == dropLeft) {
                arrowCanvas.arrowPoint.x = dropDownItem.width
                arrowCanvas.arrowBase1.x = arrowCanvas.arrowPoint.x - _arrowPointHeight
                arrowCanvas.arrowBase1.y = arrowCanvas.arrowPoint.y - (_arrowBaseWidth / 2)
                arrowCanvas.arrowBase2.x = arrowCanvas.arrowBase1.x
                arrowCanvas.arrowBase2.y = arrowCanvas.arrowBase1.y + _arrowBaseWidth
            } else {
                arrowCanvas.arrowPoint.x = 0
                arrowCanvas.arrowBase1.x = _arrowPointHeight
                arrowCanvas.arrowBase1.y = arrowCanvas.arrowPoint.y - (_arrowBaseWidth / 2)
                arrowCanvas.arrowBase2.x = arrowCanvas.arrowBase1.x
                arrowCanvas.arrowBase2.y = arrowCanvas.arrowBase1.y + _arrowBaseWidth
            }
        }
        arrowCanvas.requestPaint()
    } // function - _calcPositions

    QGCPalette { id: qgcPal }

    MouseArea {
        x:          _viewportMaxLeft
        y:          _viewportMaxTop
        width:      _viewportMaxRight -_viewportMaxLeft
        height:     _viewportMaxBottom - _viewportMaxTop
        visible:    _showDropDown

        onClicked: _showDropDown = false
    }

    // Button
Don Gagne's avatar
Don Gagne committed
        id:             button
        anchors.fill:   parent
        fillMode:       Image.PreserveAspectFit
Don Gagne's avatar
Don Gagne committed
        opacity:        _showDropDown ? 1.0 : 0.75

        MouseArea {
            anchors.fill: parent

            onClicked: _showDropDown = !_showDropDown
        }
    } // Image - button
Don Gagne's avatar
Don Gagne committed

    Item {
        id:         dropDownItem
        visible:    _showDropDown

        QGCCanvas {
Don Gagne's avatar
Don Gagne committed
            id:             arrowCanvas
            anchors.fill:   parent

            property var arrowPoint: Qt.point(0, 0)
            property var arrowBase1: Qt.point(0, 0)
            property var arrowBase2: Qt.point(0, 0)

            onPaint: {
                var context = getContext("2d")
                context.reset()
                context.beginPath()

                context.moveTo(dropItemHolderRect.x, dropItemHolderRect.y)
                if (dropDirection == dropDown) {
                    context.lineTo(arrowBase2.x, arrowBase2.y)
                    context.lineTo(arrowPoint.x, arrowPoint.y)
                    context.lineTo(arrowBase1.x, arrowBase1.y)
                }
                context.lineTo(dropItemHolderRect.x + dropItemHolderRect.width, dropItemHolderRect.y)
                if (dropDirection == dropLeft) {
                    context.lineTo(arrowBase2.x, arrowBase2.y)
                    context.lineTo(arrowPoint.x, arrowPoint.y)
                    context.lineTo(arrowBase1.x, arrowBase1.y)
                }
                context.lineTo(dropItemHolderRect.x + dropItemHolderRect.width, dropItemHolderRect.y + dropItemHolderRect.height)
                if (dropDirection == dropUp) {
                    context.lineTo(arrowBase2.x, arrowBase2.y)
                    context.lineTo(arrowPoint.x, arrowPoint.y)
                    context.lineTo(arrowBase1.x, arrowBase1.y)
                }
                context.lineTo(dropItemHolderRect.x, dropItemHolderRect.y + dropItemHolderRect.height)
                if (dropDirection == dropRight) {
                    context.lineTo(arrowBase2.x, arrowBase2.y)
                    context.lineTo(arrowPoint.x, arrowPoint.y)
                    context.lineTo(arrowBase1.x, arrowBase1.y)
                }
                context.lineTo(dropItemHolderRect.x, dropItemHolderRect.y)

                context.closePath()
                context.fillStyle = qgcPal.button
                context.fill()
            }
        } // Canvas - arrowCanvas

        Item {
            id:     dropItemHolderRect
            //color:  qgcPal.button
            //radius: _dropCornerRadius

            Loader {
                id: dropDownLoader
                x:  _dropMargin
                y:  _dropMargin

                Connections {
                    target: dropDownLoader.item

                    onWidthChanged: _calcPositions()
                    onHeightChanged: _calcPositions()
                }
Don Gagne's avatar
Don Gagne committed
            }
        }
    } // Item - dropDownItem
}