linphone-desktop/tests/ui/modules/Linphone/Paned.qml
2016-10-06 13:37:11 +02:00

256 lines
6.4 KiB
QML

import QtQuick 2.7
import Linphone.Styles 1.0
import Utils 1.0
// ===================================================================
//
// Paned is one container divided in two areas.
// The division between the areas can be modified with a handle.
//
// Each area can have a fixed or dynamic minimum width.
// See `minimumLeftLimit` and `minimumRightLimit` attributes.
//
// To create a dynamic minimum width, it's necessary to give
// a percentage to `minmimumLeftLimit` or `minimumRightLimit` like:
// `minimumLeftLimit: '66%'`.
// The percentage is relative to the container width.
//
// ===================================================================
Item {
id: container
property alias childA: contentA.data
property alias childB: contentB.data
property int closingEdge: Qt.LeftEdge
// User limits: string or int values.
// By default: no limits.
property var maximumLeftLimit
property var maximumRightLimit
property var minimumLeftLimit: 0
property var minimumRightLimit: 0
property bool _isClosed
property int _savedContentAWidth
// Internal limits.
property var _maximumLeftLimit
property var _maximumRightLimit
property var _minimumLeftLimit
property var _minimumRightLimit
function _getLimitValue (limit) {
if (limit == null) {
return
}
return limit.isDynamic
? width * limit.value
: limit.value
}
function _parseLimit (limit) {
if (limit == null) {
return
}
if (Utils.isString(limit)) {
var arr = limit.split('%')
if (arr[1] === '') {
return {
isDynamic: true,
value: +arr[0] / 100
}
}
}
return {
value: limit
}
}
function _applyLimits () {
var maximumLeftLimit = _getLimitValue(_maximumLeftLimit)
var maximumRightLimit = _getLimitValue(_maximumRightLimit)
var minimumLeftLimit = _getLimitValue(_minimumLeftLimit)
var minimumRightLimit = _getLimitValue(_minimumRightLimit)
var theoreticalBWidth = container.width - contentA.width - handle.width
// If closed, set correctly the handle position to left or right.
if (_isClosed) {
contentA.width = (closingEdge === Qt.RightEdge)
? container.width - handle.width
: 0
}
// width(A) < minimum width(A).
else if (contentA.width < minimumLeftLimit) {
contentA.width = minimumLeftLimit
}
// width(A) > maximum width(A).
else if (maximumLeftLimit != null && contentA.width > maximumLeftLimit) {
contentA.width = maximumLeftLimit
}
// width(B) < minimum width(B).
else if (theoreticalBWidth < minimumRightLimit) {
contentA.width = container.width - handle.width - minimumRightLimit
}
// width(B) > maximum width(B).
else if (maximumRightLimit != null && theoreticalBWidth > maximumRightLimit) {
contentA.width = container.width - handle.width - maximumRightLimit
}
}
function _applyLimitsOnUserMove (offset) {
var minimumRightLimit = _getLimitValue(_minimumRightLimit)
var minimumLeftLimit = _getLimitValue(_minimumLeftLimit)
// One area is closed.
if (_isClosed) {
if (closingEdge === Qt.LeftEdge) {
if (offset > minimumLeftLimit / 2) {
_updateClosing()
}
} else {
if (-offset > minimumRightLimit / 2) {
_updateClosing()
}
}
return
}
// Check limits.
var maximumLeftLimit = _getLimitValue(_maximumLeftLimit)
var maximumRightLimit = _getLimitValue(_maximumRightLimit)
var theoreticalBWidth = container.width - offset - contentA.width - handle.width
// width(A) < minimum width(A).
if (contentA.width + offset < minimumLeftLimit) {
contentA.width = minimumLeftLimit
if (closingEdge === Qt.LeftEdge && -offset > minimumLeftLimit / 2) {
_updateClosing()
}
}
// width(A) > maximum width(A).
else if (maximumLeftLimit != null && contentA.width + offset > maximumLeftLimit) {
contentA.width = maximumLeftLimit
}
// width(B) < minimum width(B).
else if (theoreticalBWidth < minimumRightLimit) {
contentA.width = container.width - handle.width - minimumRightLimit
if (closingEdge === Qt.RightEdge && offset > minimumRightLimit / 2) {
_updateClosing()
}
}
// width(B) > maximum width(B).
else if (maximumRightLimit != null && theoreticalBWidth > maximumRightLimit) {
contentA.width = container.width - handle.width - maximumRightLimit
}
// Resize A/B.
else {
contentA.width = contentA.width + offset
}
}
function _updateClosing () {
// Save state and close.
if (!_isClosed) {
_isClosed = true
_savedContentAWidth = contentA.width
if (closingEdge === Qt.LeftEdge) {
closingTransitionA.running = true
} else {
closingTransitionB.running = true
}
return
}
// Restore old state.
_isClosed = false
contentA.width = _savedContentAWidth
_applyLimits()
}
onWidthChanged: _applyLimits()
Component.onCompleted: {
// Unable to modify this properties after creation.
// It's a desired choice.
_maximumLeftLimit = _parseLimit(maximumLeftLimit)
_maximumRightLimit = _parseLimit(maximumRightLimit)
_minimumLeftLimit = _parseLimit(minimumLeftLimit)
_minimumRightLimit = _parseLimit(minimumRightLimit)
contentA.width = _getLimitValue(_minimumLeftLimit)
}
Item {
id: contentA
height: parent.height
}
MouseArea {
id: handle
property int _mouseStart
anchors.left: contentA.right
cursorShape: Qt.SplitHCursor
height: parent.height
hoverEnabled: true
width: PanedStyle.handle.width
onDoubleClicked: _updateClosing()
onMouseXChanged: pressed &&
_applyLimitsOnUserMove(handle.mouseX - _mouseStart)
onPressed: _mouseStart = mouseX
Rectangle {
anchors.fill: parent
color: parent.pressed
? PanedStyle.handle.color.pressed
: (parent.containsMouse
? PanedStyle.handle.color.hovered
: PanedStyle.handle.color.normal
)
}
}
Item {
id: contentB
anchors.left: handle.right
height: parent.height
width: container.width - contentA.width - handle.width
}
PropertyAnimation {
id: closingTransitionA
target: contentA
property: 'width'
to: 0
duration: 200
}
PropertyAnimation {
id: closingTransitionB
duration: 200
property: 'width'
target: contentA
to: container.width - handle.width
}
}