Compare commits

..

65 Commits
1.6.5 ... 1.6.7

Author SHA1 Message Date
53d28448e0 update 2024-01-20 16:26:04 +08:00
5b7bd8a774 update 2024-01-17 15:33:05 +08:00
0f3910c96b update 2024-01-17 14:00:20 +08:00
4cfd14e9bd update 2024-01-09 21:57:02 +08:00
e295b61596 update 2024-01-09 18:07:36 +08:00
fe8083fcb1 fix bug #397 and #393 2024-01-09 00:17:30 +08:00
7546547364 update 2024-01-08 17:43:46 +08:00
4dbb68abf6 update 2024-01-08 17:11:16 +08:00
d37cd00322 update 2024-01-08 17:03:24 +08:00
f04bc2951f update 2024-01-08 16:40:19 +08:00
993de241cb fix bug #398 2024-01-08 14:07:38 +08:00
cd7ce7fe67 update 2024-01-08 10:43:25 +08:00
d397b88892 update 2024-01-05 20:00:28 +08:00
ae2d517ad0 update 2024-01-05 18:18:08 +08:00
fde1b5ff3a Merge branch 'main' of https://github.com/zhuzichu520/FluentUI 2024-01-05 11:36:53 +08:00
53ba535abc update 2024-01-05 11:36:22 +08:00
5ea480afcb update 2024-01-04 18:49:06 +08:00
9d47c30a6b update 2024-01-04 18:46:33 +08:00
833a8217f4 update 2024-01-04 18:00:44 +08:00
3a0f6355c8 update 2024-01-04 14:28:51 +08:00
28a42d7ecc Merge pull request #392 from mentalfl0w/main
Use more elegant singleton and fix spell bug.
2024-01-04 10:22:43 +08:00
8778ca85a3 Use more elegant singleton and fix spell bug. 2024-01-04 00:26:42 +08:00
bb19554215 update 2024-01-03 21:21:33 +08:00
e0c28e2693 update 2024-01-03 17:48:10 +08:00
1d917baac7 update 2024-01-03 16:56:28 +08:00
cc4e88adbd update 2024-01-02 22:55:17 +08:00
284afed52f update 2024-01-02 22:33:47 +08:00
924ce5d127 update 2024-01-02 18:31:44 +08:00
0e0a385f2d update 2024-01-02 18:27:59 +08:00
1464e647d9 update 2024-01-02 16:56:28 +08:00
0241ecd07f update 2024-01-02 14:53:53 +08:00
0cad207359 update 2024-01-02 13:04:28 +08:00
00e028be07 update 2024-01-01 20:38:18 +08:00
4f66c546a8 update 2024-01-01 20:01:46 +08:00
475d293906 update 2023-12-31 11:20:48 +08:00
a6b8e656f3 update 2023-12-31 00:08:18 +08:00
4b84e9175d update 2023-12-30 22:31:56 +08:00
475cb54d73 update 2023-12-30 22:03:49 +08:00
b0edf23f33 update 2023-12-30 21:10:49 +08:00
c123db97b7 update 2023-12-30 20:34:14 +08:00
1450016c69 update 2023-12-30 20:33:33 +08:00
6221eb4178 update 2023-12-29 23:09:46 +08:00
42f0987e73 update 2023-12-29 17:38:04 +08:00
99ff310448 update 2023-12-29 11:13:10 +08:00
bf5c722058 update 2023-12-29 11:04:54 +08:00
8253fb611f update 2023-12-29 00:40:18 +08:00
0b0fbe1e64 update 2023-12-28 23:21:30 +08:00
2d1957afe3 update 2023-12-28 22:55:38 +08:00
823721ab8c update 2023-12-28 21:30:27 +08:00
bf074da658 update 2023-12-28 21:20:47 +08:00
91a692484f update 2023-12-28 20:47:36 +08:00
46f7299362 update 2023-12-28 15:07:04 +08:00
9f652a7c76 update 2023-12-28 14:27:19 +08:00
9adb6b645b update 2023-12-28 12:42:22 +08:00
2cfc73c00b update 2023-12-22 18:07:46 +08:00
d817782526 update 2023-12-22 12:39:04 +08:00
9dd9d10049 update 2023-12-22 02:09:47 +08:00
fa6b5cfc45 update 2023-12-22 01:30:25 +08:00
217ceabbaa update 2023-12-21 18:12:43 +08:00
83a66b3f15 update 2023-12-21 10:44:46 +08:00
3239e6f12c update 2023-12-20 22:00:10 +08:00
1c67f2a41b update 2023-12-20 21:58:59 +08:00
0b7358af41 fix bug #377 2023-12-20 18:06:46 +08:00
a851696eb0 fix bug #377 2023-12-20 18:01:09 +08:00
f6cc83123b update 2023-12-20 17:17:41 +08:00
109 changed files with 1381 additions and 608 deletions

View File

@ -22,7 +22,7 @@ jobs:
strategy:
matrix:
os: [macos-13]
qt_ver: [6.6.0]
qt_ver: [6.6.1]
qt_arch: [clang_64]
env:
targetName: example
@ -50,11 +50,13 @@ jobs:
cmake --version
mkdir build
cd build
cmake -DCMAKE_MESSAGE_LOG_LEVEL=STATUS -DCMAKE_PREFIX_PATH=/Users/runner/work/FluentUI/Qt/6.6.0/macos -DCMAKE_C_COMPILER=clang -DCMAKE_CXX_COMPILER=clang++ -DCMAKE_BUILD_TYPE=Release -GNinja ..
cmake -DCMAKE_MESSAGE_LOG_LEVEL=STATUS -DCMAKE_PREFIX_PATH=/Users/runner/work/FluentUI/Qt/6.6.1/macos -DCMAKE_C_COMPILER=clang -DCMAKE_CXX_COMPILER=clang++ -DCMAKE_BUILD_TYPE=Release -GNinja ..
cmake --build . --target all --config Release --parallel
- name: package
run: |
# 先删除所有dSYM文件减少包的体积
sudo find /Users/runner/work/FluentUI/Qt/6.6.1/macos/qml -name "*.dSYM" | xargs rm -r
# 拷贝依赖
sudo macdeployqt bin/release/${targetName}.app -qmldir=. -dmg

View File

@ -23,7 +23,7 @@ jobs:
strategy:
matrix:
os: [ubuntu-20.04]
qt_ver: [6.6.0]
qt_ver: [6.6.1]
qt_arch: [gcc_64]
env:
targetName: example
@ -55,7 +55,7 @@ jobs:
cmake --version
mkdir build
cd build
cmake -DCMAKE_MESSAGE_LOG_LEVEL=STATUS -DCMAKE_PREFIX_PATH=/home/runner/work/FluentUI/Qt/6.6.0/gcc_64 -DCMAKE_C_COMPILER=gcc -DCMAKE_CXX_COMPILER=g++ -DCMAKE_BUILD_TYPE=Release -GNinja ..
cmake -DCMAKE_MESSAGE_LOG_LEVEL=STATUS -DCMAKE_PREFIX_PATH=/home/runner/work/FluentUI/Qt/6.6.1/gcc_64 -DCMAKE_C_COMPILER=gcc -DCMAKE_CXX_COMPILER=g++ -DCMAKE_BUILD_TYPE=Release -GNinja ..
cmake --build . --target all --config Release --parallel
- name: install QT linux deploy

View File

@ -24,7 +24,7 @@ jobs:
os: [windows-2022]
include:
- qt_arch: win64_mingw
qt_ver: 6.6.0
qt_ver: 6.6.1
qt_tools: "tools_mingw,9.0.0-1-202203221220,qt.tools.win64_mingw900"
qt_tools_mingw_install: mingw900_64
env:
@ -69,7 +69,7 @@ jobs:
mkdir build
cd build
ninja --version
cmake -DCMAKE_MESSAGE_LOG_LEVEL=STATUS -DCMAKE_PREFIX_PATH=D:\a\FluentUI\Qt\6.6.0\mingw_64 -DCMAKE_C_COMPILER=gcc -DCMAKE_CXX_COMPILER=g++ -DCMAKE_BUILD_TYPE=Release -GNinja ..
cmake -DCMAKE_MESSAGE_LOG_LEVEL=STATUS -DCMAKE_PREFIX_PATH=D:\a\FluentUI\Qt\6.6.1\mingw_64 -DCMAKE_C_COMPILER=gcc -DCMAKE_CXX_COMPILER=g++ -DCMAKE_BUILD_TYPE=Release -GNinja ..
cmake --build . --target all --config Release --parallel
- name: package

View File

@ -23,7 +23,7 @@ jobs:
matrix:
os: [windows-2019]
include:
- qt_ver: 6.6.0
- qt_ver: 6.6.1
qt_arch: win64_msvc2019_64
msvc_arch: x64
qt_arch_install: msvc2019_64
@ -52,7 +52,7 @@ jobs:
ninja --version
mkdir build
cd build
cmake -DCMAKE_MESSAGE_LOG_LEVEL=STATUS -DCMAKE_PREFIX_PATH=D:\a\FluentUI\Qt\6.6.0\msvc2019_64 -DCMAKE_C_COMPILER=cl -DCMAKE_CXX_COMPILER=cl -DCMAKE_BUILD_TYPE=Release -GNinja ..
cmake -DCMAKE_MESSAGE_LOG_LEVEL=STATUS -DCMAKE_PREFIX_PATH=D:\a\FluentUI\Qt\6.6.1\msvc2019_64 -DCMAKE_C_COMPILER=cl -DCMAKE_CXX_COMPILER=cl -DCMAKE_BUILD_TYPE=Release -GNinja ..
cmake --build . --target all --config Release --parallel
echo winSdkDir=%WindowsSdkDir% >> %GITHUB_ENV%
echo winSdkVer=%WindowsSdkVersion% >> %GITHUB_ENV%

Binary file not shown.

Binary file not shown.

View File

