Compare commits

...

40 Commits

Author SHA1 Message Date
d5ca38dec2 update framelesshelper 2023-07-17 10:12:57 +08:00
cb50c31e1e update 2023-07-17 09:25:12 +08:00
561b4ec8c0 update 2023-07-15 00:20:33 +08:00
4df6800ea4 update 2023-07-14 23:56:08 +08:00
1ecc1bd569 update 2023-07-14 18:18:46 +08:00
0810572e27 update 2023-07-14 16:15:25 +08:00
5ac0ba7463 update 2023-07-13 12:18:38 +08:00
596457cf59 Merge branch 'main' of https://github.com/zhuzichu520/FluentUI 2023-07-13 10:21:13 +08:00
8595b2fdec update 2023-07-13 10:20:45 +08:00
2337680aaf Merge pull request #200 from mentalfl0w/dev
Add Svg module to resolve unsupported image format error.
2023-07-12 08:37:49 +08:00
ba06480436 Add Svg module to resolve unsupported image format error. 2023-07-11 23:38:36 +08:00
0d87dadc61 update 2023-07-11 17:16:21 +08:00
7290b98fdb update 2023-07-11 16:43:28 +08:00
78815224fe update 2023-07-11 10:46:57 +08:00
6275c161fe Merge pull request #195 from mentalfl0w/main
Fix the bug of static resources didn't imported by engine.
2023-07-10 21:37:40 +08:00
9f24cdaebd Fix the bug of static resources didn't imported by engine. 2023-07-10 19:09:50 +08:00
e2ff752ed9 Merge pull request #193 from mentalfl0w/main
Add Build static lib option and fix the bug of static lib build.
2023-07-10 09:18:55 +08:00
ea88707366 Add Build static lib option and fix the bug of static lib build. 2023-07-10 00:03:41 +08:00
112bb6e07a update 2023-07-07 17:58:00 +08:00
26ad581072 update 2023-07-07 16:56:29 +08:00
03771cd7c9 update 2023-07-07 16:04:17 +08:00
9223d5f937 update 2023-07-07 11:47:03 +08:00
a273aa4588 Merge branch 'main' of https://github.com/zhuzichu520/FluentUI 2023-07-07 09:04:58 +08:00
fbcb65f549 update 2023-07-07 09:04:43 +08:00
082fd79c51 update 2023-07-06 18:50:15 +08:00
80619f6974 update 2023-07-06 18:17:52 +08:00
ad4d077480 update 2023-07-05 21:34:08 +08:00
ff93a6204a update 2023-07-05 19:18:32 +08:00
5a7dfeea6e update 2023-07-04 22:47:55 +08:00
0240244bba update 2023-07-04 22:39:57 +08:00
887fd2c02b update 2023-07-04 22:38:56 +08:00
e625b91b08 update 2023-07-04 16:08:04 +08:00
a5cf6f734b updatre 2023-07-04 15:45:50 +08:00
414bc14996 updatre 2023-07-04 15:43:29 +08:00
7276eb5f2f update 2023-07-04 15:15:58 +08:00
b6c689e0ec update 2023-07-04 15:09:48 +08:00
a48bc51edc update 2023-07-03 21:25:26 +08:00
b2d0975ed7 update 2023-07-03 18:44:43 +08:00
7dea573069 update 2023-07-03 18:08:25 +08:00
0d4dd483da update 2023-07-03 11:50:26 +08:00
77 changed files with 1246 additions and 682 deletions

View File

@ -4,6 +4,13 @@ project(FluentUI VERSION 0.1 LANGUAGES CXX)
option(FLUENTUI_BUILD_EXAMPLES "Build FluentUI demo applications." ON)
option(FLUENTUI_BUILD_FRAMELESSHEPLER "Build FramelessHelper." ON)
option(FLUENTUI_BUILD_STATIC_LIB "Build static library." OFF)
#设置QML插件输出目录可以通过外部设置如果外部没有设置就默认到<QT_SDK_DIR_PATH>\qml\FluentUI目录下
set(FLUENTUI_QML_PLUGIN_DIRECTORY "" CACHE PATH "Path to FluentUI plugin")
if(NOT FLUENTUI_QML_PLUGIN_DIRECTORY)
set(FLUENTUI_QML_PLUGIN_DIRECTORY ${CMAKE_PREFIX_PATH}/qml/FluentUI)
endif()
add_subdirectory(src)
@ -12,11 +19,15 @@ if (FLUENTUI_BUILD_EXAMPLES)
endif ()
if (FLUENTUI_BUILD_FRAMELESSHEPLER)
add_definitions(-DFRAMELESSHELPER_CORE_NO_DEBUG_OUTPUT)
add_definitions(-DFRAMELESSHELPER_QUICK_NO_DEBUG_OUTPUT)
set(FRAMELESSHELPER_BUILD_STATIC ON)
set(FRAMELESSHELPER_NO_SUMMARY OFF)
set(FRAMELESSHELPER_NO_DEBUG_OUTPUT OFF)
set(FRAMELESSHELPER_BUILD_WIDGETS OFF)
add_subdirectory(framelesshelper)
endif ()
message("------------------------ FluentUI ------------------------")
message("Build FluentUI demo applications.: ${FLUENTUI_BUILD_EXAMPLES}")
message("Build FramelessHelper.: ${FLUENTUI_BUILD_FRAMELESSHEPLER}")
message("Build static library.: ${FLUENTUI_BUILD_STATIC_LIB}")
message("Path to FluentUI plugin.: ${FLUENTUI_QML_PLUGIN_DIRECTORY}")

View File

