diff --git a/CMakeLists.txt b/CMakeLists.txt
index 9d416420..3ef5a1d8 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -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)
diff --git a/example/example_en_US.ts b/example/example_en_US.ts
index f20047c2..47476754 100644
--- a/example/example_en_US.ts
+++ b/example/example_en_US.ts
@@ -475,46 +475,51 @@
-
+
-
+
-
+
-
+
+
+
+
+
+
-
+
-
+
-
+
-
+
@@ -2376,13 +2381,23 @@ Some contents...
-
-
+
+
-
-
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/example/example_zh_CN.ts b/example/example_zh_CN.ts
index 048a6c55..8ae59fac 100644
--- a/example/example_zh_CN.ts
+++ b/example/example_zh_CN.ts
@@ -475,46 +475,51 @@
+
+
+
+
+
二维码
-
+
游览
-
+
时间轴
-
+
验证码
-
+
网络
-
+
远程加载
-
+
热加载
-
+
3D
-
+
测试崩溃
@@ -2459,14 +2464,32 @@ Some contents...
树
-
- 共计%1条数据,当前显示的%2条数据
+ 共计%1条数据,当前显示的%2条数据
-
- 共计选中%1条数据
+ 共计选中%1条数据
+
+
+
+
+ 标题
+
+
+
+
+ 地址
+
+
+
+
+ 头像
+
+
+
+
+ 名称
diff --git a/example/qml/global/ItemsOriginal.qml b/example/qml/global/ItemsOriginal.qml
index 47615f0a..8e96b2e0 100644
--- a/example/qml/global/ItemsOriginal.qml
+++ b/example/qml/global/ItemsOriginal.qml
@@ -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
diff --git a/example/qml/page/T_TreeView.qml b/example/qml/page/T_TreeView.qml
index df7d47f2..c1ead5f5 100644
--- a/example/qml/page/T_TreeView.qml
+++ b/example/qml/page/T_TreeView.qml
@@ -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,99 +48,202 @@ FluContentPage {
return dig();
}
- Column{
- id: layout_column
- spacing: 12
- width: 300
- anchors{
- top:parent.top
- left: parent.left
- leftMargin: 10
- bottom:parent.bottom
- bottomMargin: 20
- }
+ // 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()
+ // }
+ // }
+ // }
- 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)
- }
-
- 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: 30
- from: 30
- to:100
- }
- }
- FluToggleSwitch{
- id: switch_showline
- text:"showLine"
- checked: false
- }
- FluToggleSwitch{
- id: switch_draggable
- text:"draggable"
- 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: layout_column.right
+ left: parent.left
+ right: parent.right
top: parent.top
+ topMargin: 10
+ }
+ height: 80
+ clip: true
+ Row{
+ spacing: 12
+ anchors{
+ left: parent.left
+ leftMargin: 10
+ verticalCenter: parent.verticalCenter
+ }
+ Column{
+ anchors.verticalCenter: parent.verticalCenter
+ RowLayout{
+ spacing: 10
+ FluText{
+ text: "cellHeight:"
+ Layout.alignment: Qt.AlignVCenter
+ }
+ FluSlider{
+ id: slider_cell_height
+ value: 38
+ from: 38
+ to:100
+ }
+ }
+ RowLayout{
+ spacing: 10
+ FluText{
+ text: "depthPadding:"
+ Layout.alignment: Qt.AlignVCenter
+ }
+ FluSlider{
+ id: slider_depth_padding
+ value: 15
+ from: 15
+ to:100
+ }
+ }
+ }
+ Column{
+ spacing: 8
+ anchors.verticalCenter: parent.verticalCenter
+ FluToggleSwitch{
+ id: switch_showline
+ text:"showLine"
+ checked: false
+ }
+ FluToggleSwitch{
+ id: switch_checkable
+ text:"checkable"
+ checked: false
+ }
+ }
+ Column{
+ spacing: 8
+ anchors.verticalCenter: parent.verticalCenter
+ FluButton{
+ text: "all expand"
+ onClicked: {
+ tree_view.allExpand()
+ }
+ }
+ FluButton{
+ text: "all collapse"
+ onClicked: {
+ tree_view.allCollapse()
+ }
+ }
+ }
+
+ }
+ }
+
+ FluFrame{
+ anchors{
+ 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
diff --git a/src/FluTreeModel.cpp b/src/FluTreeModel.cpp
index f53fede8..d2c3b5b9 100644
--- a/src/FluTreeModel.cpp
+++ b/src/FluTreeModel.cpp
@@ -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:
- return QVariant::fromValue(_rows.at(index.row()));
+ 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 FluTreeModel::roleNames() const {
- return { {Qt::DisplayRole, "dataModel"} };
+ return {
+ {TreeModelRoles::RowModel, "rowModel"},
+ {TreeModelRoles::ColumnModel, "columnModel"}
+ };
};
void FluTreeModel::setData(QList 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> 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();
+ 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* 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* srcChildren = &(dragItem->_parent->_children);
- QList* 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 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 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){
diff --git a/src/FluTreeModel.h b/src/FluTreeModel.h
index 9b588d3d..a64e1efb 100644
--- a/src/FluTreeModel.h
+++ b/src/FluTreeModel.h
@@ -4,6 +4,7 @@
#include
#include
#include
+#include
#include
#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 _children;
FluTreeNode* _parent = nullptr;
};
@@ -84,9 +83,14 @@ class FluTreeModel : public QAbstractItemModel
Q_OBJECT
Q_PROPERTY_AUTO(int,dataSourceSize)
Q_PROPERTY_AUTO(QList,selectionModel)
+ Q_PROPERTY_AUTO(QList,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 data);
Q_INVOKABLE QObject* getRow(int row);
+ Q_INVOKABLE void setRow(int row,QVariantMap data);
Q_INVOKABLE void setData(QList data);
Q_INVOKABLE void setDataSource(QList> 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);
diff --git a/src/FluWatermark.cpp b/src/FluWatermark.cpp
index 363de1f5..54f2405e 100644
--- a/src/FluWatermark.cpp
+++ b/src/FluWatermark.cpp
@@ -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);
diff --git a/src/Qt5/imports/FluentUI/Controls/FluAcrylic.qml b/src/Qt5/imports/FluentUI/Controls/FluAcrylic.qml
index 5ee5ddfb..66d06fb1 100644
--- a/src/Qt5/imports/FluentUI/Controls/FluAcrylic.qml
+++ b/src/Qt5/imports/FluentUI/Controls/FluAcrylic.qml
@@ -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
diff --git a/src/Qt5/imports/FluentUI/Controls/FluTableView.qml b/src/Qt5/imports/FluentUI/Controls/FluTableView.qml
index 68891d97..3a6d429c 100644
--- a/src/Qt5/imports/FluentUI/Controls/FluTableView.qml
+++ b/src/Qt5/imports/FluentUI/Controls/FluTableView.qml
@@ -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{
diff --git a/src/Qt5/imports/FluentUI/Controls/FluTreeView.qml b/src/Qt5/imports/FluentUI/Controls/FluTreeView.qml
index 59e33919..6fb81008 100644
--- a/src/Qt5/imports/FluentUI/Controls/FluTreeView.qml
+++ b/src/Qt5/imports/FluentUI/Controls/FluTreeView.qml
@@ -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
- }
- NumberAnimation {
- properties: "opacity"
- duration: 83
- from: 0
- to: 1
- }
- }
+ onDepthPaddingChanged: {
+ table_view.forceLayout()
+ }
+ onCellHeightChanged: {
+ table_view.forceLayout()
+ }
+ onCheckableChanged: {
+ delay_force_layout.restart()
+ }
+ Timer{
+ id:delay_force_layout
+ interval: 30
+ onTriggered: {
+ table_view.forceLayout()
}
- move: Transition {
- NumberAnimation { property: "y"; duration: 200 }
- }
- 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
- }
+ }
+ 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
}
- }
- delegate: Item {
- id:item_control
- implicitWidth: item_loader_container.width
- implicitHeight: item_loader_container.height
- ListView.onReused: {
- item_loader_container.item.reused()
+ if(control.columnSource[column].editMultiline === true){
+ return com_edit_multiline
}
- 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: {
-
- }
- onPooled: {
- }
- 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)
+ 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()
+ }
+ rightPadding: 34
+ onCommit: {
+ if(!readOnly){
+ editTextChaged(text_box.text)
+ }
+ 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
}
- FluLoader{
- property var dataModel: itemModel
- property var itemMouse: item_mouse
- id:item_loader_cell
- Layout.leftMargin: 10
- Layout.preferredWidth: {
- if(item){
- return item.width
- }
- return 0
- }
+ Item{
Layout.fillHeight: true
- sourceComponent:com_item_text
+ 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{
+ 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
+ }
+ 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
+ }
}
diff --git a/src/Qt5/imports/FluentUI/plugins.qmltypes b/src/Qt5/imports/FluentUI/plugins.qmltypes
index c1bda21d..365b380d 100644
--- a/src/Qt5/imports/FluentUI/plugins.qmltypes
+++ b/src/Qt5/imports/FluentUI/plugins.qmltypes
@@ -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" }
+ Property { name: "columnSource"; type: "QList" }
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" }
diff --git a/src/Qt6/imports/FluentUI/Controls/FluAcrylic.qml b/src/Qt6/imports/FluentUI/Controls/FluAcrylic.qml
index 035fe423..7a76e91f 100644
--- a/src/Qt6/imports/FluentUI/Controls/FluAcrylic.qml
+++ b/src/Qt6/imports/FluentUI/Controls/FluAcrylic.qml
@@ -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
diff --git a/src/Qt6/imports/FluentUI/Controls/FluTableView.qml b/src/Qt6/imports/FluentUI/Controls/FluTableView.qml
index 4ff45c9e..a8634eb6 100644
--- a/src/Qt6/imports/FluentUI/Controls/FluTableView.qml
+++ b/src/Qt6/imports/FluentUI/Controls/FluTableView.qml
@@ -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{
diff --git a/src/Qt6/imports/FluentUI/Controls/FluTreeView.qml b/src/Qt6/imports/FluentUI/Controls/FluTreeView.qml
index e08e5dbd..d698deea 100644
--- a/src/Qt6/imports/FluentUI/Controls/FluTreeView.qml
+++ b/src/Qt6/imports/FluentUI/Controls/FluTreeView.qml
@@ -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
- }
- NumberAnimation {
- properties: "opacity"
- duration: 83
- from: 0
- to: 1
- }
- }
+ onDepthPaddingChanged: {
+ table_view.forceLayout()
+ }
+ onCellHeightChanged: {
+ table_view.forceLayout()
+ }
+ onCheckableChanged: {
+ delay_force_layout.restart()
+ }
+ Timer{
+ id:delay_force_layout
+ interval: 30
+ onTriggered: {
+ table_view.forceLayout()
}
- move: Transition {
- NumberAnimation { property: "y"; duration: 200 }
- }
- 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
- }
+ }
+ 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
}
- }
- delegate: Item {
- id:item_control
- implicitWidth: item_loader_container.width
- implicitHeight: item_loader_container.height
- ListView.onReused: {
- item_loader_container.item.reused()
+ if(control.columnSource[column].editMultiline === true){
+ return com_edit_multiline
}
- 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: {
-
- }
- onPooled: {
- }
- 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)
+ 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()
+ }
+ rightPadding: 34
+ onCommit: {
+ if(!readOnly){
+ editTextChaged(text_box.text)
+ }
+ 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
}
- FluLoader{
- property var dataModel: itemModel
- property var itemMouse: item_mouse
- id:item_loader_cell
- Layout.leftMargin: 10
- Layout.preferredWidth: {
- if(item){
- return item.width
- }
- return 0
- }
+ Item{
Layout.fillHeight: true
- sourceComponent:com_item_text
+ 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{
+ 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
+ }
+ 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
+ }
}