Compare commits

..

28 Commits

Author SHA1 Message Date
18685b17ec update 2024-05-03 16:56:40 +08:00
0eb4d9f346 update 2024-05-03 01:54:38 +08:00
8015dcc2f1 update 2024-05-02 23:52:30 +08:00
0b1755e9eb update 2024-05-01 01:11:25 +08:00
e471d5a230 update 2024-04-30 19:38:05 +08:00
f922978338 update 2024-04-30 19:27:57 +08:00
91bda2a22c update 2024-04-30 13:07:46 +08:00
6638fe2e06 update 2024-04-30 13:06:27 +08:00
bf001d99d2 update 2024-04-30 12:59:09 +08:00
30531079b5 update 2024-04-29 10:12:34 +08:00
a746bc2684 update 2024-04-28 21:05:43 +08:00
96a6d0e7fa update 2024-04-28 20:22:05 +08:00
c733f3c60e update 2024-04-28 18:38:37 +08:00
effd9f3058 update 2024-04-28 18:19:21 +08:00
d93aac3518 update 2024-04-28 15:56:37 +08:00
5f6745b630 udpate 2024-04-28 13:03:20 +08:00
4f202831b8 Merge branch 'main' of https://github.com/zhuzichu520/FluentUI 2024-04-28 10:51:29 +08:00
29cee84edd update 2024-04-28 10:51:13 +08:00
2d4e61445e Merge pull request #488 from yanhuacuo/path-for-insertRow
Add the functionality to insert new rows into the table
2024-04-28 10:47:28 +08:00
cc79854191 Merge pull request #489 from w-jt/main
FluPagination.qml 添加自定义控件,通过header和footer属性添加控件
2024-04-28 10:46:47 +08:00
500efa6298 添加自定义控件,通过header和footer属性添加控件
添加自定义控件,通过header和footer属性添加控件
2024-04-27 11:54:42 +08:00
355332da96 添加自定义控件,通过header和footer属性添加控件
添加自定义控件,通过header和footer属性添加控件
2024-04-27 11:53:57 +08:00
a0d662a8a5 添加自定义控件,通过header和footer属性添加控件
添加自定义控件,通过header和footer属性添加控件
2024-04-27 11:49:29 +08:00
aecc3fe3b4 添加自定义控件,通过header和footer属性添加控件
添加自定义控件,通过header和footer属性添加控件
2024-04-27 11:48:19 +08:00
3554fb99cd Add the functionality to insert new rows into the table 2024-04-27 09:40:37 +08:00
24fdff7e35 fix bug 2024-04-25 00:08:18 +08:00
d2fdd08604 update 2024-04-24 17:24:31 +08:00
1f5d6ce1aa update 2024-04-24 17:12:00 +08:00
36 changed files with 1294 additions and 738 deletions

View File

@ -1292,6 +1292,7 @@ My only desire is to be permitted to drive out the traitors and restore the Han.
<message> <message>
<location filename="qml/page/T_GroupBox.qml" line="24"/> <location filename="qml/page/T_GroupBox.qml" line="24"/>
<source>RadioButton Group</source> <source>RadioButton Group</source>
<oldsource>RadioButton Group111111111111111111111111</oldsource>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
</context> </context>
@ -1331,12 +1332,7 @@ My only desire is to be permitted to drive out the traitors and restore the Han.
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="qml/page/T_Icons.qml" line="20"/> <location filename="qml/page/T_Icons.qml" line="51"/>
<source>Search</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="qml/page/T_Icons.qml" line="60"/>
<source>You Copied </source> <source>You Copied </source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
@ -1968,7 +1964,7 @@ Some contents...</source>
</message> </message>
<message> <message>
<location filename="qml/page/T_TableView.qml" line="177"/> <location filename="qml/page/T_TableView.qml" line="177"/>
<location filename="qml/page/T_TableView.qml" line="478"/> <location filename="qml/page/T_TableView.qml" line="509"/>
<source>Name</source> <source>Name</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
@ -1988,60 +1984,70 @@ Some contents...</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="qml/page/T_TableView.qml" line="337"/> <location filename="qml/page/T_TableView.qml" line="365"/>
<source>Age</source> <source>Age</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="qml/page/T_TableView.qml" line="412"/> <location filename="qml/page/T_TableView.qml" line="440"/>
<source>Clear All</source> <source>Clear All</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="qml/page/T_TableView.qml" line="473"/> <location filename="qml/page/T_TableView.qml" line="447"/>
<source>Avatar</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="qml/page/T_TableView.qml" line="491"/>
<source>Address</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="qml/page/T_TableView.qml" line="498"/>
<source>Nickname</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="qml/page/T_TableView.qml" line="505"/>
<source>Long String</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="qml/page/T_TableView.qml" line="513"/>
<source>Options</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="qml/page/T_TableView.qml" line="532"/>
<source>&lt;Previous</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="qml/page/T_TableView.qml" line="533"/>
<source>Next&gt;</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="qml/page/T_TableView.qml" line="419"/>
<source>Delete Selection</source> <source>Delete Selection</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="qml/page/T_TableView.qml" line="443"/> <location filename="qml/page/T_TableView.qml" line="470"/>
<source>Add a row of Data</source> <source>Add a row of Data</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message>
<location filename="qml/page/T_TableView.qml" line="476"/>
<source>Insert a Row</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="qml/page/T_TableView.qml" line="483"/>
<source>Focus not acquired: Please click any item in the form as the target for insertion!</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="qml/page/T_TableView.qml" line="514"/>
<source>Avatar</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="qml/page/T_TableView.qml" line="528"/>
<source>Address</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="qml/page/T_TableView.qml" line="536"/>
<source>Nickname</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="qml/page/T_TableView.qml" line="543"/>
<source>Long String</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="qml/page/T_TableView.qml" line="551"/>
<source>Options</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="qml/page/T_TableView.qml" line="569"/>
<source>&lt;Previous</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="qml/page/T_TableView.qml" line="570"/>
<source>Next&gt;</source>
<translation type="unfinished"></translation>
</message>
</context> </context>
<context> <context>
<name>T_Text</name> <name>T_Text</name>
@ -2193,12 +2199,12 @@ Some contents...</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="qml/page/T_Timeline.qml" line="115"/> <location filename="qml/page/T_Timeline.qml" line="114"/>
<source>Append</source> <source>Append</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="qml/page/T_Timeline.qml" line="121"/> <location filename="qml/page/T_Timeline.qml" line="120"/>
<source>clear</source> <source>clear</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>

View File

@ -1378,6 +1378,7 @@ My only desire is to be permitted to drive out the traitors and restore the Han.
<message> <message>
<location filename="qml/page/T_GroupBox.qml" line="24"/> <location filename="qml/page/T_GroupBox.qml" line="24"/>
<source>RadioButton Group</source> <source>RadioButton Group</source>
<oldsource>RadioButton Group111111111111111111111111</oldsource>
<translation type="unfinished">单选框分组</translation> <translation type="unfinished">单选框分组</translation>
</message> </message>
</context> </context>
@ -1417,12 +1418,11 @@ My only desire is to be permitted to drive out the traitors and restore the Han.
<translation type="unfinished">请输入关键字</translation> <translation type="unfinished">请输入关键字</translation>
</message> </message>
<message> <message>
<location filename="qml/page/T_Icons.qml" line="20"/>
<source>Search</source> <source>Search</source>
<translation type="unfinished">搜索</translation> <translation type="obsolete">搜索</translation>
</message> </message>
<message> <message>
<location filename="qml/page/T_Icons.qml" line="60"/> <location filename="qml/page/T_Icons.qml" line="51"/>
<source>You Copied </source> <source>You Copied </source>
<translation type="unfinished">您复制</translation> <translation type="unfinished">您复制</translation>
</message> </message>
@ -2110,7 +2110,7 @@ Some contents...</source>
</message> </message>
<message> <message>
<location filename="qml/page/T_TableView.qml" line="177"/> <location filename="qml/page/T_TableView.qml" line="177"/>
<location filename="qml/page/T_TableView.qml" line="478"/> <location filename="qml/page/T_TableView.qml" line="509"/>
<source>Name</source> <source>Name</source>
<translation type="unfinished">名称</translation> <translation type="unfinished">名称</translation>
</message> </message>
@ -2130,57 +2130,67 @@ Some contents...</source>
<translation type="unfinished">全选</translation> <translation type="unfinished">全选</translation>
</message> </message>
<message> <message>
<location filename="qml/page/T_TableView.qml" line="337"/> <location filename="qml/page/T_TableView.qml" line="365"/>
<source>Age</source> <source>Age</source>
<translation type="unfinished">年龄</translation> <translation type="unfinished">年龄</translation>
</message> </message>
<message> <message>
<location filename="qml/page/T_TableView.qml" line="412"/> <location filename="qml/page/T_TableView.qml" line="440"/>
<source>Clear All</source> <source>Clear All</source>
<translation type="unfinished">清除所有</translation> <translation type="unfinished">清除所有</translation>
</message> </message>
<message> <message>
<location filename="qml/page/T_TableView.qml" line="473"/> <location filename="qml/page/T_TableView.qml" line="476"/>
<source>Insert a Row</source>
<translation type="unfinished">插入一行</translation>
</message>
<message>
<location filename="qml/page/T_TableView.qml" line="483"/>
<source>Focus not acquired: Please click any item in the form as the target for insertion!</source>
<translation type="unfinished">焦点未获取:请点击表格中的任意一项,作为插入的靶点!</translation>
</message>
<message>
<location filename="qml/page/T_TableView.qml" line="514"/>
<source>Avatar</source> <source>Avatar</source>
<translation type="unfinished">头像</translation> <translation type="unfinished">头像</translation>
</message> </message>
<message> <message>
<location filename="qml/page/T_TableView.qml" line="491"/> <location filename="qml/page/T_TableView.qml" line="528"/>
<source>Address</source> <source>Address</source>
<translation type="unfinished">地址</translation> <translation type="unfinished">地址</translation>
</message> </message>
<message> <message>
<location filename="qml/page/T_TableView.qml" line="498"/> <location filename="qml/page/T_TableView.qml" line="536"/>
<source>Nickname</source> <source>Nickname</source>
<translation type="unfinished">昵称</translation> <translation type="unfinished">昵称</translation>
</message> </message>
<message> <message>
<location filename="qml/page/T_TableView.qml" line="505"/> <location filename="qml/page/T_TableView.qml" line="543"/>
<source>Long String</source> <source>Long String</source>
<translation type="unfinished">长字符串</translation> <translation type="unfinished">长字符串</translation>
</message> </message>
<message> <message>
<location filename="qml/page/T_TableView.qml" line="513"/> <location filename="qml/page/T_TableView.qml" line="551"/>
<source>Options</source> <source>Options</source>
<translation type="unfinished">操作</translation> <translation type="unfinished">操作</translation>
</message> </message>
<message> <message>
<location filename="qml/page/T_TableView.qml" line="532"/> <location filename="qml/page/T_TableView.qml" line="569"/>
<source>&lt;Previous</source> <source>&lt;Previous</source>
<translation type="unfinished">&lt;上一页</translation> <translation type="unfinished">&lt;上一页</translation>
</message> </message>
<message> <message>
<location filename="qml/page/T_TableView.qml" line="533"/> <location filename="qml/page/T_TableView.qml" line="570"/>
<source>Next&gt;</source> <source>Next&gt;</source>
<translation type="unfinished">下一页&gt;</translation> <translation type="unfinished">下一页&gt;</translation>
</message> </message>
<message> <message>
<location filename="qml/page/T_TableView.qml" line="419"/> <location filename="qml/page/T_TableView.qml" line="447"/>
<source>Delete Selection</source> <source>Delete Selection</source>
<translation type="unfinished">删除选中</translation> <translation type="unfinished">删除选中</translation>
</message> </message>
<message> <message>
<location filename="qml/page/T_TableView.qml" line="443"/> <location filename="qml/page/T_TableView.qml" line="470"/>
<source>Add a row of Data</source> <source>Add a row of Data</source>
<translation type="unfinished">添加一行数据</translation> <translation type="unfinished">添加一行数据</translation>
</message> </message>
@ -2335,12 +2345,12 @@ Some contents...</source>
<translation type="unfinished">时间轴</translation> <translation type="unfinished">时间轴</translation>
</message> </message>
<message> <message>
<location filename="qml/page/T_Timeline.qml" line="115"/> <location filename="qml/page/T_Timeline.qml" line="114"/>
<source>Append</source> <source>Append</source>
<translation type="unfinished">追加</translation> <translation type="unfinished">追加</translation>
</message> </message>
<message> <message>
<location filename="qml/page/T_Timeline.qml" line="121"/> <location filename="qml/page/T_Timeline.qml" line="120"/>
<source>clear</source> <source>clear</source>
<translation type="unfinished">清空</translation> <translation type="unfinished">清空</translation>
</message> </message>

View File

