263 lines
9.4 KiB
QML
263 lines
9.4 KiB
QML
import QtQuick 2.15
|
|
import QtQuick.Templates 2.15 as T
|
|
import DelegateUI 1.0
|
|
|
|
Item {
|
|
id: control
|
|
|
|
height: __listView.contentHeight
|
|
|
|
titleFont {
|
|
family: DelTheme.DelCollapse.fontFamily
|
|
pixelSize: DelTheme.DelCollapse.fontSizeTitle
|
|
}
|
|
contentFont {
|
|
family: DelTheme.DelCollapse.fontFamily
|
|
pixelSize: DelTheme.DelCollapse.fontSizeContent
|
|
}
|
|
|
|
signal actived(key: string)
|
|
|
|
property bool animationEnabled: DelTheme.animationEnabled
|
|
property int hoverCursorShape: Qt.PointingHandCursor
|
|
property var initModel: []
|
|
property alias count: __listModel.count
|
|
property alias spacing: __listView.spacing
|
|
property bool accordion: false
|
|
property var activeKey: accordion ? "" : []
|
|
property var defaultActiveKey: []
|
|
property int expandIcon: DelIcon.RightOutlined
|
|
property font titleFont
|
|
property color colorBg: DelTheme.DelCollapse.colorBg
|
|
property color colorIcon: DelTheme.DelCollapse.colorIcon
|
|
property color colorTitle: DelTheme.DelCollapse.colorTitle
|
|
property color colorTitleBg: DelTheme.DelCollapse.colorTitleBg
|
|
property font contentFont
|
|
property color colorContent: DelTheme.DelCollapse.colorContent
|
|
property color colorContentBg: DelTheme.DelCollapse.colorContentBg
|
|
property color colorBorder: DelTheme.isDark ? DelTheme.DelCollapse.colorBorderDark : DelTheme.DelCollapse.colorBorder
|
|
property int radiusBg: 6
|
|
property Component titleDelegate: Row {
|
|
leftPadding: 16
|
|
rightPadding: 16
|
|
height: Math.max(40, __icon.height, __title.height)
|
|
spacing: 8
|
|
|
|
DelIconText {
|
|
id: __icon
|
|
anchors.verticalCenter: parent.verticalCenter
|
|
iconSource: control.expandIcon
|
|
colorIcon: control.colorIcon
|
|
rotation: isActive ? 90 : 0
|
|
|
|
Behavior on rotation { enabled: control.animationEnabled; RotationAnimation { duration: DelTheme.Primary.durationFast } }
|
|
}
|
|
|
|
Text {
|
|
id: __title
|
|
anchors.verticalCenter: parent.verticalCenter
|
|
text: model.title
|
|
elide: Text.ElideRight
|
|
font: control.titleFont
|
|
color: control.colorTitle
|
|
}
|
|
|
|
HoverHandler {
|
|
cursorShape: control.hoverCursorShape
|
|
}
|
|
}
|
|
property Component contentDelegate: DelCopyableText {
|
|
padding: 16
|
|
topPadding: 8
|
|
bottomPadding: 8
|
|
text: model.content
|
|
font: control.contentFont
|
|
wrapMode: Text.WordWrap
|
|
color: control.colorContent
|
|
}
|
|
|
|
onInitModelChanged: {
|
|
clear();
|
|
for (const object of initModel) {
|
|
append(object);
|
|
}
|
|
}
|
|
|
|
function get(index) {
|
|
return __listModel.get(index);
|
|
}
|
|
|
|
function set(index, object) {
|
|
__listModel.set(index, object);
|
|
}
|
|
|
|
function setProperty(index, propertyName, value) {
|
|
__listModel.setProperty(index, propertyName, value);
|
|
}
|
|
|
|
function move(from, to, count = 1) {
|
|
__listModel.move(from, to, count);
|
|
}
|
|
|
|
function insert(index, object) {
|
|
__listModel.insert(index, object);
|
|
}
|
|
|
|
function append(object) {
|
|
__listModel.append(object);
|
|
}
|
|
|
|
function remove(index, count = 1) {
|
|
__listModel.remove(index, count);
|
|
}
|
|
|
|
function clear() {
|
|
__listModel.clear();
|
|
}
|
|
|
|
Behavior on colorBg { enabled: control.animationEnabled; ColorAnimation { duration: DelTheme.Primary.durationFast } }
|
|
Behavior on colorTitle { enabled: control.animationEnabled; ColorAnimation { duration: DelTheme.Primary.durationFast } }
|
|
Behavior on colorTitleBg { enabled: control.animationEnabled; ColorAnimation { duration: DelTheme.Primary.durationFast } }
|
|
Behavior on colorContent { enabled: control.animationEnabled; ColorAnimation { duration: DelTheme.Primary.durationFast } }
|
|
Behavior on colorContentBg { enabled: control.animationEnabled; ColorAnimation { duration: DelTheme.Primary.durationFast } }
|
|
|
|
QtObject {
|
|
id: __private
|
|
function calcActiveKey() {
|
|
if (control.accordion) {
|
|
for (let i = 0; i < __listView.count; i++) {
|
|
const item = __listView.itemAtIndex(i);
|
|
if (item && item.active) {
|
|
control.activeKey = item.model.key;
|
|
break;
|
|
}
|
|
}
|
|
} else {
|
|
let keys = [];
|
|
for (let i = 0; i < __listView.count; i++) {
|
|
const item = __listView.itemAtIndex(i);
|
|
if (item && item.active) {
|
|
keys.push(item.model.key);
|
|
}
|
|
}
|
|
control.activeKey = keys;
|
|
}
|
|
}
|
|
}
|
|
|
|
ListView {
|
|
id: __listView
|
|
anchors.fill: parent
|
|
interactive: false
|
|
spacing: -1
|
|
model: ListModel { id: __listModel }
|
|
onContentHeightChanged: cacheBuffer = contentHeight;
|
|
delegate: DelRectangle {
|
|
id: __rootItem
|
|
width: __listView.width
|
|
height: __column.height + ((detached && active) ? 1 : 0)
|
|
topLeftRadius: (isStart || detached) ? control.radiusBg : 0
|
|
topRightRadius: (isStart || detached) ? control.radiusBg : 0
|
|
bottomLeftRadius: (isEnd || detached) ? control.radiusBg : 0
|
|
bottomRightRadius: (isEnd || detached) ? control.radiusBg : 0
|
|
color: control.colorBg
|
|
border.color: control.colorBorder
|
|
border.width: detached ? 1 : 0
|
|
clip: true
|
|
|
|
required property var model
|
|
required property int index
|
|
property bool isStart: index == 0
|
|
property bool isEnd: (index + 1) === control.count
|
|
property bool active: false
|
|
property bool detached: __listView.spacing !== -1
|
|
|
|
Component.onCompleted: {
|
|
if (control.defaultActiveKey.indexOf(model.key) != -1)
|
|
active = true;
|
|
}
|
|
|
|
Column {
|
|
id: __column
|
|
width: parent.width
|
|
anchors.horizontalCenter: parent.horizontalCenter
|
|
|
|
DelRectangle {
|
|
width: parent.width
|
|
height: __titleLoader.height
|
|
topLeftRadius: (isStart || detached) ? control.radiusBg : 0
|
|
topRightRadius: (isStart || detached) ? control.radiusBg : 0
|
|
bottomLeftRadius: (isEnd && !active) || (detached && !active) ? control.radiusBg : 0
|
|
bottomRightRadius: (isEnd && !active) || (detached && !active) ? control.radiusBg : 0
|
|
color: control.colorTitleBg
|
|
border.color: control.colorBorder
|
|
|
|
Loader {
|
|
id: __titleLoader
|
|
width: parent.width
|
|
sourceComponent: titleDelegate
|
|
property alias model: __rootItem.model
|
|
property alias index: __rootItem.index
|
|
property alias isActive: __rootItem.active
|
|
|
|
HoverHandler {
|
|
cursorShape: Qt.PointingHandCursor
|
|
}
|
|
|
|
TapHandler {
|
|
onTapped: {
|
|
if (control.accordion) {
|
|
for (let i = 0; i < __listView.count; i++) {
|
|
const item = __listView.itemAtIndex(i);
|
|
if (item && item !== __rootItem) {
|
|
item.active = false;
|
|
}
|
|
}
|
|
__rootItem.active = !__rootItem.active;
|
|
} else {
|
|
__rootItem.active = !__rootItem.active;
|
|
}
|
|
if (__rootItem.active)
|
|
control.actived(__rootItem.model.key);
|
|
__private.calcActiveKey();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
DelRectangle {
|
|
width: parent.width - __rootItem.border.width * 2
|
|
height: active ? __contentLoader.height : 0
|
|
anchors.horizontalCenter: parent.horizontalCenter
|
|
bottomLeftRadius: control.radiusBg
|
|
bottomRightRadius: control.radiusBg
|
|
color: control.colorContentBg
|
|
clip: true
|
|
|
|
Behavior on height { enabled: control.animationEnabled; NumberAnimation { duration: DelTheme.Primary.durationFast } }
|
|
|
|
Loader {
|
|
id: __contentLoader
|
|
width: parent.width
|
|
anchors.centerIn: parent
|
|
sourceComponent: contentDelegate
|
|
property alias model: __rootItem.model
|
|
property alias index: __rootItem.index
|
|
property alias isActive: __rootItem.active
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
Loader {
|
|
anchors.fill: __listView
|
|
active: spacing === -1
|
|
sourceComponent: Rectangle {
|
|
color: "transparent"
|
|
border.color: control.colorBorder
|
|
radius: control.radiusBg
|
|
}
|
|
}
|
|
}
|