parent
24fdee32a2
commit
ffbfa977b5
|
@ -0,0 +1,534 @@
|
||||||
|
/****************************************************************************
|
||||||
|
**
|
||||||
|
** Copyright (C) 2016 The Qt Company Ltd.
|
||||||
|
** Contact: https://www.qt.io/licensing/
|
||||||
|
**
|
||||||
|
** This file is part of the Qt Quick Controls module of the Qt Toolkit.
|
||||||
|
**
|
||||||
|
** $QT_BEGIN_LICENSE:LGPL$
|
||||||
|
** Commercial License Usage
|
||||||
|
** Licensees holding valid commercial Qt licenses may use this file in
|
||||||
|
** accordance with the commercial license agreement provided with the
|
||||||
|
** Software or, alternatively, in accordance with the terms contained in
|
||||||
|
** a written agreement between you and The Qt Company. For licensing terms
|
||||||
|
** and conditions see https://www.qt.io/terms-conditions. For further
|
||||||
|
** information use the contact form at https://www.qt.io/contact-us.
|
||||||
|
**
|
||||||
|
** GNU Lesser General Public License Usage
|
||||||
|
** Alternatively, this file may be used under the terms of the GNU Lesser
|
||||||
|
** General Public License version 3 as published by the Free Software
|
||||||
|
** Foundation and appearing in the file LICENSE.LGPL3 included in the
|
||||||
|
** packaging of this file. Please review the following information to
|
||||||
|
** ensure the GNU Lesser General Public License version 3 requirements
|
||||||
|
** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
|
||||||
|
**
|
||||||
|
** GNU General Public License Usage
|
||||||
|
** Alternatively, this file may be used under the terms of the GNU
|
||||||
|
** General Public License version 2.0 or (at your option) the GNU General
|
||||||
|
** Public license version 3 or any later version approved by the KDE Free
|
||||||
|
** Qt Foundation. The licenses are as published by the Free Software
|
||||||
|
** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
|
||||||
|
** included in the packaging of this file. Please review the following
|
||||||
|
** information to ensure the GNU General Public License requirements will
|
||||||
|
** be met: https://www.gnu.org/licenses/gpl-2.0.html and
|
||||||
|
** https://www.gnu.org/licenses/gpl-3.0.html.
|
||||||
|
**
|
||||||
|
** $QT_END_LICENSE$
|
||||||
|
**
|
||||||
|
****************************************************************************/
|
||||||
|
|
||||||
|
import QtQuick 2.9
|
||||||
|
import QtQuick.Controls 2.2
|
||||||
|
import QtQuick.Layouts 1.3
|
||||||
|
import QtQuick.Window 2.1
|
||||||
|
|
||||||
|
Item {
|
||||||
|
id: root
|
||||||
|
|
||||||
|
property int orientation: Qt.Horizontal
|
||||||
|
|
||||||
|
/*!
|
||||||
|
This property holds the delegate that will be instantiated between each
|
||||||
|
child item. Inside the delegate the following properties are available:
|
||||||
|
|
||||||
|
\table
|
||||||
|
\row \li readonly property bool styleData.index \li Specifies the index of the splitter handle. The handle
|
||||||
|
between the first and the second item will get index 0,
|
||||||
|
the next handle index 1 etc.
|
||||||
|
\row \li readonly property bool styleData.hovered \li The handle is being hovered.
|
||||||
|
\row \li readonly property bool styleData.pressed \li The handle is being pressed.
|
||||||
|
\row \li readonly property bool styleData.resizing \li The handle is being dragged.
|
||||||
|
\endtable
|
||||||
|
|
||||||
|
*/
|
||||||
|
property Component handleDelegate: Rectangle {
|
||||||
|
width: 1
|
||||||
|
height: 1
|
||||||
|
visible: false
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
This propery is \c true when the user is resizing any of the items by
|
||||||
|
dragging on the splitter handles.
|
||||||
|
*/
|
||||||
|
property bool resizing: false
|
||||||
|
|
||||||
|
/*! \internal */
|
||||||
|
default property alias __contents: contents.data
|
||||||
|
/*! \internal */
|
||||||
|
property alias __items: splitterItems.children
|
||||||
|
/*! \internal */
|
||||||
|
property alias __handles: splitterHandles.children
|
||||||
|
|
||||||
|
clip: true
|
||||||
|
Component.onCompleted: d.init()
|
||||||
|
onWidthChanged: d.updateLayout()
|
||||||
|
onHeightChanged: d.updateLayout()
|
||||||
|
onOrientationChanged: d.changeOrientation()
|
||||||
|
|
||||||
|
/*! \qmlmethod void SplitView::addItem(Item item)
|
||||||
|
Add an item to the end of the view.
|
||||||
|
\since QtQuick.Controls 1.3 */
|
||||||
|
function addItem(item) {
|
||||||
|
d.updateLayoutGuard = true
|
||||||
|
d.addItem_impl(item)
|
||||||
|
d.calculateImplicitSize()
|
||||||
|
d.updateLayoutGuard = false
|
||||||
|
d.updateFillIndex()
|
||||||
|
}
|
||||||
|
|
||||||
|
/*! \qmlmethod void SplitView::removeItem(Item item)
|
||||||
|
Remove \a item from the view.
|
||||||
|
\since QtQuick.Controls 1.4 */
|
||||||
|
function removeItem(item) {
|
||||||
|
d.updateLayoutGuard = true
|
||||||
|
var result = d.removeItem_impl(item)
|
||||||
|
if (result !== null) {
|
||||||
|
d.calculateImplicitSize()
|
||||||
|
d.updateLayoutGuard = false
|
||||||
|
d.updateFillIndex()
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
d.updateLayoutGuard = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
SystemPalette { id: pal }
|
||||||
|
|
||||||
|
QtObject {
|
||||||
|
id: d
|
||||||
|
|
||||||
|
readonly property string leftMargin: horizontal ? "leftMargin" : "topMargin"
|
||||||
|
readonly property string topMargin: horizontal ? "topMargin" : "leftMargin"
|
||||||
|
readonly property string rightMargin: horizontal ? "rightMargin" : "bottomMargin"
|
||||||
|
|
||||||
|
property bool horizontal: orientation == Qt.Horizontal
|
||||||
|
readonly property string minimum: horizontal ? "minimumWidth" : "minimumHeight"
|
||||||
|
readonly property string maximum: horizontal ? "maximumWidth" : "maximumHeight"
|
||||||
|
readonly property string otherMinimum: horizontal ? "minimumHeight" : "minimumWidth"
|
||||||
|
readonly property string otherMaximum: horizontal ? "maximumHeight" : "maximumWidth"
|
||||||
|
readonly property string offset: horizontal ? "x" : "y"
|
||||||
|
readonly property string otherOffset: horizontal ? "y" : "x"
|
||||||
|
readonly property string size: horizontal ? "width" : "height"
|
||||||
|
readonly property string otherSize: horizontal ? "height" : "width"
|
||||||
|
readonly property string implicitSize: horizontal ? "implicitWidth" : "implicitHeight"
|
||||||
|
readonly property string implicitOtherSize: horizontal ? "implicitHeight" : "implicitWidth"
|
||||||
|
|
||||||
|
property int fillIndex: -1
|
||||||
|
property bool updateLayoutGuard: true
|
||||||
|
|
||||||
|
function extraMarginSize(item, other) {
|
||||||
|
if (typeof(other) === 'undefined')
|
||||||
|
other = false;
|
||||||
|
if (other === horizontal)
|
||||||
|
// vertical
|
||||||
|
return item.Layout.topMargin + item.Layout.bottomMargin
|
||||||
|
return item.Layout.leftMargin + item.Layout.rightMargin
|
||||||
|
}
|
||||||
|
|
||||||
|
function addItem_impl(item)
|
||||||
|
{
|
||||||
|
// temporarily set fillIndex to new item
|
||||||
|
fillIndex = __items.length
|
||||||
|
if (splitterItems.children.length > 0)
|
||||||
|
handleLoader.createObject(splitterHandles, {"__handleIndex":splitterItems.children.length - 1})
|
||||||
|
|
||||||
|
item.parent = splitterItems
|
||||||
|
d.initItemConnections(item)
|
||||||
|
}
|
||||||
|
|
||||||
|
function initItemConnections(item)
|
||||||
|
{
|
||||||
|
// should match disconnections in terminateItemConnections
|
||||||
|
item.widthChanged.connect(d.updateLayout)
|
||||||
|
item.heightChanged.connect(d.updateLayout)
|
||||||
|
item.Layout.maximumWidthChanged.connect(d.updateLayout)
|
||||||
|
item.Layout.minimumWidthChanged.connect(d.updateLayout)
|
||||||
|
item.Layout.maximumHeightChanged.connect(d.updateLayout)
|
||||||
|
item.Layout.minimumHeightChanged.connect(d.updateLayout)
|
||||||
|
item.Layout.leftMarginChanged.connect(d.updateLayout)
|
||||||
|
item.Layout.topMarginChanged.connect(d.updateLayout)
|
||||||
|
item.Layout.rightMarginChanged.connect(d.updateLayout)
|
||||||
|
item.Layout.bottomMarginChanged.connect(d.updateLayout)
|
||||||
|
item.visibleChanged.connect(d.updateFillIndex)
|
||||||
|
item.Layout.fillWidthChanged.connect(d.updateFillIndex)
|
||||||
|
item.Layout.fillHeightChanged.connect(d.updateFillIndex)
|
||||||
|
}
|
||||||
|
|
||||||
|
function terminateItemConnections(item)
|
||||||
|
{
|
||||||
|
// should match connections in initItemConnections
|
||||||
|
item.widthChanged.disconnect(d.updateLayout)
|
||||||
|
item.heightChanged.disconnect(d.updateLayout)
|
||||||
|
item.Layout.maximumWidthChanged.disconnect(d.updateLayout)
|
||||||
|
item.Layout.minimumWidthChanged.disconnect(d.updateLayout)
|
||||||
|
item.Layout.maximumHeightChanged.disconnect(d.updateLayout)
|
||||||
|
item.Layout.minimumHeightChanged.disconnect(d.updateLayout)
|
||||||
|
item.visibleChanged.disconnect(d.updateFillIndex)
|
||||||
|
item.Layout.fillWidthChanged.disconnect(d.updateFillIndex)
|
||||||
|
item.Layout.fillHeightChanged.disconnect(d.updateFillIndex)
|
||||||
|
}
|
||||||
|
|
||||||
|
function removeItem_impl(item)
|
||||||
|
{
|
||||||
|
var pos = itemPos(item)
|
||||||
|
|
||||||
|
// Check pos range
|
||||||
|
if (pos < 0 || pos >= __items.length)
|
||||||
|
return null
|
||||||
|
|
||||||
|
// Temporary unset the fillIndex
|
||||||
|
fillIndex = __items.length - 1
|
||||||
|
|
||||||
|
// Remove the handle at the left/right of the item that
|
||||||
|
// is going to be removed
|
||||||
|
var handlePos = -1
|
||||||
|
var hasPrevious = pos > 0
|
||||||
|
var hasNext = (pos + 1) < __items.length
|
||||||
|
|
||||||
|
if (hasPrevious)
|
||||||
|
handlePos = pos-1
|
||||||
|
else if (hasNext)
|
||||||
|
handlePos = pos
|
||||||
|
if (handlePos >= 0) {
|
||||||
|
var handle = __handles[handlePos]
|
||||||
|
handle.visible = false
|
||||||
|
handle.parent = null
|
||||||
|
handle.destroy()
|
||||||
|
for (var i = handlePos; i < __handles.length; ++i)
|
||||||
|
__handles[i].__handleIndex = i
|
||||||
|
}
|
||||||
|
|
||||||
|
// Remove the item.
|
||||||
|
// Disconnect the item to be removed
|
||||||
|
terminateItemConnections(item)
|
||||||
|
item.parent = null
|
||||||
|
|
||||||
|
return item
|
||||||
|
}
|
||||||
|
|
||||||
|
function itemPos(item)
|
||||||
|
{
|
||||||
|
for (var i = 0; i < __items.length; ++i)
|
||||||
|
if (item === __items[i])
|
||||||
|
return i
|
||||||
|
return -1
|
||||||
|
}
|
||||||
|
|
||||||
|
function init()
|
||||||
|
{
|
||||||
|
for (var i=0; i<__contents.length; ++i) {
|
||||||
|
var item = __contents[i];
|
||||||
|
if (!item.hasOwnProperty("x"))
|
||||||
|
continue
|
||||||
|
addItem_impl(item)
|
||||||
|
i-- // item was removed from list
|
||||||
|
}
|
||||||
|
|
||||||
|
d.calculateImplicitSize()
|
||||||
|
d.updateLayoutGuard = false
|
||||||
|
d.updateFillIndex()
|
||||||
|
}
|
||||||
|
|
||||||
|
function updateFillIndex()
|
||||||
|
{
|
||||||
|
if (lastItem.visible !== root.visible)
|
||||||
|
return
|
||||||
|
var policy = (root.orientation === Qt.Horizontal) ? "fillWidth" : "fillHeight"
|
||||||
|
for (var i=0; i<__items.length-1; ++i) {
|
||||||
|
if (__items[i].Layout[policy] === true)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
d.fillIndex = i
|
||||||
|
d.updateLayout()
|
||||||
|
}
|
||||||
|
|
||||||
|
function changeOrientation()
|
||||||
|
{
|
||||||
|
if (__items.length == 0)
|
||||||
|
return;
|
||||||
|
d.updateLayoutGuard = true
|
||||||
|
|
||||||
|
// Swap width/height for items and handles:
|
||||||
|
for (var i=0; i<__items.length; ++i) {
|
||||||
|
var item = __items[i]
|
||||||
|
var tmp = item.x
|
||||||
|
item.x = item.y
|
||||||
|
item.y = tmp
|
||||||
|
tmp = item.width
|
||||||
|
item.width = item.height
|
||||||
|
item.height = tmp
|
||||||
|
|
||||||
|
var handle = __handles[i]
|
||||||
|
if (handle) {
|
||||||
|
tmp = handle.x
|
||||||
|
handle.x = handle.y
|
||||||
|
handle.y = handle.x
|
||||||
|
tmp = handle.width
|
||||||
|
handle.width = handle.height
|
||||||
|
handle.height = tmp
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Change d.horizontal explicit, since the binding will change too late:
|
||||||
|
d.horizontal = orientation == Qt.Horizontal
|
||||||
|
d.updateLayoutGuard = false
|
||||||
|
d.updateFillIndex()
|
||||||
|
}
|
||||||
|
|
||||||
|
function calculateImplicitSize()
|
||||||
|
{
|
||||||
|
var implicitSize = 0
|
||||||
|
var implicitOtherSize = 0
|
||||||
|
|
||||||
|
for (var i=0; i<__items.length; ++i) {
|
||||||
|
var item = __items[i];
|
||||||
|
implicitSize += clampedMinMax(item[d.size], item.Layout[minimum], item.Layout[maximum]) + extraMarginSize(item)
|
||||||
|
var os = clampedMinMax(item[otherSize], item.Layout[otherMinimum], item.Layout[otherMaximum]) + extraMarginSize(item, true)
|
||||||
|
implicitOtherSize = Math.max(implicitOtherSize, os)
|
||||||
|
|
||||||
|
var handle = __handles[i]
|
||||||
|
if (handle)
|
||||||
|
implicitSize += handle[d.size] //### Can handles have margins??
|
||||||
|
}
|
||||||
|
|
||||||
|
root[d.implicitSize] = implicitSize
|
||||||
|
root[d.implicitOtherSize] = implicitOtherSize
|
||||||
|
}
|
||||||
|
|
||||||
|
function clampedMinMax(value, minimum, maximum)
|
||||||
|
{
|
||||||
|
if (value < minimum)
|
||||||
|
value = minimum
|
||||||
|
if (value > maximum)
|
||||||
|
value = maximum
|
||||||
|
return value
|
||||||
|
}
|
||||||
|
|
||||||
|
function accumulatedSize(firstIndex, lastIndex, includeFillItemMinimum)
|
||||||
|
{
|
||||||
|
// Go through items and handles, and
|
||||||
|
// calculate their accummulated width.
|
||||||
|
var w = 0
|
||||||
|
for (var i=firstIndex; i<lastIndex; ++i) {
|
||||||
|
|
||||||
|
var item = __items[i]
|
||||||
|
if (item.visible || i == d.fillIndex) {
|
||||||
|
if (i !== d.fillIndex)
|
||||||
|
w += item[d.size] + extraMarginSize(item)
|
||||||
|
else if (includeFillItemMinimum && item.Layout[minimum] !== undefined)
|
||||||
|
w += item.Layout[minimum] + extraMarginSize(item)
|
||||||
|
}
|
||||||
|
|
||||||
|
var handle = __handles[i]
|
||||||
|
if (handle && handle.visible)
|
||||||
|
w += handle[d.size]
|
||||||
|
}
|
||||||
|
return w
|
||||||
|
}
|
||||||
|
|
||||||
|
function updateLayout()
|
||||||
|
{
|
||||||
|
// This function will reposition both handles and
|
||||||
|
// items according to the their width/height:
|
||||||
|
if (__items.length === 0)
|
||||||
|
return;
|
||||||
|
if (!lastItem.visible)
|
||||||
|
return;
|
||||||
|
if (d.updateLayoutGuard === true)
|
||||||
|
return
|
||||||
|
d.updateLayoutGuard = true
|
||||||
|
|
||||||
|
// Ensure all items within their min/max:
|
||||||
|
for (var i=0; i<__items.length; ++i) {
|
||||||
|
if (i !== d.fillIndex) {
|
||||||
|
var item = __items[i];
|
||||||
|
var clampedSize = clampedMinMax(item[d.size], item.Layout[d.minimum], item.Layout[d.maximum])
|
||||||
|
if (clampedSize != item[d.size])
|
||||||
|
item[d.size] = clampedSize
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set size of fillItem to remaining available space.
|
||||||
|
// Special case: If SplitView size is zero, we leave fillItem with the size
|
||||||
|
// it already got, and assume that SplitView ends up with implicit size as size:
|
||||||
|
if (root[d.size] != 0) {
|
||||||
|
var fillItem = __items[fillIndex]
|
||||||
|
var superfluous = root[d.size] - d.accumulatedSize(0, __items.length, false)
|
||||||
|
fillItem[d.size] = clampedMinMax(superfluous - extraMarginSize(fillItem), fillItem.Layout[minimum], fillItem.Layout[maximum]);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Position items and handles according to their width:
|
||||||
|
var lastVisibleItem, lastVisibleHandle, handle
|
||||||
|
var pos = 0;
|
||||||
|
for (i=0; i<__items.length; ++i) {
|
||||||
|
// Position item to the right of the previous visible handle:
|
||||||
|
item = __items[i];
|
||||||
|
if (item.visible || i == d.fillIndex) {
|
||||||
|
pos += item.Layout[leftMargin]
|
||||||
|
item[d.offset] = pos
|
||||||
|
item[d.otherOffset] = item.Layout[topMargin]
|
||||||
|
item[d.otherSize] = clampedMinMax(root[otherSize], item.Layout[otherMinimum], item.Layout[otherMaximum]) - extraMarginSize(item, true)
|
||||||
|
lastVisibleItem = item
|
||||||
|
pos += Math.max(0, item[d.size]) + item.Layout[rightMargin]
|
||||||
|
}
|
||||||
|
|
||||||
|
handle = __handles[i]
|
||||||
|
if (handle && handle.visible) {
|
||||||
|
handle[d.offset] = pos
|
||||||
|
handle[d.otherOffset] = 0 //### can handles have margins?
|
||||||
|
handle[d.otherSize] = root[d.otherSize]
|
||||||
|
lastVisibleHandle = handle
|
||||||
|
pos += handle[d.size]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
d.updateLayoutGuard = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Component {
|
||||||
|
id: handleLoader
|
||||||
|
Loader {
|
||||||
|
id: itemHandle
|
||||||
|
|
||||||
|
property int __handleIndex: -1
|
||||||
|
property QtObject styleData: QtObject {
|
||||||
|
readonly property int index: __handleIndex
|
||||||
|
readonly property alias hovered: mouseArea.containsMouse
|
||||||
|
readonly property alias pressed: mouseArea.pressed
|
||||||
|
readonly property bool resizing: mouseArea.drag.active
|
||||||
|
onResizingChanged: root.resizing = resizing
|
||||||
|
}
|
||||||
|
property bool resizeLeftItem: (d.fillIndex > __handleIndex)
|
||||||
|
visible: __items[__handleIndex + (resizeLeftItem ? 0 : 1)].visible
|
||||||
|
sourceComponent: handleDelegate
|
||||||
|
onWidthChanged: d.updateLayout()
|
||||||
|
onHeightChanged: d.updateLayout()
|
||||||
|
onXChanged: moveHandle()
|
||||||
|
onYChanged: moveHandle()
|
||||||
|
|
||||||
|
MouseArea {
|
||||||
|
id: mouseArea
|
||||||
|
anchors.fill: parent
|
||||||
|
property real defaultMargin: Screen.pixelDensity * 2
|
||||||
|
anchors.leftMargin: (parent.width <= 1) ? -defaultMargin : 0
|
||||||
|
anchors.rightMargin: (parent.width <= 1) ? -defaultMargin : 0
|
||||||
|
anchors.topMargin: (parent.height <= 1) ? -defaultMargin : 0
|
||||||
|
anchors.bottomMargin: (parent.height <= 1) ? -defaultMargin : 0
|
||||||
|
hoverEnabled: true
|
||||||
|
drag.threshold: 0
|
||||||
|
drag.target: parent
|
||||||
|
drag.axis: root.orientation === Qt.Horizontal ? Drag.XAxis : Drag.YAxis
|
||||||
|
cursorShape: root.orientation === Qt.Horizontal ? Qt.SplitHCursor : Qt.SplitVCursor
|
||||||
|
}
|
||||||
|
|
||||||
|
function moveHandle() {
|
||||||
|
// Moving the handle means resizing an item. Which one,
|
||||||
|
// left or right, depends on where the fillItem is.
|
||||||
|
// 'updateLayout' will be overridden in case new width violates max/min.
|
||||||
|
// 'updateLayout' will be triggered when an item changes width.
|
||||||
|
if (d.updateLayoutGuard)
|
||||||
|
return
|
||||||
|
|
||||||
|
var leftHandle, leftItem, rightItem, rightHandle
|
||||||
|
var leftEdge, rightEdge, newWidth, leftStopX, rightStopX
|
||||||
|
var i
|
||||||
|
|
||||||
|
if (resizeLeftItem) {
|
||||||
|
// Ensure that the handle is not crossing other handles. So
|
||||||
|
// find the first visible handle to the left to determine the left edge:
|
||||||
|
leftEdge = 0
|
||||||
|
for (i=__handleIndex-1; i>=0; --i) {
|
||||||
|
leftHandle = __handles[i]
|
||||||
|
if (leftHandle.visible) {
|
||||||
|
leftEdge = leftHandle[d.offset] + leftHandle[d.size]
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Ensure: leftStopX >= itemHandle[d.offset] >= rightStopX
|
||||||
|
var min = d.accumulatedSize(__handleIndex+1, __items.length, true)
|
||||||
|
rightStopX = root[d.size] - min - itemHandle[d.size]
|
||||||
|
leftStopX = Math.max(leftEdge, itemHandle[d.offset])
|
||||||
|
itemHandle[d.offset] = Math.min(rightStopX, Math.max(leftStopX, itemHandle[d.offset]))
|
||||||
|
|
||||||
|
newWidth = itemHandle[d.offset] - leftEdge
|
||||||
|
leftItem = __items[__handleIndex]
|
||||||
|
// The next line will trigger 'updateLayout':
|
||||||
|
leftItem[d.size] = newWidth
|
||||||
|
} else {
|
||||||
|
// Resize item to the right.
|
||||||
|
// Ensure that the handle is not crossing other handles. So
|
||||||
|
// find the first visible handle to the right to determine the right edge:
|
||||||
|
rightEdge = root[d.size]
|
||||||
|
for (i=__handleIndex+1; i<__handles.length; ++i) {
|
||||||
|
rightHandle = __handles[i]
|
||||||
|
if (rightHandle.visible) {
|
||||||
|
rightEdge = rightHandle[d.offset]
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Ensure: leftStopX <= itemHandle[d.offset] <= rightStopX
|
||||||
|
min = d.accumulatedSize(0, __handleIndex+1, true)
|
||||||
|
leftStopX = min - itemHandle[d.size]
|
||||||
|
rightStopX = Math.min((rightEdge - itemHandle[d.size]), itemHandle[d.offset])
|
||||||
|
itemHandle[d.offset] = Math.max(leftStopX, Math.min(itemHandle[d.offset], rightStopX))
|
||||||
|
|
||||||
|
newWidth = rightEdge - (itemHandle[d.offset] + itemHandle[d.size])
|
||||||
|
rightItem = __items[__handleIndex+1]
|
||||||
|
// The next line will trigger 'updateLayout':
|
||||||
|
rightItem[d.size] = newWidth
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Item {
|
||||||
|
id: contents
|
||||||
|
visible: false
|
||||||
|
anchors.fill: parent
|
||||||
|
}
|
||||||
|
Item {
|
||||||
|
id: splitterItems
|
||||||
|
anchors.fill: parent
|
||||||
|
}
|
||||||
|
Item {
|
||||||
|
id: splitterHandles
|
||||||
|
anchors.fill: parent
|
||||||
|
}
|
||||||
|
|
||||||
|
Item {
|
||||||
|
id: lastItem
|
||||||
|
onVisibleChanged: d.updateFillIndex()
|
||||||
|
}
|
||||||
|
|
||||||
|
Component.onDestruction: {
|
||||||
|
for (var i=0; i<splitterItems.children.length; ++i) {
|
||||||
|
var item = splitterItems.children[i];
|
||||||
|
d.terminateItemConnections(item)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -5,3 +5,4 @@ SideNavButton 2.0 SideNavButton.qml
|
||||||
ScrollHelper 2.0 ScrollHelper.qml
|
ScrollHelper 2.0 ScrollHelper.qml
|
||||||
AutoListView 2.0 AutoListView.qml
|
AutoListView 2.0 AutoListView.qml
|
||||||
AutoTextField 2.0 AutoTextField.qml
|
AutoTextField 2.0 AutoTextField.qml
|
||||||
|
SplitView 2.0 SplitView.qml
|
||||||
|
|
|
@ -1,5 +1,64 @@
|
||||||
import QtQuick 2.9
|
import QtQuick 2.9
|
||||||
|
|
||||||
RoomForm {
|
import QtQuick 2.9
|
||||||
roomListModel.onNewMessage: if (!window.active) spectralController.postNotification(roomId, eventId, roomName, senderName, text, icon, iconPath)
|
import QtQuick.Controls 2.2
|
||||||
|
import QtQuick.Layouts 1.3
|
||||||
|
import QtQuick.Controls.Material 2.2
|
||||||
|
|
||||||
|
import Spectral.Panel 2.0
|
||||||
|
import Spectral.Component 2.0
|
||||||
|
import Spectral.Effect 2.0
|
||||||
|
|
||||||
|
import Spectral 0.1
|
||||||
|
import Spectral.Setting 0.1
|
||||||
|
|
||||||
|
Page {
|
||||||
|
property alias connection: roomListModel.connection
|
||||||
|
property alias enteredRoom: roomListForm.enteredRoom
|
||||||
|
property alias filter: roomListForm.filter
|
||||||
|
|
||||||
|
id: page
|
||||||
|
|
||||||
|
RoomListModel {
|
||||||
|
id: roomListModel
|
||||||
|
|
||||||
|
onNewMessage: if (!window.active) spectralController.postNotification(roomId, eventId, roomName, senderName, text, icon, iconPath)
|
||||||
|
}
|
||||||
|
|
||||||
|
SplitView {
|
||||||
|
anchors.fill: parent
|
||||||
|
|
||||||
|
RoomListPanel {
|
||||||
|
// Layout.fillHeight: true
|
||||||
|
width: page.width * 0.35
|
||||||
|
Layout.minimumWidth: 64
|
||||||
|
// Layout.maximumWidth: 360
|
||||||
|
|
||||||
|
id: roomListForm
|
||||||
|
|
||||||
|
listModel: roomListModel
|
||||||
|
|
||||||
|
onWidthChanged: {
|
||||||
|
if (width < 240) width = 64
|
||||||
|
}
|
||||||
|
|
||||||
|
ElevationEffect {
|
||||||
|
anchors.fill: source
|
||||||
|
z: source.z - 1
|
||||||
|
|
||||||
|
source: parent
|
||||||
|
elevation: 2
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
RoomPanel {
|
||||||
|
Layout.fillWidth: true
|
||||||
|
Layout.minimumWidth: 360
|
||||||
|
// Layout.fillHeight: true
|
||||||
|
|
||||||
|
id: roomForm
|
||||||
|
|
||||||
|
currentRoom: roomListForm.enteredRoom
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,62 +0,0 @@
|
||||||
import QtQuick 2.9
|
|
||||||
import QtQuick.Controls 2.2
|
|
||||||
import QtQuick.Layouts 1.3
|
|
||||||
import QtQuick.Controls.Material 2.2
|
|
||||||
|
|
||||||
import Spectral.Panel 2.0
|
|
||||||
import Spectral.Component 2.0
|
|
||||||
import Spectral.Effect 2.0
|
|
||||||
|
|
||||||
import Spectral 0.1
|
|
||||||
import Spectral.Setting 0.1
|
|
||||||
|
|
||||||
Page {
|
|
||||||
property alias connection: roomListModel.connection
|
|
||||||
property alias filter: roomListForm.filter
|
|
||||||
|
|
||||||
property alias roomListModel: roomListModel
|
|
||||||
property alias enteredRoom: roomListForm.enteredRoom
|
|
||||||
|
|
||||||
id: page
|
|
||||||
|
|
||||||
RoomListModel {
|
|
||||||
id: roomListModel
|
|
||||||
}
|
|
||||||
|
|
||||||
RowLayout {
|
|
||||||
anchors.fill: parent
|
|
||||||
|
|
||||||
spacing: 0
|
|
||||||
|
|
||||||
RoomListPanel {
|
|
||||||
Layout.fillHeight: true
|
|
||||||
Layout.preferredWidth: MSettings.miniMode ? 64 : page.width * 0.35
|
|
||||||
Layout.minimumWidth: 64
|
|
||||||
Layout.maximumWidth: 360
|
|
||||||
|
|
||||||
id: roomListForm
|
|
||||||
|
|
||||||
listModel: roomListModel
|
|
||||||
|
|
||||||
layer.enabled: true
|
|
||||||
layer.effect: ElevationEffect {
|
|
||||||
elevation: 2
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
RoomPanel {
|
|
||||||
Layout.fillWidth: true
|
|
||||||
Layout.fillHeight: true
|
|
||||||
|
|
||||||
id: roomForm
|
|
||||||
|
|
||||||
currentRoom: roomListForm.enteredRoom
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/*##^## Designer {
|
|
||||||
D{i:0;autoSize:false;height:480;width:640}
|
|
||||||
}
|
|
||||||
##^##*/
|
|
|
@ -97,13 +97,6 @@ Page {
|
||||||
|
|
||||||
onCheckedChanged: MSettings.darkTheme = checked
|
onCheckedChanged: MSettings.darkTheme = checked
|
||||||
}
|
}
|
||||||
|
|
||||||
Switch {
|
|
||||||
text: "Mini Room List"
|
|
||||||
checked: MSettings.miniMode
|
|
||||||
|
|
||||||
onCheckedChanged: MSettings.miniMode = checked
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -14,7 +14,7 @@ Rectangle {
|
||||||
AutoMouseArea {
|
AutoMouseArea {
|
||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
|
|
||||||
hoverEnabled: MSettings.miniMode
|
hoverEnabled: miniMode
|
||||||
|
|
||||||
onSecondaryClicked: {
|
onSecondaryClicked: {
|
||||||
roomContextMenu.model = model
|
roomContextMenu.model = model
|
||||||
|
@ -29,7 +29,7 @@ Rectangle {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ToolTip.visible: MSettings.miniMode && containsMouse
|
ToolTip.visible: miniMode && containsMouse
|
||||||
ToolTip.text: name
|
ToolTip.text: name
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -23,10 +23,12 @@ Rectangle {
|
||||||
property alias searchField: searchField
|
property alias searchField: searchField
|
||||||
property alias model: listView.model
|
property alias model: listView.model
|
||||||
|
|
||||||
|
property bool miniMode: width == 64
|
||||||
|
|
||||||
color: MSettings.darkTheme ? "#323232" : "#f3f3f3"
|
color: MSettings.darkTheme ? "#323232" : "#f3f3f3"
|
||||||
|
|
||||||
Label {
|
Label {
|
||||||
text: MSettings.miniMode ? "Empty" : "Here? No, not here."
|
text: miniMode ? "Empty" : "Here? No, not here."
|
||||||
anchors.centerIn: parent
|
anchors.centerIn: parent
|
||||||
visible: listView.count === 0
|
visible: listView.count === 0
|
||||||
}
|
}
|
||||||
|
@ -55,7 +57,7 @@ Rectangle {
|
||||||
Layout.preferredWidth: height
|
Layout.preferredWidth: height
|
||||||
Layout.fillHeight: true
|
Layout.fillHeight: true
|
||||||
|
|
||||||
visible: !MSettings.miniMode && !searchField.text
|
visible: !miniMode && !searchField.text
|
||||||
|
|
||||||
icon: "\ue8b6"
|
icon: "\ue8b6"
|
||||||
color: "grey"
|
color: "grey"
|
||||||
|
@ -65,7 +67,7 @@ Rectangle {
|
||||||
Layout.preferredWidth: height
|
Layout.preferredWidth: height
|
||||||
Layout.fillHeight: true
|
Layout.fillHeight: true
|
||||||
|
|
||||||
visible: !MSettings.miniMode && searchField.text
|
visible: !miniMode && searchField.text
|
||||||
|
|
||||||
contentItem: MaterialIcon {
|
contentItem: MaterialIcon {
|
||||||
icon: "\ue5cd"
|
icon: "\ue5cd"
|
||||||
|
@ -116,10 +118,10 @@ Rectangle {
|
||||||
|
|
||||||
text: section
|
text: section
|
||||||
color: "grey"
|
color: "grey"
|
||||||
leftPadding: MSettings.miniMode ? undefined : 16
|
leftPadding: miniMode ? undefined : 16
|
||||||
elide: Text.ElideRight
|
elide: Text.ElideRight
|
||||||
verticalAlignment: Text.AlignVCenter
|
verticalAlignment: Text.AlignVCenter
|
||||||
horizontalAlignment: MSettings.miniMode ? Text.AlignHCenter : undefined
|
horizontalAlignment: miniMode ? Text.AlignHCenter : undefined
|
||||||
}
|
}
|
||||||
|
|
||||||
RoomContextMenu { id: roomContextMenu }
|
RoomContextMenu { id: roomContextMenu }
|
||||||
|
|
|
@ -8,5 +8,4 @@ Settings {
|
||||||
property bool confirmOnExit: true
|
property bool confirmOnExit: true
|
||||||
|
|
||||||
property bool darkTheme
|
property bool darkTheme
|
||||||
property bool miniMode
|
|
||||||
}
|
}
|
||||||
|
|
2
res.qrc
2
res.qrc
|
@ -38,7 +38,6 @@
|
||||||
<file>imports/Spectral/Page/SettingForm.ui.qml</file>
|
<file>imports/Spectral/Page/SettingForm.ui.qml</file>
|
||||||
<file>imports/Spectral/Page/SettingCategoryDelegate.qml</file>
|
<file>imports/Spectral/Page/SettingCategoryDelegate.qml</file>
|
||||||
<file>imports/Spectral/Page/SettingAccountDelegate.qml</file>
|
<file>imports/Spectral/Page/SettingAccountDelegate.qml</file>
|
||||||
<file>imports/Spectral/Page/RoomForm.ui.qml</file>
|
|
||||||
<file>imports/Spectral/Page/LoginForm.ui.qml</file>
|
<file>imports/Spectral/Page/LoginForm.ui.qml</file>
|
||||||
<file>imports/Spectral/Panel/qmldir</file>
|
<file>imports/Spectral/Panel/qmldir</file>
|
||||||
<file>imports/Spectral/Panel/RoomDrawer.qml</file>
|
<file>imports/Spectral/Panel/RoomDrawer.qml</file>
|
||||||
|
@ -54,5 +53,6 @@
|
||||||
<file>imports/Spectral/Component/Timeline/TimelineLabel.qml</file>
|
<file>imports/Spectral/Component/Timeline/TimelineLabel.qml</file>
|
||||||
<file>imports/Spectral/Component/AutoTextField.qml</file>
|
<file>imports/Spectral/Component/AutoTextField.qml</file>
|
||||||
<file>imports/Spectral/Panel/RoomPanelInput.qml</file>
|
<file>imports/Spectral/Panel/RoomPanelInput.qml</file>
|
||||||
|
<file>imports/Spectral/Component/SplitView.qml</file>
|
||||||
</qresource>
|
</qresource>
|
||||||
</RCC>
|
</RCC>
|
||||||
|
|
Loading…
Reference in New Issue