Compare commits

...

17 Commits
1.2.1 ... 1.2.3

Author SHA1 Message Date
3a46fd11c6 update 2023-04-10 22:07:30 +08:00
70f048f629 update 2023-04-10 22:05:20 +08:00
1f2d0d9b9f update 2023-04-10 18:17:22 +08:00
09e87e0fb8 update 2023-04-09 19:29:50 +08:00
0603a7603d update 2023-04-09 18:08:37 +08:00
d9a4f01e20 update 2023-04-09 17:59:00 +08:00
93709cd1dd update 2023-04-08 21:23:03 +08:00
0000e557a7 update 2023-04-08 20:44:27 +08:00
d2183e350e update 2023-04-08 20:26:49 +08:00
47caf4bb52 update 2023-04-08 20:20:44 +08:00
6fb9ee41fb update 2023-04-08 20:12:28 +08:00
b349c22434 update 2023-04-08 20:08:26 +08:00
12fa3487bb Merge pull request #29 from LiangLiang723/win32_cmake_fix
🐛 修复 windows 下生成 dll 库带 linux 前缀导致查找不到控件
2023-04-08 19:57:14 +08:00
a76806645a 🐛 修复 windows 下生成 dll 库带 linux 前缀导致查找不到控件 2023-04-08 19:45:39 +08:00
738db25c2c Merge pull request #28 from LiangLiang723/win32_cmake_fix
🐛 修复 windows 下生成 dll 库带 linux 前缀导致查找不到控件
2023-04-08 19:43:35 +08:00
9f8a5f5646 🐛 修复 windows 下生成 dll 库带 linux 前缀导致查找不到控件 2023-04-08 19:32:35 +08:00
c59c07e756 update 2023-04-07 20:48:04 +08:00
40 changed files with 786 additions and 201 deletions

View File

@ -38,7 +38,7 @@ jobs:
arch: ${{ matrix.qt_arch }}
modules: 'qt5compat qtmultimedia qtshadertools qtimageformats'
- name: ubuntu install GL library
run: sudo apt-get install -y libglew-dev libglfw3-dev qml-module-qtquick-controls qml-module-qtquick-controls2
run: sudo apt-get install -y libxkbcommon-x11-dev libxcb-icccm4-dev libxcb-image0-dev libxcb-keysyms1-dev libxcb-randr0-dev libxcb-shape0-dev libxcb-xfixes0-dev libxcb-xinerama0-dev libxcb-sync-dev libxcb-render-util0-dev libxcb-shm0-dev
- uses: actions/checkout@v2
with:
fetch-depth: 1

View File

