mirror of
https://github.com/zhuzichu520/FluentUI.git
synced 2024-11-22 10:40:10 +08:00
update
This commit is contained in:
parent
6ebd659e13
commit
6a31e86505
@ -8,7 +8,7 @@ if(MSVC)
|
||||
set(CMAKE_EXE_LINKER_FLAGS_RELEASE "${CMAKE_EXE_LINKER_FLAGS_RELEASE} /DEBUG /OPT:REF /OPT:ICF")
|
||||
endif()
|
||||
|
||||
list(APPEND CMAKE_MODULE_PATH ${CMAKE_SOURCE_DIR}/.cmake/)
|
||||
list(APPEND CMAKE_MODULE_PATH ${CMAKE_CURRENT_LIST_DIR}/.cmake/)
|
||||
|
||||
include(GetGitRevisionDescription)
|
||||
|
||||
|
@ -475,46 +475,51 @@
|
||||
</message>
|
||||
<message>
|
||||
<location filename="qml/global/ItemsOriginal.qml" line="430"/>
|
||||
<source>QRCode</source>
|
||||
<source>CodeEditor</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="qml/global/ItemsOriginal.qml" line="436"/>
|
||||
<source>Tour</source>
|
||||
<source>QRCode</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="qml/global/ItemsOriginal.qml" line="442"/>
|
||||
<source>Timeline</source>
|
||||
<source>Tour</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="qml/global/ItemsOriginal.qml" line="448"/>
|
||||
<source>Captcha</source>
|
||||
<source>Timeline</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="qml/global/ItemsOriginal.qml" line="454"/>
|
||||
<source>Captcha</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="qml/global/ItemsOriginal.qml" line="460"/>
|
||||
<source>Network</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="qml/global/ItemsOriginal.qml" line="461"/>
|
||||
<location filename="qml/global/ItemsOriginal.qml" line="467"/>
|
||||
<source>Remote Loader</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="qml/global/ItemsOriginal.qml" line="475"/>
|
||||
<location filename="qml/global/ItemsOriginal.qml" line="481"/>
|
||||
<source>Hot Loader</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="qml/global/ItemsOriginal.qml" line="481"/>
|
||||
<location filename="qml/global/ItemsOriginal.qml" line="487"/>
|
||||
<source>3D</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="qml/global/ItemsOriginal.qml" line="487"/>
|
||||
<location filename="qml/global/ItemsOriginal.qml" line="493"/>
|
||||
<source>Test Crash</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
@ -2376,13 +2381,23 @@ Some contents...</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="qml/page/T_TreeView.qml" line="44"/>
|
||||
<source>Total %1 data, %2 data currently displayed</source>
|
||||
<location filename="qml/page/T_TreeView.qml" line="230"/>
|
||||
<source>Title</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="qml/page/T_TreeView.qml" line="48"/>
|
||||
<source>A total of %1 data items are selected</source>
|
||||
<location filename="qml/page/T_TreeView.qml" line="238"/>
|
||||
<source>Avatar</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="qml/page/T_TreeView.qml" line="242"/>
|
||||
<source>Address</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="qml/page/T_TreeView.qml" line="234"/>
|
||||
<source>Name</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
</context>
|
||||
|
@ -475,46 +475,51 @@
|
||||
</message>
|
||||
<message>
|
||||
<location filename="qml/global/ItemsOriginal.qml" line="430"/>
|
||||
<source>CodeEditor</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="qml/global/ItemsOriginal.qml" line="436"/>
|
||||
<source>QRCode</source>
|
||||
<translation type="unfinished">二维码</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="qml/global/ItemsOriginal.qml" line="436"/>
|
||||
<location filename="qml/global/ItemsOriginal.qml" line="442"/>
|
||||
<source>Tour</source>
|
||||
<translation type="unfinished">游览</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="qml/global/ItemsOriginal.qml" line="442"/>
|
||||
<location filename="qml/global/ItemsOriginal.qml" line="448"/>
|
||||
<source>Timeline</source>
|
||||
<translation type="unfinished">时间轴</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="qml/global/ItemsOriginal.qml" line="448"/>
|
||||
<location filename="qml/global/ItemsOriginal.qml" line="454"/>
|
||||
<source>Captcha</source>
|
||||
<translation type="unfinished">验证码</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="qml/global/ItemsOriginal.qml" line="454"/>
|
||||
<location filename="qml/global/ItemsOriginal.qml" line="460"/>
|
||||
<source>Network</source>
|
||||
<translation type="unfinished">网络</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="qml/global/ItemsOriginal.qml" line="461"/>
|
||||
<location filename="qml/global/ItemsOriginal.qml" line="467"/>
|
||||
<source>Remote Loader</source>
|
||||
<translation type="unfinished">远程加载</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="qml/global/ItemsOriginal.qml" line="475"/>
|
||||
<location filename="qml/global/ItemsOriginal.qml" line="481"/>
|
||||
<source>Hot Loader</source>
|
||||
<translation type="unfinished">热加载</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="qml/global/ItemsOriginal.qml" line="481"/>
|
||||
<location filename="qml/global/ItemsOriginal.qml" line="487"/>
|
||||
<source>3D</source>
|
||||
<translation type="unfinished">3D</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="qml/global/ItemsOriginal.qml" line="487"/>
|
||||
<location filename="qml/global/ItemsOriginal.qml" line="493"/>
|
||||
<source>Test Crash</source>
|
||||
<translation type="unfinished">测试崩溃</translation>
|
||||
</message>
|
||||
@ -2459,14 +2464,32 @@ Some contents...</source>
|
||||
<translation type="unfinished">树</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="qml/page/T_TreeView.qml" line="44"/>
|
||||
<source>Total %1 data, %2 data currently displayed</source>
|
||||
<translation type="unfinished">共计%1条数据,当前显示的%2条数据</translation>
|
||||
<translation type="obsolete">共计%1条数据,当前显示的%2条数据</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="qml/page/T_TreeView.qml" line="48"/>
|
||||
<source>A total of %1 data items are selected</source>
|
||||
<translation type="unfinished">共计选中%1条数据</translation>
|
||||
<translation type="obsolete">共计选中%1条数据</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="qml/page/T_TreeView.qml" line="230"/>
|
||||
<source>Title</source>
|
||||
<translation type="unfinished">标题</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="qml/page/T_TreeView.qml" line="242"/>
|
||||
<source>Address</source>
|
||||
<translation type="unfinished">地址</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="qml/page/T_TreeView.qml" line="238"/>
|
||||
<source>Avatar</source>
|
||||
<translation type="unfinished">头像</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="qml/page/T_TreeView.qml" line="234"/>
|
||||
<source>Name</source>
|
||||
<translation type="unfinished">名称</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
|
@ -426,6 +426,12 @@ FluObject{
|
||||
FluPaneItemExpander{
|
||||
title: qsTr("Other")
|
||||
icon: FluentIcons.Shop
|
||||
FluPaneItem{
|
||||
title: qsTr("CodeEditor")
|
||||
menuDelegate: paneItemMenu
|
||||
url: "qrc:/example/qml/page/T_CodeEditor.qml"
|
||||
onTap: { navigationView.push(url) }
|
||||
}
|
||||
FluPaneItem{
|
||||
title: qsTr("QRCode")
|
||||
menuDelegate: paneItemMenu
|
||||
|
@ -9,14 +9,34 @@ FluContentPage {
|
||||
|
||||
title: qsTr("TreeView")
|
||||
|
||||
|
||||
|
||||
function treeData(){
|
||||
const dig = (path = '0', level = 4) => {
|
||||
const names = ["孙悟空", "猪八戒", "沙和尚", "唐僧","白骨夫人","金角大王","熊山君","黄风怪","银角大王"]
|
||||
function getRandomName(){
|
||||
var randomIndex = Math.floor(Math.random() * names.length)
|
||||
return names[randomIndex]
|
||||
}
|
||||
const addresses = ["傲来国界花果山水帘洞","傲来国界坎源山脏水洞","大唐国界黑风山黑风洞","大唐国界黄风岭黄风洞","大唐国界骷髅山白骨洞","宝象国界碗子山波月洞","宝象国界平顶山莲花洞","宝象国界压龙山压龙洞","乌鸡国界号山枯松涧火云洞","乌鸡国界衡阳峪黑水河河神府"]
|
||||
function getRandomAddresses(){
|
||||
var randomIndex = Math.floor(Math.random() * addresses.length)
|
||||
return addresses[randomIndex]
|
||||
}
|
||||
const avatars = ["qrc:/example/res/svg/avatar_1.svg", "qrc:/example/res/svg/avatar_2.svg", "qrc:/example/res/svg/avatar_3.svg", "qrc:/example/res/svg/avatar_4.svg","qrc:/example/res/svg/avatar_5.svg","qrc:/example/res/svg/avatar_6.svg","qrc:/example/res/svg/avatar_7.svg","qrc:/example/res/svg/avatar_8.svg","qrc:/example/res/svg/avatar_9.svg","qrc:/example/res/svg/avatar_10.svg","qrc:/example/res/svg/avatar_11.svg","qrc:/example/res/svg/avatar_12.svg"]
|
||||
function getRandomAvatar(){
|
||||
var randomIndex = Math.floor(Math.random() * avatars.length);
|
||||
return avatars[randomIndex];
|
||||
}
|
||||
const dig = (path = '0', level = 5) => {
|
||||
const list = [];
|
||||
for (let i = 0; i < 6; i += 1) {
|
||||
for (let i = 0; i < 5; i += 1) {
|
||||
const key = `${path}-${i}`;
|
||||
const treeNode = {
|
||||
title: key,
|
||||
key,
|
||||
_key: key,
|
||||
name: getRandomName(),
|
||||
avatar:tree_view.customItem(com_avatar,{avatar:getRandomAvatar()}),
|
||||
address: getRandomAddresses()
|
||||
};
|
||||
if (level > 0) {
|
||||
treeNode.children = dig(key, level - 1);
|
||||
@ -28,26 +48,107 @@ FluContentPage {
|
||||
return dig();
|
||||
}
|
||||
|
||||
Column{
|
||||
id: layout_column
|
||||
spacing: 12
|
||||
width: 300
|
||||
// Row{
|
||||
// id: layout_column
|
||||
// spacing: 12
|
||||
// width: 340
|
||||
// anchors{
|
||||
// top:parent.top
|
||||
// left: parent.left
|
||||
// leftMargin: 10
|
||||
// bottom:parent.bottom
|
||||
// bottomMargin: 20
|
||||
// }
|
||||
// RowLayout{
|
||||
// spacing: 10
|
||||
// FluText{
|
||||
// text: "cellHeight:"
|
||||
// Layout.alignment: Qt.AlignVCenter
|
||||
// }
|
||||
// FluSlider{
|
||||
// id: slider_cell_height
|
||||
// value: 30
|
||||
// from: 30
|
||||
// to:100
|
||||
// }
|
||||
// }
|
||||
// RowLayout{
|
||||
// spacing: 10
|
||||
// FluText{
|
||||
// text: "depthPadding:"
|
||||
// Layout.alignment: Qt.AlignVCenter
|
||||
// }
|
||||
// FluSlider{
|
||||
// id: slider_depth_padding
|
||||
// value: 15
|
||||
// from: 15
|
||||
// to:100
|
||||
// }
|
||||
// }
|
||||
// FluToggleSwitch{
|
||||
// id: switch_showline
|
||||
// text:"showLine"
|
||||
// checked: false
|
||||
// }
|
||||
// FluToggleSwitch{
|
||||
// id: switch_checkable
|
||||
// text:"checkable"
|
||||
// checked: false
|
||||
// }
|
||||
// FluButton{
|
||||
// text: "all expand"
|
||||
// onClicked: {
|
||||
// tree_view.allExpand()
|
||||
// }
|
||||
// }
|
||||
// FluButton{
|
||||
// text: "all collapse"
|
||||
// onClicked: {
|
||||
// tree_view.allCollapse()
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
||||
Component{
|
||||
id:com_avatar
|
||||
Item{
|
||||
FluClip{
|
||||
anchors.centerIn: parent
|
||||
width: height
|
||||
height: parent.height/3*2
|
||||
radius: [height/2,height/2,height/2,height/2]
|
||||
Image{
|
||||
anchors.fill: parent
|
||||
source: {
|
||||
if(options && options.avatar){
|
||||
return options.avatar
|
||||
}
|
||||
return ""
|
||||
}
|
||||
sourceSize: Qt.size(80,80)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
FluFrame{
|
||||
id:layout_controls
|
||||
anchors{
|
||||
left: parent.left
|
||||
right: parent.right
|
||||
top: parent.top
|
||||
topMargin: 10
|
||||
}
|
||||
height: 80
|
||||
clip: true
|
||||
Row{
|
||||
spacing: 12
|
||||
anchors{
|
||||
left: parent.left
|
||||
leftMargin: 10
|
||||
bottom:parent.bottom
|
||||
bottomMargin: 20
|
||||
verticalCenter: parent.verticalCenter
|
||||
}
|
||||
|
||||
FluText{
|
||||
text: qsTr("Total %1 data, %2 data currently displayed").arg(tree_view.count()).arg(tree_view.visibleCount())
|
||||
}
|
||||
|
||||
FluText{
|
||||
text: qsTr("A total of %1 data items are selected").arg(tree_view.selectionModel().length)
|
||||
}
|
||||
|
||||
Column{
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
RowLayout{
|
||||
spacing: 10
|
||||
FluText{
|
||||
@ -56,8 +157,8 @@ FluContentPage {
|
||||
}
|
||||
FluSlider{
|
||||
id: slider_cell_height
|
||||
value: 30
|
||||
from: 30
|
||||
value: 38
|
||||
from: 38
|
||||
to:100
|
||||
}
|
||||
}
|
||||
@ -69,26 +170,29 @@ FluContentPage {
|
||||
}
|
||||
FluSlider{
|
||||
id: slider_depth_padding
|
||||
value: 30
|
||||
from: 30
|
||||
value: 15
|
||||
from: 15
|
||||
to:100
|
||||
}
|
||||
}
|
||||
}
|
||||
Column{
|
||||
spacing: 8
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
FluToggleSwitch{
|
||||
id: switch_showline
|
||||
text:"showLine"
|
||||
checked: false
|
||||
}
|
||||
FluToggleSwitch{
|
||||
id: switch_draggable
|
||||
text:"draggable"
|
||||
checked: false
|
||||
}
|
||||
FluToggleSwitch{
|
||||
id: switch_checkable
|
||||
text:"checkable"
|
||||
checked: false
|
||||
}
|
||||
}
|
||||
Column{
|
||||
spacing: 8
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
FluButton{
|
||||
text: "all expand"
|
||||
onClicked: {
|
||||
@ -102,25 +206,44 @@ FluContentPage {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
FluFrame{
|
||||
anchors{
|
||||
left: layout_column.right
|
||||
top: parent.top
|
||||
left: parent.left
|
||||
top: layout_controls.bottom
|
||||
topMargin: 10
|
||||
bottom: parent.bottom
|
||||
right: parent.right
|
||||
rightMargin: 5
|
||||
topMargin: 5
|
||||
bottomMargin: 5
|
||||
}
|
||||
FluShadow{}
|
||||
FluTreeView{
|
||||
id:tree_view
|
||||
anchors.fill: parent
|
||||
cellHeight: slider_cell_height.value
|
||||
draggable:switch_draggable.checked
|
||||
showLine: switch_showline.checked
|
||||
checkable:switch_checkable.checked
|
||||
depthPadding: slider_depth_padding.value
|
||||
columnSource:[
|
||||
{
|
||||
title: qsTr("Title"),
|
||||
dataIndex: 'title',
|
||||
width: 300
|
||||
},{
|
||||
title: qsTr("Name"),
|
||||
dataIndex: 'name',
|
||||
width: 100
|
||||
},{
|
||||
title: qsTr("Avatar"),
|
||||
dataIndex: 'avatar',
|
||||
width: 100
|
||||
},{
|
||||
title: qsTr("Address"),
|
||||
dataIndex: 'address',
|
||||
width: 200
|
||||
},
|
||||
]
|
||||
Component.onCompleted: {
|
||||
var data = treeData()
|
||||
dataSource = data
|
||||
|
@ -24,13 +24,15 @@ int FluTreeModel::rowCount(const QModelIndex &parent) const {
|
||||
};
|
||||
|
||||
int FluTreeModel::columnCount(const QModelIndex &parent) const {
|
||||
return 1;;
|
||||
return this->_columnSource.size();
|
||||
};
|
||||
|
||||
QVariant FluTreeModel::data(const QModelIndex &index, int role) const {
|
||||
switch (role) {
|
||||
case Qt::DisplayRole:
|
||||
case TreeModelRoles::RowModel:
|
||||
return QVariant::fromValue(_rows.at(index.row()));
|
||||
case TreeModelRoles::ColumnModel:
|
||||
return QVariant::fromValue(_columnSource.at(index.column()));
|
||||
default:
|
||||
break;
|
||||
}
|
||||
@ -38,7 +40,10 @@ QVariant FluTreeModel::data(const QModelIndex &index, int role) const {
|
||||
};
|
||||
|
||||
QHash<int, QByteArray> FluTreeModel::roleNames() const {
|
||||
return { {Qt::DisplayRole, "dataModel"} };
|
||||
return {
|
||||
{TreeModelRoles::RowModel, "rowModel"},
|
||||
{TreeModelRoles::ColumnModel, "columnModel"}
|
||||
};
|
||||
};
|
||||
|
||||
void FluTreeModel::setData(QList<FluTreeNode*> data){
|
||||
@ -76,6 +81,11 @@ QObject* FluTreeModel::getRow(int row){
|
||||
return _rows.at(row);
|
||||
}
|
||||
|
||||
void FluTreeModel::setRow(int row,QVariantMap data){
|
||||
_rows.at(row)->_data = data;
|
||||
Q_EMIT dataChanged(index(row,0),index(row,columnCount()-1));
|
||||
}
|
||||
|
||||
void FluTreeModel::checkRow(int row,bool checked){
|
||||
auto itemData = _rows.at(row);
|
||||
if(itemData->hasChildren()){
|
||||
@ -125,10 +135,9 @@ void FluTreeModel::setDataSource(QList<QMap<QString,QVariant>> data){
|
||||
auto item = data.at(data.count()-1);
|
||||
data.pop_back();
|
||||
FluTreeNode* node = new FluTreeNode(this);
|
||||
node->_title = item.value("title").toString();
|
||||
node->_key = item.value("key").toString();
|
||||
node->_depth = item.value("__depth").toInt();
|
||||
node->_parent = item.value("__parent").value<FluTreeNode*>();
|
||||
node->_data = item;
|
||||
node->_isExpanded = true;
|
||||
if(node->_parent){
|
||||
node->_parent->_children.append(node);
|
||||
@ -201,110 +210,6 @@ void FluTreeModel::expand(int row){
|
||||
insertRows(row+1,insertData);
|
||||
}
|
||||
|
||||
void FluTreeModel::dragAndDrop(int dragIndex,int dropIndex,bool isDropTopArea){
|
||||
if(dropIndex>_rows.count() || dropIndex<0){
|
||||
return;
|
||||
}
|
||||
auto dragItem = _rows[dragIndex];
|
||||
auto dropItem = _rows[dropIndex];
|
||||
int targetIndex;
|
||||
if(dropIndex > dragIndex){
|
||||
if(isDropTopArea){
|
||||
targetIndex = dropIndex;
|
||||
}else{
|
||||
targetIndex = dropIndex+1;
|
||||
}
|
||||
}else{
|
||||
if(isDropTopArea){
|
||||
targetIndex = dropIndex;
|
||||
}else{
|
||||
targetIndex = dropIndex+1;
|
||||
}
|
||||
}
|
||||
if (!beginMoveRows(QModelIndex(), dragIndex, dragIndex, QModelIndex(), targetIndex)) {
|
||||
return;
|
||||
}
|
||||
if(dropIndex > dragIndex){
|
||||
if(isDropTopArea){
|
||||
targetIndex = dropIndex-1;
|
||||
}else{
|
||||
targetIndex = dropIndex;
|
||||
}
|
||||
}else{
|
||||
if(isDropTopArea){
|
||||
targetIndex = dropIndex;
|
||||
}else{
|
||||
targetIndex = dropIndex+1;
|
||||
}
|
||||
}
|
||||
_rows.move(dragIndex,targetIndex);
|
||||
endMoveRows();
|
||||
|
||||
Q_EMIT layoutAboutToBeChanged();
|
||||
if(dragItem->_parent == dropItem->_parent){
|
||||
QList<FluTreeNode*>* children = &(dragItem->_parent->_children);
|
||||
int srcIndex = children->indexOf(dragItem);
|
||||
int destIndex = children->indexOf(dropItem);
|
||||
if(dropIndex > dragIndex){
|
||||
if(isDropTopArea){
|
||||
targetIndex = destIndex-1;
|
||||
}else{
|
||||
targetIndex = destIndex;
|
||||
}
|
||||
}else{
|
||||
if(isDropTopArea){
|
||||
targetIndex = destIndex;
|
||||
}else{
|
||||
targetIndex = destIndex+1;
|
||||
}
|
||||
}
|
||||
children->move(srcIndex,targetIndex);
|
||||
}else{
|
||||
QList<FluTreeNode*>* srcChildren = &(dragItem->_parent->_children);
|
||||
QList<FluTreeNode*>* destChildren = &(dropItem->_parent->_children);
|
||||
int srcIndex = srcChildren->indexOf(dragItem);
|
||||
int destIndex = destChildren->indexOf(dropItem);
|
||||
dragItem->_depth = dropItem->_depth;
|
||||
dragItem->_parent = dropItem->_parent;
|
||||
if(dragItem->hasChildren()){
|
||||
QList<FluTreeNode*> stack = dragItem->_children;
|
||||
foreach (auto node, stack) {
|
||||
node->_depth = dragItem->_depth+1;
|
||||
}
|
||||
std::reverse(stack.begin(), stack.end());
|
||||
while (stack.count() > 0) {
|
||||
auto item = stack.at(stack.count()-1);
|
||||
stack.pop_back();
|
||||
QList<FluTreeNode*> children = item->_children;
|
||||
if(!children.isEmpty()){
|
||||
std::reverse(children.begin(), children.end());
|
||||
foreach (auto c, children) {
|
||||
c->_depth = item->_depth+1;
|
||||
stack.append(c);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
srcChildren->removeAt(srcIndex);
|
||||
if(dropIndex > dragIndex){
|
||||
if(isDropTopArea){
|
||||
targetIndex = destIndex;
|
||||
}else{
|
||||
targetIndex = destIndex + 1;
|
||||
}
|
||||
}else{
|
||||
if(isDropTopArea){
|
||||
targetIndex = destIndex;
|
||||
}else{
|
||||
targetIndex = destIndex + 1;
|
||||
}
|
||||
}
|
||||
destChildren->insert(targetIndex,dragItem);
|
||||
}
|
||||
changePersistentIndex(index(qMin(dragIndex,dropIndex),0),index(qMax(dragIndex,dropIndex),0));
|
||||
Q_EMIT dataChanged(index(0,0),index(rowCount()-1,0));
|
||||
}
|
||||
|
||||
bool FluTreeModel::hitHasChildrenExpanded(int row){
|
||||
auto itemData = _rows.at(row);
|
||||
if(itemData->hasChildren() && itemData->_isExpanded){
|
||||
|
@ -4,6 +4,7 @@
|
||||
#include <QObject>
|
||||
#include <QAbstractTableModel>
|
||||
#include <QJsonArray>
|
||||
#include <QVariant>
|
||||
#include <QtQml/qqml.h>
|
||||
#include "stdafx.h"
|
||||
|
||||
@ -12,17 +13,15 @@
|
||||
*/
|
||||
class FluTreeNode : public QObject{
|
||||
Q_OBJECT
|
||||
Q_PROPERTY(QString key READ key CONSTANT)
|
||||
Q_PROPERTY(QString title READ title CONSTANT)
|
||||
Q_PROPERTY(QVariantMap data READ data CONSTANT)
|
||||
Q_PROPERTY(int depth READ depth CONSTANT)
|
||||
Q_PROPERTY(bool isExpanded READ isExpanded CONSTANT)
|
||||
Q_PROPERTY(bool checked READ checked CONSTANT)
|
||||
public:
|
||||
explicit FluTreeNode(QObject *parent = nullptr);
|
||||
Q_INVOKABLE QString key(){return _key;};
|
||||
Q_INVOKABLE QString title(){return _title;};
|
||||
Q_INVOKABLE int depth(){return _depth;};
|
||||
Q_INVOKABLE bool isExpanded(){return _isExpanded;};
|
||||
Q_INVOKABLE QVariantMap data(){return _data;};
|
||||
Q_INVOKABLE bool hasChildren(){ return !_children.isEmpty();};
|
||||
Q_INVOKABLE bool hasNextNodeByIndex(int index){
|
||||
FluTreeNode* p = this;
|
||||
@ -70,11 +69,11 @@ public:
|
||||
return true;
|
||||
}
|
||||
public:
|
||||
QString _key="";
|
||||
QString _title="";
|
||||
int _depth=0;
|
||||
bool _checked = false;
|
||||
bool _isExpanded=true;
|
||||
QVariantMap _data;
|
||||
QList<FluTreeNode*> _children;
|
||||
FluTreeNode* _parent = nullptr;
|
||||
};
|
||||
@ -84,9 +83,14 @@ class FluTreeModel : public QAbstractItemModel
|
||||
Q_OBJECT
|
||||
Q_PROPERTY_AUTO(int,dataSourceSize)
|
||||
Q_PROPERTY_AUTO(QList<FluTreeNode*>,selectionModel)
|
||||
Q_PROPERTY_AUTO(QList<QVariantMap>,columnSource)
|
||||
QML_NAMED_ELEMENT(FluTreeModel)
|
||||
QML_ADDED_IN_MINOR_VERSION(1)
|
||||
public:
|
||||
enum TreeModelRoles {
|
||||
RowModel = 0x0101,
|
||||
ColumnModel = 0x0102
|
||||
};
|
||||
explicit FluTreeModel(QObject *parent = nullptr);
|
||||
int rowCount(const QModelIndex &parent = QModelIndex()) const override;
|
||||
int columnCount(const QModelIndex &parent = QModelIndex()) const override;
|
||||
@ -98,11 +102,11 @@ public:
|
||||
Q_INVOKABLE void removeRows(int row,int count);
|
||||
Q_INVOKABLE void insertRows(int row,QList<FluTreeNode*> data);
|
||||
Q_INVOKABLE QObject* getRow(int row);
|
||||
Q_INVOKABLE void setRow(int row,QVariantMap data);
|
||||
Q_INVOKABLE void setData(QList<FluTreeNode*> data);
|
||||
Q_INVOKABLE void setDataSource(QList<QMap<QString,QVariant>> data);
|
||||
Q_INVOKABLE void collapse(int row);
|
||||
Q_INVOKABLE void expand(int row);
|
||||
Q_INVOKABLE void dragAndDrop(int dragIndex,int dropIndex,bool isDropTopArea);
|
||||
Q_INVOKABLE FluTreeNode* getNode(int row);
|
||||
Q_INVOKABLE void refreshNode(int row);
|
||||
Q_INVOKABLE void checkRow(int row,bool checked);
|
||||
|
@ -1,5 +1,7 @@
|
||||
#include "FluWatermark.h"
|
||||
|
||||
#include "FluTextStyle.h"
|
||||
|
||||
FluWatermark::FluWatermark(QQuickItem* parent) : QQuickPaintedItem(parent){
|
||||
gap(QPoint(100,100));
|
||||
offset(QPoint(_gap.x()/2,_gap.y()/2));
|
||||
@ -17,6 +19,7 @@ FluWatermark::FluWatermark(QQuickItem* parent) : QQuickPaintedItem(parent){
|
||||
|
||||
void FluWatermark::paint(QPainter* painter){
|
||||
QFont font;
|
||||
font.setFamily(FluTextStyle::getInstance()->family());
|
||||
font.setPixelSize(_textSize);
|
||||
painter->setFont(font);
|
||||
painter->setPen(_textColor);
|
||||
|
@ -10,8 +10,7 @@ Item {
|
||||
property real noiseOpacity: 0.02
|
||||
property alias target: effect_source.sourceItem
|
||||
property int blurRadius: 32
|
||||
property rect targetRect: Qt.rect(control.x, control.y, control.width,
|
||||
control.height)
|
||||
property rect targetRect: Qt.rect(control.x, control.y, control.width,control.height)
|
||||
ShaderEffectSource {
|
||||
id: effect_source
|
||||
anchors.fill: parent
|
||||
|
@ -90,7 +90,7 @@ Rectangle {
|
||||
if(!readOnly){
|
||||
editTextChaged(text_box.text)
|
||||
}
|
||||
tableView.closeEditor()
|
||||
control.closeEditor()
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -119,7 +119,7 @@ Rectangle {
|
||||
if(!readOnly){
|
||||
editTextChaged(text_box.text)
|
||||
}
|
||||
tableView.closeEditor()
|
||||
control.closeEditor()
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -258,7 +258,7 @@ Rectangle {
|
||||
anchors.fill: parent
|
||||
acceptedButtons: Qt.LeftButton
|
||||
onPressed:{
|
||||
closeEditor()
|
||||
control.closeEditor()
|
||||
}
|
||||
onCanceled: {
|
||||
}
|
||||
@ -275,7 +275,7 @@ Rectangle {
|
||||
onClicked:
|
||||
(event)=>{
|
||||
d.current = rowObject
|
||||
closeEditor()
|
||||
control.closeEditor()
|
||||
event.accepted = true
|
||||
}
|
||||
}
|
||||
@ -381,6 +381,7 @@ Rectangle {
|
||||
clip: true
|
||||
onRowsChanged: {
|
||||
control.closeEditor()
|
||||
table_view.flick(0,1)
|
||||
}
|
||||
delegate: com_table_delegate
|
||||
FluLoader{
|
||||
|
@ -5,283 +5,186 @@ import QtQuick.Controls 2.15
|
||||
import Qt.labs.qmlmodels 1.0
|
||||
import FluentUI 1.0
|
||||
|
||||
Item {
|
||||
property int currentIndex : -1
|
||||
Rectangle {
|
||||
property var dataSource
|
||||
property var columnSource : []
|
||||
property bool showLine: true
|
||||
property bool draggable: false
|
||||
property int cellHeight: 30
|
||||
property int depthPadding: 30
|
||||
property int depthPadding: 15
|
||||
property bool checkable: false
|
||||
property color lineColor: FluTheme.dark ? Qt.rgba(111/255,111/255,111/255,1) : Qt.rgba(217/255,217/255,217/255,1)
|
||||
property color lineColor: FluTheme.dividerColor
|
||||
property color borderColor: FluTheme.dark ? Qt.rgba(37/255,37/255,37/255,1) : Qt.rgba(228/255,228/255,228/255,1)
|
||||
property color selectedBorderColor: FluTheme.primaryColor
|
||||
property color selectedColor: FluTools.withOpacity(FluTheme.primaryColor,0.3)
|
||||
readonly property alias current: d.current
|
||||
id:control
|
||||
QtObject {
|
||||
id:d
|
||||
property int dy
|
||||
property var current
|
||||
property int dropIndex: -1
|
||||
property bool isDropTopArea: false
|
||||
property int dragIndex: -1
|
||||
property color hitColor: FluTheme.primaryColor
|
||||
}
|
||||
color: FluTheme.dark ? Qt.rgba(39/255,39/255,39/255,1) : Qt.rgba(251/255,251/255,253/255,1)
|
||||
onDataSourceChanged: {
|
||||
tree_model.setDataSource(dataSource)
|
||||
}
|
||||
onColumnSourceChanged: {
|
||||
var columns= []
|
||||
var headerRow = {}
|
||||
columnSource.forEach(function(item){
|
||||
var column = Qt.createQmlObject('import Qt.labs.qmlmodels 1.0;TableModelColumn{}',control);
|
||||
column.display = item.dataIndex
|
||||
columns.push(column)
|
||||
headerRow[item.dataIndex] = item.title
|
||||
})
|
||||
header_column_model.columns = columns
|
||||
header_column_model.rows = [headerRow]
|
||||
}
|
||||
FluTreeModel{
|
||||
id:tree_model
|
||||
columnSource: control.columnSource
|
||||
}
|
||||
ListView{
|
||||
id:table_view
|
||||
ScrollBar.horizontal: FluScrollBar{}
|
||||
ScrollBar.vertical: FluScrollBar{}
|
||||
boundsBehavior: Flickable.StopAtBounds
|
||||
model: tree_model
|
||||
anchors.fill: parent
|
||||
clip: true
|
||||
flickableDirection: Flickable.HorizontalAndVerticalFlick
|
||||
contentWidth: contentItem.childrenRect.width
|
||||
reuseItems: true
|
||||
removeDisplaced : Transition{
|
||||
ParallelAnimation{
|
||||
NumberAnimation {
|
||||
properties: "y"
|
||||
duration: 167
|
||||
from: d.dy + table_view.height
|
||||
easing.type: Easing.OutCubic
|
||||
onDepthPaddingChanged: {
|
||||
table_view.forceLayout()
|
||||
}
|
||||
NumberAnimation {
|
||||
properties: "opacity"
|
||||
duration: 83
|
||||
from: 0
|
||||
to: 1
|
||||
onCellHeightChanged: {
|
||||
table_view.forceLayout()
|
||||
}
|
||||
onCheckableChanged: {
|
||||
delay_force_layout.restart()
|
||||
}
|
||||
Timer{
|
||||
id:delay_force_layout
|
||||
interval: 30
|
||||
onTriggered: {
|
||||
table_view.forceLayout()
|
||||
}
|
||||
}
|
||||
QtObject {
|
||||
id:d
|
||||
property var current
|
||||
property int defaultItemWidth: 100
|
||||
property int rowHoverIndex: -1
|
||||
property var editDelegate
|
||||
property var editPosition
|
||||
function getEditDelegate(column){
|
||||
var obj = control.columnSource[column].editDelegate
|
||||
if(obj){
|
||||
return obj
|
||||
}
|
||||
move: Transition {
|
||||
NumberAnimation { property: "y"; duration: 200 }
|
||||
if(control.columnSource[column].editMultiline === true){
|
||||
return com_edit_multiline
|
||||
}
|
||||
add: Transition{
|
||||
ParallelAnimation{
|
||||
NumberAnimation {
|
||||
properties: "y"
|
||||
duration: 167
|
||||
from: d.dy - control.cellHeight
|
||||
easing.type: Easing.OutCubic
|
||||
}
|
||||
NumberAnimation {
|
||||
properties: "opacity"
|
||||
duration: 83
|
||||
from: 0
|
||||
to: 1
|
||||
}
|
||||
}
|
||||
}
|
||||
delegate: Item {
|
||||
id:item_control
|
||||
implicitWidth: item_loader_container.width
|
||||
implicitHeight: item_loader_container.height
|
||||
ListView.onReused: {
|
||||
item_loader_container.item.reused()
|
||||
}
|
||||
ListView.onPooled: {
|
||||
item_loader_container.item.pooled()
|
||||
}
|
||||
FluLoader{
|
||||
property var itemControl: item_control
|
||||
property var itemModel: dataModel
|
||||
property int rowIndex: index
|
||||
property bool isItemLoader: true
|
||||
id:item_loader_container
|
||||
sourceComponent: com_item_container
|
||||
}
|
||||
}
|
||||
FluLoader{
|
||||
id:loader_container
|
||||
property var itemControl
|
||||
property var itemModel
|
||||
property bool isItemLoader: false
|
||||
return com_edit
|
||||
}
|
||||
}
|
||||
Component{
|
||||
id:com_item_container
|
||||
id:com_edit
|
||||
FluTextBox{
|
||||
id:text_box
|
||||
text: String(display)
|
||||
readOnly: true === control.columnSource[column].readOnly
|
||||
Component.onCompleted: {
|
||||
forceActiveFocus()
|
||||
selectAll()
|
||||
}
|
||||
onCommit: {
|
||||
if(!readOnly){
|
||||
editTextChaged(text_box.text)
|
||||
}
|
||||
control.closeEditor()
|
||||
}
|
||||
}
|
||||
}
|
||||
Component{
|
||||
id:com_edit_multiline
|
||||
Item{
|
||||
signal reused
|
||||
signal pooled
|
||||
onReused: {
|
||||
|
||||
anchors.fill: parent
|
||||
Flickable{
|
||||
id:item_scroll
|
||||
clip: true
|
||||
anchors.fill: parent
|
||||
ScrollBar.vertical: multiline_text_srcoll_bar
|
||||
boundsBehavior: Flickable.StopAtBounds
|
||||
TextArea.flickable: FluMultilineTextBox {
|
||||
id:text_box
|
||||
text: String(display)
|
||||
readOnly: true === control.columnSource[column].readOnly
|
||||
verticalAlignment: TextInput.AlignVCenter
|
||||
isCtrlEnterForNewline: true
|
||||
Component.onCompleted: {
|
||||
forceActiveFocus()
|
||||
selectAll()
|
||||
}
|
||||
onPooled: {
|
||||
rightPadding: 34
|
||||
onCommit: {
|
||||
if(!readOnly){
|
||||
editTextChaged(text_box.text)
|
||||
}
|
||||
property bool isCurrent: d.current === itemModel
|
||||
id:item_container
|
||||
width: {
|
||||
var w = 46 + item_loader_cell.width + control.depthPadding*itemModel.depth
|
||||
if(control.width>w){
|
||||
return control.width
|
||||
}
|
||||
return w
|
||||
}
|
||||
height: control.cellHeight
|
||||
implicitWidth: width
|
||||
implicitHeight: height
|
||||
function toggle(){
|
||||
var pos = FluTools.cursorPos()
|
||||
var viewPos = table_view.mapToGlobal(0,0)
|
||||
d.dy = table_view.contentY + pos.y-viewPos.y
|
||||
if(itemModel.isExpanded){
|
||||
tree_model.collapse(rowIndex)
|
||||
}else{
|
||||
tree_model.expand(rowIndex)
|
||||
control.closeEditor()
|
||||
}
|
||||
}
|
||||
Rectangle{
|
||||
width: 3
|
||||
height: 18
|
||||
radius: 1.5
|
||||
color: FluTheme.primaryColor
|
||||
visible: isCurrent
|
||||
}
|
||||
FluIconButton{
|
||||
iconSource:FluentIcons.ChromeClose
|
||||
iconSize: 10
|
||||
width: 20
|
||||
height: 20
|
||||
padding: 0
|
||||
verticalPadding: 0
|
||||
horizontalPadding: 0
|
||||
visible: {
|
||||
if(text_box.readOnly)
|
||||
return false
|
||||
return text_box.text !== ""
|
||||
}
|
||||
anchors{
|
||||
left: parent.left
|
||||
leftMargin: 6
|
||||
verticalCenter: parent.verticalCenter
|
||||
right: parent.right
|
||||
rightMargin: 15
|
||||
}
|
||||
onClicked:{
|
||||
text_box.text = ""
|
||||
}
|
||||
}
|
||||
FluScrollBar{
|
||||
id:multiline_text_srcoll_bar
|
||||
anchors{
|
||||
right: parent.right
|
||||
rightMargin: 5
|
||||
top: parent.top
|
||||
bottom: parent.bottom
|
||||
topMargin: 3
|
||||
bottomMargin: 3
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Component{
|
||||
id:com_column
|
||||
Item{
|
||||
id:item_container
|
||||
clip: true
|
||||
function toggle(){
|
||||
if(rowModel.isExpanded){
|
||||
tree_model.collapse(row)
|
||||
}else{
|
||||
tree_model.expand(row)
|
||||
}
|
||||
delay_force_layout.restart()
|
||||
}
|
||||
MouseArea{
|
||||
id:item_mouse
|
||||
property point clickPos: Qt.point(0,0)
|
||||
anchors.fill: parent
|
||||
drag.target:control.draggable ? loader_container : undefined
|
||||
hoverEnabled: true
|
||||
drag.onActiveChanged: {
|
||||
if(drag.active){
|
||||
if(itemModel.isExpanded && itemModel.hasChildren()){
|
||||
tree_model.collapse(rowIndex)
|
||||
}
|
||||
d.dragIndex = rowIndex
|
||||
loader_container.sourceComponent = com_item_container
|
||||
}
|
||||
}
|
||||
onPressed:
|
||||
(mouse)=>{
|
||||
clickPos = Qt.point(mouse.x,mouse.y)
|
||||
loader_container.itemControl = itemControl
|
||||
loader_container.itemModel = itemModel
|
||||
var cellPosition = item_container.mapToItem(table_view, 0, 0)
|
||||
loader_container.width = item_container.width
|
||||
loader_container.height = item_container.height
|
||||
loader_container.x = 0
|
||||
loader_container.y = cellPosition.y
|
||||
}
|
||||
onClicked: {
|
||||
d.current = itemModel
|
||||
d.current = rowModel
|
||||
}
|
||||
onDoubleClicked: {
|
||||
if(itemModel.hasChildren()){
|
||||
if(rowModel.hasChildren()){
|
||||
item_container.toggle()
|
||||
}
|
||||
}
|
||||
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.dropIndex = -1
|
||||
return
|
||||
}
|
||||
if((mouse.x-table_view.contentX)>table_view.width || (mouse.x-table_view.contentX)<0){
|
||||
d.dropIndex = -1
|
||||
return
|
||||
}
|
||||
var pos = FluTools.cursorPos()
|
||||
var viewPos = table_view.mapToGlobal(0,0)
|
||||
var y = table_view.contentY + pos.y-viewPos.y
|
||||
var index = Math.floor(y/control.cellHeight)
|
||||
if(index<0 || index>table_view.count-1){
|
||||
d.dropIndex = -1
|
||||
return
|
||||
}
|
||||
if(tree_model.hitHasChildrenExpanded(index) && y>index*control.cellHeight+control.cellHeight/2){
|
||||
d.dropIndex = index + 1
|
||||
d.isDropTopArea = true
|
||||
}else{
|
||||
d.dropIndex = index
|
||||
if(y>index*control.cellHeight+control.cellHeight/2){
|
||||
d.isDropTopArea = false
|
||||
}else{
|
||||
d.isDropTopArea = true
|
||||
}
|
||||
}
|
||||
}
|
||||
onCanceled: {
|
||||
loader_container.sourceComponent = undefined
|
||||
loader_container.x = 0
|
||||
loader_container.y = 0
|
||||
d.dropIndex = -1
|
||||
d.dragIndex = -1
|
||||
}
|
||||
onReleased: {
|
||||
loader_container.sourceComponent = undefined
|
||||
if(d.dropIndex !== -1){
|
||||
tree_model.dragAndDrop(d.dragIndex,d.dropIndex,d.isDropTopArea)
|
||||
}
|
||||
d.dropIndex = -1
|
||||
d.dragIndex = -1
|
||||
loader_container.x = 0
|
||||
loader_container.y = 0
|
||||
}
|
||||
}
|
||||
Drag.active: item_mouse.drag.active
|
||||
Rectangle{
|
||||
id:item_line_drop_tip
|
||||
anchors{
|
||||
left: layout_row.left
|
||||
leftMargin: 26
|
||||
right: parent.right
|
||||
rightMargin: 10
|
||||
bottom: parent.bottom
|
||||
bottomMargin: -1.5
|
||||
top: undefined
|
||||
}
|
||||
states: [
|
||||
State {
|
||||
when:d.isDropTopArea
|
||||
AnchorChanges {
|
||||
target: item_line_drop_tip
|
||||
anchors.top: item_container.top
|
||||
anchors.bottom: undefined
|
||||
}
|
||||
PropertyChanges {
|
||||
target: item_line_drop_tip
|
||||
anchors.topMargin: -1.5
|
||||
}
|
||||
}
|
||||
]
|
||||
height: 3
|
||||
radius: 1.5
|
||||
color: d.hitColor
|
||||
visible: d.dropIndex === rowIndex
|
||||
Rectangle{
|
||||
width: 10
|
||||
height: 10
|
||||
radius: 5
|
||||
border.width: 3
|
||||
border.color: d.hitColor
|
||||
color: FluTheme.dark ? FluColors.Black : FluColors.White
|
||||
anchors{
|
||||
top: parent.top
|
||||
left: parent.left
|
||||
topMargin: -3
|
||||
leftMargin: -5
|
||||
}
|
||||
}
|
||||
}
|
||||
FluRectangle{
|
||||
width: 1
|
||||
color: control.lineColor
|
||||
visible: control.showLine && isItemLoader && itemModel.depth !== 0 && !itemModel.hasChildren()
|
||||
height: itemModel.hideLineFooter() ? parent.height/2 : parent.height
|
||||
visible: control.showLine && rowModel.depth !== 0 && !rowModel.hasChildren()
|
||||
height: rowModel.hideLineFooter() ? parent.height/2 : parent.height
|
||||
anchors{
|
||||
top: parent.top
|
||||
left: item_line_h.left
|
||||
@ -291,7 +194,7 @@ Item {
|
||||
id:item_line_h
|
||||
height: 1
|
||||
color: control.lineColor
|
||||
visible: control.showLine && isItemLoader && itemModel.depth !== 0 && !itemModel.hasChildren()
|
||||
visible: control.showLine && rowModel.depth !== 0 && !rowModel.hasChildren()
|
||||
width: depthPadding - 10
|
||||
anchors{
|
||||
right: layout_row.left
|
||||
@ -300,12 +203,12 @@ Item {
|
||||
}
|
||||
}
|
||||
Repeater{
|
||||
model: Math.max(itemModel.depth-1,0)
|
||||
model: Math.max(rowModel.depth-1,0)
|
||||
delegate: FluRectangle{
|
||||
required property int index
|
||||
width: 1
|
||||
color: control.lineColor
|
||||
visible: control.showLine && isItemLoader && itemModel.depth !== 0 && itemModel.hasNextNodeByIndex(index)
|
||||
visible: control.showLine && rowModel.depth !== 0 && rowModel.hasNextNodeByIndex(index)
|
||||
anchors{
|
||||
top:parent.top
|
||||
bottom: parent.bottom
|
||||
@ -314,57 +217,34 @@ Item {
|
||||
}
|
||||
}
|
||||
}
|
||||
Rectangle{
|
||||
anchors.fill: parent
|
||||
radius: 4
|
||||
anchors.leftMargin: 6
|
||||
anchors.rightMargin: 6
|
||||
border.color: d.hitColor
|
||||
border.width: d.dragIndex === rowIndex ? 1 : 0
|
||||
color: {
|
||||
if(isCurrent){
|
||||
return FluTheme.itemCheckColor
|
||||
}
|
||||
if(item_mouse.containsMouse || item_check_box.hovered){
|
||||
return FluTheme.itemHoverColor
|
||||
}
|
||||
if(item_loader_expand.item && item_loader_expand.item.hovered){
|
||||
return FluTheme.itemHoverColor
|
||||
}
|
||||
return FluTheme.itemNormalColor
|
||||
}
|
||||
}
|
||||
RowLayout{
|
||||
id:layout_row
|
||||
height: parent.height
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
anchors.left: parent.left
|
||||
anchors.fill: parent
|
||||
spacing: 0
|
||||
anchors.leftMargin: 14 + control.depthPadding*itemModel.depth
|
||||
anchors.leftMargin: 14 + control.depthPadding*rowModel.depth
|
||||
Component{
|
||||
id:com_icon_btn
|
||||
FluIconButton{
|
||||
opacity: itemModel.hasChildren()
|
||||
opacity: rowModel.hasChildren()
|
||||
onClicked: {
|
||||
item_container.toggle()
|
||||
}
|
||||
contentItem:FluIcon{
|
||||
rotation: itemModel.isExpanded?0:-90
|
||||
rotation: rowModel.isExpanded?0:-90
|
||||
iconSource:FluentIcons.ChevronDown
|
||||
iconSize: 16
|
||||
anchors.centerIn: parent
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
FluLoader{
|
||||
id:item_loader_expand
|
||||
Layout.preferredWidth: 20
|
||||
Layout.preferredHeight: 20
|
||||
sourceComponent: itemModel.hasChildren() ? com_icon_btn : undefined
|
||||
sourceComponent: rowModel.hasChildren() ? com_icon_btn : undefined
|
||||
Layout.alignment: Qt.AlignVCenter
|
||||
}
|
||||
|
||||
FluCheckBox{
|
||||
id:item_check_box
|
||||
Layout.preferredWidth: 18
|
||||
@ -372,39 +252,453 @@ Item {
|
||||
Layout.leftMargin: 5
|
||||
horizontalPadding:0
|
||||
verticalPadding: 0
|
||||
checked: itemModel.checked
|
||||
checked: rowModel.checked
|
||||
animationEnabled:false
|
||||
visible: control.checkable
|
||||
padding: 0
|
||||
clickListener: function(){
|
||||
tree_model.checkRow(rowIndex,!itemModel.checked)
|
||||
tree_model.checkRow(row,!rowModel.checked)
|
||||
}
|
||||
Layout.alignment: Qt.AlignVCenter
|
||||
}
|
||||
Item{
|
||||
Layout.fillHeight: true
|
||||
Layout.fillWidth: true
|
||||
Layout.leftMargin: 6
|
||||
FluText {
|
||||
id:item_text
|
||||
text: String(display)
|
||||
elide: Text.ElideRight
|
||||
verticalAlignment: Text.AlignVCenter
|
||||
anchors.fill: parent
|
||||
MouseArea{
|
||||
acceptedButtons: Qt.NoButton
|
||||
id: hover_handler
|
||||
hoverEnabled: true
|
||||
anchors.fill: parent
|
||||
}
|
||||
FluTooltip{
|
||||
text: item_text.text
|
||||
delay: 500
|
||||
visible: item_text.contentWidth < item_text.implicitWidth && hover_handler.containsMouse
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
Component{
|
||||
id:com_other
|
||||
FluText {
|
||||
id:item_text
|
||||
text: String(display)
|
||||
elide: Text.ElideRight
|
||||
wrapMode: Text.WrapAnywhere
|
||||
anchors{
|
||||
fill: parent
|
||||
leftMargin: 11
|
||||
rightMargin: 11
|
||||
topMargin: 6
|
||||
bottomMargin: 6
|
||||
}
|
||||
verticalAlignment: Text.AlignVCenter
|
||||
MouseArea{
|
||||
acceptedButtons: Qt.NoButton
|
||||
id: hover_handler
|
||||
hoverEnabled: true
|
||||
anchors.fill: parent
|
||||
}
|
||||
FluTooltip{
|
||||
text: item_text.text
|
||||
delay: 500
|
||||
visible: item_text.contentWidth < item_text.implicitWidth && item_text.contentHeight < item_text.implicitHeight && hover_handler.containsMouse
|
||||
}
|
||||
}
|
||||
}
|
||||
TableView{
|
||||
id:table_view
|
||||
ScrollBar.horizontal: FluScrollBar{}
|
||||
ScrollBar.vertical: FluScrollBar{}
|
||||
boundsBehavior: Flickable.StopAtBounds
|
||||
model: tree_model
|
||||
anchors{
|
||||
top: header_horizontal.bottom
|
||||
left: parent.left
|
||||
right: parent.right
|
||||
bottom: parent.bottom
|
||||
}
|
||||
clip: true
|
||||
columnWidthProvider: function(column) {
|
||||
var columnObject = control.columnSource[column]
|
||||
var width = columnObject.width
|
||||
if(width){
|
||||
return width
|
||||
}
|
||||
var minimumWidth = columnObject.minimumWidth
|
||||
if(minimumWidth){
|
||||
return minimumWidth
|
||||
}
|
||||
return d.defaultItemWidth
|
||||
}
|
||||
rowHeightProvider: function(row) {
|
||||
return control.cellHeight
|
||||
}
|
||||
delegate: MouseArea{
|
||||
property var rowObject : rowModel.data
|
||||
property alias isRowSelected: item_table_loader.isRowSelected
|
||||
property var display: rowModel.data[columnModel.dataIndex]
|
||||
property bool isObject: typeof(item_table.display) == "object"
|
||||
property bool editVisible: {
|
||||
if(rowObject && d.editPosition && d.editPosition._key === rowObject._key && d.editPosition.column === column){
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
implicitHeight: 30
|
||||
implicitWidth: 30
|
||||
id: item_table
|
||||
hoverEnabled: true
|
||||
onEntered: {
|
||||
d.rowHoverIndex = row
|
||||
}
|
||||
onWidthChanged: {
|
||||
if(editVisible){
|
||||
updateEditPosition()
|
||||
}
|
||||
}
|
||||
onHeightChanged: {
|
||||
if(editVisible){
|
||||
updateEditPosition()
|
||||
}
|
||||
}
|
||||
onXChanged: {
|
||||
if(editVisible){
|
||||
updateEditPosition()
|
||||
}
|
||||
}
|
||||
onYChanged: {
|
||||
if(editVisible){
|
||||
updateEditPosition()
|
||||
}
|
||||
}
|
||||
function updateEditPosition(){
|
||||
var obj = {}
|
||||
obj._key = rowObject._key
|
||||
obj.column = column
|
||||
obj.row = row
|
||||
obj.x = item_table.x
|
||||
obj.y = item_table.y + 1
|
||||
obj.width = item_table.width
|
||||
obj.height = item_table.height - 2
|
||||
d.editPosition = obj
|
||||
}
|
||||
onDoubleClicked:{
|
||||
if(typeof(display) == "object"){
|
||||
return
|
||||
}
|
||||
d.editDelegate = d.getEditDelegate(column)
|
||||
updateEditPosition()
|
||||
loader_edit.display = display
|
||||
}
|
||||
onClicked:
|
||||
(event)=>{
|
||||
d.current = rowModel
|
||||
event.accepted = true
|
||||
}
|
||||
Rectangle{
|
||||
anchors.fill: parent
|
||||
color:{
|
||||
if(item_table.isRowSelected){
|
||||
return control.selectedColor
|
||||
}
|
||||
if(d.rowHoverIndex === row || item_table.isRowSelected){
|
||||
return FluTheme.dark ? Qt.rgba(1,1,1,0.06) : Qt.rgba(0,0,0,0.06)
|
||||
}
|
||||
return (row%2!==0) ? control.color : (FluTheme.dark ? Qt.rgba(1,1,1,0.015) : Qt.rgba(0,0,0,0.015))
|
||||
}
|
||||
Item{
|
||||
anchors.fill: parent
|
||||
visible: item_table.isRowSelected
|
||||
Rectangle{
|
||||
width: 1
|
||||
height: parent.height
|
||||
anchors.left: parent.left
|
||||
color: control.selectedBorderColor
|
||||
visible: column === 0
|
||||
}
|
||||
Rectangle{
|
||||
width: 1
|
||||
height: parent.height
|
||||
anchors.right: parent.right
|
||||
color: control.selectedBorderColor
|
||||
visible: column === control.columnSource.length-1
|
||||
}
|
||||
Rectangle{
|
||||
width: parent.width
|
||||
height: 1
|
||||
anchors.top: parent.top
|
||||
color: control.selectedBorderColor
|
||||
}
|
||||
Rectangle{
|
||||
width: parent.width
|
||||
height: 1
|
||||
anchors.bottom: parent.bottom
|
||||
color: control.selectedBorderColor
|
||||
}
|
||||
}
|
||||
}
|
||||
FluLoader{
|
||||
property var dataModel: itemModel
|
||||
property var itemMouse: item_mouse
|
||||
id:item_loader_cell
|
||||
Layout.leftMargin: 10
|
||||
Layout.preferredWidth: {
|
||||
if(item){
|
||||
return item.width
|
||||
anchors.fill: parent
|
||||
id:item_table_loader
|
||||
property var rowModel : model.rowModel
|
||||
property var columnModel : model.columnModel
|
||||
property int row : model.row
|
||||
property int column: model.column
|
||||
property var display: item_table.display
|
||||
property bool isRowSelected: d.current === rowModel
|
||||
property var options: {
|
||||
if(isObject){
|
||||
return display.options
|
||||
}
|
||||
return {}
|
||||
}
|
||||
sourceComponent: {
|
||||
if(column === 0)
|
||||
return com_column
|
||||
if(item_table.isObject){
|
||||
return item_table.display.comId
|
||||
}
|
||||
return com_other
|
||||
}
|
||||
}
|
||||
}
|
||||
FluLoader{
|
||||
id:loader_edit
|
||||
property var tableView: control
|
||||
property var display
|
||||
property int column: {
|
||||
if(d.editPosition){
|
||||
return d.editPosition.column
|
||||
}
|
||||
return 0
|
||||
}
|
||||
Layout.fillHeight: true
|
||||
sourceComponent:com_item_text
|
||||
property int row: {
|
||||
if(d.editPosition){
|
||||
return d.editPosition.row
|
||||
}
|
||||
return 0
|
||||
}
|
||||
signal editTextChaged(string text)
|
||||
sourceComponent: d.editPosition ? d.editDelegate : undefined
|
||||
onEditTextChaged:
|
||||
(text)=>{
|
||||
const obj = tree_model.getRow(row).data
|
||||
obj[control.columnSource[column].dataIndex] = text
|
||||
tree_model.setRow(row,obj)
|
||||
}
|
||||
width: {
|
||||
if(d.editPosition){
|
||||
return d.editPosition.width
|
||||
}
|
||||
return 0
|
||||
}
|
||||
height: {
|
||||
if(d.editPosition){
|
||||
return d.editPosition.height
|
||||
}
|
||||
return 0
|
||||
}
|
||||
x:{
|
||||
if(d.editPosition){
|
||||
return d.editPosition.x
|
||||
}
|
||||
return 0
|
||||
}
|
||||
y:{
|
||||
if(d.editPosition){
|
||||
return d.editPosition.y
|
||||
}
|
||||
return 0
|
||||
}
|
||||
z:999
|
||||
}
|
||||
}
|
||||
TableModel{
|
||||
id:header_column_model
|
||||
TableModelColumn {}
|
||||
}
|
||||
Component{
|
||||
id:com_column_text
|
||||
FluText {
|
||||
id: column_text
|
||||
text: modelData
|
||||
anchors.fill: parent
|
||||
horizontalAlignment: Text.AlignHCenter
|
||||
verticalAlignment: Text.AlignVCenter
|
||||
}
|
||||
}
|
||||
Component{
|
||||
id:com_column_header_delegate
|
||||
Rectangle{
|
||||
id:column_item_control
|
||||
readonly property real cellPadding: 8
|
||||
property bool canceled: false
|
||||
property int columnIndex: column
|
||||
property var columnObject : control.columnSource[column]
|
||||
implicitWidth: {
|
||||
return (item_column_loader.item && item_column_loader.item.implicitWidth) + (cellPadding * 2)
|
||||
}
|
||||
implicitHeight: Math.max(36, (item_column_loader.item&&item_column_loader.item.implicitHeight) + (cellPadding * 2))
|
||||
color: FluTheme.dark ? Qt.rgba(50/255,50/255,50/255,1) : Qt.rgba(247/255,247/255,247/255,1)
|
||||
Rectangle{
|
||||
border.color: control.borderColor
|
||||
width: parent.width
|
||||
height: 1
|
||||
anchors.top: parent.top
|
||||
color:"#00000000"
|
||||
}
|
||||
Rectangle{
|
||||
border.color: control.borderColor
|
||||
width: parent.width
|
||||
height: 1
|
||||
anchors.bottom: parent.bottom
|
||||
color:"#00000000"
|
||||
}
|
||||
Rectangle{
|
||||
border.color: control.borderColor
|
||||
width: 1
|
||||
height: parent.height
|
||||
anchors.left: parent.left
|
||||
color:"#00000000"
|
||||
}
|
||||
Rectangle{
|
||||
border.color: control.borderColor
|
||||
width: 1
|
||||
height: parent.height
|
||||
anchors.right: parent.right
|
||||
color:"#00000000"
|
||||
visible: column === table_view.columns - 1
|
||||
}
|
||||
MouseArea{
|
||||
id:column_item_control_mouse
|
||||
anchors.fill: parent
|
||||
anchors.rightMargin: 6
|
||||
hoverEnabled: true
|
||||
onCanceled: {
|
||||
column_item_control.canceled = true
|
||||
}
|
||||
onContainsMouseChanged: {
|
||||
if(!containsMouse){
|
||||
column_item_control.canceled = false
|
||||
}
|
||||
}
|
||||
onClicked:
|
||||
(event)=>{
|
||||
|
||||
}
|
||||
}
|
||||
FluLoader{
|
||||
id:item_column_loader
|
||||
property var itemModel: model
|
||||
property var modelData: model.display
|
||||
property var tableView: table_view
|
||||
property var options:{
|
||||
if(typeof(modelData) == "object"){
|
||||
return modelData.options
|
||||
}
|
||||
return {}
|
||||
}
|
||||
property int column: column_item_control.columnIndex
|
||||
width: parent.width
|
||||
height: parent.height
|
||||
sourceComponent: {
|
||||
if(typeof(modelData) == "object"){
|
||||
return modelData.comId
|
||||
}
|
||||
return com_column_text
|
||||
}
|
||||
}
|
||||
MouseArea{
|
||||
property point clickPos: "0,0"
|
||||
height: parent.height
|
||||
width: 6
|
||||
anchors.right: parent.right
|
||||
acceptedButtons: Qt.LeftButton
|
||||
hoverEnabled: true
|
||||
visible: !(columnObject.width === columnObject.minimumWidth && columnObject.width === columnObject.maximumWidth && columnObject.width)
|
||||
cursorShape: Qt.SplitHCursor
|
||||
preventStealing: true
|
||||
onPressed :
|
||||
(mouse)=>{
|
||||
FluTools.setOverrideCursor(Qt.SplitHCursor)
|
||||
clickPos = Qt.point(mouse.x, mouse.y)
|
||||
}
|
||||
onReleased:{
|
||||
FluTools.restoreOverrideCursor()
|
||||
}
|
||||
onCanceled: {
|
||||
FluTools.restoreOverrideCursor()
|
||||
}
|
||||
onPositionChanged:
|
||||
(mouse)=>{
|
||||
if(!pressed){
|
||||
return
|
||||
}
|
||||
var delta = Qt.point(mouse.x - clickPos.x, mouse.y - clickPos.y)
|
||||
var minimumWidth = columnObject.minimumWidth
|
||||
var maximumWidth = columnObject.maximumWidth
|
||||
var w = columnObject.width
|
||||
if(!w){
|
||||
w = d.defaultItemWidth
|
||||
}
|
||||
if(!minimumWidth){
|
||||
minimumWidth = d.defaultItemWidth
|
||||
}
|
||||
if(!maximumWidth){
|
||||
maximumWidth = 65535
|
||||
}
|
||||
columnObject.width = Math.min(Math.max(minimumWidth, w + delta.x),maximumWidth)
|
||||
table_view.forceLayout()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TableView {
|
||||
id: header_horizontal
|
||||
model: header_column_model
|
||||
anchors{
|
||||
left: table_view.left
|
||||
right: table_view.right
|
||||
top: parent.top
|
||||
}
|
||||
height: Math.max(1, contentHeight)
|
||||
boundsBehavior: Flickable.StopAtBounds
|
||||
clip: true
|
||||
syncDirection: Qt.Horizontal
|
||||
columnWidthProvider: table_view.columnWidthProvider
|
||||
syncView: table_view.rows === 0 ? null : table_view
|
||||
onContentXChanged:{
|
||||
timer_horizontal_force_layout.restart()
|
||||
}
|
||||
Timer{
|
||||
id:timer_horizontal_force_layout
|
||||
interval: 50
|
||||
onTriggered: {
|
||||
header_horizontal.forceLayout()
|
||||
}
|
||||
}
|
||||
delegate: com_column_header_delegate
|
||||
}
|
||||
|
||||
Component{
|
||||
id:com_item_text
|
||||
Item{
|
||||
width: item_text.width
|
||||
FluText {
|
||||
id:item_text
|
||||
text: dataModel.title
|
||||
text: model.title
|
||||
rightPadding: 14
|
||||
anchors.centerIn: parent
|
||||
color:{
|
||||
@ -423,7 +717,7 @@ Item {
|
||||
return tree_model.dataSourceSize
|
||||
}
|
||||
function visibleCount(){
|
||||
return table_view.count
|
||||
return table_view.rows
|
||||
}
|
||||
function collapse(rowIndex){
|
||||
tree_model.collapse(rowIndex)
|
||||
@ -437,4 +731,14 @@ Item {
|
||||
function allCollapse(){
|
||||
tree_model.allCollapse()
|
||||
}
|
||||
function customItem(comId,options={}){
|
||||
var o = {}
|
||||
o.comId = comId
|
||||
o.options = options
|
||||
return o
|
||||
}
|
||||
function closeEditor(){
|
||||
d.editPosition = undefined
|
||||
d.editDelegate = undefined
|
||||
}
|
||||
}
|
||||
|
@ -21,6 +21,24 @@ Module {
|
||||
Property { name: "lighter"; type: "QColor" }
|
||||
Property { name: "lightest"; type: "QColor" }
|
||||
}
|
||||
Component {
|
||||
name: "FluApp"
|
||||
prototype: "QObject"
|
||||
exports: ["FluentUI/FluApp 1.0"]
|
||||
exportMetaObjectRevisions: [0]
|
||||
Property { name: "useSystemAppBar"; type: "bool" }
|
||||
Property { name: "windowIcon"; type: "string" }
|
||||
Property { name: "locale"; type: "QLocale" }
|
||||
Method {
|
||||
name: "init"
|
||||
Parameter { name: "target"; type: "QObject"; isPointer: true }
|
||||
Parameter { name: "locale"; type: "QLocale" }
|
||||
}
|
||||
Method {
|
||||
name: "init"
|
||||
Parameter { name: "target"; type: "QObject"; isPointer: true }
|
||||
}
|
||||
}
|
||||
Component {
|
||||
name: "FluCalendarViewType"
|
||||
exports: ["FluentUI/FluCalendarViewType 1.0"]
|
||||
@ -50,6 +68,50 @@ Module {
|
||||
Parameter { name: "code"; type: "string" }
|
||||
}
|
||||
}
|
||||
Component {
|
||||
name: "FluColors"
|
||||
prototype: "QObject"
|
||||
exports: ["FluentUI/FluColors 1.0"]
|
||||
exportMetaObjectRevisions: [0]
|
||||
Property { name: "Transparent"; type: "QColor" }
|
||||
Property { name: "Black"; type: "QColor" }
|
||||
Property { name: "White"; type: "QColor" }
|
||||
Property { name: "Grey10"; type: "QColor" }
|
||||
Property { name: "Grey20"; type: "QColor" }
|
||||
Property { name: "Grey30"; type: "QColor" }
|
||||
Property { name: "Grey40"; type: "QColor" }
|
||||
Property { name: "Grey50"; type: "QColor" }
|
||||
Property { name: "Grey60"; type: "QColor" }
|
||||
Property { name: "Grey70"; type: "QColor" }
|
||||
Property { name: "Grey80"; type: "QColor" }
|
||||
Property { name: "Grey90"; type: "QColor" }
|
||||
Property { name: "Grey100"; type: "QColor" }
|
||||
Property { name: "Grey110"; type: "QColor" }
|
||||
Property { name: "Grey120"; type: "QColor" }
|
||||
Property { name: "Grey130"; type: "QColor" }
|
||||
Property { name: "Grey140"; type: "QColor" }
|
||||
Property { name: "Grey150"; type: "QColor" }
|
||||
Property { name: "Grey160"; type: "QColor" }
|
||||
Property { name: "Grey170"; type: "QColor" }
|
||||
Property { name: "Grey180"; type: "QColor" }
|
||||
Property { name: "Grey190"; type: "QColor" }
|
||||
Property { name: "Grey200"; type: "QColor" }
|
||||
Property { name: "Grey210"; type: "QColor" }
|
||||
Property { name: "Grey220"; type: "QColor" }
|
||||
Property { name: "Yellow"; type: "FluAccentColor"; isPointer: true }
|
||||
Property { name: "Orange"; type: "FluAccentColor"; isPointer: true }
|
||||
Property { name: "Red"; type: "FluAccentColor"; isPointer: true }
|
||||
Property { name: "Magenta"; type: "FluAccentColor"; isPointer: true }
|
||||
Property { name: "Purple"; type: "FluAccentColor"; isPointer: true }
|
||||
Property { name: "Blue"; type: "FluAccentColor"; isPointer: true }
|
||||
Property { name: "Teal"; type: "FluAccentColor"; isPointer: true }
|
||||
Property { name: "Green"; type: "FluAccentColor"; isPointer: true }
|
||||
Method {
|
||||
name: "createAccentColor"
|
||||
type: "FluAccentColor*"
|
||||
Parameter { name: "primaryColor"; type: "QColor" }
|
||||
}
|
||||
}
|
||||
Component {
|
||||
name: "FluContentDialogType"
|
||||
exports: ["FluentUI/FluContentDialogType 1.0"]
|
||||
@ -226,6 +288,49 @@ Module {
|
||||
Parameter { name: "filter"; type: "QJSValue" }
|
||||
}
|
||||
}
|
||||
Component {
|
||||
name: "FluTextStyle"
|
||||
prototype: "QObject"
|
||||
exports: ["FluentUI/FluTextStyle 1.0"]
|
||||
exportMetaObjectRevisions: [0]
|
||||
Property { name: "family"; type: "string" }
|
||||
Property { name: "Caption"; type: "QFont" }
|
||||
Property { name: "Body"; type: "QFont" }
|
||||
Property { name: "BodyStrong"; type: "QFont" }
|
||||
Property { name: "Subtitle"; type: "QFont" }
|
||||
Property { name: "Title"; type: "QFont" }
|
||||
Property { name: "TitleLarge"; type: "QFont" }
|
||||
Property { name: "Display"; type: "QFont" }
|
||||
}
|
||||
Component {
|
||||
name: "FluTheme"
|
||||
prototype: "QObject"
|
||||
exports: ["FluentUI/FluTheme 1.0"]
|
||||
exportMetaObjectRevisions: [0]
|
||||
Property { name: "dark"; type: "bool"; isReadonly: true }
|
||||
Property { name: "accentColor"; type: "FluAccentColor"; isPointer: true }
|
||||
Property { name: "primaryColor"; type: "QColor" }
|
||||
Property { name: "backgroundColor"; type: "QColor" }
|
||||
Property { name: "dividerColor"; type: "QColor" }
|
||||
Property { name: "windowBackgroundColor"; type: "QColor" }
|
||||
Property { name: "windowActiveBackgroundColor"; type: "QColor" }
|
||||
Property { name: "fontPrimaryColor"; type: "QColor" }
|
||||
Property { name: "fontSecondaryColor"; type: "QColor" }
|
||||
Property { name: "fontTertiaryColor"; type: "QColor" }
|
||||
Property { name: "itemNormalColor"; type: "QColor" }
|
||||
Property { name: "itemHoverColor"; type: "QColor" }
|
||||
Property { name: "itemPressColor"; type: "QColor" }
|
||||
Property { name: "itemCheckColor"; type: "QColor" }
|
||||
Property { name: "darkMode"; type: "int" }
|
||||
Property { name: "nativeText"; type: "bool" }
|
||||
Property { name: "animationEnabled"; type: "bool" }
|
||||
Method {
|
||||
name: "awesomeList"
|
||||
type: "QJsonArray"
|
||||
Parameter { name: "keyword"; type: "string" }
|
||||
}
|
||||
Method { name: "awesomeList"; type: "QJsonArray" }
|
||||
}
|
||||
Component {
|
||||
name: "FluThemeType"
|
||||
exports: ["FluentUI/FluThemeType 1.0"]
|
||||
@ -267,6 +372,115 @@ Module {
|
||||
}
|
||||
}
|
||||
}
|
||||
Component {
|
||||
name: "FluTools"
|
||||
prototype: "QObject"
|
||||
exports: ["FluentUI/FluTools 1.0"]
|
||||
exportMetaObjectRevisions: [0]
|
||||
Method { name: "qtMajor"; type: "int" }
|
||||
Method { name: "qtMinor"; type: "int" }
|
||||
Method { name: "isMacos"; type: "bool" }
|
||||
Method { name: "isLinux"; type: "bool" }
|
||||
Method { name: "isWin"; type: "bool" }
|
||||
Method {
|
||||
name: "clipText"
|
||||
Parameter { name: "text"; type: "string" }
|
||||
}
|
||||
Method { name: "uuid"; type: "string" }
|
||||
Method {
|
||||
name: "readFile"
|
||||
type: "string"
|
||||
Parameter { name: "fileName"; type: "string" }
|
||||
}
|
||||
Method {
|
||||
name: "setQuitOnLastWindowClosed"
|
||||
Parameter { name: "val"; type: "bool" }
|
||||
}
|
||||
Method {
|
||||
name: "setOverrideCursor"
|
||||
Parameter { name: "shape"; type: "Qt::CursorShape" }
|
||||
}
|
||||
Method { name: "restoreOverrideCursor" }
|
||||
Method {
|
||||
name: "html2PlantText"
|
||||
type: "string"
|
||||
Parameter { name: "html"; type: "string" }
|
||||
}
|
||||
Method {
|
||||
name: "toLocalPath"
|
||||
type: "string"
|
||||
Parameter { name: "url"; type: "QUrl" }
|
||||
}
|
||||
Method {
|
||||
name: "deleteLater"
|
||||
Parameter { name: "p"; type: "QObject"; isPointer: true }
|
||||
}
|
||||
Method {
|
||||
name: "getFileNameByUrl"
|
||||
type: "string"
|
||||
Parameter { name: "url"; type: "QUrl" }
|
||||
}
|
||||
Method { name: "getVirtualGeometry"; type: "QRect" }
|
||||
Method { name: "getApplicationDirPath"; type: "string" }
|
||||
Method {
|
||||
name: "getUrlByFilePath"
|
||||
type: "QUrl"
|
||||
Parameter { name: "path"; type: "string" }
|
||||
}
|
||||
Method {
|
||||
name: "withOpacity"
|
||||
type: "QColor"
|
||||
Parameter { type: "QColor" }
|
||||
Parameter { name: "alpha"; type: "double" }
|
||||
}
|
||||
Method {
|
||||
name: "md5"
|
||||
type: "string"
|
||||
Parameter { name: "text"; type: "string" }
|
||||
}
|
||||
Method {
|
||||
name: "sha256"
|
||||
type: "string"
|
||||
Parameter { name: "text"; type: "string" }
|
||||
}
|
||||
Method {
|
||||
name: "toBase64"
|
||||
type: "string"
|
||||
Parameter { name: "text"; type: "string" }
|
||||
}
|
||||
Method {
|
||||
name: "fromBase64"
|
||||
type: "string"
|
||||
Parameter { name: "text"; type: "string" }
|
||||
}
|
||||
Method {
|
||||
name: "removeDir"
|
||||
type: "bool"
|
||||
Parameter { name: "dirPath"; type: "string" }
|
||||
}
|
||||
Method {
|
||||
name: "removeFile"
|
||||
type: "bool"
|
||||
Parameter { name: "filePath"; type: "string" }
|
||||
}
|
||||
Method {
|
||||
name: "showFileInFolder"
|
||||
Parameter { name: "path"; type: "string" }
|
||||
}
|
||||
Method { name: "isSoftware"; type: "bool" }
|
||||
Method { name: "currentTimestamp"; type: "qlonglong" }
|
||||
Method { name: "cursorPos"; type: "QPoint" }
|
||||
Method { name: "windowIcon"; type: "QIcon" }
|
||||
Method { name: "cursorScreenIndex"; type: "int" }
|
||||
Method { name: "windowBuildNumber"; type: "int" }
|
||||
Method { name: "isWindows11OrGreater"; type: "bool" }
|
||||
Method { name: "isWindows10OrGreater"; type: "bool" }
|
||||
Method {
|
||||
name: "desktopAvailableGeometry"
|
||||
type: "QRect"
|
||||
Parameter { name: "window"; type: "QQuickWindow"; isPointer: true }
|
||||
}
|
||||
}
|
||||
Component {
|
||||
name: "FluTreeModel"
|
||||
prototype: "QAbstractItemModel"
|
||||
@ -274,6 +488,7 @@ Module {
|
||||
exportMetaObjectRevisions: [0]
|
||||
Property { name: "dataSourceSize"; type: "int" }
|
||||
Property { name: "selectionModel"; type: "QList<FluTreeNode*>" }
|
||||
Property { name: "columnSource"; type: "QList<QVariantMap>" }
|
||||
Method {
|
||||
name: "removeRows"
|
||||
Parameter { name: "row"; type: "int" }
|
||||
@ -305,12 +520,6 @@ Module {
|
||||
name: "expand"
|
||||
Parameter { name: "row"; type: "int" }
|
||||
}
|
||||
Method {
|
||||
name: "dragAndDrop"
|
||||
Parameter { name: "dragIndex"; type: "int" }
|
||||
Parameter { name: "dropIndex"; type: "int" }
|
||||
Parameter { name: "isDropTopArea"; type: "bool" }
|
||||
}
|
||||
Method {
|
||||
name: "getNode"
|
||||
type: "FluTreeNode*"
|
||||
@ -2242,7 +2451,7 @@ Module {
|
||||
}
|
||||
Property {
|
||||
name: "layoutMacosButtons"
|
||||
type: "FluLoader_QMLTYPE_13"
|
||||
type: "FluLoader_QMLTYPE_12"
|
||||
isReadonly: true
|
||||
isPointer: true
|
||||
}
|
||||
@ -2932,15 +3141,15 @@ Module {
|
||||
defaultProperty: "data"
|
||||
Property { name: "logo"; type: "QUrl" }
|
||||
Property { name: "title"; type: "string" }
|
||||
Property { name: "items"; type: "FluObject_QMLTYPE_137"; isPointer: true }
|
||||
Property { name: "footerItems"; type: "FluObject_QMLTYPE_137"; isPointer: true }
|
||||
Property { name: "items"; type: "FluObject_QMLTYPE_172"; isPointer: true }
|
||||
Property { name: "footerItems"; type: "FluObject_QMLTYPE_172"; isPointer: true }
|
||||
Property { name: "displayMode"; type: "int" }
|
||||
Property { name: "autoSuggestBox"; type: "QQmlComponent"; isPointer: true }
|
||||
Property { name: "actionItem"; type: "QQmlComponent"; isPointer: true }
|
||||
Property { name: "topPadding"; type: "int" }
|
||||
Property { name: "pageMode"; type: "int" }
|
||||
Property { name: "navItemRightMenu"; type: "FluMenu_QMLTYPE_38"; isPointer: true }
|
||||
Property { name: "navItemExpanderRightMenu"; type: "FluMenu_QMLTYPE_38"; isPointer: true }
|
||||
Property { name: "navItemRightMenu"; type: "FluMenu_QMLTYPE_42"; isPointer: true }
|
||||
Property { name: "navItemExpanderRightMenu"; type: "FluMenu_QMLTYPE_42"; isPointer: true }
|
||||
Property { name: "navCompactWidth"; type: "int" }
|
||||
Property { name: "navTopMargin"; type: "int" }
|
||||
Property { name: "cellHeight"; type: "int" }
|
||||
|
@ -10,8 +10,7 @@ Item {
|
||||
property real noiseOpacity: 0.02
|
||||
property alias target: effect_source.sourceItem
|
||||
property int blurRadius: 32
|
||||
property rect targetRect: Qt.rect(control.x, control.y, control.width,
|
||||
control.height)
|
||||
property rect targetRect: Qt.rect(control.x, control.y, control.width,control.height)
|
||||
ShaderEffectSource {
|
||||
id: effect_source
|
||||
anchors.fill: parent
|
||||
|
@ -91,7 +91,7 @@ Rectangle {
|
||||
if(!readOnly){
|
||||
editTextChaged(text_box.text)
|
||||
}
|
||||
tableView.closeEditor()
|
||||
control.closeEditor()
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -120,7 +120,7 @@ Rectangle {
|
||||
if(!readOnly){
|
||||
editTextChaged(text_box.text)
|
||||
}
|
||||
tableView.closeEditor()
|
||||
control.closeEditor()
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -259,7 +259,7 @@ Rectangle {
|
||||
anchors.fill: parent
|
||||
acceptedButtons: Qt.LeftButton
|
||||
onPressed:{
|
||||
closeEditor()
|
||||
control.closeEditor()
|
||||
}
|
||||
onCanceled: {
|
||||
}
|
||||
@ -276,7 +276,7 @@ Rectangle {
|
||||
onClicked:
|
||||
(event)=>{
|
||||
d.current = rowObject
|
||||
closeEditor()
|
||||
control.closeEditor()
|
||||
event.accepted = true
|
||||
}
|
||||
}
|
||||
@ -382,6 +382,7 @@ Rectangle {
|
||||
clip: true
|
||||
onRowsChanged: {
|
||||
control.closeEditor()
|
||||
table_view.flick(0,1)
|
||||
}
|
||||
delegate: com_table_delegate
|
||||
FluLoader{
|
||||
|
@ -5,283 +5,186 @@ import QtQuick.Controls
|
||||
import Qt.labs.qmlmodels
|
||||
import FluentUI
|
||||
|
||||
Item {
|
||||
property int currentIndex : -1
|
||||
Rectangle {
|
||||
property var dataSource
|
||||
property var columnSource : []
|
||||
property bool showLine: true
|
||||
property bool draggable: false
|
||||
property int cellHeight: 30
|
||||
property int depthPadding: 30
|
||||
property int depthPadding: 15
|
||||
property bool checkable: false
|
||||
property color lineColor: FluTheme.dark ? Qt.rgba(111/255,111/255,111/255,1) : Qt.rgba(217/255,217/255,217/255,1)
|
||||
property color lineColor: FluTheme.dividerColor
|
||||
property color borderColor: FluTheme.dark ? Qt.rgba(37/255,37/255,37/255,1) : Qt.rgba(228/255,228/255,228/255,1)
|
||||
property color selectedBorderColor: FluTheme.primaryColor
|
||||
property color selectedColor: FluTools.withOpacity(FluTheme.primaryColor,0.3)
|
||||
readonly property alias current: d.current
|
||||
id:control
|
||||
QtObject {
|
||||
id:d
|
||||
property int dy
|
||||
property var current
|
||||
property int dropIndex: -1
|
||||
property bool isDropTopArea: false
|
||||
property int dragIndex: -1
|
||||
property color hitColor: FluTheme.primaryColor
|
||||
}
|
||||
color: FluTheme.dark ? Qt.rgba(39/255,39/255,39/255,1) : Qt.rgba(251/255,251/255,253/255,1)
|
||||
onDataSourceChanged: {
|
||||
tree_model.setDataSource(dataSource)
|
||||
}
|
||||
onColumnSourceChanged: {
|
||||
var columns= []
|
||||
var headerRow = {}
|
||||
columnSource.forEach(function(item){
|
||||
var column = Qt.createQmlObject('import Qt.labs.qmlmodels 1.0;TableModelColumn{}',control);
|
||||
column.display = item.dataIndex
|
||||
columns.push(column)
|
||||
headerRow[item.dataIndex] = item.title
|
||||
})
|
||||
header_column_model.columns = columns
|
||||
header_column_model.rows = [headerRow]
|
||||
}
|
||||
FluTreeModel{
|
||||
id:tree_model
|
||||
columnSource: control.columnSource
|
||||
}
|
||||
ListView{
|
||||
id:table_view
|
||||
ScrollBar.horizontal: FluScrollBar{}
|
||||
ScrollBar.vertical: FluScrollBar{}
|
||||
boundsBehavior: Flickable.StopAtBounds
|
||||
model: tree_model
|
||||
anchors.fill: parent
|
||||
clip: true
|
||||
flickableDirection: Flickable.HorizontalAndVerticalFlick
|
||||
contentWidth: contentItem.childrenRect.width
|
||||
reuseItems: true
|
||||
removeDisplaced : Transition{
|
||||
ParallelAnimation{
|
||||
NumberAnimation {
|
||||
properties: "y"
|
||||
duration: 167
|
||||
from: d.dy + table_view.height
|
||||
easing.type: Easing.OutCubic
|
||||
onDepthPaddingChanged: {
|
||||
table_view.forceLayout()
|
||||
}
|
||||
NumberAnimation {
|
||||
properties: "opacity"
|
||||
duration: 83
|
||||
from: 0
|
||||
to: 1
|
||||
onCellHeightChanged: {
|
||||
table_view.forceLayout()
|
||||
}
|
||||
onCheckableChanged: {
|
||||
delay_force_layout.restart()
|
||||
}
|
||||
Timer{
|
||||
id:delay_force_layout
|
||||
interval: 30
|
||||
onTriggered: {
|
||||
table_view.forceLayout()
|
||||
}
|
||||
}
|
||||
QtObject {
|
||||
id:d
|
||||
property var current
|
||||
property int defaultItemWidth: 100
|
||||
property int rowHoverIndex: -1
|
||||
property var editDelegate
|
||||
property var editPosition
|
||||
function getEditDelegate(column){
|
||||
var obj = control.columnSource[column].editDelegate
|
||||
if(obj){
|
||||
return obj
|
||||
}
|
||||
move: Transition {
|
||||
NumberAnimation { property: "y"; duration: 200 }
|
||||
if(control.columnSource[column].editMultiline === true){
|
||||
return com_edit_multiline
|
||||
}
|
||||
add: Transition{
|
||||
ParallelAnimation{
|
||||
NumberAnimation {
|
||||
properties: "y"
|
||||
duration: 167
|
||||
from: d.dy - control.cellHeight
|
||||
easing.type: Easing.OutCubic
|
||||
}
|
||||
NumberAnimation {
|
||||
properties: "opacity"
|
||||
duration: 83
|
||||
from: 0
|
||||
to: 1
|
||||
}
|
||||
}
|
||||
}
|
||||
delegate: Item {
|
||||
id:item_control
|
||||
implicitWidth: item_loader_container.width
|
||||
implicitHeight: item_loader_container.height
|
||||
ListView.onReused: {
|
||||
item_loader_container.item.reused()
|
||||
}
|
||||
ListView.onPooled: {
|
||||
item_loader_container.item.pooled()
|
||||
}
|
||||
FluLoader{
|
||||
property var itemControl: item_control
|
||||
property var itemModel: dataModel
|
||||
property int rowIndex: index
|
||||
property bool isItemLoader: true
|
||||
id:item_loader_container
|
||||
sourceComponent: com_item_container
|
||||
}
|
||||
}
|
||||
FluLoader{
|
||||
id:loader_container
|
||||
property var itemControl
|
||||
property var itemModel
|
||||
property bool isItemLoader: false
|
||||
return com_edit
|
||||
}
|
||||
}
|
||||
Component{
|
||||
id:com_item_container
|
||||
id:com_edit
|
||||
FluTextBox{
|
||||
id:text_box
|
||||
text: String(display)
|
||||
readOnly: true === control.columnSource[column].readOnly
|
||||
Component.onCompleted: {
|
||||
forceActiveFocus()
|
||||
selectAll()
|
||||
}
|
||||
onCommit: {
|
||||
if(!readOnly){
|
||||
editTextChaged(text_box.text)
|
||||
}
|
||||
control.closeEditor()
|
||||
}
|
||||
}
|
||||
}
|
||||
Component{
|
||||
id:com_edit_multiline
|
||||
Item{
|
||||
signal reused
|
||||
signal pooled
|
||||
onReused: {
|
||||
|
||||
anchors.fill: parent
|
||||
Flickable{
|
||||
id:item_scroll
|
||||
clip: true
|
||||
anchors.fill: parent
|
||||
ScrollBar.vertical: multiline_text_srcoll_bar
|
||||
boundsBehavior: Flickable.StopAtBounds
|
||||
TextArea.flickable: FluMultilineTextBox {
|
||||
id:text_box
|
||||
text: String(display)
|
||||
readOnly: true === control.columnSource[column].readOnly
|
||||
verticalAlignment: TextInput.AlignVCenter
|
||||
isCtrlEnterForNewline: true
|
||||
Component.onCompleted: {
|
||||
forceActiveFocus()
|
||||
selectAll()
|
||||
}
|
||||
onPooled: {
|
||||
rightPadding: 34
|
||||
onCommit: {
|
||||
if(!readOnly){
|
||||
editTextChaged(text_box.text)
|
||||
}
|
||||
property bool isCurrent: d.current === itemModel
|
||||
id:item_container
|
||||
width: {
|
||||
var w = 46 + item_loader_cell.width + control.depthPadding*itemModel.depth
|
||||
if(control.width>w){
|
||||
return control.width
|
||||
}
|
||||
return w
|
||||
}
|
||||
height: control.cellHeight
|
||||
implicitWidth: width
|
||||
implicitHeight: height
|
||||
function toggle(){
|
||||
var pos = FluTools.cursorPos()
|
||||
var viewPos = table_view.mapToGlobal(0,0)
|
||||
d.dy = table_view.contentY + pos.y-viewPos.y
|
||||
if(itemModel.isExpanded){
|
||||
tree_model.collapse(rowIndex)
|
||||
}else{
|
||||
tree_model.expand(rowIndex)
|
||||
control.closeEditor()
|
||||
}
|
||||
}
|
||||
Rectangle{
|
||||
width: 3
|
||||
height: 18
|
||||
radius: 1.5
|
||||
color: FluTheme.primaryColor
|
||||
visible: isCurrent
|
||||
}
|
||||
FluIconButton{
|
||||
iconSource:FluentIcons.ChromeClose
|
||||
iconSize: 10
|
||||
width: 20
|
||||
height: 20
|
||||
padding: 0
|
||||
verticalPadding: 0
|
||||
horizontalPadding: 0
|
||||
visible: {
|
||||
if(text_box.readOnly)
|
||||
return false
|
||||
return text_box.text !== ""
|
||||
}
|
||||
anchors{
|
||||
left: parent.left
|
||||
leftMargin: 6
|
||||
verticalCenter: parent.verticalCenter
|
||||
right: parent.right
|
||||
rightMargin: 15
|
||||
}
|
||||
onClicked:{
|
||||
text_box.text = ""
|
||||
}
|
||||
}
|
||||
FluScrollBar{
|
||||
id:multiline_text_srcoll_bar
|
||||
anchors{
|
||||
right: parent.right
|
||||
rightMargin: 5
|
||||
top: parent.top
|
||||
bottom: parent.bottom
|
||||
topMargin: 3
|
||||
bottomMargin: 3
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Component{
|
||||
id:com_column
|
||||
Item{
|
||||
id:item_container
|
||||
clip: true
|
||||
function toggle(){
|
||||
if(rowModel.isExpanded){
|
||||
tree_model.collapse(row)
|
||||
}else{
|
||||
tree_model.expand(row)
|
||||
}
|
||||
delay_force_layout.restart()
|
||||
}
|
||||
MouseArea{
|
||||
id:item_mouse
|
||||
property point clickPos: Qt.point(0,0)
|
||||
anchors.fill: parent
|
||||
drag.target:control.draggable ? loader_container : undefined
|
||||
hoverEnabled: true
|
||||
drag.onActiveChanged: {
|
||||
if(drag.active){
|
||||
if(itemModel.isExpanded && itemModel.hasChildren()){
|
||||
tree_model.collapse(rowIndex)
|
||||
}
|
||||
d.dragIndex = rowIndex
|
||||
loader_container.sourceComponent = com_item_container
|
||||
}
|
||||
}
|
||||
onPressed:
|
||||
(mouse)=>{
|
||||
clickPos = Qt.point(mouse.x,mouse.y)
|
||||
loader_container.itemControl = itemControl
|
||||
loader_container.itemModel = itemModel
|
||||
var cellPosition = item_container.mapToItem(table_view, 0, 0)
|
||||
loader_container.width = item_container.width
|
||||
loader_container.height = item_container.height
|
||||
loader_container.x = 0
|
||||
loader_container.y = cellPosition.y
|
||||
}
|
||||
onClicked: {
|
||||
d.current = itemModel
|
||||
d.current = rowModel
|
||||
}
|
||||
onDoubleClicked: {
|
||||
if(itemModel.hasChildren()){
|
||||
if(rowModel.hasChildren()){
|
||||
item_container.toggle()
|
||||
}
|
||||
}
|
||||
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.dropIndex = -1
|
||||
return
|
||||
}
|
||||
if((mouse.x-table_view.contentX)>table_view.width || (mouse.x-table_view.contentX)<0){
|
||||
d.dropIndex = -1
|
||||
return
|
||||
}
|
||||
var pos = FluTools.cursorPos()
|
||||
var viewPos = table_view.mapToGlobal(0,0)
|
||||
var y = table_view.contentY + pos.y-viewPos.y
|
||||
var index = Math.floor(y/control.cellHeight)
|
||||
if(index<0 || index>table_view.count-1){
|
||||
d.dropIndex = -1
|
||||
return
|
||||
}
|
||||
if(tree_model.hitHasChildrenExpanded(index) && y>index*control.cellHeight+control.cellHeight/2){
|
||||
d.dropIndex = index + 1
|
||||
d.isDropTopArea = true
|
||||
}else{
|
||||
d.dropIndex = index
|
||||
if(y>index*control.cellHeight+control.cellHeight/2){
|
||||
d.isDropTopArea = false
|
||||
}else{
|
||||
d.isDropTopArea = true
|
||||
}
|
||||
}
|
||||
}
|
||||
onCanceled: {
|
||||
loader_container.sourceComponent = undefined
|
||||
loader_container.x = 0
|
||||
loader_container.y = 0
|
||||
d.dropIndex = -1
|
||||
d.dragIndex = -1
|
||||
}
|
||||
onReleased: {
|
||||
loader_container.sourceComponent = undefined
|
||||
if(d.dropIndex !== -1){
|
||||
tree_model.dragAndDrop(d.dragIndex,d.dropIndex,d.isDropTopArea)
|
||||
}
|
||||
d.dropIndex = -1
|
||||
d.dragIndex = -1
|
||||
loader_container.x = 0
|
||||
loader_container.y = 0
|
||||
}
|
||||
}
|
||||
Drag.active: item_mouse.drag.active
|
||||
Rectangle{
|
||||
id:item_line_drop_tip
|
||||
anchors{
|
||||
left: layout_row.left
|
||||
leftMargin: 26
|
||||
right: parent.right
|
||||
rightMargin: 10
|
||||
bottom: parent.bottom
|
||||
bottomMargin: -1.5
|
||||
top: undefined
|
||||
}
|
||||
states: [
|
||||
State {
|
||||
when:d.isDropTopArea
|
||||
AnchorChanges {
|
||||
target: item_line_drop_tip
|
||||
anchors.top: item_container.top
|
||||
anchors.bottom: undefined
|
||||
}
|
||||
PropertyChanges {
|
||||
target: item_line_drop_tip
|
||||
anchors.topMargin: -1.5
|
||||
}
|
||||
}
|
||||
]
|
||||
height: 3
|
||||
radius: 1.5
|
||||
color: d.hitColor
|
||||
visible: d.dropIndex === rowIndex
|
||||
Rectangle{
|
||||
width: 10
|
||||
height: 10
|
||||
radius: 5
|
||||
border.width: 3
|
||||
border.color: d.hitColor
|
||||
color: FluTheme.dark ? FluColors.Black : FluColors.White
|
||||
anchors{
|
||||
top: parent.top
|
||||
left: parent.left
|
||||
topMargin: -3
|
||||
leftMargin: -5
|
||||
}
|
||||
}
|
||||
}
|
||||
FluRectangle{
|
||||
width: 1
|
||||
color: control.lineColor
|
||||
visible: control.showLine && isItemLoader && itemModel.depth !== 0 && !itemModel.hasChildren()
|
||||
height: itemModel.hideLineFooter() ? parent.height/2 : parent.height
|
||||
visible: control.showLine && rowModel.depth !== 0 && !rowModel.hasChildren()
|
||||
height: rowModel.hideLineFooter() ? parent.height/2 : parent.height
|
||||
anchors{
|
||||
top: parent.top
|
||||
left: item_line_h.left
|
||||
@ -291,7 +194,7 @@ Item {
|
||||
id:item_line_h
|
||||
height: 1
|
||||
color: control.lineColor
|
||||
visible: control.showLine && isItemLoader && itemModel.depth !== 0 && !itemModel.hasChildren()
|
||||
visible: control.showLine && rowModel.depth !== 0 && !rowModel.hasChildren()
|
||||
width: depthPadding - 10
|
||||
anchors{
|
||||
right: layout_row.left
|
||||
@ -300,12 +203,12 @@ Item {
|
||||
}
|
||||
}
|
||||
Repeater{
|
||||
model: Math.max(itemModel.depth-1,0)
|
||||
model: Math.max(rowModel.depth-1,0)
|
||||
delegate: FluRectangle{
|
||||
required property int index
|
||||
width: 1
|
||||
color: control.lineColor
|
||||
visible: control.showLine && isItemLoader && itemModel.depth !== 0 && itemModel.hasNextNodeByIndex(index)
|
||||
visible: control.showLine && rowModel.depth !== 0 && rowModel.hasNextNodeByIndex(index)
|
||||
anchors{
|
||||
top:parent.top
|
||||
bottom: parent.bottom
|
||||
@ -314,57 +217,34 @@ Item {
|
||||
}
|
||||
}
|
||||
}
|
||||
Rectangle{
|
||||
anchors.fill: parent
|
||||
radius: 4
|
||||
anchors.leftMargin: 6
|
||||
anchors.rightMargin: 6
|
||||
border.color: d.hitColor
|
||||
border.width: d.dragIndex === rowIndex ? 1 : 0
|
||||
color: {
|
||||
if(isCurrent){
|
||||
return FluTheme.itemCheckColor
|
||||
}
|
||||
if(item_mouse.containsMouse || item_check_box.hovered){
|
||||
return FluTheme.itemHoverColor
|
||||
}
|
||||
if(item_loader_expand.item && item_loader_expand.item.hovered){
|
||||
return FluTheme.itemHoverColor
|
||||
}
|
||||
return FluTheme.itemNormalColor
|
||||
}
|
||||
}
|
||||
RowLayout{
|
||||
id:layout_row
|
||||
height: parent.height
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
anchors.left: parent.left
|
||||
anchors.fill: parent
|
||||
spacing: 0
|
||||
anchors.leftMargin: 14 + control.depthPadding*itemModel.depth
|
||||
anchors.leftMargin: 14 + control.depthPadding*rowModel.depth
|
||||
Component{
|
||||
id:com_icon_btn
|
||||
FluIconButton{
|
||||
opacity: itemModel.hasChildren()
|
||||
opacity: rowModel.hasChildren()
|
||||
onClicked: {
|
||||
item_container.toggle()
|
||||
}
|
||||
contentItem:FluIcon{
|
||||
rotation: itemModel.isExpanded?0:-90
|
||||
rotation: rowModel.isExpanded?0:-90
|
||||
iconSource:FluentIcons.ChevronDown
|
||||
iconSize: 16
|
||||
anchors.centerIn: parent
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
FluLoader{
|
||||
id:item_loader_expand
|
||||
Layout.preferredWidth: 20
|
||||
Layout.preferredHeight: 20
|
||||
sourceComponent: itemModel.hasChildren() ? com_icon_btn : undefined
|
||||
sourceComponent: rowModel.hasChildren() ? com_icon_btn : undefined
|
||||
Layout.alignment: Qt.AlignVCenter
|
||||
}
|
||||
|
||||
FluCheckBox{
|
||||
id:item_check_box
|
||||
Layout.preferredWidth: 18
|
||||
@ -372,39 +252,453 @@ Item {
|
||||
Layout.leftMargin: 5
|
||||
horizontalPadding:0
|
||||
verticalPadding: 0
|
||||
checked: itemModel.checked
|
||||
checked: rowModel.checked
|
||||
animationEnabled:false
|
||||
visible: control.checkable
|
||||
padding: 0
|
||||
clickListener: function(){
|
||||
tree_model.checkRow(rowIndex,!itemModel.checked)
|
||||
tree_model.checkRow(row,!rowModel.checked)
|
||||
}
|
||||
Layout.alignment: Qt.AlignVCenter
|
||||
}
|
||||
Item{
|
||||
Layout.fillHeight: true
|
||||
Layout.fillWidth: true
|
||||
Layout.leftMargin: 6
|
||||
FluText {
|
||||
id:item_text
|
||||
text: String(display)
|
||||
elide: Text.ElideRight
|
||||
verticalAlignment: Text.AlignVCenter
|
||||
anchors.fill: parent
|
||||
MouseArea{
|
||||
acceptedButtons: Qt.NoButton
|
||||
id: hover_handler
|
||||
hoverEnabled: true
|
||||
anchors.fill: parent
|
||||
}
|
||||
FluTooltip{
|
||||
text: item_text.text
|
||||
delay: 500
|
||||
visible: item_text.contentWidth < item_text.implicitWidth && hover_handler.containsMouse
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
Component{
|
||||
id:com_other
|
||||
FluText {
|
||||
id:item_text
|
||||
text: String(display)
|
||||
elide: Text.ElideRight
|
||||
wrapMode: Text.WrapAnywhere
|
||||
anchors{
|
||||
fill: parent
|
||||
leftMargin: 11
|
||||
rightMargin: 11
|
||||
topMargin: 6
|
||||
bottomMargin: 6
|
||||
}
|
||||
verticalAlignment: Text.AlignVCenter
|
||||
MouseArea{
|
||||
acceptedButtons: Qt.NoButton
|
||||
id: hover_handler
|
||||
hoverEnabled: true
|
||||
anchors.fill: parent
|
||||
}
|
||||
FluTooltip{
|
||||
text: item_text.text
|
||||
delay: 500
|
||||
visible: item_text.contentWidth < item_text.implicitWidth && item_text.contentHeight < item_text.implicitHeight && hover_handler.containsMouse
|
||||
}
|
||||
}
|
||||
}
|
||||
TableView{
|
||||
id:table_view
|
||||
ScrollBar.horizontal: FluScrollBar{}
|
||||
ScrollBar.vertical: FluScrollBar{}
|
||||
boundsBehavior: Flickable.StopAtBounds
|
||||
model: tree_model
|
||||
anchors{
|
||||
top: header_horizontal.bottom
|
||||
left: parent.left
|
||||
right: parent.right
|
||||
bottom: parent.bottom
|
||||
}
|
||||
clip: true
|
||||
columnWidthProvider: function(column) {
|
||||
var columnObject = control.columnSource[column]
|
||||
var width = columnObject.width
|
||||
if(width){
|
||||
return width
|
||||
}
|
||||
var minimumWidth = columnObject.minimumWidth
|
||||
if(minimumWidth){
|
||||
return minimumWidth
|
||||
}
|
||||
return d.defaultItemWidth
|
||||
}
|
||||
rowHeightProvider: function(row) {
|
||||
return control.cellHeight
|
||||
}
|
||||
delegate: MouseArea{
|
||||
property var rowObject : rowModel.data
|
||||
property alias isRowSelected: item_table_loader.isRowSelected
|
||||
property var display: rowModel.data[columnModel.dataIndex]
|
||||
property bool isObject: typeof(item_table.display) == "object"
|
||||
property bool editVisible: {
|
||||
if(rowObject && d.editPosition && d.editPosition._key === rowObject._key && d.editPosition.column === column){
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
implicitHeight: 30
|
||||
implicitWidth: 30
|
||||
id: item_table
|
||||
hoverEnabled: true
|
||||
onEntered: {
|
||||
d.rowHoverIndex = row
|
||||
}
|
||||
onWidthChanged: {
|
||||
if(editVisible){
|
||||
updateEditPosition()
|
||||
}
|
||||
}
|
||||
onHeightChanged: {
|
||||
if(editVisible){
|
||||
updateEditPosition()
|
||||
}
|
||||
}
|
||||
onXChanged: {
|
||||
if(editVisible){
|
||||
updateEditPosition()
|
||||
}
|
||||
}
|
||||
onYChanged: {
|
||||
if(editVisible){
|
||||
updateEditPosition()
|
||||
}
|
||||
}
|
||||
function updateEditPosition(){
|
||||
var obj = {}
|
||||
obj._key = rowObject._key
|
||||
obj.column = column
|
||||
obj.row = row
|
||||
obj.x = item_table.x
|
||||
obj.y = item_table.y + 1
|
||||
obj.width = item_table.width
|
||||
obj.height = item_table.height - 2
|
||||
d.editPosition = obj
|
||||
}
|
||||
onDoubleClicked:{
|
||||
if(typeof(display) == "object"){
|
||||
return
|
||||
}
|
||||
d.editDelegate = d.getEditDelegate(column)
|
||||
updateEditPosition()
|
||||
loader_edit.display = display
|
||||
}
|
||||
onClicked:
|
||||
(event)=>{
|
||||
d.current = rowModel
|
||||
event.accepted = true
|
||||
}
|
||||
Rectangle{
|
||||
anchors.fill: parent
|
||||
color:{
|
||||
if(item_table.isRowSelected){
|
||||
return control.selectedColor
|
||||
}
|
||||
if(d.rowHoverIndex === row || item_table.isRowSelected){
|
||||
return FluTheme.dark ? Qt.rgba(1,1,1,0.06) : Qt.rgba(0,0,0,0.06)
|
||||
}
|
||||
return (row%2!==0) ? control.color : (FluTheme.dark ? Qt.rgba(1,1,1,0.015) : Qt.rgba(0,0,0,0.015))
|
||||
}
|
||||
Item{
|
||||
anchors.fill: parent
|
||||
visible: item_table.isRowSelected
|
||||
Rectangle{
|
||||
width: 1
|
||||
height: parent.height
|
||||
anchors.left: parent.left
|
||||
color: control.selectedBorderColor
|
||||
visible: column === 0
|
||||
}
|
||||
Rectangle{
|
||||
width: 1
|
||||
height: parent.height
|
||||
anchors.right: parent.right
|
||||
color: control.selectedBorderColor
|
||||
visible: column === control.columnSource.length-1
|
||||
}
|
||||
Rectangle{
|
||||
width: parent.width
|
||||
height: 1
|
||||
anchors.top: parent.top
|
||||
color: control.selectedBorderColor
|
||||
}
|
||||
Rectangle{
|
||||
width: parent.width
|
||||
height: 1
|
||||
anchors.bottom: parent.bottom
|
||||
color: control.selectedBorderColor
|
||||
}
|
||||
}
|
||||
}
|
||||
FluLoader{
|
||||
property var dataModel: itemModel
|
||||
property var itemMouse: item_mouse
|
||||
id:item_loader_cell
|
||||
Layout.leftMargin: 10
|
||||
Layout.preferredWidth: {
|
||||
if(item){
|
||||
return item.width
|
||||
anchors.fill: parent
|
||||
id:item_table_loader
|
||||
property var rowModel : model.rowModel
|
||||
property var columnModel : model.columnModel
|
||||
property int row : model.row
|
||||
property int column: model.column
|
||||
property var display: item_table.display
|
||||
property bool isRowSelected: d.current === rowModel
|
||||
property var options: {
|
||||
if(isObject){
|
||||
return display.options
|
||||
}
|
||||
return {}
|
||||
}
|
||||
sourceComponent: {
|
||||
if(column === 0)
|
||||
return com_column
|
||||
if(item_table.isObject){
|
||||
return item_table.display.comId
|
||||
}
|
||||
return com_other
|
||||
}
|
||||
}
|
||||
}
|
||||
FluLoader{
|
||||
id:loader_edit
|
||||
property var tableView: control
|
||||
property var display
|
||||
property int column: {
|
||||
if(d.editPosition){
|
||||
return d.editPosition.column
|
||||
}
|
||||
return 0
|
||||
}
|
||||
Layout.fillHeight: true
|
||||
sourceComponent:com_item_text
|
||||
property int row: {
|
||||
if(d.editPosition){
|
||||
return d.editPosition.row
|
||||
}
|
||||
return 0
|
||||
}
|
||||
signal editTextChaged(string text)
|
||||
sourceComponent: d.editPosition ? d.editDelegate : undefined
|
||||
onEditTextChaged:
|
||||
(text)=>{
|
||||
const obj = tree_model.getRow(row).data
|
||||
obj[control.columnSource[column].dataIndex] = text
|
||||
tree_model.setRow(row,obj)
|
||||
}
|
||||
width: {
|
||||
if(d.editPosition){
|
||||
return d.editPosition.width
|
||||
}
|
||||
return 0
|
||||
}
|
||||
height: {
|
||||
if(d.editPosition){
|
||||
return d.editPosition.height
|
||||
}
|
||||
return 0
|
||||
}
|
||||
x:{
|
||||
if(d.editPosition){
|
||||
return d.editPosition.x
|
||||
}
|
||||
return 0
|
||||
}
|
||||
y:{
|
||||
if(d.editPosition){
|
||||
return d.editPosition.y
|
||||
}
|
||||
return 0
|
||||
}
|
||||
z:999
|
||||
}
|
||||
}
|
||||
TableModel{
|
||||
id:header_column_model
|
||||
TableModelColumn {}
|
||||
}
|
||||
Component{
|
||||
id:com_column_text
|
||||
FluText {
|
||||
id: column_text
|
||||
text: modelData
|
||||
anchors.fill: parent
|
||||
horizontalAlignment: Text.AlignHCenter
|
||||
verticalAlignment: Text.AlignVCenter
|
||||
}
|
||||
}
|
||||
Component{
|
||||
id:com_column_header_delegate
|
||||
Rectangle{
|
||||
id:column_item_control
|
||||
readonly property real cellPadding: 8
|
||||
property bool canceled: false
|
||||
property int columnIndex: column
|
||||
property var columnObject : control.columnSource[column]
|
||||
implicitWidth: {
|
||||
return (item_column_loader.item && item_column_loader.item.implicitWidth) + (cellPadding * 2)
|
||||
}
|
||||
implicitHeight: Math.max(36, (item_column_loader.item&&item_column_loader.item.implicitHeight) + (cellPadding * 2))
|
||||
color: FluTheme.dark ? Qt.rgba(50/255,50/255,50/255,1) : Qt.rgba(247/255,247/255,247/255,1)
|
||||
Rectangle{
|
||||
border.color: control.borderColor
|
||||
width: parent.width
|
||||
height: 1
|
||||
anchors.top: parent.top
|
||||
color:"#00000000"
|
||||
}
|
||||
Rectangle{
|
||||
border.color: control.borderColor
|
||||
width: parent.width
|
||||
height: 1
|
||||
anchors.bottom: parent.bottom
|
||||
color:"#00000000"
|
||||
}
|
||||
Rectangle{
|
||||
border.color: control.borderColor
|
||||
width: 1
|
||||
height: parent.height
|
||||
anchors.left: parent.left
|
||||
color:"#00000000"
|
||||
}
|
||||
Rectangle{
|
||||
border.color: control.borderColor
|
||||
width: 1
|
||||
height: parent.height
|
||||
anchors.right: parent.right
|
||||
color:"#00000000"
|
||||
visible: column === table_view.columns - 1
|
||||
}
|
||||
MouseArea{
|
||||
id:column_item_control_mouse
|
||||
anchors.fill: parent
|
||||
anchors.rightMargin: 6
|
||||
hoverEnabled: true
|
||||
onCanceled: {
|
||||
column_item_control.canceled = true
|
||||
}
|
||||
onContainsMouseChanged: {
|
||||
if(!containsMouse){
|
||||
column_item_control.canceled = false
|
||||
}
|
||||
}
|
||||
onClicked:
|
||||
(event)=>{
|
||||
|
||||
}
|
||||
}
|
||||
FluLoader{
|
||||
id:item_column_loader
|
||||
property var itemModel: model
|
||||
property var modelData: model.display
|
||||
property var tableView: table_view
|
||||
property var options:{
|
||||
if(typeof(modelData) == "object"){
|
||||
return modelData.options
|
||||
}
|
||||
return {}
|
||||
}
|
||||
property int column: column_item_control.columnIndex
|
||||
width: parent.width
|
||||
height: parent.height
|
||||
sourceComponent: {
|
||||
if(typeof(modelData) == "object"){
|
||||
return modelData.comId
|
||||
}
|
||||
return com_column_text
|
||||
}
|
||||
}
|
||||
MouseArea{
|
||||
property point clickPos: "0,0"
|
||||
height: parent.height
|
||||
width: 6
|
||||
anchors.right: parent.right
|
||||
acceptedButtons: Qt.LeftButton
|
||||
hoverEnabled: true
|
||||
visible: !(columnObject.width === columnObject.minimumWidth && columnObject.width === columnObject.maximumWidth && columnObject.width)
|
||||
cursorShape: Qt.SplitHCursor
|
||||
preventStealing: true
|
||||
onPressed :
|
||||
(mouse)=>{
|
||||
FluTools.setOverrideCursor(Qt.SplitHCursor)
|
||||
clickPos = Qt.point(mouse.x, mouse.y)
|
||||
}
|
||||
onReleased:{
|
||||
FluTools.restoreOverrideCursor()
|
||||
}
|
||||
onCanceled: {
|
||||
FluTools.restoreOverrideCursor()
|
||||
}
|
||||
onPositionChanged:
|
||||
(mouse)=>{
|
||||
if(!pressed){
|
||||
return
|
||||
}
|
||||
var delta = Qt.point(mouse.x - clickPos.x, mouse.y - clickPos.y)
|
||||
var minimumWidth = columnObject.minimumWidth
|
||||
var maximumWidth = columnObject.maximumWidth
|
||||
var w = columnObject.width
|
||||
if(!w){
|
||||
w = d.defaultItemWidth
|
||||
}
|
||||
if(!minimumWidth){
|
||||
minimumWidth = d.defaultItemWidth
|
||||
}
|
||||
if(!maximumWidth){
|
||||
maximumWidth = 65535
|
||||
}
|
||||
columnObject.width = Math.min(Math.max(minimumWidth, w + delta.x),maximumWidth)
|
||||
table_view.forceLayout()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TableView {
|
||||
id: header_horizontal
|
||||
model: header_column_model
|
||||
anchors{
|
||||
left: table_view.left
|
||||
right: table_view.right
|
||||
top: parent.top
|
||||
}
|
||||
height: Math.max(1, contentHeight)
|
||||
boundsBehavior: Flickable.StopAtBounds
|
||||
clip: true
|
||||
syncDirection: Qt.Horizontal
|
||||
columnWidthProvider: table_view.columnWidthProvider
|
||||
syncView: table_view.rows === 0 ? null : table_view
|
||||
onContentXChanged:{
|
||||
timer_horizontal_force_layout.restart()
|
||||
}
|
||||
Timer{
|
||||
id:timer_horizontal_force_layout
|
||||
interval: 50
|
||||
onTriggered: {
|
||||
header_horizontal.forceLayout()
|
||||
}
|
||||
}
|
||||
delegate: com_column_header_delegate
|
||||
}
|
||||
|
||||
Component{
|
||||
id:com_item_text
|
||||
Item{
|
||||
width: item_text.width
|
||||
FluText {
|
||||
id:item_text
|
||||
text: dataModel.title
|
||||
text: model.title
|
||||
rightPadding: 14
|
||||
anchors.centerIn: parent
|
||||
color:{
|
||||
@ -423,7 +717,7 @@ Item {
|
||||
return tree_model.dataSourceSize
|
||||
}
|
||||
function visibleCount(){
|
||||
return table_view.count
|
||||
return table_view.rows
|
||||
}
|
||||
function collapse(rowIndex){
|
||||
tree_model.collapse(rowIndex)
|
||||
@ -437,4 +731,14 @@ Item {
|
||||
function allCollapse(){
|
||||
tree_model.allCollapse()
|
||||
}
|
||||
function customItem(comId,options={}){
|
||||
var o = {}
|
||||
o.comId = comId
|
||||
o.options = options
|
||||
return o
|
||||
}
|
||||
function closeEditor(){
|
||||
d.editPosition = undefined
|
||||
d.editDelegate = undefined
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user