main
zhuzihcu 2023-04-10 18:17:22 +08:00
parent 09e87e0fb8
commit 1f2d0d9b9f
16 changed files with 764 additions and 18 deletions

51
example/T_Settings.qml Normal file
View File

@ -0,0 +1,51 @@
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: 200
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:"Top",mode:FluNavigationView2.Top},{title:"Open",mode:FluNavigationView2.Open},{title:"Compact",mode:FluNavigationView2.Compact},{title:"Minimal",mode:FluNavigationView2.Minimal},{title:"Auto",mode:FluNavigationView2.Auto}]
delegate: FluRadioButton{
selected : MainEvent.displayMode===modelData.mode
text:modelData.title
onClicked:{
MainEvent.displayMode = modelData.mode
console.debug(modelData.mode)
}
}
}
}
}
}

View File

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

View File

@ -308,7 +308,6 @@ FluObject{
if(navigationView.getCurrentIndex() === i){ if(navigationView.getCurrentIndex() === i){
return return
} }
item.tap()
navigationView.setCurrentIndex(i) navigationView.setCurrentIndex(i)
if(item.parent){ if(item.parent){
item.parent.isExpand = true item.parent.isExpand = true

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -520,6 +520,7 @@ Item {
return footerItems.children return footerItems.children
} }
} }
interactive: false
currentIndex: -1 currentIndex: -1
delegate: Loader{ delegate: Loader{
property var model: modelData property var model: modelData

View File

@ -0,0 +1,668 @@
import QtQuick
import QtQuick.Window
import QtQuick.Controls
import QtQuick.Layouts
import FluentUI
Item {
enum DisplayMode {
Open,
Top,
Compact,
Minimal,
Auto
}
property url logo
property string title: ""
property FluObject items
property FluObject footerItems
property int displayMode: FluNavigationView2.Open
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 var stackItems: []
property bool enableNavigationPanel: false
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: layout_list.width
height: {
if(model.parent){
return model.parent.isExpand ? 1 : 0
}
return 1
}
Behavior on height {
NumberAnimation{
duration: 150
}
}
}
}
Component{
id:com_panel_item_header
Item{
height: {
if(model.parent){
return model.parent.isExpand ? 30 : 0
}
return 30
}
Behavior on height {
NumberAnimation{
duration: 150
}
}
width: layout_list.width
FluText{
text:model.title
fontStyle: FluText.BodyStrong
anchors{
bottom: parent.bottom
left:parent.left
leftMargin: 10
}
}
}
}
Component{
id:com_panel_item_expander
Item{
height: 38
width: layout_list.width
Rectangle{
radius: 4
anchors{
top: parent.top
bottom: parent.bottom
left: parent.left
right: parent.right
topMargin: 2
bottomMargin: 2
leftMargin: 6
rightMargin: 6
}
Rectangle{
width: 3
height: 18
radius: 1.5
color: FluTheme.primaryColor.dark
visible: {
for(var i=0;i<model.children.length;i++){
var item = model.children[i]
if(item.idx === nav_list.currentIndex && !model.isExpand){
return true
}
}
return false
}
anchors{
verticalCenter: parent.verticalCenter
}
}
FluIcon{
rotation: model.isExpand?0:180
iconSource:FluentIcons.ChevronUp
iconSize: 15
anchors{
verticalCenter: parent.verticalCenter
right: parent.right
rightMargin: 12
}
visible: {
if(displayMode === FluNavigationView2.Compact){
return false
}
return true
}
Behavior on rotation {
NumberAnimation{
duration: 150
}
}
}
MouseArea{
id:item_mouse
hoverEnabled: true
anchors.fill: parent
onClicked: {
if(displayMode === FluNavigationView2.Compact){
return
}
model.isExpand = !model.isExpand
}
}
color: {
if(FluTheme.dark){
if((nav_list.currentIndex === idx)&&type===0){
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 === idx&&type===0){
return Qt.rgba(0,0,0,0.06)
}
if(item_mouse.containsMouse){
return Qt.rgba(0,0,0,0.03)
}
return Qt.rgba(0,0,0,0)
}
}
FluIcon{
id:item_icon
iconSource: {
if(model.icon){
return model.icon
}
return 0
}
width: 30
height: 30
iconSize: 15
anchors{
verticalCenter: parent.verticalCenter
left:parent.left
leftMargin: 3
}
}
FluText{
id:item_title
text:model.title
visible: {
if(displayMode === FluNavigationView2.Compact){
return false
}
return true
}
anchors{
verticalCenter: parent.verticalCenter
left:item_icon.right
}
color:{
if(item_mouse.pressed){
return FluTheme.dark ? FluColors.Grey80 : FluColors.Grey120
}
return FluTheme.dark ? FluColors.White : FluColors.Grey220
}
}
}
}
}
Component{
id:com_panel_item
Item{
Behavior on height {
NumberAnimation{
duration: 150
}
}
clip: true
height: {
if(model.parent){
return model.parent.isExpand ? 38 : 0
}
return 38
}
width: layout_list.width
Rectangle{
radius: 4
anchors{
top: parent.top
bottom: parent.bottom
left: parent.left
right: parent.right
topMargin: 2
bottomMargin: 2
leftMargin: 6
rightMargin: 6
}
MouseArea{
id:item_mouse
hoverEnabled: true
anchors.fill: parent
onClicked: {
if(type === 0){
if(model.tapFunc){
model.tapFunc()
}else{
nav_list.currentIndex = idx
layout_footer.currentIndex = -1
}
}else{
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
}
}
}
}
color: {
if(FluTheme.dark){
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(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)
}
return Qt.rgba(0,0,0,0)
}
}
FluIcon{
id:item_icon
iconSource: {
if(model.icon){
return model.icon
}
return 0
}
width: 30
height: 30
iconSize: 15
anchors{
verticalCenter: parent.verticalCenter
left:parent.left
leftMargin: 3
}
}
FluText{
id:item_title
text:model.title
visible: {
if(displayMode === FluNavigationView2.Compact){
return false
}
return true
}
color:{
if(item_mouse.pressed){
return FluTheme.dark ? FluColors.Grey80 : FluColors.Grey120
}
return FluTheme.dark ? FluColors.White : FluColors.Grey220
}
anchors{
verticalCenter: parent.verticalCenter
left:item_icon.right
}
}
}
}
}
Item {
id:nav_app_bar
width: parent.width
height: 50
z:999
RowLayout{
height:parent.height
spacing: 0
FluIconButton{
iconSource: FluentIcons.ChromeBack
Layout.leftMargin: 5
Layout.preferredWidth: 40
Layout.preferredHeight: 40
Layout.alignment: Qt.AlignVCenter
disabled: nav_swipe.depth === 1
iconSize: 13
onClicked: {
nav_swipe.pop()
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{
id:btn_nav
iconSource: FluentIcons.GlobalNavButton
iconSize: 15
Layout.preferredWidth: 40
Layout.preferredHeight: 40
visible: displayMode === FluNavigationView2.Minimal
Layout.alignment: Qt.AlignVCenter
onClicked: {
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
}
return 5
}
Layout.alignment: Qt.AlignVCenter
}
FluText{
Layout.alignment: Qt.AlignVCenter
text:control.title
Layout.leftMargin: 12
fontStyle: FluText.Body
}
}
}
Item{
anchors{
left: displayMode === FluNavigationView2.Minimal ? parent.left : layout_list.right
top: nav_app_bar.bottom
right: parent.right
bottom: parent.bottom
}
StackView{
id:nav_swipe
anchors.fill: parent
clip: true
popEnter : Transition{}
popExit : Transition {
NumberAnimation { properties: "y"; from: 0; to: nav_swipe.height; duration: 200 }
}
pushEnter: Transition {
NumberAnimation { properties: "y"; from: nav_swipe.height; to: 0; duration: 200 }
}
pushExit : Transition{}
replaceEnter : Transition{}
replaceExit : Transition{}
}
}
MouseArea{
anchors.fill: parent
enabled: (displayMode === FluNavigationView2.Minimal && d.enableNavigationPanel)
onClicked: {
d.enableNavigationPanel = false
}
}
Rectangle{
id:layout_list
width: {
if(displayMode === FluNavigationView2.Compact){
return 50
}
return 300
}
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 === FluNavigationView2.Minimal ? 1 : 0
color: {
if(displayMode === FluNavigationView2.Minimal){
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){
return FluTheme.dark ? Qt.rgba(32/255,32/255,32/255,1) : Qt.rgba(238/255,244/255,249/255,1)
}
return FluTheme.dark ? Qt.rgba(32/255,32/255,32/255,1) : Qt.rgba(243/255,243/255,243/255,1)
}
Behavior on color{
ColorAnimation {
duration: 300
}
}
x: {
if(displayMode !== FluNavigationView2.Minimal)
return 0
return (displayMode === FluNavigationView2.Minimal && d.enableNavigationPanel) ? 0 : -width
}
Item{
id:layout_header
width: layout_list.width
clip: true
y:nav_app_bar.height
height: 38
Loader{
id:loader_auto_suggest_box
anchors.centerIn: parent
sourceComponent: autoSuggestBox
visible: {
if(displayMode === FluNavigationView2.Compact){
return false
}
return true
}
}
FluIconButton{
visible:displayMode === FluNavigationView2.Compact
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
}
}
}
ListView{
id:nav_list
clip: true
ScrollBar.vertical: FluScrollBar {}
model:d.handleItems()
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
}
}
}
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 idx: index
property int type: 0
sourceComponent: {
if(modelData instanceof FluPaneItem){
return com_panel_item
}
if(modelData instanceof FluPaneItemHeader){
return com_panel_item_header
}
if(modelData instanceof FluPaneItemSeparator){
return com_panel_item_separatorr
}
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
}
}
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 idx: index
property int type: 1
sourceComponent: {
if(modelData instanceof FluPaneItem){
return com_panel_item
}
if(modelData instanceof FluPaneItemHeader){
return com_panel_item_header
}
if(modelData instanceof FluPaneItemSeparator){
return com_panel_item_separatorr
}
}
}
}
}
function setCurrentIndex(index){
nav_list.currentIndex = index
}
function getItems(){
return nav_list.model
}
function push(url){
nav_swipe.push(url)
}
function getCurrentIndex(){
return nav_list.currentIndex
}
}

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 import FluentUI
FluObject { FluObject {
readonly property int flag : 3
readonly property string key : FluApp.uuid() readonly property string key : FluApp.uuid()
property string title property string title
property int icon property int icon
property bool isExpand: false property bool isExpand: false
property var parent property var parent
property int idx property int idx
signal tap
} }

View File

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

View File

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

View File

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