Compare commits

..

29 Commits
1.6.5 ... 1.6.6

Author SHA1 Message Date
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
60 changed files with 625 additions and 378 deletions

View File

@ -22,7 +22,7 @@ jobs:
strategy: strategy:
matrix: matrix:
os: [macos-13] os: [macos-13]
qt_ver: [6.6.0] qt_ver: [6.6.1]
qt_arch: [clang_64] qt_arch: [clang_64]
env: env:
targetName: example targetName: example
@ -50,11 +50,13 @@ jobs:
cmake --version cmake --version
mkdir build mkdir build
cd 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 cmake --build . --target all --config Release --parallel
- name: package - name: package
run: | 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 sudo macdeployqt bin/release/${targetName}.app -qmldir=. -dmg

View File

@ -23,7 +23,7 @@ jobs:
strategy: strategy:
matrix: matrix:
os: [ubuntu-20.04] os: [ubuntu-20.04]
qt_ver: [6.6.0] qt_ver: [6.6.1]
qt_arch: [gcc_64] qt_arch: [gcc_64]
env: env:
targetName: example targetName: example
@ -55,7 +55,7 @@ jobs:
cmake --version cmake --version
mkdir build mkdir build
cd 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 cmake --build . --target all --config Release --parallel
- name: install QT linux deploy - name: install QT linux deploy

View File

@ -24,7 +24,7 @@ jobs:
os: [windows-2022] os: [windows-2022]
include: include:
- qt_arch: win64_mingw - 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: "tools_mingw,9.0.0-1-202203221220,qt.tools.win64_mingw900"
qt_tools_mingw_install: mingw900_64 qt_tools_mingw_install: mingw900_64
env: env:
@ -69,7 +69,7 @@ jobs:
mkdir build mkdir build
cd build cd build
ninja --version 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 cmake --build . --target all --config Release --parallel
- name: package - name: package

View File

@ -23,7 +23,7 @@ jobs:
matrix: matrix:
os: [windows-2019] os: [windows-2019]
include: include:
- qt_ver: 6.6.0 - qt_ver: 6.6.1
qt_arch: win64_msvc2019_64 qt_arch: win64_msvc2019_64
msvc_arch: x64 msvc_arch: x64
qt_arch_install: msvc2019_64 qt_arch_install: msvc2019_64
@ -52,7 +52,7 @@ jobs:
ninja --version ninja --version
mkdir build mkdir build
cd 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 cmake --build . --target all --config Release --parallel
echo winSdkDir=%WindowsSdkDir% >> %GITHUB_ENV% echo winSdkDir=%WindowsSdkDir% >> %GITHUB_ENV%
echo winSdkVer=%WindowsSdkVersion% >> %GITHUB_ENV% echo winSdkVer=%WindowsSdkVersion% >> %GITHUB_ENV%

Binary file not shown.

Binary file not shown.

View File

