Files
FluentUI/src/Qt5/imports/FluentUI/Controls/FluTabView.qml
朱子楚\zhuzi cc4e88adbd update
2024-01-02 22:55:17 +08:00

299 lines
12 KiB
QML

import QtQuick 2.15
import QtQuick.Controls 2.15
import QtQuick.Layouts 1.15
import FluentUI 1.0
Item {
property int tabWidthBehavior : FluTabViewType.Equal
property int closeButtonVisibility : FluTabViewType.Always
property int itemWidth: 146
property bool addButtonVisibility: true
signal newPressed
id:control
implicitHeight: height
implicitWidth: width
anchors.fill: {
if(parent)
return parent
return undefined
}
QtObject {
id: d
property int dragIndex: -1
property bool dragBehavior: false
property bool itemPress: false
property int maxEqualWidth: 240
}
MouseArea{
anchors.fill: parent
preventStealing: true
}
ListModel{
id:tab_model
}
FluIconButton{
id:btn_new
visible: addButtonVisibility
width: 34
height: 34
x:Math.min(tab_nav.contentWidth,tab_nav.width)
anchors.top: parent.top
iconSource: FluentIcons.Add
onClicked: {
newPressed()
}
}
ListView{
id:tab_nav
height: 34
orientation: ListView.Horizontal
anchors{
top: parent.top
left: parent.left
right: parent.right
rightMargin: 34
}
interactive: false
model: tab_model
move: Transition {
NumberAnimation { properties: "x"; duration: 100; easing.type: Easing.OutCubic }
NumberAnimation { properties: "y"; duration: 100; easing.type: Easing.OutCubic }
}
moveDisplaced: Transition {
NumberAnimation { properties: "x"; duration: 300; easing.type: Easing.OutCubic}
NumberAnimation { properties: "y"; duration: 100; easing.type: Easing.OutCubic }
}
clip: true
ScrollBar.horizontal: ScrollBar{
id: scroll_nav
policy: ScrollBar.AlwaysOff
}
delegate: Item{
width: item_layout.width
height: item_container.height
z: item_mouse_drag.pressed ? 1000 : 1
Item{
id:item_layout
width: item_container.width
height: item_container.height
Item{
id:item_container
property real timestamp: new Date().getTime()
height: tab_nav.height
width: {
if(tabWidthBehavior === FluTabViewType.Equal){
return Math.max(Math.min(d.maxEqualWidth,tab_nav.width/tab_nav.count),41 + item_btn_close.width)
}
if(tabWidthBehavior === FluTabViewType.SizeToContent){
return itemWidth
}
if(tabWidthBehavior === FluTabViewType.Compact){
return item_mouse_hove.containsMouse || item_btn_close.hovered || tab_nav.currentIndex === index ? itemWidth : 41 + item_btn_close.width
}
return Math.max(Math.min(d.maxEqualWidth,tab_nav.width/tab_nav.count),41 + item_btn_close.width)
}
Behavior on x { enabled: d.dragBehavior; NumberAnimation { duration: 200 } }
Behavior on y { enabled: d.dragBehavior; NumberAnimation { duration: 200 } }
MouseArea{
id:item_mouse_hove
anchors.fill: parent
hoverEnabled: true
}
FluTooltip{
visible: item_mouse_hove.containsMouse
text:item_text.text
delay: 1000
}
MouseArea{
id:item_mouse_drag
anchors.fill: parent
drag.target: item_container
drag.axis: Drag.XAxis
onWheel: (wheel)=>{
if (wheel.angleDelta.y > 0) scroll_nav.decrease()
else scroll_nav.increase()
}
onPressed: {
d.itemPress = true
item_container.timestamp = new Date().getTime();
d.dragBehavior = false;
var pos = tab_nav.mapFromItem(item_container, 0, 0)
d.dragIndex = model.index
item_container.parent = tab_nav
item_container.x = pos.x
item_container.y = pos.y
}
onReleased: {
d.itemPress = false
timer.stop()
var timeDiff = new Date().getTime() - item_container.timestamp
if (timeDiff < 300) {
tab_nav.currentIndex = index
}
d.dragIndex = -1;
var pos = tab_nav.mapToItem(item_layout, item_container.x, item_container.y)
item_container.parent = item_layout;
item_container.x = pos.x;
item_container.y = pos.y;
d.dragBehavior = true;
item_container.x = 0;
item_container.y = 0;
}
onPositionChanged: {
var pos = tab_nav.mapFromItem(item_container, 0, 0)
updatePosition(pos)
if(pos.x<0){
timer.isIncrease = false
timer.restart()
}else if(pos.x>tab_nav.width-itemWidth){
timer.isIncrease = true
timer.restart()
}else{
timer.stop()
}
}
Timer{
id:timer
property bool isIncrease: true
interval: 10
repeat: true
onTriggered: {
if(isIncrease){
if(tab_nav.contentX>=tab_nav.contentWidth-tab_nav.width){
return
}
tab_nav.contentX = tab_nav.contentX+2
}else{
if(tab_nav.contentX<=0){
return
}
tab_nav.contentX = tab_nav.contentX-2
}
item_mouse_drag.updatePosition(tab_nav.mapFromItem(item_container, 0, 0))
}
}
function updatePosition(pos){
var idx = tab_nav.indexAt(pos.x+tab_nav.contentX+1, pos.y)
var firstIdx = tab_nav.indexAt(tab_nav.contentX+1, pos.y)
var lastIdx = tab_nav.indexAt(tab_nav.width+tab_nav.contentX-1, pos.y)
if(lastIdx === -1){
lastIdx = tab_nav.count-1
}
if (idx!==-1 && idx >= firstIdx && idx <= lastIdx && d.dragIndex !== idx) {
tab_model.move(d.dragIndex, idx, 1)
d.dragIndex = idx;
}
}
}
FluRectangle{
anchors.fill: parent
radius: [6,6,0,0]
color: {
if(item_mouse_hove.containsMouse || item_btn_close.hovered){
return FluTheme.itemHoverColor
}
if(tab_nav.currentIndex === index){
return FluTheme.itemCheckColor
}
return FluTheme.itemNormalColor
}
}
RowLayout{
spacing: 0
height: parent.height
Image{
source:model.icon
Layout.leftMargin: 10
Layout.preferredWidth: 14
Layout.preferredHeight: 14
Layout.alignment: Qt.AlignVCenter
}
FluText{
id:item_text
text: model.text
Layout.leftMargin: 10
visible: {
if(tabWidthBehavior === FluTabViewType.Equal){
return true
}
if(tabWidthBehavior === FluTabViewType.SizeToContent){
return true
}
if(tabWidthBehavior === FluTabViewType.Compact){
return item_mouse_hove.containsMouse || item_btn_close.hovered || tab_nav.currentIndex === index
}
return false
}
Layout.preferredWidth: visible?item_container.width - 41 - item_btn_close.width:0
elide: Text.ElideRight
Layout.alignment: Qt.AlignVCenter
}
}
FluIconButton{
id:item_btn_close
iconSource: FluentIcons.ChromeClose
iconSize: 10
width: visible ? 24 : 0
height: 24
visible: {
if(closeButtonVisibility === FluTabViewType.Never)
return false
if(closeButtonVisibility === FluTabViewType.OnHover)
return item_mouse_hove.containsMouse || item_btn_close.hovered
return true
}
anchors{
right: parent.right
rightMargin: 5
verticalCenter: parent.verticalCenter
}
onClicked: {
tab_model.remove(index)
}
}
FluDivider{
width: 1
height: 16
orientation: Qt.Vertical
anchors{
verticalCenter: parent.verticalCenter
right: parent.right
}
}
}
}
}
}
Item{
id:container
anchors{
top: tab_nav.bottom
left: parent.left
right: parent.right
bottom: parent.bottom
}
Repeater{
model:tab_model
FluLoader{
property var argument: model.argument
anchors.fill: parent
sourceComponent: model.page
visible: tab_nav.currentIndex === index
}
}
}
function createTab(icon,text,page,argument={}){
return {icon:icon,text:text,page:page,argument:argument}
}
function appendTab(icon,text,page,argument){
tab_model.append(createTab(icon,text,page,argument))
}
function setTabList(list){
tab_model.clear()
tab_model.append(list)
}
function count(){
return tab_nav.count
}
}