@ -8,6 +8,11 @@ if(APPLE)
set(CMAKE_OSX_ARCHITECTURES "arm64;x86_64" CACHE STRING "" FORCE)
endif()
#判断FluentUI库类型
if(FLUENTUI_BUILD_STATIC_LIB)
add_definitions(-DFLUENTUI_BUILD_STATIC_LIB)
endif()
#设置可执行文件输出目录
if(CMAKE_BUILD_TYPE STREQUAL "Debug")
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_SOURCE_DIR}/bin/debug)
@ -19,9 +24,9 @@ endif()
file(TO_CMAKE_PATH "/" PATH_SEPARATOR)
#设置版本号
add_definitions(-DVERSION=1,3,7,2)
add_definitions(-DVERSION=1,3,7,4)
find_package(Qt6 REQUIRED COMPONENTS Quick)
find_package(Qt6 REQUIRED COMPONENTS Quick Svg)
if(QT_VERSION VERSION_GREATER_EQUAL "6.3")
qt_standard_project_setup()
@ -98,12 +103,24 @@ set_target_properties(example PROPERTIES
)
#链接库
target_link_libraries(example PRIVATE
Qt6::Quick
fluentuiplugin
FramelessHelper::Core
FramelessHelper::Quick
)
if (FLUENTUI_BUILD_STATIC_LIB)
target_link_libraries(example PRIVATE
Qt6::Quick
Qt::Svg
fluentui
fluentuiplugin
FramelessHelper::Core
FramelessHelper::Quick
)
else()
target_link_libraries(example PRIVATE
Qt6::Quick
Qt::Svg
fluentuiplugin
FramelessHelper::Core
FramelessHelper::Quick
)
endif()
#安装
install(TARGETS example

View File

@ -10,10 +10,12 @@ Window {
Component.onCompleted: {
FluApp.init(app)
FluTheme.darkMode = FluDarkMode.System
FluTheme.enableAnimation = true
FluApp.routes = {
"/":"qrc:/example/qml/window/MainWindow.qml",
"/about":"qrc:/example/qml/window/AboutWindow.qml",
"/login":"qrc:/example/qml/window/LoginWindow.qml",
"/hotload":"qrc:/example/qml/window/HotloadWindow.qml",
"/singleTaskWindow":"qrc:/example/qml/window/SingleTaskWindow.qml",
"/standardWindow":"qrc:/example/qml/window/StandardWindow.qml",
"/singleInstanceWindow":"qrc:/example/qml/window/SingleInstanceWindow.qml"

View File

@ -37,11 +37,6 @@ FluExpander{
rightMargin: 5
topMargin: 5
}
onActiveFocusChanged: {
if(activeFocus){
control.expand = true
}
}
onClicked:{
FluTools.clipText(content.text)
showSuccess("复制成功")

View File

@ -333,6 +333,12 @@ FluObject{
navigationView.push("qrc:/example/qml/page/T_RemoteLoader.qml")
}
}
FluPaneItem{
title:"HotLoader"
tapFunc:function(){
FluApp.navigate("/hotload")
}
}
}
function getRecentlyAddedData(){

View File

@ -33,6 +33,7 @@ FluContentPage {
cellWidth: 80
cellHeight: 80
clip: true
boundsBehavior: GridView.StopAtBounds
model:FluApp.awesomelist()
ScrollBar.vertical: FluScrollBar {}
anchors{

View File

@ -24,6 +24,7 @@ FluScrollablePage{
FluTextButton{
disabled:text_button_switch.checked
text:"Text Button"
contentDescription: "文本按钮"
onClicked: {
showInfo("点击Text Button")
}
@ -222,7 +223,7 @@ FluScrollablePage{
FluMenuItem{
text:"Menu_4"
onClicked: {
console.debug(parent.height)
}
}
}
@ -240,20 +241,18 @@ FluScrollablePage{
Layout.topMargin: -1
code:'FluDropDownButton{
text:"DropDownButton"
items:[
FluMenuItem{
text:"Menu_1"
},
FluMenuItem{
text:"Menu_2"
},
FluMenuItem{
text:"Menu_3"
},
FluMenuItem{
text:"Menu_4"
}
]
FluMenuItem{
text:"Menu_1"
},
FluMenuItem{
text:"Menu_2"
},
FluMenuItem{
text:"Menu_3"
},
FluMenuItem{
text:"Menu_4"
}
}'
}

View File

@ -23,8 +23,6 @@ FluScrollablePage{
text:"此颜色组件是Github上的开源项目"
}
FluTextButton{
leftPadding: 0
rightPadding: 0
text:"https://github.com/rshest/qml-colorpicker"
onClicked: {
Qt.openUrlExternally(text)

View File

@ -46,6 +46,7 @@ FluScrollablePage{
}
FluComboBox {
editable: true
font:FluTextStyle.BodyStrong
model: ListModel {
id: model_2
ListElement { text: "Banana" }

View File

@ -76,7 +76,6 @@ FluScrollablePage{
Image{
source: "qrc:/example/res/image/banner_1.jpg"
asynchronous: true
sourceSize: Qt.size(400,300)
fillMode:Image.PreserveAspectCrop
}
Image{

View File

@ -7,7 +7,8 @@ import FluentUI
FluScrollablePage{
pageMode: FluNavigationView.SingleTask
launchMode: FluPage.SingleTask
animDisabled: true
ListModel{
id:model_header

View File

@ -11,7 +11,7 @@ FluScrollablePage{
FluArea{
Layout.fillWidth: true
height: 300
height: 260
paddings: 10
Layout.topMargin: 20
Column{

View File

@ -12,7 +12,7 @@ FluScrollablePage{
FluArea{
Layout.fillWidth: true
Layout.topMargin: 20
height: 200
height: 240
paddings: 10
ColumnLayout{
spacing: 14
@ -44,6 +44,12 @@ FluScrollablePage{
showSuccess("这是一个Success样式的InfoBar这是一个Success样式的InfoBar")
}
}
FluButton{
text:"Loading"
onClicked: {
showLoading()
}
}
}
}
CodeExpander{

View File

@ -12,32 +12,71 @@ FluScrollablePage{
FluArea{
Layout.fillWidth: true
Layout.topMargin: 20
height: 260
height: 110
paddings: 10
ColumnLayout{
spacing: 20
spacing: 10
anchors{
verticalCenter: parent.verticalCenter
left: parent.left
}
FluText{
text: "indeterminate = true"
}
FluProgressBar{
}
FluProgressRing{
}
}
}
CodeExpander{
Layout.fillWidth: true
Layout.topMargin: -1
code:'FluProgressBar{
}
FluProgressRing{
}
'
}
FluArea{
Layout.fillWidth: true
Layout.topMargin: 20
height: 230
paddings: 10
ColumnLayout{
spacing: 10
anchors{
verticalCenter: parent.verticalCenter
left: parent.left
}
FluText{
text: "indeterminate = false"
}
FluProgressBar{
id:progress_bar
indeterminate: false
progress: slider.value/100
}
FluProgressRing{
id:progress_ring
indeterminate: false
progress: slider.value/100
}
FluProgressBar{
indeterminate: false
progressVisible: true
progress: slider.value/100
}
FluProgressRing{
indeterminate: false
progressVisible: true
progress: slider.value/100
}
FluSlider{
onValueChanged:{
var progress = value/100
progress_bar.progress = progress
progress_ring.progress = progress
}
id:slider
Component.onCompleted: {
value = 50
}
@ -48,22 +87,14 @@ FluScrollablePage{
Layout.fillWidth: true
Layout.topMargin: -1
code:'FluProgressBar{
}
FluProgressRing{
}
FluProgressBar{
indeterminate: false
}
FluProgressRing{
indeterminate: false
}'
progressVisible: true
}
'
}
}

View File

@ -12,7 +12,7 @@ FluScrollablePage{
FluArea{
Layout.fillWidth: true
Layout.topMargin: 20
height: 480
height: 460
paddings: 10
Column{

View File

@ -6,7 +6,7 @@ import FluentUI
import "qrc:///example/qml/component"
FluPage{
pageMode: FluNavigationView.SingleTop
launchMode: FluPage.SingleTop
FluRemoteLoader{
anchors.fill: parent
source: "https://zhu-zichu.gitee.io/T_RemoteLoader.qml"

View File

@ -64,8 +64,8 @@ FluContentPage{
address: getRandomAddresses(),
nickname: getRandomNickname(),
longstring:"你好你好你好你好你好你好你好你好你好你好你好你好你好你好你好你好你好你好你好你好你好你好你好你好你好你好你好你好你好你好你好你好你好你好你好你好你好你好你好你好你好你好你好你好你好你好你好你好你好你好你好你好你好你好你好你好你好你好你好你好你好你好你好你好你好你好你好你好你好你好你好你好你好你好你好你好你好你好你好你好你好",
height:46,
minimumHeight:46,
height:42,
minimumHeight:42,
maximumHeight:300,
action:com_action
})

View File

@ -7,7 +7,7 @@ import "qrc:///example/qml/component"
FluScrollablePage{
pageMode: FluNavigationView.SingleInstance
launchMode: FluPage.SingleInstance
title:"TextBox"
FluArea{

View File

@ -12,7 +12,7 @@ FluScrollablePage{
FluArea{
Layout.fillWidth: true
Layout.topMargin: 20
height: 210
height: 270
paddings: 10
ColumnLayout{
spacing:0
@ -72,6 +72,17 @@ FluScrollablePage{
FluTheme.nativeText = !FluTheme.nativeText
}
}
FluText{
text:"开启动画效果"
Layout.topMargin: 20
}
FluToggleSwitch{
Layout.topMargin: 5
checked: FluTheme.enableAnimation
onClicked: {
FluTheme.enableAnimation = !FluTheme.enableAnimation
}
}
}
}
CodeExpander{

View File

@ -8,7 +8,7 @@ import "qrc:///example/qml/component"
FluScrollablePage{
title:"TimePicker"
launchMode: FluPage.SingleInstance
FluArea{
Layout.fillWidth: true
Layout.topMargin: 20
@ -60,10 +60,10 @@ FluScrollablePage{
}
FluTimePicker{
hourFormat:FluTimePicker.HH
onCurrentChanged: {
showSuccess(current.toLocaleTimeString(Qt.locale("de_DE")))
}
hourFormat:FluTimePicker.HH
onCurrentChanged: {
showSuccess(current.toLocaleTimeString(Qt.locale("de_DE")))
}
}
}

View File

@ -0,0 +1,85 @@
import QtQuick
import QtQuick.Controls
import QtQuick.Layouts
import FluentUI
import example
import "qrc:///example/qml/component"
CustomWindow {
id:window
title:"热加载"
width: 800
height: 600
minimumWidth: 520
minimumHeight: 200
launchMode: FluWindow.SingleTask
FileWatcher{
id:watcher
onFileChanged: {
loader.reload()
}
}
FluArea{
anchors.fill: parent
FluRemoteLoader{
id:loader
anchors.fill: parent
statusMode: FluStatusView.Success
lazy: true
errorItem: Item{
FluText{
text:loader.itemLodaer().sourceComponent.errorString()
color:"red"
anchors.fill: parent
wrapMode: Text.WrapAnywhere
padding: 20
verticalAlignment: Qt.AlignVCenter
horizontalAlignment: Qt.AlignHCenter
}
}
}
FluText{
text:"拖入qml文件"
font.pixelSize: 26
anchors.centerIn: parent
visible: !loader.itemLodaer().item && loader.statusMode === FluStatusView.Success
}
Rectangle{
radius: 4
anchors.fill: parent
color: "#33333333"
visible: drop_area.containsDrag
}
DropArea{
id:drop_area
anchors.fill: parent
onEntered:
(event)=>{
if(!event.hasUrls){
event.accepted = false
return
}
if (event.urls.length !== 1) {
event.accepted = false
return
}
var url = event.urls[0].toString()
var fileExtension = url.substring(url.lastIndexOf(".") + 1)
if (fileExtension !== "qml") {
event.accepted = false
return
}
return true
}
onDropped:
(event)=>{
var path = event.urls[0].toString()
loader.source = path
watcher.path = path
loader.reload()
}
}
}
}

View File

@ -16,15 +16,19 @@ CustomWindow {
height: 640
closeDestory:false
minimumWidth: 520
minimumHeight: 460
minimumHeight: 200
appBarVisible: false
launchMode: FluWindow.SingleTask
closeFunc:function(event){
close_app.open()
dialog_close.open()
event.accepted = false
}
Component.onCompleted: {
FluTools.setQuitOnLastWindowClosed(false)
}
Connections{
target: appInfo
function onActiveWindow(){
@ -59,7 +63,7 @@ CustomWindow {
}
FluContentDialog{
id:close_app
id:dialog_close
title:"退出"
message:"确定要退出程序吗?"
negativeText:"最小化"
@ -95,7 +99,7 @@ CustomWindow {
when: flipable.flipped
}
transitions: Transition {
NumberAnimation { target: flipable; property: "flipAngle"; duration: 1000 ; easing.type: Easing.OutQuad}
NumberAnimation { target: flipable; property: "flipAngle"; duration: 1000 ; easing.type: Easing.OutCubic}
}
back: Item{
anchors.fill: flipable
@ -168,18 +172,16 @@ CustomWindow {
width: parent.width
height: parent.height
z:999
//Stack模式每次切换都会将页面压入栈中随着栈的页面增多消耗的内存也越多内存消耗多就会卡顿这时候就需要按返回将页面pop掉释放内存。该模式可以配合FluPage中的launchMode属性设置页面的启动模式
// pageMode: FluNavigationView.Stack
//NoStack模式每次切换都会销毁之前的页面然后创建一个新的页面只需消耗少量内存推荐
// pageMode: FluNavigationView.NoStack
items: ItemsOriginal
footerItems:ItemsFooter
topPadding:FluTools.isMacos() ? 20 : 5
displayMode:MainEvent.displayMode
logo: "qrc:/example/res/image/favicon.ico"
title:"FluentUI"
Behavior on rotation {
NumberAnimation{
duration: 167
}
}
transformOrigin: Item.Center
onLogoClicked:{
clickCount += 1
if(clickCount === 1){
@ -222,7 +224,7 @@ CustomWindow {
}
function handleDarkChanged(button){
if(FluTools.isMacos()){
if(FluTools.isMacos() || !FluTheme.enableAnimation){
changeDark()
}else{
var target = window.contentItem

View File

@ -5,6 +5,7 @@
CircularReveal::CircularReveal(QQuickItem* parent) : QQuickPaintedItem(parent)
{
setVisible(false);
_anim = new QPropertyAnimation(this, "radius", this);
_anim->setDuration(333);
_anim->setEasingCurve(QEasingCurve::OutCubic);
@ -19,6 +20,7 @@ CircularReveal::CircularReveal(QQuickItem* parent) : QQuickPaintedItem(parent)
void CircularReveal::paint(QPainter* painter)
{
painter->save();
painter->eraseRect(boundingRect());
painter->drawImage(QRect(0, 0, static_cast<int>(width()), static_cast<int>(height())), _source);
QPainterPath path;
path.moveTo(_center.x(),_center.y());

View File

@ -0,0 +1,24 @@
#include "FileWatcher.h"
FileWatcher::FileWatcher(QObject *parent)
: QObject{parent}
{
connect(&_watcher, &QFileSystemWatcher::fileChanged, this, [=](const QString &path){
Q_EMIT fileChanged();
clean();
_watcher.addPath(_path);
});
connect(this,&FileWatcher::pathChanged,this,[=](){
clean();
_watcher.addPath(_path.replace("file:///",""));
});
if(!_path.isEmpty()){
_watcher.addPath(_path);
}
}
void FileWatcher::clean(){
foreach (const QString &item, _watcher.files()) {
_watcher.removePath(item);
}
}

View File

@ -0,0 +1,21 @@
#ifndef FILEWATCHER_H
#define FILEWATCHER_H
#include <QObject>
#include <QFileSystemWatcher>
#include "src/stdafx.h"
class FileWatcher : public QObject
{
Q_OBJECT
Q_PROPERTY_AUTO(QString,path);
public:
explicit FileWatcher(QObject *parent = nullptr);
Q_SIGNAL void fileChanged();
private:
void clean();
private:
QFileSystemWatcher _watcher;
};
#endif // FILEWATCHER_H

View File

@ -7,11 +7,12 @@
#include <FramelessHelper/Quick/framelessquickmodule.h>
#include <FramelessHelper/Core/private/framelessconfig_p.h>
#include "src/component/CircularReveal.h"
#include "src/component/FileWatcher.h"
#include "AppInfo.h"
FRAMELESSHELPER_USE_NAMESPACE
int main(int argc, char *argv[])
int main(int argc, char *argv[])
{
//将样式设置为Basic不然会导致组件显示异常
qputenv("QT_QUICK_CONTROLS_STYLE","Basic");
@ -35,11 +36,13 @@ int main(int argc, char *argv[])
if(!appInfo->isOwnerProcess(&ipc)){
return 0;
}
app.setQuitOnLastWindowClosed(false);
QQmlApplicationEngine engine;
FramelessHelper::Quick::registerTypes(&engine);
#ifdef FLUENTUI_BUILD_STATIC_LIB
engine.addImportPath("qrc:/"); // 让静态资源可以被QML引擎搜索到
#endif
qmlRegisterType<CircularReveal>("example", 1, 0, "CircularReveal");
qmlRegisterType<FileWatcher>("example", 1, 0, "FileWatcher");
appInfo->init(&engine);
const QUrl url(QStringLiteral("qrc:/example/qml/App.qml"));
QObject::connect(&engine, &QQmlApplicationEngine::objectCreated,

View File

@ -1,18 +1,18 @@
cmake_minimum_required(VERSION 3.20)
project(fluentuiplugin LANGUAGES CXX)
if (FLUENTUI_BUILD_STATIC_LIB)
project(fluentui LANGUAGES CXX)
else()
project(fluentuiplugin LANGUAGES CXX)
endif()
#配置通用编译
set(CMAKE_CXX_STANDARD_REQUIRED ON)
if(APPLE)
set(CMAKE_OSX_ARCHITECTURES "arm64;x86_64" CACHE STRING "" FORCE)
endif()
#设置QML插件输出目录->D:\Qt\6.4.3\msvc2019_64\qml\FluentUI
set(QML_PLUGIN_DIRECTORY ${CMAKE_PREFIX_PATH}/qml/FluentUI)
#设置版本号
add_definitions(-DVERSION=1,3,7,2)
add_definitions(-DVERSION=1,3,7,4)
find_package(Qt6 REQUIRED COMPONENTS Core Quick Qml)
@ -39,7 +39,7 @@ foreach(filepath ${QML_PATHS})
endforeach(filepath)
#遍历所有资源文件
file(GLOB_RECURSE RES_PATHS *.png *.jpg *.svg *.ico *.ttf *.webp)
file(GLOB_RECURSE RES_PATHS *.png *.jpg *.svg *.ico *.ttf *.webp qmldir)
foreach(filepath ${RES_PATHS})
string(REPLACE "${CMAKE_CURRENT_SOURCE_DIR}/" "" filename ${filepath})
list(APPEND resource_files ${filename})
@ -52,26 +52,44 @@ foreach(filepath IN LISTS qml_files resource_files)
endforeach()
#添加qml模块
qt_add_library(fluentuiplugin SHARED)
qt_add_qml_module(fluentuiplugin
#没有下面这行代码就会生成fluentuiplugin.dll与fluentuipluginplugin.dll两个动态库
PLUGIN_TARGET fluentuiplugin
OUTPUT_DIRECTORY ${QML_PLUGIN_DIRECTORY}
VERSION 1.0
URI "FluentUI"
#修改qmltypes文件名称。默认fluentuiplugin.qmltypes使用默认名称有时候import FluentUI会爆红所以修改成plugins.qmltypes
TYPEINFO "plugins.qmltypes"
SOURCES ${sources_files} fluentui.rc
QML_FILES ${qml_files}
RESOURCES ${resource_files}
)
if (FLUENTUI_BUILD_STATIC_LIB)
set(LIB_TYPE "STATIC")
else()
set(LIB_TYPE "SHARED")
endif()
qt_add_library(${PROJECT_NAME} ${LIB_TYPE})
if (FLUENTUI_BUILD_STATIC_LIB)
qt_add_qml_module(${PROJECT_NAME}
#在静态库编译中使用PLUGIN_TARGET会导致链接失败
OUTPUT_DIRECTORY ${FLUENTUI_QML_PLUGIN_DIRECTORY}
VERSION 1.0
URI "FluentUI"
TYPEINFO "plugins.qmltypes"
SOURCES ${sources_files} fluentui.rc
QML_FILES ${qml_files}
RESOURCES ${resource_files}
)
else()
qt_add_qml_module(${PROJECT_NAME}
#没有下面这行代码就会生成fluentuiplugin.dll与fluentuipluginplugin.dll两个动态库
PLUGIN_TARGET fluentuiplugin
OUTPUT_DIRECTORY ${FLUENTUI_QML_PLUGIN_DIRECTORY}
VERSION 1.0
URI "FluentUI"
#修改qmltypes文件名称。默认fluentuiplugin.qmltypes使用默认名称有时候import FluentUI会爆红所以修改成plugins.qmltypes
TYPEINFO "plugins.qmltypes"
SOURCES ${sources_files} fluentui.rc
QML_FILES ${qml_files}
RESOURCES ${resource_files}
)
endif()
#链接库
target_link_libraries(fluentuiplugin PUBLIC
target_link_libraries(${PROJECT_NAME} PUBLIC
Qt::CorePrivate
Qt::QuickPrivate
Qt::QmlPrivate
)
#安装
install(DIRECTORY ${QML_PLUGIN_DIRECTORY} DESTINATION ${CMAKE_INSTALL_PREFIX}/imports)
install(DIRECTORY ${FLUENTUI_QML_PLUGIN_DIRECTORY} DESTINATION ${CMAKE_INSTALL_PREFIX}/imports)

View File

@ -7,9 +7,9 @@
namespace Fluent_DarkMode {
Q_NAMESPACE
enum Fluent_DarkModeType {
System = 0x0,
Light = 0x1,
Dark = 0x2,
System = 0x0,
Light = 0x1,
Dark = 0x2,
};
Q_ENUM_NS(Fluent_DarkModeType)
QML_NAMED_ELEMENT(FluDarkMode)

View File

@ -12,7 +12,7 @@ FluTextStyle::FluTextStyle(QObject *parent)
Body(body);
QFont bodyStrong;
bodyStrong.setPixelSize(14);
bodyStrong.setPixelSize(13);
bodyStrong.setBold(true);
BodyStrong(bodyStrong);

View File

@ -31,6 +31,7 @@ FluTheme::FluTheme(QObject *parent)
});
primaryColor(FluColors::getInstance()->Blue());
nativeText(false);
enableAnimation(false);
darkMode(Fluent_DarkMode::Fluent_DarkModeType::Light);
_systemDark = systemDark();
qApp->installEventFilter(this);

View File

@ -32,6 +32,11 @@ class FluTheme : public QObject
*/
Q_PROPERTY_AUTO(bool,nativeText);
/**
* @brief 是否开启动画效果
*/
Q_PROPERTY_AUTO(bool,enableAnimation);
QML_NAMED_ELEMENT(FluTheme)
QML_SINGLETON
private:

View File

@ -19,6 +19,9 @@ Rectangle{
property color closeNormalColor: Qt.rgba(0,0,0,0)
property color closeHoverColor: Qt.rgba(251/255,115/255,115/255,1)
property bool showDark: false
property bool showClose: true
property bool showMinimize: true
property bool showMaximize: true
property bool titleVisible: true
property bool isMac: FluTools.isMacos()
property color borerlessColor : FluTheme.dark ? FluTheme.primaryColor.lighter : FluTheme.primaryColor.dark
@ -96,7 +99,7 @@ Rectangle{
iconSize: 11
text:minimizeText
radius: 0
visible: !isMac
visible: !isMac && showMinimize
iconColor: root.textColor
color: hovered ? minimizeHoverColor : minimizeNormalColor
onClicked: minClickListener()
@ -108,7 +111,7 @@ Rectangle{
iconSource : d.isRestore ? FluentIcons.ChromeRestore : FluentIcons.ChromeMaximize
color: hovered ? maximizeHoverColor : maximizeNormalColor
Layout.alignment: Qt.AlignVCenter
visible: d.resizable && !isMac
visible: d.resizable && !isMac && showMaximize
radius: 0
iconColor: root.textColor
text:d.isRestore?restoreText:maximizeText
@ -122,7 +125,7 @@ Rectangle{
text:closeText
width: 40
height: 30
visible: !isMac
visible: !isMac && showClose
radius: 0
iconSize: 10
iconColor: hovered ? Qt.rgba(1,1,1,1) : root.textColor

View File

@ -22,33 +22,29 @@ FluTextBox{
id:control_popup
y:control.height
focus: false
// modal: true
// Overlay.modal: Item{}
padding: 0
enter: Transition {
NumberAnimation {
property: "opacity"
from:0
to:1
duration: 83
duration: FluTheme.enableAnimation ? 83 : 0
}
}
onVisibleChanged: {
if(visible){
list_view.currentIndex = -1
}
}
background: Rectangle{
id:container
width: control.width
radius: 4
contentItem: FluRectangle{
radius: [4,4,4,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
boundsBehavior: ListView.StopAtBounds
ScrollBar.vertical: FluScrollBar {}
header: Item{
width: control.width
@ -63,53 +59,39 @@ FluTextBox{
}
}
}
delegate:Control{
delegate:FluControl{
id:item_control
height: 38
width: control.width
padding:10
onClicked:{
handleClick(modelData)
}
background: Rectangle{
FluFocusRectangle{
visible: item_control.activeFocus
radius:4
}
color: {
if(list_view.currentIndex === index){
return FluTheme.dark ? Qt.rgba(63/255,60/255,61/255,1) : Qt.rgba(237/255,237/255,242/255,1)
}
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)
}
MouseArea{
id:mouse_area
anchors.fill: parent
Connections{
target: control
function onHandleClicked(){
if((list_view.currentIndex === index)){
handleClick(modelData)
}
}
}
onClicked: handleClick(modelData)
}
Rectangle{
width: 3
color:FluTheme.primaryColor.dark
visible: list_view.currentIndex === index
radius: 3
height: 20
anchors{
left: parent.left
verticalCenter: parent.verticalCenter
}
}
}
contentItem: FluText{
text:modelData.title
anchors{
verticalCenter: parent.verticalCenter
}
leftPadding: 10
rightPadding: 10
verticalAlignment : Qt.AlignVCenter
}
}
}
}
background: Item{
id:container
implicitWidth: control.width
implicitHeight: 38*Math.min(Math.max(list_view.count,1),8)
}
}
onTextChanged: {
loadData()

View File

@ -33,7 +33,7 @@ Item {
properties: "opacity"
from: 1
to: 0
duration: 83
duration: FluTheme.enableAnimation ? 83 : 0
}
}
add: Transition {
@ -41,7 +41,7 @@ Item {
properties: "opacity"
from: 0
to: 1
duration: 83
duration: FluTheme.enableAnimation ? 83 : 0
}
}
delegate: Item{

View File

@ -65,7 +65,7 @@ Rectangle {
property: "opacity"
from:0
to:1
duration: 83
duration: FluTheme.enableAnimation ? 83 : 0
}
}
exit:Transition {
@ -73,7 +73,7 @@ Rectangle {
property: "opacity"
from:1
to:0
duration: 83
duration: FluTheme.enableAnimation ? 83 : 0
}
}
contentItem: Item{

View File

@ -87,6 +87,7 @@ Button {
return normalColor
}
Behavior on color {
enabled: FluTheme.enableAnimation
ColorAnimation{
duration: 83
}
@ -98,6 +99,7 @@ Button {
visible: checked
iconColor: FluTheme.dark ? Qt.rgba(0,0,0,1) : Qt.rgba(1,1,1,1)
Behavior on visible {
enabled: FluTheme.enableAnimation
NumberAnimation{
duration: 83
}

View File

@ -50,7 +50,7 @@ Button{
property: "opacity"
from:0
to:1
duration: 83
duration: FluTheme.enableAnimation ? 83 : 0
}
}
@ -59,7 +59,7 @@ Button{
property: "opacity"
from:1
to:0
duration: 83
duration: FluTheme.enableAnimation ? 83 : 0
}
}
function showPopup() {

View File

@ -16,7 +16,7 @@ ComboBox {
implicitHeight: Math.max(implicitBackgroundHeight + topInset + bottomInset,
implicitContentHeight + topPadding + bottomPadding,
implicitIndicatorHeight + topPadding + bottomPadding)
font: FluTextStyle.Body
leftPadding: padding + (!control.mirrored || !indicator || !indicator.visible ? 0 : indicator.width + spacing)
rightPadding: padding + (control.mirrored || !indicator || !indicator.visible ? 0 : indicator.width + spacing)
enabled: !disabled
@ -24,6 +24,7 @@ ComboBox {
width: ListView.view.width
text: control.textRole ? (Array.isArray(control.model) ? modelData[control.textRole] : model[control.textRole]) : modelData
palette.text: control.palette.text
font: control.font
palette.highlightedText: control.palette.highlightedText
highlighted: control.highlightedIndex === index
hoverEnabled: control.hoverEnabled
@ -39,8 +40,8 @@ ComboBox {
}
contentItem: T.TextField {
property bool disabled: !control.editable
leftPadding: !control.mirrored ? 12 : control.editable && activeFocus ? 3 : 1
rightPadding: control.mirrored ? 12 : control.editable && activeFocus ? 3 : 1
leftPadding: !control.mirrored ? 10 : control.editable && activeFocus ? 3 : 1
rightPadding: control.mirrored ? 10 : control.editable && activeFocus ? 3 : 1
topPadding: 6 - control.padding
bottomPadding: 6 - control.padding
renderType: FluTheme.nativeText ? Text.NativeRendering : Text.QtRendering
@ -49,7 +50,7 @@ ComboBox {
text: control.editable ? control.editText : control.displayText
enabled: control.editable
autoScroll: control.editable
font:FluTextStyle.Body
font:control.font
readOnly: control.down
color: FluTheme.dark ? Qt.rgba(255/255,255/255,255/255,1) : Qt.rgba(27/255,27/255,27/255,1)
inputMethodHints: control.inputMethodHints
@ -113,7 +114,7 @@ ComboBox {
property: "opacity"
from:0
to:1
duration: 83
duration: FluTheme.enableAnimation ? 83 : 0
}
}
exit:Transition {
@ -121,7 +122,7 @@ ComboBox {
property: "opacity"
from:1
to:0
duration: 83
duration: FluTheme.enableAnimation ? 83 : 0
}
}
background:Rectangle{

View File

@ -11,6 +11,7 @@ FluPopup {
property string neutralText: "Neutral"
property string negativeText: "Negative"
property string positiveText: "Positive"
property int delayTime: 100
signal neutralClicked
signal negativeClicked
signal positiveClicked
@ -88,7 +89,8 @@ FluPopup {
text: neutralText
onClicked: {
popup.close()
neutralClicked()
timer_delay.targetFlags = FluContentDialog.NeutralButton
timer_delay.restart()
}
}
FluButton{
@ -99,7 +101,8 @@ FluPopup {
text: negativeText
onClicked: {
popup.close()
negativeClicked()
timer_delay.targetFlags = FluContentDialog.NegativeButton
timer_delay.restart()
}
}
FluFilledButton{
@ -110,10 +113,27 @@ FluPopup {
text: positiveText
onClicked: {
popup.close()
positiveClicked()
timer_delay.targetFlags = FluContentDialog.PositiveButton
timer_delay.restart()
}
}
}
}
}
Timer{
property int targetFlags
id:timer_delay
interval: popup.delayTime
onTriggered: {
if(targetFlags === FluContentDialog.NegativeButton){
negativeClicked()
}
if(targetFlags === FluContentDialog.NeutralButton){
neutralClicked()
}
if(targetFlags === FluContentDialog.PositiveButton){
positiveClicked()
}
}
}
}

View File

@ -101,7 +101,7 @@ Rectangle {
property: "opacity"
from:0
to:1
duration: 83
duration: FluTheme.enableAnimation ? 83 : 0
}
}
exit:Transition {
@ -109,7 +109,7 @@ Rectangle {
property: "opacity"
from:1
to:0
duration: 83
duration: FluTheme.enableAnimation ? 83 : 0
}
}
background:Item{

View File

@ -3,5 +3,5 @@ import QtQuick.Window
import FluentUI
Rectangle {
color: FluTheme.dark ? Qt.rgba(60/255,60/255,60/255,1) : Qt.rgba(210/255,210/255,210/255,1)
color: FluTheme.dark ? Qt.rgba(80/255,80/255,80/255,1) : Qt.rgba(210/255,210/255,210/255,1)
}

View File

@ -75,7 +75,7 @@ Button {
color: control.textColor
}
onClicked: {
if(items && menu.count !==0){
if(menu.count !==0){
var pos = control.mapToItem(null, 0, 0)
var containerHeight = menu.count*36
if(window.height>pos.y+control.height+containerHeight){

View File

@ -9,10 +9,8 @@ Item {
property int contentHeight : 300
default property alias content: container.data
id:control
height: layout_header.height + container.height
width: 400
implicitWidth: width
implicitHeight: height
implicitHeight: Math.max((layout_header.height + container.height),layout_header.height)
implicitWidth: 400
Rectangle{
id:layout_header
width: parent.width
@ -56,31 +54,69 @@ Item {
iconSource:FluentIcons.ChevronUp
iconSize: 15
Behavior on rotation {
enabled: FluTheme.enableAnimation
NumberAnimation{
duration: 167
easing.type: Easing.OutCubic
}
}
}
}
}
Rectangle{
id:container
width: parent.width
clip: true
Item{
anchors{
top: layout_header.bottom
topMargin: -1
left: layout_header.left
}
radius: 4
color: FluTheme.dark ? Qt.rgba(39/255,39/255,39/255,1) : Qt.rgba(251/255,251/255,253/255,1)
border.color: FluTheme.dark ? Qt.rgba(45/255,45/255,45/255,1) : Qt.rgba(226/255,229/255,234/255,1)
height: expand ? contentHeight : 0
Behavior on height {
NumberAnimation{
duration: 167
easing.type: Easing.InCubic
}
width: parent.width
clip: true
visible: contentHeight+container.y !== 0
height: contentHeight+container.y
Rectangle{
id:container
width: parent.width
height: parent.height
radius: 4
color: FluTheme.dark ? Qt.rgba(39/255,39/255,39/255,1) : Qt.rgba(251/255,251/255,253/255,1)
border.color: FluTheme.dark ? Qt.rgba(45/255,45/255,45/255,1) : Qt.rgba(226/255,229/255,234/255,1)
y: -contentHeight
states: [
State{
name:"expand"
when: control.expand
PropertyChanges {
target: container
y:0
}
},
State{
name:"collapsed"
when: !control.expand
PropertyChanges {
target: container
y:-contentHeight
}
}
]
transitions: [
Transition {
to:"expand"
NumberAnimation {
properties: "y"
duration: FluTheme.enableAnimation ? 167 : 0
easing.type: Easing.OutCubic
}
},
Transition {
to:"collapsed"
NumberAnimation {
properties: "y"
duration: FluTheme.enableAnimation ? 167 : 0
easing.type: Easing.OutCubic
}
}
]
}
}
}

View File

@ -2,43 +2,47 @@ import QtQuick
import QtQuick.Controls
import FluentUI
Item {
property alias sourceSize : image.sourceSize
property alias fillMode : image.fillMode
property url source
Image {
property string errorButtonText: "重新加载"
property var status
property var clickErrorListener : function(){
image.source = ""
image.source = control.source
}
property Component errorItem : com_error
property Component loadingItem: com_loading
id: control
Image{
id:image
Loader{
anchors.fill: parent
source: control.source
opacity: control.status === Image.Ready
onStatusChanged:{
control.status = image.status
}
Behavior on opacity {
NumberAnimation{
duration: 83
sourceComponent: {
if(control.status === Image.Loading){
return com_loading
}else if(control.status == Image.Error){
return com_error
}else{
return undefined
}
}
}
Rectangle{
anchors.fill: parent
color: FluTheme.dark ? Qt.rgba(1,1,1,0.03) : Qt.rgba(0,0,0,0.03)
FluProgressRing{
anchors.centerIn: parent
visible: control.status === Image.Loading
Component{
id:com_loading
Rectangle{
color: FluTheme.dark ? Qt.rgba(1,1,1,0.03) : Qt.rgba(0,0,0,0.03)
FluProgressRing{
anchors.centerIn: parent
visible: control.status === Image.Loading
}
}
FluFilledButton{
text: control.errorButtonText
anchors.centerIn: parent
visible: control.status === Image.Error
onClicked: clickErrorListener()
}
Component{
id:com_error
Rectangle{
color: FluTheme.dark ? Qt.rgba(1,1,1,0.03) : Qt.rgba(0,0,0,0.03)
FluFilledButton{
text: control.errorButtonText
anchors.centerIn: parent
visible: control.status === Image.Error
onClicked: clickErrorListener()
}
}
}
}

View File

@ -49,7 +49,11 @@ FluObject {
spacing: 20
width: parent.width
move: Transition {
NumberAnimation { properties: "y"; easing.type: Easing.OutBack; duration: 300 }
NumberAnimation {
properties: "y"
easing.type: Easing.OutCubic
duration: FluTheme.enableAnimation ? 333 : 0
}
}
onChildrenChanged: if(children.length === 0) destroy();
function getLastloader(){
@ -89,9 +93,10 @@ FluObject {
scale: item ? 1 : 0;
asynchronous: true
Behavior on scale {
enabled: FluTheme.enableAnimation
NumberAnimation {
easing.type: Easing.OutBack;
duration: 100
easing.type: Easing.OutCubic
duration: 167
}
}
sourceComponent:itemcomponent ? itemcomponent : mcontrol.fluent_sytle;

View File

@ -31,7 +31,6 @@ Item{
var y = 0;
var w = control.width;
var h = control.height;
ctx.setTransform(1, 0, 0, 1, 0, 0);
ctx.clearRect(0, 0, canvas.width, canvas.height);
ctx.save();
ctx.beginPath();

View File

@ -5,7 +5,7 @@ import QtQuick.Templates as T
import FluentUI
T.Menu {
property bool animEnabled: true
property bool enableAnimation: true
id: control
implicitWidth: Math.max(implicitBackgroundWidth + leftInset + rightInset,
contentWidth + leftPadding + rightPadding)
@ -20,7 +20,7 @@ T.Menu {
property: "opacity"
from:0
to:1
duration: animEnabled ? 83 : 0
duration: FluTheme.enableAnimation && control.enableAnimation ? 83 : 0
}
}
exit:Transition {
@ -28,7 +28,7 @@ T.Menu {
property: "opacity"
from:1
to:0
duration: animEnabled ? 83 : 0
duration: FluTheme.enableAnimation && control.enableAnimation ? 83 : 0
}
}
contentItem: ListView {

View File

@ -23,7 +23,7 @@ TextArea{
font:FluTextStyle.Body
wrapMode: Text.WrapAnywhere
padding: 8
leftPadding: 8
leftPadding: padding+2
renderType: FluTheme.nativeText ? Text.NativeRendering : Text.QtRendering
selectedTextColor: color
selectionColor: Qt.alpha(FluTheme.primaryColor.lightest,0.6)

View File

@ -12,27 +12,27 @@ Item {
Minimal = 2,
Auto = 3
}
enum PageModeFlag{
Standard = 0,
SingleTask = 1,
SingleTop = 2,
SingleInstance = 3
enum PageMode {
Stack = 0,
NoStack = 1
}
property url logo
property string title: ""
property FluObject items
property FluObject footerItems
property bool dontPageAnimation: false
property int displayMode: FluNavigationView.Auto
property Component autoSuggestBox
property Component actionItem
property int topPadding: 0
property int navWidth: 300
property int pageMode: FluNavigationView.Stack
signal logoClicked
id:control
QtObject{
id:d
property bool animDisabled:false
property var stackItems: []
property int displayMode: FluNavigationView.Open
property int displayMode: control.displayMode
property bool enableNavigationPanel: false
property bool isCompact: d.displayMode === FluNavigationView.Compact
property bool isMinimal: d.displayMode === FluNavigationView.Minimal
@ -43,21 +43,21 @@ Item {
collapseAll()
}
function handleItems(){
var idx = 0
var _idx = 0
var data = []
if(items){
for(var i=0;i<items.children.length;i++){
var item = items.children[i]
item.idx = idx
item._idx = _idx
data.push(item)
idx++
_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
itemChild._idx = _idx
data.push(itemChild)
idx++
_idx++
}
}
}
@ -66,10 +66,10 @@ Item {
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;
var objEmpty = comEmpty.createObject(items,{_idx:_idx});
itemFooter._idx = _idx;
data.push(objEmpty)
idx++
_idx++
}
}
}
@ -90,6 +90,14 @@ Item {
return FluNavigationView.Open
}
})
timer_anim_delay.restart()
}
Timer{
id:timer_anim_delay
interval: 200
onTriggered: {
d.animDisabled = true
}
}
Connections{
target: d
@ -118,11 +126,6 @@ Item {
}
return 1
}
Behavior on height {
NumberAnimation{
duration: 83
}
}
}
}
Component{
@ -135,6 +138,7 @@ Item {
return 30
}
Behavior on height {
enabled: FluTheme.enableAnimation && d.animDisabled
NumberAnimation{
duration: 83
}
@ -201,7 +205,6 @@ Item {
return false
}
}
Rectangle{
radius: 4
anchors.fill: parent
@ -213,7 +216,7 @@ Item {
visible: {
for(var i=0;i<model.children.length;i++){
var item = model.children[i]
if(item.idx === nav_list.currentIndex && !model.isExpand){
if(item._idx === nav_list.currentIndex && !model.isExpand){
return true
}
}
@ -223,7 +226,6 @@ Item {
verticalCenter: parent.verticalCenter
}
}
FluIcon{
id:item_icon_expand
rotation: model.isExpand?0:180
@ -241,14 +243,16 @@ Item {
return true
}
Behavior on rotation {
enabled: FluTheme.enableAnimation && d.animDisabled
NumberAnimation{
duration: 83
duration: 167
easing.type: Easing.OutCubic
}
}
}
color: {
if(FluTheme.dark){
if((nav_list.currentIndex === idx)&&type===0){
if((nav_list.currentIndex === _idx)&&type===0){
return Qt.rgba(1,1,1,0.06)
}
if(item_control.hovered){
@ -256,7 +260,7 @@ Item {
}
return Qt.rgba(0,0,0,0)
}else{
if(nav_list.currentIndex === idx&&type===0){
if(nav_list.currentIndex === _idx&&type===0){
return Qt.rgba(0,0,0,0.06)
}
if(item_control.hovered){
@ -326,6 +330,7 @@ Item {
id:com_panel_item
Item{
Behavior on height {
enabled: FluTheme.enableAnimation && d.animDisabled
NumberAnimation{
duration: 83
}
@ -361,7 +366,7 @@ Item {
if(model.tapFunc){
model.tapFunc()
}else{
nav_list.currentIndex = idx
nav_list.currentIndex = _idx
layout_footer.currentIndex = -1
model.tap()
if(d.isMinimal || d.isCompact){
@ -372,8 +377,8 @@ Item {
if(model.tapFunc){
model.tapFunc()
}else{
nav_list.currentIndex = nav_list.count-layout_footer.count+idx
layout_footer.currentIndex = idx
nav_list.currentIndex = nav_list.count-layout_footer.count+_idx
layout_footer.currentIndex = _idx
model.tap()
if(d.isMinimal || d.isCompact){
d.enableNavigationPanel = false
@ -387,11 +392,11 @@ Item {
color: {
if(FluTheme.dark){
if(type===0){
if(nav_list.currentIndex === idx){
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)){
if(nav_list.currentIndex === (nav_list.count-layout_footer.count+_idx)){
return Qt.rgba(1,1,1,0.06)
}
}
@ -401,11 +406,11 @@ Item {
return Qt.rgba(0,0,0,0)
}else{
if(type===0){
if(nav_list.currentIndex === idx){
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)){
if(nav_list.currentIndex === (nav_list.count-layout_footer.count+_idx)){
return Qt.rgba(0,0,0,0.06)
}
}
@ -515,31 +520,39 @@ Item {
Layout.preferredWidth: 30
Layout.preferredHeight: 30
Layout.alignment: Qt.AlignVCenter
disabled: nav_swipe.depth <= 1
disabled: {
return d.stackItems.length <= 1
}
iconSize: 13
onClicked: {
FluTools.deleteItem(nav_swipe.pop())
d.stackItems.pop()
d.stackItems = d.stackItems.slice(0, -1)
var item = d.stackItems[d.stackItems.length-1]
if(item.idx<(nav_list.count - layout_footer.count)){
if(item._idx<(nav_list.count - layout_footer.count)){
layout_footer.currentIndex = -1
}else{
layout_footer.currentIndex = item.idx-(nav_list.count-layout_footer.count)
layout_footer.currentIndex = item._idx-(nav_list.count-layout_footer.count)
}
nav_list.currentIndex = item.idx
if(nav_swipe.currentItem.pageMode === FluNavigationView.SingleInstance){
var url = nav_swipe.currentItem.url
var pageIndex = -1
for(var i=0;i<nav_swipe2.children.length;i++){
var obj = nav_swipe2.children[i]
if(obj.url === url){
pageIndex = i
break
nav_list.currentIndex = item._idx
if(pageMode === FluNavigationView.Stack){
var nav_stack = loader_content.item.navStack()
var nav_stack2 = loader_content.item.navStack2()
nav_stack.pop()
if(nav_stack.currentItem.launchMode === FluPage.SingleInstance){
var url = nav_stack.currentItem.url
var pageIndex = -1
for(var i=0;i<nav_stack2.children.length;i++){
var obj = nav_stack2.children[i]
if(obj.url === url){
pageIndex = i
break
}
}
if(pageIndex !== -1){
nav_stack2.currentIndex = pageIndex
}
}
if(pageIndex !== -1){
nav_swipe2.currentIndex = pageIndex
}
}else if(pageMode === FluNavigationView.NoStack){
loader_content.setSource(item._ext.url,item._ext.argument)
}
}
}
@ -557,14 +570,16 @@ Item {
visible: opacity
opacity: d.isMinimal
Behavior on opacity{
enabled: FluTheme.enableAnimation && d.animDisabled
NumberAnimation{
duration: 83
}
}
Behavior on Layout.preferredWidth {
enabled: FluTheme.enableAnimation && d.animDisabled
NumberAnimation{
duration: 167
easing.type: Easing.InCubic
easing.type: Easing.OutCubic
}
}
}
@ -611,7 +626,39 @@ Item {
}
}
}
Item{
Component{
id:com_stack_content
Item{
StackView{
id:nav_stack
anchors.fill: parent
clip: true
visible: !nav_stack2.visible
popEnter : Transition{}
popExit : Transition {}
pushEnter: Transition {}
pushExit : Transition{}
replaceEnter : Transition{}
replaceExit : Transition{}
}
StackLayout{
id:nav_stack2
anchors.fill: nav_stack
clip: true
visible: nav_stack.currentItem?.launchMode === FluPage.SingleInstance
}
function navStack(){
return nav_stack
}
function navStack2(){
return nav_stack2
}
}
}
Loader{
id:loader_content
anchors{
left: parent.left
top: nav_app_bar.bottom
@ -624,33 +671,17 @@ Item {
if(d.isCompact){
return 50
}
return 300
return control.navWidth
}
}
Behavior on anchors.leftMargin {
enabled: FluTheme.enableAnimation && d.animDisabled
NumberAnimation{
duration: 167
easing.type: Easing.InCubic
easing.type: Easing.OutCubic
}
}
StackView{
id:nav_swipe
anchors.fill: parent
clip: true
visible: !nav_swipe2.visible
popEnter : Transition{}
popExit : Transition {}
pushEnter: Transition {}
pushExit : Transition{}
replaceEnter : Transition{}
replaceExit : Transition{}
}
StackLayout{
id:nav_swipe2
anchors.fill: nav_swipe
clip: true
visible: nav_swipe.currentItem.pageMode === FluNavigationView.SingleInstance
}
sourceComponent: com_stack_content
}
MouseArea{
anchors.fill: parent
@ -667,7 +698,7 @@ Item {
if(d.isCompactAndNotPanel){
return 50
}
return 300
return control.navWidth
}
anchors{
top: parent.top
@ -683,15 +714,17 @@ Item {
}
x: visible ? 0 : -width
Behavior on width {
enabled: FluTheme.enableAnimation && d.animDisabled
NumberAnimation{
duration: 167
easing.type: Easing.InCubic
easing.type: Easing.OutCubic
}
}
Behavior on x {
enabled: FluTheme.enableAnimation && d.animDisabled
NumberAnimation{
duration: 167
easing.type: Easing.InCubic
easing.type: Easing.OutCubic
}
}
visible: {
@ -700,7 +733,7 @@ Item {
return d.isMinimalAndPanel ? true : false
}
FluAcrylic {
sourceItem:nav_swipe
sourceItem:loader_content
anchors.fill: layout_list
color: {
if(d.isMinimalAndPanel || d.isCompactAndPanel){
@ -751,27 +784,8 @@ Item {
}
}
}
ListView{
id:nav_list
clip: true
ScrollBar.vertical: FluScrollBar {}
model:d.handleItems()
highlightMoveDuration: 167
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
}
}
}
currentIndex: -1
Flickable{
id:layout_flickable
anchors{
top: layout_header.bottom
topMargin: 6
@ -779,29 +793,58 @@ Item {
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
boundsBehavior: ListView.StopAtBounds
clip: true
contentHeight: nav_list.contentHeight
ScrollBar.vertical: FluScrollBar {}
ListView{
id:nav_list
clip: true
anchors.fill: parent
model:d.handleItems()
boundsBehavior: ListView.StopAtBounds
highlightMoveDuration: FluTheme.enableAnimation && d.animDisabled ? 167 : 0
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
}
}
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
}
currentIndex: -1
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
@ -809,6 +852,7 @@ Item {
height: childrenRect.height
anchors.bottom: parent.bottom
interactive: false
boundsBehavior: ListView.StopAtBounds
currentIndex: -1
model: {
if(footerItems){
@ -832,7 +876,7 @@ Item {
}
delegate: Loader{
property var model: modelData
property var idx: index
property var _idx: index
property int type: 1
sourceComponent: {
if(modelData instanceof FluPaneItem){
@ -931,7 +975,7 @@ Item {
modelData.tapFunc()
}else{
modelData.tap()
nav_list.currentIndex = idx
nav_list.currentIndex = _idx
layout_footer.currentIndex = -1
if(d.isMinimal || d.isCompact){
d.enableNavigationPanel = false
@ -961,7 +1005,7 @@ Item {
Component{
id:com_placeholder
Item{
property int pageMode: FluNavigationView.SingleInstance
property int launchMode: FluPage.SingleInstance
property string url
}
}
@ -983,68 +1027,90 @@ Item {
function getItems(){
return nav_list.model
}
function push(url,argument={}){
var page = nav_swipe.find(function(item) {
return item.url === url;
})
if(page){
switch(page.pageMode)
{
case FluNavigationView.SingleTask:
while(nav_swipe.currentItem !== page)
{
FluTools.deleteItem(nav_swipe.pop())
d.stackItems.pop()
}
return
case FluNavigationView.SingleTop:
if (nav_swipe.currentItem.url === url){
return
}
break
case FluNavigationView.Standard:
default:
}
}
var pageIndex = -1
for(var i=0;i<nav_swipe2.children.length;i++){
var item = nav_swipe2.children[i]
if(item.url === url){
pageIndex = i
break
}
}
var options = Object.assign(argument,{url:url})
if(pageIndex!==-1){
nav_swipe2.currentIndex = pageIndex
nav_swipe.push(com_placeholder,options)
}else{
var comp = Qt.createComponent(url)
if (comp.status === Component.Ready) {
var obj = comp.createObject(nav_swipe,options)
if(obj.pageMode === FluNavigationView.SingleInstance){
nav_swipe.push(com_placeholder,options)
nav_swipe2.children.push(obj)
nav_swipe2.currentIndex = nav_swipe2.count - 1
}else{
nav_swipe.push(obj)
}
}else{
console.error(comp.errorString())
}
}
d.stackItems.push(nav_list.model[nav_list.currentIndex])
}
function getCurrentIndex(){
return nav_list.currentIndex
}
function getCurrentUrl(){
if(nav_swipe.currentItem){
return nav_swipe.currentItem.url
if(pageMode === FluNavigationView.Stack){
var nav_stack = loader_content.item.navStack()
if(nav_stack.currentItem){
return nav_stack.currentItem.url
}
}else if(pageMode === FluNavigationView.NoStack){
return loader_content.source.toString()
}
return undefined
}
function push(url,argument={}){
function stackPush(){
var nav_stack = loader_content.item.navStack()
var nav_stack2 = loader_content.item.navStack2()
var page = nav_stack.find(function(item) {
return item.url === url;
})
if(page){
switch(page.launchMode)
{
case FluPage.SingleTask:
while(nav_stack.currentItem !== page)
{
nav_stack.pop()
d.stackItems = d.stackItems.slice(0, -1)
}
return
case FluPage.SingleTop:
if (nav_stack.currentItem.url === url){
return
}
break
case FluPage.Standard:
default:
}
}
var pageIndex = -1
for(var i=0;i<nav_stack2.children.length;i++){
var item = nav_stack2.children[i]
if(item.url === url){
pageIndex = i
break
}
}
var options = Object.assign(argument,{url:url})
if(pageIndex!==-1){
nav_stack2.currentIndex = pageIndex
nav_stack.push(com_placeholder,options)
}else{
var comp = Qt.createComponent(url)
if (comp.status === Component.Ready) {
var obj = comp.createObject(nav_stack,options)
if(obj.launchMode === FluPage.SingleInstance){
nav_stack.push(com_placeholder,options)
nav_stack2.children.push(obj)
nav_stack2.currentIndex = nav_stack2.count - 1
}else{
nav_stack.push(obj)
}
}else{
console.error(comp.errorString())
}
}
d.stackItems = d.stackItems.concat(nav_list.model[nav_list.currentIndex])
}
function noStackPush(){
if(loader_content.source.toString() === url){
return
}
loader_content.setSource(url,argument)
var obj = nav_list.model[nav_list.currentIndex]
obj._ext = {url:url,argument:argument}
d.stackItems = d.stackItems.concat(obj)
}
if(pageMode === FluNavigationView.Stack){
stackPush()
}else if(pageMode === FluNavigationView.NoStack){
noStackPush()
}
}
function startPageByItem(data){
var items = getItems()
for(var i=0;i<items.length;i++){

View File

@ -5,14 +5,33 @@ import QtQuick.Window
import FluentUI
Item {
property int pageMode: FluNavigationView.SingleTop
enum LaunchMode{
Standard = 0,
SingleTask = 1,
SingleTop = 2,
SingleInstance = 3
}
property int launchMode: FluPage.SingleTop
property bool animDisabled: false
property string url : ""
id: control
opacity: visible
visible: false
StackView.onRemoved: destroy()
Behavior on opacity{
enabled: !animDisabled && FluTheme.enableAnimation
NumberAnimation{
duration: 83
duration: 167
}
}
transform: Translate {
y: control.visible ? 0 : 80
Behavior on y{
enabled: !animDisabled && FluTheme.enableAnimation
NumberAnimation{
duration: 167
easing.type: Easing.OutCubic
}
}
}
Component.onCompleted: {

View File

@ -4,7 +4,8 @@ import FluentUI
QtObject {
readonly property string key : FluTools.uuid()
readonly property int flag : 0
property int _idx
property var _ext
property string title
property int order : 0
property int icon
@ -15,7 +16,6 @@ QtObject {
property string desc
property var image
property var parent
property int idx
property int count: 0
signal tap
property var tapFunc

View File

@ -4,6 +4,7 @@ import FluentUI
QtObject {
readonly property string key : FluTools.uuid()
property int _idx
property var _ext
property var parent
property int idx
}

View File

@ -4,10 +4,10 @@ import FluentUI
FluObject {
readonly property string key : FluTools.uuid()
property int _idx
property string title
property var icon
property Component cusIcon
property bool isExpand: false
property var parent
property int idx
}

View File

@ -4,7 +4,7 @@ import FluentUI
QtObject {
readonly property string key : FluTools.uuid()
property int _idx
property string title
property var parent
property int idx
}

View File

@ -4,6 +4,6 @@ import FluentUI
QtObject {
readonly property string key : FluTools.uuid()
property int _idx
property var parent
property int idx
}

View File

@ -23,7 +23,7 @@ TextField{
}
font:FluTextStyle.Body
padding: 8
leftPadding: 8
leftPadding: padding+2
echoMode:btn_reveal.pressed ? TextField.Normal : TextField.Password
renderType: FluTheme.nativeText ? Text.NativeRendering : Text.QtRendering
selectionColor: Qt.alpha(FluTheme.primaryColor.lightest,0.6)

View File

@ -28,7 +28,7 @@ Item {
spacing: 20
interactive: false
orientation: ListView.Horizontal
highlightMoveDuration: 167
highlightMoveDuration: FluTheme.enableAnimation ? 167 : 0
highlight: Item{
clip: true
Rectangle{
@ -38,9 +38,10 @@ Item {
width: nav_list.currentItem ? nav_list.currentItem.width : 0
y:37
Behavior on width {
enabled: FluTheme.enableAnimation
NumberAnimation{
duration: 167
easing.type: Easing.InCubic
easing.type: Easing.OutCubic
}
}
}

View File

@ -20,11 +20,12 @@ Popup {
properties: "scale"
from:1.2
to:1
duration: 83
duration: FluTheme.enableAnimation ? 83 : 0
easing.type: Easing.OutCubic
}
NumberAnimation {
property: "opacity"
duration: 83
duration: FluTheme.enableAnimation ? 83 : 0
from:0
to:1
}
@ -34,11 +35,12 @@ Popup {
properties: "scale"
from:1
to:1.2
duration: 83
duration: FluTheme.enableAnimation ? 83 : 0
easing.type: Easing.OutCubic
}
NumberAnimation {
property: "opacity"
duration: 83
duration: FluTheme.enableAnimation ? 83 : 0
from:1
to:0
}

View File

@ -2,44 +2,67 @@ import QtQuick
import QtQuick.Controls
import FluentUI
FluRectangle {
Item{
property real progress: 0.5
property bool indeterminate: true
property bool progressVisible: false
id: control
width: 150
height: 5
radius: [3,3,3,3]
clip: true
color: FluTheme.dark ? Qt.rgba(99/255,99/255,99/255,1) : Qt.rgba(214/255,214/255,214/255,1)
Component.onCompleted: {
if(indeterminate){
bar.x = -control.width*0.5
behavior.enabled = true
bar.x = control.width
}else{
bar.x = 0
FluRectangle {
shadow: false
radius: [3,3,3,3]
anchors.fill: parent
color: FluTheme.dark ? Qt.rgba(99/255,99/255,99/255,1) : Qt.rgba(214/255,214/255,214/255,1)
Component.onCompleted: {
if(indeterminate){
bar.x = -control.width*0.5
behavior.enabled = true
bar.x = control.width
}else{
bar.x = 0
}
}
}
Rectangle{
id:bar
radius: 3
width: control.width*progress
height: control.height
color:FluTheme.dark ? FluTheme.primaryColor.lighter : FluTheme.primaryColor.dark
Behavior on x{
id:behavior
enabled: false
NumberAnimation{
duration: 1000
onRunningChanged: {
if(!running){
behavior.enabled = false
bar.x = -control.width*0.5
behavior.enabled = true
bar.x = control.width
Rectangle{
id:bar
radius: 3
width: control.width*progress
height: control.height
color:FluTheme.dark ? FluTheme.primaryColor.lighter : FluTheme.primaryColor.dark
Behavior on x{
id:behavior
enabled: false
NumberAnimation{
duration: 1000
onRunningChanged: {
if(!running){
behavior.enabled = false
bar.x = -control.width*0.5
behavior.enabled = true
bar.x = control.width
}
}
}
}
}
}
FluText{
text:(control.progress * 100).toFixed(0) + "%"
font.pixelSize: 10
visible: {
if(control.indeterminate){
return false
}
return control.progressVisible
}
anchors{
left: parent.left
leftMargin: control.width+5
verticalCenter: parent.verticalCenter
}
}
}

View File

@ -3,11 +3,11 @@ import QtQuick.Controls
import FluentUI
Rectangle {
property real linWidth : width/8
property real linWidth : 5
property real progress: 0.25
property bool indeterminate: true
readonly property real radius2 : radius - linWidth/2
property color primaryColor : FluTheme.dark ? FluTheme.primaryColor.lighter : FluTheme.primaryColor.dark
property bool progressVisible: false
id: control
width: 44
height: 44
@ -24,6 +24,10 @@ Rectangle {
control.rotation = 360
}
}
QtObject{
id:d
property real _radius: control.radius-control.linWidth/2
}
Connections{
target: FluTheme
function onDarkChanged(){
@ -35,8 +39,6 @@ Rectangle {
enabled: false
NumberAnimation{
duration: 999
easing.type: Easing.BezierSpline
easing.bezierCurve: [0.55,0.55,0,1]
onRunningChanged: {
if(!running){
behavior.enabled = false
@ -53,18 +55,28 @@ Rectangle {
antialiasing: true
renderTarget: Canvas.Image
onPaint: {
var ctx = canvas.getContext("2d");
ctx.setTransform(1, 0, 0, 1, 0, 0);
ctx.clearRect(0, 0, canvas.width, canvas.height);
ctx.save();
ctx.lineWidth = linWidth;
ctx.strokeStyle = primaryColor;
ctx.fillStyle = primaryColor;
ctx.beginPath();
ctx.arc(width/2, height/2, radius2 ,-0.5 * Math.PI,-0.5 * Math.PI + progress * 2 * Math.PI);
ctx.stroke();
ctx.closePath();
ctx.restore();
var ctx = canvas.getContext("2d")
ctx.clearRect(0, 0, canvas.width, canvas.height)
ctx.save()
ctx.lineWidth = linWidth
ctx.strokeStyle = primaryColor
ctx.fillStyle = primaryColor
ctx.beginPath()
ctx.arc(width/2, height/2, d._radius ,-0.5 * Math.PI,-0.5 * Math.PI + progress * 2 * Math.PI)
ctx.stroke()
ctx.closePath()
ctx.restore()
}
}
FluText{
text:(control.progress * 100).toFixed(0) + "%"
font.pixelSize: 10
visible: {
if(control.indeterminate){
return false
}
return control.progressVisible
}
anchors.centerIn: parent
}
}

View File

@ -62,10 +62,10 @@ Button {
return checked ? 4 : 1
}
Behavior on border.width {
enabled: FluTheme.enableAnimation
NumberAnimation{
duration: 167
easing.type: Easing.BezierSpline
easing.bezierCurve: [ 0, 0, 0, 1 ]
easing.type: Easing.OutCubic
}
}
border.color: {

View File

@ -9,6 +9,15 @@ Item{
property bool shadow: true
default property alias contentItem: container.data
id:control
onWidthChanged: {
canvas.requestPaint()
}
onHeightChanged: {
canvas.requestPaint()
}
onRadiusChanged: {
canvas.requestPaint()
}
FluShadow{
anchors.fill: container
radius: control.radius[0]
@ -36,7 +45,6 @@ Item{
var y = 0;
var w = control.width;
var h = control.height;
ctx.setTransform(1, 0, 0, 1, 0, 0);
ctx.clearRect(0, 0, canvas.width, canvas.height);
ctx.save();
ctx.beginPath();

View File

@ -33,4 +33,7 @@ FluStatusView {
var timestamp = Date.now();
loader.source = control.source+"?"+timestamp
}
function itemLodaer(){
return loader
}
}

View File

@ -41,7 +41,7 @@ T.ScrollBar {
}
states: [
State{
name:"hide"
name:"show"
when: contentItem.collapsed
PropertyChanges {
target: rect_bar
@ -50,8 +50,8 @@ T.ScrollBar {
}
}
,State{
name:"show"
when: !contentItem.expand
name:"hide"
when: !contentItem.collapsed
PropertyChanges {
target: rect_bar
width: vertical ? 2 : parent.width
@ -61,26 +61,24 @@ T.ScrollBar {
]
transitions:[
Transition {
from: "hide"
to: "hide"
SequentialAnimation {
PauseAnimation { duration: 450 }
NumberAnimation {
target: rect_bar
properties: vertical ? "width" : "height"
duration: 167
easing.type: Easing.InCubic
to:2
easing.type: Easing.OutCubic
}
}
}
,Transition {
from: "show"
to: "show"
NumberAnimation {
target: rect_bar
properties: vertical ? "width" : "height"
duration: 167
easing.type: Easing.InCubic
to:6
easing.type: Easing.OutCubic
}
}
]

View File

@ -44,6 +44,7 @@ FluPage {
anchors.right: flickview.right
anchors.rightMargin: 2
}
boundsBehavior: Flickable.StopAtBounds
anchors{
top: text_title.bottom
bottom: parent.bottom

View File

@ -36,8 +36,10 @@ T.Slider {
return control.hovered ? 6/10 : 5/10
}
Behavior on scale {
enabled: FluTheme.enableAnimation
NumberAnimation{
duration: 167
easing.type: Easing.OutCubic
}
}
}

View File

@ -19,77 +19,90 @@ Item{
property string errorButtonText: "重新加载"
property color color: FluTheme.dark ? Window.active ? Qt.rgba(38/255,44/255,54/255,1) : Qt.rgba(39/255,39/255,39/255,1) : Qt.rgba(251/255,251/255,253/255,1)
signal errorClicked
property Component loadingItem : com_loading
property Component emptyItem : com_empty
property Component errorItem : com_error
Item{
id:container
anchors.fill: parent
visible: statusMode === FluStatusView.Success
visible: statusMode===FluStatusView.Success
}
FluArea{
paddings: 0
border.width: 0
anchors.fill: container
visible: opacity
opacity: statusMode === FluStatusView.Loading
Behavior on opacity {
NumberAnimation { duration: 83 }
}
color:control.color
ColumnLayout{
anchors.centerIn: parent
visible: statusMode === FluStatusView.Loading
FluProgressRing{
indeterminate: true
Layout.alignment: Qt.AlignHCenter
Loader{
id:loader
anchors.fill: parent
visible: statusMode!==FluStatusView.Success
sourceComponent: {
if(statusMode === FluStatusView.Loading){
return loadingItem
}
FluText{
text:control.loadingText
Layout.alignment: Qt.AlignHCenter
if(statusMode === FluStatusView.Empty){
return emptyItem
}
if(statusMode === FluStatusView.Error){
return errorItem
}
return undefined
}
}
Component{
id:com_loading
FluArea{
paddings: 0
border.width: 0
radius: 0
color:control.color
ColumnLayout{
anchors.centerIn: parent
FluProgressRing{
indeterminate: true
Layout.alignment: Qt.AlignHCenter
}
FluText{
text:control.loadingText
Layout.alignment: Qt.AlignHCenter
}
}
}
}
FluArea{
paddings: 0
border.width: 0
anchors.fill: container
visible: opacity
color:control.color
opacity: statusMode === FluStatusView.Empty
Behavior on opacity {
NumberAnimation { duration: 83 }
}
ColumnLayout{
anchors.centerIn: parent
visible: statusMode === FluStatusView.Empty
FluText{
text:control.emptyText
font: FluTextStyle.BodyStrong
Layout.alignment: Qt.AlignHCenter
Component {
id:com_empty
FluArea{
paddings: 0
border.width: 0
radius: 0
color:control.color
ColumnLayout{
anchors.centerIn: parent
FluText{
text:control.emptyText
font: FluTextStyle.BodyStrong
Layout.alignment: Qt.AlignHCenter
}
}
}
}
FluArea{
paddings: 0
border.width: 0
anchors.fill: container
visible: opacity
color:control.color
opacity: statusMode === FluStatusView.Error
Behavior on opacity {
NumberAnimation { duration: 83 }
}
ColumnLayout{
anchors.centerIn: parent
FluText{
text:control.errorText
font: FluTextStyle.BodyStrong
Layout.alignment: Qt.AlignHCenter
}
FluFilledButton{
id:btn_error
Layout.alignment: Qt.AlignHCenter
text:control.errorButtonText
onClicked:{
control.errorClicked()
Component{
id:com_error
FluArea{
paddings: 0
border.width: 0
radius: 0
color:control.color
ColumnLayout{
anchors.centerIn: parent
FluText{
text:control.errorText
font: FluTextStyle.BodyStrong
Layout.alignment: Qt.AlignHCenter
}
FluFilledButton{
id:btn_error
Layout.alignment: Qt.AlignHCenter
text:control.errorButtonText
onClicked:{
control.errorClicked()
}
}
}
}

View File

@ -49,6 +49,9 @@ Rectangle {
if(obj){
return obj
}
if(columnSource[column].editMultiline === true){
return com_edit_multiline
}
return com_edit
}
}
@ -63,6 +66,23 @@ Rectangle {
}
Component{
id:com_edit
FluTextBox{
text: display
readOnly: true === columnSource[column].readOnly
Component.onCompleted: {
forceActiveFocus()
selectAll()
}
onCommit: {
if(!readOnly){
display = text
}
tableView.closeEditor()
}
}
}
Component{
id:com_edit_multiline
Item{
anchors.fill: parent
ScrollView{
@ -202,7 +222,7 @@ Rectangle {
implicitWidth: columnSource[column].width
Rectangle{
anchors.fill: parent
visible: item_loader.sourceComponent === null
visible: !item_loader.sourceComponent
color: selected ? control.selectionColor : "#00000000"
}
MouseArea{
@ -212,6 +232,9 @@ Rectangle {
closeEditor()
table_view.interactive = false
}
onCanceled: {
table_view.interactive = true
}
onReleased: {
table_view.interactive = true
}
@ -223,7 +246,7 @@ Rectangle {
}
onClicked:
(event)=>{
item_loader.sourceComponent = null
item_loader.sourceComponent = undefined
if(!(event.modifiers & Qt.ControlModifier)){
selection_model.clear()
}
@ -256,7 +279,7 @@ Rectangle {
property int column
property int row
property var tableView: control
sourceComponent: null
sourceComponent: undefined
onDisplayChanged: {
var obj = table_model.getRow(row)
obj[columnSource[column].dataIndex] = display
@ -270,12 +293,7 @@ Rectangle {
}
SelectionRectangle {
id:selection_rect
target: {
if(item_loader.sourceComponent){
return null
}
return table_view
}
target: table_view
bottomRightHandle:com_handle
topLeftHandle: com_handle
onDraggingChanged: {
@ -298,26 +316,24 @@ Rectangle {
syncView: table_view
boundsBehavior: Flickable.StopAtBounds
clip: true
delegate: FluControl {
delegate: Rectangle {
id:column_item_control
readonly property real cellPadding: 8
property bool canceled: false
readonly property var obj : columnSource[column]
implicitWidth: column_text.implicitWidth + (cellPadding * 2)
implicitHeight: Math.max(header_horizontal.height, column_text.implicitHeight + (cellPadding * 2))
Rectangle{
anchors.fill: parent
color:{
d.selectionFlag
if(column_item_control.pressed){
return control.pressedButtonColor
}
if(selection_model.isColumnSelected(column)){
return control.hoverButtonColor
}
return column_item_control.hovered ? control.hoverButtonColor : FluTheme.dark ? Qt.rgba(50/255,50/255,50/255,1) : Qt.rgba(247/255,247/255,247/255,1)
color:{
d.selectionFlag
if(column_item_control_mouse.pressed){
return control.pressedButtonColor
}
border.color: FluTheme.dark ? "#252525" : "#e4e4e4"
if(selection_model.isColumnSelected(column)){
return control.hoverButtonColor
}
return column_item_control_mouse.containsMouse&&!canceled ? control.hoverButtonColor : FluTheme.dark ? Qt.rgba(50/255,50/255,50/255,1) : Qt.rgba(247/255,247/255,247/255,1)
}
border.color: FluTheme.dark ? "#252525" : "#e4e4e4"
FluText {
id: column_text
text: model.display
@ -330,13 +346,30 @@ Rectangle {
horizontalAlignment: Text.AlignHCenter
verticalAlignment: Text.AlignVCenter
}
onClicked: {
closeEditor()
selection_model.clear()
for(var i=0;i<=table_view.rows;i++){
selection_model.select(table_model.index(i,column),ItemSelectionModel.Select)
MouseArea{
id:column_item_control_mouse
anchors.fill: parent
anchors.rightMargin: 6
hoverEnabled: true
onCanceled: {
column_item_control.canceled = true
}
d.selectionFlag = !d.selectionFlag
onContainsMouseChanged: {
if(!containsMouse){
column_item_control.canceled = false
}
}
onClicked:
(event)=>{
closeEditor()
if(!(event.modifiers & Qt.ControlModifier)){
selection_model.clear()
}
for(var i=0;i<=table_view.rows;i++){
selection_model.select(table_model.index(i,column),ItemSelectionModel.Select)
}
d.selectionFlag = !d.selectionFlag
}
}
MouseArea{
property point clickPos: "0,0"
@ -344,20 +377,28 @@ Rectangle {
width: 6
anchors.right: parent.right
acceptedButtons: Qt.LeftButton
hoverEnabled: true
visible: !(obj.width === obj.minimumWidth && obj.width === obj.maximumWidth)
cursorShape: Qt.SplitHCursor
preventStealing: true
propagateComposedEvents: true
onPressed :
(mouse)=>{
header_horizontal.interactive = false
FluTools.setOverrideCursor(Qt.SplitHCursor)
clickPos = Qt.point(mouse.x, mouse.y)
}
onReleased:{
header_horizontal.interactive = true
FluTools.restoreOverrideCursor()
}
onCanceled: {
header_horizontal.interactive = true
FluTools.restoreOverrideCursor()
}
onPositionChanged:
(mouse)=>{
if(!pressed){
return
}
var delta = Qt.point(mouse.x - clickPos.x, mouse.y - clickPos.y)
var minimumWidth = obj.minimumWidth
var maximumWidth = obj.maximumWidth
@ -391,25 +432,23 @@ Rectangle {
return []
}
}
delegate: FluControl{
delegate: Rectangle{
id:item_control
readonly property real cellPadding: 8
property bool canceled: false
implicitWidth: Math.max(header_vertical.width, row_text.implicitWidth + (cellPadding * 2))
implicitHeight: row_text.implicitHeight + (cellPadding * 2)
Rectangle{
anchors.fill: parent
color: {
d.selectionFlag
if(item_control.pressed){
return control.pressedButtonColor
}
if(selection_model.isRowSelected(row)){
return control.hoverButtonColor
}
return item_control.hovered ? control.hoverButtonColor : FluTheme.dark ? Qt.rgba(50/255,50/255,50/255,1) : Qt.rgba(247/255,247/255,247/255,1)
color: {
d.selectionFlag
if(item_control_mouse.pressed){
return control.pressedButtonColor
}
border.color: FluTheme.dark ? "#252525" : "#e4e4e4"
if(selection_model.isRowSelected(row)){
return control.hoverButtonColor
}
return item_control_mouse.containsMouse&&!canceled ? control.hoverButtonColor : FluTheme.dark ? Qt.rgba(50/255,50/255,50/255,1) : Qt.rgba(247/255,247/255,247/255,1)
}
border.color: FluTheme.dark ? "#252525" : "#e4e4e4"
FluText{
id:row_text
anchors.centerIn: parent
@ -419,13 +458,30 @@ Rectangle {
return selection_model.rowIntersectsSelection(row)
}
}
onClicked: {
closeEditor()
selection_model.clear()
for(var i=0;i<=columnSource.length;i++){
selection_model.select(table_model.index(row,i),ItemSelectionModel.Select)
MouseArea{
id:item_control_mouse
anchors.fill: parent
anchors.bottomMargin: 6
hoverEnabled: true
onCanceled: {
item_control.canceled = true
}
d.selectionFlag = !d.selectionFlag
onContainsMouseChanged: {
if(!containsMouse){
item_control.canceled = false
}
}
onClicked:
(event)=>{
closeEditor()
if(!(event.modifiers & Qt.ControlModifier)){
selection_model.clear()
}
for(var i=0;i<=columnSource.length;i++){
selection_model.select(table_model.index(row,i),ItemSelectionModel.Select)
}
d.selectionFlag = !d.selectionFlag
}
}
MouseArea{
property point clickPos: "0,0"
@ -434,28 +490,35 @@ Rectangle {
anchors.bottom: parent.bottom
acceptedButtons: Qt.LeftButton
cursorShape: Qt.SplitVCursor
preventStealing: true
visible: {
var obj = table_model.getRow(row)
return !(obj.height === obj.minimumHeight && obj.width === obj.maximumHeight)
}
propagateComposedEvents: true
onPressed :
(mouse)=>{
header_vertical.interactive = false
FluTools.setOverrideCursor(Qt.SplitVCursor)
clickPos = Qt.point(mouse.x, mouse.y)
}
onReleased:{
header_vertical.interactive = true
FluTools.restoreOverrideCursor()
}
onCanceled: {
header_vertical.interactive = true
FluTools.restoreOverrideCursor()
}
onPositionChanged:
(mouse)=>{
if(!pressed){
return
}
var obj = table_model.getRow(row)
var delta = Qt.point(mouse.x - clickPos.x, mouse.y - clickPos.y)
var minimumHeight = obj.minimumHeight
var maximumHeight = obj.maximumHeight
if(!minimumHeight){
minimumHeight = 46
minimumHeight = 42
}
if(!maximumHeight){
maximumHeight = 65535

View File

@ -16,7 +16,7 @@ TextField{
id:control
width: 300
padding: 8
leftPadding: 8
leftPadding: padding+2
enabled: !disabled
color: {
if(!enabled){
@ -83,6 +83,7 @@ TextField{
right: parent.right
rightMargin: closeRightMargin
}
contentDescription:"清空"
onClicked:{
control.text = ""
}

View File

@ -47,10 +47,10 @@ Rectangle{
}
}
Behavior on height{
enabled: FluTheme.enableAnimation
NumberAnimation{
duration: 83
easing.type: Easing.BezierSpline
easing.bezierCurve: [ 1, 0, 0, 0 ]
easing.type: Easing.OutCubic
}
}
}

View File

@ -9,7 +9,7 @@ FluMenu{
property string selectAllText : "全选"
property var inputItem
id:menu
animEnabled: false
enableAnimation: false
width: 120
onVisibleChanged: {
inputItem.forceActiveFocus()

View File

@ -106,7 +106,7 @@ Rectangle {
property: "opacity"
from:0
to:1
duration: 83
duration: FluTheme.enableAnimation ? 83 : 0
}
}
exit:Transition {
@ -114,7 +114,7 @@ Rectangle {
property: "opacity"
from:1
to:0
duration: 83
duration: FluTheme.enableAnimation ? 83 : 0
}
}
background:Item{

View File

@ -69,17 +69,11 @@ Button {
return borderNormalColor
}
Rectangle {
width: pressed ? 28 : 20
anchors{
left: checked ? undefined : parent.left
leftMargin: checked ? 20 : 0
right: checked ? parent.right : undefined
rightMargin: checked ? 0: 20
}
width: 20
x:checked ? control_backgound.width-width : 0
height: 20
radius: 10
scale: hovered&enabled ? 7/10 : 6/10
anchors.verticalCenter: parent.verticalCenter
color: {
if(!enabled){
return dotDisableColor
@ -89,28 +83,16 @@ Button {
}
return dotNormalColor
}
Behavior on anchors.leftMargin {
Behavior on x {
enabled: FluTheme.enableAnimation
NumberAnimation {
duration: 167
easing.type: Easing.BezierSpline
easing.bezierCurve: [ 1, 0, 0, 0 ]
}
}
Behavior on anchors.rightMargin {
NumberAnimation {
duration: 167
easing.type: Easing.BezierSpline
easing.bezierCurve: [ 0, 0, 0, 1 ]
}
}
Behavior on width {
NumberAnimation {
duration: 167
easing.type: Easing.OutCubic
}
}
Behavior on scale {
enabled: FluTheme.enableAnimation
NumberAnimation {
duration: 167
easing.type: Easing.OutCubic
}
}
}

View File

@ -105,7 +105,6 @@ Item {
verticalCenter: parent.verticalCenter
}
}
MouseArea{
id:item_layout_mouse
anchors.fill: parent
@ -200,9 +199,7 @@ Item {
FluIconButton{
id:item_layout_expanded
color:"#00000000"
iconSource:item_layout.expanded?FluentIcons.ChevronDown:FluentIcons.ChevronRight
opacity: item_layout.hasChild
iconSize: 15
onClicked: {
if(!item_layout.hasChild){
item_layout_rect.onClickItem()
@ -210,6 +207,18 @@ Item {
}
model.expanded = !model.expanded
}
contentItem: FluIcon{
rotation: item_layout.expanded?0:-90
iconSource:FluentIcons.ChevronDown
iconSize: 15
Behavior on rotation {
enabled: FluTheme.enableAnimation
NumberAnimation{
duration: 167
easing.type: Easing.OutCubic
}
}
}
}
FluText {
text: item_layout.text
@ -250,6 +259,7 @@ Item {
model: tree_model
flickableDirection: Flickable.HorizontalAndVerticalFlick
clip: true
boundsBehavior: ListView.StopAtBounds
ScrollBar.vertical: FluScrollBar {}
ScrollBar.horizontal: FluScrollBar { }
}

View File

@ -16,6 +16,7 @@ Window {
property string route
property var argument:({})
property var pageRegister
property Component loadingItem: com_loading
property var closeFunc: function(event){
if(closeDestory){
deleteWindow()
@ -50,13 +51,65 @@ Window {
anchors.fill: parent
clip: true
}
Loader{
property string loadingText: "加载中..."
property bool cancel: false
id:loader_loading
anchors.fill: container
}
FluInfoBar{
id:infoBar
root: window
}
Component{
id:com_loading
Popup{
id:popup_loading
modal:true
focus: true
anchors.centerIn: Overlay.overlay
closePolicy: {
if(cancel){
return Popup.CloseOnEscape | Popup.CloseOnPressOutside
}
return Popup.NoAutoClose
}
Overlay.modal: Rectangle {
color: "#44000000"
}
onVisibleChanged: {
if(!visible){
loader_loading.sourceComponent = undefined
}
}
visible: true
background: Item{}
contentItem: Item{
ColumnLayout{
spacing: 8
anchors.centerIn: parent
FluProgressRing{
Layout.alignment: Qt.AlignHCenter
}
FluText{
text:loadingText
Layout.alignment: Qt.AlignHCenter
}
}
}
}
}
WindowHelper{
id:helper
}
function showLoading(text = "加载中...",cancel = true){
loader_loading.loadingText = text
loader_loading.cancel = cancel
loader_loading.sourceComponent = com_loading
}
function hideLoading(){
loader_loading.sourceComponent = undefined
}
function showSuccess(text,duration,moremsg){
infoBar.showSuccess(text,duration,moremsg)
}

View File

@ -1,68 +1,83 @@
module FluentUI
FluAppBar 1.0 FluAppBar.qml
FluArea 1.0 FluArea.qml
FluAutoSuggestBox 1.0 FluAutoSuggestBox.qml
FluBadge 1.0 FluBadge.qml
FluBreadcrumbBar 1.0 FluBreadcrumbBar.qml
FluButton 1.0 FluButton.qml
FluCalendarPicker 1.0 FluCalendarPicker.qml
FluCalendarView 1.0 FluCalendarView.qml
FluCarousel 1.0 FluCarousel.qml
FluCheckBox 1.0 FluCheckBox.qml
FluColorPicker 1.0 FluColorPicker.qml
FluColorView 1.0 FluColorView.qml
FluComboBox 1.0 FluComboBox.qml
FluContentDialog 1.0 FluContentDialog.qml
FluContentPage 1.0 FluContentPage.qml
FluDatePicker 1.0 FluDatePicker.qml
FluDivider 1.0 FluDivider.qml
FluDropDownButton 1.0 FluDropDownButton.qml
FluExpander 1.0 FluExpander.qml
FluFilledButton 1.0 FluFilledButton.qml
FluFlipView 1.0 FluFlipView.qml
FluFocusRectangle 1.0 FluFocusRectangle.qml
FluIcon 1.0 FluIcon.qml
FluIconButton 1.0 FluIconButton.qml
FluInfoBar 1.0 FluInfoBar.qml
FluItem 1.0 FluItem.qml
FluMediaPlayer 1.0 FluMediaPlayer.qml
FluMenu 1.0 FluMenu.qml
FluMenuItem 1.0 FluMenuItem.qml
FluMultilineTextBox 1.0 FluMultilineTextBox.qml
FluNavigationView 1.0 FluNavigationView.qml
FluObject 1.0 FluObject.qml
FluPagination 1.0 FluPagination.qml
FluPaneItem 1.0 FluPaneItem.qml
FluPaneItemEmpty 1.0 FluPaneItemEmpty.qml
FluPaneItemExpander 1.0 FluPaneItemExpander.qml
FluPaneItemHeader 1.0 FluPaneItemHeader.qml
FluPaneItemSeparator 1.0 FluPaneItemSeparator.qml
FluPasswordBox 1.0 FluPasswordBox.qml
FluPivot 1.0 FluPivot.qml
FluPivotItem 1.0 FluPivotItem.qml
FluProgressBar 1.0 FluProgressBar.qml
FluProgressRing 1.0 FluProgressRing.qml
FluRadioButton 1.0 FluRadioButton.qml
FluRatingControl 1.0 FluRatingControl.qml
FluRectangle 1.0 FluRectangle.qml
FluScrollablePage 1.0 FluScrollablePage.qml
FluScrollBar 1.0 FluScrollBar.qml
FluShadow 1.0 FluShadow.qml
FluSlider 1.0 FluSlider.qml
FluStatusView 1.0 FluStatusView.qml
FluTableView 1.0 FluTableView.qml
FluTabView 1.0 FluTabView.qml
FluText 1.0 FluText.qml
FluTextBox 1.0 FluTextBox.qml
FluTextBoxBackground 1.0 FluTextBoxBackground.qml
FluTextBoxMenu 1.0 FluTextBoxMenu.qml
FluTextButton 1.0 FluTextButton.qml
FluTimePicker 1.0 FluTimePicker.qml
FluToggleButton 1.0 FluToggleButton.qml
FluToggleSwitch 1.0 FluToggleSwitch.qml
FluTooltip 1.0 FluTooltip.qml
FluTreeView 1.0 FluTreeView.qml
FluWindow 1.0 FluWindow.qml
FluWindowResize 1.0 FluWindowResize.qml
FluSingleton 1.0 FluSingleton.qml
classname FluentUIPlugin
designersupported
typeinfo plugins.qmltypes
FluAppBar 1.0 Controls/FluAppBar.qml
FluArea 1.0 Controls/FluArea.qml
FluAcrylic 1.0 Controls/FluAcrylic.qml
FluAutoSuggestBox 1.0 Controls/FluAutoSuggestBox.qml
FluBadge 1.0 Controls/FluBadge.qml
FluBreadcrumbBar 1.0 Controls/FluBreadcrumbBar.qml
FluButton 1.0 Controls/FluButton.qml
FluCalendarPicker 1.0 Controls/FluCalendarPicker.qml
FluCalendarView 1.0 Controls/FluCalendarView.qml
FluCarousel 1.0 Controls/FluCarousel.qml
FluCheckBox 1.0 Controls/FluCheckBox.qml
FluColorPicker 1.0 Controls/FluColorPicker.qml
FluColorView 1.0 Controls/FluColorView.qml
FluComboBox 1.0 Controls/FluComboBox.qml
FluControl 1.0 Controls/FluControl.qml
FluContentDialog 1.0 Controls/FluContentDialog.qml
FluContentPage 1.0 Controls/FluContentPage.qml
FluCopyableText 1.0 Controls/FluCopyableText.qml
FluDatePicker 1.0 Controls/FluDatePicker.qml
FluDivider 1.0 Controls/FluDivider.qml
FluDropDownButton 1.0 Controls/FluDropDownButton.qml
FluExpander 1.0 Controls/FluExpander.qml
FluFilledButton 1.0 Controls/FluFilledButton.qml
FluFlipView 1.0 Controls/FluFlipView.qml
FluFocusRectangle 1.0 Controls/FluFocusRectangle.qml
FluIcon 1.0 Controls/FluIcon.qml
FluIconButton 1.0 Controls/FluIconButton.qml
FluInfoBar 1.0 Controls/FluInfoBar.qml
FluItem 1.0 Controls/FluItem.qml
FluImage 1.0 Controls/FluImage.qml
FluMediaPlayer 1.0 Controls/FluMediaPlayer.qml
FluMenu 1.0 Controls/FluMenu.qml
FluMenuItem 1.0 Controls/FluMenuItem.qml
FluMenuSeparator 1.0 Controls/FluMenuSeparator.qml
FluMenuBar 1.0 Controls/FluMenuBar.qml
FluMenuBarItem 1.0 Controls/FluMenuBarItem.qml
FluMultilineTextBox 1.0 Controls/FluMultilineTextBox.qml
FluNavigationView 1.0 Controls/FluNavigationView.qml
FluObject 1.0 Controls/FluObject.qml
FluPage 1.0 Controls/FluPage.qml
FluPagination 1.0 Controls/FluPagination.qml
FluPaneItem 1.0 Controls/FluPaneItem.qml
FluPaneItemEmpty 1.0 Controls/FluPaneItemEmpty.qml
FluPaneItemExpander 1.0 Controls/FluPaneItemExpander.qml
FluPaneItemHeader 1.0 Controls/FluPaneItemHeader.qml
FluPaneItemSeparator 1.0 Controls/FluPaneItemSeparator.qml
FluPasswordBox 1.0 Controls/FluPasswordBox.qml
FluPivot 1.0 Controls/FluPivot.qml
FluPivotItem 1.0 Controls/FluPivotItem.qml
FluPopup 1.0 Controls/FluPopup.qml
FluProgressBar 1.0 Controls/FluProgressBar.qml
FluProgressRing 1.0 Controls/FluProgressRing.qml
FluRadioButton 1.0 Controls/FluRadioButton.qml
FluRadioButtons 1.0 Controls/FluRadioButtons.qml
FluRatingControl 1.0 Controls/FluRatingControl.qml
FluRectangle 1.0 Controls/FluRectangle.qml
FluRemoteLoader 1.0 Controls/FluRemoteLoader.qml
FluScrollablePage 1.0 Controls/FluScrollablePage.qml
FluScrollBar 1.0 Controls/FluScrollBar.qml
FluShadow 1.0 Controls/FluShadow.qml
FluSlider 1.0 Controls/FluSlider.qml
FluSpinBox 1.0 Controls/FluSpinBox.qml
FluStatusView 1.0 Controls/FluStatusView.qml
FluTableView 1.0 Controls/FluTableView.qml
FluTabView 1.0 Controls/FluTabView.qml
FluText 1.0 Controls/FluText.qml
FluTextBox 1.0 Controls/FluTextBox.qml
FluTextBoxBackground 1.0 Controls/FluTextBoxBackground.qml
FluTextBoxMenu 1.0 Controls/FluTextBoxMenu.qml
FluTextButton 1.0 Controls/FluTextButton.qml
FluTimePicker 1.0 Controls/FluTimePicker.qml
FluToggleButton 1.0 Controls/FluToggleButton.qml
FluToggleSwitch 1.0 Controls/FluToggleSwitch.qml
FluTooltip 1.0 Controls/FluTooltip.qml
FluTreeView 1.0 Controls/FluTreeView.qml
FluWindow 1.0 Controls/FluWindow.qml
FluSingleton 1.0 Controls/FluSingleton.qml
plugin fluentuiplugin