import QtQuick 2.7 import QtQuick.Controls 1.4 import QtQuick.Controls.Styles 1.4 import QGroundControl 1.0 import QGroundControl.ScreenTools 1.0 import QGroundControl.Palette 1.0 Item { id: _root z: QGroundControl.zOrderWidgets signal clicked() property alias buttonImage: roundButton.buttonImage property alias rotateImage: roundButton.rotateImage property real radius: ScreenTools.isMobile ? ScreenTools.defaultFontPixelHeight * 1.75 : ScreenTools.defaultFontPixelHeight * 1.25 property int dropDirection: dropDown property alias dropDownComponent: dropDownLoader.sourceComponent property real viewportMargins: 0 property real topMargin: parent.height - ScreenTools.availableHeight property alias lightBorders: roundButton.lightBorders 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 readonly property real _arrowBaseWidth: radius // Width of long side of arrow readonly property real _arrowPointHeight: radius * 0.666 // Height is long side to point readonly property real _dropCornerRadius: ScreenTools.defaultFontPixelWidth * 0.5 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 + topMargin property real _viewportMaxBottom: parent.height - (viewportMargins * 2) - y // Set up ExclusiveGroup support. We use the checked property to drive visibility of drop down. property alias checked: roundButton.checked property ExclusiveGroup exclusiveGroup: null onExclusiveGroupChanged: { if (exclusiveGroup) { exclusiveGroup.bindCheckable(_root) } } function hideDropDown() { checked = false } 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 = roundButton.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 = (roundButton.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 = roundButton.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 = (roundButton.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: checked onClicked: { checked = false _root.clicked() } } RoundButton { id: roundButton radius: parent.width / 2 onClicked: { _calcPositions() _root.clicked() } } Item { id: dropDownItem visible: checked Canvas { 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.windowShade context.fill() } } // Canvas - arrowCanvas Item { id: dropItemHolderRect Loader { id: dropDownLoader x: _dropMargin y: _dropMargin } } } // Item - dropDownItem }