@ -62,6 +62,12 @@
|FluDatePicker|日期选择器||
|FluMenu|菜单Popup||
|FluNavigationView|响应式导航布局||
|FluScrollbar|滚动条||
|FluToggleButton|开关按钮||
|FluPagination|分页组件||
|FluTableView|表格组件||
|FluMediaPlayer|播放器||
|FluFlipView|FlipView||
# 部分效果预览
@ -77,6 +83,10 @@
![](doc/preview/theme.png)
## TableView表格组件
![](doc/preview/tableview.png)
## FluTreeView树组件
![](doc/preview/treeview.png)
@ -85,13 +95,5 @@
![](doc/preview/carousel.png)
## InfoBar提示框组件
![](doc/preview/infobar.png)
## 多窗口路由跳转
![](doc/preview/multiwindow.png)
### ⚡ Visitor count
![](https://profile-counter.glitch.me/zhuzichu520-FluentUI/count.svg)

Binary file not shown.

Before

Width:  |  Height:  |  Size: 103 KiB

After

Width:  |  Height:  |  Size: 46 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 383 KiB

After

Width:  |  Height:  |  Size: 204 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 382 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 204 KiB

After

Width:  |  Height:  |  Size: 218 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 89 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 103 KiB

BIN
doc/preview/tableview.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 71 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 73 KiB

After

Width:  |  Height:  |  Size: 35 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 101 KiB

After

Width:  |  Height:  |  Size: 49 KiB

View File

@ -7,6 +7,8 @@ set(CMAKE_AUTOUIC ON)
set(CMAKE_CXX_STANDARD 17)
file(TO_CMAKE_PATH "/" PATH_SEPARATOR)
if(CMAKE_SIZEOF_VOID_P EQUAL 8)
set(platform 64)
else()
@ -44,20 +46,17 @@ add_executable(${PROJECT_NAME} ${SOURCES} ${HEADERS} ${QT_RESOURCES} ${RC_ICONS}
if(WIN32)
if(CMAKE_C_COMPILER_ID STREQUAL "MSVC")
file(GLOB DLL_FILES ${CMAKE_CURRENT_SOURCE_DIR}/../third/msvc/*.dll)
add_custom_command(TARGET ${PROJECT_NAME} POST_BUILD
COMMAND ${CMAKE_COMMAND} -E copy
${DLL_FILES}
${CMAKE_RUNTIME_OUTPUT_DIRECTORY}
)
set(DLLPATH ${CMAKE_CURRENT_SOURCE_DIR}/../third/msvc/*.dll)
else()
file(GLOB DLL_FILES ${CMAKE_CURRENT_SOURCE_DIR}/../third/mingw/*.dll)
add_custom_command(TARGET ${PROJECT_NAME} POST_BUILD
COMMAND ${CMAKE_COMMAND} -E copy
${DLL_FILES}
${CMAKE_RUNTIME_OUTPUT_DIRECTORY}
)
set(DLLPATH ${CMAKE_CURRENT_SOURCE_DIR}/../third/mingw/*.dll)
endif()
string(REPLACE "/" ${PATH_SEPARATOR} DLLPATH "${DLLPATH}")
file(GLOB DLL_FILES ${DLLPATH})
add_custom_command(TARGET ${PROJECT_NAME} POST_BUILD
COMMAND ${CMAKE_COMMAND} -E copy
${DLL_FILES}
${CMAKE_RUNTIME_OUTPUT_DIRECTORY}
)
endif()
target_compile_definitions(${PROJECT_NAME} PRIVATE

View File

@ -52,12 +52,12 @@ FluScrollablePage{
}
CodeExpander{
Layout.fillWidth: true
code:' showInfo("这是一个Info样式的InfoBar")
code:'showInfo("这是一个Info样式的InfoBar")
showWarning("这是一个Warning样式的InfoBar")
showWarning("这是一个Warning样式的InfoBar")
showError("这是一个Error样式的InfoBar")
showError("这是一个Error样式的InfoBar")
showSuccess("这是一个Success样式的InfoBar这是一个Success样式的InfoBar")'
showSuccess("这是一个Success样式的InfoBar这是一个Success样式的InfoBar")'
}
}

50
example/T_Settings.qml Normal file
View File

@ -0,0 +1,50 @@
import QtQuick
import QtQuick.Layouts
import QtQuick.Window
import QtQuick.Controls
import FluentUI
import "qrc:///global/"
import "./component"
FluScrollablePage{
title:"Settings"
leftPadding:10
rightPadding:10
bottomPadding:20
spacing: 0
FluArea{
Layout.fillWidth: true
Layout.topMargin: 20
height: 168
paddings: 10
ColumnLayout{
spacing: 10
anchors{
verticalCenter: parent.verticalCenter
left: parent.left
}
FluText{
text:"NavigationView Display Mode"
fontStyle: FluText.BodyStrong
Layout.bottomMargin: 4
}
Repeater{
id:repeater
model: [{title:"Open",mode:FluNavigationView.Open},{title:"Compact",mode:FluNavigationView.Compact},{title:"Minimal",mode:FluNavigationView.Minimal},{title:"Auto",mode:FluNavigationView.Auto}]
delegate: FluRadioButton{
selected : MainEvent.displayMode===modelData.mode
text:modelData.title
onClicked:{
MainEvent.displayMode = modelData.mode
}
}
}
}
}
}

91
example/T_StatusView.qml Normal file
View File

@ -0,0 +1,91 @@
import QtQuick
import QtQuick.Layouts
import QtQuick.Controls
import QtQuick.Window
import FluentUI
import "./component"
FluScrollablePage{
title:"StatusView"
leftPadding:10
rightPadding:10
bottomPadding:20
spacing: 0
FluArea{
id:layout_actions
Layout.fillWidth: true
Layout.topMargin: 20
height: 50
paddings: 10
RowLayout{
spacing: 14
FluDropDownButton{
id:btn_status_mode
Layout.preferredWidth: 140
text:"Loading"
items:[
FluMenuItem{
text:"Loading"
onClicked: {
btn_status_mode.text = text
status_view.statusMode = FluStatusView.Loading
}
},
FluMenuItem{
text:"Empty"
onClicked: {
btn_status_mode.text = text
status_view.statusMode = FluStatusView.Empty
}
},
FluMenuItem{
text:"Error"
onClicked: {
btn_status_mode.text = text
status_view.statusMode = FluStatusView.Error
}
},
FluMenuItem{
text:"Success"
onClicked: {
btn_status_mode.text = text
status_view.statusMode = FluStatusView.Success
}
}
]
}
}
}
FluArea{
Layout.fillWidth: true
Layout.topMargin: 10
height: 380
paddings: 10
FluStatusView{
id:status_view
anchors.fill: parent
onErrorClicked:{
showError("点击重新加载")
}
Rectangle {
anchors.fill: parent
color:FluTheme.primaryColor.dark
}
}
}
CodeExpander{
Layout.fillWidth: true
code:'FluStatusView{
anchors.fill: parent
statusMode: FluStatusView.Loading
Rectangle{
anchors.fill: parent
color:FluTheme.primaryColor.dark
}
}'
}
}

View File

@ -45,12 +45,10 @@ FluScrollablePage{
loadData(1,10)
}
FluTableView{
id:table_view
Layout.fillWidth: true
Layout.topMargin: 20
width:parent.width
pageCurrent:1
pageCount:10
itemCount: 1000
@ -102,9 +100,61 @@ FluScrollablePage{
action:com_action
})
}
table_view.dataSource = dataSource
}
CodeExpander{
Layout.fillWidth: true
Layout.topMargin: 10
code:'FluTableView{
id:table_view
Layout.fillWidth: true
Layout.topMargin: 20
width:parent.width
pageCurrent:1
pageCount:10
itemCount: 1000
onRequestPage:
(page,count)=> {
loadData(page,count)
}
Component.onCompleted: {
const columns = [
{
title: "姓名",
dataIndex: "name",
width:100
},
{
title: "年龄",
dataIndex: "age",
width:100
},
{
title: "住址",
dataIndex: "address",
width:200
},
{
title: "别名",
dataIndex: "nickname",
width:100
}
];
table_view.columns = columns
const dataSource = [
{
name: "孙悟空”,
age: 500,
address:"钟灵毓秀的花果山,如神仙仙境的水帘洞",
nickname:"齐天大圣"
}
];
table_view.dataSource = columns
}
}'
}
}

View File

@ -113,7 +113,12 @@ FluExpander{
"FluTooltip",
"FluTreeView",
"FluWindow",
"FluWindowResize"
"FluWindowResize",
"FluToggleButton",
"FluTableView",
"FluColors",
"FluTheme",
"FluStatusView"
];
code = code.replace(/\n/g, "<br>");
code = code.replace(/ /g, "&nbsp;");

View File

@ -5,17 +5,22 @@ import FluentUI
FluObject{
id:footer_items
property var navigationView
FluPaneItemSeparator{}
FluPaneItem{
title:"意见反馈"
onTap:{
Qt.openUrlExternally("https://github.com/zhuzichu520/FluentUI/issues/new")
}
}
FluPaneItem{
title:"关于"
onTap:{
title:"About"
icon:FluentIcons.Contact
tapFunc:function(){
FluApp.navigate("/about")
}
}
FluPaneItem{
title:"Settings"
icon:FluentIcons.Settings
onTap:{
navigationView.push("qrc:/T_Settings.qml")
}
}
}

View File

@ -118,6 +118,12 @@ FluObject{
navigationView.push("qrc:/T_Rectangle.qml")
}
}
FluPaneItem{
title:"StatusView"
onTap:{
navigationView.push("qrc:/T_StatusView.qml")
}
}
FluPaneItem{
title:"Carousel"
onTap:{
@ -302,7 +308,6 @@ FluObject{
if(navigationView.getCurrentIndex() === i){
return
}
item.tap()
navigationView.setCurrentIndex(i)
if(item.parent){
item.parent.isExpand = true

View File

@ -0,0 +1,10 @@
pragma Singleton
import QtQuick
import FluentUI
QtObject {
property int displayMode : FluNavigationView.Auto
}

View File

@ -1,2 +1,3 @@
singleton ItemsOriginal 1.0 ItemsOriginal.qml
singleton ItemsFooter 1.0 ItemsFooter.qml
singleton MainEvent 1.0 MainEvent.qml

View File

@ -36,7 +36,7 @@ FluWindow {
fontStyle: FluText.Title
}
FluText{
text:"v1.2.1"
text:"v1.2.3"
fontStyle: FluText.Body
Layout.alignment: Qt.AlignBottom
}

View File

@ -15,9 +15,10 @@ FluWindow {
FluAppBar{
id:appbar
z:10
z:9
showDark: true
width:parent.width
darkText: "Dark Mode"
}
FluNavigationView{
@ -25,15 +26,16 @@ FluWindow {
anchors.fill: parent
items: ItemsOriginal
footerItems:ItemsFooter
z:11
displayMode:MainEvent.displayMode
logo: "qrc:/res/image/favicon.ico"
z: 11
title:"FluentUI"
autoSuggestBox:FluAutoSuggestBox{
width: 280
anchors.centerIn: parent
iconSource: FluentIcons.Zoom
iconSource: FluentIcons.Search
items: ItemsOriginal.getSearchData()
placeholderText: "查找"
placeholderText: "Search"
onItemClicked:
(data)=>{
ItemsOriginal.startPageByItem(data)
@ -41,8 +43,8 @@ FluWindow {
}
Component.onCompleted: {
ItemsOriginal.navigationView = nav_view
ItemsFooter.navigationView = nav_view
nav_view.setCurrentIndex(0)
nav_view.push("qrc:/T_Home.qml")
}
}

View File

@ -157,5 +157,8 @@
<file>T_Pivot.qml</file>
<file>component/CodeExpander.qml</file>
<file>T_TableView.qml</file>
<file>T_StatusView.qml</file>
<file>T_Settings.qml</file>
<file>global/MainEvent.qml</file>
</qresource>
</RCC>

View File

@ -10,6 +10,10 @@ set(QT_INSTALL_QML ${Qt6Core_DIR}/../../../qml)
set(TARGET_TYPE SHARED)
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin/FluentUI)
if(WIN32)
set(CMAKE_SHARED_LIBRARY_PREFIX "")
endif()
set(TARGET_RESOURCES res.qrc)
set(TARGET_SOURCES
Def.cpp

View File

@ -33,6 +33,8 @@ void Fluent::registerTypes(const char *uri){
qmlRegisterType<WindowHelper>(uri,major,minor,"WindowHelper");
qmlRegisterType<FluColorSet>(uri,major,minor,"FluColorSet");
qmlRegisterType(QUrl("qrc:/com.zhuzichu/controls/FluStatusView.qml"),uri,major,minor,"FluStatusView");
qmlRegisterType(QUrl("qrc:/com.zhuzichu/controls/FluPagination.qml"),uri,major,minor,"FluPagination");
qmlRegisterType(QUrl("qrc:/com.zhuzichu/controls/FluToggleButton.qml"),uri,major,minor,"FluToggleButton");
qmlRegisterType(QUrl("qrc:/com.zhuzichu/controls/FluTableView.qml"),uri,major,minor,"FluTableView");
qmlRegisterType(QUrl("qrc:/com.zhuzichu/controls/FluPivotItem.qml"),uri,major,minor,"FluPivotItem");

View File

@ -5,6 +5,7 @@ import FluentUI
FluTextBox{
property var items:[]
property string emptyText: "没有找到结果"
property int autoSuggestBoxReplacement: FluentIcons.Search
signal itemClicked(var data)
signal handleClicked
QtObject{

View File

@ -48,6 +48,5 @@ FluControl {
return Qt.rgba(1,1,1,1)
}
}
font.pixelSize: 14
}
}

View File

@ -6,48 +6,112 @@ import FluentUI
Item {
property alias logo : image_logo.source
property string title: ""
property FluObject items
property FluObject footerItems
property int displayMode: width<=700 ? FluNavigationView.Minimal : FluNavigationView.Open
property bool displaMinimalMenu : false
property Component autoSuggestBox
id:root
onDisplayModeChanged: {
if(displayMode === FluNavigationView.Minimal){
anim_navi.enabled = false
displaMinimalMenu = false
timer_anim_enable.restart()
}
}
Timer{
id:timer_anim_enable
interval: 150
onTriggered: {
anim_navi.enabled = true
}
}
enum DisplayMode {
Minimal,
Open,
Compact,
Minimal,
Auto
}
property url logo
property string title: ""
property FluObject items
property FluObject footerItems
property int displayMode: FluNavigationView.Auto
property Component autoSuggestBox
property var window : {
if(Window.window == null)
return null
return Window.window
}
id:control
QtObject{
id:d
property bool enableStack: true
property int displayMode: {
if(control.displayMode !==FluNavigationView.Auto){
return control.displayMode
}
if(control.width<=700){
return FluNavigationView.Minimal
}else if(control.width<=900){
return FluNavigationView.Compact
}else{
return FluNavigationView.Open
}
}
property var stackItems: []
property bool enableNavigationPanel: false
property bool isCompact: d.displayMode === FluNavigationView.Compact
property bool isMinimal: d.displayMode === FluNavigationView.Minimal
property bool isCompactAndPanel: d.displayMode === FluNavigationView.Compact && d.enableNavigationPanel
property bool isCompactAndNotPanel:d.displayMode === FluNavigationView.Compact && !d.enableNavigationPanel
property bool isMinimalAndPanel: d.displayMode === FluNavigationView.Minimal && d.enableNavigationPanel
onIsCompactAndNotPanelChanged: {
collapseAll()
}
onDisplayModeChanged: {
if(d.displayMode === FluNavigationView.Compact){
collapseAll()
}
if(d.displayMode === FluNavigationView.Minimal){
anim_layout_list_x.enabled = false
d.enableNavigationPanel = false
timer_anim_x_enable.restart()
}
}
function handleItems(){
var idx = 0
var data = []
if(items){
for(var i=0;i<items.children.length;i++){
var item = items.children[i]
item.idx = idx
data.push(item)
idx++
if(item instanceof FluPaneItemExpander){
for(var j=0;j<item.children.length;j++){
var itemChild = item.children[j]
itemChild.parent = item
itemChild.idx = idx
data.push(itemChild)
idx++
}
}
}
if(footerItems){
var comEmpty = Qt.createComponent("FluPaneItemEmpty.qml");
for(var k=0;k<footerItems.children.length;k++){
var itemFooter = footerItems.children[k]
if (comEmpty.status === Component.Ready) {
var objEmpty = comEmpty.createObject(items,{idx:idx});
itemFooter.idx = idx;
data.push(objEmpty)
idx++
}
}
}
}
return data
}
}
Component{
id:com_panel_item_empty
Item{
visible: false
}
}
Component{
id:com_panel_item_separatorr
FluDivider{
width: nav_list.width
width: layout_list.width
height: {
if(model.parent){
return model.parent.isExpand ? 1 : 0
@ -76,7 +140,7 @@ Item {
duration: 150
}
}
width: nav_list.width
width: layout_list.width
FluText{
text:model.title
fontStyle: FluText.BodyStrong
@ -93,8 +157,7 @@ Item {
id:com_panel_item_expander
Item{
height: 38
width: nav_list.width
width: layout_list.width
Rectangle{
radius: 4
anchors{
@ -134,6 +197,18 @@ Item {
right: parent.right
rightMargin: 12
}
opacity: {
if(d.isCompactAndNotPanel){
return false
}
return true
}
visible:opacity
Behavior on opacity {
NumberAnimation{
duration: 220
}
}
Behavior on rotation {
NumberAnimation{
duration: 150
@ -145,12 +220,16 @@ Item {
hoverEnabled: true
anchors.fill: parent
onClicked: {
if(d.isCompactAndNotPanel){
control_popup.showPopup(Qt.point(50,mapToItem(control,0,0).y),model.children)
return
}
model.isExpand = !model.isExpand
}
}
color: {
if(FluTheme.dark){
if((nav_list.currentIndex === position)&&type===0){
if((nav_list.currentIndex === idx)&&type===0){
return Qt.rgba(1,1,1,0.06)
}
if(item_mouse.containsMouse){
@ -158,7 +237,7 @@ Item {
}
return Qt.rgba(0,0,0,0)
}else{
if(nav_list.currentIndex === position&&type===0){
if(nav_list.currentIndex === idx&&type===0){
return Qt.rgba(0,0,0,0.06)
}
if(item_mouse.containsMouse){
@ -167,7 +246,6 @@ Item {
return Qt.rgba(0,0,0,0)
}
}
FluIcon{
id:item_icon
iconSource: {
@ -185,10 +263,21 @@ Item {
leftMargin: 3
}
}
FluText{
id:item_title
text:model.title
opacity: {
if(d.isCompactAndNotPanel){
return false
}
return true
}
visible:opacity
Behavior on opacity {
NumberAnimation{
duration: 220
}
}
anchors{
verticalCenter: parent.verticalCenter
left:item_icon.right
@ -219,8 +308,7 @@ Item {
}
return 38
}
width: nav_list.width
width: layout_list.width
Rectangle{
radius: 4
anchors{
@ -238,33 +326,55 @@ Item {
hoverEnabled: true
anchors.fill: parent
onClicked: {
if(type===0){
if(type === 0){
if(model.tapFunc){
model.tapFunc()
return
}
if(nav_list.currentIndex !== position){
nav_list.currentIndex = position
model.tap()
}else{
nav_list.currentIndex = idx
layout_footer.currentIndex = -1
if(d.isMinimal || d.isCompact){
d.enableNavigationPanel = false
}
}
}else{
model.tap()
if(model.tapFunc){
model.tapFunc()
}else{
model.tap()
d.stackItems.push(model)
nav_list.currentIndex = nav_list.count-layout_footer.count+idx
layout_footer.currentIndex = idx
if(d.isMinimal || d.isCompact){
d.enableNavigationPanel = false
}
}
}
displaMinimalMenu = false
}
}
color: {
if(FluTheme.dark){
if((nav_list.currentIndex === position)&&type===0){
return Qt.rgba(1,1,1,0.06)
if(type===0){
if(nav_list.currentIndex === idx){
return Qt.rgba(1,1,1,0.06)
}
}else{
if(nav_list.currentIndex === (nav_list.count-layout_footer.count+idx)){
return Qt.rgba(1,1,1,0.06)
}
}
if(item_mouse.containsMouse){
return Qt.rgba(1,1,1,0.03)
}
return Qt.rgba(0,0,0,0)
}else{
if(nav_list.currentIndex === position&&type===0){
return Qt.rgba(0,0,0,0.06)
if(type===0){
if(nav_list.currentIndex === idx){
return Qt.rgba(0,0,0,0.06)
}
}else{
if(nav_list.currentIndex === (nav_list.count-layout_footer.count+idx)){
return Qt.rgba(0,0,0,0.06)
}
}
if(item_mouse.containsMouse){
return Qt.rgba(0,0,0,0.03)
@ -272,7 +382,6 @@ Item {
return Qt.rgba(0,0,0,0)
}
}
FluIcon{
id:item_icon
iconSource: {
@ -290,10 +399,21 @@ Item {
leftMargin: 3
}
}
FluText{
id:item_title
text:model.title
opacity: {
if(d.isCompactAndNotPanel){
return false
}
return true
}
visible:opacity
Behavior on opacity {
NumberAnimation{
duration: 220
}
}
color:{
if(item_mouse.pressed){
return FluTheme.dark ? FluColors.Grey80 : FluColors.Grey120
@ -309,6 +429,7 @@ Item {
}
}
Item {
id:nav_app_bar
width: parent.width
@ -327,11 +448,17 @@ Item {
iconSize: 13
onClicked: {
nav_swipe.pop()
nav_list.stackIndex.pop()
var index = nav_list.stackIndex[nav_list.stackIndex.length-1]
nav_list.enableStack = false
nav_list.currentIndex = index
nav_list.enableStack = true
d.stackItems.pop()
var item = d.stackItems[d.stackItems.length-1]
d.enableStack = false
if(item.idx<(nav_list.count - layout_footer.count)){
layout_footer.currentIndex = -1
}else{
console.debug(item.idx-(nav_list.count-layout_footer.count))
layout_footer.currentIndex = item.idx-(nav_list.count-layout_footer.count)
}
nav_list.currentIndex = item.idx
d.enableStack = true
}
}
FluIconButton{
@ -340,17 +467,17 @@ Item {
iconSize: 15
Layout.preferredWidth: 40
Layout.preferredHeight: 40
visible: displayMode === FluNavigationView.Minimal
visible: d.isMinimal
Layout.alignment: Qt.AlignVCenter
onClicked: {
displaMinimalMenu = !displaMinimalMenu
d.enableNavigationPanel = !d.enableNavigationPanel
}
}
Image{
id:image_logo
Layout.preferredHeight: 20
Layout.preferredWidth: 20
source: control.logo
Layout.leftMargin: {
if(btn_nav.visible){
return 12
@ -361,7 +488,7 @@ Item {
}
FluText{
Layout.alignment: Qt.AlignVCenter
text:root.title
text:control.title
Layout.leftMargin: 12
fontStyle: FluText.Body
}
@ -370,12 +497,12 @@ Item {
Item{
anchors{
left: displayMode === FluNavigationView.Minimal ? parent.left : layout_list.right
left: d.isMinimal || d.isCompactAndPanel ? parent.left : layout_list.right
top: nav_app_bar.bottom
right: parent.right
bottom: parent.bottom
leftMargin: d.isCompactAndPanel ? 50 : 0
}
StackView{
id:nav_swipe
anchors.fill: parent
@ -395,19 +522,39 @@ Item {
MouseArea{
anchors.fill: parent
enabled: (displayMode === FluNavigationView.Minimal && displaMinimalMenu)
enabled: d.isMinimalAndPanel||d.isCompactAndPanel
onClicked: {
displaMinimalMenu = false
d.enableNavigationPanel = false
}
}
Rectangle{
id:layout_list
width: 300
width: {
if(d.isCompactAndNotPanel){
return 50
}
return 300
}
Behavior on width{
NumberAnimation{
duration: 150
}
}
Behavior on x{
id:anim_layout_list_x
NumberAnimation{
duration: 150
}
}
anchors{
top: parent.top
bottom: parent.bottom
}
border.color: FluTheme.dark ? Qt.rgba(45/255,45/255,45/255,1) : Qt.rgba(226/255,230/255,234/255,1)
border.width: displayMode === FluNavigationView.Minimal ? 1 : 0
border.width: d.isMinimal || d.isCompactAndPanel ? 1 : 0
color: {
if(displayMode === FluNavigationView.Minimal){
if(d.isMinimal || d.isCompactAndPanel){
return FluTheme.dark ? Qt.rgba(61/255,61/255,61/255,1) : Qt.rgba(243/255,243/255,243/255,1)
}
if(window && window.active){
@ -415,64 +562,62 @@ Item {
}
return FluTheme.dark ? Qt.rgba(32/255,32/255,32/255,1) : Qt.rgba(243/255,243/255,243/255,1)
}
anchors{
top: parent.top
bottom: parent.bottom
}
x: {
if(displayMode !== FluNavigationView.Minimal)
return 0
return (displayMode === FluNavigationView.Minimal && displaMinimalMenu) ? 0 : -width
}
Behavior on x{
id:anim_navi
NumberAnimation{
duration: 150
}
}
Behavior on color{
ColorAnimation {
duration: 300
}
}
x: {
if(d.displayMode !== FluNavigationView.Minimal)
return 0
return d.isMinimalAndPanel ? 0 : -width
}
Item{
id:layout_header
width: layout_list.width
clip: true
y:nav_app_bar.height
height: {
if(loader_auto_suggest_box.item){
return loader_auto_suggest_box.item.height
}
return 0
}
height: 38
Loader{
id:loader_auto_suggest_box
anchors.horizontalCenter: parent.horizontalCenter
anchors.centerIn: parent
sourceComponent: autoSuggestBox
visible: {
if(d.isCompactAndNotPanel){
return false
}
return true
}
}
FluIconButton{
visible:d.isCompactAndNotPanel
hoverColor: FluTheme.dark ? Qt.rgba(1,1,1,0.03) : Qt.rgba(0,0,0,0.03)
pressedColor: FluTheme.dark ? Qt.rgba(1,1,1,0.03) : Qt.rgba(0,0,0,0.03)
normalColor: FluTheme.dark ? Qt.rgba(0,0,0,0) : Qt.rgba(0,0,0,0)
width:38
height:34
x:6
y:2
iconSize: 15
iconSource: {
if(loader_auto_suggest_box.item){
return loader_auto_suggest_box.item.autoSuggestBoxReplacement
}
return 0
}
onClicked: {
d.enableNavigationPanel = !d.enableNavigationPanel
}
}
}
ListView{
id:nav_list
property bool enableStack: true
property var stackIndex: []
clip: true
anchors{
top: layout_header.bottom
topMargin: 6
left: parent.left
right: parent.right
bottom: layout_footer.top
}
ScrollBar.vertical: FluScrollBar {}
model:d.handleItems()
highlightMoveDuration: 150
currentIndex: -1
onCurrentIndexChanged: {
if(enableStack){
stackIndex.push(currentIndex)
}
}
highlight: Item{
clip: true
Rectangle{
@ -487,11 +632,26 @@ Item {
}
}
}
ScrollBar.vertical: FluScrollBar {}
model:handleItems()
onCurrentIndexChanged: {
if(d.enableStack){
var item = model[currentIndex]
if(item instanceof FluPaneItem){
item.tap()
d.stackItems.push(item)
}
}
}
currentIndex: -1
anchors{
top: layout_header.bottom
topMargin: 6
left: parent.left
right: parent.right
bottom: layout_footer.top
}
delegate: Loader{
property var model: modelData
property var position: index
property var idx: index
property int type: 0
sourceComponent: {
if(modelData instanceof FluPaneItem){
@ -506,24 +666,43 @@ Item {
if(modelData instanceof FluPaneItemExpander){
return com_panel_item_expander
}
if(modelData instanceof FluPaneItemEmpty){
return com_panel_item_empty
}
}
}
}
ListView{
id:layout_footer
clip: true
width: layout_list.width
height: childrenRect.height
anchors.bottom: parent.bottom
interactive: false
currentIndex: -1
model: {
if(footerItems){
return footerItems.children
}
}
currentIndex: -1
highlightMoveDuration: 150
highlight: Item{
clip: true
Rectangle{
height: 18
radius: 1.5
color: FluTheme.primaryColor.dark
width: 3
anchors{
verticalCenter: parent.verticalCenter
left: parent.left
leftMargin: 6
}
}
}
delegate: Loader{
property var model: modelData
property var position: index
property var idx: index
property int type: 1
sourceComponent: {
if(modelData instanceof FluPaneItem){
@ -540,27 +719,91 @@ Item {
}
}
function handleItems(){
var idx = 0
var data = []
if(items){
for(var i=0;i<items.children.length;i++){
var item = items.children[i]
item.idx = idx
data.push(item)
idx++
if(item instanceof FluPaneItemExpander){
for(var j=0;j<item.children.length;j++){
var itemChild = item.children[j]
itemChild.parent = item
itemChild.idx = idx
data.push(itemChild)
idx++
Popup{
property var childModel
id:control_popup
enter: Transition {
NumberAnimation {
property: "opacity"
from:0
to:1
duration: 150
}
}
background: Rectangle{
width: 160
radius: 4
FluShadow{
radius: 4
}
color: FluTheme.dark ? Qt.rgba(51/255,48/255,48/255,1) : Qt.rgba(248/255,250/255,253/255,1)
height: 38*Math.min(Math.max(list_view.count,1),8)
ListView{
id:list_view
anchors.fill: parent
clip: true
currentIndex: -1
model: control_popup.childModel
ScrollBar.vertical: FluScrollBar {}
delegate:FluControl{
width: 160
padding:10
background: Rectangle{
color: {
if(hovered){
return FluTheme.dark ? Qt.rgba(63/255,60/255,61/255,1) : Qt.rgba(237/255,237/255,242/255,1)
}
return FluTheme.dark ? Qt.rgba(51/255,48/255,48/255,1) : Qt.rgba(0,0,0,0)
}
}
contentItem: FluText{
text:modelData.title
anchors{
verticalCenter: parent.verticalCenter
}
}
onClicked: {
if(modelData.tapFunc){
modelData.tapFunc()
}else{
nav_list.currentIndex = idx
layout_footer.currentIndex = -1
if(d.isMinimal || d.isCompact){
d.enableNavigationPanel = false
}
}
control_popup.close()
}
}
}
}
return data
function showPopup(pos,model){
control_popup.x = pos.x
control_popup.y = pos.y
control_popup.childModel = model
control_popup.open()
}
}
Timer{
id:timer_anim_x_enable
interval: 150
onTriggered: {
anim_layout_list_x.enabled = true
}
}
function collapseAll(){
for(var i=0;i<nav_list.model.length;i++){
var item = nav_list.model[i]
if(item instanceof FluPaneItemExpander){
item.isExpand = false
}
}
}
function setCurrentIndex(index){
nav_list.currentIndex = index
}
function getItems(){
@ -571,10 +814,6 @@ Item {
nav_swipe.push(url)
}
function setCurrentIndex(index){
nav_list.currentIndex = index
}
function getCurrentIndex(){
return nav_list.currentIndex
}

View File

@ -1,4 +1,5 @@
import QtQuick
import QtQuick.Controls
import FluentUI
import QtQuick.Layouts
@ -7,6 +8,8 @@ Item {
signal requestPage(int page,int count)
property string previousText: "<上一页"
property string nextText: "下一页>"
property int pageCurrent: 0
property int itemCount: 0
property int pageCount: itemCount>0?Math.ceil(itemCount/__itemPerPage):0
@ -28,7 +31,7 @@ Item {
FluToggleButton{
visible: control.pageCount>1
disabled: control.pageCurrent<=1
text:"<上一页"
text:control.previousText
onClicked: {
control.calcNewPage(control.pageCurrent-1);
}
@ -76,8 +79,7 @@ Item {
}
FluToggleButton{
property int pageNumber:control.pageCount
visible: control.pageCount>0
enabled: control.pageCurrent>1
visible: control.pageCount>1
selected: pageNumber === control.pageCurrent
text:String(pageNumber)
onClicked: {
@ -88,7 +90,7 @@ Item {
FluToggleButton{
visible: control.pageCount>1
disabled: control.pageCurrent>=control.pageCount
text:"下一页>"
text:control.nextText
onClicked: {
control.calcNewPage(control.pageCurrent+1);
}

View File

@ -0,0 +1,7 @@
import QtQuick
QtObject {
readonly property string key : FluApp.uuid()
property var parent
property int idx
}

View File

@ -2,12 +2,10 @@
import FluentUI
FluObject {
readonly property int flag : 3
readonly property string key : FluApp.uuid()
property string title
property int icon
property bool isExpand: false
property var parent
property int idx
signal tap
}

View File

@ -1,7 +1,6 @@
import QtQuick
QtObject {
readonly property int flag : 1
readonly property string key : FluApp.uuid()
property string title
property var parent

View File

@ -1,7 +1,6 @@
import QtQuick
QtObject {
readonly property int flag : 2
readonly property string key : FluApp.uuid()
property var parent
property int idx

View File

@ -9,14 +9,6 @@ Item{
property bool shadow: true
default property alias contentItem: container.data
Rectangle{
id:container
width: control.width
height: control.height
opacity: 0
color:control.color
}
FluShadow{
anchors.fill: container
radius: control.radius[0]
@ -28,6 +20,14 @@ Item{
}
}
Rectangle{
id:container
width: control.width
height: control.height
opacity: 0
color:control.color
}
Canvas {
id: canvas
anchors.fill: parent

View File

@ -10,7 +10,6 @@ ScrollBar {
property color handlePressColor: Qt.darker(handleNormalColor)
property bool expand: false
implicitWidth: Math.max(implicitBackgroundWidth + leftInset + rightInset,
implicitContentWidth + leftPadding + rightPadding)
implicitHeight: Math.max(implicitBackgroundHeight + topInset + bottomInset,
@ -144,7 +143,7 @@ ScrollBar {
iconSize: 8
anchors.top: parent.top
anchors.topMargin: 4
visible:vertical && expand
visible:vertical && expand && item_react.opacity
onClicked:{
decrease()
}
@ -152,7 +151,7 @@ ScrollBar {
FluIconButton{
id:btn_bottom
iconSource: FluentIcons.CaretSolidDown
visible:vertical && expand
visible:vertical && expand && item_react.opacity
width:10
height:10
iconSize: 8
@ -167,7 +166,7 @@ ScrollBar {
FluIconButton{
id:btn_left
iconSource: FluentIcons.CaretSolidLeft
visible:!vertical && expand
visible:!vertical && expand && item_react.opacity
width:10
height:10
iconSize: 8
@ -182,7 +181,7 @@ ScrollBar {
FluIconButton{
id:btn_right
iconSource: FluentIcons.CaretSolidRight
visible:!vertical && expand
visible:!vertical && expand && item_react.opacity
width:10
height:10
iconSize: 8

View File

@ -0,0 +1,108 @@
import QtQuick
import QtQuick.Controls
import QtQuick.Layouts
import FluentUI
Item{
enum StatusMode {
Loading,
Empty,
Error,
Success
}
default property alias content: container.data
property int statusMode: FluStatusView.Loading
signal errorClicked
Item{
id:container
anchors.fill: parent
visible: statusMode === FluStatusView.Success
}
FluArea{
paddings: 0
border.width: 0
anchors.fill: container
visible: opacity
opacity: statusMode === FluStatusView.Loading
Behavior on opacity {
NumberAnimation { duration: 150 }
}
ColumnLayout{
anchors.centerIn: parent
visible: statusMode === FluStatusView.Loading
FluProgressRing{
indeterminate: true
Layout.alignment: Qt.AlignHCenter
}
FluText{
text:"正在加载..."
Layout.alignment: Qt.AlignHCenter
}
}
}
FluArea{
paddings: 0
border.width: 0
anchors.fill: container
visible: opacity
opacity: statusMode === FluStatusView.Empty
Behavior on opacity {
NumberAnimation { duration: 150 }
}
ColumnLayout{
anchors.centerIn: parent
visible: statusMode === FluStatusView.Empty
FluText{
text:"空空如也"
fontStyle: FluText.BodyStrong
Layout.alignment: Qt.AlignHCenter
}
}
}
FluArea{
paddings: 0
border.width: 0
anchors.fill: container
visible: opacity
opacity: statusMode === FluStatusView.Error
Behavior on opacity {
NumberAnimation { duration: 150 }
}
ColumnLayout{
anchors.centerIn: parent
FluText{
text:"页面出错了..."
fontStyle: FluText.BodyStrong
Layout.alignment: Qt.AlignHCenter
}
FluFilledButton{
id:btn_error
Layout.alignment: Qt.AlignHCenter
text:"重新加载"
onClicked:{
errorClicked.call()
}
}
}
}
function showSuccessView(){
statusMode = FluStatusView.Success
}
function showLoadingView(){
statusMode = FluStatusView.Loading
}
function showEmptyView(){
statusMode = FluStatusView.Empty
}
function showErrorView(){
statusMode = FluStatusView.Error
}
}

View File

@ -6,7 +6,8 @@ FluControl {
property bool disabled: false
property color normalColor: FluTheme.dark ? FluTheme.primaryColor.lighter : FluTheme.primaryColor.dark
property color hoverColor: FluTheme.dark ? Qt.darker(normalColor,1.3) : Qt.lighter(normalColor,1.3)
property color hoverColor: FluTheme.dark ? Qt.darker(normalColor,1.15) : Qt.lighter(normalColor,1.15)
property color pressedColor: FluTheme.dark ? Qt.darker(normalColor,1.3) : Qt.lighter(normalColor,1.3)
property color disableColor: FluTheme.dark ? Qt.rgba(82/255,82/255,82/255,1) : Qt.rgba(199/255,199/255,199/255,1)
property bool textBold: true
@ -36,6 +37,9 @@ FluControl {
if(disabled){
return disableColor
}
if(pressed){
return pressedColor
}
return hovered ? hoverColor :normalColor
}
}

View File

@ -96,6 +96,5 @@ FluControl {
}
}
}
font.pixelSize: 14
}
}

View File

@ -70,5 +70,7 @@
<file>controls/FluTableView.qml</file>
<file>controls/FluPagination.qml</file>
<file>controls/FluToggleButton.qml</file>
<file>controls/FluStatusView.qml</file>
<file>controls/FluPaneItemEmpty.qml</file>
</qresource>
</RCC>