@ -14,17 +14,8 @@ FluContentPage {
anchors{ anchors{
top: parent.top top: parent.top
} }
} onTextChanged: {
grid_view.model = FluApp.iconData(text_box.text)
FluFilledButton{
text: qsTr("Search")
anchors{
left: text_box.right
verticalCenter: text_box.verticalCenter
leftMargin: 14
}
onClicked: {
grid_view.model = FluApp.iconDatas(text_box.text)
} }
} }
GridView{ GridView{
@ -33,7 +24,7 @@ FluContentPage {
cellHeight: 110 cellHeight: 110
clip: true clip: true
boundsBehavior: GridView.StopAtBounds boundsBehavior: GridView.StopAtBounds
model: FluApp.iconDatas() model: FluApp.iconData()
ScrollBar.vertical: FluScrollBar {} ScrollBar.vertical: FluScrollBar {}
anchors{ anchors{
topMargin: 10 topMargin: 10

View File

@ -13,7 +13,7 @@ FluContentPage{
property var dataSource : [] property var dataSource : []
property int sortType: 0 property int sortType: 0
property bool seletedAll: true property bool selectedAll: true
property string nameKeyword: "" property string nameKeyword: ""
onNameKeywordChanged: { onNameKeywordChanged: {
@ -32,11 +32,11 @@ FluContentPage{
onCheckBoxChanged: { onCheckBoxChanged: {
for(var i =0;i< table_view.rows ;i++){ for(var i =0;i< table_view.rows ;i++){
if(false === table_view.getRow(i).checkbox.options.checked){ if(false === table_view.getRow(i).checkbox.options.checked){
root.seletedAll = false root.selectedAll = false
return return
} }
} }
root.seletedAll = true root.selectedAll = true
} }
onSortTypeChanged: { onSortTypeChanged: {
@ -238,13 +238,15 @@ FluContentPage{
Layout.alignment: Qt.AlignVCenter Layout.alignment: Qt.AlignVCenter
} }
FluCheckBox{ FluCheckBox{
checked: true === root.seletedAll checked: true === root.selectedAll
animationEnabled: false animationEnabled: false
Layout.alignment: Qt.AlignVCenter Layout.alignment: Qt.AlignVCenter
clickListener: function(){ clickListener: function(){
root.seletedAll = !root.seletedAll root.selectedAll = !root.selectedAll
var checked = root.seletedAll var checked = root.selectedAll
itemModel.display = table_view.customItem(com_column_checbox,{"checked":checked}) var columnModel = model.display
columnModel.title = table_view.customItem(com_column_checbox,{"checked":checked})
model.display = columnModel
for(var i =0;i< table_view.rows ;i++){ for(var i =0;i< table_view.rows ;i++){
var rowData = table_view.getRow(i) var rowData = table_view.getRow(i)
rowData.checkbox = table_view.customItem(com_checbox,{"checked":checked}) rowData.checkbox = table_view.customItem(com_checbox,{"checked":checked})
@ -271,7 +273,8 @@ FluContentPage{
} }
Component.onCompleted: { Component.onCompleted: {
currentIndex=["100","300","500","1000"].findIndex((element) => element === display) currentIndex=["100","300","500","1000"].findIndex((element) => element === display)
selectAll() textBox.forceActiveFocus()
textBox.selectAll()
} }
onCommit: { onCommit: {
editTextChaged(editText) editTextChaged(editText)
@ -280,6 +283,29 @@ FluContentPage{
} }
} }
Component{
id:com_auto_suggestbox
FluAutoSuggestBox {
id: textbox
anchors.fill: parent
focus: true
Component.onCompleted: {
var data = ["傲来国界花果山水帘洞","傲来国界坎源山脏水洞","大唐国界黑风山黑风洞","大唐国界黄风岭黄风洞","大唐国界骷髅山白骨洞","宝象国界碗子山波月洞","宝象国界平顶山莲花洞","宝象国界压龙山压龙洞","乌鸡国界号山枯松涧火云洞","乌鸡国界衡阳峪黑水河河神府"]
var result = data.map(function(item) {
return {title: item};
});
items = result
textbox.text= String(display)
forceActiveFocus()
selectAll()
}
onCommit: {
editTextChaged(textbox.text)
tableView.closeEditor()
}
}
}
Component{ Component{
id:com_avatar id:com_avatar
Item{ Item{
@ -323,7 +349,9 @@ FluContentPage{
cursorShape: Qt.PointingHandCursor cursorShape: Qt.PointingHandCursor
onClicked: { onClicked: {
custom_update_dialog.showDialog(options.title,function(text){ custom_update_dialog.showDialog(options.title,function(text){
itemModel.display = table_view.customItem(com_column_update_title,{"title":text}) var columnModel = model.display
columnModel.title = table_view.customItem(com_column_update_title,{"title":text})
model.display = columnModel
}) })
} }
} }
@ -421,15 +449,15 @@ FluContentPage{
var data = [] var data = []
var rows = [] var rows = []
for (var i = 0; i < table_view.rows; i++) { for (var i = 0; i < table_view.rows; i++) {
var item = table_view.getRow(i); var item = table_view.getRow(i)
rows.push(item) rows.push(item)
if (!item.checkbox.options.checked) { if (!item.checkbox.options.checked) {
data.push(item); data.push(item);
} }
} }
var sourceModel = table_view.sourceModel; var sourceModel = table_view.sourceModel
for (i = 0; i < sourceModel.rowCount; i++) { for (i = 0; i < sourceModel.rowCount; i++) {
var sourceItem = sourceModel.getRow(i); var sourceItem = sourceModel.getRow(i)
const foundItem = rows.find(item=> item._key === sourceItem._key) const foundItem = rows.find(item=> item._key === sourceItem._key)
if (!foundItem) { if (!foundItem) {
data.push(sourceItem); data.push(sourceItem);
@ -438,14 +466,24 @@ FluContentPage{
table_view.dataSource = data table_view.dataSource = data
} }
} }
FluButton{ FluButton{
text: qsTr("Add a row of Data") text: qsTr("Add a row of Data")
onClicked: { onClicked: {
table_view.appendRow(genTestObject()) table_view.appendRow(genTestObject())
} }
} }
FluButton{
text: qsTr("Insert a Row")
onClicked: {
var index = table_view.currentIndex()
if(index !== -1){
var testObj = genTestObject()
table_view.insertRow(index,testObj)
}else{
showWarning(qsTr("Focus not acquired: Please click any item in the form as the target for insertion!"))
}
}
}
} }
} }
@ -465,20 +503,19 @@ FluContentPage{
{ {
title: table_view.customItem(com_column_checbox,{checked:true}), title: table_view.customItem(com_column_checbox,{checked:true}),
dataIndex: 'checkbox', dataIndex: 'checkbox',
width:100, frozen: true
minimumWidth:100,
maximumWidth:100
},
{
title: table_view.customItem(com_column_update_title,{title:qsTr("Avatar")}),
dataIndex: 'avatar',
width:100
}, },
{ {
title: table_view.customItem(com_column_filter_name,{title:qsTr("Name")}), title: table_view.customItem(com_column_filter_name,{title:qsTr("Name")}),
dataIndex: 'name', dataIndex: 'name',
readOnly:true readOnly:true
}, },
{
title: table_view.customItem(com_column_update_title,{title:qsTr("Avatar")}),
dataIndex: 'avatar',
width:100,
frozen:true
},
{ {
title: table_view.customItem(com_column_sort_age,{sort:0}), title: table_view.customItem(com_column_sort_age,{sort:0}),
dataIndex: 'age', dataIndex: 'age',
@ -490,6 +527,7 @@ FluContentPage{
{ {
title: qsTr("Address"), title: qsTr("Address"),
dataIndex: 'address', dataIndex: 'address',
editDelegate: com_auto_suggestbox,
width:200, width:200,
minimumWidth:100, minimumWidth:100,
maximumWidth:250 maximumWidth:250
@ -513,8 +551,7 @@ FluContentPage{
title: qsTr("Options"), title: qsTr("Options"),
dataIndex: 'action', dataIndex: 'action',
width:160, width:160,
minimumWidth:160, frozen:true
maximumWidth:160
} }
] ]
} }
@ -566,7 +603,7 @@ FluContentPage{
return avatars[randomIndex]; return avatars[randomIndex];
} }
return { return {
checkbox: table_view.customItem(com_checbox,{checked:root.seletedAll}), checkbox: table_view.customItem(com_checbox,{checked:root.selectedAll}),
avatar:table_view.customItem(com_avatar,{avatar:getAvatar()}), avatar:table_view.customItem(com_avatar,{avatar:getAvatar()}),
name: getRandomName(), name: getRandomName(),
age:getRandomAge(), age:getRandomAge(),
@ -579,7 +616,7 @@ FluContentPage{
} }
} }
function loadData(page,count){ function loadData(page,count){
root.seletedAll = true root.selectedAll = true
const dataSource = [] const dataSource = []
for(var i=0;i<count;i++){ for(var i=0;i<count;i++){
dataSource.push(genTestObject()) dataSource.push(genTestObject())

View File

@ -44,7 +44,6 @@ FluScrollablePage{
wrapMode: Text.WrapAnywhere wrapMode: Text.WrapAnywhere
horizontalAlignment: isRight ? Qt.AlignRight : Qt.AlignLeft horizontalAlignment: isRight ? Qt.AlignRight : Qt.AlignLeft
text: modelData.text text: modelData.text
font.bold: true
linkColor: FluTheme.dark ? FluColors.Teal.lighter : FluColors.Teal.dark linkColor: FluTheme.dark ? FluColors.Teal.lighter : FluColors.Teal.dark
onLinkActivated: onLinkActivated:
(link)=> { (link)=> {

View File

@ -15,7 +15,7 @@ FluWindow {
title: "FluentUI" title: "FluentUI"
width: 1000 width: 1000
height: 680 height: 680
minimumWidth: 1000 minimumWidth: 800
minimumHeight: 200 minimumHeight: 200
launchMode: FluWindowType.SingleTask launchMode: FluWindowType.SingleTask
fitsAppBarWindows: true fitsAppBarWindows: true

View File

@ -1,6 +1,5 @@
#include "FluApp.h" #include "FluApp.h"
#include <QQmlEngine>
#include <QGuiApplication> #include <QGuiApplication>
#include <QQuickItem> #include <QQuickItem>
#include <QTimer> #include <QTimer>
@ -32,7 +31,7 @@ void FluApp::init(QObject *target, QLocale locale) {
} }
} }
[[maybe_unused]] QJsonArray FluApp::iconDatas(const QString &keyword) { [[maybe_unused]] QJsonArray FluApp::iconData(const QString &keyword) {
QJsonArray arr; QJsonArray arr;
QMetaEnum enumType = Fluent_Icons::staticMetaObject.enumerator(Fluent_Icons::staticMetaObject.indexOfEnumerator("Fluent_IconType")); QMetaEnum enumType = Fluent_Icons::staticMetaObject.enumerator(Fluent_Icons::staticMetaObject.indexOfEnumerator("Fluent_IconType"));
for (int i = 0; i <= enumType.keyCount() - 1; ++i) { for (int i = 0; i <= enumType.keyCount() - 1; ++i) {

View File

@ -36,7 +36,7 @@ SINGLETON(FluApp)
Q_INVOKABLE void init(QObject *target, QLocale locale = QLocale::system()); Q_INVOKABLE void init(QObject *target, QLocale locale = QLocale::system());
[[maybe_unused]] Q_INVOKABLE static QJsonArray iconDatas(const QString &keyword = ""); [[maybe_unused]] Q_INVOKABLE static QJsonArray iconData(const QString &keyword = "");
private: private:
QQmlEngine *_engine{}; QQmlEngine *_engine{};

View File

@ -7,6 +7,7 @@
#include "FluTools.h" #include "FluTools.h"
#ifdef Q_OS_WIN #ifdef Q_OS_WIN
#pragma comment (lib, "user32.lib") #pragma comment (lib, "user32.lib")
#pragma comment (lib, "dwmapi.lib") #pragma comment (lib, "dwmapi.lib")
@ -14,7 +15,6 @@
#include <windowsx.h> #include <windowsx.h>
#include <dwmapi.h> #include <dwmapi.h>
static inline QByteArray qtNativeEventType() { static inline QByteArray qtNativeEventType() {
static const auto result = "windows_generic_MSG"; static const auto result = "windows_generic_MSG";
return result; return result;
@ -35,15 +35,28 @@ static inline bool isCompositionEnabled() {
return false; return false;
} }
static inline void setShadow(HWND hwnd) {
const MARGINS shadow = {1, 0, 0, 0};
typedef HRESULT (WINAPI *DwmExtendFrameIntoClientAreaPtr)(HWND hWnd, const MARGINS *pMarInset);
HMODULE module = LoadLibraryW(L"dwmapi.dll");
if (module) {
DwmExtendFrameIntoClientAreaPtr dwm_extendframe_into_client_area_;
dwm_extendframe_into_client_area_ = reinterpret_cast<DwmExtendFrameIntoClientAreaPtr>(GetProcAddress(module, "DwmExtendFrameIntoClientArea"));
if (dwm_extendframe_into_client_area_) {
dwm_extendframe_into_client_area_(hwnd, &shadow);
}
}
}
#endif #endif
bool containsCursorToItem(QQuickItem *item) { bool containsCursorToItem(QQuickItem *item) {
if (!item || !item->isVisible()) { if (!item || !item->isVisible()) {
return false; return false;
} }
auto point = QCursor::pos(); auto point = item->window()->mapFromGlobal(QCursor::pos());
auto rect = QRectF(item->mapToGlobal(QPoint(0, 0)), item->size()); auto rect = QRectF(item->mapToItem(item->window()->contentItem(), QPointF(0, 0)), item->size());
if (point.x() > rect.x() && point.x() < (rect.x() + rect.width()) && point.y() > rect.y() && point.y() < (rect.y() + rect.height())) { if (rect.contains(point)) {
return true; return true;
} }
return false; return false;
@ -74,11 +87,6 @@ void FluFrameless::componentComplete() {
int h = window()->height(); int h = window()->height();
_current = window()->winId(); _current = window()->winId();
window()->setFlags((window()->flags()) | Qt::CustomizeWindowHint | Qt::WindowMinimizeButtonHint | Qt::WindowCloseButtonHint | Qt::FramelessWindowHint); window()->setFlags((window()->flags()) | Qt::CustomizeWindowHint | Qt::WindowMinimizeButtonHint | Qt::WindowCloseButtonHint | Qt::FramelessWindowHint);
#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
if (QQuickWindow::sceneGraphBackend() == "software") {
window()->setFlag(Qt::FramelessWindowHint, false);
}
#endif
if (!_fixSize) { if (!_fixSize) {
window()->setFlag(Qt::WindowMaximizeButtonHint); window()->setFlag(Qt::WindowMaximizeButtonHint);
} }
@ -97,20 +105,31 @@ void FluFrameless::componentComplete() {
HWND hwnd = reinterpret_cast<HWND>(window()->winId()); HWND hwnd = reinterpret_cast<HWND>(window()->winId());
DWORD style = ::GetWindowLongPtr(hwnd, GWL_STYLE); DWORD style = ::GetWindowLongPtr(hwnd, GWL_STYLE);
if (_fixSize) { if (_fixSize) {
::SetWindowLongPtr(hwnd, GWL_STYLE, style | WS_THICKFRAME); #if (QT_VERSION == QT_VERSION_CHECK(6, 5, 3) || QT_VERSION == QT_VERSION_CHECK(6, 6, 0))
::SetWindowLongPtr(hwnd, GWL_STYLE, style | WS_THICKFRAME);;
#else
::SetWindowLongPtr(hwnd, GWL_STYLE, style | WS_THICKFRAME | WS_CAPTION);
#endif
for (int i = 0; i <= QGuiApplication::screens().count() - 1; ++i) { for (int i = 0; i <= QGuiApplication::screens().count() - 1; ++i) {
connect(QGuiApplication::screens().at(i), &QScreen::logicalDotsPerInchChanged, this, [=] { connect(QGuiApplication::screens().at(i), &QScreen::logicalDotsPerInchChanged, this, [=] {
SetWindowPos(hwnd, nullptr, 0, 0, 0, 0, SWP_NOZORDER | SWP_NOOWNERZORDER | SWP_NOMOVE | SWP_FRAMECHANGED); SetWindowPos(hwnd, nullptr, 0, 0, 0, 0, SWP_NOZORDER | SWP_NOOWNERZORDER | SWP_NOMOVE | SWP_FRAMECHANGED);
}); });
} }
} else { } else {
#if (QT_VERSION == QT_VERSION_CHECK(6, 5, 3) || QT_VERSION == QT_VERSION_CHECK(6, 6, 0))
::SetWindowLongPtr(hwnd, GWL_STYLE, style | WS_MAXIMIZEBOX | WS_THICKFRAME); ::SetWindowLongPtr(hwnd, GWL_STYLE, style | WS_MAXIMIZEBOX | WS_THICKFRAME);
#else
::SetWindowLongPtr(hwnd, GWL_STYLE, style | WS_MAXIMIZEBOX | WS_THICKFRAME | WS_CAPTION);
#endif
} }
SetWindowPos(hwnd, nullptr, 0, 0, 0, 0, SWP_NOZORDER | SWP_NOOWNERZORDER | SWP_NOMOVE | SWP_NOSIZE | SWP_FRAMECHANGED); SetWindowPos(hwnd, nullptr, 0, 0, 0, 0, SWP_NOZORDER | SWP_NOOWNERZORDER | SWP_NOMOVE | SWP_NOSIZE | SWP_FRAMECHANGED);
connect(window(), &QQuickWindow::screenChanged, this, [hwnd] { connect(window(), &QQuickWindow::screenChanged, this, [hwnd] {
::SetWindowPos(hwnd, nullptr, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER | SWP_FRAMECHANGED | SWP_NOOWNERZORDER); ::SetWindowPos(hwnd, nullptr, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER | SWP_FRAMECHANGED | SWP_NOOWNERZORDER);
::RedrawWindow(hwnd, nullptr, nullptr, RDW_INVALIDATE | RDW_UPDATENOW); ::RedrawWindow(hwnd, nullptr, nullptr, RDW_INVALIDATE | RDW_UPDATENOW);
}); });
if (!window()->property("_hideShadow").toBool()) {
setShadow(hwnd);
}
#endif #endif
h = qRound(h + _appbar->height()); h = qRound(h + _appbar->height());
if (_fixSize) { if (_fixSize) {
@ -141,7 +160,7 @@ void FluFrameless::componentComplete() {
const auto uMsg = msg->message; const auto uMsg = msg->message;
const auto wParam = msg->wParam; const auto wParam = msg->wParam;
const auto lParam = msg->lParam; const auto lParam = msg->lParam;
static QPoint offsetXY; static int offsetXY;
if (uMsg == WM_WINDOWPOSCHANGING) { if (uMsg == WM_WINDOWPOSCHANGING) {
auto *wp = reinterpret_cast<WINDOWPOS *>(lParam); auto *wp = reinterpret_cast<WINDOWPOS *>(lParam);
if (wp != nullptr && (wp->flags & SWP_NOSIZE) == 0) { if (wp != nullptr && (wp->flags & SWP_NOSIZE) == 0) {
@ -150,42 +169,37 @@ void FluFrameless::componentComplete() {
return true; return true;
} }
return false; return false;
} else if (uMsg == WM_NCCALCSIZE) { } else if (uMsg == WM_NCCALCSIZE && wParam == TRUE) {
const auto clientRect = ((wParam == FALSE) ? reinterpret_cast<LPRECT>(lParam) : &(reinterpret_cast<LPNCCALCSIZE_PARAMS>(lParam))->rgrc[0]); const auto clientRect = &(reinterpret_cast<LPNCCALCSIZE_PARAMS>(lParam))->rgrc[0];
const LONG originalTop = clientRect->top; const LONG originalTop = clientRect->top;
const LONG originalLeft = clientRect->left; const LONG originalLeft = clientRect->left;
const LONG originalRight = clientRect->right;
const LONG originalBottom = clientRect->bottom; const LONG originalBottom = clientRect->bottom;
const LONG originalRight = clientRect->right;
const LRESULT hitTestResult = ::DefWindowProcW(hwnd, WM_NCCALCSIZE, wParam, lParam); const LRESULT hitTestResult = ::DefWindowProcW(hwnd, WM_NCCALCSIZE, wParam, lParam);
if ((hitTestResult != HTERROR) && (hitTestResult != HTNOWHERE)) { if ((hitTestResult != HTERROR) && (hitTestResult != HTNOWHERE)) {
*result = static_cast<QT_NATIVE_EVENT_RESULT_TYPE>(hitTestResult); *result = static_cast<QT_NATIVE_EVENT_RESULT_TYPE>(hitTestResult);
return true; return true;
} }
int offsetSize; if (clientRect->left - originalLeft != 0) {
bool isMaximum = ::IsZoomed(hwnd); offsetXY = clientRect->left - originalLeft;
auto _offsetXY = QPoint(abs(clientRect->left - originalLeft), abs(clientRect->top - originalTop));
if (_offsetXY.x() != 0) {
offsetXY = _offsetXY;
} }
if (isMaximum || _isFullScreen()) { #if (QT_VERSION == QT_VERSION_CHECK(6, 5, 3) || QT_VERSION == QT_VERSION_CHECK(6, 6, 0))
offsetSize = 0; clientRect->top = originalTop;
} else { clientRect->bottom = originalBottom;
offsetSize = 1; clientRect->left = originalLeft;
} clientRect->right = originalRight;
if (!isCompositionEnabled()) {
offsetSize = 0;
}
#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
clientRect->top = originalTop + offsetSize;
clientRect->bottom = originalBottom - offsetSize;
clientRect->left = originalLeft + offsetSize;
clientRect->right = originalRight - offsetSize;
#else #else
bool isMaximum = ::IsZoomed(hwnd);
if (!isMaximum) { if (!isMaximum) {
clientRect->top = originalTop + offsetSize; clientRect->top = originalTop;
clientRect->bottom = originalBottom - offsetSize; clientRect->bottom = originalBottom;
clientRect->left = originalLeft + offsetSize; clientRect->left = originalLeft;
clientRect->right = originalRight - offsetSize; clientRect->right = originalRight;
} else {
clientRect->top = originalTop + offsetXY;
clientRect->bottom = originalBottom - offsetXY;
clientRect->left = originalLeft + offsetXY;
clientRect->right = originalRight - offsetXY;
} }
#endif #endif
_setMaximizeHovered(false); _setMaximizeHovered(false);
@ -244,6 +258,29 @@ void FluFrameless::componentComplete() {
} }
*result = HTCLIENT; *result = HTCLIENT;
return true; return true;
} else if (uMsg == WM_NCPAINT) {
if (isCompositionEnabled()) {
return false;
}
*result = FALSE;
return true;
} else if (uMsg == WM_NCACTIVATE) {
if (isCompositionEnabled()) {
return false;
}
*result = TRUE;
return true;
} else if (uMsg == WM_GETMINMAXINFO) {
auto *minmaxInfo = reinterpret_cast<MINMAXINFO *>(lParam);
auto pixelRatio = window()->devicePixelRatio();
auto geometry = window()->screen()->availableGeometry();
RECT rect;
SystemParametersInfo(SPI_GETWORKAREA, 0, &rect, 0);
minmaxInfo->ptMaxPosition.x = rect.left;
minmaxInfo->ptMaxPosition.y = rect.top;
minmaxInfo->ptMaxSize.x = qRound(geometry.width() * pixelRatio);
minmaxInfo->ptMaxSize.y = qRound(geometry.height() * pixelRatio);
return false;
} else if (_isWindows11OrGreater && (uMsg == WM_NCLBUTTONDBLCLK || uMsg == WM_NCLBUTTONDOWN)) { } else if (_isWindows11OrGreater && (uMsg == WM_NCLBUTTONDBLCLK || uMsg == WM_NCLBUTTONDOWN)) {
if (_hitMaximizeButton()) { if (_hitMaximizeButton()) {
QMouseEvent event = QMouseEvent(QEvent::MouseButtonPress, QPoint(), QPoint(), Qt::LeftButton, Qt::LeftButton, Qt::NoModifier); QMouseEvent event = QMouseEvent(QEvent::MouseButtonPress, QPoint(), QPoint(), Qt::LeftButton, Qt::LeftButton, Qt::NoModifier);
@ -258,38 +295,11 @@ void FluFrameless::componentComplete() {
_setMaximizePressed(false); _setMaximizePressed(false);
return true; return true;
} }
} else if (uMsg == WM_NCPAINT) {
*result = FALSE;
return true;
} else if (uMsg == WM_NCACTIVATE) {
*result = static_cast<QT_NATIVE_EVENT_RESULT_TYPE>(::DefWindowProcW(hwnd, WM_NCACTIVATE, wParam, -1));
return true;
} else if (uMsg == WM_GETMINMAXINFO) {
auto *minmaxInfo = reinterpret_cast<MINMAXINFO *>(lParam);
#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
minmaxInfo->ptMaxPosition.x = 0;
minmaxInfo->ptMaxPosition.y = 0;
minmaxInfo->ptMaxSize.x = 0;
minmaxInfo->ptMaxSize.y = 0;
return false;
#else
auto pixelRatio = window()->devicePixelRatio();
auto geometry = window()->screen()->availableGeometry();
RECT rect;
SystemParametersInfo(SPI_GETWORKAREA, 0, &rect, 0);
if (!_fixSize) {
minmaxInfo->ptMinTrackSize.x = qRound(window()->minimumWidth() * pixelRatio + offsetXY.x());
minmaxInfo->ptMinTrackSize.y = qRound(window()->minimumHeight() * pixelRatio + offsetXY.y() + _appbar->height() * pixelRatio);
}
minmaxInfo->ptMaxPosition.x = rect.left - offsetXY.x();
minmaxInfo->ptMaxPosition.y = rect.top - offsetXY.x();
minmaxInfo->ptMaxSize.x = qRound(geometry.width() * pixelRatio) + offsetXY.x() * 2;
minmaxInfo->ptMaxSize.y = qRound(geometry.height() * pixelRatio) + offsetXY.y() * 2;
return true;
#endif
} else if (uMsg == WM_NCRBUTTONDOWN) { } else if (uMsg == WM_NCRBUTTONDOWN) {
if (wParam == HTCAPTION) { if (wParam == HTCAPTION) {
_showSystemMenu(QCursor::pos()); auto pos = window()->position();
auto offset = window()->mapFromGlobal(QCursor::pos());
_showSystemMenu(QPoint(pos.x() + offset.x(), pos.y() + offset.y()));
} }
} else if (uMsg == WM_KEYDOWN || uMsg == WM_SYSKEYDOWN) { } else if (uMsg == WM_KEYDOWN || uMsg == WM_SYSKEYDOWN) {
const bool altPressed = ((wParam == VK_MENU) || (::GetKeyState(VK_MENU) < 0)); const bool altPressed = ((wParam == VK_MENU) || (::GetKeyState(VK_MENU) < 0));
@ -327,6 +337,15 @@ bool FluFrameless::_isFullScreen() {
void FluFrameless::_showSystemMenu(QPoint point) { void FluFrameless::_showSystemMenu(QPoint point) {
#ifdef Q_OS_WIN #ifdef Q_OS_WIN
QScreen *screen = window()->screen();
if (!screen) {
screen = QGuiApplication::primaryScreen();
}
if (!screen) {
return;
}
const QPoint origin = screen->geometry().topLeft();
auto nativePos = QPointF(QPointF(point - origin) * window()->devicePixelRatio()).toPoint() + origin;
HWND hwnd = reinterpret_cast<HWND>(window()->winId()); HWND hwnd = reinterpret_cast<HWND>(window()->winId());
DWORD style = ::GetWindowLongPtr(hwnd, GWL_STYLE); DWORD style = ::GetWindowLongPtr(hwnd, GWL_STYLE);
::SetWindowLongPtr(hwnd, GWL_STYLE, style | WS_SYSMENU); ::SetWindowLongPtr(hwnd, GWL_STYLE, style | WS_SYSMENU);
@ -345,8 +364,8 @@ void FluFrameless::_showSystemMenu(QPoint point) {
::EnableMenuItem(hMenu, SC_SIZE, MFS_DISABLED); ::EnableMenuItem(hMenu, SC_SIZE, MFS_DISABLED);
::EnableMenuItem(hMenu, SC_MAXIMIZE, MFS_DISABLED); ::EnableMenuItem(hMenu, SC_MAXIMIZE, MFS_DISABLED);
} }
const int result = ::TrackPopupMenu(hMenu, (TPM_RETURNCMD | (QGuiApplication::isRightToLeft() ? TPM_RIGHTALIGN : TPM_LEFTALIGN)), qRound(point.x() * window()->devicePixelRatio()), const int result = ::TrackPopupMenu(hMenu, (TPM_RETURNCMD | (QGuiApplication::isRightToLeft() ? TPM_RIGHTALIGN : TPM_LEFTALIGN)), nativePos.x(),
qRound(point.y() * window()->devicePixelRatio()), 0, hwnd, nullptr); nativePos.y(), 0, hwnd, nullptr);
if (result != FALSE) { if (result != FALSE) {
::PostMessageW(hwnd, WM_SYSCOMMAND, result, 0); ::PostMessageW(hwnd, WM_SYSCOMMAND, result, 0);
} }

73
src/FluTableModel.cpp Normal file
View File

@ -0,0 +1,73 @@
#include "FluTableModel.h"
FluTableModel::FluTableModel(QObject *parent) : QAbstractTableModel{parent} {
}
int FluTableModel::rowCount(const QModelIndex &parent) const {
return _rows.count();
}
int FluTableModel::columnCount(const QModelIndex &parent) const {
return this->_columnSource.size();
}
QVariant FluTableModel::data(const QModelIndex &index, int role) const {
switch (role) {
case FluTableModel::RowModel:
return QVariant::fromValue(_rows.at(index.row()));
case FluTableModel::ColumnModel:
return QVariant::fromValue(_columnSource.at(index.column()));
default:
break;
}
return {};
}
QHash<int, QByteArray> FluTableModel::roleNames() const {
return {
{FluTableModel::RowModel, "rowModel"},
{FluTableModel::ColumnModel, "columnModel"}
};
}
QModelIndex FluTableModel::parent(const QModelIndex &child) const {
return {};
}
QModelIndex FluTableModel::index(int row, int column, const QModelIndex &parent) const {
if (!hasIndex(row, column, parent) || parent.isValid())
return {};
return createIndex(row, column);
}
void FluTableModel::clear() {
beginResetModel();
this->_rows.clear();
endResetModel();
}
QVariant FluTableModel::getRow(int rowIndex) {
return _rows.at(rowIndex);
}
void FluTableModel::setRow(int rowIndex, QVariant row) {
_rows.replace(rowIndex, row.toMap());
Q_EMIT dataChanged(index(rowIndex, 0), index(rowIndex, columnCount() - 1));
}
void FluTableModel::insertRow(int rowIndex, QVariant row) {
beginInsertRows(QModelIndex(), rowIndex, rowIndex);
_rows.insert(rowIndex, row.toMap());
endInsertRows();
}
void FluTableModel::removeRow(int rowIndex, int rows) {
beginRemoveRows(QModelIndex(), rowIndex, rowIndex + rows - 1);
_rows = _rows.mid(0, rowIndex) + _rows.mid(rowIndex + rows);
endRemoveRows();
}
void FluTableModel::appendRow(QVariant row) {
insertRow(rowCount(), row);
}

51
src/FluTableModel.h Normal file
View File

@ -0,0 +1,51 @@
#ifndef FLUTABLEMODEL_H
#define FLUTABLEMODEL_H
#include <QObject>
#include <QAbstractItemModel>
#include <QtQml/qqml.h>
#include "stdafx.h"
class FluTableModel : public QAbstractTableModel {
Q_OBJECT
Q_PROPERTY_AUTO(int, dataSourceSize)
Q_PROPERTY_AUTO(QList<QVariantMap>, columnSource)
Q_PROPERTY_AUTO(QList<QVariantMap>, rows)
Q_PROPERTY(int rowCount READ rowCount CONSTANT)
QML_NAMED_ELEMENT(FluTableModel)
public:
enum TableModelRoles {
RowModel = 0x0101,
ColumnModel = 0x0102
};
explicit FluTableModel(QObject *parent = nullptr);
[[nodiscard]] int rowCount(const QModelIndex &parent = {}) const override;
[[nodiscard]] int columnCount(const QModelIndex &parent = {}) const override;
[[nodiscard]] QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override;
[[nodiscard]] QHash<int, QByteArray> roleNames() const override;
[[nodiscard]] QModelIndex parent(const QModelIndex &child) const override;
[[nodiscard]] QModelIndex index(int row, int column, const QModelIndex &parent = {}) const override;
Q_INVOKABLE void clear();
Q_INVOKABLE QVariant getRow(int rowIndex);
Q_INVOKABLE void setRow(int rowIndex, QVariant row);
Q_INVOKABLE void insertRow(int rowIndex, QVariant row);
Q_INVOKABLE void removeRow(int rowIndex, int rows = 1);
Q_INVOKABLE void appendRow(QVariant row);
};
#endif // FLUTABLEMODEL_H

View File

@ -3,9 +3,8 @@
#include <QJSValueList> #include <QJSValueList>
FluTableSortProxyModel::FluTableSortProxyModel(QSortFilterProxyModel *parent) : QSortFilterProxyModel{parent} { FluTableSortProxyModel::FluTableSortProxyModel(QSortFilterProxyModel *parent) : QSortFilterProxyModel{parent} {
_model = nullptr;
connect(this, &FluTableSortProxyModel::modelChanged, this, [=] { connect(this, &FluTableSortProxyModel::modelChanged, this, [=] {
setSourceModel(this->model()); setSourceModel(this->model().value<QAbstractTableModel *>());
}); });
} }
@ -59,15 +58,18 @@ bool FluTableSortProxyModel::lessThan(const QModelIndex &source_left, const QMod
[[maybe_unused]] QVariant FluTableSortProxyModel::getRow(int rowIndex) { [[maybe_unused]] QVariant FluTableSortProxyModel::getRow(int rowIndex) {
QVariant result; QVariant result;
QMetaObject::invokeMethod(_model, "getRow", Q_RETURN_ARG(QVariant, result), Q_ARG(int, mapToSource(index(rowIndex, 0)).row())); QMetaObject::invokeMethod(_model.value<QAbstractTableModel *>(), "getRow", Q_RETURN_ARG(QVariant, result), Q_ARG(int, mapToSource(index(rowIndex, 0)).row()));
return result; return result;
} }
[[maybe_unused]] void FluTableSortProxyModel::setRow(int rowIndex, const QVariant &val) { [[maybe_unused]] void FluTableSortProxyModel::setRow(int rowIndex, const QVariant &val) {
QMetaObject::invokeMethod(_model, "setRow", Q_ARG(int, mapToSource(index(rowIndex, 0)).row()), Q_ARG(QVariant, val)); QMetaObject::invokeMethod(_model.value<QAbstractTableModel *>(), "setRow", Q_ARG(int, mapToSource(index(rowIndex, 0)).row()), Q_ARG(QVariant, val));
}
[[maybe_unused]] void FluTableSortProxyModel::insertRow(int rowIndex, const QVariant &val) {
QMetaObject::invokeMethod(_model.value<QAbstractTableModel *>(), "insertRow", Q_ARG(int, mapToSource(index(rowIndex, 0)).row()), Q_ARG(QVariant, val));
} }
[[maybe_unused]] void FluTableSortProxyModel::removeRow(int rowIndex, int rows) { [[maybe_unused]] void FluTableSortProxyModel::removeRow(int rowIndex, int rows) {
QMetaObject::invokeMethod(_model, "removeRow", Q_ARG(int, mapToSource(index(rowIndex, 0)).row()), Q_ARG(int, rows)); QMetaObject::invokeMethod(_model.value<QAbstractTableModel *>(), "removeRow", Q_ARG(int, mapToSource(index(rowIndex, 0)).row()), Q_ARG(int, rows));
} }

View File

@ -8,7 +8,7 @@
class FluTableSortProxyModel : public QSortFilterProxyModel { class FluTableSortProxyModel : public QSortFilterProxyModel {
Q_OBJECT Q_OBJECT
Q_PROPERTY_AUTO_P(QAbstractTableModel*, model) Q_PROPERTY_AUTO_P(QVariant, model)
QML_NAMED_ELEMENT(FluTableSortProxyModel) QML_NAMED_ELEMENT(FluTableSortProxyModel)
public: public:
explicit FluTableSortProxyModel(QSortFilterProxyModel *parent = nullptr); explicit FluTableSortProxyModel(QSortFilterProxyModel *parent = nullptr);
@ -23,6 +23,8 @@ public:
[[maybe_unused]] Q_INVOKABLE void setRow(int rowIndex, const QVariant &val); [[maybe_unused]] Q_INVOKABLE void setRow(int rowIndex, const QVariant &val);
[[maybe_unused]] Q_INVOKABLE void insertRow(int rowIndex, const QVariant &val);
[[maybe_unused]] Q_INVOKABLE void removeRow(int rowIndex, int rows); [[maybe_unused]] Q_INVOKABLE void removeRow(int rowIndex, int rows);
[[maybe_unused]] Q_INVOKABLE void setComparator(const QJSValue &comparator); [[maybe_unused]] Q_INVOKABLE void setComparator(const QJSValue &comparator);

View File

@ -95,5 +95,5 @@ SINGLETON(FluTools)
Q_INVOKABLE QString getWallpaperFilePath(); Q_INVOKABLE QString getWallpaperFilePath();
Q_INVOKABLE QColor imageMainColor(const QImage& image, double bright = 1); Q_INVOKABLE QColor imageMainColor(const QImage &image, double bright = 1);
}; };

View File

@ -1,12 +1,11 @@
#include "FluTreeModel.h" #include "FluTreeModel.h"
#include <QMetaEnum> #include <QMetaEnum>
#include <utility>
FluTreeNode::FluTreeNode(QObject *parent) : QObject{parent} { FluTreeNode::FluTreeNode(QObject *parent) : QObject{parent} {
} }
FluTreeModel::FluTreeModel(QObject *parent) : QAbstractItemModel{parent} { FluTreeModel::FluTreeModel(QObject *parent) : QAbstractTableModel{parent} {
_dataSourceSize = 0; _dataSourceSize = 0;
} }
@ -17,7 +16,7 @@ QModelIndex FluTreeModel::parent(const QModelIndex &child) const {
QModelIndex FluTreeModel::index(int row, int column, const QModelIndex &parent) const { QModelIndex FluTreeModel::index(int row, int column, const QModelIndex &parent) const {
if (!hasIndex(row, column, parent) || parent.isValid()) if (!hasIndex(row, column, parent) || parent.isValid())
return {}; return {};
return createIndex(row, column, _rows.at(row)); return createIndex(row, column);
} }
int FluTreeModel::rowCount(const QModelIndex &parent) const { int FluTreeModel::rowCount(const QModelIndex &parent) const {
@ -265,12 +264,12 @@ void FluTreeModel::allCollapse() {
endResetModel(); endResetModel();
} }
QVariant FluTreeModel::selectionModel(){ QVariant FluTreeModel::selectionModel() {
QList<FluTreeNode *> data; QList<FluTreeNode *> data;
foreach (auto item, _dataSource) { foreach (auto item, _dataSource) {
if (item->checked()) { if (item->checked()) {
data.append(item); data.append(item);
}
} }
}
return QVariant::fromValue(data); return QVariant::fromValue(data);
} }

View File

@ -86,12 +86,11 @@ public:
FluTreeNode *_parent = nullptr; FluTreeNode *_parent = nullptr;
}; };
class FluTreeModel : public QAbstractItemModel { class FluTreeModel : public QAbstractTableModel {
Q_OBJECT Q_OBJECT
Q_PROPERTY_AUTO(int, dataSourceSize) Q_PROPERTY_AUTO(int, dataSourceSize)
Q_PROPERTY_AUTO(QList<QVariantMap>, columnSource) Q_PROPERTY_AUTO(QList<QVariantMap>, columnSource)
QML_NAMED_ELEMENT(FluTreeModel) QML_NAMED_ELEMENT(FluTreeModel)
QML_ADDED_IN_MINOR_VERSION(1)
public: public:
enum TreeModelRoles { enum TreeModelRoles {
RowModel = 0x0101, RowModel = 0x0101,

View File

@ -15,6 +15,7 @@
#include "FluQrCodeItem.h" #include "FluQrCodeItem.h"
#include "FluTableSortProxyModel.h" #include "FluTableSortProxyModel.h"
#include "FluFrameless.h" #include "FluFrameless.h"
#include "FluTableModel.h"
void FluentUI::registerTypes(QQmlEngine *engine) { void FluentUI::registerTypes(QQmlEngine *engine) {
initializeEngine(engine, _uri); initializeEngine(engine, _uri);
@ -32,6 +33,7 @@ void FluentUI::registerTypes(const char *uri) const {
qmlRegisterType<FluWatermark>(uri, major, minor, "FluWatermark"); qmlRegisterType<FluWatermark>(uri, major, minor, "FluWatermark");
qmlRegisterType<FluAccentColor>(uri, major, minor, "FluAccentColor"); qmlRegisterType<FluAccentColor>(uri, major, minor, "FluAccentColor");
qmlRegisterType<FluTreeModel>(uri, major, minor, "FluTreeModel"); qmlRegisterType<FluTreeModel>(uri, major, minor, "FluTreeModel");
qmlRegisterType<FluTableModel>(uri, major, minor, "FluTableModel");
qmlRegisterType<FluRectangle>(uri, major, minor, "FluRectangle"); qmlRegisterType<FluRectangle>(uri, major, minor, "FluRectangle");
qmlRegisterType<FluFrameless>(uri, major, minor, "FluFrameless"); qmlRegisterType<FluFrameless>(uri, major, minor, "FluFrameless");
qmlRegisterType<FluTableSortProxyModel>(uri, major, minor, "FluTableSortProxyModel"); qmlRegisterType<FluTableSortProxyModel>(uri, major, minor, "FluTableSortProxyModel");

View File

@ -7,6 +7,7 @@ FluTextBox{
property var items:[] property var items:[]
property string emptyText: qsTr("No results found") property string emptyText: qsTr("No results found")
property int autoSuggestBoxReplacement: FluentIcons.Search property int autoSuggestBoxReplacement: FluentIcons.Search
property string textRole: "title"
property var filter: function(item){ property var filter: function(item){
if(item.title.indexOf(control.text)!==-1){ if(item.title.indexOf(control.text)!==-1){
return true return true
@ -25,7 +26,7 @@ FluTextBox{
function handleClick(modelData){ function handleClick(modelData){
control_popup.visible = false control_popup.visible = false
control.itemClicked(modelData) control.itemClicked(modelData)
control.updateText(modelData.title) control.updateText(modelData[textRole])
} }
function loadData(){ function loadData(){
var result = [] var result = []
@ -48,7 +49,6 @@ FluTextBox{
} }
Popup{ Popup{
id:control_popup id:control_popup
y:control.height
focus: false focus: false
padding: 0 padding: 0
enter: Transition { enter: Transition {
@ -62,7 +62,7 @@ FluTextBox{
contentItem: FluClip{ contentItem: FluClip{
radius: [5,5,5,5] radius: [5,5,5,5]
ListView{ ListView{
id:list_view id: list_view
anchors.fill: parent anchors.fill: parent
clip: true clip: true
boundsBehavior: ListView.StopAtBounds boundsBehavior: ListView.StopAtBounds
@ -72,7 +72,7 @@ FluTextBox{
height: visible ? 38 : 0 height: visible ? 38 : 0
visible: list_view.count === 0 visible: list_view.count === 0
FluText{ FluText{
text:emptyText text: emptyText
anchors{ anchors{
verticalCenter: parent.verticalCenter verticalCenter: parent.verticalCenter
left: parent.left left: parent.left
@ -81,10 +81,10 @@ FluTextBox{
} }
} }
delegate:FluControl{ delegate:FluControl{
id:item_control id: item_control
height: 38 height: 38
width: control.width width: control.width
onClicked:{ onClicked: {
d.handleClick(modelData) d.handleClick(modelData)
} }
background: Rectangle{ background: Rectangle{
@ -103,7 +103,7 @@ FluTextBox{
} }
} }
contentItem: FluText{ contentItem: FluText{
text:modelData.title text: modelData[textRole]
leftPadding: 10 leftPadding: 10
rightPadding: 10 rightPadding: 10
verticalAlignment : Qt.AlignVCenter verticalAlignment : Qt.AlignVCenter
@ -128,7 +128,7 @@ FluTextBox{
if(d.flagVisible){ if(d.flagVisible){
var pos = control.mapToItem(null, 0, 0) var pos = control.mapToItem(null, 0, 0)
if(d.window.height>pos.y+control.height+rect_background.implicitHeight){ if(d.window.height>pos.y+control.height+rect_background.implicitHeight){
control_popup.y = control.height control_popup.y = Qt.binding(function(){return control.height})
} else if(pos.y>rect_background.implicitHeight){ } else if(pos.y>rect_background.implicitHeight){
control_popup.y = -rect_background.implicitHeight control_popup.y = -rect_background.implicitHeight
} else { } else {

View File

@ -11,6 +11,7 @@ T.ComboBox {
property color normalColor: FluTheme.dark ? Qt.rgba(62/255,62/255,62/255,1) : Qt.rgba(254/255,254/255,254/255,1) property color normalColor: FluTheme.dark ? Qt.rgba(62/255,62/255,62/255,1) : Qt.rgba(254/255,254/255,254/255,1)
property color hoverColor: FluTheme.dark ? Qt.rgba(68/255,68/255,68/255,1) : Qt.rgba(251/255,251/255,251/255,1) property color hoverColor: FluTheme.dark ? Qt.rgba(68/255,68/255,68/255,1) : Qt.rgba(251/255,251/255,251/255,1)
property color disableColor: FluTheme.dark ? Qt.rgba(59/255,59/255,59/255,1) : Qt.rgba(252/255,252/255,252/255,1) property color disableColor: FluTheme.dark ? Qt.rgba(59/255,59/255,59/255,1) : Qt.rgba(252/255,252/255,252/255,1)
property alias textBox: text_field
implicitWidth: Math.max(implicitBackgroundWidth + leftInset + rightInset, implicitWidth: Math.max(implicitBackgroundWidth + leftInset + rightInset,
implicitContentWidth + leftPadding + rightPadding) implicitContentWidth + leftPadding + rightPadding)
implicitHeight: Math.max(implicitBackgroundHeight + topInset + bottomInset, implicitHeight: Math.max(implicitBackgroundHeight + topInset + bottomInset,
@ -39,6 +40,7 @@ T.ComboBox {
opacity: enabled ? 1 : 0.3 opacity: enabled ? 1 : 0.3
} }
contentItem: T.TextField { contentItem: T.TextField {
id: text_field
property bool disabled: !control.editable property bool disabled: !control.editable
leftPadding: !control.mirrored ? 10 : control.editable && activeFocus ? 3 : 1 leftPadding: !control.mirrored ? 10 : control.editable && activeFocus ? 3 : 1
rightPadding: control.mirrored ? 10 : control.editable && activeFocus ? 3 : 1 rightPadding: control.mirrored ? 10 : control.editable && activeFocus ? 3 : 1

View File

@ -48,9 +48,6 @@ T.MenuBarItem {
radius: 3 radius: 3
color: { color: {
if(control.highlighted){ if(control.highlighted){
return FluTheme.itemCheckColor
}
if(control.hovered){
return FluTheme.itemHoverColor return FluTheme.itemHoverColor
} }
return FluTheme.itemNormalColor return FluTheme.itemNormalColor

View File

@ -99,9 +99,9 @@ T.MenuItem {
anchors.fill: parent anchors.fill: parent
anchors.margins: 3 anchors.margins: 3
radius: 4 radius: 4
color:{ color: {
if(control.highlighted){ if(control.highlighted){
return FluTheme.itemCheckColor return FluTheme.itemHoverColor
} }
return FluTheme.itemNormalColor return FluTheme.itemNormalColor
} }

View File

@ -3,98 +3,107 @@ import QtQuick.Controls 2.15
import QtQuick.Layouts 1.15 import QtQuick.Layouts 1.15
import FluentUI 1.0 import FluentUI 1.0
Item { Item {
signal requestPage(int page,int count) signal requestPage(int page, int count)
property string previousText: qsTr("<Previous") property string previousText: qsTr("<Previous")
property string nextText: qsTr("Next>") property string nextText: qsTr("Next>")
property int pageCurrent: 0 property int pageCurrent: 0
property int itemCount: 0 property int itemCount: 0
property int pageButtonCount: 5 property int pageButtonCount: 5
property int pageCount: itemCount>0?Math.ceil(itemCount/__itemPerPage):0 property int pageCount: itemCount > 0 ? Math.ceil(itemCount / __itemPerPage) : 0
property int __itemPerPage: 10 property int __itemPerPage: 10
property int __pageButtonHalf: Math.floor(pageButtonCount/2)+1 property int __pageButtonHalf: Math.floor(pageButtonCount / 2) + 1
property Component header: null
property Component footer: null
id: control id: control
implicitHeight: 40 implicitHeight: 40
implicitWidth: content.width implicitWidth: content.width
Row{ Row {
id: content id: content
height: control.height height: control.height
spacing: 10 spacing: 10
padding: 10 padding: 10
FluToggleButton{ Loader {
visible: control.pageCount>1 sourceComponent: header
disabled: control.pageCurrent<=1 }
text:control.previousText FluToggleButton {
clickListener:function() { visible: control.pageCount > 1
control.calcNewPage(control.pageCurrent-1); disabled: control.pageCurrent <= 1
text: control.previousText
clickListener: function () {
control.calcNewPage(control.pageCurrent - 1);
} }
} }
Row{ Row {
spacing: 5 spacing: 5
FluToggleButton{ FluToggleButton {
property int pageNumber:1 property int pageNumber: 1
visible: control.pageCount>0 visible: control.pageCount > 0
checked: pageNumber === control.pageCurrent checked: pageNumber === control.pageCurrent
text:String(pageNumber) text: String(pageNumber)
clickListener:function() { clickListener: function () {
control.calcNewPage(pageNumber); control.calcNewPage(pageNumber);
} }
} }
FluText{ FluText {
visible: (control.pageCount>control.pageButtonCount&& visible: (control.pageCount > control.pageButtonCount &&
control.pageCurrent>control.__pageButtonHalf) control.pageCurrent > control.__pageButtonHalf)
text: "..." text: "..."
} }
Repeater{ Repeater {
id: button_repeator id: button_repeator
model: (control.pageCount<2)?0:(control.pageCount>=control.pageButtonCount)?(control.pageButtonCount-2):(control.pageCount-2) model: (control.pageCount < 2) ? 0 : (control.pageCount >= control.pageButtonCount) ? (control.pageButtonCount - 2) : (control.pageCount - 2)
delegate:FluToggleButton{ delegate: FluToggleButton {
property int pageNumber: { property int pageNumber: {
return (control.pageCurrent<=control.__pageButtonHalf) return (control.pageCurrent <= control.__pageButtonHalf)
?(2+index) ? (2 + index)
:(control.pageCount-control.pageCurrent<=control.pageButtonCount-control.__pageButtonHalf) : (control.pageCount - control.pageCurrent <= control.pageButtonCount - control.__pageButtonHalf)
?(control.pageCount-button_repeator.count+index) ? (control.pageCount - button_repeator.count + index)
:(control.pageCurrent+2+index-control.__pageButtonHalf) : (control.pageCurrent + 2 + index - control.__pageButtonHalf)
} }
text:String(pageNumber) text: String(pageNumber)
checked: pageNumber === control.pageCurrent checked: pageNumber === control.pageCurrent
clickListener:function(){ clickListener: function () {
control.calcNewPage(pageNumber); control.calcNewPage(pageNumber);
} }
} }
} }
FluText{ FluText {
visible: (control.pageCount>control.pageButtonCount&& visible: (control.pageCount > control.pageButtonCount &&
control.pageCount-control.pageCurrent>control.pageButtonCount-control.__pageButtonHalf) control.pageCount - control.pageCurrent > control.pageButtonCount - control.__pageButtonHalf)
text: "..." text: "..."
} }
FluToggleButton{ FluToggleButton {
property int pageNumber:control.pageCount property int pageNumber: control.pageCount
visible: control.pageCount>1 visible: control.pageCount > 1
checked: pageNumber === control.pageCurrent checked: pageNumber === control.pageCurrent
text:String(pageNumber) text: String(pageNumber)
clickListener:function(){ clickListener: function () {
control.calcNewPage(pageNumber); control.calcNewPage(pageNumber);
} }
} }
} }
FluToggleButton{ FluToggleButton {
visible: control.pageCount>1 visible: control.pageCount > 1
disabled: control.pageCurrent>=control.pageCount disabled: control.pageCurrent >= control.pageCount
text:control.nextText text: control.nextText
clickListener:function() { clickListener: function () {
control.calcNewPage(control.pageCurrent+1); control.calcNewPage(control.pageCurrent + 1);
} }
} }
Loader {
sourceComponent: footer
}
} }
function calcNewPage(page) function calcNewPage(page) {
{ if (!page)
if(!page)
return return
let page_num=Number(page) let page_num = Number(page)
if(page_num<1||page_num>control.pageCount||page_num===control.pageCurrent) if (page_num < 1 || page_num > control.pageCount || page_num === control.pageCurrent)
return return
control.pageCurrent=page_num control.pageCurrent = page_num
control.requestPage(page_num,control.__itemPerPage) control.requestPage(page_num, control.__itemPerPage)
} }
} }

View File

@ -171,7 +171,7 @@ T.ScrollBar {
,Transition { ,Transition {
to: "show" to: "show"
SequentialAnimation { SequentialAnimation {
PauseAnimation { duration: 450 } PauseAnimation { duration: 150 }
NumberAnimation { NumberAnimation {
target: rect_bar target: rect_bar
properties: vertical ? "width" : "height" properties: vertical ? "width" : "height"

View File

@ -4,7 +4,7 @@ import FluentUI 1.0
Item { Item {
//高性能阴影比DropShadow阴影性能高出数倍 //高性能阴影比DropShadow阴影性能高出数倍
property color color: FluTheme.dark ? "#AAAAAA" : "#999999" property color color: FluTheme.dark ? "#000000" : "#999999"
property int elevation: 5 property int elevation: 5
property int radius: 4 property int radius: 4
id:control id:control

View File

@ -9,8 +9,10 @@ Rectangle {
readonly property alias rows: table_view.rows readonly property alias rows: table_view.rows
readonly property alias columns: table_view.columns readonly property alias columns: table_view.columns
readonly property alias current: d.current readonly property alias current: d.current
readonly property alias sourceModel: table_model property var sourceModel:FluTableModel {
property var columnSource columnSource: control.columnSource
}
property var columnSource: []
property var dataSource property var dataSource
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 borderColor: FluTheme.dark ? Qt.rgba(37/255,37/255,37/255,1) : Qt.rgba(228/255,228/255,228/255,1)
property bool horizonalHeaderVisible: true property bool horizonalHeaderVisible: true
@ -27,17 +29,20 @@ Rectangle {
onColumnSourceChanged: { onColumnSourceChanged: {
if(columnSource.length!==0){ if(columnSource.length!==0){
var columns= [] var columns= []
var columnsData = []
var headerRow = {} var headerRow = {}
columnSource.forEach(function(item){ var offsetX = 0
var column = Qt.createQmlObject('import Qt.labs.qmlmodels 1.0;TableModelColumn{}',table_model); for(var i=0;i<=columnSource.length-1;i++){
var item = columnSource[i]
if(!item.width){
item.width = d.defaultItemWidth
}
item.x = offsetX
offsetX = offsetX + item.width
var column = Qt.createQmlObject('import Qt.labs.qmlmodels 1.0;TableModelColumn{}',sourceModel);
column.display = item.dataIndex column.display = item.dataIndex
columnsData.push(item)
columns.push(column) columns.push(column)
headerRow[item.dataIndex] = item.title headerRow[item.dataIndex] = item
}) }
d.columns_data = columnsData
table_model.columns = columns
header_column_model.columns = columns header_column_model.columns = columns
header_column_model.rows = [headerRow] header_column_model.rows = [headerRow]
} }
@ -48,46 +53,42 @@ Rectangle {
property int rowHoverIndex: -1 property int rowHoverIndex: -1
property int defaultItemWidth: 100 property int defaultItemWidth: 100
property int defaultItemHeight: 42 property int defaultItemHeight: 42
property var columns_data: []
property var editDelegate property var editDelegate
property var editPosition property var editPosition
signal tableItemLayout(int column)
function getEditDelegate(column){ function getEditDelegate(column){
var obj =d.columns_data[column].editDelegate var obj =control.columnSource[column].editDelegate
if(obj){ if(obj){
return obj return obj
} }
if(d.columns_data[column].editMultiline === true){ if(control.columnSource[column].editMultiline === true){
return com_edit_multiline return com_edit_multiline
} }
return com_edit return com_edit
} }
} }
onDataSourceChanged: { onDataSourceChanged: {
table_model.clear() sourceModel.clear()
table_model.rows = dataSource sourceModel.rows = dataSource
}
TableModel {
id:table_model
TableModelColumn {}
} }
TableModel{ TableModel{
id:header_column_model id: header_column_model
TableModelColumn {} TableModelColumn { display : "title"}
} }
TableModel{ TableModel{
id:header_row_model id: header_row_model
TableModelColumn { display: "rowIndex" } TableModelColumn { display: "rowIndex" }
} }
FluTableSortProxyModel{ FluTableSortProxyModel{
id:table_sort_model id: table_sort_model
model: table_model model: control.sourceModel
} }
Component{ Component{
id:com_edit id:com_edit
FluTextBox{ FluTextBox{
id:text_box id:text_box
text: String(display) text: String(display)
readOnly: true === d.columns_data[column].readOnly readOnly: true === control.columnSource[column].readOnly
Component.onCompleted: { Component.onCompleted: {
forceActiveFocus() forceActiveFocus()
selectAll() selectAll()
@ -113,7 +114,7 @@ Rectangle {
TextArea.flickable: FluMultilineTextBox { TextArea.flickable: FluMultilineTextBox {
id:text_box id:text_box
text: String(display) text: String(display)
readOnly: true === d.columns_data[column].readOnly readOnly: true === control.columnSource[column].readOnly
verticalAlignment: TextInput.AlignVCenter verticalAlignment: TextInput.AlignVCenter
isCtrlEnterForNewline: true isCtrlEnterForNewline: true
Component.onCompleted: { Component.onCompleted: {
@ -196,14 +197,39 @@ Rectangle {
id:com_table_delegate id:com_table_delegate
MouseArea{ MouseArea{
id:item_table_mouse id:item_table_mouse
property var rowObject : control.getRow(row) implicitWidth: TableView.view.width
property var itemModel: model property var _model: model
property bool isMainTable: TableView.view == table_view
property var currentTableView: TableView.view
visible: {
if(isMainTable && columnModel.frozen){
return false
}
if(!isMainTable){
if(currentTableView.dataIndex !== columnModel.dataIndex)
return false
}
return true
}
property bool isRowSelected: {
if(rowModel === null)
return false
if(d.current){
return rowModel._key === d.current._key
}
return false
}
property bool editVisible: { property bool editVisible: {
if(rowObject && d.editPosition && d.editPosition._key === rowObject._key && d.editPosition.column === column){ if(d.editPosition && d.editPosition._key === rowModel._key && d.editPosition.column === column){
return true return true
} }
return false return false
} }
TableView.onPooled: {
if(d.editPosition && d.editPosition.row === row && d.editPosition.column === column){
control.closeEditor()
}
}
hoverEnabled: true hoverEnabled: true
onEntered: { onEntered: {
d.rowHoverIndex = row d.rowHoverIndex = row
@ -212,25 +238,37 @@ Rectangle {
if(editVisible){ if(editVisible){
updateEditPosition() updateEditPosition()
} }
if(isMainTable){
updateTableItem()
}
} }
onHeightChanged: { onHeightChanged: {
if(editVisible){ if(editVisible){
updateEditPosition() updateEditPosition()
} }
if(isMainTable){
updateTableItem()
}
} }
onXChanged: { onXChanged: {
if(editVisible){ if(editVisible){
updateEditPosition() updateEditPosition()
} }
if(isMainTable){
updateTableItem()
}
} }
onYChanged: { onYChanged: {
if(editVisible){ if(editVisible){
updateEditPosition() updateEditPosition()
} }
if(isMainTable){
updateTableItem()
}
} }
function updateEditPosition(){ function updateEditPosition(){
var obj = {} var obj = {}
obj._key = rowObject._key obj._key = rowModel._key
obj.column = column obj.column = column
obj.row = row obj.row = row
obj.x = item_table_mouse.x obj.x = item_table_mouse.x
@ -239,26 +277,22 @@ Rectangle {
obj.height = item_table_mouse.height - 2 obj.height = item_table_mouse.height - 2
d.editPosition = obj d.editPosition = obj
} }
function updateTableItem(){
var columnModel = control.columnSource[column]
columnModel.x = item_table_mouse.x
columnModel.y = item_table_mouse.y
d.tableItemLayout(column)
}
Rectangle{ Rectangle{
id:item_table
anchors.fill: parent anchors.fill: parent
property point position: Qt.point(column,row)
property bool isRowSelected: {
if(rowObject === null)
return false
if(d.current){
return rowObject._key === d.current._key
}
return false
}
color:{ color:{
if(item_table.isRowSelected){ if(item_table_mouse.isRowSelected){
return control.selectedColor return control.selectedColor
} }
if(d.rowHoverIndex === row || item_table.isRowSelected){ if(d.rowHoverIndex === row || item_table_mouse.isRowSelected){
return FluTheme.dark ? Qt.rgba(1,1,1,0.06) : Qt.rgba(0,0,0,0.06) 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)) return (row%2!==0) ? control.color : (FluTheme.dark ? Qt.rgba(1,1,1,0.03) : Qt.rgba(0,0,0,0.03))
} }
MouseArea{ MouseArea{
anchors.fill: parent anchors.fill: parent
@ -271,25 +305,28 @@ Rectangle {
onReleased: { onReleased: {
} }
onDoubleClicked:{ onDoubleClicked:{
if(typeof(display) == "object"){ if(item_table_loader.isObject){
return return
} }
loader_edit.display = item_table_loader.display
d.editDelegate = d.getEditDelegate(column) d.editDelegate = d.getEditDelegate(column)
updateEditPosition() item_table_mouse.updateEditPosition()
loader_edit.display = display
} }
onClicked: onClicked:
(event)=>{ (event)=>{
d.current = rowObject d.current = rowModel
control.closeEditor() control.closeEditor()
event.accepted = true event.accepted = true
} }
} }
FluLoader{ FluLoader{
property var model: itemModel id: item_table_loader
property var display: itemModel.display property var model: item_table_mouse._model
property int row: item_table.position.y property var display: rowModel[columnModel.dataIndex]
property int column: item_table.position.x property var rowModel : model.rowModel
property var columnModel : model.columnModel
property int row : model.row
property int column: model.column
property bool isObject: typeof(display) == "object" property bool isObject: typeof(display) == "object"
property var options: { property var options: {
if(isObject){ if(isObject){
@ -299,15 +336,53 @@ Rectangle {
} }
anchors.fill: parent anchors.fill: parent
sourceComponent: { sourceComponent: {
if(isObject){ if(item_table_mouse.visible){
return display.comId if(isObject){
return display.comId
}
return com_text
} }
return com_text return undefined
} }
} }
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
}
anchors{
fill: parent
margins: 1
}
signal editTextChaged(string text)
sourceComponent: {
if(item_table_mouse.visible && d.editPosition && d.editPosition.column === model.column && d.editPosition.row === model.row){
return d.editDelegate
}
return undefined
}
onEditTextChaged:
(text)=>{
var obj = control.getRow(row)
obj[control.columnSource[column].dataIndex] = text
control.setRow(row,obj)
}
z:999
}
Item{ Item{
anchors.fill: parent anchors.fill: parent
visible: item_table.isRowSelected visible: item_table_mouse.isRowSelected
Rectangle{ Rectangle{
width: 1 width: 1
height: parent.height height: parent.height
@ -360,24 +435,24 @@ Rectangle {
ScrollBar.horizontal:scroll_bar_h ScrollBar.horizontal:scroll_bar_h
ScrollBar.vertical:scroll_bar_v ScrollBar.vertical:scroll_bar_v
columnWidthProvider: function(column) { columnWidthProvider: function(column) {
var columnObject = d.columns_data[column] var columnModel = control.columnSource[column]
var width = columnObject.width var width = columnModel.width
if(width){ if(width){
return width return width
} }
var minimumWidth = columnObject.minimumWidth var minimumWidth = columnModel.minimumWidth
if(minimumWidth){ if(minimumWidth){
return minimumWidth return minimumWidth
} }
return d.defaultItemWidth return d.defaultItemWidth
} }
rowHeightProvider: function(row) { rowHeightProvider: function(row) {
var rowObject = control.getRow(row) var rowModel = control.getRow(row)
var height = rowObject.height var height = rowModel.height
if(height){ if(height){
return height return height
} }
var minimumHeight = rowObject._minimumHeight var minimumHeight = rowModel._minimumHeight
if(minimumHeight){ if(minimumHeight){
return minimumHeight return minimumHeight
} }
@ -390,70 +465,37 @@ Rectangle {
table_view.flick(0,1) table_view.flick(0,1)
} }
delegate: com_table_delegate delegate: com_table_delegate
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)=>{
var obj = control.getRow(row)
obj[d.columns_data[column].dataIndex] = text
control.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
}
} }
} }
Component{ Component{
id:com_column_header_delegate id:com_column_header_delegate
Rectangle{ Rectangle{
id:column_item_control id: column_item_control
property var currentTableView : TableView.view
readonly property real cellPadding: 8 readonly property real cellPadding: 8
property bool canceled: false property bool canceled: false
property int columnIndex: column property var _model: model
readonly property var columnObject : d.columns_data[column] readonly property var columnModel : control.columnSource[_index]
implicitWidth: { readonly property int _index : {
return (item_column_loader.item && item_column_loader.item.implicitWidth) + (cellPadding * 2) const isDataIndex = (element) => {
return element.dataIndex === display.dataIndex
}
return control.columnSource.findIndex(isDataIndex)
}
readonly property bool isHeaderHorizontal: TableView.view == header_horizontal
implicitWidth: {
if(column_item_control.isHeaderHorizontal){
return (item_column_loader.item && item_column_loader.item.implicitWidth) + (cellPadding * 2)
}
return TableView.view.width
}
implicitHeight: {
if(column_item_control.isHeaderHorizontal){
return Math.max(36, (item_column_loader.item&&item_column_loader.item.implicitHeight) + (cellPadding * 2))
}
return TableView.view.height
} }
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) color: FluTheme.dark ? Qt.rgba(50/255,50/255,50/255,1) : Qt.rgba(247/255,247/255,247/255,1)
Rectangle{ Rectangle{
border.color: control.borderColor border.color: control.borderColor
@ -474,7 +516,7 @@ Rectangle {
width: 1 width: 1
height: parent.height height: parent.height
anchors.left: parent.left anchors.left: parent.left
visible: column !== 0 visible: column_item_control._index !== 0
color:"#00000000" color:"#00000000"
} }
Rectangle{ Rectangle{
@ -483,7 +525,7 @@ Rectangle {
height: parent.height height: parent.height
anchors.right: parent.right anchors.right: parent.right
color:"#00000000" color:"#00000000"
visible: column === table_view.columns - 1 visible: column_item_control._index === table_view.columns - 1
} }
MouseArea{ MouseArea{
id:column_item_control_mouse id:column_item_control_mouse
@ -505,22 +547,23 @@ Rectangle {
} }
FluLoader{ FluLoader{
id:item_column_loader id:item_column_loader
property var itemModel: model property var model: column_item_control._model
property var modelData: model.display property var display: model.display.title
property var tableView: table_view property var tableView: table_view
property var tableModel: table_model property var sourceModel: control.sourceModel
property bool isObject: typeof(display) == "object"
property var options:{ property var options:{
if(typeof(modelData) == "object"){ if(isObject){
return modelData.options return display.options
} }
return {} return {}
} }
property int column: column_item_control.columnIndex property int column: column_item_control._index
width: parent.width width: parent.width
height: parent.height height: parent.height
sourceComponent: { sourceComponent: {
if(typeof(modelData) == "object"){ if(isObject){
return modelData.comId return display.comId
} }
return com_column_text return com_column_text
} }
@ -532,7 +575,7 @@ Rectangle {
anchors.right: parent.right anchors.right: parent.right
acceptedButtons: Qt.LeftButton acceptedButtons: Qt.LeftButton
hoverEnabled: true hoverEnabled: true
visible: !(columnObject.width === columnObject.minimumWidth && columnObject.width === columnObject.maximumWidth && columnObject.width) visible: !columnModel.frozen && !(columnModel.width === columnModel.minimumWidth && columnModel.width === columnModel.maximumWidth && columnModel.width)
cursorShape: Qt.SplitHCursor cursorShape: Qt.SplitHCursor
preventStealing: true preventStealing: true
onPressed : onPressed :
@ -552,9 +595,9 @@ Rectangle {
return return
} }
var delta = Qt.point(mouse.x - clickPos.x, mouse.y - clickPos.y) var delta = Qt.point(mouse.x - clickPos.x, mouse.y - clickPos.y)
var minimumWidth = columnObject.minimumWidth var minimumWidth = columnModel.minimumWidth
var maximumWidth = columnObject.maximumWidth var maximumWidth = columnModel.maximumWidth
var w = columnObject.width var w = columnModel.width
if(!w){ if(!w){
w = d.defaultItemWidth w = d.defaultItemWidth
} }
@ -564,9 +607,10 @@ Rectangle {
if(!maximumWidth){ if(!maximumWidth){
maximumWidth = 65535 maximumWidth = 65535
} }
columnObject.width = Math.min(Math.max(minimumWidth, w + delta.x),maximumWidth) columnModel.width = Math.min(Math.max(minimumWidth, w + delta.x),maximumWidth)
table_view.forceLayout() table_view.forceLayout()
header_horizontal.forceLayout() header_horizontal.forceLayout()
// column_item_control.currentTableView.forceLayout()
} }
} }
} }
@ -577,7 +621,7 @@ Rectangle {
id:item_control id:item_control
readonly property real cellPadding: 8 readonly property real cellPadding: 8
property bool canceled: false property bool canceled: false
property var rowObject: control.getRow(row) property var rowModel: control.getRow(row)
implicitWidth: Math.max(30, row_text.implicitWidth + (cellPadding * 2)) implicitWidth: Math.max(30, row_text.implicitWidth + (cellPadding * 2))
implicitHeight: row_text.implicitHeight + (cellPadding * 2) implicitHeight: row_text.implicitHeight + (cellPadding * 2)
color: FluTheme.dark ? Qt.rgba(50/255,50/255,50/255,1) : Qt.rgba(247/255,247/255,247/255,1) color: FluTheme.dark ? Qt.rgba(50/255,50/255,50/255,1) : Qt.rgba(247/255,247/255,247/255,1)
@ -643,9 +687,9 @@ Rectangle {
cursorShape: Qt.SplitVCursor cursorShape: Qt.SplitVCursor
preventStealing: true preventStealing: true
visible: { visible: {
if(rowObject === null) if(rowModel === null)
return false return false
return !(rowObject.height === rowObject._minimumHeight && rowObject.height === rowObject._maximumHeight && rowObject.height) return !(rowModel.height === rowModel._minimumHeight && rowModel.height === rowModel._maximumHeight && rowModel.height)
} }
onPressed : onPressed :
(mouse)=>{ (mouse)=>{
@ -663,11 +707,11 @@ Rectangle {
if(!pressed){ if(!pressed){
return return
} }
var rowObject = control.getRow(row) var rowModel = control.getRow(row)
var delta = Qt.point(mouse.x - clickPos.x, mouse.y - clickPos.y) var delta = Qt.point(mouse.x - clickPos.x, mouse.y - clickPos.y)
var minimumHeight = rowObject._minimumHeight var minimumHeight = rowModel._minimumHeight
var maximumHeight = rowObject._maximumHeight var maximumHeight = rowModel._maximumHeight
var h = rowObject.height var h = rowModel.height
if(!h){ if(!h){
h = d.defaultItemHeight h = d.defaultItemHeight
} }
@ -677,8 +721,8 @@ Rectangle {
if(!maximumHeight){ if(!maximumHeight){
maximumHeight = 65535 maximumHeight = 65535
} }
rowObject.height = Math.min(Math.max(minimumHeight, h + delta.y),maximumHeight) rowModel.height = Math.min(Math.max(minimumHeight, h + delta.y),maximumHeight)
control.setRow(row,rowObject) control.setRow(row,rowModel)
table_view.forceLayout() table_view.forceLayout()
} }
} }
@ -688,7 +732,7 @@ Rectangle {
id:com_column_text id:com_column_text
FluText { FluText {
id: column_text id: column_text
text: modelData text: String(display)
anchors.fill: parent anchors.fill: parent
horizontalAlignment: Text.AlignHCenter horizontalAlignment: Text.AlignHCenter
verticalAlignment: Text.AlignVCenter verticalAlignment: Text.AlignVCenter
@ -791,6 +835,124 @@ Rectangle {
} }
} }
} }
Item{
anchors{
left: header_vertical.right
top: parent.top
bottom: parent.bottom
right: parent.right
}
Component{
id: com_table_frozen
Rectangle{
id: item_layout_frozen
anchors.fill: parent
color: {
if(Window.active){
return FluTheme.dark ? Qt.rgba(48/255,48/255,48/255,1) :Qt.rgba(1,1,1,1)
}
return FluTheme.dark ? Qt.rgba(56/255,56/255,56/255,1) :Qt.rgba(243/255,243/255,243/255,1)
}
visible: table_view.rows !== 0
Rectangle{
z:99
anchors.fill: parent
border.color: FluTheme.dark ? Qt.rgba(26/255,26/255,26/255,0.6) : Qt.rgba(191/255,191/255,191/255,0.3)
FluShadow{
radius: 0
anchors.fill: parent
}
color: "#00000000"
}
TableView {
id:item_table_frozen_header
model: header_column_model
boundsBehavior: Flickable.StopAtBounds
clip: true
interactive: false
anchors{
left: parent.left
right: parent.right
top: parent.top
bottom: item_table_frozen.top
}
delegate: com_column_header_delegate
}
TableView{
property string dataIndex: columnModel.dataIndex
id: item_table_frozen
clip: true
interactive: false
anchors{
fill: parent
topMargin: header_horizontal.height
}
boundsBehavior: TableView.StopAtBounds
model: table_sort_model
delegate: com_table_delegate
syncDirection: Qt.Vertical
syncView: table_view
Component.onCompleted: {
item_table_frozen_header.contentX = columnModel.width * _index
item_table_frozen.contentX = columnModel.width * _index
}
}
}
}
Repeater{
model: control.columnSource
delegate: FluLoader{
id: item_layout_frozen
readonly property int _index : model.index
readonly property var columnModel : control.columnSource[_index]
Connections{
target: d
function onTableItemLayout(column){
if(item_layout_frozen._index === column){
updateLayout()
}
}
}
Connections{
target: table_view
function onContentXChanged(){
updateLayout()
}
}
function updateLayout(){
width = table_view.columnWidthProvider(_index)
x = Qt.binding(function(){
var minX = 0
var maxX = table_view.width-item_layout_frozen.width
for(var i=0;i<_index;i++){
var item = control.columnSource[i]
if(item.frozen){
minX = minX + item.width
}
}
for(i=_index+1;i<control.columnSource.length;i++){
item = control.columnSource[i]
if(item.frozen){
maxX = maxX- item.width
}
}
return Math.min(Math.max(columnModel.x - table_view.contentX,minX),maxX)}
)
}
Component.onCompleted: {
updateLayout()
}
height: control.height
visible: {
if(modelData.frozen){
return true
}
return false
}
sourceComponent: visible ? com_table_frozen : undefined
}
}
}
FluScrollBar { FluScrollBar {
id: scroll_bar_h id: scroll_bar_h
anchors{ anchors{
@ -837,7 +999,7 @@ Rectangle {
function sort(callback=undefined){ function sort(callback=undefined){
if(callback){ if(callback){
table_sort_model.setComparator(function(left,right){ table_sort_model.setComparator(function(left,right){
return callback(table_model.getRow(left),table_model.getRow(right)) return callback(sourceModel.getRow(left),sourceModel.getRow(right))
}) })
}else{ }else{
table_sort_model.setComparator(undefined) table_sort_model.setComparator(undefined)
@ -846,7 +1008,7 @@ Rectangle {
function filter(callback=undefined){ function filter(callback=undefined){
if(callback){ if(callback){
table_sort_model.setFilter(function(index){ table_sort_model.setFilter(function(index){
return callback(table_model.getRow(index)) return callback(sourceModel.getRow(index))
}) })
}else{ }else{
table_sort_model.setFilter(undefined) table_sort_model.setFilter(undefined)
@ -868,7 +1030,26 @@ Rectangle {
table_view.model.removeRow(rowIndex,rows) table_view.model.removeRow(rowIndex,rows)
} }
} }
function insertRow(rowIndex,obj){
if(rowIndex>=0 && rowIndex<table_view.rows){
sourceModel.insertRow(rowIndex,obj)
}
}
function currentIndex(){
var index = -1
if(!d.current){
return index
}
for (var i = 0; i <= sourceModel.rowCount-1; i++) {
var sourceItem = sourceModel.getRow(i);
if(sourceItem._key === d.current._key){
index = i
break
}
}
return index
}
function appendRow(obj){ function appendRow(obj){
table_model.appendRow(obj) sourceModel.appendRow(obj)
} }
} }

View File

@ -60,8 +60,9 @@ Window {
signal lazyLoad() signal lazyLoad()
property var _windowRegister property var _windowRegister
property string _route property string _route
id:window property bool _hideShadow: false
color:"transparent" id: window
color: FluTools.isSoftware() ? window.backgroundColor : "transparent"
Component.onCompleted: { Component.onCompleted: {
FluRouter.addWindow(window) FluRouter.addWindow(window)
useSystemAppBar = FluApp.useSystemAppBar useSystemAppBar = FluApp.useSystemAppBar
@ -142,7 +143,7 @@ Window {
} }
Timer{ Timer{
id:timer_update_image id:timer_update_image
interval: 500 interval: 150
onTriggered: { onTriggered: {
img_back.source = "" img_back.source = ""
img_back.source = FluTools.getUrlByFilePath(FluTheme.desktopImagePath) img_back.source = FluTools.getUrlByFilePath(FluTheme.desktopImagePath)
@ -279,13 +280,7 @@ Window {
id:loader_border id:loader_border
anchors.fill: parent anchors.fill: parent
sourceComponent: { sourceComponent: {
if(window.useSystemAppBar){ if(window.useSystemAppBar || FluTools.isWin() || window.visibility === Window.Maximized || window.visibility === Window.FullScreen){
return undefined
}
if(FluTools.isWindows10OrGreater()){
return undefined
}
if(window.visibility === Window.Maximized || window.visibility === Window.FullScreen){
return undefined return undefined
} }
return com_border return com_border
@ -307,7 +302,6 @@ Window {
info_bar.showError(text,duration,moremsg) info_bar.showError(text,duration,moremsg)
} }
function moveWindowToDesktopCenter(){ function moveWindowToDesktopCenter(){
screen = Qt.application.screens[FluTools.cursorScreenIndex()]
var availableGeometry = FluTools.desktopAvailableGeometry(window) var availableGeometry = FluTools.desktopAvailableGeometry(window)
window.setGeometry((availableGeometry.width-window.width)/2+Screen.virtualX,(availableGeometry.height-window.height)/2+Screen.virtualY,window.width,window.height) window.setGeometry((availableGeometry.width-window.width)/2+Screen.virtualX,(availableGeometry.height-window.height)/2+Screen.virtualY,window.width,window.height)
} }

View File

@ -6,6 +6,7 @@ FluTextBox{
property var items:[] property var items:[]
property string emptyText: qsTr("No results found") property string emptyText: qsTr("No results found")
property int autoSuggestBoxReplacement: FluentIcons.Search property int autoSuggestBoxReplacement: FluentIcons.Search
property string textRole: "title"
property var filter: function(item){ property var filter: function(item){
if(item.title.indexOf(control.text)!==-1){ if(item.title.indexOf(control.text)!==-1){
return true return true
@ -24,7 +25,7 @@ FluTextBox{
function handleClick(modelData){ function handleClick(modelData){
control_popup.visible = false control_popup.visible = false
control.itemClicked(modelData) control.itemClicked(modelData)
control.updateText(modelData.title) control.updateText(modelData[textRole])
} }
function loadData(){ function loadData(){
var result = [] var result = []
@ -47,7 +48,6 @@ FluTextBox{
} }
Popup{ Popup{
id:control_popup id:control_popup
y:control.height
focus: false focus: false
padding: 0 padding: 0
enter: Transition { enter: Transition {
@ -61,7 +61,7 @@ FluTextBox{
contentItem: FluClip{ contentItem: FluClip{
radius: [5,5,5,5] radius: [5,5,5,5]
ListView{ ListView{
id:list_view id: list_view
anchors.fill: parent anchors.fill: parent
clip: true clip: true
boundsBehavior: ListView.StopAtBounds boundsBehavior: ListView.StopAtBounds
@ -71,7 +71,7 @@ FluTextBox{
height: visible ? 38 : 0 height: visible ? 38 : 0
visible: list_view.count === 0 visible: list_view.count === 0
FluText{ FluText{
text:emptyText text: emptyText
anchors{ anchors{
verticalCenter: parent.verticalCenter verticalCenter: parent.verticalCenter
left: parent.left left: parent.left
@ -80,10 +80,10 @@ FluTextBox{
} }
} }
delegate:FluControl{ delegate:FluControl{
id:item_control id: item_control
height: 38 height: 38
width: control.width width: control.width
onClicked:{ onClicked: {
d.handleClick(modelData) d.handleClick(modelData)
} }
background: Rectangle{ background: Rectangle{
@ -102,7 +102,7 @@ FluTextBox{
} }
} }
contentItem: FluText{ contentItem: FluText{
text:modelData.title text: modelData[textRole]
leftPadding: 10 leftPadding: 10
rightPadding: 10 rightPadding: 10
verticalAlignment : Qt.AlignVCenter verticalAlignment : Qt.AlignVCenter
@ -127,7 +127,7 @@ FluTextBox{
if(d.flagVisible){ if(d.flagVisible){
var pos = control.mapToItem(null, 0, 0) var pos = control.mapToItem(null, 0, 0)
if(d.window.height>pos.y+control.height+rect_background.implicitHeight){ if(d.window.height>pos.y+control.height+rect_background.implicitHeight){
control_popup.y = control.height control_popup.y = Qt.binding(function(){return control.height})
} else if(pos.y>rect_background.implicitHeight){ } else if(pos.y>rect_background.implicitHeight){
control_popup.y = -rect_background.implicitHeight control_popup.y = -rect_background.implicitHeight
} else { } else {

View File

@ -11,6 +11,7 @@ T.ComboBox {
property color normalColor: FluTheme.dark ? Qt.rgba(62/255,62/255,62/255,1) : Qt.rgba(254/255,254/255,254/255,1) property color normalColor: FluTheme.dark ? Qt.rgba(62/255,62/255,62/255,1) : Qt.rgba(254/255,254/255,254/255,1)
property color hoverColor: FluTheme.dark ? Qt.rgba(68/255,68/255,68/255,1) : Qt.rgba(251/255,251/255,251/255,1) property color hoverColor: FluTheme.dark ? Qt.rgba(68/255,68/255,68/255,1) : Qt.rgba(251/255,251/255,251/255,1)
property color disableColor: FluTheme.dark ? Qt.rgba(59/255,59/255,59/255,1) : Qt.rgba(252/255,252/255,252/255,1) property color disableColor: FluTheme.dark ? Qt.rgba(59/255,59/255,59/255,1) : Qt.rgba(252/255,252/255,252/255,1)
property alias textBox: text_field
implicitWidth: Math.max(implicitBackgroundWidth + leftInset + rightInset, implicitWidth: Math.max(implicitBackgroundWidth + leftInset + rightInset,
implicitContentWidth + leftPadding + rightPadding) implicitContentWidth + leftPadding + rightPadding)
implicitHeight: Math.max(implicitBackgroundHeight + topInset + bottomInset, implicitHeight: Math.max(implicitBackgroundHeight + topInset + bottomInset,
@ -39,6 +40,7 @@ T.ComboBox {
opacity: enabled ? 1 : 0.3 opacity: enabled ? 1 : 0.3
} }
contentItem: T.TextField { contentItem: T.TextField {
id: text_field
property bool disabled: !control.editable property bool disabled: !control.editable
leftPadding: !control.mirrored ? 10 : control.editable && activeFocus ? 3 : 1 leftPadding: !control.mirrored ? 10 : control.editable && activeFocus ? 3 : 1
rightPadding: control.mirrored ? 10 : control.editable && activeFocus ? 3 : 1 rightPadding: control.mirrored ? 10 : control.editable && activeFocus ? 3 : 1

View File

@ -49,9 +49,6 @@ T.MenuBarItem {
radius: 3 radius: 3
color: { color: {
if(control.highlighted){ if(control.highlighted){
return FluTheme.itemCheckColor
}
if(control.hovered){
return FluTheme.itemHoverColor return FluTheme.itemHoverColor
} }
return FluTheme.itemNormalColor return FluTheme.itemNormalColor

View File

@ -100,9 +100,9 @@ T.MenuItem {
anchors.fill: parent anchors.fill: parent
anchors.margins: 3 anchors.margins: 3
radius: 4 radius: 4
color:{ color: {
if(control.highlighted){ if(control.highlighted){
return FluTheme.itemCheckColor return FluTheme.itemHoverColor
} }
return FluTheme.itemNormalColor return FluTheme.itemNormalColor
} }

View File

@ -4,97 +4,105 @@ import QtQuick.Layouts
import FluentUI import FluentUI
Item { Item {
signal requestPage(int page,int count) signal requestPage(int page, int count)
property string previousText: qsTr("<Previous") property string previousText: qsTr("<Previous")
property string nextText: qsTr("Next>") property string nextText: qsTr("Next>")
property int pageCurrent: 0 property int pageCurrent: 0
property int itemCount: 0 property int itemCount: 0
property int pageButtonCount: 5 property int pageButtonCount: 5
property int pageCount: itemCount>0?Math.ceil(itemCount/__itemPerPage):0 property int pageCount: itemCount > 0 ? Math.ceil(itemCount / __itemPerPage) : 0
property int __itemPerPage: 10 property int __itemPerPage: 10
property int __pageButtonHalf: Math.floor(pageButtonCount/2)+1 property int __pageButtonHalf: Math.floor(pageButtonCount / 2) + 1
property Component header: null
property Component footer: null
id: control id: control
implicitHeight: 40 implicitHeight: 40
implicitWidth: content.width implicitWidth: content.width
Row{ Row {
id: content id: content
height: control.height height: control.height
spacing: 10 spacing: 10
padding: 10 padding: 10
FluToggleButton{ Loader {
visible: control.pageCount>1 sourceComponent: header
disabled: control.pageCurrent<=1 }
text:control.previousText FluToggleButton {
clickListener:function() { visible: control.pageCount > 1
control.calcNewPage(control.pageCurrent-1); disabled: control.pageCurrent <= 1
text: control.previousText
clickListener: function () {
control.calcNewPage(control.pageCurrent - 1);
} }
} }
Row{ Row {
spacing: 5 spacing: 5
FluToggleButton{ FluToggleButton {
property int pageNumber:1 property int pageNumber: 1
visible: control.pageCount>0 visible: control.pageCount > 0
checked: pageNumber === control.pageCurrent checked: pageNumber === control.pageCurrent
text:String(pageNumber) text: String(pageNumber)
clickListener:function() { clickListener: function () {
control.calcNewPage(pageNumber); control.calcNewPage(pageNumber);
} }
} }
FluText{ FluText {
visible: (control.pageCount>control.pageButtonCount&& visible: (control.pageCount > control.pageButtonCount &&
control.pageCurrent>control.__pageButtonHalf) control.pageCurrent > control.__pageButtonHalf)
text: "..." text: "..."
} }
Repeater{ Repeater {
id: button_repeator id: button_repeator
model: (control.pageCount<2)?0:(control.pageCount>=control.pageButtonCount)?(control.pageButtonCount-2):(control.pageCount-2) model: (control.pageCount < 2) ? 0 : (control.pageCount >= control.pageButtonCount) ? (control.pageButtonCount - 2) : (control.pageCount - 2)
delegate:FluToggleButton{ delegate: FluToggleButton {
property int pageNumber: { property int pageNumber: {
return (control.pageCurrent<=control.__pageButtonHalf) return (control.pageCurrent <= control.__pageButtonHalf)
?(2+index) ? (2 + index)
:(control.pageCount-control.pageCurrent<=control.pageButtonCount-control.__pageButtonHalf) : (control.pageCount - control.pageCurrent <= control.pageButtonCount - control.__pageButtonHalf)
?(control.pageCount-button_repeator.count+index) ? (control.pageCount - button_repeator.count + index)
:(control.pageCurrent+2+index-control.__pageButtonHalf) : (control.pageCurrent + 2 + index - control.__pageButtonHalf)
} }
text:String(pageNumber) text: String(pageNumber)
checked: pageNumber === control.pageCurrent checked: pageNumber === control.pageCurrent
clickListener:function(){ clickListener: function () {
control.calcNewPage(pageNumber); control.calcNewPage(pageNumber);
} }
} }
} }
FluText{ FluText {
visible: (control.pageCount>control.pageButtonCount&& visible: (control.pageCount > control.pageButtonCount &&
control.pageCount-control.pageCurrent>control.pageButtonCount-control.__pageButtonHalf) control.pageCount - control.pageCurrent > control.pageButtonCount - control.__pageButtonHalf)
text: "..." text: "..."
} }
FluToggleButton{ FluToggleButton {
property int pageNumber:control.pageCount property int pageNumber: control.pageCount
visible: control.pageCount>1 visible: control.pageCount > 1
checked: pageNumber === control.pageCurrent checked: pageNumber === control.pageCurrent
text:String(pageNumber) text: String(pageNumber)
clickListener:function(){ clickListener: function () {
control.calcNewPage(pageNumber); control.calcNewPage(pageNumber);
} }
} }
} }
FluToggleButton{ FluToggleButton {
visible: control.pageCount>1 visible: control.pageCount > 1
disabled: control.pageCurrent>=control.pageCount disabled: control.pageCurrent >= control.pageCount
text:control.nextText text: control.nextText
clickListener:function() { clickListener: function () {
control.calcNewPage(control.pageCurrent+1); control.calcNewPage(control.pageCurrent + 1);
} }
} }
Loader {
sourceComponent: footer
}
} }
function calcNewPage(page) function calcNewPage(page) {
{ if (!page)
if(!page)
return return
let page_num=Number(page) let page_num = Number(page)
if(page_num<1||page_num>control.pageCount||page_num===control.pageCurrent) if (page_num < 1 || page_num > control.pageCount || page_num === control.pageCurrent)
return return
control.pageCurrent=page_num control.pageCurrent = page_num
control.requestPage(page_num,control.__itemPerPage) control.requestPage(page_num, control.__itemPerPage)
} }
} }

View File

@ -56,7 +56,9 @@ QtObject {
var launchMode = win.launchMode var launchMode = win.launchMode
if(launchMode === 1){ if(launchMode === 1){
win.argument = argument win.argument = argument
win.show() if(!win.visible){
win.visible = true
}
win.raise() win.raise()
win.requestActivate() win.requestActivate()
return return

View File

@ -173,7 +173,7 @@ T.ScrollBar {
,Transition { ,Transition {
to: "show" to: "show"
SequentialAnimation { SequentialAnimation {
PauseAnimation { duration: 450 } PauseAnimation { duration: 150 }
NumberAnimation { NumberAnimation {
target: rect_bar target: rect_bar
properties: vertical ? "width" : "height" properties: vertical ? "width" : "height"

View File

@ -4,7 +4,7 @@ import FluentUI
Item { Item {
//高性能阴影比DropShadow阴影性能高出数倍 //高性能阴影比DropShadow阴影性能高出数倍
property color color: FluTheme.dark ? "#AAAAAA" : "#999999" property color color: FluTheme.dark ? "#000000" : "#999999"
property int elevation: 5 property int elevation: 5
property int radius: 4 property int radius: 4
id:control id:control

View File

@ -9,8 +9,10 @@ Rectangle {
readonly property alias rows: table_view.rows readonly property alias rows: table_view.rows
readonly property alias columns: table_view.columns readonly property alias columns: table_view.columns
readonly property alias current: d.current readonly property alias current: d.current
readonly property alias sourceModel: table_model property var sourceModel:FluTableModel {
property var columnSource columnSource: control.columnSource
}
property var columnSource: []
property var dataSource property var dataSource
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 borderColor: FluTheme.dark ? Qt.rgba(37/255,37/255,37/255,1) : Qt.rgba(228/255,228/255,228/255,1)
property bool horizonalHeaderVisible: true property bool horizonalHeaderVisible: true
@ -27,17 +29,20 @@ Rectangle {
onColumnSourceChanged: { onColumnSourceChanged: {
if(columnSource.length!==0){ if(columnSource.length!==0){
var columns= [] var columns= []
var columnsData = []
var headerRow = {} var headerRow = {}
columnSource.forEach(function(item){ var offsetX = 0
var column = Qt.createQmlObject('import Qt.labs.qmlmodels 1.0;TableModelColumn{}',table_model); for(var i=0;i<=columnSource.length-1;i++){
var item = columnSource[i]
if(!item.width){
item.width = d.defaultItemWidth
}
item.x = offsetX
offsetX = offsetX + item.width
var column = Qt.createQmlObject('import Qt.labs.qmlmodels 1.0;TableModelColumn{}',sourceModel);
column.display = item.dataIndex column.display = item.dataIndex
columnsData.push(item)
columns.push(column) columns.push(column)
headerRow[item.dataIndex] = item.title headerRow[item.dataIndex] = item
}) }
d.columns_data = columnsData
table_model.columns = columns
header_column_model.columns = columns header_column_model.columns = columns
header_column_model.rows = [headerRow] header_column_model.rows = [headerRow]
} }
@ -48,46 +53,42 @@ Rectangle {
property int rowHoverIndex: -1 property int rowHoverIndex: -1
property int defaultItemWidth: 100 property int defaultItemWidth: 100
property int defaultItemHeight: 42 property int defaultItemHeight: 42
property var columns_data: []
property var editDelegate property var editDelegate
property var editPosition property var editPosition
signal tableItemLayout(int column)
function getEditDelegate(column){ function getEditDelegate(column){
var obj =d.columns_data[column].editDelegate var obj =control.columnSource[column].editDelegate
if(obj){ if(obj){
return obj return obj
} }
if(d.columns_data[column].editMultiline === true){ if(control.columnSource[column].editMultiline === true){
return com_edit_multiline return com_edit_multiline
} }
return com_edit return com_edit
} }
} }
onDataSourceChanged: { onDataSourceChanged: {
table_model.clear() sourceModel.clear()
table_model.rows = dataSource sourceModel.rows = dataSource
}
TableModel {
id:table_model
TableModelColumn {}
} }
TableModel{ TableModel{
id:header_column_model id: header_column_model
TableModelColumn {} TableModelColumn { display : "title"}
} }
TableModel{ TableModel{
id:header_row_model id: header_row_model
TableModelColumn { display: "rowIndex" } TableModelColumn { display: "rowIndex" }
} }
FluTableSortProxyModel{ FluTableSortProxyModel{
id:table_sort_model id: table_sort_model
model: table_model model: control.sourceModel
} }
Component{ Component{
id:com_edit id:com_edit
FluTextBox{ FluTextBox{
id:text_box id:text_box
text: String(display) text: String(display)
readOnly: true === d.columns_data[column].readOnly readOnly: true === control.columnSource[column].readOnly
Component.onCompleted: { Component.onCompleted: {
forceActiveFocus() forceActiveFocus()
selectAll() selectAll()
@ -113,7 +114,7 @@ Rectangle {
TextArea.flickable: FluMultilineTextBox { TextArea.flickable: FluMultilineTextBox {
id:text_box id:text_box
text: String(display) text: String(display)
readOnly: true === d.columns_data[column].readOnly readOnly: true === control.columnSource[column].readOnly
verticalAlignment: TextInput.AlignVCenter verticalAlignment: TextInput.AlignVCenter
isCtrlEnterForNewline: true isCtrlEnterForNewline: true
Component.onCompleted: { Component.onCompleted: {
@ -196,14 +197,39 @@ Rectangle {
id:com_table_delegate id:com_table_delegate
MouseArea{ MouseArea{
id:item_table_mouse id:item_table_mouse
property var rowObject : control.getRow(row) implicitWidth: TableView.view.width
property var itemModel: model property var _model: model
property bool isMainTable: TableView.view == table_view
property var currentTableView: TableView.view
visible: {
if(isMainTable && columnModel.frozen){
return false
}
if(!isMainTable){
if(currentTableView.dataIndex !== columnModel.dataIndex)
return false
}
return true
}
property bool isRowSelected: {
if(rowModel === null)
return false
if(d.current){
return rowModel._key === d.current._key
}
return false
}
property bool editVisible: { property bool editVisible: {
if(rowObject && d.editPosition && d.editPosition._key === rowObject._key && d.editPosition.column === column){ if(d.editPosition && d.editPosition._key === rowModel._key && d.editPosition.column === column){
return true return true
} }
return false return false
} }
TableView.onPooled: {
if(d.editPosition && d.editPosition.row === row && d.editPosition.column === column){
control.closeEditor()
}
}
hoverEnabled: true hoverEnabled: true
onEntered: { onEntered: {
d.rowHoverIndex = row d.rowHoverIndex = row
@ -212,25 +238,37 @@ Rectangle {
if(editVisible){ if(editVisible){
updateEditPosition() updateEditPosition()
} }
if(isMainTable){
updateTableItem()
}
} }
onHeightChanged: { onHeightChanged: {
if(editVisible){ if(editVisible){
updateEditPosition() updateEditPosition()
} }
if(isMainTable){
updateTableItem()
}
} }
onXChanged: { onXChanged: {
if(editVisible){ if(editVisible){
updateEditPosition() updateEditPosition()
} }
if(isMainTable){
updateTableItem()
}
} }
onYChanged: { onYChanged: {
if(editVisible){ if(editVisible){
updateEditPosition() updateEditPosition()
} }
if(isMainTable){
updateTableItem()
}
} }
function updateEditPosition(){ function updateEditPosition(){
var obj = {} var obj = {}
obj._key = rowObject._key obj._key = rowModel._key
obj.column = column obj.column = column
obj.row = row obj.row = row
obj.x = item_table_mouse.x obj.x = item_table_mouse.x
@ -239,26 +277,22 @@ Rectangle {
obj.height = item_table_mouse.height - 2 obj.height = item_table_mouse.height - 2
d.editPosition = obj d.editPosition = obj
} }
function updateTableItem(){
var columnModel = control.columnSource[column]
columnModel.x = item_table_mouse.x
columnModel.y = item_table_mouse.y
d.tableItemLayout(column)
}
Rectangle{ Rectangle{
id:item_table
anchors.fill: parent anchors.fill: parent
property point position: Qt.point(column,row)
property bool isRowSelected: {
if(rowObject === null)
return false
if(d.current){
return rowObject._key === d.current._key
}
return false
}
color:{ color:{
if(item_table.isRowSelected){ if(item_table_mouse.isRowSelected){
return control.selectedColor return control.selectedColor
} }
if(d.rowHoverIndex === row || item_table.isRowSelected){ if(d.rowHoverIndex === row || item_table_mouse.isRowSelected){
return FluTheme.dark ? Qt.rgba(1,1,1,0.06) : Qt.rgba(0,0,0,0.06) 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)) return (row%2!==0) ? control.color : (FluTheme.dark ? Qt.rgba(1,1,1,0.03) : Qt.rgba(0,0,0,0.03))
} }
MouseArea{ MouseArea{
anchors.fill: parent anchors.fill: parent
@ -271,25 +305,28 @@ Rectangle {
onReleased: { onReleased: {
} }
onDoubleClicked:{ onDoubleClicked:{
if(typeof(display) == "object"){ if(item_table_loader.isObject){
return return
} }
loader_edit.display = item_table_loader.display
d.editDelegate = d.getEditDelegate(column) d.editDelegate = d.getEditDelegate(column)
updateEditPosition() item_table_mouse.updateEditPosition()
loader_edit.display = display
} }
onClicked: onClicked:
(event)=>{ (event)=>{
d.current = rowObject d.current = rowModel
control.closeEditor() control.closeEditor()
event.accepted = true event.accepted = true
} }
} }
FluLoader{ FluLoader{
property var model: itemModel id: item_table_loader
property var display: itemModel.display property var model: item_table_mouse._model
property int row: item_table.position.y property var display: rowModel[columnModel.dataIndex]
property int column: item_table.position.x property var rowModel : model.rowModel
property var columnModel : model.columnModel
property int row : model.row
property int column: model.column
property bool isObject: typeof(display) == "object" property bool isObject: typeof(display) == "object"
property var options: { property var options: {
if(isObject){ if(isObject){
@ -299,15 +336,53 @@ Rectangle {
} }
anchors.fill: parent anchors.fill: parent
sourceComponent: { sourceComponent: {
if(isObject){ if(item_table_mouse.visible){
return display.comId if(isObject){
return display.comId
}
return com_text
} }
return com_text return undefined
} }
} }
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
}
anchors{
fill: parent
margins: 1
}
signal editTextChaged(string text)
sourceComponent: {
if(item_table_mouse.visible && d.editPosition && d.editPosition.column === model.column && d.editPosition.row === model.row){
return d.editDelegate
}
return undefined
}
onEditTextChaged:
(text)=>{
var obj = control.getRow(row)
obj[control.columnSource[column].dataIndex] = text
control.setRow(row,obj)
}
z:999
}
Item{ Item{
anchors.fill: parent anchors.fill: parent
visible: item_table.isRowSelected visible: item_table_mouse.isRowSelected
Rectangle{ Rectangle{
width: 1 width: 1
height: parent.height height: parent.height
@ -360,24 +435,24 @@ Rectangle {
ScrollBar.horizontal:scroll_bar_h ScrollBar.horizontal:scroll_bar_h
ScrollBar.vertical:scroll_bar_v ScrollBar.vertical:scroll_bar_v
columnWidthProvider: function(column) { columnWidthProvider: function(column) {
var columnObject = d.columns_data[column] var columnModel = control.columnSource[column]
var width = columnObject.width var width = columnModel.width
if(width){ if(width){
return width return width
} }
var minimumWidth = columnObject.minimumWidth var minimumWidth = columnModel.minimumWidth
if(minimumWidth){ if(minimumWidth){
return minimumWidth return minimumWidth
} }
return d.defaultItemWidth return d.defaultItemWidth
} }
rowHeightProvider: function(row) { rowHeightProvider: function(row) {
var rowObject = control.getRow(row) var rowModel = control.getRow(row)
var height = rowObject.height var height = rowModel.height
if(height){ if(height){
return height return height
} }
var minimumHeight = rowObject._minimumHeight var minimumHeight = rowModel._minimumHeight
if(minimumHeight){ if(minimumHeight){
return minimumHeight return minimumHeight
} }
@ -390,70 +465,37 @@ Rectangle {
table_view.flick(0,1) table_view.flick(0,1)
} }
delegate: com_table_delegate delegate: com_table_delegate
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)=>{
var obj = control.getRow(row)
obj[d.columns_data[column].dataIndex] = text
control.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
}
} }
} }
Component{ Component{
id:com_column_header_delegate id:com_column_header_delegate
Rectangle{ Rectangle{
id:column_item_control id: column_item_control
property var currentTableView : TableView.view
readonly property real cellPadding: 8 readonly property real cellPadding: 8
property bool canceled: false property bool canceled: false
property int columnIndex: column property var _model: model
readonly property var columnObject : d.columns_data[column] readonly property var columnModel : control.columnSource[_index]
implicitWidth: { readonly property int _index : {
return (item_column_loader.item && item_column_loader.item.implicitWidth) + (cellPadding * 2) const isDataIndex = (element) => {
return element.dataIndex === display.dataIndex
}
return control.columnSource.findIndex(isDataIndex)
}
readonly property bool isHeaderHorizontal: TableView.view == header_horizontal
implicitWidth: {
if(column_item_control.isHeaderHorizontal){
return (item_column_loader.item && item_column_loader.item.implicitWidth) + (cellPadding * 2)
}
return TableView.view.width
}
implicitHeight: {
if(column_item_control.isHeaderHorizontal){
return Math.max(36, (item_column_loader.item&&item_column_loader.item.implicitHeight) + (cellPadding * 2))
}
return TableView.view.height
} }
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) color: FluTheme.dark ? Qt.rgba(50/255,50/255,50/255,1) : Qt.rgba(247/255,247/255,247/255,1)
Rectangle{ Rectangle{
border.color: control.borderColor border.color: control.borderColor
@ -474,7 +516,7 @@ Rectangle {
width: 1 width: 1
height: parent.height height: parent.height
anchors.left: parent.left anchors.left: parent.left
visible: column !== 0 visible: column_item_control._index !== 0
color:"#00000000" color:"#00000000"
} }
Rectangle{ Rectangle{
@ -483,7 +525,7 @@ Rectangle {
height: parent.height height: parent.height
anchors.right: parent.right anchors.right: parent.right
color:"#00000000" color:"#00000000"
visible: column === table_view.columns - 1 visible: column_item_control._index === table_view.columns - 1
} }
MouseArea{ MouseArea{
id:column_item_control_mouse id:column_item_control_mouse
@ -505,22 +547,23 @@ Rectangle {
} }
FluLoader{ FluLoader{
id:item_column_loader id:item_column_loader
property var itemModel: model property var model: column_item_control._model
property var modelData: model.display property var display: model.display.title
property var tableView: table_view property var tableView: table_view
property var tableModel: table_model property var sourceModel: control.sourceModel
property bool isObject: typeof(display) == "object"
property var options:{ property var options:{
if(typeof(modelData) == "object"){ if(isObject){
return modelData.options return display.options
} }
return {} return {}
} }
property int column: column_item_control.columnIndex property int column: column_item_control._index
width: parent.width width: parent.width
height: parent.height height: parent.height
sourceComponent: { sourceComponent: {
if(typeof(modelData) == "object"){ if(isObject){
return modelData.comId return display.comId
} }
return com_column_text return com_column_text
} }
@ -532,7 +575,7 @@ Rectangle {
anchors.right: parent.right anchors.right: parent.right
acceptedButtons: Qt.LeftButton acceptedButtons: Qt.LeftButton
hoverEnabled: true hoverEnabled: true
visible: !(columnObject.width === columnObject.minimumWidth && columnObject.width === columnObject.maximumWidth && columnObject.width) visible: !columnModel.frozen && !(columnModel.width === columnModel.minimumWidth && columnModel.width === columnModel.maximumWidth && columnModel.width)
cursorShape: Qt.SplitHCursor cursorShape: Qt.SplitHCursor
preventStealing: true preventStealing: true
onPressed : onPressed :
@ -552,9 +595,9 @@ Rectangle {
return return
} }
var delta = Qt.point(mouse.x - clickPos.x, mouse.y - clickPos.y) var delta = Qt.point(mouse.x - clickPos.x, mouse.y - clickPos.y)
var minimumWidth = columnObject.minimumWidth var minimumWidth = columnModel.minimumWidth
var maximumWidth = columnObject.maximumWidth var maximumWidth = columnModel.maximumWidth
var w = columnObject.width var w = columnModel.width
if(!w){ if(!w){
w = d.defaultItemWidth w = d.defaultItemWidth
} }
@ -564,9 +607,10 @@ Rectangle {
if(!maximumWidth){ if(!maximumWidth){
maximumWidth = 65535 maximumWidth = 65535
} }
columnObject.width = Math.min(Math.max(minimumWidth, w + delta.x),maximumWidth) columnModel.width = Math.min(Math.max(minimumWidth, w + delta.x),maximumWidth)
table_view.forceLayout() table_view.forceLayout()
header_horizontal.forceLayout() header_horizontal.forceLayout()
// column_item_control.currentTableView.forceLayout()
} }
} }
} }
@ -577,7 +621,7 @@ Rectangle {
id:item_control id:item_control
readonly property real cellPadding: 8 readonly property real cellPadding: 8
property bool canceled: false property bool canceled: false
property var rowObject: control.getRow(row) property var rowModel: control.getRow(row)
implicitWidth: Math.max(30, row_text.implicitWidth + (cellPadding * 2)) implicitWidth: Math.max(30, row_text.implicitWidth + (cellPadding * 2))
implicitHeight: row_text.implicitHeight + (cellPadding * 2) implicitHeight: row_text.implicitHeight + (cellPadding * 2)
color: FluTheme.dark ? Qt.rgba(50/255,50/255,50/255,1) : Qt.rgba(247/255,247/255,247/255,1) color: FluTheme.dark ? Qt.rgba(50/255,50/255,50/255,1) : Qt.rgba(247/255,247/255,247/255,1)
@ -643,9 +687,9 @@ Rectangle {
cursorShape: Qt.SplitVCursor cursorShape: Qt.SplitVCursor
preventStealing: true preventStealing: true
visible: { visible: {
if(rowObject === null) if(rowModel === null)
return false return false
return !(rowObject.height === rowObject._minimumHeight && rowObject.height === rowObject._maximumHeight && rowObject.height) return !(rowModel.height === rowModel._minimumHeight && rowModel.height === rowModel._maximumHeight && rowModel.height)
} }
onPressed : onPressed :
(mouse)=>{ (mouse)=>{
@ -663,11 +707,11 @@ Rectangle {
if(!pressed){ if(!pressed){
return return
} }
var rowObject = control.getRow(row) var rowModel = control.getRow(row)
var delta = Qt.point(mouse.x - clickPos.x, mouse.y - clickPos.y) var delta = Qt.point(mouse.x - clickPos.x, mouse.y - clickPos.y)
var minimumHeight = rowObject._minimumHeight var minimumHeight = rowModel._minimumHeight
var maximumHeight = rowObject._maximumHeight var maximumHeight = rowModel._maximumHeight
var h = rowObject.height var h = rowModel.height
if(!h){ if(!h){
h = d.defaultItemHeight h = d.defaultItemHeight
} }
@ -677,8 +721,8 @@ Rectangle {
if(!maximumHeight){ if(!maximumHeight){
maximumHeight = 65535 maximumHeight = 65535
} }
rowObject.height = Math.min(Math.max(minimumHeight, h + delta.y),maximumHeight) rowModel.height = Math.min(Math.max(minimumHeight, h + delta.y),maximumHeight)
control.setRow(row,rowObject) control.setRow(row,rowModel)
table_view.forceLayout() table_view.forceLayout()
} }
} }
@ -688,7 +732,7 @@ Rectangle {
id:com_column_text id:com_column_text
FluText { FluText {
id: column_text id: column_text
text: modelData text: String(display)
anchors.fill: parent anchors.fill: parent
horizontalAlignment: Text.AlignHCenter horizontalAlignment: Text.AlignHCenter
verticalAlignment: Text.AlignVCenter verticalAlignment: Text.AlignVCenter
@ -791,6 +835,124 @@ Rectangle {
} }
} }
} }
Item{
anchors{
left: header_vertical.right
top: parent.top
bottom: parent.bottom
right: parent.right
}
Component{
id: com_table_frozen
Rectangle{
id: item_layout_frozen
anchors.fill: parent
color: {
if(Window.active){
return FluTheme.dark ? Qt.rgba(48/255,48/255,48/255,1) :Qt.rgba(1,1,1,1)
}
return FluTheme.dark ? Qt.rgba(56/255,56/255,56/255,1) :Qt.rgba(243/255,243/255,243/255,1)
}
visible: table_view.rows !== 0
Rectangle{
z:99
anchors.fill: parent
border.color: FluTheme.dark ? Qt.rgba(26/255,26/255,26/255,0.6) : Qt.rgba(191/255,191/255,191/255,0.3)
FluShadow{
radius: 0
anchors.fill: parent
}
color: "#00000000"
}
TableView {
id:item_table_frozen_header
model: header_column_model
boundsBehavior: Flickable.StopAtBounds
clip: true
interactive: false
anchors{
left: parent.left
right: parent.right
top: parent.top
bottom: item_table_frozen.top
}
delegate: com_column_header_delegate
}
TableView{
property string dataIndex: columnModel.dataIndex
id: item_table_frozen
clip: true
interactive: false
anchors{
fill: parent
topMargin: header_horizontal.height
}
boundsBehavior: TableView.StopAtBounds
model: table_sort_model
delegate: com_table_delegate
syncDirection: Qt.Vertical
syncView: table_view
Component.onCompleted: {
item_table_frozen_header.contentX = columnModel.width * _index
item_table_frozen.contentX = columnModel.width * _index
}
}
}
}
Repeater{
model: control.columnSource
delegate: FluLoader{
id: item_layout_frozen
readonly property int _index : model.index
readonly property var columnModel : control.columnSource[_index]
Connections{
target: d
function onTableItemLayout(column){
if(item_layout_frozen._index === column){
updateLayout()
}
}
}
Connections{
target: table_view
function onContentXChanged(){
updateLayout()
}
}
function updateLayout(){
width = table_view.columnWidthProvider(_index)
x = Qt.binding(function(){
var minX = 0
var maxX = table_view.width-item_layout_frozen.width
for(var i=0;i<_index;i++){
var item = control.columnSource[i]
if(item.frozen){
minX = minX + item.width
}
}
for(i=_index+1;i<control.columnSource.length;i++){
item = control.columnSource[i]
if(item.frozen){
maxX = maxX- item.width
}
}
return Math.min(Math.max(columnModel.x - table_view.contentX,minX),maxX)}
)
}
Component.onCompleted: {
updateLayout()
}
height: control.height
visible: {
if(modelData.frozen){
return true
}
return false
}
sourceComponent: visible ? com_table_frozen : undefined
}
}
}
FluScrollBar { FluScrollBar {
id: scroll_bar_h id: scroll_bar_h
anchors{ anchors{
@ -837,7 +999,7 @@ Rectangle {
function sort(callback=undefined){ function sort(callback=undefined){
if(callback){ if(callback){
table_sort_model.setComparator(function(left,right){ table_sort_model.setComparator(function(left,right){
return callback(table_model.getRow(left),table_model.getRow(right)) return callback(sourceModel.getRow(left),sourceModel.getRow(right))
}) })
}else{ }else{
table_sort_model.setComparator(undefined) table_sort_model.setComparator(undefined)
@ -846,7 +1008,7 @@ Rectangle {
function filter(callback=undefined){ function filter(callback=undefined){
if(callback){ if(callback){
table_sort_model.setFilter(function(index){ table_sort_model.setFilter(function(index){
return callback(table_model.getRow(index)) return callback(sourceModel.getRow(index))
}) })
}else{ }else{
table_sort_model.setFilter(undefined) table_sort_model.setFilter(undefined)
@ -868,7 +1030,26 @@ Rectangle {
table_view.model.removeRow(rowIndex,rows) table_view.model.removeRow(rowIndex,rows)
} }
} }
function insertRow(rowIndex,obj){
if(rowIndex>=0 && rowIndex<table_view.rows){
sourceModel.insertRow(rowIndex,obj)
}
}
function currentIndex(){
var index = -1
if(!d.current){
return index
}
for (var i = 0; i <= sourceModel.rowCount-1; i++) {
var sourceItem = sourceModel.getRow(i);
if(sourceItem._key === d.current._key){
index = i
break
}
}
return index
}
function appendRow(obj){ function appendRow(obj){
table_model.appendRow(obj) sourceModel.appendRow(obj)
} }
} }

View File

@ -59,8 +59,9 @@ Window {
signal lazyLoad() signal lazyLoad()
property var _windowRegister property var _windowRegister
property string _route property string _route
id:window property bool _hideShadow: false
color:"transparent" id: window
color: FluTools.isSoftware() ? window.backgroundColor : "transparent"
Component.onCompleted: { Component.onCompleted: {
FluRouter.addWindow(window) FluRouter.addWindow(window)
useSystemAppBar = FluApp.useSystemAppBar useSystemAppBar = FluApp.useSystemAppBar
@ -141,7 +142,7 @@ Window {
} }
Timer{ Timer{
id:timer_update_image id:timer_update_image
interval: 500 interval: 150
onTriggered: { onTriggered: {
img_back.source = "" img_back.source = ""
img_back.source = FluTools.getUrlByFilePath(FluTheme.desktopImagePath) img_back.source = FluTools.getUrlByFilePath(FluTheme.desktopImagePath)
@ -278,13 +279,7 @@ Window {
id:loader_border id:loader_border
anchors.fill: parent anchors.fill: parent
sourceComponent: { sourceComponent: {
if(window.useSystemAppBar){ if(window.useSystemAppBar || FluTools.isWin() || window.visibility === Window.Maximized || window.visibility === Window.FullScreen){
return undefined
}
if(FluTools.isWindows10OrGreater()){
return undefined
}
if(window.visibility === Window.Maximized || window.visibility === Window.FullScreen){
return undefined return undefined
} }
return com_border return com_border
@ -306,7 +301,6 @@ Window {
info_bar.showError(text,duration,moremsg) info_bar.showError(text,duration,moremsg)
} }
function moveWindowToDesktopCenter(){ function moveWindowToDesktopCenter(){
screen = Qt.application.screens[FluTools.cursorScreenIndex()]
var availableGeometry = FluTools.desktopAvailableGeometry(window) var availableGeometry = FluTools.desktopAvailableGeometry(window)
window.setGeometry((availableGeometry.width-window.width)/2+Screen.virtualX,(availableGeometry.height-window.height)/2+Screen.virtualY,window.width,window.height) window.setGeometry((availableGeometry.width-window.width)/2+Screen.virtualX,(availableGeometry.height-window.height)/2+Screen.virtualY,window.width,window.height)
} }