diff --git a/example/qml/page/T_TreeView.qml b/example/qml/page/T_TreeView.qml index b817173b..910615f5 100644 --- a/example/qml/page/T_TreeView.qml +++ b/example/qml/page/T_TreeView.qml @@ -102,6 +102,18 @@ FluScrollablePage { text:"draggable" checked: true } + FluButton{ + text:"all expand" + onClicked: { + tree_view.allExpand() + } + } + FluButton{ + text:"all collapse" + onClicked: { + tree_view.allCollapse() + } + } } } CodeExpander{ @@ -119,4 +131,3 @@ FluScrollablePage { ' } } - diff --git a/src/FluTreeModel.cpp b/src/FluTreeModel.cpp index c94330e4..b5b3122a 100644 --- a/src/FluTreeModel.cpp +++ b/src/FluTreeModel.cpp @@ -200,8 +200,12 @@ void FluTreeModel::dragAnddrop(int dragIndex,int dropIndex,bool isDropTopArea){ } } srcChildren->removeAt(srcIndex); - destChildren->insert(destIndex+1,dragItem); - int offset = 1; + int offset = 0; + if(!isDropTopArea){ + offset = offset + 1; + } + destChildren->insert(destIndex+offset,dragItem); + offset = 1; if(isDropTopArea){ offset = offset - 1; } @@ -211,10 +215,10 @@ void FluTreeModel::dragAnddrop(int dragIndex,int dropIndex,bool isDropTopArea){ } bool FluTreeModel::hitHasChildrenExpanded(int row){ - auto itemData = _rows.at(row); - if(itemData->hasChildren() && itemData->_isExpanded){ - return true; - } +// auto itemData = _rows.at(row); +// if(itemData->hasChildren() && itemData->_isExpanded){ +// return true; +// } return false; } diff --git a/src/Qt5/imports/FluentUI/Controls/FluTreeView.qml b/src/Qt5/imports/FluentUI/Controls/FluTreeView.qml index c91f16a4..5368a8e9 100644 --- a/src/Qt5/imports/FluentUI/Controls/FluTreeView.qml +++ b/src/Qt5/imports/FluentUI/Controls/FluTreeView.qml @@ -16,10 +16,13 @@ Item { id:d property var current property int dropIndex: -1 + property var hoverItem + property int hoverIndex: -1 + property bool itemPress: false + property bool itemDragActive: false property bool isDropTopArea: false property int dragIndex: -1 property color hitColor: FluTheme.dark ? FluTheme.primaryColor.lighter : FluTheme.primaryColor.dark - } onDataSourceChanged: { tree_model.setDataSource(dataSource) @@ -41,6 +44,7 @@ Item { signal pooled onReused: { + console.debug(itemModel.title) } onPooled: { } @@ -83,6 +87,7 @@ Item { drag.target:control.draggable ? loader_container : undefined hoverEnabled: true drag.onActiveChanged: { + d.itemDragActive = drag.active if(drag.active){ if(itemModel.isExpanded && itemModel.hasChildren()){ tree_model.collapse(rowIndex) @@ -93,6 +98,7 @@ Item { } onPressed: (mouse)=>{ + d.itemPress = true clickPos = Qt.point(mouse.x,mouse.y) console.debug(clickPos) loader_container.itemControl = itemControl @@ -100,8 +106,8 @@ Item { var cellPosition = item_container.mapToItem(table_view, 0, 0) loader_container.width = item_container.width loader_container.height = item_container.height - loader_container.x = table_view.contentX + cellPosition.x - loader_container.y = table_view.contentY + cellPosition.y + loader_container.x = cellPosition.x + loader_container.y = cellPosition.y } onClicked: { d.current = itemModel @@ -111,17 +117,21 @@ Item { item_container.toggle() } } + onExited: { + d.hoverIndex = -1 + } onPositionChanged: (mouse)=> { - if(!drag.active){ - return - } var cellPosition = item_container.mapToItem(table_view, 0, 0) if(mouse.y+cellPosition.y<0 || mouse.y+cellPosition.y>table_view.height){ + d.hoverItem = undefined + d.hoverIndex = -1 d.dropIndex = -1 return } if((mouse.x-table_view.contentX)>table_view.width || (mouse.x-table_view.contentX)<0){ + d.hoverItem = undefined + d.hoverIndex = -1 d.dropIndex = -1 return } @@ -129,6 +139,16 @@ Item { var viewPos = table_view.mapToGlobal(0,0) var y = table_view.contentY + pos.y-viewPos.y var index = Math.floor(y/30) + if(item_mouse.pressed){ + d.hoverItem = undefined + d.hoverIndex = -1 + }else{ + d.hoverItem = item_container + d.hoverIndex = index + } + if(!drag.active){ + return + } if(tree_model.hitHasChildrenExpanded(index) && y>index*30+15){ d.dropIndex = index + 1 d.isDropTopArea = true @@ -143,10 +163,12 @@ Item { } onCanceled: { loader_container.sourceComponent = undefined + d.itemPress = false d.dropIndex = -1 d.dragIndex = -1 } onReleased: { + d.itemPress = false loader_container.sourceComponent = undefined if(d.dropIndex !== -1){ tree_model.dragAnddrop(d.dragIndex,d.dropIndex,d.isDropTopArea) @@ -155,6 +177,7 @@ Item { d.dragIndex = -1 } } + Drag.dragType: Drag.None Drag.active: item_mouse.drag.active Rectangle{ id:item_line_drop_tip @@ -255,17 +278,11 @@ Item { if(isCurrent){ return Qt.rgba(1,1,1,0.03) } - if(item_mouse.containsMouse){ - return Qt.rgba(1,1,1,0.03) - } return Qt.rgba(0,0,0,0) }else{ if(isCurrent){ return Qt.rgba(0,0,0,0.06) } - if(item_mouse.containsMouse){ - return Qt.rgba(0,0,0,0.03) - } return Qt.rgba(0,0,0,0) } } @@ -275,18 +292,26 @@ Item { anchors.verticalCenter: parent.verticalCenter anchors.left: parent.left anchors.leftMargin: 14 + 30*itemModel.depth - FluIconButton{ + Item{ + opacity: itemModel.hasChildren() Layout.preferredWidth: 20 Layout.preferredHeight: 20 - enabled: opacity - opacity: itemModel.hasChildren() - contentItem: FluIcon{ + TapHandler{ + enabled: parent.opacity + onSingleTapped: { + item_container.toggle() + } + } + MouseArea{ + cursorShape: Qt.PointingHandCursor + acceptedButtons: Qt.NoButton + anchors.fill: parent + } + FluIcon{ rotation: itemModel.isExpanded?0:-90 iconSource:FluentIcons.ChevronDown iconSize: 16 - } - onClicked: { - item_container.toggle() + anchors.centerIn: parent } } Item{ @@ -299,9 +324,6 @@ Item { text: itemModel.title anchors.centerIn: parent color:{ - if(item_mouse.pressed){ - return FluTheme.dark ? FluColors.Grey80 : FluColors.Grey120 - } return FluTheme.dark ? FluColors.White : FluColors.Grey220 } } @@ -309,10 +331,65 @@ Item { } } } + Component{ + id:com_background + Item{ + Rectangle{ + radius: 4 + anchors{ + fill: parent + leftMargin: 6 + rightMargin: 6 + } + color:{ + if(FluTheme.dark){ + if(d.itemPress){ + return Qt.rgba(1,1,1,0.06) + } + return Qt.rgba(1,1,1,0.03) + }else{ + if(d.itemPress){ + return Qt.rgba(0,0,0,0.06) + } + return Qt.rgba(0,0,0,0.03) + } + } + } + } + } ScrollView{ + id:scroll_view anchors.fill: parent ScrollBar.horizontal.policy: ScrollBar.AlwaysOff ScrollBar.vertical.policy: ScrollBar.AlwaysOff + Loader{ + id:loader_background + y:{ + if(d.hoverItem){ + var cellPosition = d.hoverItem.mapToItem(table_view, 0, 0) + return cellPosition.y + } + return 0 + } + width: { + if(d.hoverItem){ + return d.hoverItem.width + } + return 0 + } + height: { + if(d.hoverItem){ + return d.hoverItem.height + } + return 0 + } + sourceComponent: { + if(d.hoverIndex === -1 || d.itemDragActive){ + return undefined + } + return com_background + } + } TableView{ id:table_view ScrollBar.horizontal: FluScrollBar{} @@ -360,4 +437,17 @@ Item { function visibleCount(){ return table_view.rows } + function collapse(rowIndex){ + tree_model.collapse(rowIndex) + } + function expand(rowIndex){ + tree_model.expand(rowIndex) + } + function allExpand(){ + tree_model.allExpand() + } + function allCollapse(){ + tree_model.allCollapse() + } + } diff --git a/src/Qt6/imports/FluentUI/Controls/FluTreeView.qml b/src/Qt6/imports/FluentUI/Controls/FluTreeView.qml index 02f7c345..4b41d1d7 100644 --- a/src/Qt6/imports/FluentUI/Controls/FluTreeView.qml +++ b/src/Qt6/imports/FluentUI/Controls/FluTreeView.qml @@ -16,10 +16,13 @@ Item { id:d property var current property int dropIndex: -1 + property var hoverItem + property int hoverIndex: -1 + property bool itemPress: false + property bool itemDragActive: false property bool isDropTopArea: false property int dragIndex: -1 property color hitColor: FluTheme.dark ? FluTheme.primaryColor.lighter : FluTheme.primaryColor.dark - } onDataSourceChanged: { tree_model.setDataSource(dataSource) @@ -41,6 +44,7 @@ Item { signal pooled onReused: { + console.debug(itemModel.title) } onPooled: { } @@ -83,6 +87,7 @@ Item { drag.target:control.draggable ? loader_container : undefined hoverEnabled: true drag.onActiveChanged: { + d.itemDragActive = drag.active if(drag.active){ if(itemModel.isExpanded && itemModel.hasChildren()){ tree_model.collapse(rowIndex) @@ -93,6 +98,7 @@ Item { } onPressed: (mouse)=>{ + d.itemPress = true clickPos = Qt.point(mouse.x,mouse.y) console.debug(clickPos) loader_container.itemControl = itemControl @@ -100,8 +106,8 @@ Item { var cellPosition = item_container.mapToItem(table_view, 0, 0) loader_container.width = item_container.width loader_container.height = item_container.height - loader_container.x = table_view.contentX + cellPosition.x - loader_container.y = table_view.contentY + cellPosition.y + loader_container.x = cellPosition.x + loader_container.y = cellPosition.y } onClicked: { d.current = itemModel @@ -111,17 +117,21 @@ Item { item_container.toggle() } } + onExited: { + d.hoverIndex = -1 + } onPositionChanged: (mouse)=> { - if(!drag.active){ - return - } var cellPosition = item_container.mapToItem(table_view, 0, 0) if(mouse.y+cellPosition.y<0 || mouse.y+cellPosition.y>table_view.height){ + d.hoverItem = undefined + d.hoverIndex = -1 d.dropIndex = -1 return } if((mouse.x-table_view.contentX)>table_view.width || (mouse.x-table_view.contentX)<0){ + d.hoverItem = undefined + d.hoverIndex = -1 d.dropIndex = -1 return } @@ -129,6 +139,16 @@ Item { var viewPos = table_view.mapToGlobal(0,0) var y = table_view.contentY + pos.y-viewPos.y var index = Math.floor(y/30) + if(item_mouse.pressed){ + d.hoverItem = undefined + d.hoverIndex = -1 + }else{ + d.hoverItem = item_container + d.hoverIndex = index + } + if(!drag.active){ + return + } if(tree_model.hitHasChildrenExpanded(index) && y>index*30+15){ d.dropIndex = index + 1 d.isDropTopArea = true @@ -143,10 +163,12 @@ Item { } onCanceled: { loader_container.sourceComponent = undefined + d.itemPress = false d.dropIndex = -1 d.dragIndex = -1 } onReleased: { + d.itemPress = false loader_container.sourceComponent = undefined if(d.dropIndex !== -1){ tree_model.dragAnddrop(d.dragIndex,d.dropIndex,d.isDropTopArea) @@ -155,6 +177,7 @@ Item { d.dragIndex = -1 } } + Drag.dragType: Drag.None Drag.active: item_mouse.drag.active Rectangle{ id:item_line_drop_tip @@ -255,17 +278,11 @@ Item { if(isCurrent){ return Qt.rgba(1,1,1,0.03) } - if(item_mouse.containsMouse){ - return Qt.rgba(1,1,1,0.03) - } return Qt.rgba(0,0,0,0) }else{ if(isCurrent){ return Qt.rgba(0,0,0,0.06) } - if(item_mouse.containsMouse){ - return Qt.rgba(0,0,0,0.03) - } return Qt.rgba(0,0,0,0) } } @@ -275,18 +292,26 @@ Item { anchors.verticalCenter: parent.verticalCenter anchors.left: parent.left anchors.leftMargin: 14 + 30*itemModel.depth - FluIconButton{ + Item{ + opacity: itemModel.hasChildren() Layout.preferredWidth: 20 Layout.preferredHeight: 20 - enabled: opacity - opacity: itemModel.hasChildren() - contentItem: FluIcon{ + TapHandler{ + enabled: parent.opacity + onSingleTapped: { + item_container.toggle() + } + } + MouseArea{ + cursorShape: Qt.PointingHandCursor + acceptedButtons: Qt.NoButton + anchors.fill: parent + } + FluIcon{ rotation: itemModel.isExpanded?0:-90 iconSource:FluentIcons.ChevronDown iconSize: 16 - } - onClicked: { - item_container.toggle() + anchors.centerIn: parent } } Item{ @@ -299,9 +324,6 @@ Item { text: itemModel.title anchors.centerIn: parent color:{ - if(item_mouse.pressed){ - return FluTheme.dark ? FluColors.Grey80 : FluColors.Grey120 - } return FluTheme.dark ? FluColors.White : FluColors.Grey220 } } @@ -309,10 +331,65 @@ Item { } } } + Component{ + id:com_background + Item{ + Rectangle{ + radius: 4 + anchors{ + fill: parent + leftMargin: 6 + rightMargin: 6 + } + color:{ + if(FluTheme.dark){ + if(d.itemPress){ + return Qt.rgba(1,1,1,0.06) + } + return Qt.rgba(1,1,1,0.03) + }else{ + if(d.itemPress){ + return Qt.rgba(0,0,0,0.06) + } + return Qt.rgba(0,0,0,0.03) + } + } + } + } + } ScrollView{ + id:scroll_view anchors.fill: parent ScrollBar.horizontal.policy: ScrollBar.AlwaysOff ScrollBar.vertical.policy: ScrollBar.AlwaysOff + Loader{ + id:loader_background + y:{ + if(d.hoverItem){ + var cellPosition = d.hoverItem.mapToItem(table_view, 0, 0) + return cellPosition.y + } + return 0 + } + width: { + if(d.hoverItem){ + return d.hoverItem.width + } + return 0 + } + height: { + if(d.hoverItem){ + return d.hoverItem.height + } + return 0 + } + sourceComponent: { + if(d.hoverIndex === -1 || d.itemDragActive){ + return undefined + } + return com_background + } + } TableView{ id:table_view ScrollBar.horizontal: FluScrollBar{}