@ -2,6 +2,12 @@ cmake_minimum_required(VERSION 3.20)
project(FluentUI VERSION 1.0)
if(MSVC)
#让Release也生成pdb文件
set(CMAKE_SHARED_LINKER_FLAGS_RELEASE "${CMAKE_SHARED_LINKER_FLAGS_RELEASE} /DEBUG /OPT:REF /OPT:ICF")
set(CMAKE_EXE_LINKER_FLAGS_RELEASE "${CMAKE_EXE_LINKER_FLAGS_RELEASE} /DEBUG /OPT:REF /OPT:ICF")
endif()
set(FLUENTUI_DIRECTORY ${CMAKE_CURRENT_LIST_DIR})
list(APPEND CMAKE_MODULE_PATH ${FLUENTUI_DIRECTORY}/.cmake/)
@ -26,6 +32,7 @@ endif()
add_subdirectory(src)
#Release也支持日志打印代码位置
target_compile_definitions(fluentuiplugin
PRIVATE
QT_MESSAGELOGCONTEXT

View File

@ -1,6 +1,6 @@
cmake_minimum_required(VERSION 3.20)
project(example VERSION 1.0)
project(example VERSION 1.0 LANGUAGES CXX)
#配置通用编译
set(CMAKE_CXX_STANDARD 17)
@ -24,6 +24,7 @@ endif()
#获取文件路径分隔符(解决执行命令的时候有些平台会报错)
file(TO_CMAKE_PATH "/" PATH_SEPARATOR)
#导入Qt相关依赖包
find_package(QT NAMES Qt6 Qt5 REQUIRED COMPONENTS Quick Svg Network)
find_package(Qt${QT_VERSION_MAJOR} REQUIRED COMPONENTS Quick Svg Network)
@ -49,24 +50,33 @@ foreach(filepath ${CPP_FILES})
list(APPEND sources_files ${filename})
endforeach(filepath)
if(WIN32)
list(APPEND sources_files "src/app_dmp.h")
endif()
if(QT_VERSION VERSION_GREATER_EQUAL "6.2")
#遍历所有qml文件
file(GLOB_RECURSE QML_PATHS *.qml)
file(GLOB_RECURSE QML_PATHS *.qml qmldir)
foreach(filepath ${QML_PATHS})
string(REPLACE "${CMAKE_CURRENT_SOURCE_DIR}/" "" filename ${filepath})
if(${filepath} MATCHES "Qt${QT_VERSION_MAJOR}/")
string(REPLACE "qml-Qt${QT_VERSION_MAJOR}" "qml" filealias ${filename})
if(${filepath} MATCHES "qml-Qt6")
string(REPLACE "qml-Qt6" "qml" filealias ${filename})
set_source_files_properties(${filename} PROPERTIES QT_RESOURCE_ALIAS ${filealias})
list(APPEND qml_files ${filename})
if(${filename} MATCHES "qmldir")
list(APPEND resource_files ${filename})
else()
list(APPEND qml_files ${filename})
endif()
endif()
endforeach(filepath)
#遍历所有资源文件
file(GLOB_RECURSE RES_PATHS *.png *.jpg *.svg *.ico *.ttf *.webp *.obj qmldir)
file(GLOB_RECURSE RES_PATHS *.png *.jpg *.svg *.ico *.ttf *.webp *.obj)
foreach(filepath ${RES_PATHS})
string(REPLACE "${CMAKE_CURRENT_SOURCE_DIR}/" "" filename ${filepath})
list(APPEND resource_files ${filename})
endforeach(filepath)
endif()
#如果是Windows平台则生成rc文件还有inno setup脚本文件
@ -95,20 +105,19 @@ else ()
)
endif ()
#复制程序运行所需要的动态库
if(WIN32)
#复制动态库到可执行文件同级目录下
if(CMAKE_SIZEOF_VOID_P EQUAL 4)
set(3RDPARTY_ARCH_DIR ${CMAKE_SOURCE_DIR}/3rdparty/Win_x86)
elseif(CMAKE_SIZEOF_VOID_P EQUAL 8)
set(3RDPARTY_ARCH_DIR ${CMAKE_SOURCE_DIR}/3rdparty/Win_x64)
endif()
if(MSVC)
set(DLLPATH ${3RDPARTY_ARCH_DIR}/msvc/*.dll)
if(CMAKE_SIZEOF_VOID_P EQUAL 4)
set(3RDPARTY_DLL_DIR ${CMAKE_SOURCE_DIR}/3rdparty/msvc/x86/*.dll)
elseif(CMAKE_SIZEOF_VOID_P EQUAL 8)
set(3RDPARTY_DLL_DIR ${CMAKE_SOURCE_DIR}/3rdparty/msvc/x64/*.dll)
endif()
elseif(MINGW)
set(DLLPATH ${3RDPARTY_ARCH_DIR}/mingw/*.dll)
set(3RDPARTY_DLL_DIR ${CMAKE_SOURCE_DIR}/3rdparty/mingw/*.dll)
endif()
string(REPLACE "/" ${PATH_SEPARATOR} DLLPATH "${DLLPATH}")
file(GLOB DLL_FILES ${DLLPATH})
string(REPLACE "/" ${PATH_SEPARATOR} 3RDPARTY_DLL_DIR "${3RDPARTY_DLL_DIR}")
file(GLOB DLL_FILES ${3RDPARTY_DLL_DIR})
add_custom_command(TARGET ${PROJECT_NAME} POST_BUILD
COMMAND ${CMAKE_COMMAND} -E copy
${DLL_FILES}
@ -117,7 +126,7 @@ if(WIN32)
endif()
if(QT_VERSION VERSION_GREATER_EQUAL "6.2")
#添加qml模块
#如果是Qt6.2以上则使用qt_add_qml_module添加资源文件
qt_add_qml_module(example
URI "example"
VERSION 1.0
@ -126,10 +135,11 @@ if(QT_VERSION VERSION_GREATER_EQUAL "6.2")
RESOURCE_PREFIX "/"
)
else()
#如果是Qt6.2以下则使用qrc添加资源文件
target_include_directories(example PRIVATE
${CMAKE_CURRENT_SOURCE_DIR}
)
target_sources(example PRIVATE example.qrc)
target_sources(example PRIVATE example.qrc)
endif()
#导入component头文件,不然通过QML_NAMED_ELEMENT生成的c++类会找不到头文件报错
@ -153,11 +163,13 @@ set_target_properties(example PROPERTIES
WIN32_EXECUTABLE TRUE
)
#Release也支持日志打印代码位置
target_compile_definitions(example
PRIVATE
QT_MESSAGELOGCONTEXT
)
#目标文件链接库
target_link_libraries(example PRIVATE
Qt${QT_VERSION_MAJOR}::Quick
Qt${QT_VERSION_MAJOR}::Svg

View File

@ -196,5 +196,7 @@
<file>qml/chart/T_ScatterChart.qml</file>
<file>qml/chart/T_BubbleChart.qml</file>
<file>qml/chart/T_PolarAreaChart.qml</file>
<file>res/image/ic_crash.png</file>
<file>qml/window/CrashWindow.qml</file>
</qresource>
</RCC>

View File

@ -36,12 +36,17 @@ Item {
"/about":"qrc:/example/qml/window/AboutWindow.qml",
"/login":"qrc:/example/qml/window/LoginWindow.qml",
"/hotload":"qrc:/example/qml/window/HotloadWindow.qml",
"/crash":"qrc:/example/qml/window/CrashWindow.qml",
"/singleTaskWindow":"qrc:/example/qml/window/SingleTaskWindow.qml",
"/standardWindow":"qrc:/example/qml/window/StandardWindow.qml",
"/singleInstanceWindow":"qrc:/example/qml/window/SingleInstanceWindow.qml",
"/pageWindow":"qrc:/example/qml/window/PageWindow.qml"
}
FluApp.initialRoute = "/"
FluApp.run()
var args = Qt.application.arguments
if(args.length>=2 && args[1].startsWith("-crashed=")){
FluApp.navigate("/crash",{crashFilePath:args[1].replace("-crashed=","")})
}else{
FluApp.navigate("/")
}
}
}

View File

@ -50,9 +50,7 @@ FluObject{
}
title:"Buttons"
menuDelegate: paneItemMenu
image:"qrc:/example/res/image/control/Button.png"
recentlyUpdated:true
desc:"A control that responds to user input and raisesa Click event."
extra:({image:"qrc:/example/res/image/control/Button.png",recentlyUpdated:true,desc:"A control that responds to user input and raisesa Click event."})
url:"qrc:/example/qml/page/T_Buttons.qml"
onTap:{
item_buttons.count = 0
@ -83,18 +81,14 @@ FluObject{
FluPaneItem{
title:"Slider"
menuDelegate: paneItemMenu
image:"qrc:/example/res/image/control/Slider.png"
recentlyUpdated:true
desc:"A control that lets the user select from a rangeof values by moving a Thumb control along atrack."
extra:({image:"qrc:/example/res/image/control/Slider.png",recentlyUpdated:true,desc:"A control that lets the user select from a rangeof values by moving a Thumb control along atrack."})
url:"qrc:/example/qml/page/T_Slider.qml"
onTap:{ navigationView.push(url) }
}
FluPaneItem{
title:"CheckBox"
menuDelegate: paneItemMenu
image:"qrc:/example/res/image/control/Checkbox.png"
recentlyUpdated:true
desc:"A control that a user can select or clear."
extra:({image:"qrc:/example/res/image/control/Checkbox.png",recentlyUpdated:true,desc:"A control that a user can select or clear."})
url:"qrc:/example/qml/page/T_CheckBox.qml"
onTap:{ navigationView.push(url) }
}
@ -164,9 +158,7 @@ FluObject{
FluPaneItem{
title:"InfoBar"
menuDelegate: paneItemMenu
image:"qrc:/example/res/image/control/InfoBar.png"
recentlyUpdated:true
desc:"An inline message to display app-wide statuschange information."
extra:({image:"qrc:/example/res/image/control/InfoBar.png",recentlyUpdated:true,desc:"An inline message to display app-wide statuschange information."})
url:"qrc:/example/qml/page/T_InfoBar.qml"
onTap:{ navigationView.push(url) }
}
@ -276,10 +268,7 @@ FluObject{
FluPaneItem{
title:"Pivot"
menuDelegate: paneItemMenu
image:"qrc:/example/res/image/control/Pivot.png"
recentlyAdded:true
order:3
desc:"Presents information from different sources in atabbed view."
extra:({image:"qrc:/example/res/image/control/Pivot.png",order:3,recentlyAdded:true,desc:"Presents information from different sources in atabbed view."})
url:"qrc:/example/qml/page/T_Pivot.qml"
onTap:{ navigationView.push(url) }
}
@ -292,10 +281,7 @@ FluObject{
FluPaneItem{
title:"TabView"
menuDelegate: paneItemMenu
image:"qrc:/example/res/image/control/TabView.png"
recentlyAdded:true
order:1
desc:"A control that displays a collection of tabs thatcan be used to display several documents."
extra:({image:"qrc:/example/res/image/control/TabView.png",order:1,recentlyAdded:true,desc:"A control that displays a collection of tabs thatcan be used to display several documents."})
url:"qrc:/example/qml/page/T_TabView.qml"
onTap:{ navigationView.push(url) }
}
@ -308,10 +294,7 @@ FluObject{
FluPaneItem{
title:"TableView"
menuDelegate: paneItemMenu
image:"qrc:/example/res/image/control/DataGrid.png"
recentlyAdded:true
order:4
desc:"The TableView control provides a flexible way to display a collection of data in rows and columns"
extra:({image:"qrc:/example/res/image/control/DataGrid.png",order:4,recentlyAdded:true,desc:"The TableView control provides a flexible way to display a collection of data in rows and columns"})
url:"qrc:/example/qml/page/T_TableView.qml"
onTap:{ navigationView.push(url) }
}
@ -330,10 +313,7 @@ FluObject{
FluPaneItem{
title:"FlipView"
menuDelegate: paneItemMenu
image:"qrc:/example/res/image/control/FlipView.png"
recentlyAdded:true
order:2
desc:"Presents a collection of items that the user canflip through, one item at a time."
extra:({image:"qrc:/example/res/image/control/FlipView.png",order:2,recentlyAdded:true,desc:"Presents a collection of items that the user canflip through, one item at a time."})
url:"qrc:/example/qml/page/T_FlipView.qml"
onTap:{ navigationView.push(url) }
}
@ -486,25 +466,25 @@ FluObject{
url:"qrc:/example/qml/page/T_3D.qml"
onTap:{ navigationView.push(url) }
}
FluPaneItem{
title:"Test Crash"
visible: FluTools.isWin()
onTapListener: function(){
AppInfo.testCrash()
}
}
}
function getRecentlyAddedData(){
var arr = []
for(var i=0;i<children.length;i++){
var item = children[i]
if(item instanceof FluPaneItem && item.recentlyAdded){
var items = navigationView.getItems();
for(var i=0;i<items.length;i++){
var item = items[i]
if(item instanceof FluPaneItem && item.extra && item.extra.recentlyAdded){
arr.push(item)
}
if(item instanceof FluPaneItemExpander){
for(var j=0;j<item.children.length;j++){
var itemChild = item.children[j]
if(itemChild instanceof FluPaneItem && itemChild.recentlyAdded){
arr.push(itemChild)
}
}
}
}
arr.sort(function(o1,o2){ return o2.order-o1.order })
arr.sort(function(o1,o2){ return o2.extra.order-o1.extra.order })
return arr
}
@ -513,7 +493,7 @@ FluObject{
var items = navigationView.getItems();
for(var i=0;i<items.length;i++){
var item = items[i]
if(item instanceof FluPaneItem && item.recentlyUpdated){
if(item instanceof FluPaneItem && item.extra && item.extra.recentlyUpdated){
arr.push(item)
}
}

View File

@ -27,7 +27,6 @@ FluScrollablePage{
id: bg
fillMode:Image.PreserveAspectCrop
anchors.fill: parent
asynchronous: true
verticalAlignment: Qt.AlignTop
sourceSize: Qt.size(960,640)
source: "qrc:/example/res/image/bg_home_header.png"
@ -160,7 +159,7 @@ FluScrollablePage{
Component{
id:com_item
Item{
property string desc: modelData.desc
property string desc: modelData.extra.desc
width: 320
height: 120
FluArea{
@ -182,7 +181,7 @@ FluScrollablePage{
id:item_icon
height: 40
width: 40
source: modelData.image
source: modelData.extra.image
anchors{
left: parent.left
leftMargin: 20

View File

@ -407,7 +407,7 @@ FluContentPage{
text: "Download File"
onClicked: {
folder_dialog.showDialog(function(path){
FluNetwork.get("http://clips.vorwaerts-gmbh.de/big_buck_bunny.mp4")
FluNetwork.get("http://vjs.zencdn.net/v/oceans.mp4")
.toDownload(path)
.bind(root)
.go(callable_download_file)
@ -421,7 +421,7 @@ FluContentPage{
text: "Breakpoint Download File"
onClicked: {
folder_dialog.showDialog(function(path){
FluNetwork.get("http://clips.vorwaerts-gmbh.de/big_buck_bunny.mp4")
FluNetwork.get("http://vjs.zencdn.net/v/oceans.mp4")
.toDownload(path,true)
.bind(root)
.go(callable_breakpoint_download_file)
@ -521,7 +521,7 @@ FluContentPage{
property var onSelectListener
id: folder_dialog
folder: StandardPaths.standardLocations(StandardPaths.DownloadLocation)[0]
currentFile: StandardPaths.standardLocations(StandardPaths.DownloadLocation)[0]+"/big_buck_bunny.mp4"
currentFile: StandardPaths.standardLocations(StandardPaths.DownloadLocation)[0]+"/oceans.mp4"
fileMode: FileDialog.SaveFile
onAccepted: {
folder_dialog.onSelectListener(FluTools.toLocalPath(folder_dialog.currentFile))

View File

@ -87,26 +87,6 @@ FluScrollablePage{
}
}
FluArea{
Layout.fillWidth: true
Layout.topMargin: 20
height: 50
paddings: 10
FluCheckBox{
text:"Software Render"
checked: SettingsHelper.getRender() === "software"
anchors.verticalCenter: parent.verticalCenter
onClicked: {
if(SettingsHelper.getRender() === "software"){
SettingsHelper.saveRender("")
}else{
SettingsHelper.saveRender("software")
}
dialog_restart.open()
}
}
}
FluContentDialog{
id:dialog_restart
title:"友情提示"

View File

@ -67,10 +67,10 @@ FluScrollablePage{
text:"Always"
Layout.preferredWidth: 120
FluMenuItem{
text:"Nerver"
text:"Never"
onClicked: {
btn_close_button_visibility.text = text
tab_view.closeButtonVisibility = FluTabViewType.Nerver
tab_view.closeButtonVisibility = FluTabViewType.Never
}
}
FluMenuItem{

View File

@ -29,6 +29,43 @@ FluContentPage{
}
}
FluContentDialog{
id:custom_update_dialog
signal showDialog(string text,var callback)
property var _textBox
property var onAccpetListener
title:"修改列名"
negativeText:"取消"
contentDelegate: Component{
Item{
width: parent.width
height: 60
FluTextBox{
id:textbox_text
anchors.centerIn: parent
}
Connections{
target: custom_update_dialog
function onShowDialog(text,callback){
custom_update_dialog._textBox = textbox_text
custom_update_dialog.onAccpetListener = callback
textbox_text.text = text
textbox_text.forceActiveFocus()
custom_update_dialog.open()
}
}
}
}
onNegativeClicked:{
}
positiveText:"确定"
onPositiveClicked:{
if(custom_update_dialog.onAccpetListener && custom_update_dialog._textBox){
custom_update_dialog.onAccpetListener(custom_update_dialog._textBox.text)
}
}
}
Component{
id:com_checbox
Item{
@ -158,6 +195,34 @@ FluContentPage{
}
}
Component{
id:com_column_update_title
Item{
FluText{
id:text_title
text: {
if(options.title){
return options.title
}
return ""
}
anchors.fill: parent
verticalAlignment: Qt.AlignVCenter
horizontalAlignment: Qt.AlignHCenter
elide: Text.ElideRight
}
MouseArea{
anchors.fill: parent
cursorShape: Qt.PointingHandCursor
onClicked: {
custom_update_dialog.showDialog(options.title,function(text){
itemModel.display = table_view.customItem(com_column_update_title,{"title":text})
})
}
}
}
}
Component{
id:com_column_sort_age
Item{
@ -236,7 +301,7 @@ FluContentPage{
maximumWidth:80,
},
{
title: '头像',
title: table_view.customItem(com_column_update_title,{title:'头像'}),
dataIndex: 'avatar',
width:100,
minimumWidth:100,

View File

@ -9,7 +9,7 @@ FluWindow {
id:window
title:"关于"
width: 600
height: 600
height: 580
fixSize: true
launchMode: FluWindowType.SingleTask

View File

@ -0,0 +1,72 @@
import QtQuick
import QtQuick.Controls
import QtQuick.Layouts
import FluentUI
import Qt.labs.platform
import "qrc:///example/qml/component"
FluWindow {
id:window
title:"友情提示"
width: 300
height: 400
fixSize: true
showMinimize: false
showStayTop: false
property string crashFilePath
onInitArgument:
(argument)=>{
crashFilePath = argument.crashFilePath
}
Image{
width: 540/2
height: 285/2
anchors{
horizontalCenter: parent.horizontalCenter
top: parent.top
topMargin: 40
}
source: "qrc:/example/res/image/ic_crash.png"
}
FluText{
id:text_info
anchors{
horizontalCenter: parent.horizontalCenter
top: parent.top
topMargin: 240
}
text:"发生意外错误\n给您带来的不便我们深表歉意"
horizontalAlignment: Text.AlignHCenter
verticalAlignment: Text.AlignVCenter
}
RowLayout{
anchors{
horizontalCenter: parent.horizontalCenter
bottom: parent.bottom
bottomMargin: 20
}
FluButton{
text:"日志上报"
onClicked: {
FluTools.showFileInFolder(crashFilePath)
}
}
Item{
width: 30
height: 1
}
FluFilledButton{
text:"重启程序"
onClicked: {
FluApp.exit(931)
}
}
}
}

View File

@ -36,12 +36,17 @@ Item {
"/about":"qrc:/example/qml/window/AboutWindow.qml",
"/login":"qrc:/example/qml/window/LoginWindow.qml",
"/hotload":"qrc:/example/qml/window/HotloadWindow.qml",
"/crash":"qrc:/example/qml/window/CrashWindow.qml",
"/singleTaskWindow":"qrc:/example/qml/window/SingleTaskWindow.qml",
"/standardWindow":"qrc:/example/qml/window/StandardWindow.qml",
"/singleInstanceWindow":"qrc:/example/qml/window/SingleInstanceWindow.qml",
"/pageWindow":"qrc:/example/qml/window/PageWindow.qml"
}
FluApp.initialRoute = "/"
FluApp.run()
var args = Qt.application.arguments
if(args.length>=2 && args[1].startsWith("-crashed=")){
FluApp.navigate("/crash",{crashFilePath:args[1].replace("-crashed=","")})
}else{
FluApp.navigate("/")
}
}
}

View File

@ -50,9 +50,7 @@ FluObject{
}
title:"Buttons"
menuDelegate: paneItemMenu
image:"qrc:/example/res/image/control/Button.png"
recentlyUpdated:true
desc:"A control that responds to user input and raisesa Click event."
extra:({image:"qrc:/example/res/image/control/Button.png",recentlyUpdated:true,desc:"A control that responds to user input and raisesa Click event."})
url:"qrc:/example/qml/page/T_Buttons.qml"
onTap:{
item_buttons.count = 0
@ -83,18 +81,14 @@ FluObject{
FluPaneItem{
title:"Slider"
menuDelegate: paneItemMenu
image:"qrc:/example/res/image/control/Slider.png"
recentlyUpdated:true
desc:"A control that lets the user select from a rangeof values by moving a Thumb control along atrack."
extra:({image:"qrc:/example/res/image/control/Slider.png",recentlyUpdated:true,desc:"A control that lets the user select from a rangeof values by moving a Thumb control along atrack."})
url:"qrc:/example/qml/page/T_Slider.qml"
onTap:{ navigationView.push(url) }
}
FluPaneItem{
title:"CheckBox"
menuDelegate: paneItemMenu
image:"qrc:/example/res/image/control/Checkbox.png"
recentlyUpdated:true
desc:"A control that a user can select or clear."
extra:({image:"qrc:/example/res/image/control/Checkbox.png",recentlyUpdated:true,desc:"A control that a user can select or clear."})
url:"qrc:/example/qml/page/T_CheckBox.qml"
onTap:{ navigationView.push(url) }
}
@ -164,9 +158,7 @@ FluObject{
FluPaneItem{
title:"InfoBar"
menuDelegate: paneItemMenu
image:"qrc:/example/res/image/control/InfoBar.png"
recentlyUpdated:true
desc:"An inline message to display app-wide statuschange information."
extra:({image:"qrc:/example/res/image/control/InfoBar.png",recentlyUpdated:true,desc:"An inline message to display app-wide statuschange information."})
url:"qrc:/example/qml/page/T_InfoBar.qml"
onTap:{ navigationView.push(url) }
}
@ -276,10 +268,7 @@ FluObject{
FluPaneItem{
title:"Pivot"
menuDelegate: paneItemMenu
image:"qrc:/example/res/image/control/Pivot.png"
recentlyAdded:true
order:3
desc:"Presents information from different sources in atabbed view."
extra:({image:"qrc:/example/res/image/control/Pivot.png",order:3,recentlyAdded:true,desc:"Presents information from different sources in atabbed view."})
url:"qrc:/example/qml/page/T_Pivot.qml"
onTap:{ navigationView.push(url) }
}
@ -292,10 +281,7 @@ FluObject{
FluPaneItem{
title:"TabView"
menuDelegate: paneItemMenu
image:"qrc:/example/res/image/control/TabView.png"
recentlyAdded:true
order:1
desc:"A control that displays a collection of tabs thatcan be used to display several documents."
extra:({image:"qrc:/example/res/image/control/TabView.png",order:1,recentlyAdded:true,desc:"A control that displays a collection of tabs thatcan be used to display several documents."})
url:"qrc:/example/qml/page/T_TabView.qml"
onTap:{ navigationView.push(url) }
}
@ -308,10 +294,7 @@ FluObject{
FluPaneItem{
title:"TableView"
menuDelegate: paneItemMenu
image:"qrc:/example/res/image/control/DataGrid.png"
recentlyAdded:true
order:4
desc:"The TableView control provides a flexible way to display a collection of data in rows and columns"
extra:({image:"qrc:/example/res/image/control/DataGrid.png",order:4,recentlyAdded:true,desc:"The TableView control provides a flexible way to display a collection of data in rows and columns"})
url:"qrc:/example/qml/page/T_TableView.qml"
onTap:{ navigationView.push(url) }
}
@ -330,10 +313,7 @@ FluObject{
FluPaneItem{
title:"FlipView"
menuDelegate: paneItemMenu
image:"qrc:/example/res/image/control/FlipView.png"
recentlyAdded:true
order:2
desc:"Presents a collection of items that the user canflip through, one item at a time."
extra:({image:"qrc:/example/res/image/control/FlipView.png",order:2,recentlyAdded:true,desc:"Presents a collection of items that the user canflip through, one item at a time."})
url:"qrc:/example/qml/page/T_FlipView.qml"
onTap:{ navigationView.push(url) }
}
@ -486,25 +466,25 @@ FluObject{
url:"qrc:/example/qml/page/T_3D.qml"
onTap:{ navigationView.push(url) }
}
FluPaneItem{
title:"Test Crash"
visible: FluTools.isWin()
onTapListener: function(){
AppInfo.testCrash()
}
}
}
function getRecentlyAddedData(){
var arr = []
for(var i=0;i<children.length;i++){
var item = children[i]
if(item instanceof FluPaneItem && item.recentlyAdded){
var items = navigationView.getItems();
for(var i=0;i<items.length;i++){
var item = items[i]
if(item instanceof FluPaneItem && item.extra && item.extra.recentlyAdded){
arr.push(item)
}
if(item instanceof FluPaneItemExpander){
for(var j=0;j<item.children.length;j++){
var itemChild = item.children[j]
if(itemChild instanceof FluPaneItem && itemChild.recentlyAdded){
arr.push(itemChild)
}
}
}
}
arr.sort(function(o1,o2){ return o2.order-o1.order })
arr.sort(function(o1,o2){ return o2.extra.order-o1.extra.order })
return arr
}
@ -513,7 +493,7 @@ FluObject{
var items = navigationView.getItems();
for(var i=0;i<items.length;i++){
var item = items[i]
if(item instanceof FluPaneItem && item.recentlyUpdated){
if(item instanceof FluPaneItem && item.extra && item.extra.recentlyUpdated){
arr.push(item)
}
}

View File

@ -27,7 +27,6 @@ FluScrollablePage{
id: bg
fillMode:Image.PreserveAspectCrop
anchors.fill: parent
asynchronous: true
verticalAlignment: Qt.AlignTop
sourceSize: Qt.size(960,640)
source: "qrc:/example/res/image/bg_home_header.png"
@ -160,7 +159,7 @@ FluScrollablePage{
Component{
id:com_item
Item{
property string desc: modelData.desc
property string desc: modelData.extra.desc
width: 320
height: 120
FluArea{
@ -182,7 +181,7 @@ FluScrollablePage{
id:item_icon
height: 40
width: 40
source: modelData.image
source: modelData.extra.image
anchors{
left: parent.left
leftMargin: 20

View File

@ -408,7 +408,7 @@ FluContentPage{
text: "Download File"
onClicked: {
folder_dialog.showDialog(function(path){
FluNetwork.get("http://clips.vorwaerts-gmbh.de/big_buck_bunny.mp4")
FluNetwork.get("http://vjs.zencdn.net/v/oceans.mp4")
.toDownload(path)
.bind(root)
.go(callable_download_file)
@ -422,7 +422,7 @@ FluContentPage{
text: "Breakpoint Download File"
onClicked: {
folder_dialog.showDialog(function(path){
FluNetwork.get("http://clips.vorwaerts-gmbh.de/big_buck_bunny.mp4")
FluNetwork.get("http://vjs.zencdn.net/v/oceans.mp4")
.toDownload(path,true)
.bind(root)
.go(callable_breakpoint_download_file)
@ -522,7 +522,7 @@ FluContentPage{
property var onSelectListener
id: folder_dialog
folder: StandardPaths.standardLocations(StandardPaths.DownloadLocation)[0]
currentFile: StandardPaths.standardLocations(StandardPaths.DownloadLocation)[0]+"/big_buck_bunny.mp4"
currentFile: StandardPaths.standardLocations(StandardPaths.DownloadLocation)[0]+"/oceans.mp4"
fileMode: FileDialog.SaveFile
onAccepted: {
folder_dialog.onSelectListener(FluTools.toLocalPath(folder_dialog.currentFile))

View File

@ -90,26 +90,6 @@ FluScrollablePage{
}
}
FluArea{
Layout.fillWidth: true
Layout.topMargin: 20
height: 50
paddings: 10
FluCheckBox{
text:"Software Render"
checked: SettingsHelper.getRender() === "software"
anchors.verticalCenter: parent.verticalCenter
onClicked: {
if(SettingsHelper.getRender() === "software"){
SettingsHelper.saveRender("")
}else{
SettingsHelper.saveRender("software")
}
dialog_restart.open()
}
}
}
FluContentDialog{
id:dialog_restart
title:"友情提示"

View File

@ -68,10 +68,10 @@ FluScrollablePage{
text:"Always"
Layout.preferredWidth: 120
FluMenuItem{
text:"Nerver"
text:"Never"
onClicked: {
btn_close_button_visibility.text = text
tab_view.closeButtonVisibility = FluTabViewType.Nerver
tab_view.closeButtonVisibility = FluTabViewType.Never
}
}
FluMenuItem{

View File

@ -30,6 +30,43 @@ FluContentPage{
}
}
FluContentDialog{
id:custom_update_dialog
signal showDialog(string text,var callback)
property var _textBox
property var onAccpetListener
title:"修改列名"
negativeText:"取消"
contentDelegate: Component{
Item{
width: parent.width
height: 60
FluTextBox{
id:textbox_text
anchors.centerIn: parent
}
Connections{
target: custom_update_dialog
function onShowDialog(text,callback){
custom_update_dialog._textBox = textbox_text
custom_update_dialog.onAccpetListener = callback
textbox_text.text = text
textbox_text.forceActiveFocus()
custom_update_dialog.open()
}
}
}
}
onNegativeClicked:{
}
positiveText:"确定"
onPositiveClicked:{
if(custom_update_dialog.onAccpetListener && custom_update_dialog._textBox){
custom_update_dialog.onAccpetListener(custom_update_dialog._textBox.text)
}
}
}
Component{
id:com_checbox
Item{
@ -159,6 +196,34 @@ FluContentPage{
}
}
Component{
id:com_column_update_title
Item{
FluText{
id:text_title
text: {
if(options.title){
return options.title
}
return ""
}
anchors.fill: parent
verticalAlignment: Qt.AlignVCenter
horizontalAlignment: Qt.AlignHCenter
elide: Text.ElideRight
}
MouseArea{
anchors.fill: parent
cursorShape: Qt.PointingHandCursor
onClicked: {
custom_update_dialog.showDialog(options.title,function(text){
itemModel.display = table_view.customItem(com_column_update_title,{"title":text})
})
}
}
}
}
Component{
id:com_column_sort_age
Item{
@ -237,7 +302,7 @@ FluContentPage{
maximumWidth:80,
},
{
title: '头像',
title: table_view.customItem(com_column_update_title,{title:'头像'}),
dataIndex: 'avatar',
width:100,
minimumWidth:100,

View File

@ -10,7 +10,7 @@ FluWindow {
id:window
title:"关于"
width: 600
height: 600
height: 580
fixSize: true
launchMode: FluWindowType.SingleTask

View File

@ -0,0 +1,72 @@
import QtQuick 2.15
import QtQuick.Controls 2.15
import QtQuick.Layouts 1.15
import FluentUI 1.0
import Qt.labs.platform 1.0
import "qrc:///example/qml/component"
FluWindow {
id:window
title:"友情提示"
width: 300
height: 400
fixSize: true
showMinimize: false
showStayTop: false
property string crashFilePath
onInitArgument:
(argument)=>{
crashFilePath = argument.crashFilePath
}
Image{
width: 540/2
height: 285/2
anchors{
horizontalCenter: parent.horizontalCenter
top: parent.top
topMargin: 40
}
source: "qrc:/example/res/image/ic_crash.png"
}
FluText{
id:text_info
anchors{
horizontalCenter: parent.horizontalCenter
top: parent.top
topMargin: 240
}
text:"发生意外错误\n给您带来的不便我们深表歉意"
horizontalAlignment: Text.AlignHCenter
verticalAlignment: Text.AlignVCenter
}
RowLayout{
anchors{
horizontalCenter: parent.horizontalCenter
bottom: parent.bottom
bottomMargin: 20
}
FluButton{
text:"日志上报"
onClicked: {
FluTools.showFileInFolder(crashFilePath)
}
}
Item{
width: 30
height: 1
}
FluFilledButton{
text:"重启程序"
onClicked: {
FluApp.exit(931)
}
}
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

View File

@ -11,6 +11,7 @@ AppInfo::AppInfo(QObject *parent)
version(APPLICATION_VERSION);
}
void AppInfo::init(QQmlApplicationEngine *engine){
engine->rootContext();
void AppInfo::testCrash(){
auto *crash = reinterpret_cast<volatile int *>(0);
*crash = 0;
}

View File

@ -13,8 +13,8 @@ class AppInfo : public QObject
private:
explicit AppInfo(QObject *parent = nullptr);
public:
SINGLETONG(AppInfo)
void init(QQmlApplicationEngine *engine);
SINGLETON(AppInfo)
Q_INVOKABLE void testCrash();
};
#endif // APPINFO_H

82
example/src/app_dmp.h Normal file
View File

@ -0,0 +1,82 @@
#ifndef APP_DUMP_H
#define APP_DUMP_H
#include <Windows.h>
#include <DbgHelp.h>
#include <QDateTime>
#include <QDir>
#include <QGuiApplication>
#include <QProcess>
#include <QStandardPaths>
#include <QString>
#pragma comment(lib, "Dbghelp.lib")
static void miniDumpWriteDump(HANDLE hProcess,DWORD ProcessId,HANDLE hFile,MINIDUMP_TYPE DumpType,CONST PMINIDUMP_EXCEPTION_INFORMATION ExceptionParam,CONST PMINIDUMP_USER_STREAM_INFORMATION UserStreamParam,CONST PMINIDUMP_CALLBACK_INFORMATION CallbackParam){
typedef HRESULT (WINAPI* MiniDumpWriteDumpPtr)(HANDLE hProcess,DWORD ProcessId,HANDLE hFile,MINIDUMP_TYPE DumpType,CONST PMINIDUMP_EXCEPTION_INFORMATION ExceptionParam,CONST PMINIDUMP_USER_STREAM_INFORMATION UserStreamParam,CONST PMINIDUMP_CALLBACK_INFORMATION CallbackParam);
HMODULE module = LoadLibraryW(L"Dbghelp.dll");
if (module)
{
MiniDumpWriteDumpPtr mini_dump_write_dump;
mini_dump_write_dump= reinterpret_cast<MiniDumpWriteDumpPtr>(GetProcAddress(module, "MiniDumpWriteDump"));
if (mini_dump_write_dump)
{
mini_dump_write_dump(hProcess,ProcessId,hFile,DumpType,ExceptionParam,UserStreamParam,CallbackParam);
}
}
}
BOOL CALLBACK MyMiniDumpCallback(PVOID, const PMINIDUMP_CALLBACK_INPUT input, PMINIDUMP_CALLBACK_OUTPUT output) {
if (input == NULL || output == NULL)
return FALSE;
BOOL ret = FALSE;
switch (input->CallbackType) {
case IncludeModuleCallback:
case IncludeThreadCallback:
case ThreadCallback:
case ThreadExCallback:
ret = TRUE;
break;
case ModuleCallback: {
if (!(output->ModuleWriteFlags & ModuleReferencedByMemory)) {
output->ModuleWriteFlags &= ~ModuleWriteModule;
}
ret = TRUE;
} break;
default:
break;
}
return ret;
}
void WriteDump(EXCEPTION_POINTERS* exp, const std::wstring& path) {
HANDLE h = ::CreateFileW(path.c_str(), GENERIC_WRITE | GENERIC_READ, FILE_SHARE_WRITE | FILE_SHARE_READ, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
MINIDUMP_EXCEPTION_INFORMATION info;
info.ThreadId = ::GetCurrentThreadId();
info.ExceptionPointers = exp;
info.ClientPointers = FALSE;
MINIDUMP_CALLBACK_INFORMATION mci;
mci.CallbackRoutine = (MINIDUMP_CALLBACK_ROUTINE)MyMiniDumpCallback;
mci.CallbackParam = 0;
MINIDUMP_TYPE mdt = (MINIDUMP_TYPE)(MiniDumpWithIndirectlyReferencedMemory | MiniDumpScanMemory);
miniDumpWriteDump(GetCurrentProcess(), GetCurrentProcessId(), h, mdt, &info, NULL, &mci);
::CloseHandle(h);
}
LONG WINAPI MyUnhandledExceptionFilter(EXCEPTION_POINTERS* exp) {
const QString dumpFileName = QString("%1_%2.dmp").arg("crash",QDateTime::currentDateTime().toString("yyyyMMdd_hhmmss"));
const QString dumpDirPath = QStandardPaths::writableLocation(QStandardPaths::AppLocalDataLocation)+"/dmp";
const QDir dumpDir(dumpDirPath);
if(!dumpDir.exists()){
dumpDir.mkpath(dumpDirPath);
}
QString dumpFilePath = dumpDir.filePath(dumpFileName);
WriteDump(exp, dumpFilePath.toStdWString());
QStringList arguments;
arguments << "-crashed=" + dumpFilePath;
QProcess::startDetached(qApp->applicationFilePath(), arguments);
return EXCEPTION_EXECUTE_HANDLER;
}
#endif // APP_DUMP_H

View File

@ -92,8 +92,11 @@ QString Log::prettyProductInfoWrapper()
return productName;
}
static inline void myMessageHandler(const QtMsgType type, const QMessageLogContext &context, const QString &message)
static inline void messageHandler(const QtMsgType type, const QMessageLogContext &context, const QString &message)
{
if(message == "Could not get the INetworkConnection instance for the adapter GUID."){
return;
}
if(logLevelMap[type]>g_logLevel){
return;
}
@ -165,12 +168,13 @@ static inline void myMessageHandler(const QtMsgType type, const QMessageLogConte
}
}
void Log::setup(const QString &app)
void Log::setup(const QString &app,int level)
{
Q_ASSERT(!app.isEmpty());
if (app.isEmpty()) {
return;
}
g_logLevel = level;
static bool once = false;
if (once) {
return;
@ -184,7 +188,7 @@ void Log::setup(const QString &app)
logDir.mkpath(logDirPath);
}
g_file_path = logDir.filePath(logFileName);
qInstallMessageHandler(myMessageHandler);
qInstallMessageHandler(messageHandler);
qInfo()<<"===================================================";
qInfo()<<"[AppName]"<<g_app;
qInfo()<<"[AppVersion]"<<APPLICATION_VERSION;

View File

@ -5,7 +5,7 @@
namespace Log
{
QString prettyProductInfoWrapper();
void setup(const QString &app);
void setup(const QString &app,int level = 4);
}
#endif // LOG_H

View File

@ -16,11 +16,9 @@ class SettingsHelper : public QObject
private:
explicit SettingsHelper(QObject* parent = nullptr);
public:
SINGLETONG(SettingsHelper)
SINGLETON(SettingsHelper)
~SettingsHelper() override;
void init(char *argv[]);
Q_INVOKABLE void saveRender(const QVariant& render){save("render",render);}
Q_INVOKABLE QString getRender(){return get("render").toString();}
Q_INVOKABLE void saveDarkMode(int darkModel){save("darkMode",darkModel);}
Q_INVOKABLE int getDarkMode(){return get("darkMode",QVariant(0)).toInt();}
Q_INVOKABLE void saveUseSystemAppBar(bool useSystemAppBar){save("useSystemAppBar",useSystemAppBar);}

View File

@ -8,6 +8,7 @@
#include <QProcess>
#include <QtQml/qqmlextensionplugin.h>
#include <QLoggingCategory>
#include "Version.h"
#include "AppInfo.h"
#include "helper/Log.h"
#include "src/component/CircularReveal.h"
@ -22,9 +23,21 @@ Q_IMPORT_QML_PLUGIN(FluentUIPlugin)
#include <FluentUI.h>
#endif
#ifdef WIN32
#include "app_dmp.h"
#endif
int main(int argc, char *argv[])
{
#ifdef WIN32
::SetUnhandledExceptionFilter(MyUnhandledExceptionFilter);
qputenv("QT_QPA_PLATFORM","windows:darkmode=2");
#endif
#if (QT_VERSION >= QT_VERSION_CHECK(6, 0, 0))
qputenv("QT_QUICK_CONTROLS_STYLE","Basic");
#else
qputenv("QT_QUICK_CONTROLS_STYLE","Default");
#endif
#ifdef Q_OS_LINUX
//fix bug UOSv20 does not print logs
qputenv("QT_LOGGING_RULES","");
@ -34,8 +47,13 @@ int main(int argc, char *argv[])
QGuiApplication::setOrganizationName("ZhuZiChu");
QGuiApplication::setOrganizationDomain("https://zhuzichu520.github.io");
QGuiApplication::setApplicationName("FluentUI");
QGuiApplication::setApplicationDisplayName("FluentUI Exmaple");
QGuiApplication::setApplicationVersion(APPLICATION_VERSION);
SettingsHelper::getInstance()->init(argv);
Log::setup("example");
#if (QT_VERSION >= QT_VERSION_CHECK(6, 5, 0))
QQuickWindow::setGraphicsApi(QSGRendererInterface::OpenGL);
#endif
#if (QT_VERSION < QT_VERSION_CHECK(6, 0, 0))
QGuiApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
QGuiApplication::setAttribute(Qt::AA_UseHighDpiPixmaps);
@ -43,18 +61,8 @@ int main(int argc, char *argv[])
QGuiApplication::setHighDpiScaleFactorRoundingPolicy(Qt::HighDpiScaleFactorRoundingPolicy::PassThrough);
#endif
#endif
if(SettingsHelper::getInstance()->getRender()=="software"){
#if (QT_VERSION >= QT_VERSION_CHECK(6, 0, 0))
QQuickWindow::setGraphicsApi(QSGRendererInterface::Software);
#elif (QT_VERSION >= QT_VERSION_CHECK(5, 14, 0))
QQuickWindow::setSceneGraphBackend(QSGRendererInterface::Software);
#endif
}
QGuiApplication app(argc, argv);
// QLoggingCategory::setFilterRules(QStringLiteral("qt.scenegraph.general=true"));
// qSetMessagePattern("%{category}: %{message}");
QQmlApplicationEngine engine;
AppInfo::getInstance()->init(&engine);
engine.rootContext()->setContextProperty("AppInfo",AppInfo::getInstance());
engine.rootContext()->setContextProperty("SettingsHelper",SettingsHelper::getInstance());
#ifdef FLUENTUI_BUILD_STATIC_LIB

View File

@ -2,46 +2,39 @@
#define SINGLETON_H
#include <QMutex>
#include <QScopedPointer>
#include <memory>
#include <mutex>
template <typename T>
class Singleton {
public:
static T* getInstance();
Singleton(const Singleton& other) = delete;
Singleton<T>& operator=(const Singleton& other) = delete;
private:
static std::mutex mutex;
static T* instance;
Q_DISABLE_COPY_MOVE(Singleton)
};
template <typename T>
std::mutex Singleton<T>::mutex;
template <typename T>
T* Singleton<T>::instance;
template <typename T>
T* Singleton<T>::getInstance() {
static QMutex mutex;
QMutexLocker locker(&mutex);
static T* instance = nullptr;
if (instance == nullptr) {
std::lock_guard<std::mutex> locker(mutex);
if (instance == nullptr) {
instance = new T();
}
instance = new T();
}
return instance;
}
#define SINGLETONG(Class) \
private: \
#define SINGLETON(Class) \
private: \
friend class Singleton<Class>; \
friend struct QScopedPointerDeleter<Class>; \
\
public: \
static Class* getInstance() { \
public: \
static Class* getInstance() { \
return Singleton<Class>::getInstance(); \
}
#define HIDE_CONSTRUCTOR(Class) \
private: \
Class() = default; \
Class(const Class& other) = delete; \
Q_DISABLE_COPY_MOVE(Class);
#endif // SINGLETON_H

View File

@ -2,20 +2,36 @@
#define STDAFX_H
#define Q_PROPERTY_AUTO(TYPE, M) \
Q_PROPERTY(TYPE M MEMBER _##M NOTIFY M##Changed) \
public: \
Q_SIGNAL void M##Changed(); \
void M(TYPE in_##M) \
{ \
_##M = in_##M; \
Q_EMIT M##Changed(); \
} \
TYPE M() \
{ \
return _##M; \
} \
\
private: \
TYPE _##M;
Q_PROPERTY(TYPE M MEMBER _##M NOTIFY M##Changed) \
public: \
Q_SIGNAL void M##Changed(); \
void M(TYPE in_##M) \
{ \
_##M = in_##M; \
Q_EMIT M##Changed(); \
} \
TYPE M() \
{ \
return _##M; \
} \
private: \
TYPE _##M; \
#define Q_PROPERTY_READONLY_AUTO(TYPE, M) \
Q_PROPERTY(TYPE M READ M NOTIFY M##Changed FINAL) \
public: \
Q_SIGNAL void M##Changed(); \
void M(TYPE in_##M) \
{ \
_##M = in_##M; \
Q_EMIT M##Changed(); \
} \
TYPE M() \
{ \
return _##M; \
} \
private: \
TYPE _##M; \
#endif // STDAFX_H

View File

@ -14,6 +14,7 @@ if (FLUENTUI_BUILD_STATIC_LIB)
add_definitions(-DFLUENTUI_BUILD_STATIC_LIB)
endif()
#导入Qt相关依赖包
find_package(QT NAMES Qt6 Qt5 REQUIRED COMPONENTS Core Quick Qml)
find_package(Qt${QT_VERSION_MAJOR} REQUIRED COMPONENTS Core Quick Qml)
@ -64,7 +65,6 @@ if(QT_VERSION VERSION_GREATER_EQUAL "6.2")
endforeach()
endif()
#添加qml模块
if (FLUENTUI_BUILD_STATIC_LIB)
set(LIB_TYPE "STATIC")
else()
@ -89,6 +89,7 @@ if(WIN32)
endif()
if(QT_VERSION VERSION_GREATER_EQUAL "6.2")
#如果是Qt6.2版本以上则使用qt_add_libraryqt_add_qml_module函数添加资源文件
if(FLUENTUI_BUILD_STATIC_LIB)
set(FLUENTUI_QML_PLUGIN_DIRECTORY ${CMAKE_BINARY_DIR}/FluentUI)
endif()
@ -106,6 +107,7 @@ if(QT_VERSION VERSION_GREATER_EQUAL "6.2")
RESOURCE_PREFIX "/qt/qml"
)
else()
#如果是Qt6.2版本以下则使用add_qmlplugin函数添加资源文件这是个自定义的函数详情见.cmake/QmlPlugin.cmake
include(QmlPlugin)
add_qmlplugin(${PROJECT_NAME}
URI "FluentUI"
@ -120,6 +122,7 @@ endif()
target_compile_definitions(${PROJECT_NAME}
PRIVATE
#导入qrcode配置文件
HAVE_CONFIG_H
)

View File

@ -145,7 +145,7 @@ enum TabWidthBehavior {
};
Q_ENUM_NS(TabWidthBehavior)
enum CloseButtonVisibility {
Nerver = 0x0000,
Never = 0x0000,
Always = 0x0001,
OnHover = 0x0002
};

View File

@ -29,7 +29,7 @@ private:
explicit FluApp(QObject *parent = nullptr);
~FluApp();
public:
SINGLETONG(FluApp)
SINGLETON(FluApp)
static FluApp *create(QQmlEngine *qmlEngine, QJSEngine *jsEngine){return getInstance();}
Q_INVOKABLE void run();
Q_INVOKABLE void navigate(const QString& route,const QJsonObject& argument = {},FluRegister* fluRegister = nullptr);
@ -39,7 +39,7 @@ public:
void removeWindow(QQuickWindow* window);
private:
QMap<quint64, QQuickWindow*> _windows;
QObject* _application;
QObject* _application = nullptr;
};
#endif // FLUAPP_H

View File

@ -2,6 +2,7 @@
#define FLUCOLORSET_H
#include <QObject>
#include <QtQml/qqml.h>
#include "stdafx.h"
/**
@ -17,6 +18,7 @@ class FluColorSet : public QObject
Q_PROPERTY_AUTO(QString,light)
Q_PROPERTY_AUTO(QString,lighter)
Q_PROPERTY_AUTO(QString,lightest)
QML_NAMED_ELEMENT(FluColorSet)
public:
explicit FluColorSet(QObject *parent = nullptr);
};

View File

@ -27,7 +27,7 @@ FluColors::FluColors(QObject *parent):QObject{parent}{
Grey210("#161514");
Grey220("#11100f");
FluColorSet *yellow = new FluColorSet();
FluColorSet *yellow = new FluColorSet(this);
yellow->darkest("#f9a825");
yellow->darker("#fbc02d");
yellow->dark("#fdd435");
@ -37,7 +37,7 @@ FluColors::FluColors(QObject *parent):QObject{parent}{
yellow->lightest("#fff59b");
Yellow(yellow);
FluColorSet *orange = new FluColorSet();
FluColorSet *orange = new FluColorSet(this);
orange->darkest("#993d07");
orange->darker("#ac4408");
orange->dark("#d1580a");
@ -47,7 +47,7 @@ FluColors::FluColors(QObject *parent):QObject{parent}{
orange->lightest("#fac06a");
Orange(orange);
FluColorSet *red = new FluColorSet();
FluColorSet *red = new FluColorSet(this);
red->darkest("#8f0a15");
red->darker("#a20b18");
red->dark("#b90d1c");
@ -57,7 +57,7 @@ FluColors::FluColors(QObject *parent):QObject{parent}{
red->lightest("#f06b76");
Red(red);
FluColorSet *magenta = new FluColorSet();
FluColorSet *magenta = new FluColorSet(this);
magenta->darkest("#6f004f");
magenta->darker("#a0076c");
magenta->dark("#b50d7d");
@ -67,7 +67,7 @@ FluColors::FluColors(QObject *parent):QObject{parent}{
magenta->lightest("#f18cd5");
Magenta(magenta);
FluColorSet *purple = new FluColorSet();
FluColorSet *purple = new FluColorSet(this);
purple->darkest("#2c0f76");
purple->darker("#3d0f99");
purple->dark("#4e11ae");
@ -77,7 +77,7 @@ FluColors::FluColors(QObject *parent):QObject{parent}{
purple->lightest("#9e8ed9");
Purple(purple);
FluColorSet *blue = new FluColorSet();
FluColorSet *blue = new FluColorSet(this);
blue->darkest("#004A83");
blue->darker("#005494");
blue->dark("#0066B4");
@ -87,7 +87,7 @@ FluColors::FluColors(QObject *parent):QObject{parent}{
blue->lightest("#60ABE4");
Blue(blue);
FluColorSet *teal = new FluColorSet();
FluColorSet *teal = new FluColorSet(this);
teal->darkest("#006E5B");
teal->darker("#007C67");
teal->dark("#00977D");
@ -97,7 +97,7 @@ FluColors::FluColors(QObject *parent):QObject{parent}{
teal->lightest("#60CFBC");
Teal(teal);
FluColorSet *green = new FluColorSet();
FluColorSet *green = new FluColorSet(this);
green->darkest("#094C09");
green->darker("#0C5D0C");
green->dark("#0E6F0E");

View File

@ -51,7 +51,7 @@ class FluColors : public QObject
private:
explicit FluColors(QObject *parent = nullptr);
public:
SINGLETONG(FluColors)
SINGLETON(FluColors)
static FluColors *create(QQmlEngine *qmlEngine, QJSEngine *jsEngine){return getInstance();}
};

View File

@ -23,7 +23,7 @@ class FluEventBus : public QObject
private:
explicit FluEventBus(QObject *parent = nullptr);
public:
SINGLETONG(FluEventBus)
SINGLETON(FluEventBus)
static FluEventBus *create(QQmlEngine *qmlEngine, QJSEngine *jsEngine){return getInstance();}
Q_INVOKABLE void registerEvent(FluEvent* event);
Q_INVOKABLE void unRegisterEvent(FluEvent* event);

View File

@ -1,11 +1,14 @@
#include "FluFramelessHelper.h"
#include <QGuiApplication>
#include <QOperatingSystemVersion>
#include <QScreen>
#include "FluTools.h"
#ifdef Q_OS_WIN
#pragma comment (lib,"user32.lib")
#pragma comment (lib,"dwmapi.lib")
#include <windows.h>
#include <windowsx.h>
#include <dwmapi.h>
static inline QByteArray qtNativeEventType()
@ -13,6 +16,7 @@ static inline QByteArray qtNativeEventType()
static const auto result = "windows_generic_MSG";
return result;
}
static inline bool isCompositionEnabled(){
typedef HRESULT (WINAPI* DwmIsCompositionEnabledPtr)(BOOL *pfEnabled);
HMODULE module = LoadLibraryW(L"dwmapi.dll");
@ -29,42 +33,21 @@ static inline bool isCompositionEnabled(){
}
return false;
}
static inline void showShadow(HWND hwnd){
if(isCompositionEnabled()){
const MARGINS shadow = { 1, 1, 1, 1 };
typedef HRESULT (WINAPI* DwmExtendFrameIntoClientAreaPtr)(HWND hWnd, const MARGINS *pMarInset);
HMODULE module = LoadLibraryW(L"dwmapi.dll");
if (module)
{
DwmExtendFrameIntoClientAreaPtr dwm_extendframe_into_client_area_;
dwm_extendframe_into_client_area_= reinterpret_cast<DwmExtendFrameIntoClientAreaPtr>(GetProcAddress(module, "DwmExtendFrameIntoClientArea"));
if (dwm_extendframe_into_client_area_)
{
dwm_extendframe_into_client_area_(hwnd, &shadow);
}
}
}else{
ULONG_PTR cNewStyle = GetClassLongPtr(hwnd, GCL_STYLE) | CS_DROPSHADOW;
SetClassLongPtr(hwnd, GCL_STYLE, cNewStyle);
}
}
#endif
FramelessEventFilter::FramelessEventFilter(QQuickWindow* window){
_window = window;
_current = window->winId();
FramelessEventFilter::FramelessEventFilter(FluFramelessHelper* helper){
_helper = helper;
_current = _helper->window->winId();
}
bool FramelessEventFilter::nativeEventFilter(const QByteArray &eventType, void *message, QT_NATIVE_EVENT_RESULT_TYPE *result){
#ifdef Q_OS_WIN
if ((eventType != qtNativeEventType()) || !message || !result || !_window) {
if ((eventType != qtNativeEventType()) || !message || _helper.isNull() || _helper->window.isNull()) {
return false;
}
const auto msg = static_cast<const MSG *>(message);
const HWND hwnd = msg->hwnd;
if (!hwnd) {
if (!hwnd || !msg) {
return false;
}
const qint64 wid = reinterpret_cast<qint64>(hwnd);
@ -74,34 +57,89 @@ bool FramelessEventFilter::nativeEventFilter(const QByteArray &eventType, void *
const UINT uMsg = msg->message;
const WPARAM wParam = msg->wParam;
const LPARAM lParam = msg->lParam;
if (!msg || !hwnd)
{
return false;
}
static QPoint offsetXY;
if(uMsg == WM_WINDOWPOSCHANGING){
WINDOWPOS* wp = reinterpret_cast<WINDOWPOS*>(lParam);
if (wp != nullptr && (wp->flags & SWP_NOSIZE) == 0)
{
wp->flags |= SWP_NOCOPYBITS;
*result = DefWindowProc(hwnd, uMsg, wParam, lParam);
*result = DefWindowProcW(hwnd, uMsg, wParam, lParam);
return true;
}
return false;
}else if(uMsg == WM_NCCALCSIZE){
const auto clientRect = ((wParam == FALSE) ? reinterpret_cast<LPRECT>(lParam) : &(reinterpret_cast<LPNCCALCSIZE_PARAMS>(lParam))->rgrc[0]);
const LONG originalTop = clientRect->top;
const LONG originalLeft = clientRect->left;
#if QT_VERSION < QT_VERSION_CHECK(6,0,0)
const LONG originalRight = clientRect->right;
const LONG originalBottom = clientRect->bottom;
#endif
const LRESULT hitTestResult = ::DefWindowProcW(hwnd, WM_NCCALCSIZE, wParam, lParam);
if ((hitTestResult != HTERROR) && (hitTestResult != HTNOWHERE)) {
*result = hitTestResult;
return true;
}
int offsetSize = 0;
bool isMaximum = IsZoomed(hwnd);
offsetXY = QPoint(abs(clientRect->left - originalLeft),abs(clientRect->top - originalTop));
if(isMaximum || _helper->window->visibility() == QWindow::FullScreen){
_helper->setOriginalPos(QPoint(originalLeft,originalTop));
offsetSize = 0;
}else{
_helper->setOriginalPos({});
offsetSize = 1;
}
if(!isCompositionEnabled()){
offsetSize = 0;
}
clientRect->top = originalTop+offsetSize;
#if QT_VERSION < QT_VERSION_CHECK(6,0,0)
if(!isMaximum){
clientRect->bottom = originalBottom-offsetSize;
clientRect->left = originalLeft+offsetSize;
clientRect->right = originalRight-offsetSize;
}
#endif
*result = WVR_REDRAW;
return true;
}else if(uMsg == WM_NCPAINT){
if(!isCompositionEnabled()){
*result = WVR_REDRAW;
}if(uMsg == WM_NCHITTEST){
if(FluTools::getInstance()->isWindows11OrGreater() && _helper->hoverMaxBtn() && _helper->resizeable()){
if (*result == HTNOWHERE) {
*result = HTZOOM;
}
return true;
}
*result = HTCLIENT;
return true;
}else if(uMsg == WM_NCLBUTTONDBLCLK || uMsg == WM_NCLBUTTONDOWN){
if(FluTools::getInstance()->isWindows11OrGreater() && _helper->hoverMaxBtn() && _helper->resizeable()){
QMouseEvent event = QMouseEvent(QEvent::MouseButtonPress, QPoint(), QPoint(), Qt::LeftButton, Qt::LeftButton, Qt::NoModifier);
QGuiApplication::sendEvent(_helper->maximizeButton(),&event);
return true;
}
return false;
}else if(uMsg == WM_NCACTIVATE){
if(!isCompositionEnabled()){
*result = 1;
return true;
}else if(uMsg == WM_NCLBUTTONUP || uMsg == WM_NCRBUTTONUP){
if(FluTools::getInstance()->isWindows11OrGreater() && _helper->hoverMaxBtn() && _helper->resizeable()){
QMouseEvent event = QMouseEvent(QEvent::MouseButtonRelease, QPoint(), QPoint(), Qt::LeftButton, Qt::LeftButton, Qt::NoModifier);
QGuiApplication::sendEvent(_helper->maximizeButton(),&event);
}
return false;
}else if(uMsg == WM_NCPAINT){
*result = FALSE;
return true;
}else if(uMsg == WM_NCACTIVATE){
*result = DefWindowProcW(hwnd, WM_NCACTIVATE, wParam, -1);
return true;
}else if(uMsg == WM_GETMINMAXINFO){
#if QT_VERSION < QT_VERSION_CHECK(6,0,0)
MINMAXINFO* minmaxInfo = reinterpret_cast<MINMAXINFO *>(lParam);
auto pixelRatio = _helper->window->devicePixelRatio();
auto geometry = _helper->window->screen()->availableGeometry();
minmaxInfo->ptMaxSize.x = geometry.width()*pixelRatio + offsetXY.x()*2;
minmaxInfo->ptMaxSize.y = geometry.height()*pixelRatio + offsetXY.y()*2;
#endif
return false;
}
return false;
#endif
@ -111,56 +149,58 @@ bool FramelessEventFilter::nativeEventFilter(const QByteArray &eventType, void *
FluFramelessHelper::FluFramelessHelper(QObject *parent)
: QObject{parent}
{
}
void FluFramelessHelper::classBegin(){
}
void FluFramelessHelper::updateCursor(int edges){
void FluFramelessHelper::_updateCursor(int edges){
switch (edges) {
case 0:
_window->setCursor(Qt::ArrowCursor);
window->setCursor(Qt::ArrowCursor);
break;
case Qt::LeftEdge:
case Qt::RightEdge:
_window->setCursor(Qt::SizeHorCursor);
window->setCursor(Qt::SizeHorCursor);
break;
case Qt::TopEdge:
case Qt::BottomEdge:
_window->setCursor(Qt::SizeVerCursor);
window->setCursor(Qt::SizeVerCursor);
break;
case Qt::LeftEdge | Qt::TopEdge:
case Qt::RightEdge | Qt::BottomEdge:
_window->setCursor(Qt::SizeFDiagCursor);
window->setCursor(Qt::SizeFDiagCursor);
break;
case Qt::RightEdge | Qt::TopEdge:
case Qt::LeftEdge | Qt::BottomEdge:
_window->setCursor(Qt::SizeBDiagCursor);
window->setCursor(Qt::SizeBDiagCursor);
break;
}
}
bool FluFramelessHelper::eventFilter(QObject *obj, QEvent *ev){
if (!_window.isNull() && _window->flags() & Qt::FramelessWindowHint) {
static int edges = 0;
const int margin = 8;
if (!window.isNull() && window->flags()) {
static int margin = 8;
switch (ev->type()) {
case QEvent::MouseButtonPress:
if(edges!=0){
updateCursor(edges);
_window->startSystemResize(Qt::Edges(edges));
if(_edges!=0){
QMouseEvent *event = static_cast<QMouseEvent*>(ev);
if(event->button() == Qt::LeftButton){
_updateCursor(_edges);
window->startSystemResize(Qt::Edges(_edges));
}
}
break;
case QEvent::MouseButtonRelease:
edges = 0;
updateCursor(edges);
_edges = 0;
_updateCursor(_edges);
break;
case QEvent::MouseMove: {
if(_window->visibility() == QWindow::Maximized || _window->visibility() == QWindow::FullScreen){
if(_maximized() || _fullScreen()){
break;
}
if(_window->width() == _window->maximumWidth() && _window->width() == _window->minimumWidth() && _window->height() == _window->maximumHeight() && _window->height() == _window->minimumHeight()){
if(!resizeable()){
break;
}
QMouseEvent *event = static_cast<QMouseEvent*>(ev);
@ -170,27 +210,27 @@ bool FluFramelessHelper::eventFilter(QObject *obj, QEvent *ev){
#else
event->position().toPoint();
#endif
if(p.x() >= margin && p.x() <= (_window->width() - margin) && p.y() >= margin && p.y() <= (_window->height() - margin)){
if(edges != 0){
edges = 0;
updateCursor(edges);
if(p.x() >= margin && p.x() <= (window->width() - margin) && p.y() >= margin && p.y() <= (window->height() - margin)){
if(_edges != 0){
_edges = 0;
_updateCursor(_edges);
}
break;
}
edges = 0;
_edges = 0;
if ( p.x() < margin ) {
edges |= Qt::LeftEdge;
_edges |= Qt::LeftEdge;
}
if ( p.x() > (_window->width() - margin) ) {
edges |= Qt::RightEdge;
if ( p.x() > (window->width() - margin) ) {
_edges |= Qt::RightEdge;
}
if ( p.y() < margin ) {
edges |= Qt::TopEdge;
_edges |= Qt::TopEdge;
}
if ( p.y() > (_window->height() - margin) ) {
edges |= Qt::BottomEdge;
if ( p.y() > (window->height() - margin) ) {
_edges |= Qt::BottomEdge;
}
updateCursor(edges);
_updateCursor(_edges);
break;
}
default:
@ -203,54 +243,146 @@ bool FluFramelessHelper::eventFilter(QObject *obj, QEvent *ev){
void FluFramelessHelper::componentComplete(){
auto o = parent();
while (nullptr != o) {
_window = (QQuickWindow*)o;
window = (QQuickWindow*)o;
o = o->parent();
}
if(!_window.isNull()){
_window->setFlags(Qt::FramelessWindowHint|Qt::Window|Qt::WindowTitleHint|Qt::WindowMinMaxButtonsHint|Qt::WindowCloseButtonHint);
if(!window.isNull()){
_stayTop = QQmlProperty(window,"stayTop");
_screen = QQmlProperty(window,"screen");
_fixSize = QQmlProperty(window,"fixSize");
_originalPos = QQmlProperty(window,"_originalPos");
_realHeight = QQmlProperty(window,"_realHeight");
_realWidth = QQmlProperty(window,"_realWidth");
_appBarHeight = QQmlProperty(window,"_appBarHeight");
#ifdef Q_OS_WIN
_nativeEvent =new FramelessEventFilter(_window);
window->setFlag(Qt::CustomizeWindowHint,true);
_nativeEvent =new FramelessEventFilter(this);
qApp->installNativeEventFilter(_nativeEvent);
HWND hwnd = reinterpret_cast<HWND>(_window->winId());
SetWindowPos(hwnd,nullptr,0,0,0,0,SWP_NOZORDER | SWP_NOOWNERZORDER | SWP_NOMOVE | SWP_NOSIZE |SWP_FRAMECHANGED);
showShadow(hwnd);
HWND hwnd = reinterpret_cast<HWND>(window->winId());
DWORD style = ::GetWindowLong(hwnd, GWL_STYLE);
if(resizeable()){
SetWindowLongPtr(hwnd, GWL_STYLE, style | WS_MAXIMIZEBOX | WS_THICKFRAME);
}else{
SetWindowLongPtr(hwnd, GWL_STYLE, style | WS_THICKFRAME);
}
SetWindowPos(hwnd,nullptr,0,0,0,0,SWP_NOZORDER | SWP_NOOWNERZORDER | SWP_NOMOVE | SWP_NOSIZE | SWP_FRAMECHANGED);
#else
window->setFlags((window->flags() & (~Qt::WindowMinMaxButtonsHint) & (~Qt::Dialog)) | Qt::FramelessWindowHint | Qt::Window);
#endif
_stayTop = QQmlProperty(_window,"stayTop");
int w = _realWidth.read().toInt();
int h = _realHeight.read().toInt()+_appBarHeight.read().toInt();
if(!resizeable()){
window->setMaximumSize(QSize(w,h));
window->setMinimumSize(QSize(w,h));
}
window->setWidth(w);
window->setHeight(h);
_onStayTopChange();
_stayTop.connectNotifySignal(this,SLOT(_onStayTopChange()));
_screen = QQmlProperty(_window,"screen");
_screen.connectNotifySignal(this,SLOT(_onScreenChanged()));
_window->installEventFilter(this);
window->installEventFilter(this);
Q_EMIT loadCompleted();
}
}
void FluFramelessHelper::_onScreenChanged(){
_window->update();
QGuiApplication::processEvents();
#ifdef Q_OS_WIN
HWND hwnd = reinterpret_cast<HWND>(window->winId());
SetWindowPos(hwnd,0,0,0,0,0,SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER | SWP_FRAMECHANGED | SWP_NOOWNERZORDER);
RedrawWindow(hwnd, NULL, NULL, RDW_INVALIDATE | RDW_UPDATENOW);
#endif
}
void FluFramelessHelper::showSystemMenu(){
#ifdef Q_OS_WIN
QPoint point = QCursor::pos();
HWND hwnd = reinterpret_cast<HWND>(window->winId());
DWORD style = GetWindowLongPtr(hwnd,GWL_STYLE);
SetWindowLongPtr(hwnd, GWL_STYLE, style | WS_SYSMENU);
const HMENU hMenu = ::GetSystemMenu(hwnd, FALSE);
DeleteMenu(hMenu, SC_MOVE, MF_BYCOMMAND);
DeleteMenu(hMenu, SC_SIZE, MF_BYCOMMAND);
if(_maximized() || _fullScreen()){
EnableMenuItem(hMenu,SC_RESTORE,MFS_ENABLED);
}else{
EnableMenuItem(hMenu,SC_RESTORE,MFS_DISABLED);
}
if(resizeable() && !_maximized() && !_fullScreen()){
EnableMenuItem(hMenu,SC_MAXIMIZE,MFS_ENABLED);
}else{
EnableMenuItem(hMenu,SC_MAXIMIZE,MFS_DISABLED);
}
const int result = TrackPopupMenu(hMenu, (TPM_RETURNCMD | (QGuiApplication::isRightToLeft() ? TPM_RIGHTALIGN : TPM_LEFTALIGN)), point.x()*window->devicePixelRatio(), point.y()*window->devicePixelRatio(), 0, hwnd, nullptr);
if (result != FALSE) {
PostMessageW(hwnd, WM_SYSCOMMAND, result, 0);
}
SetWindowLongPtr(hwnd, GWL_STYLE, style &~ WS_SYSMENU);
#endif
}
void FluFramelessHelper::_onStayTopChange(){
bool isStayTop = _stayTop.read().toBool();
#ifdef Q_OS_WIN
HWND hwnd = reinterpret_cast<HWND>(_window->winId());
DWORD style = GetWindowLongPtr(hwnd,GWL_STYLE);
SetWindowLongPtr(hwnd, GWL_STYLE, style | WS_THICKFRAME | WS_CAPTION &~ WS_SYSMENU);
HWND hwnd = reinterpret_cast<HWND>(window->winId());
if(isStayTop){
SetWindowPos(hwnd, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE);
}else{
SetWindowPos(hwnd, HWND_NOTOPMOST, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE);
}
#else
_window->setFlag(Qt::WindowStaysOnTopHint,isStayTop);
window->setFlag(Qt::WindowStaysOnTopHint,isStayTop);
#endif
}
FluFramelessHelper::~FluFramelessHelper(){
if (!_window.isNull()) {
_window->setFlags(Qt::Window);
if (!window.isNull()) {
window->setFlags(Qt::Window);
#ifdef Q_OS_WIN
qApp->removeNativeEventFilter(_nativeEvent);
delete _nativeEvent;
#endif
_window->removeEventFilter(this);
window->removeEventFilter(this);
}
}
bool FluFramelessHelper::hoverMaxBtn(){
QVariant appBar = window->property("appBar");
if(appBar.isNull()){
return false;
}
QVariant var;
QMetaObject::invokeMethod(appBar.value<QObject*>(), "maximizeButtonHover",Q_RETURN_ARG(QVariant, var));
if(var.isNull()){
return false;
}
return var.toBool();
}
QObject* FluFramelessHelper::maximizeButton(){
QVariant appBar = window->property("appBar");
if(appBar.isNull()){
return nullptr;
}
QVariant var;
QMetaObject::invokeMethod(appBar.value<QObject*>(), "maximizeButton",Q_RETURN_ARG(QVariant, var));
if(var.isNull()){
return nullptr;
}
return var.value<QObject*>();
}
void FluFramelessHelper::setOriginalPos(QVariant pos){
_originalPos.write(pos);
}
bool FluFramelessHelper::resizeable(){
return !_fixSize.read().toBool();
}
bool FluFramelessHelper::_maximized(){
return window->visibility() == QWindow::Maximized;
}
bool FluFramelessHelper::_fullScreen(){
return window->visibility() == QWindow::FullScreen;
}

View File

@ -15,13 +15,15 @@ using QT_NATIVE_EVENT_RESULT_TYPE = long;
using QT_ENTER_EVENT_TYPE = QEvent;
#endif
class FluFramelessHelper;
class FramelessEventFilter : public QAbstractNativeEventFilter
{
public:
FramelessEventFilter(QQuickWindow* window);
FramelessEventFilter(FluFramelessHelper* helper);
bool nativeEventFilter(const QByteArray &eventType, void *message, QT_NATIVE_EVENT_RESULT_TYPE *result) override;
public:
QQuickWindow* _window = nullptr;
QPointer<FluFramelessHelper> _helper = nullptr;
qint64 _current = 0;
};
@ -34,17 +36,32 @@ public:
~FluFramelessHelper();
void classBegin() override;
void componentComplete() override;
bool hoverMaxBtn();
bool resizeable();
QObject* maximizeButton();
void setOriginalPos(QVariant pos);
Q_INVOKABLE void showSystemMenu();
Q_SIGNAL void loadCompleted();
protected:
bool eventFilter(QObject *obj, QEvent *event) override;
private:
void updateCursor(int edges);
void _updateCursor(int edges);
bool _maximized();
bool _fullScreen();
Q_SLOT void _onStayTopChange();
Q_SLOT void _onScreenChanged();
public:
QPointer<QQuickWindow> window = nullptr;
private:
QPointer<QQuickWindow> _window = nullptr;
FramelessEventFilter* _nativeEvent = nullptr;
QQmlProperty _stayTop;
QQmlProperty _screen;
QQmlProperty _originalPos;
QQmlProperty _fixSize;
QQmlProperty _realHeight;
QQmlProperty _realWidth;
QQmlProperty _appBarHeight;
int _edges = 0;
};
#endif // FLUFRAMELESSHELPER_H

View File

@ -162,7 +162,7 @@ QString NetworkParams::buildCacheKey(){
void NetworkParams::go(NetworkCallable* callable){
QJSValueList data;
data<<qjsEngine(FluNetwork::getInstance())->newQObject(this);
data<<qjsEngine(callable)->newQObject(this);
FluNetwork::getInstance()->_interceptor.call(data);
if(_downloadParam){
FluNetwork::getInstance()->handleDownload(this,callable);
@ -364,6 +364,18 @@ void FluNetwork::handleDownload(NetworkParams* params,NetworkCallable* c){
}
});
loop.exec();
int httpStatus = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt();
if(httpStatus == 200){
if(!callable.isNull()){
callable->success(destPath);
}
printRequestEndLog(request,params,reply,destPath);
}else{
if(!callable.isNull()){
callable->error(httpStatus,reply->errorString(),destPath);
}
printRequestEndLog(request,params,reply,destPath);
}
if(conn_destoryed){
disconnect(conn_destoryed);
}

View File

@ -104,7 +104,7 @@ class FluNetwork : public QObject
private:
explicit FluNetwork(QObject *parent = nullptr);
public:
SINGLETONG(FluNetwork)
SINGLETON(FluNetwork)
static FluNetwork *create(QQmlEngine *qmlEngine, QJSEngine *jsEngine){return getInstance();}
Q_INVOKABLE NetworkParams* get(const QString& url);
Q_INVOKABLE NetworkParams* head(const QString& url);

View File

@ -23,7 +23,7 @@ public:
private:
explicit FluTextStyle(QObject *parent = nullptr);
public:
SINGLETONG(FluTextStyle)
SINGLETON(FluTextStyle)
static FluTextStyle *create(QQmlEngine *qmlEngine, QJSEngine *jsEngine){return getInstance();}
};

View File

@ -40,7 +40,7 @@ private:
bool systemDark();
void refreshColors();
public:
SINGLETONG(FluTheme)
SINGLETON(FluTheme)
Q_INVOKABLE QJsonArray awesomeList(const QString& keyword = "");
Q_SIGNAL void darkChanged();
static FluTheme *create(QQmlEngine *qmlEngine, QJSEngine *jsEngine){return getInstance();}

View File

@ -14,6 +14,7 @@
#include <QTextDocument>
#include <QQuickWindow>
#include <QDateTime>
#include <QSettings>
FluTools::FluTools(QObject *parent):QObject{parent}{
@ -179,3 +180,67 @@ qint64 FluTools::currentTimestamp(){
QIcon FluTools::windowIcon(){
return QGuiApplication::windowIcon();
}
int FluTools::cursorScreenIndex(){
int screenIndex = 0;
int screenCount = qApp->screens().count();
if (screenCount > 1) {
QPoint pos = QCursor::pos();
for (int i = 0; i < screenCount; ++i) {
if (qApp->screens().at(i)->geometry().contains(pos)) {
screenIndex = i;
break;
}
}
}
return screenIndex;
}
int FluTools::windowBuildNumber(){
#if defined(Q_OS_WIN)
QSettings regKey {QString::fromUtf8("HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion"), QSettings::NativeFormat};
if (regKey.contains(QString::fromUtf8("CurrentBuildNumber"))) {
auto buildNumber = regKey.value(QString::fromUtf8("CurrentBuildNumber")).toInt();
return buildNumber;
}
#endif
return -1;
}
bool FluTools::isWindows11OrGreater(){
static QVariant var;
if(var.isNull()){
#if defined(Q_OS_WIN)
auto buildNumber = windowBuildNumber();
if(buildNumber>=22000){
var = QVariant::fromValue(true);
return true;
}
#endif
var = QVariant::fromValue(false);
return false;
}else{
return var.toBool();
}
}
bool FluTools::isWindows10OrGreater(){
static QVariant var;
if(var.isNull()){
#if defined(Q_OS_WIN)
auto buildNumber = windowBuildNumber();
if(buildNumber>=10240){
var = QVariant::fromValue(true);
return true;
}
#endif
var = QVariant::fromValue(false);
return false;
}else{
return var.toBool();
}
}
int FluTools::getTaskBarHeight(QQuickWindow* window){
return window->screen()->geometry().height() - window->screen()->availableGeometry().height();
}

View File

@ -5,6 +5,7 @@
#include <QFile>
#include <QColor>
#include <QtQml/qqml.h>
#include <QQuickWindow>
#include "singleton.h"
/**
@ -18,7 +19,7 @@ class FluTools : public QObject
private:
explicit FluTools(QObject *parent = nullptr);
public:
SINGLETONG(FluTools)
SINGLETON(FluTools)
static FluTools *create(QQmlEngine *qmlEngine, QJSEngine *jsEngine){return getInstance();}
Q_INVOKABLE int qtMajor();
Q_INVOKABLE int qtMinor();
@ -50,6 +51,11 @@ public:
Q_INVOKABLE qint64 currentTimestamp();
Q_INVOKABLE QPoint cursorPos();
Q_INVOKABLE QIcon windowIcon();
Q_INVOKABLE int cursorScreenIndex();
Q_INVOKABLE int windowBuildNumber();
Q_INVOKABLE bool isWindows11OrGreater();
Q_INVOKABLE bool isWindows10OrGreater();
Q_INVOKABLE int getTaskBarHeight(QQuickWindow* window);
};
#endif // FLUTOOLS_H

View File

@ -53,7 +53,7 @@ class ViewModelManager:public QObject{
private:
explicit ViewModelManager(QObject *parent = nullptr);
public:
SINGLETONG(ViewModelManager)
SINGLETON(ViewModelManager)
bool exist(const QString& key);
void insert(const QString& key,QObject* value);
QObject* getModel(const QString& key);

View File

@ -116,7 +116,6 @@ void FluentUI::registerTypes(const char *uri){
qmlRegisterType(QUrl("qrc:/qt/qml/FluentUI/Controls/FluSpinBox.qml"),uri,major,minor,"FluSpinBox");
qmlRegisterType(QUrl("qrc:/qt/qml/FluentUI/Controls/FluStatusView.qml"),uri,major,minor,"FluStatusView");
qmlRegisterType(QUrl("qrc:/qt/qml/FluentUI/Controls/FluTabView.qml"),uri,major,minor,"FluTabView");
qmlRegisterType(QUrl("qrc:/qt/qml/FluentUI/Controls/FluTableModelColumn.qml"),uri,major,minor,"FluTableModelColumn");
qmlRegisterType(QUrl("qrc:/qt/qml/FluentUI/Controls/FluTableView.qml"),uri,major,minor,"FluTableView");
qmlRegisterType(QUrl("qrc:/qt/qml/FluentUI/Controls/FluText.qml"),uri,major,minor,"FluText");
qmlRegisterType(QUrl("qrc:/qt/qml/FluentUI/Controls/FluTextBox.qml"),uri,major,minor,"FluTextBox");

View File

@ -9,7 +9,7 @@ class FluentUI : public QObject
{
Q_OBJECT
public:
SINGLETONG(FluentUI)
SINGLETON(FluentUI)
Q_DECL_EXPORT void registerTypes(QQmlEngine *engine);
void registerTypes(const char *uri);
void initializeEngine(QQmlEngine *engine, const char *uri);

View File

@ -44,6 +44,7 @@ Rectangle{
d.win.visibility = Window.Windowed
else
d.win.visibility = Window.Maximized
d.hoverMaxBtn = false
}
}
property var minClickListener: function(){
@ -64,6 +65,11 @@ Rectangle{
FluTheme.darkMode = FluThemeType.Dark
}
}
property var systemMenuListener: function(){
if(d.win instanceof FluWindow){
d.win.showSystemMenu()
}
}
id:control
color: Qt.rgba(0,0,0,0)
height: visible ? 30 : 0
@ -71,6 +77,7 @@ Rectangle{
z: 65535
Item{
id:d
property bool hoverMaxBtn: false
property var win: Window.window
property bool stayTop: {
if(d.win instanceof FluWindow){
@ -83,14 +90,23 @@ Rectangle{
}
MouseArea{
anchors.fill: parent
onPositionChanged: {
d.win.startSystemMove()
}
onDoubleClicked: {
if(d.resizable){
btn_maximize.clicked()
onPositionChanged:
(mouse)=>{
d.win.startSystemMove()
}
onDoubleClicked:
(mouse)=>{
if(d.resizable && Qt.LeftButton){
btn_maximize.clicked()
}
}
acceptedButtons: Qt.LeftButton|Qt.RightButton
onClicked:
(mouse)=>{
if (mouse.button === Qt.RightButton){
control.systemMenuListener()
}
}
}
}
Row{
anchors{
@ -218,6 +234,9 @@ Rectangle{
if(pressed){
return maximizePressColor
}
if(FluTools.isWindows11OrGreater()){
return d.hoverMaxBtn ? maximizeHoverColor : maximizeNormalColor
}
return hovered ? maximizeHoverColor : maximizeNormalColor
}
Layout.alignment: Qt.AlignVCenter
@ -263,4 +282,17 @@ Rectangle{
function darkButton(){
return btn_dark
}
function maximizeButtonHover(){
var hover = false;
var pos = btn_maximize.mapToGlobal(0,0)
if(btn_maximize.visible){
var rect = Qt.rect(pos.x,pos.y,btn_maximize.width,btn_maximize.height)
pos = FluTools.cursorPos()
if(pos.x>rect.x && pos.x<(rect.x+rect.width) && pos.y>rect.y && pos.y<(rect.y+rect.height)){
hover = true;
}
}
d.hoverMaxBtn = hover
return hover;
}
}

View File

@ -99,12 +99,12 @@ FluTextBox{
loadData()
if(d.flagVisible){
var pos = control.mapToItem(null, 0, 0)
if(d.window.height>pos.y+control.height+container.height){
if(window.height>pos.y+control.height+container.implicitHeight){
control_popup.y = control.height
} else if(pos.y>container.height){
control_popup.y = -container.height
} else if(pos.y>container.implicitHeight){
control_popup.y = -container.implicitHeight
} else {
popup.y = d.window.height-(pos.y+container.height)
control_popup.y = window.height-(pos.y+container.implicitHeight)
}
control_popup.visible = true
}

View File

@ -102,6 +102,7 @@ T.ComboBox {
height: Math.min(contentItem.implicitHeight, control.Window.height - topMargin - bottomMargin)
topMargin: 6
bottomMargin: 6
modal: true
contentItem: ListView {
clip: true
implicitHeight: contentHeight

View File

@ -36,7 +36,7 @@ FluPopup {
clip: true
boundsBehavior:Flickable.StopAtBounds
width: parent.width
height: Math.min(text_message.height,300)
height: message === "" ? 0 : Math.min(text_message.height,300)
ScrollBar.vertical: FluScrollBar {}
FluText{
id:text_message

View File

@ -64,6 +64,7 @@ TextArea{
anchors.fill: parent
cursorShape: Qt.IBeamCursor
acceptedButtons: Qt.RightButton
visible: !readOnly
onClicked: control.echoMode !== TextInput.Password && menu.popup()
}
FluTextBoxMenu{

View File

@ -41,15 +41,22 @@ Item {
function handleItems(){
var _idx = 0
var data = []
var comEmpty = Qt.createComponent("FluPaneItemEmpty.qml");
if(items){
for(var i=0;i<items.children.length;i++){
var item = items.children[i]
if(item.visible !== true){
continue
}
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]
if(itemChild.visible !== true){
continue
}
itemChild._parent = item
itemChild._idx = _idx
data.push(itemChild)
@ -58,20 +65,33 @@ Item {
}
}
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++
if(itemFooter.visible !== true){
continue
}
var objEmpty = comEmpty.createObject(items,{_idx:_idx});
itemFooter._idx = _idx;
data.push(objEmpty)
_idx++
}
}
}
return data
}
function handleFooterItems(){
var data = []
if(footerItems){
for(var i=0;i<footerItems.children.length;i++){
var item = footerItems.children[i]
if(item.visible !== true){
continue
}
data.push(item)
}
}
return data;
}
}
Component.onCompleted: {
d.displayMode = Qt.binding(function(){
@ -257,6 +277,9 @@ Item {
}
for(var i=0;i<model.children.length;i++){
var item = model.children[i]
if(item.visible !== true){
continue
}
if(item._idx === nav_list.currentIndex && !model.isExpand){
return true
}
@ -1039,11 +1062,7 @@ Item {
interactive: false
boundsBehavior: ListView.StopAtBounds
currentIndex: -1
model: {
if(footerItems){
return footerItems.children
}
}
model: d.handleFooterItems()
highlightMoveDuration: 150
highlight: Item{
clip: true

View File

@ -7,22 +7,19 @@ QtObject {
property int _idx
property var _ext
property var _parent
property bool visible: true
property string title
property int order : 0
property var url
property bool disabled: false
property int icon
property bool iconVisible: true
property Component infoBadge
property bool recentlyAdded: false
property bool recentlyUpdated: false
property string desc
property var image
property int count: 0
property var onTapListener
property Component iconDelegate
property Component menuDelegate
property Component editDelegate
property var extra
property bool showEdit
signal tap
}

View File

@ -7,4 +7,5 @@ QtObject {
property int _idx
property var _ext
property var _parent
property bool visible: true
}

View File

@ -5,6 +5,7 @@ import FluentUI 1.0
FluObject {
readonly property string key : FluTools.uuid()
property int _idx
property bool visible: true
property string title
property var icon
property bool disabled: false

View File

@ -5,6 +5,7 @@ import FluentUI 1.0
QtObject {
readonly property string key : FluTools.uuid()
property int _idx
property bool visible: true
property string title
property var parent
}

View File

@ -5,6 +5,7 @@ import FluentUI 1.0
QtObject {
readonly property string key : FluTools.uuid()
property int _idx
property bool visible: true
property var parent
property real spacing
property int size:1

View File

@ -8,7 +8,7 @@ Button {
property string contentDescription: ""
QtObject{
id:d
property bool checked: rect_back.height == background.height
property bool checked: (rect_back.height === background.height) && (progress === 1)
}
property color normalColor: {
if(d.checked){
@ -70,7 +70,7 @@ Button {
color: FluTheme.primaryColor
anchors.bottom: parent.bottom
Behavior on height{
enabled: control.progress === 1
enabled: control.progress !== 0
SequentialAnimation {
PauseAnimation {
duration: FluTheme.enableAnimation ? 167 : 0

View File

@ -4,6 +4,7 @@ import FluentUI 1.0
T.Slider {
property bool tooltipEnabled: true
property string text: String(control.value)
id: control
to:100
stepSize:1
@ -68,6 +69,6 @@ T.Slider {
FluTooltip{
parent: control.handle
visible: control.tooltipEnabled && (control.pressed || control.hovered)
text:String(control.value)
text:control.text
}
}

View File

@ -236,7 +236,7 @@ Item {
width: visible ? 24 : 0
height: 24
visible: {
if(closeButtonVisibility === FluTabViewType.Nerver)
if(closeButtonVisibility === FluTabViewType.Never)
return false
if(closeButtonVisibility === FluTabViewType.OnHover)
return item_mouse_hove.containsMouse || item_btn_close.hovered

View File

@ -1,5 +0,0 @@
import Qt.labs.qmlmodels 1.0
TableModelColumn{
}

View File

@ -9,23 +9,23 @@ Rectangle {
property var dataSource
property color borderColor: FluTheme.dark ? "#252525" : "#e4e4e4"
property alias tableModel: table_model
property bool horizonalHeaderVisible: true
property bool verticalHeaderVisible: true
id:control
color: FluTheme.dark ? Qt.rgba(39/255,39/255,39/255,1) : Qt.rgba(251/255,251/255,253/255,1)
onColumnSourceChanged: {
if(columnSource.length!==0){
var com_column = Qt.createComponent("FluTableModelColumn.qml")
if (com_column.status === Component.Ready) {
var columns= []
var header_rows = {}
columnSource.forEach(function(item){
var column = com_column.createObject(table_model,{display:item.dataIndex});
columns.push(column)
header_rows[item.dataIndex] = item.title
})
table_model.columns = columns
header_model.columns = columns
d.header_rows = [header_rows]
}
var columns= []
var header_rows = {}
columnSource.forEach(function(item){
var column = Qt.createQmlObject('import Qt.labs.qmlmodels 1.0;TableModelColumn{}',table_model);
column.display = item.dataIndex
columns.push(column)
header_rows[item.dataIndex] = item.title
})
table_model.columns = columns
header_model.columns = columns
d.header_rows = [header_rows]
}
}
QtObject{
@ -382,8 +382,9 @@ Rectangle {
syncDirection: Qt.Horizontal
anchors.left: scroll_table.left
anchors.top: parent.top
visible: control.horizonalHeaderVisible
implicitWidth: syncView ? syncView.width : 0
implicitHeight: Math.max(1, contentHeight)
implicitHeight: visible ? Math.max(1, contentHeight) : 0
syncView: table_view
boundsBehavior: Flickable.StopAtBounds
clip: true
@ -519,7 +520,8 @@ Rectangle {
boundsBehavior: Flickable.StopAtBounds
anchors.top: scroll_table.top
anchors.left: parent.left
implicitWidth: Math.max(1, contentWidth)
visible: control.verticalHeaderVisible
implicitWidth: visible ? Math.max(1, contentWidth) : 0
implicitHeight: syncView ? syncView.height : 0
syncDirection: Qt.Vertical
syncView: table_view

View File

@ -62,6 +62,7 @@ TextField{
anchors.fill: parent
cursorShape: Qt.IBeamCursor
acceptedButtons: Qt.RightButton
visible: !readOnly
onClicked: control.echoMode !== TextInput.Password && menu.popup()
}
RowLayout{

View File

@ -40,7 +40,12 @@ Window {
property bool showStayTop: true
property bool autoMaximize: false
property bool useSystemAppBar
property color resizeBorderColor: FluTheme.dark ? Qt.rgba(80/255,80/255,80/255,1) : Qt.rgba(210/255,210/255,210/255,1)
property color resizeBorderColor: {
if(window.active){
return _accentColor
}
return FluTheme.dark ? "#3D3D3E" : "#A7A7A7"
}
property int resizeBorderWidth: 1
property var closeListener: function(event){
if(closeDestory){
@ -50,22 +55,28 @@ Window {
event.accepted = false
}
}
signal showSystemMenu
signal initArgument(var argument)
signal firstVisible()
property point _offsetXY : Qt.point(0,0)
property var _originalPos
property color _accentColor : FluTheme.dark ? "#333333" : "#6E6E6E"
property int _realHeight
property int _realWidth
property int _appBarHeight: appBar.height
id:window
maximumWidth: fixSize ? width : 16777215
maximumHeight: fixSize ? height : 16777215
minimumWidth: fixSize ? width : 0
minimumHeight: fixSize ? height : 0
color:"transparent"
Component.onCompleted: {
useSystemAppBar = FluApp.useSystemAppBar
if(!useSystemAppBar){
loader_frameless.sourceComponent = com_frameless
}
_realHeight = height
_realWidth = width
moveWindowToDesktopCenter()
fixWindowSize()
lifecycle.onCompleted(window)
initArgument(argument)
moveWindowToDesktopCenter()
useSystemAppBar = FluApp.useSystemAppBar
if(!useSystemAppBar){
loader_frameless_helper.sourceComponent = com_frameless_helper
}
if(window.autoMaximize){
window.showMaximized()
}else{
@ -75,6 +86,24 @@ Window {
Component.onDestruction: {
lifecycle.onDestruction()
}
on_OriginalPosChanged: {
if(_originalPos){
var dx = (_originalPos.x - screen.virtualX)/screen.devicePixelRatio
var dy = (_originalPos.y - screen.virtualY)/screen.devicePixelRatio
if(dx<0 && dy<0){
_offsetXY = Qt.point(Math.abs(dx)-1,Math.abs(dy)-1)
}else{
_offsetXY = Qt.point(0,0)
}
}else{
_offsetXY = Qt.point(0,0)
}
}
onShowSystemMenu: {
if(loader_frameless_helper.item){
loader_frameless_helper.item.showSystemMenu()
}
}
onVisibleChanged: {
if(visible && d.isFirstVisible){
window.firstVisible()
@ -91,8 +120,12 @@ Window {
function onClosing(event){closeListener(event)}
}
Component{
id:com_frameless
FluFramelessHelper{}
id:com_frameless_helper
FluFramelessHelper{
onLoadCompleted:{
window.moveWindowToDesktopCenter()
}
}
}
Component{
id:com_background
@ -169,34 +202,17 @@ Window {
}
}
FluLoader{
id:loader_frameless
id:loader_frameless_helper
}
Item{
id:layout_container
property int offsetX: {
if(window.visibility === Window.Maximized){
var dx = window.x-Screen.virtualX
if(dx<0){
return Math.abs(dx)
}
}
return 0
}
property int offsetY: {
if(window.visibility === Window.Maximized){
var dy = window.y-Screen.virtualY
if(dy<0){
return Math.abs(dy)
}
}
return 0
}
property bool isMaximum : window.visibility == Window.Maximized
anchors{
fill:parent
leftMargin: offsetX
rightMargin: offsetX
topMargin: offsetY
bottomMargin: offsetY
topMargin: _offsetXY.y
bottomMargin: isMaximum ? 0 : _offsetXY.y
leftMargin: isMaximum ? 0 :_offsetXY.x
rightMargin: isMaximum ? 0 : _offsetXY.x
}
onWidthChanged: {
window.appBar.width = width
@ -249,11 +265,17 @@ Window {
border.width: window.resizeBorderWidth
border.color: window.resizeBorderColor
visible: {
if(window.useSystemAppBar){
if(window.useSystemAppBar || FluTools.isWindows10OrGreater()){
return false
}
if(window.visibility == Window.Maximized || window.visibility == Window.FullScreen){
return false
if(FluTools.isMacos()){
if(window.visibility == Window.FullScreen){
return false
}
}else{
if(window.visibility == Window.Maximized || window.visibility == Window.FullScreen){
return false
}
}
return true
}
@ -286,7 +308,17 @@ Window {
return lifecycle.createRegister(window,path)
}
function moveWindowToDesktopCenter(){
window.setGeometry((Screen.width-window.width)/2+Screen.virtualX,(Screen.height-window.height)/2+Screen.virtualY,window.width,window.height)
screen = Qt.application.screens[FluTools.cursorScreenIndex()]
var taskBarHeight = FluTools.getTaskBarHeight(window)
window.setGeometry((Screen.width-window.width)/2+Screen.virtualX,(Screen.height-window.height-taskBarHeight)/2+Screen.virtualY,window.width,window.height)
}
function fixWindowSize(){
if(fixSize){
window.maximumWidth = window.width
window.maximumHeight = window.height
window.minimumWidth = window.width
window.minimumHeight = window.height
}
}
function onResult(data){
if(_pageRegister){

View File

@ -7277,8 +7277,9 @@ var core_layouts = {
}
}];
};
chart.boxes.push(item);
if(Array.isArray(chart.boxes)){
chart.boxes.push(item);
}
},
/**
@ -7287,9 +7288,13 @@ var core_layouts = {
* @param {ILayoutItem} layoutItem - the item to remove from the layout
*/
removeBox: function(chart, layoutItem) {
var index = chart.boxes ? chart.boxes.indexOf(layoutItem) : -1;
if (index !== -1) {
chart.boxes.splice(index, 1);
if(chart.boxes){
if(layoutItem){
if(Array.isArray(chart.boxes)){
var index = chart.boxes.indexOf(layoutItem)
chart.boxes.splice(index, 1);
}
}
}
},
@ -9656,12 +9661,16 @@ helpers$1.extend(Chart.prototype, /** @lends Chart */ {
// plugins options references might have change, let's invalidate the cache
// https://github.com/chartjs/Chart.js/issues/5111#issuecomment-355934167
core_plugins._invalidate(me);
// core_plugins._invalidate(me);
if (core_plugins.notify(me, 'beforeUpdate') === false) {
return;
}
if(me.data === undefined){
return;
}
// In case the entire data object changed
me.tooltip._data = me.data;
@ -9885,8 +9894,11 @@ helpers$1.extend(Chart.prototype, /** @lends Chart */ {
*/
transition: function(easingValue) {
var me = this;
for (var i = 0, ilen = (me.data.datasets || []).length; i < ilen; ++i) {
var datasets = [];
if(me.data){
datasets = me.data.datasets
}
for (var i = 0, ilen = datasets.length; i < ilen; ++i) {
if (me.isDatasetVisible(i)) {
me.getDatasetMeta(i).controller.transition(easingValue);
}
@ -9900,7 +9912,10 @@ helpers$1.extend(Chart.prototype, /** @lends Chart */ {
*/
_getSortedDatasetMetas: function(filterVisible) {
var me = this;
var datasets = me.data.datasets || [];
var datasets = []
if(me.data){
datasets = me.data.datasets;
}
var result = [];
var i, ilen;
@ -12357,9 +12372,9 @@ var Scale = core_element.extend({
}
// MV workaround, as it seems that emptying line dash does not work
if(ctx.getLineDash && ctx.getLineDash().length === 0) {
ctx.setLineDash([9999]);
}
// if(ctx.getLineDash && ctx.getLineDash().length === 0) {
// ctx.setLineDash([9999]);
// }
ctx.beginPath();

View File

@ -80,6 +80,8 @@ Module {
prototype: "QObject"
exports: ["FluentUI/FluFramelessHelper 1.0"]
exportMetaObjectRevisions: [0]
Signal { name: "loadCompleted" }
Method { name: "showSystemMenu" }
}
Component {
name: "FluNavigationViewType"
@ -186,7 +188,7 @@ Module {
Enum {
name: "CloseButtonVisibility"
values: {
"Nerver": 0,
"Never": 0,
"Always": 1,
"OnHover": 2
}
@ -2341,11 +2343,13 @@ Module {
Property { name: "closeClickListener"; type: "QVariant" }
Property { name: "stayTopClickListener"; type: "QVariant" }
Property { name: "darkClickListener"; type: "QVariant" }
Property { name: "systemMenuListener"; type: "QVariant" }
Method { name: "stayTopButton"; type: "QVariant" }
Method { name: "minimizeButton"; type: "QVariant" }
Method { name: "maximizeButton"; type: "QVariant" }
Method { name: "closeButton"; type: "QVariant" }
Method { name: "darkButton"; type: "QVariant" }
Method { name: "maximizeButtonHover"; type: "QVariant" }
}
Component {
prototype: "QQuickRectangle"
@ -3013,15 +3017,15 @@ Module {
defaultProperty: "data"
Property { name: "logo"; type: "QUrl" }
Property { name: "title"; type: "string" }
Property { name: "items"; type: "FluObject_QMLTYPE_125"; isPointer: true }
Property { name: "footerItems"; type: "FluObject_QMLTYPE_125"; isPointer: true }
Property { name: "items"; type: "FluObject_QMLTYPE_157"; isPointer: true }
Property { name: "footerItems"; type: "FluObject_QMLTYPE_157"; isPointer: true }
Property { name: "displayMode"; type: "int" }
Property { name: "autoSuggestBox"; type: "QQmlComponent"; isPointer: true }
Property { name: "actionItem"; type: "QQmlComponent"; isPointer: true }
Property { name: "topPadding"; type: "int" }
Property { name: "pageMode"; type: "int" }
Property { name: "navItemRightMenu"; type: "FluMenu_QMLTYPE_34"; isPointer: true }
Property { name: "navItemExpanderRightMenu"; type: "FluMenu_QMLTYPE_34"; isPointer: true }
Property { name: "navItemRightMenu"; type: "FluMenu_QMLTYPE_45"; isPointer: true }
Property { name: "navItemExpanderRightMenu"; type: "FluMenu_QMLTYPE_45"; isPointer: true }
Property { name: "navCompactWidth"; type: "int" }
Property { name: "navTopMargin"; type: "int" }
Property { name: "cellHeight"; type: "int" }
@ -3109,21 +3113,17 @@ Module {
Property { name: "_ext"; type: "QVariant" }
Property { name: "_parent"; type: "QVariant" }
Property { name: "title"; type: "string" }
Property { name: "order"; type: "int" }
Property { name: "url"; type: "QVariant" }
Property { name: "disabled"; type: "bool" }
Property { name: "icon"; type: "int" }
Property { name: "iconVisible"; type: "bool" }
Property { name: "infoBadge"; type: "QQmlComponent"; isPointer: true }
Property { name: "recentlyAdded"; type: "bool" }
Property { name: "recentlyUpdated"; type: "bool" }
Property { name: "desc"; type: "string" }
Property { name: "image"; type: "QVariant" }
Property { name: "count"; type: "int" }
Property { name: "onTapListener"; type: "QVariant" }
Property { name: "iconDelegate"; type: "QQmlComponent"; isPointer: true }
Property { name: "menuDelegate"; type: "QQmlComponent"; isPointer: true }
Property { name: "editDelegate"; type: "QQmlComponent"; isPointer: true }
Property { name: "extra"; type: "QVariant" }
Property { name: "showEdit"; type: "bool" }
Signal { name: "tap" }
}
@ -3534,13 +3534,6 @@ Module {
}
Method { name: "count"; type: "QVariant" }
}
Component {
prototype: "QQmlTableModelColumn"
name: "FluentUI/FluTableModelColumn 1.0"
exports: ["FluentUI/FluTableModelColumn 1.0"]
exportMetaObjectRevisions: [0]
isComposite: true
}
Component {
prototype: "QQuickRectangle"
name: "FluentUI/FluTableView 1.0"
@ -3798,7 +3791,15 @@ Module {
Property { name: "resizeBorderColor"; type: "QColor" }
Property { name: "resizeBorderWidth"; type: "int" }
Property { name: "closeListener"; type: "QVariant" }
Property { name: "_offsetXY"; type: "QPointF" }
Property { name: "_originalPos"; type: "QVariant" }
Property { name: "_accentColor"; type: "QColor" }
Property { name: "_realHeight"; type: "int" }
Property { name: "_realWidth"; type: "int" }
Property { name: "_appBarHeight"; type: "int" }
Property { name: "_enableMarginsBottomLeftRight"; type: "bool" }
Property { name: "content"; type: "QObject"; isList: true; isReadonly: true }
Signal { name: "showSystemMenu" }
Signal {
name: "initArgument"
Parameter { name: "argument"; type: "QVariant" }
@ -3846,12 +3847,14 @@ Module {
Parameter { name: "path"; type: "QVariant" }
}
Method { name: "moveWindowToDesktopCenter"; type: "QVariant" }
Method { name: "fixWindowSize"; type: "QVariant" }
Method {
name: "onResult"
type: "QVariant"
Parameter { name: "data"; type: "QVariant" }
}
Method { name: "containerItem"; type: "QVariant" }
Method { name: "layoutContainer"; type: "QVariant" }
Method { name: "layoutContent"; type: "QVariant" }
}
Component {
prototype: "QQuickRow"

View File

@ -75,7 +75,6 @@ FluSlider 1.0 Controls/FluSlider.qml
FluSpinBox 1.0 Controls/FluSpinBox.qml
FluStatusView 1.0 Controls/FluStatusView.qml
FluTabView 1.0 Controls/FluTabView.qml
FluTableModelColumn 1.0 Controls/FluTableModelColumn.qml
FluTableView 1.0 Controls/FluTableView.qml
FluText 1.0 Controls/FluText.qml
FluTextBox 1.0 Controls/FluTextBox.qml

View File

@ -71,7 +71,6 @@
<file>FluentUI/Controls/FluSpinBox.qml</file>
<file>FluentUI/Controls/FluStaggeredView.qml</file>
<file>FluentUI/Controls/FluStatusView.qml</file>
<file>FluentUI/Controls/FluTableModelColumn.qml</file>
<file>FluentUI/Controls/FluTableView.qml</file>
<file>FluentUI/Controls/FluTabView.qml</file>
<file>FluentUI/Controls/FluText.qml</file>

View File

@ -44,6 +44,7 @@ Rectangle{
d.win.visibility = Window.Windowed
else
d.win.visibility = Window.Maximized
d.hoverMaxBtn = false
}
}
property var minClickListener: function(){
@ -64,6 +65,11 @@ Rectangle{
FluTheme.darkMode = FluThemeType.Dark
}
}
property var systemMenuListener: function(){
if(d.win instanceof FluWindow){
d.win.showSystemMenu()
}
}
id:control
color: Qt.rgba(0,0,0,0)
height: visible ? 30 : 0
@ -71,6 +77,7 @@ Rectangle{
z: 65535
Item{
id:d
property bool hoverMaxBtn: false
property var win: Window.window
property bool stayTop: {
if(d.win instanceof FluWindow){
@ -83,14 +90,23 @@ Rectangle{
}
MouseArea{
anchors.fill: parent
onPositionChanged: {
d.win.startSystemMove()
}
onDoubleClicked: {
if(d.resizable){
btn_maximize.clicked()
onPositionChanged:
(mouse)=>{
d.win.startSystemMove()
}
onDoubleClicked:
(mouse)=>{
if(d.resizable && Qt.LeftButton){
btn_maximize.clicked()
}
}
acceptedButtons: Qt.LeftButton|Qt.RightButton
onClicked:
(mouse)=>{
if (mouse.button === Qt.RightButton){
control.systemMenuListener()
}
}
}
}
Row{
anchors{
@ -218,6 +234,9 @@ Rectangle{
if(pressed){
return maximizePressColor
}
if(FluTools.isWindows11OrGreater()){
return d.hoverMaxBtn ? maximizeHoverColor : maximizeNormalColor
}
return hovered ? maximizeHoverColor : maximizeNormalColor
}
Layout.alignment: Qt.AlignVCenter
@ -263,4 +282,17 @@ Rectangle{
function darkButton(){
return btn_dark
}
function maximizeButtonHover(){
var hover = false;
var pos = btn_maximize.mapToGlobal(0,0)
if(btn_maximize.visible){
var rect = Qt.rect(pos.x,pos.y,btn_maximize.width,btn_maximize.height)
pos = FluTools.cursorPos()
if(pos.x>rect.x && pos.x<(rect.x+rect.width) && pos.y>rect.y && pos.y<(rect.y+rect.height)){
hover = true;
}
}
d.hoverMaxBtn = hover
return hover;
}
}

View File

@ -98,12 +98,12 @@ FluTextBox{
loadData()
if(d.flagVisible){
var pos = control.mapToItem(null, 0, 0)
if(window.height>pos.y+control.height+container.height){
if(window.height>pos.y+control.height+container.implicitHeight){
control_popup.y = control.height
} else if(pos.y>container.height){
control_popup.y = -container.height
} else if(pos.y>container.implicitHeight){
control_popup.y = -container.implicitHeight
} else {
popup.y = window.height-(pos.y+container.height)
control_popup.y = window.height-(pos.y+container.implicitHeight)
}
control_popup.visible = true
}

View File

@ -102,6 +102,7 @@ T.ComboBox {
height: Math.min(contentItem.implicitHeight, control.Window.height - topMargin - bottomMargin)
topMargin: 6
bottomMargin: 6
modal: true
contentItem: ListView {
clip: true
implicitHeight: contentHeight

View File

@ -36,7 +36,7 @@ FluPopup {
clip: true
boundsBehavior:Flickable.StopAtBounds
width: parent.width
height: Math.min(text_message.height,300)
height: message === "" ? 0 : Math.min(text_message.height,300)
ScrollBar.vertical: FluScrollBar {}
FluText{
id:text_message

View File

@ -65,6 +65,7 @@ TextArea{
anchors.fill: parent
cursorShape: Qt.IBeamCursor
acceptedButtons: Qt.RightButton
visible: !readOnly
onClicked: control.echoMode !== TextInput.Password && menu.popup()
}
FluTextBoxMenu{

View File

@ -42,15 +42,22 @@ Item {
function handleItems(){
var _idx = 0
var data = []
var comEmpty = Qt.createComponent("FluPaneItemEmpty.qml");
if(items){
for(var i=0;i<items.children.length;i++){
var item = items.children[i]
if(item.visible !== true){
continue
}
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]
if(itemChild.visible !== true){
continue
}
itemChild._parent = item
itemChild._idx = _idx
data.push(itemChild)
@ -59,20 +66,33 @@ Item {
}
}
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++
if(itemFooter.visible !== true){
continue
}
var objEmpty = comEmpty.createObject(items,{_idx:_idx});
itemFooter._idx = _idx;
data.push(objEmpty)
_idx++
}
}
}
return data
}
function handleFooterItems(){
var data = []
if(footerItems){
for(var i=0;i<footerItems.children.length;i++){
var item = footerItems.children[i]
if(item.visible !== true){
continue
}
data.push(item)
}
}
return data;
}
}
Component.onCompleted: {
d.displayMode = Qt.binding(function(){
@ -258,6 +278,9 @@ Item {
}
for(var i=0;i<model.children.length;i++){
var item = model.children[i]
if(item.visible !== true){
continue
}
if(item._idx === nav_list.currentIndex && !model.isExpand){
return true
}
@ -1040,11 +1063,7 @@ Item {
interactive: false
boundsBehavior: ListView.StopAtBounds
currentIndex: -1
model: {
if(footerItems){
return footerItems.children
}
}
model: d.handleFooterItems()
highlightMoveDuration: 150
highlight: Item{
clip: true

View File

@ -7,22 +7,19 @@ QtObject {
property int _idx
property var _ext
property var _parent
property bool visible: true
property string title
property int order : 0
property var url
property bool disabled: false
property int icon
property bool iconVisible: true
property Component infoBadge
property bool recentlyAdded: false
property bool recentlyUpdated: false
property string desc
property var image
property int count: 0
property var onTapListener
property Component iconDelegate
property Component menuDelegate
property Component editDelegate
property var extra
property bool showEdit
signal tap
}

View File

@ -7,4 +7,5 @@ QtObject {
property int _idx
property var _ext
property var _parent
property bool visible: true
}

View File

@ -5,6 +5,7 @@ import FluentUI
FluObject {
readonly property string key : FluTools.uuid()
property int _idx
property bool visible: true
property string title
property var icon
property bool disabled: false

View File

@ -5,6 +5,7 @@ import FluentUI
QtObject {
readonly property string key : FluTools.uuid()
property int _idx
property bool visible: true
property string title
property var parent
}

View File

@ -5,6 +5,7 @@ import FluentUI
QtObject {
readonly property string key : FluTools.uuid()
property int _idx
property bool visible: true
property var parent
property real spacing
property int size:1

View File

@ -9,7 +9,7 @@ Button {
property string contentDescription: ""
QtObject{
id:d
property bool checked: rect_back.height == background.height
property bool checked: (rect_back.height === background.height) && (progress === 1)
}
property color normalColor: {
if(d.checked){
@ -71,7 +71,7 @@ Button {
color: FluTheme.primaryColor
anchors.bottom: parent.bottom
Behavior on height{
enabled: control.progress === 1
enabled: control.progress !== 0
SequentialAnimation {
PauseAnimation {
duration: FluTheme.enableAnimation ? 167 : 0

View File

@ -5,6 +5,7 @@ import FluentUI
T.Slider {
property bool tooltipEnabled: true
property string text: String(control.value)
id: control
to:100
stepSize:1
@ -69,6 +70,6 @@ T.Slider {
FluTooltip{
parent: control.handle
visible: control.tooltipEnabled && (control.pressed || control.hovered)
text:String(control.value)
text:control.text
}
}

View File

@ -236,7 +236,7 @@ Item {
width: visible ? 24 : 0
height: 24
visible: {
if(closeButtonVisibility === FluTabViewType.Nerver)
if(closeButtonVisibility === FluTabViewType.Never)
return false
if(closeButtonVisibility === FluTabViewType.OnHover)
return item_mouse_hove.containsMouse || item_btn_close.hovered

Some files were not shown because too many files have changed in this diff Show More