@ -26,6 +26,7 @@ endif()
add_subdirectory(src) add_subdirectory(src)
#Release也支持日志打印代码位置
target_compile_definitions(fluentuiplugin target_compile_definitions(fluentuiplugin
PRIVATE PRIVATE
QT_MESSAGELOGCONTEXT QT_MESSAGELOGCONTEXT

View File

@ -24,6 +24,7 @@ endif()
#获取文件路径分隔符(解决执行命令的时候有些平台会报错) #获取文件路径分隔符(解决执行命令的时候有些平台会报错)
file(TO_CMAKE_PATH "/" PATH_SEPARATOR) file(TO_CMAKE_PATH "/" PATH_SEPARATOR)
#导入Qt相关依赖包
find_package(QT NAMES Qt6 Qt5 REQUIRED COMPONENTS Quick Svg Network) find_package(QT NAMES Qt6 Qt5 REQUIRED COMPONENTS Quick Svg Network)
find_package(Qt${QT_VERSION_MAJOR} REQUIRED COMPONENTS Quick Svg Network) find_package(Qt${QT_VERSION_MAJOR} REQUIRED COMPONENTS Quick Svg Network)
@ -51,22 +52,28 @@ endforeach(filepath)
if(QT_VERSION VERSION_GREATER_EQUAL "6.2") if(QT_VERSION VERSION_GREATER_EQUAL "6.2")
#遍历所有qml文件 #遍历所有qml文件
file(GLOB_RECURSE QML_PATHS *.qml) file(GLOB_RECURSE QML_PATHS *.qml qmldir)
foreach(filepath ${QML_PATHS}) foreach(filepath ${QML_PATHS})
string(REPLACE "${CMAKE_CURRENT_SOURCE_DIR}/" "" filename ${filepath}) string(REPLACE "${CMAKE_CURRENT_SOURCE_DIR}/" "" filename ${filepath})
if(${filepath} MATCHES "Qt${QT_VERSION_MAJOR}/") if(${filepath} MATCHES "qml-Qt6")
string(REPLACE "qml-Qt${QT_VERSION_MAJOR}" "qml" filealias ${filename}) string(REPLACE "qml-Qt6" "qml" filealias ${filename})
set_source_files_properties(${filename} PROPERTIES QT_RESOURCE_ALIAS ${filealias}) set_source_files_properties(${filename} PROPERTIES QT_RESOURCE_ALIAS ${filealias})
if(${filename} MATCHES "qmldir")
list(APPEND resource_files ${filename})
else()
list(APPEND qml_files ${filename}) list(APPEND qml_files ${filename})
endif() endif()
endif()
endforeach(filepath) 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}) foreach(filepath ${RES_PATHS})
string(REPLACE "${CMAKE_CURRENT_SOURCE_DIR}/" "" filename ${filepath}) string(REPLACE "${CMAKE_CURRENT_SOURCE_DIR}/" "" filename ${filepath})
message(${filename})
list(APPEND resource_files ${filename}) list(APPEND resource_files ${filename})
endforeach(filepath) endforeach(filepath)
endif() endif()
#如果是Windows平台则生成rc文件还有inno setup脚本文件 #如果是Windows平台则生成rc文件还有inno setup脚本文件
@ -95,20 +102,19 @@ else ()
) )
endif () endif ()
#复制程序运行所需要的动态库
if(WIN32) 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) if(MSVC)
set(DLLPATH ${3RDPARTY_ARCH_DIR}/msvc/*.dll) if(CMAKE_SIZEOF_VOID_P EQUAL 4)
elseif(MINGW) set(3RDPARTY_DLL_DIR ${CMAKE_SOURCE_DIR}/3rdparty/msvc/x86/*.dll)
set(DLLPATH ${3RDPARTY_ARCH_DIR}/mingw/*.dll) elseif(CMAKE_SIZEOF_VOID_P EQUAL 8)
set(3RDPARTY_DLL_DIR ${CMAKE_SOURCE_DIR}/3rdparty/msvc/x64/*.dll)
endif() endif()
string(REPLACE "/" ${PATH_SEPARATOR} DLLPATH "${DLLPATH}") elseif(MINGW)
file(GLOB DLL_FILES ${DLLPATH}) set(3RDPARTY_DLL_DIR ${CMAKE_SOURCE_DIR}/3rdparty/mingw/*.dll)
endif()
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 add_custom_command(TARGET ${PROJECT_NAME} POST_BUILD
COMMAND ${CMAKE_COMMAND} -E copy COMMAND ${CMAKE_COMMAND} -E copy
${DLL_FILES} ${DLL_FILES}
@ -117,7 +123,7 @@ if(WIN32)
endif() endif()
if(QT_VERSION VERSION_GREATER_EQUAL "6.2") if(QT_VERSION VERSION_GREATER_EQUAL "6.2")
#添加qml模块 #如果是Qt6.2以上则使用qt_add_qml_module添加资源文件
qt_add_qml_module(example qt_add_qml_module(example
URI "example" URI "example"
VERSION 1.0 VERSION 1.0
@ -126,6 +132,7 @@ if(QT_VERSION VERSION_GREATER_EQUAL "6.2")
RESOURCE_PREFIX "/" RESOURCE_PREFIX "/"
) )
else() else()
#如果是Qt6.2以下则使用qrc添加资源文件
target_include_directories(example PRIVATE target_include_directories(example PRIVATE
${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_SOURCE_DIR}
) )
@ -153,11 +160,13 @@ set_target_properties(example PROPERTIES
WIN32_EXECUTABLE TRUE WIN32_EXECUTABLE TRUE
) )
#Release也支持日志打印代码位置
target_compile_definitions(example target_compile_definitions(example
PRIVATE PRIVATE
QT_MESSAGELOGCONTEXT QT_MESSAGELOGCONTEXT
) )
#目标文件链接库
target_link_libraries(example PRIVATE target_link_libraries(example PRIVATE
Qt${QT_VERSION_MAJOR}::Quick Qt${QT_VERSION_MAJOR}::Quick
Qt${QT_VERSION_MAJOR}::Svg Qt${QT_VERSION_MAJOR}::Svg

View File

@ -50,9 +50,7 @@ FluObject{
} }
title:"Buttons" title:"Buttons"
menuDelegate: paneItemMenu menuDelegate: paneItemMenu
image:"qrc:/example/res/image/control/Button.png" extra:({image:"qrc:/example/res/image/control/Button.png",recentlyUpdated:true,desc:"A control that responds to user input and raisesa Click event."})
recentlyUpdated:true
desc:"A control that responds to user input and raisesa Click event."
url:"qrc:/example/qml/page/T_Buttons.qml" url:"qrc:/example/qml/page/T_Buttons.qml"
onTap:{ onTap:{
item_buttons.count = 0 item_buttons.count = 0
@ -83,18 +81,14 @@ FluObject{
FluPaneItem{ FluPaneItem{
title:"Slider" title:"Slider"
menuDelegate: paneItemMenu menuDelegate: paneItemMenu
image:"qrc:/example/res/image/control/Slider.png" 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."})
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" url:"qrc:/example/qml/page/T_Slider.qml"
onTap:{ navigationView.push(url) } onTap:{ navigationView.push(url) }
} }
FluPaneItem{ FluPaneItem{
title:"CheckBox" title:"CheckBox"
menuDelegate: paneItemMenu menuDelegate: paneItemMenu
image:"qrc:/example/res/image/control/Checkbox.png" extra:({image:"qrc:/example/res/image/control/Checkbox.png",recentlyUpdated:true,desc:"A control that a user can select or clear."})
recentlyUpdated:true
desc:"A control that a user can select or clear."
url:"qrc:/example/qml/page/T_CheckBox.qml" url:"qrc:/example/qml/page/T_CheckBox.qml"
onTap:{ navigationView.push(url) } onTap:{ navigationView.push(url) }
} }
@ -164,9 +158,7 @@ FluObject{
FluPaneItem{ FluPaneItem{
title:"InfoBar" title:"InfoBar"
menuDelegate: paneItemMenu menuDelegate: paneItemMenu
image:"qrc:/example/res/image/control/InfoBar.png" extra:({image:"qrc:/example/res/image/control/InfoBar.png",recentlyUpdated:true,desc:"An inline message to display app-wide statuschange information."})
recentlyUpdated:true
desc:"An inline message to display app-wide statuschange information."
url:"qrc:/example/qml/page/T_InfoBar.qml" url:"qrc:/example/qml/page/T_InfoBar.qml"
onTap:{ navigationView.push(url) } onTap:{ navigationView.push(url) }
} }
@ -276,10 +268,7 @@ FluObject{
FluPaneItem{ FluPaneItem{
title:"Pivot" title:"Pivot"
menuDelegate: paneItemMenu menuDelegate: paneItemMenu
image:"qrc:/example/res/image/control/Pivot.png" extra:({image:"qrc:/example/res/image/control/Pivot.png",order:3,recentlyAdded:true,desc:"Presents information from different sources in atabbed view."})
recentlyAdded:true
order:3
desc:"Presents information from different sources in atabbed view."
url:"qrc:/example/qml/page/T_Pivot.qml" url:"qrc:/example/qml/page/T_Pivot.qml"
onTap:{ navigationView.push(url) } onTap:{ navigationView.push(url) }
} }
@ -292,10 +281,7 @@ FluObject{
FluPaneItem{ FluPaneItem{
title:"TabView" title:"TabView"
menuDelegate: paneItemMenu menuDelegate: paneItemMenu
image:"qrc:/example/res/image/control/TabView.png" 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."})
recentlyAdded:true
order:1
desc:"A control that displays a collection of tabs thatcan be used to display several documents."
url:"qrc:/example/qml/page/T_TabView.qml" url:"qrc:/example/qml/page/T_TabView.qml"
onTap:{ navigationView.push(url) } onTap:{ navigationView.push(url) }
} }
@ -308,10 +294,7 @@ FluObject{
FluPaneItem{ FluPaneItem{
title:"TableView" title:"TableView"
menuDelegate: paneItemMenu menuDelegate: paneItemMenu
image:"qrc:/example/res/image/control/DataGrid.png" 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"})
recentlyAdded:true
order:4
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" url:"qrc:/example/qml/page/T_TableView.qml"
onTap:{ navigationView.push(url) } onTap:{ navigationView.push(url) }
} }
@ -330,10 +313,7 @@ FluObject{
FluPaneItem{ FluPaneItem{
title:"FlipView" title:"FlipView"
menuDelegate: paneItemMenu menuDelegate: paneItemMenu
image:"qrc:/example/res/image/control/FlipView.png" 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."})
recentlyAdded:true
order:2
desc:"Presents a collection of items that the user canflip through, one item at a time."
url:"qrc:/example/qml/page/T_FlipView.qml" url:"qrc:/example/qml/page/T_FlipView.qml"
onTap:{ navigationView.push(url) } onTap:{ navigationView.push(url) }
} }
@ -490,21 +470,14 @@ FluObject{
function getRecentlyAddedData(){ function getRecentlyAddedData(){
var arr = [] var arr = []
for(var i=0;i<children.length;i++){ var items = navigationView.getItems();
var item = children[i] for(var i=0;i<items.length;i++){
if(item instanceof FluPaneItem && item.recentlyAdded){ var item = items[i]
if(item instanceof FluPaneItem && item.extra && item.extra.recentlyAdded){
arr.push(item) 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.extra.order-o1.extra.order })
}
}
arr.sort(function(o1,o2){ return o2.order-o1.order })
return arr return arr
} }
@ -513,7 +486,7 @@ FluObject{
var items = navigationView.getItems(); var items = navigationView.getItems();
for(var i=0;i<items.length;i++){ for(var i=0;i<items.length;i++){
var item = items[i] var item = items[i]
if(item instanceof FluPaneItem && item.recentlyUpdated){ if(item instanceof FluPaneItem && item.extra && item.extra.recentlyUpdated){
arr.push(item) arr.push(item)
} }
} }

View File

@ -160,7 +160,7 @@ FluScrollablePage{
Component{ Component{
id:com_item id:com_item
Item{ Item{
property string desc: modelData.desc property string desc: modelData.extra.desc
width: 320 width: 320
height: 120 height: 120
FluArea{ FluArea{
@ -182,7 +182,7 @@ FluScrollablePage{
id:item_icon id:item_icon
height: 40 height: 40
width: 40 width: 40
source: modelData.image source: modelData.extra.image
anchors{ anchors{
left: parent.left left: parent.left
leftMargin: 20 leftMargin: 20

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{ FluContentDialog{
id:dialog_restart id:dialog_restart
title:"友情提示" title:"友情提示"

View File

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

View File

@ -50,9 +50,7 @@ FluObject{
} }
title:"Buttons" title:"Buttons"
menuDelegate: paneItemMenu menuDelegate: paneItemMenu
image:"qrc:/example/res/image/control/Button.png" extra:({image:"qrc:/example/res/image/control/Button.png",recentlyUpdated:true,desc:"A control that responds to user input and raisesa Click event."})
recentlyUpdated:true
desc:"A control that responds to user input and raisesa Click event."
url:"qrc:/example/qml/page/T_Buttons.qml" url:"qrc:/example/qml/page/T_Buttons.qml"
onTap:{ onTap:{
item_buttons.count = 0 item_buttons.count = 0
@ -83,18 +81,14 @@ FluObject{
FluPaneItem{ FluPaneItem{
title:"Slider" title:"Slider"
menuDelegate: paneItemMenu menuDelegate: paneItemMenu
image:"qrc:/example/res/image/control/Slider.png" 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."})
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" url:"qrc:/example/qml/page/T_Slider.qml"
onTap:{ navigationView.push(url) } onTap:{ navigationView.push(url) }
} }
FluPaneItem{ FluPaneItem{
title:"CheckBox" title:"CheckBox"
menuDelegate: paneItemMenu menuDelegate: paneItemMenu
image:"qrc:/example/res/image/control/Checkbox.png" extra:({image:"qrc:/example/res/image/control/Checkbox.png",recentlyUpdated:true,desc:"A control that a user can select or clear."})
recentlyUpdated:true
desc:"A control that a user can select or clear."
url:"qrc:/example/qml/page/T_CheckBox.qml" url:"qrc:/example/qml/page/T_CheckBox.qml"
onTap:{ navigationView.push(url) } onTap:{ navigationView.push(url) }
} }
@ -164,9 +158,7 @@ FluObject{
FluPaneItem{ FluPaneItem{
title:"InfoBar" title:"InfoBar"
menuDelegate: paneItemMenu menuDelegate: paneItemMenu
image:"qrc:/example/res/image/control/InfoBar.png" extra:({image:"qrc:/example/res/image/control/InfoBar.png",recentlyUpdated:true,desc:"An inline message to display app-wide statuschange information."})
recentlyUpdated:true
desc:"An inline message to display app-wide statuschange information."
url:"qrc:/example/qml/page/T_InfoBar.qml" url:"qrc:/example/qml/page/T_InfoBar.qml"
onTap:{ navigationView.push(url) } onTap:{ navigationView.push(url) }
} }
@ -276,10 +268,7 @@ FluObject{
FluPaneItem{ FluPaneItem{
title:"Pivot" title:"Pivot"
menuDelegate: paneItemMenu menuDelegate: paneItemMenu
image:"qrc:/example/res/image/control/Pivot.png" extra:({image:"qrc:/example/res/image/control/Pivot.png",order:3,recentlyAdded:true,desc:"Presents information from different sources in atabbed view."})
recentlyAdded:true
order:3
desc:"Presents information from different sources in atabbed view."
url:"qrc:/example/qml/page/T_Pivot.qml" url:"qrc:/example/qml/page/T_Pivot.qml"
onTap:{ navigationView.push(url) } onTap:{ navigationView.push(url) }
} }
@ -292,10 +281,7 @@ FluObject{
FluPaneItem{ FluPaneItem{
title:"TabView" title:"TabView"
menuDelegate: paneItemMenu menuDelegate: paneItemMenu
image:"qrc:/example/res/image/control/TabView.png" 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."})
recentlyAdded:true
order:1
desc:"A control that displays a collection of tabs thatcan be used to display several documents."
url:"qrc:/example/qml/page/T_TabView.qml" url:"qrc:/example/qml/page/T_TabView.qml"
onTap:{ navigationView.push(url) } onTap:{ navigationView.push(url) }
} }
@ -308,10 +294,7 @@ FluObject{
FluPaneItem{ FluPaneItem{
title:"TableView" title:"TableView"
menuDelegate: paneItemMenu menuDelegate: paneItemMenu
image:"qrc:/example/res/image/control/DataGrid.png" 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"})
recentlyAdded:true
order:4
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" url:"qrc:/example/qml/page/T_TableView.qml"
onTap:{ navigationView.push(url) } onTap:{ navigationView.push(url) }
} }
@ -330,10 +313,7 @@ FluObject{
FluPaneItem{ FluPaneItem{
title:"FlipView" title:"FlipView"
menuDelegate: paneItemMenu menuDelegate: paneItemMenu
image:"qrc:/example/res/image/control/FlipView.png" 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."})
recentlyAdded:true
order:2
desc:"Presents a collection of items that the user canflip through, one item at a time."
url:"qrc:/example/qml/page/T_FlipView.qml" url:"qrc:/example/qml/page/T_FlipView.qml"
onTap:{ navigationView.push(url) } onTap:{ navigationView.push(url) }
} }
@ -490,21 +470,14 @@ FluObject{
function getRecentlyAddedData(){ function getRecentlyAddedData(){
var arr = [] var arr = []
for(var i=0;i<children.length;i++){ var items = navigationView.getItems();
var item = children[i] for(var i=0;i<items.length;i++){
if(item instanceof FluPaneItem && item.recentlyAdded){ var item = items[i]
if(item instanceof FluPaneItem && item.extra && item.extra.recentlyAdded){
arr.push(item) 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.extra.order-o1.extra.order })
}
}
arr.sort(function(o1,o2){ return o2.order-o1.order })
return arr return arr
} }
@ -513,7 +486,7 @@ FluObject{
var items = navigationView.getItems(); var items = navigationView.getItems();
for(var i=0;i<items.length;i++){ for(var i=0;i<items.length;i++){
var item = items[i] var item = items[i]
if(item instanceof FluPaneItem && item.recentlyUpdated){ if(item instanceof FluPaneItem && item.extra && item.extra.recentlyUpdated){
arr.push(item) arr.push(item)
} }
} }

View File

@ -160,7 +160,7 @@ FluScrollablePage{
Component{ Component{
id:com_item id:com_item
Item{ Item{
property string desc: modelData.desc property string desc: modelData.extra.desc
width: 320 width: 320
height: 120 height: 120
FluArea{ FluArea{
@ -182,7 +182,7 @@ FluScrollablePage{
id:item_icon id:item_icon
height: 40 height: 40
width: 40 width: 40
source: modelData.image source: modelData.extra.image
anchors{ anchors{
left: parent.left left: parent.left
leftMargin: 20 leftMargin: 20

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{ FluContentDialog{
id:dialog_restart id:dialog_restart
title:"友情提示" title:"友情提示"

View File

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

View File

@ -10,7 +10,3 @@ AppInfo::AppInfo(QObject *parent)
{ {
version(APPLICATION_VERSION); version(APPLICATION_VERSION);
} }
void AppInfo::init(QQmlApplicationEngine *engine){
engine->rootContext();
}

View File

@ -14,7 +14,6 @@ private:
explicit AppInfo(QObject *parent = nullptr); explicit AppInfo(QObject *parent = nullptr);
public: public:
SINGLETONG(AppInfo) SINGLETONG(AppInfo)
void init(QQmlApplicationEngine *engine);
}; };
#endif // APPINFO_H #endif // APPINFO_H

View File

@ -94,6 +94,9 @@ QString Log::prettyProductInfoWrapper()
static inline void myMessageHandler(const QtMsgType type, const QMessageLogContext &context, const QString &message) static inline void myMessageHandler(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){ if(logLevelMap[type]>g_logLevel){
return; 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()); Q_ASSERT(!app.isEmpty());
if (app.isEmpty()) { if (app.isEmpty()) {
return; return;
} }
g_logLevel = level;
static bool once = false; static bool once = false;
if (once) { if (once) {
return; return;

View File

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

View File

@ -19,8 +19,6 @@ public:
SINGLETONG(SettingsHelper) SINGLETONG(SettingsHelper)
~SettingsHelper() override; ~SettingsHelper() override;
void init(char *argv[]); 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 void saveDarkMode(int darkModel){save("darkMode",darkModel);}
Q_INVOKABLE int getDarkMode(){return get("darkMode",QVariant(0)).toInt();} Q_INVOKABLE int getDarkMode(){return get("darkMode",QVariant(0)).toInt();}
Q_INVOKABLE void saveUseSystemAppBar(bool useSystemAppBar){save("useSystemAppBar",useSystemAppBar);} Q_INVOKABLE void saveUseSystemAppBar(bool useSystemAppBar){save("useSystemAppBar",useSystemAppBar);}

View File

@ -43,18 +43,8 @@ int main(int argc, char *argv[])
QGuiApplication::setHighDpiScaleFactorRoundingPolicy(Qt::HighDpiScaleFactorRoundingPolicy::PassThrough); QGuiApplication::setHighDpiScaleFactorRoundingPolicy(Qt::HighDpiScaleFactorRoundingPolicy::PassThrough);
#endif #endif
#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); QGuiApplication app(argc, argv);
// QLoggingCategory::setFilterRules(QStringLiteral("qt.scenegraph.general=true"));
// qSetMessagePattern("%{category}: %{message}");
QQmlApplicationEngine engine; QQmlApplicationEngine engine;
AppInfo::getInstance()->init(&engine);
engine.rootContext()->setContextProperty("AppInfo",AppInfo::getInstance()); engine.rootContext()->setContextProperty("AppInfo",AppInfo::getInstance());
engine.rootContext()->setContextProperty("SettingsHelper",SettingsHelper::getInstance()); engine.rootContext()->setContextProperty("SettingsHelper",SettingsHelper::getInstance());
#ifdef FLUENTUI_BUILD_STATIC_LIB #ifdef FLUENTUI_BUILD_STATIC_LIB

View File

@ -44,4 +44,10 @@ private: \
return Singleton<Class>::getInstance(); \ return Singleton<Class>::getInstance(); \
} }
#define HIDE_CONSTRUCTOR(Class) \
private: \
Class() = default; \
Class(const Class& other) = delete; \
Class& operator=(const Class& other) = delete;
#endif // SINGLETON_H #endif // SINGLETON_H

View File

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

View File

@ -39,7 +39,7 @@ public:
void removeWindow(QQuickWindow* window); void removeWindow(QQuickWindow* window);
private: private:
QMap<quint64, QQuickWindow*> _windows; QMap<quint64, QQuickWindow*> _windows;
QObject* _application; QObject* _application = nullptr;
}; };
#endif // FLUAPP_H #endif // FLUAPP_H

View File

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

View File

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

View File

@ -1,7 +1,7 @@
#include "FluFramelessHelper.h" #include "FluFramelessHelper.h"
#include <QGuiApplication> #include <QGuiApplication>
#include <QOperatingSystemVersion> #include "FluTools.h"
#ifdef Q_OS_WIN #ifdef Q_OS_WIN
#pragma comment (lib,"user32.lib") #pragma comment (lib,"user32.lib")
#pragma comment (lib,"dwmapi.lib") #pragma comment (lib,"dwmapi.lib")
@ -13,6 +13,34 @@ static inline QByteArray qtNativeEventType()
static const auto result = "windows_generic_MSG"; static const auto result = "windows_generic_MSG";
return result; return result;
} }
static inline bool isTaskbarAutoHide() {
APPBARDATA appBarData;
memset(&appBarData, 0, sizeof(appBarData));
appBarData.cbSize = sizeof(appBarData);
appBarData.hWnd = FindWindowW(L"Shell_TrayWnd", NULL);
LPARAM lParam = SHAppBarMessage(ABM_GETSTATE, &appBarData);
return lParam & ABS_AUTOHIDE;
}
static inline QColor getAccentColor(){
typedef HRESULT (WINAPI* DwmGetColorizationColorPtr)(DWORD* pcrColorization,BOOL* pfOpaqueBlend);
HMODULE module = LoadLibraryW(L"dwmapi.dll");
if (module)
{
DwmGetColorizationColorPtr dwm_get_colorization_color;
dwm_get_colorization_color= reinterpret_cast<DwmGetColorizationColorPtr>(GetProcAddress(module, "DwmGetColorizationColor"));
DWORD color = 0;
BOOL bOpaque = FALSE;
if (dwm_get_colorization_color)
{
dwm_get_colorization_color(&color,&bOpaque);
}
return QColor(color);
}
return QColor();
}
static inline bool isCompositionEnabled(){ static inline bool isCompositionEnabled(){
typedef HRESULT (WINAPI* DwmIsCompositionEnabledPtr)(BOOL *pfEnabled); typedef HRESULT (WINAPI* DwmIsCompositionEnabledPtr)(BOOL *pfEnabled);
HMODULE module = LoadLibraryW(L"dwmapi.dll"); HMODULE module = LoadLibraryW(L"dwmapi.dll");
@ -31,8 +59,7 @@ static inline bool isCompositionEnabled(){
} }
static inline void showShadow(HWND hwnd){ static inline void showShadow(HWND hwnd){
if(isCompositionEnabled()){ const MARGINS shadow = { 0, 0, 1, 0 };
const MARGINS shadow = { 1, 1, 1, 1 };
typedef HRESULT (WINAPI* DwmExtendFrameIntoClientAreaPtr)(HWND hWnd, const MARGINS *pMarInset); typedef HRESULT (WINAPI* DwmExtendFrameIntoClientAreaPtr)(HWND hWnd, const MARGINS *pMarInset);
HMODULE module = LoadLibraryW(L"dwmapi.dll"); HMODULE module = LoadLibraryW(L"dwmapi.dll");
if (module) if (module)
@ -44,22 +71,18 @@ static inline void showShadow(HWND hwnd){
dwm_extendframe_into_client_area_(hwnd, &shadow); dwm_extendframe_into_client_area_(hwnd, &shadow);
} }
} }
}else{
ULONG_PTR cNewStyle = GetClassLongPtr(hwnd, GCL_STYLE) | CS_DROPSHADOW;
SetClassLongPtr(hwnd, GCL_STYLE, cNewStyle);
}
} }
#endif #endif
FramelessEventFilter::FramelessEventFilter(QQuickWindow* window){ FramelessEventFilter::FramelessEventFilter(FluFramelessHelper* helper){
_window = window; _helper = helper;
_current = window->winId(); _current = _helper->window->winId();
} }
bool FramelessEventFilter::nativeEventFilter(const QByteArray &eventType, void *message, QT_NATIVE_EVENT_RESULT_TYPE *result){ bool FramelessEventFilter::nativeEventFilter(const QByteArray &eventType, void *message, QT_NATIVE_EVENT_RESULT_TYPE *result){
#ifdef Q_OS_WIN #ifdef Q_OS_WIN
if ((eventType != qtNativeEventType()) || !message || !result || !_window) { if ((eventType != qtNativeEventType()) || !message || _helper.isNull() || _helper->window.isNull()) {
return false; return false;
} }
const auto msg = static_cast<const MSG *>(message); const auto msg = static_cast<const MSG *>(message);
@ -72,12 +95,12 @@ bool FramelessEventFilter::nativeEventFilter(const QByteArray &eventType, void *
return false; return false;
} }
const UINT uMsg = msg->message; const UINT uMsg = msg->message;
const WPARAM wParam = msg->wParam;
const LPARAM lParam = msg->lParam;
if (!msg || !hwnd) if (!msg || !hwnd)
{ {
return false; return false;
} }
const WPARAM wParam = msg->wParam;
const LPARAM lParam = msg->lParam;
if(uMsg == WM_WINDOWPOSCHANGING){ if(uMsg == WM_WINDOWPOSCHANGING){
WINDOWPOS* wp = reinterpret_cast<WINDOWPOS*>(lParam); WINDOWPOS* wp = reinterpret_cast<WINDOWPOS*>(lParam);
if (wp != nullptr && (wp->flags & SWP_NOSIZE) == 0) if (wp != nullptr && (wp->flags & SWP_NOSIZE) == 0)
@ -88,20 +111,46 @@ bool FramelessEventFilter::nativeEventFilter(const QByteArray &eventType, void *
} }
return false; return false;
}else if(uMsg == WM_NCCALCSIZE){ }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;
const LRESULT hitTestResult = ::DefWindowProcW(hwnd, WM_NCCALCSIZE, wParam, lParam);
if ((hitTestResult != HTERROR) && (hitTestResult != HTNOWHERE)) {
*result = hitTestResult;
return true;
}
if(IsZoomed(hwnd)){
_helper->setOriginalPos(QPoint(originalLeft,originalTop));
if(isTaskbarAutoHide()){
clientRect->bottom -= 1;
}
}else{
_helper->setOriginalPos({});
}
clientRect->top = originalTop;
*result = WVR_REDRAW; *result = WVR_REDRAW;
return true; return true;
}else if(uMsg == WM_NCPAINT){ }if(uMsg == WM_NCHITTEST){
if(!isCompositionEnabled()){ if(FluTools::getInstance()->isWindows11OrGreater() && _helper->hoverMaxBtn() && _helper->resizeable()){
*result = WVR_REDRAW; if (*result == HTNOWHERE) {
*result = HTZOOM;
}
return true; return true;
} }
return false; return false;
}else if(uMsg == WM_NCACTIVATE){ }else if(uMsg == WM_NCLBUTTONDBLCLK || uMsg == WM_NCLBUTTONDOWN){
if(!isCompositionEnabled()){ if(FluTools::getInstance()->isWindows11OrGreater() && _helper->hoverMaxBtn() && _helper->resizeable()){
*result = 1; QMouseEvent event = QMouseEvent(QEvent::MouseButtonPress, QPoint(), QPoint(), Qt::LeftButton, Qt::LeftButton, Qt::NoModifier);
QGuiApplication::sendEvent(_helper->maximizeButton(),&event);
return true; return true;
} }
return false; return false;
}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;
} }
return false; return false;
#endif #endif
@ -111,56 +160,60 @@ bool FramelessEventFilter::nativeEventFilter(const QByteArray &eventType, void *
FluFramelessHelper::FluFramelessHelper(QObject *parent) FluFramelessHelper::FluFramelessHelper(QObject *parent)
: QObject{parent} : QObject{parent}
{ {
} }
void FluFramelessHelper::classBegin(){ void FluFramelessHelper::classBegin(){
} }
void FluFramelessHelper::updateCursor(int edges){ void FluFramelessHelper::_updateCursor(int edges){
switch (edges) { switch (edges) {
case 0: case 0:
_window->setCursor(Qt::ArrowCursor); window->setCursor(Qt::ArrowCursor);
break; break;
case Qt::LeftEdge: case Qt::LeftEdge:
case Qt::RightEdge: case Qt::RightEdge:
_window->setCursor(Qt::SizeHorCursor); window->setCursor(Qt::SizeHorCursor);
break; break;
case Qt::TopEdge: case Qt::TopEdge:
case Qt::BottomEdge: case Qt::BottomEdge:
_window->setCursor(Qt::SizeVerCursor); window->setCursor(Qt::SizeVerCursor);
break; break;
case Qt::LeftEdge | Qt::TopEdge: case Qt::LeftEdge | Qt::TopEdge:
case Qt::RightEdge | Qt::BottomEdge: case Qt::RightEdge | Qt::BottomEdge:
_window->setCursor(Qt::SizeFDiagCursor); window->setCursor(Qt::SizeFDiagCursor);
break; break;
case Qt::RightEdge | Qt::TopEdge: case Qt::RightEdge | Qt::TopEdge:
case Qt::LeftEdge | Qt::BottomEdge: case Qt::LeftEdge | Qt::BottomEdge:
_window->setCursor(Qt::SizeBDiagCursor); window->setCursor(Qt::SizeBDiagCursor);
break; break;
} }
} }
bool FluFramelessHelper::eventFilter(QObject *obj, QEvent *ev){ bool FluFramelessHelper::eventFilter(QObject *obj, QEvent *ev){
if (!_window.isNull() && _window->flags() & Qt::FramelessWindowHint) { if (!window.isNull() && window->flags()) {
static int edges = 0; static int edges = 0;
const int margin = 8; const int margin = 8;
switch (ev->type()) { switch (ev->type()) {
case QEvent::MouseButtonPress: case QEvent::MouseButtonPress:
if(edges!=0){ if(edges!=0){
updateCursor(edges); QMouseEvent *event = static_cast<QMouseEvent*>(ev);
_window->startSystemResize(Qt::Edges(edges)); if(event->button() == Qt::LeftButton){
_updateCursor(edges);
window->startSystemResize(Qt::Edges(edges));
}
} }
break; break;
case QEvent::MouseButtonRelease: case QEvent::MouseButtonRelease:
edges = 0; edges = 0;
updateCursor(edges); _updateCursor(edges);
break; break;
case QEvent::MouseMove: { case QEvent::MouseMove: {
if(_window->visibility() == QWindow::Maximized || _window->visibility() == QWindow::FullScreen){ if(_maximized() || _fullScreen()){
break; break;
} }
if(_window->width() == _window->maximumWidth() && _window->width() == _window->minimumWidth() && _window->height() == _window->maximumHeight() && _window->height() == _window->minimumHeight()){ if(!resizeable()){
break; break;
} }
QMouseEvent *event = static_cast<QMouseEvent*>(ev); QMouseEvent *event = static_cast<QMouseEvent*>(ev);
@ -170,10 +223,10 @@ bool FluFramelessHelper::eventFilter(QObject *obj, QEvent *ev){
#else #else
event->position().toPoint(); event->position().toPoint();
#endif #endif
if(p.x() >= margin && p.x() <= (_window->width() - margin) && p.y() >= margin && p.y() <= (_window->height() - margin)){ if(p.x() >= margin && p.x() <= (window->width() - margin) && p.y() >= margin && p.y() <= (window->height() - margin)){
if(edges != 0){ if(edges != 0){
edges = 0; edges = 0;
updateCursor(edges); _updateCursor(edges);
} }
break; break;
} }
@ -181,16 +234,16 @@ bool FluFramelessHelper::eventFilter(QObject *obj, QEvent *ev){
if ( p.x() < margin ) { if ( p.x() < margin ) {
edges |= Qt::LeftEdge; edges |= Qt::LeftEdge;
} }
if ( p.x() > (_window->width() - margin) ) { if ( p.x() > (window->width() - margin) ) {
edges |= Qt::RightEdge; edges |= Qt::RightEdge;
} }
if ( p.y() < margin ) { if ( p.y() < margin ) {
edges |= Qt::TopEdge; edges |= Qt::TopEdge;
} }
if ( p.y() > (_window->height() - margin) ) { if ( p.y() > (window->height() - margin) ) {
edges |= Qt::BottomEdge; edges |= Qt::BottomEdge;
} }
updateCursor(edges); _updateCursor(edges);
break; break;
} }
default: default:
@ -203,54 +256,145 @@ bool FluFramelessHelper::eventFilter(QObject *obj, QEvent *ev){
void FluFramelessHelper::componentComplete(){ void FluFramelessHelper::componentComplete(){
auto o = parent(); auto o = parent();
while (nullptr != o) { while (nullptr != o) {
_window = (QQuickWindow*)o; window = (QQuickWindow*)o;
o = o->parent(); o = o->parent();
} }
if(!_window.isNull()){ if(!window.isNull()){
_window->setFlags(Qt::FramelessWindowHint|Qt::Window|Qt::WindowTitleHint|Qt::WindowMinMaxButtonsHint|Qt::WindowCloseButtonHint); _stayTop = QQmlProperty(window,"stayTop");
_screen = QQmlProperty(window,"screen");
_fixSize = QQmlProperty(window,"fixSize");
_originalPos = QQmlProperty(window,"_originalPos");
_accentColor = QQmlProperty(window,"_accentColor");
#ifdef Q_OS_WIN #ifdef Q_OS_WIN
_nativeEvent =new FramelessEventFilter(_window); if(isCompositionEnabled()){
_accentColor.write(getAccentColor());
_nativeEvent =new FramelessEventFilter(this);
qApp->installNativeEventFilter(_nativeEvent); qApp->installNativeEventFilter(_nativeEvent);
HWND hwnd = reinterpret_cast<HWND>(_window->winId()); HWND hwnd = reinterpret_cast<HWND>(window->winId());
DWORD style = ::GetWindowLong(hwnd, GWL_STYLE);
if(resizeable()){
SetWindowLongPtr(hwnd, GWL_STYLE, style | WS_MAXIMIZEBOX | WS_THICKFRAME | WS_CAPTION);
}else{
SetWindowLongPtr(hwnd, GWL_STYLE, style | WS_THICKFRAME | WS_CAPTION);
}
SetWindowPos(hwnd,nullptr,0,0,0,0,SWP_NOZORDER | SWP_NOOWNERZORDER | SWP_NOMOVE | SWP_NOSIZE | SWP_FRAMECHANGED); SetWindowPos(hwnd,nullptr,0,0,0,0,SWP_NOZORDER | SWP_NOOWNERZORDER | SWP_NOMOVE | SWP_NOSIZE | SWP_FRAMECHANGED);
showShadow(hwnd); if(_fixSize.read().toBool()){
window->setMaximumSize(window->size());
window->setMinimumSize(window->size());
}
}else{
window->setFlags((window->flags() & (~Qt::WindowMinMaxButtonsHint) & (~Qt::Dialog)) | Qt::FramelessWindowHint | Qt::Window);
}
#else
window->setFlags((window->flags() & (~Qt::WindowMinMaxButtonsHint) & (~Qt::Dialog)) | Qt::FramelessWindowHint | Qt::Window);
#endif #endif
_stayTop = QQmlProperty(_window,"stayTop");
_onStayTopChange(); _onStayTopChange();
_stayTop.connectNotifySignal(this,SLOT(_onStayTopChange())); _stayTop.connectNotifySignal(this,SLOT(_onStayTopChange()));
_screen = QQmlProperty(_window,"screen");
_screen.connectNotifySignal(this,SLOT(_onScreenChanged())); _screen.connectNotifySignal(this,SLOT(_onScreenChanged()));
_window->installEventFilter(this); window->installEventFilter(this);
} }
} }
void FluFramelessHelper::_onScreenChanged(){ void FluFramelessHelper::_onScreenChanged(){
_window->update(); #ifdef Q_OS_WIN
QGuiApplication::processEvents(); 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_THICKFRAME | WS_CAPTION | WS_SYSMENU | WS_MAXIMIZEBOX);
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_THICKFRAME | WS_CAPTION &~ WS_SYSMENU);
#endif
} }
void FluFramelessHelper::_onStayTopChange(){ void FluFramelessHelper::_onStayTopChange(){
bool isStayTop = _stayTop.read().toBool(); bool isStayTop = _stayTop.read().toBool();
#ifdef Q_OS_WIN #ifdef Q_OS_WIN
HWND hwnd = reinterpret_cast<HWND>(_window->winId()); HWND hwnd = reinterpret_cast<HWND>(window->winId());
DWORD style = GetWindowLongPtr(hwnd,GWL_STYLE);
SetWindowLongPtr(hwnd, GWL_STYLE, style | WS_THICKFRAME | WS_CAPTION &~ WS_SYSMENU);
if(isStayTop){ if(isStayTop){
SetWindowPos(hwnd, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE); SetWindowPos(hwnd, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE);
}else{ }else{
SetWindowPos(hwnd, HWND_NOTOPMOST, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE); SetWindowPos(hwnd, HWND_NOTOPMOST, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE);
} }
#else #else
_window->setFlag(Qt::WindowStaysOnTopHint,isStayTop); window->setFlag(Qt::WindowStaysOnTopHint,isStayTop);
#endif #endif
} }
FluFramelessHelper::~FluFramelessHelper(){ FluFramelessHelper::~FluFramelessHelper(){
if (!_window.isNull()) { if (!window.isNull()) {
_window->setFlags(Qt::Window); window->setFlags(Qt::Window);
#ifdef Q_OS_WIN #ifdef Q_OS_WIN
if(isCompositionEnabled()){
qApp->removeNativeEventFilter(_nativeEvent); qApp->removeNativeEventFilter(_nativeEvent);
delete _nativeEvent;
}
#endif #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 !(window->width() == window->maximumWidth() && window->width() == window->minimumWidth() && window->height() == window->maximumHeight() && window->height() == window->minimumHeight());
}
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; using QT_ENTER_EVENT_TYPE = QEvent;
#endif #endif
class FluFramelessHelper;
class FramelessEventFilter : public QAbstractNativeEventFilter class FramelessEventFilter : public QAbstractNativeEventFilter
{ {
public: public:
FramelessEventFilter(QQuickWindow* window); FramelessEventFilter(FluFramelessHelper* helper);
bool nativeEventFilter(const QByteArray &eventType, void *message, QT_NATIVE_EVENT_RESULT_TYPE *result) override; bool nativeEventFilter(const QByteArray &eventType, void *message, QT_NATIVE_EVENT_RESULT_TYPE *result) override;
public: public:
QQuickWindow* _window = nullptr; QPointer<FluFramelessHelper> _helper = nullptr;
qint64 _current = 0; qint64 _current = 0;
}; };
@ -34,17 +36,28 @@ public:
~FluFramelessHelper(); ~FluFramelessHelper();
void classBegin() override; void classBegin() override;
void componentComplete() override; void componentComplete() override;
bool hoverMaxBtn();
bool resizeable();
QObject* maximizeButton();
void setOriginalPos(QVariant pos);
Q_INVOKABLE void showSystemMenu();
protected: protected:
bool eventFilter(QObject *obj, QEvent *event) override; bool eventFilter(QObject *obj, QEvent *event) override;
private: private:
void updateCursor(int edges); void _updateCursor(int edges);
bool _maximized();
bool _fullScreen();
Q_SLOT void _onStayTopChange(); Q_SLOT void _onStayTopChange();
Q_SLOT void _onScreenChanged(); Q_SLOT void _onScreenChanged();
public:
QPointer<QQuickWindow> window = nullptr;
private: private:
QPointer<QQuickWindow> _window = nullptr;
FramelessEventFilter* _nativeEvent = nullptr; FramelessEventFilter* _nativeEvent = nullptr;
QQmlProperty _stayTop; QQmlProperty _stayTop;
QQmlProperty _screen; QQmlProperty _screen;
QQmlProperty _originalPos;
QQmlProperty _fixSize;
QQmlProperty _accentColor;
}; };
#endif // FLUFRAMELESSHELPER_H #endif // FLUFRAMELESSHELPER_H

View File

@ -14,6 +14,7 @@
#include <QTextDocument> #include <QTextDocument>
#include <QQuickWindow> #include <QQuickWindow>
#include <QDateTime> #include <QDateTime>
#include <QSettings>
FluTools::FluTools(QObject *parent):QObject{parent}{ FluTools::FluTools(QObject *parent):QObject{parent}{
@ -179,3 +180,63 @@ qint64 FluTools::currentTimestamp(){
QIcon FluTools::windowIcon(){ QIcon FluTools::windowIcon(){
return QGuiApplication::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();
}
}

View File

@ -50,6 +50,10 @@ public:
Q_INVOKABLE qint64 currentTimestamp(); Q_INVOKABLE qint64 currentTimestamp();
Q_INVOKABLE QPoint cursorPos(); Q_INVOKABLE QPoint cursorPos();
Q_INVOKABLE QIcon windowIcon(); Q_INVOKABLE QIcon windowIcon();
Q_INVOKABLE int cursorScreenIndex();
Q_INVOKABLE int windowBuildNumber();
Q_INVOKABLE bool isWindows11OrGreater();
Q_INVOKABLE bool isWindows10OrGreater();
}; };
#endif // FLUTOOLS_H #endif // FLUTOOLS_H

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/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/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/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/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/FluText.qml"),uri,major,minor,"FluText");
qmlRegisterType(QUrl("qrc:/qt/qml/FluentUI/Controls/FluTextBox.qml"),uri,major,minor,"FluTextBox"); qmlRegisterType(QUrl("qrc:/qt/qml/FluentUI/Controls/FluTextBox.qml"),uri,major,minor,"FluTextBox");

View File

@ -64,6 +64,11 @@ Rectangle{
FluTheme.darkMode = FluThemeType.Dark FluTheme.darkMode = FluThemeType.Dark
} }
} }
property var systemMenuListener: function(){
if(d.win instanceof FluWindow){
d.win.showSystemMenu()
}
}
id:control id:control
color: Qt.rgba(0,0,0,0) color: Qt.rgba(0,0,0,0)
height: visible ? 30 : 0 height: visible ? 30 : 0
@ -71,6 +76,7 @@ Rectangle{
z: 65535 z: 65535
Item{ Item{
id:d id:d
property bool hoverMaxBtn: false
property var win: Window.window property var win: Window.window
property bool stayTop: { property bool stayTop: {
if(d.win instanceof FluWindow){ if(d.win instanceof FluWindow){
@ -83,14 +89,23 @@ Rectangle{
} }
MouseArea{ MouseArea{
anchors.fill: parent anchors.fill: parent
onPositionChanged: { onPositionChanged:
(mouse)=>{
d.win.startSystemMove() d.win.startSystemMove()
} }
onDoubleClicked: { onDoubleClicked:
if(d.resizable){ (mouse)=>{
if(d.resizable && Qt.LeftButton){
btn_maximize.clicked() btn_maximize.clicked()
} }
} }
acceptedButtons: Qt.LeftButton|Qt.RightButton
onClicked:
(mouse)=>{
if (mouse.button === Qt.RightButton){
control.systemMenuListener()
}
}
} }
Row{ Row{
anchors{ anchors{
@ -218,6 +233,9 @@ Rectangle{
if(pressed){ if(pressed){
return maximizePressColor return maximizePressColor
} }
if(FluTools.isWindows11OrGreater()){
return d.hoverMaxBtn ? maximizeHoverColor : maximizeNormalColor
}
return hovered ? maximizeHoverColor : maximizeNormalColor return hovered ? maximizeHoverColor : maximizeNormalColor
} }
Layout.alignment: Qt.AlignVCenter Layout.alignment: Qt.AlignVCenter
@ -263,4 +281,17 @@ Rectangle{
function darkButton(){ function darkButton(){
return btn_dark 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

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

View File

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

View File

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

View File

@ -13,12 +13,11 @@ Rectangle {
color: FluTheme.dark ? Qt.rgba(39/255,39/255,39/255,1) : Qt.rgba(251/255,251/255,253/255,1) color: FluTheme.dark ? Qt.rgba(39/255,39/255,39/255,1) : Qt.rgba(251/255,251/255,253/255,1)
onColumnSourceChanged: { onColumnSourceChanged: {
if(columnSource.length!==0){ if(columnSource.length!==0){
var com_column = Qt.createComponent("FluTableModelColumn.qml")
if (com_column.status === Component.Ready) {
var columns= [] var columns= []
var header_rows = {} var header_rows = {}
columnSource.forEach(function(item){ columnSource.forEach(function(item){
var column = com_column.createObject(table_model,{display:item.dataIndex}); var column = Qt.createQmlObject('import Qt.labs.qmlmodels 1.0;TableModelColumn{}',table_model);
column.display = item.dataIndex
columns.push(column) columns.push(column)
header_rows[item.dataIndex] = item.title header_rows[item.dataIndex] = item.title
}) })
@ -27,7 +26,6 @@ Rectangle {
d.header_rows = [header_rows] d.header_rows = [header_rows]
} }
} }
}
QtObject{ QtObject{
id:d id:d
property var currentRow property var currentRow

View File

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

View File

@ -40,7 +40,12 @@ Window {
property bool showStayTop: true property bool showStayTop: true
property bool autoMaximize: false property bool autoMaximize: false
property bool useSystemAppBar 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 int resizeBorderWidth: 1
property var closeListener: function(event){ property var closeListener: function(event){
if(closeDestory){ if(closeDestory){
@ -50,22 +55,22 @@ Window {
event.accepted = false event.accepted = false
} }
} }
signal showSystemMenu
signal initArgument(var argument) signal initArgument(var argument)
signal firstVisible() signal firstVisible()
property point _offsetXY : Qt.point(0,0)
property var _originalPos
property color _accentColor : FluTheme.dark ? "#333333" : "#6E6E6E"
id:window id:window
maximumWidth: fixSize ? width : 16777215
maximumHeight: fixSize ? height : 16777215
minimumWidth: fixSize ? width : 0
minimumHeight: fixSize ? height : 0
color:"transparent" color:"transparent"
Component.onCompleted: { Component.onCompleted: {
moveWindowToDesktopCenter()
useSystemAppBar = FluApp.useSystemAppBar useSystemAppBar = FluApp.useSystemAppBar
if(!useSystemAppBar){ if(!useSystemAppBar){
loader_frameless.sourceComponent = com_frameless loader_frameless_helper.sourceComponent = com_frameless
} }
lifecycle.onCompleted(window) lifecycle.onCompleted(window)
initArgument(argument) initArgument(argument)
moveWindowToDesktopCenter()
if(window.autoMaximize){ if(window.autoMaximize){
window.showMaximized() window.showMaximized()
}else{ }else{
@ -75,6 +80,24 @@ Window {
Component.onDestruction: { Component.onDestruction: {
lifecycle.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),Math.abs(dy))
}else{
_offsetXY = Qt.point(0,0)
}
}else{
_offsetXY = Qt.point(0,0)
}
}
onShowSystemMenu: {
if(loader_frameless_helper.item){
loader_frameless_helper.item.showSystemMenu()
}
}
onVisibleChanged: { onVisibleChanged: {
if(visible && d.isFirstVisible){ if(visible && d.isFirstVisible){
window.firstVisible() window.firstVisible()
@ -169,34 +192,13 @@ Window {
} }
} }
FluLoader{ FluLoader{
id:loader_frameless id:loader_frameless_helper
} }
Item{ Item{
id:layout_container 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
}
anchors{ anchors{
fill:parent fill:parent
leftMargin: offsetX topMargin: _offsetXY.y
rightMargin: offsetX
topMargin: offsetY
bottomMargin: offsetY
} }
onWidthChanged: { onWidthChanged: {
window.appBar.width = width window.appBar.width = width
@ -249,7 +251,27 @@ Window {
border.width: window.resizeBorderWidth border.width: window.resizeBorderWidth
border.color: window.resizeBorderColor border.color: window.resizeBorderColor
visible: { visible: {
if(window.useSystemAppBar){ if(window.useSystemAppBar || FluTools.isWindows10OrGreater()){
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
}
}
Rectangle{
height: 1
width: parent.width
color: window.resizeBorderColor
visible: {
if(window.useSystemAppBar || !FluTools.isWin()){
return false return false
} }
if(window.visibility == Window.Maximized || window.visibility == Window.FullScreen){ if(window.visibility == Window.Maximized || window.visibility == Window.FullScreen){
@ -286,7 +308,14 @@ Window {
return lifecycle.createRegister(window,path) return lifecycle.createRegister(window,path)
} }
function moveWindowToDesktopCenter(){ function moveWindowToDesktopCenter(){
screen = Qt.application.screens[FluTools.cursorScreenIndex()]
window.setGeometry((Screen.width-window.width)/2+Screen.virtualX,(Screen.height-window.height)/2+Screen.virtualY,window.width,window.height) window.setGeometry((Screen.width-window.width)/2+Screen.virtualX,(Screen.height-window.height)/2+Screen.virtualY,window.width,window.height)
if(fixSize){
maximumWidth = width
maximumHeight = height
minimumWidth = width
minimumHeight = height
}
} }
function onResult(data){ function onResult(data){
if(_pageRegister){ if(_pageRegister){

View File

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

View File

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

View File

@ -64,6 +64,11 @@ Rectangle{
FluTheme.darkMode = FluThemeType.Dark FluTheme.darkMode = FluThemeType.Dark
} }
} }
property var systemMenuListener: function(){
if(d.win instanceof FluWindow){
d.win.showSystemMenu()
}
}
id:control id:control
color: Qt.rgba(0,0,0,0) color: Qt.rgba(0,0,0,0)
height: visible ? 30 : 0 height: visible ? 30 : 0
@ -71,6 +76,7 @@ Rectangle{
z: 65535 z: 65535
Item{ Item{
id:d id:d
property bool hoverMaxBtn: false
property var win: Window.window property var win: Window.window
property bool stayTop: { property bool stayTop: {
if(d.win instanceof FluWindow){ if(d.win instanceof FluWindow){
@ -83,14 +89,23 @@ Rectangle{
} }
MouseArea{ MouseArea{
anchors.fill: parent anchors.fill: parent
onPositionChanged: { onPositionChanged:
(mouse)=>{
d.win.startSystemMove() d.win.startSystemMove()
} }
onDoubleClicked: { onDoubleClicked:
if(d.resizable){ (mouse)=>{
if(d.resizable && Qt.LeftButton){
btn_maximize.clicked() btn_maximize.clicked()
} }
} }
acceptedButtons: Qt.LeftButton|Qt.RightButton
onClicked:
(mouse)=>{
if (mouse.button === Qt.RightButton){
control.systemMenuListener()
}
}
} }
Row{ Row{
anchors{ anchors{
@ -218,6 +233,9 @@ Rectangle{
if(pressed){ if(pressed){
return maximizePressColor return maximizePressColor
} }
if(FluTools.isWindows11OrGreater()){
return d.hoverMaxBtn ? maximizeHoverColor : maximizeNormalColor
}
return hovered ? maximizeHoverColor : maximizeNormalColor return hovered ? maximizeHoverColor : maximizeNormalColor
} }
Layout.alignment: Qt.AlignVCenter Layout.alignment: Qt.AlignVCenter
@ -263,4 +281,17 @@ Rectangle{
function darkButton(){ function darkButton(){
return btn_dark 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

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

View File

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

View File

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

View File

@ -14,12 +14,11 @@ Rectangle {
color: FluTheme.dark ? Qt.rgba(39/255,39/255,39/255,1) : Qt.rgba(251/255,251/255,253/255,1) color: FluTheme.dark ? Qt.rgba(39/255,39/255,39/255,1) : Qt.rgba(251/255,251/255,253/255,1)
onColumnSourceChanged: { onColumnSourceChanged: {
if(columnSource.length!==0){ if(columnSource.length!==0){
var com_column = Qt.createComponent("FluTableModelColumn.qml")
if (com_column.status === Component.Ready) {
var columns= [] var columns= []
var header_rows = {} var header_rows = {}
columnSource.forEach(function(item){ columnSource.forEach(function(item){
var column = com_column.createObject(table_model,{display:item.dataIndex}); var column = Qt.createQmlObject('import Qt.labs.qmlmodels;TableModelColumn{}',table_model);
column.display = item.dataIndex
columns.push(column) columns.push(column)
header_rows[item.dataIndex] = item.title header_rows[item.dataIndex] = item.title
}) })
@ -28,7 +27,6 @@ Rectangle {
d.header_rows = [header_rows] d.header_rows = [header_rows]
} }
} }
}
QtObject{ QtObject{
id:d id:d
property var currentRow property var currentRow

View File

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

View File

@ -39,7 +39,12 @@ Window {
property bool showStayTop: true property bool showStayTop: true
property bool autoMaximize: false property bool autoMaximize: false
property bool useSystemAppBar 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 int resizeBorderWidth: 1
property var closeListener: function(event){ property var closeListener: function(event){
if(closeDestory){ if(closeDestory){
@ -49,22 +54,22 @@ Window {
event.accepted = false event.accepted = false
} }
} }
signal showSystemMenu
signal initArgument(var argument) signal initArgument(var argument)
signal firstVisible() signal firstVisible()
property point _offsetXY : Qt.point(0,0)
property var _originalPos
property color _accentColor : FluTheme.dark ? "#333333" : "#6E6E6E"
id:window id:window
maximumWidth: fixSize ? width : 16777215
maximumHeight: fixSize ? height : 16777215
minimumWidth: fixSize ? width : 0
minimumHeight: fixSize ? height : 0
color:"transparent" color:"transparent"
Component.onCompleted: { Component.onCompleted: {
moveWindowToDesktopCenter()
useSystemAppBar = FluApp.useSystemAppBar useSystemAppBar = FluApp.useSystemAppBar
if(!useSystemAppBar){ if(!useSystemAppBar){
loader_frameless.sourceComponent = com_frameless loader_frameless_helper.sourceComponent = com_frameless
} }
lifecycle.onCompleted(window) lifecycle.onCompleted(window)
initArgument(argument) initArgument(argument)
moveWindowToDesktopCenter()
if(window.autoMaximize){ if(window.autoMaximize){
window.showMaximized() window.showMaximized()
}else{ }else{
@ -74,6 +79,24 @@ Window {
Component.onDestruction: { Component.onDestruction: {
lifecycle.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),Math.abs(dy))
}else{
_offsetXY = Qt.point(0,0)
}
}else{
_offsetXY = Qt.point(0,0)
}
}
onShowSystemMenu: {
if(loader_frameless_helper.item){
loader_frameless_helper.item.showSystemMenu()
}
}
onVisibleChanged: { onVisibleChanged: {
if(visible && d.isFirstVisible){ if(visible && d.isFirstVisible){
window.firstVisible() window.firstVisible()
@ -168,34 +191,13 @@ Window {
} }
} }
FluLoader{ FluLoader{
id:loader_frameless id:loader_frameless_helper
} }
Item{ Item{
id:layout_container 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
}
anchors{ anchors{
fill:parent fill:parent
leftMargin: offsetX topMargin: _offsetXY.y
rightMargin: offsetX
topMargin: offsetY
bottomMargin: offsetY
} }
onWidthChanged: { onWidthChanged: {
window.appBar.width = width window.appBar.width = width
@ -248,7 +250,27 @@ Window {
border.width: window.resizeBorderWidth border.width: window.resizeBorderWidth
border.color: window.resizeBorderColor border.color: window.resizeBorderColor
visible: { visible: {
if(window.useSystemAppBar){ if(window.useSystemAppBar || FluTools.isWindows10OrGreater()){
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
}
}
Rectangle{
height: 1
width: parent.width
color: window.resizeBorderColor
visible: {
if(window.useSystemAppBar || !FluTools.isWin()){
return false return false
} }
if(window.visibility == Window.Maximized || window.visibility == Window.FullScreen){ if(window.visibility == Window.Maximized || window.visibility == Window.FullScreen){
@ -285,7 +307,14 @@ Window {
return lifecycle.createRegister(window,path) return lifecycle.createRegister(window,path)
} }
function moveWindowToDesktopCenter(){ function moveWindowToDesktopCenter(){
screen = Qt.application.screens[FluTools.cursorScreenIndex()]
window.setGeometry((Screen.width-window.width)/2+Screen.virtualX,(Screen.height-window.height)/2+Screen.virtualY,window.width,window.height) window.setGeometry((Screen.width-window.width)/2+Screen.virtualX,(Screen.height-window.height)/2+Screen.virtualY,window.width,window.height)
if(fixSize){
maximumWidth = width
maximumHeight = height
minimumWidth = width
minimumHeight = height
}
} }
function onResult(data){ function onResult(data){
if(_pageRegister){ if(_pageRegister){

View File

@ -4,6 +4,7 @@
#include "FluRegister.h" #include "FluRegister.h"
WindowLifecycle::WindowLifecycle(QObject *parent):QObject{parent}{ WindowLifecycle::WindowLifecycle(QObject *parent):QObject{parent}{
} }
void WindowLifecycle::onCompleted(QQuickWindow* window){ void WindowLifecycle::onCompleted(QQuickWindow* window){
@ -12,7 +13,10 @@ void WindowLifecycle::onCompleted(QQuickWindow* window){
} }
void WindowLifecycle::onDestoryOnClose(){ void WindowLifecycle::onDestoryOnClose(){
if(_window){
FluApp::getInstance()->removeWindow(this->_window); FluApp::getInstance()->removeWindow(this->_window);
_window = nullptr;
}
} }
void WindowLifecycle::onDestruction(){ void WindowLifecycle::onDestruction(){

View File

@ -23,7 +23,7 @@ public:
Q_INVOKABLE void onDestoryOnClose(); Q_INVOKABLE void onDestoryOnClose();
Q_INVOKABLE QVariant createRegister(QQuickWindow* window,const QString& path); Q_INVOKABLE QVariant createRegister(QQuickWindow* window,const QString& path);
private: private:
QQuickWindow* _window; QQuickWindow* _window = nullptr;
}; };
#endif // WINDOWLIFECYCLE_H #endif // WINDOWLIFECYCLE_H

View File

@ -44,4 +44,10 @@ private: \
return Singleton<Class>::getInstance(); \ return Singleton<Class>::getInstance(); \
} }
#define HIDE_CONSTRUCTOR(Class) \
private: \
Class() = default; \
Class(const Class& other) = delete; \
Class& operator=(const Class& other) = delete;
#endif // SINGLETON_H #endif // SINGLETON_H