FluentUI/src/controls/FluTreeView.qml

318 lines
11 KiB
QML
Raw Normal View History

2023-03-07 00:05:27 +08:00
import QtQuick 2.15
import QtQuick.Window 2.15
import QtQuick.Layouts 1.15
2023-03-07 18:43:03 +08:00
import QtQuick.Controls 2.15
2023-03-07 00:05:27 +08:00
import FluentUI 1.0
import QtGraphicalEffects 1.15
2023-03-10 18:08:32 +08:00
Item {
2023-03-07 00:05:27 +08:00
id:root
2023-03-07 23:27:32 +08:00
enum TreeViewSelectionMode {
None,
Single,
Multiple
}
property int selectionMode: FluTreeView.None
property var currentElement
property var currentParentElement
property var rootModel: tree_model.get(0).items
signal itemClicked(var item)
ListModel{
id:tree_model
ListElement{
text: "根节点"
2023-03-07 18:43:03 +08:00
expanded:true
2023-03-08 13:41:43 +08:00
items:[]
2023-03-08 11:46:40 +08:00
key:"123456"
multipSelected:false
2023-03-08 13:41:43 +08:00
multipIndex:0
multipParentKey:""
2023-03-07 18:43:03 +08:00
}
2023-03-07 00:05:27 +08:00
}
2023-03-07 23:27:32 +08:00
Component{
id: delegate_root
Column{
width: calculateWidth()
property var itemModel: model
Repeater{
id: repeater_first_level
model: items
delegate: delegate_items
}
function calculateWidth(){
var w = 0;
for(var i = 0; i < repeater_first_level.count; i++) {
var child = repeater_first_level.itemAt(i)
if(w < child.width_hint){
w = child.width_hint;
}
}
return w;
}
}
}
2023-03-07 18:43:03 +08:00
Component{
2023-03-07 23:27:32 +08:00
id:delegate_items
Column{
id:item_layout
2023-03-07 18:43:03 +08:00
2023-03-07 23:27:32 +08:00
property real level: (mapToItem(list_root,0,0).x+list_root.contentX)/0.001
property var text: model.text??"Item"
2023-03-08 11:46:40 +08:00
property bool hasChild : (model.items !== undefined) && (model.items.count !== 0)
2023-03-07 23:27:32 +08:00
property var items: model.items??[]
property var expanded: model.expanded??true
property int width_hint: calculateWidth()
property bool singleSelected: currentElement === model
2023-03-07 18:43:03 +08:00
property var itemModel: model
2023-03-07 23:27:32 +08:00
function calculateWidth(){
var w = Math.max(list_root.width, item_layout_row.implicitWidth + 10);
if(expanded){
for(var i = 0; i < repeater_items.count; i++) {
var child = repeater_items.itemAt(i)
if(w < child.width_hint){
w = child.width_hint;
}
}
}
return w;
}
2023-03-07 18:43:03 +08:00
Item{
2023-03-07 23:27:32 +08:00
id:item_layout_rect
width: list_root.contentWidth
height: item_layout_row.implicitHeight
2023-03-07 00:05:27 +08:00
2023-03-07 18:43:03 +08:00
Rectangle{
2023-03-07 23:27:32 +08:00
anchors.fill: parent
2023-03-07 18:43:03 +08:00
anchors.margins: 2
color:{
if(FluTheme.isDark){
2023-03-07 23:27:32 +08:00
if(item_layout.singleSelected && selectionMode === FluTreeView.Single){
return Qt.rgba(62/255,62/255,62/255,1)
}
2023-03-10 18:08:32 +08:00
return (item_layout_mouse.containsMouse || item_layout_expanded.hovered || item_layout_checkbox.hovered)?Qt.rgba(62/255,62/255,62/255,1):Qt.rgba(0,0,0,0)
2023-03-07 18:43:03 +08:00
}else{
2023-03-07 23:27:32 +08:00
if(item_layout.singleSelected && selectionMode === FluTreeView.Single){
2023-03-10 18:08:32 +08:00
return Qt.rgba(0,0,0,0.06)
2023-03-07 23:27:32 +08:00
}
2023-03-10 18:08:32 +08:00
return (item_layout_mouse.containsMouse || item_layout_expanded.hovered || item_layout_checkbox.hovered)?Qt.rgba(0,0,0,0.03):Qt.rgba(0,0,0,0)
2023-03-07 18:43:03 +08:00
}
}
2023-03-07 00:05:27 +08:00
2023-03-07 23:27:32 +08:00
Rectangle{
width: 3
color:FluTheme.primaryColor.dark
visible: item_layout.singleSelected && (selectionMode === FluTreeView.Single)
radius: 3
height: 20
anchors{
left: parent.left
verticalCenter: parent.verticalCenter
}
}
2023-03-07 18:43:03 +08:00
MouseArea{
id:item_layout_mouse
anchors.fill: parent
hoverEnabled: true
onClicked: {
2023-03-07 23:27:32 +08:00
item_layout_rect.onClickItem()
}
}
}
function onClickItem(){
if(selectionMode === FluTreeView.None){
itemClicked(model)
}
if(selectionMode === FluTreeView.Single){
currentElement = model
if(item_layout.parent.parent.parent.itemModel){
currentParentElement = item_layout.parent.parent.parent.itemModel
}else{
if(item_layout.parent.itemModel){
currentParentElement = item_layout.parent.itemModel
}
2023-03-07 18:43:03 +08:00
}
}
2023-03-07 23:27:32 +08:00
if(selectionMode === FluTreeView.Multiple){
}
2023-03-07 18:43:03 +08:00
}
2023-03-07 00:05:27 +08:00
2023-03-07 18:43:03 +08:00
RowLayout{
2023-03-07 23:27:32 +08:00
id:item_layout_row
anchors.verticalCenter: item_layout_rect.verticalCenter
2023-03-07 18:43:03 +08:00
Item{
width: 15*level
Layout.alignment: Qt.AlignVCenter
}
2023-03-07 23:27:32 +08:00
FluCheckBox{
2023-03-08 11:46:40 +08:00
id:item_layout_checkbox
2023-03-07 23:27:32 +08:00
text:""
2023-03-08 11:46:40 +08:00
checked: itemModel.multipSelected
2023-03-07 23:27:32 +08:00
visible: selectionMode === FluTreeView.Multiple
2023-03-08 13:41:43 +08:00
Layout.leftMargin: 5
function refreshCheckBox(){
const stack = [tree_model.get(0)];
const result = [];
while (stack.length > 0) {
const curr = stack.pop();
result.unshift(curr);
if (curr.items) {
for(var i=0 ; i<curr.items.count ; i++){
curr.items.setProperty(i,"multipIndex",i)
curr.items.setProperty(i,"multipParentKey",curr.key)
stack.push(curr.items.get(i));
}
}
}
for(var j=0 ; j<result.length-1 ; j++){
var item = result[j]
let obj = result.find(function(o) {
return o.key === item.multipParentKey;
});
if((item.items !== undefined) && (item.items.count !== 0)){
var items = item.items
for(var k=0 ; k<items.count ; k++){
if(items.get(k).multipSelected === false){
obj.items.setProperty(item.multipIndex,"multipSelected",false)
break
}
obj.items.setProperty(item.multipIndex,"multipSelected",true)
}
}
}
}
checkClicked:function(){
if(hasChild){
const stack = [itemModel];
2023-03-08 11:46:40 +08:00
while (stack.length > 0) {
const curr = stack.pop();
if (curr.items) {
for(var i=0 ; i<curr.items.count ; i++){
2023-03-08 13:41:43 +08:00
curr.items.setProperty(i,"multipSelected",!itemModel.multipSelected)
2023-03-08 11:46:40 +08:00
stack.push(curr.items.get(i));
}
}
}
2023-03-08 13:41:43 +08:00
refreshCheckBox()
}else{
itemModel.multipSelected = !itemModel.multipSelected
refreshCheckBox()
2023-03-07 23:27:32 +08:00
}
}
}
2023-03-07 18:43:03 +08:00
FluIconButton{
id:item_layout_expanded
color:"#00000000"
2023-03-07 23:27:32 +08:00
icon:item_layout.expanded?FluentIcons.FA_angle_down:FluentIcons.FA_angle_right
2023-03-08 11:46:40 +08:00
opacity: item_layout.hasChild
2023-03-07 18:43:03 +08:00
onClicked: {
2023-03-08 11:46:40 +08:00
if(!item_layout.hasChild){
2023-03-07 23:27:32 +08:00
item_layout_rect.onClickItem()
return
}
2023-03-07 18:43:03 +08:00
model.expanded = !model.expanded
}
}
2023-03-07 23:27:32 +08:00
FluText {
text: item_layout.text
2023-03-07 18:43:03 +08:00
Layout.alignment: Qt.AlignVCenter
2023-03-09 23:11:59 +08:00
topPadding: 7
bottomPadding: 7
2023-03-07 18:43:03 +08:00
}
}
}
2023-03-07 23:27:32 +08:00
2023-03-07 18:43:03 +08:00
Item{
2023-03-07 23:27:32 +08:00
id:item_sub
visible: {
2023-03-08 11:46:40 +08:00
if(!hasChild){
2023-03-07 23:27:32 +08:00
return false
}
return item_layout.expanded??false
}
width: item_sub_layout.implicitWidth
height: item_sub_layout.implicitHeight
x:0.001
Column{
id: item_sub_layout
Repeater{
id:repeater_items
model: item_layout.items
delegate: delegate_items
}
2023-03-07 18:43:03 +08:00
}
}
}
2023-03-07 00:05:27 +08:00
}
2023-03-07 23:27:32 +08:00
ListView {
id: list_root
2023-03-07 18:43:03 +08:00
anchors.fill: parent
2023-03-07 23:27:32 +08:00
delegate: delegate_root
boundsBehavior: ListView.StopAtBounds
contentWidth: contentItem.childrenRect.width
model: tree_model
flickableDirection: Flickable.HorizontalAndVerticalFlick
2023-03-07 18:43:03 +08:00
clip: true
2023-03-07 23:27:32 +08:00
ScrollBar.vertical: ScrollBar { }
ScrollBar.horizontal: ScrollBar { }
}
function updateData(items){
rootModel.clear()
rootModel.append(items)
}
function signleData(){
return currentElement
}
function multipData(){
2023-03-08 13:41:43 +08:00
const stack = [tree_model.get(0)];
const result = [];
while (stack.length > 0) {
const curr = stack.pop();
if(curr.multipSelected){
result.push(curr)
}
for(var i=0 ; i<curr.items.count ; i++){
stack.push(curr.items.get(i));
}
}
return result
2023-03-07 23:27:32 +08:00
}
function createItem(text="Title",expanded=true,items=[]){
2023-03-08 13:41:43 +08:00
return {text:text,expanded:expanded,items:items,key:uniqueRandom(),multipSelected:false,multipIndex:0,multipParentKey:""};
2023-03-07 18:43:03 +08:00
}
2023-03-07 00:05:27 +08:00
2023-03-08 11:46:40 +08:00
function uniqueRandom() {
var timestamp = Date.now();
var random = Math.floor(Math.random() * 1000000);
return timestamp.toString() + random.toString();
}
2023-03-07 00:05:27 +08:00
}