Compare commits

...

3 Commits

13 changed files with 172 additions and 64 deletions

4
.gitmodules vendored
View File

@ -1,3 +1,3 @@
[submodule "3rdparty/framelesshelper"] [submodule "lib_source/3rdparty/framelesshelper"]
path = 3rdparty/framelesshelper path = lib_source/3rdparty/framelesshelper
url = git@github.com:mentalfl0w/framelesshelper.git url = git@github.com:mentalfl0w/framelesshelper.git

View File

@ -10,27 +10,18 @@ option(RIBBONUI_BUILD_EXAMPLES "Build RibbonUI APP." ON)
option(RIBBONUI_BUILD_FRAMELESSHEPLER "Build FramelessHelper." ON) option(RIBBONUI_BUILD_FRAMELESSHEPLER "Build FramelessHelper." ON)
option(RIBBONUI_BUILD_STATIC_LIB "Build RibbonUI static library." OFF) option(RIBBONUI_BUILD_STATIC_LIB "Build RibbonUI static library." OFF)
add_subdirectory(lib_source)
if (RIBBONUI_BUILD_EXAMPLES) if (RIBBONUI_BUILD_EXAMPLES)
add_subdirectory(example) add_subdirectory(example)
endif() endif()
if (RIBBONUI_BUILD_FRAMELESSHEPLER)
set(FRAMELESSHELPER_BUILD_STATIC ON)
set(FRAMELESSHELPER_NO_SUMMARY OFF)
set(FRAMELESSHELPER_NO_DEBUG_OUTPUT ON)
set(FRAMELESSHELPER_BUILD_WIDGETS OFF)
add_subdirectory(3rdparty/framelesshelper)
endif()
if(NOT RIBBONUI_QML_PLUGIN_DIRECTORY) if(NOT RIBBONUI_QML_PLUGIN_DIRECTORY)
set(RIBBONUI_QML_PLUGIN_DIRECTORY ${QT_SDK_DIR}/qml/RibbonUI CACHE PATH "RibbonUI Plugin Path") set(RIBBONUI_QML_PLUGIN_DIRECTORY ${QT_SDK_DIR}/qml/RibbonUI CACHE PATH "RibbonUI Plugin Path")
endif() endif()
add_subdirectory(lib_source)
message("---------------------------- RibbonUI ----------------------------") message("---------------------------- RibbonUI ----------------------------")
message("Build RibbonUI APP: ${RIBBONUI_BUILD_EXAMPLES}") message("Build RibbonUI APP: ${RIBBONUI_BUILD_EXAMPLES}")
message("Build FramelessHelper: ${RIBBONUI_BUILD_FRAMELESSHEPLER}")
message("Build RibbonUI static library: ${RIBBONUI_BUILD_STATIC_LIB}") message("Build RibbonUI static library: ${RIBBONUI_BUILD_STATIC_LIB}")
message("RibbonUI QML Plugin Path: ${RIBBONUI_QML_PLUGIN_DIRECTORY}") message("RibbonUI QML Plugin Path: ${RIBBONUI_QML_PLUGIN_DIRECTORY}")
message("------------------------------------------------------------------") message("------------------------------------------------------------------")

View File

@ -85,7 +85,7 @@ qt_add_qml_module(${PROJECT_NAME}
URI ${PROJECT_NAME} URI ${PROJECT_NAME}
VERSION ${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR} VERSION ${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR}
RESOURCE_PREFIX "/qt/qml/" RESOURCE_PREFIX "/qt/qml/"
QML_FILES example.qml components/RibbonWindow.qml QML_FILES example.qml
RESOURCES resources/imgs/heart.png resources/imgs/search.png RESOURCES resources/imgs/heart.png resources/imgs/search.png
) )
@ -97,22 +97,19 @@ set_target_properties(${PROJECT_NAME} PROPERTIES
) )
if(RIBBONUI_BUILD_STATIC_LIB) if(RIBBONUI_BUILD_STATIC_LIB)
add_definitions(-DRIBBONUI_BUILD_STATIC_LIB)
target_link_libraries(${PROJECT_NAME} PRIVATE target_link_libraries(${PROJECT_NAME} PRIVATE
Qt::Quick
RibbonUIplugin RibbonUIplugin
FramelessHelper::Core
FramelessHelper::Quick
) )
target_compile_definitions(${PROJECT_NAME} PRIVATE
else() RIBBONUI_BUILD_STATIC_LIB
target_link_libraries(${PROJECT_NAME} PRIVATE
Qt::Quick
RibbonUI
FramelessHelper::Core
FramelessHelper::Quick
) )
endif() endif()
target_link_libraries(${PROJECT_NAME} PRIVATE
Qt::Quick
RibbonUI
)
target_compile_definitions(${PROJECT_NAME} PRIVATE $<$<OR:$<CONFIG:Debug>,$<CONFIG:RelWithDebInfo>>:QT_QML_DEBUG>) target_compile_definitions(${PROJECT_NAME} PRIVATE $<$<OR:$<CONFIG:Debug>,$<CONFIG:RelWithDebInfo>>:QT_QML_DEBUG>)
target_include_directories(${PROJECT_NAME} PUBLIC ${PROJECT_SOURCE_DIR}) target_include_directories(${PROJECT_NAME} PUBLIC ${PROJECT_SOURCE_DIR})

View File

@ -1,28 +1,17 @@
#include <QGuiApplication> #include <QGuiApplication>
#include <QQmlApplicationEngine> #include <QQmlApplicationEngine>
#include <QtQml/qqmlextensionplugin.h> #include <QtQml/qqmlextensionplugin.h>
#include <FramelessHelper/Quick/framelessquickmodule.h> #include "ribbonui.h"
#include <FramelessHelper/Core/private/framelessconfig_p.h>
FRAMELESSHELPER_USE_NAMESPACE
#ifdef RIBBONUI_BUILD_STATIC_LIB #ifdef RIBBONUI_BUILD_STATIC_LIB
Q_IMPORT_QML_PLUGIN(RibbonUIPlugin) Q_IMPORT_QML_PLUGIN(RibbonUIPlugin)
#endif #endif
int main(int argc, char *argv[]) int main(int argc, char *argv[])
{ {
qputenv("QT_QUICK_CONTROLS_STYLE","Basic"); RibbonUI::init(); // Must set before QGuiApplication
FramelessHelper::Quick::initialize();
QGuiApplication app(argc, argv); QGuiApplication app(argc, argv);
#ifdef Q_OS_WIN
FramelessConfig::instance()->set(Global::Option::ForceHideWindowFrameBorder);
#endif
FramelessConfig::instance()->set(Global::Option::DisableLazyInitializationForMicaMaterial);
FramelessConfig::instance()->set(Global::Option::CenterWindowBeforeShow);
FramelessConfig::instance()->set(Global::Option::EnableBlurBehindWindow);
QQmlApplicationEngine engine; QQmlApplicationEngine engine;
FramelessHelper::Quick::registerTypes(&engine); RibbonUI::registerTypes(&engine);
const QUrl url(u"qrc:/qt/qml/RibbonUIAPP/example.qml"_qs); const QUrl url(u"qrc:/qt/qml/RibbonUIAPP/example.qml"_qs);
QObject::connect(&engine, &QQmlApplicationEngine::objectCreated, QObject::connect(&engine, &QQmlApplicationEngine::objectCreated,
&app, [url](QObject *obj, const QUrl &objUrl) { &app, [url](QObject *obj, const QUrl &objUrl) {

View File

@ -5,7 +5,6 @@ import QtQuick.Controls.Material
import QtQuick.Window import QtQuick.Window
import RibbonUI import RibbonUI
import org.wangwenx190.FramelessHelper import org.wangwenx190.FramelessHelper
import "components"
RibbonWindow { RibbonWindow {
id:root id:root

View File

@ -6,6 +6,8 @@ set(CMAKE_CXX_STANDARD_REQUIRED ON)
list(APPEND CMAKE_MODULE_PATH ${CMAKE_CURRENT_SOURCE_DIR}/.cmake/) list(APPEND CMAKE_MODULE_PATH ${CMAKE_CURRENT_SOURCE_DIR}/.cmake/)
include(GNUInstallDirs)
if(QT_VERSION VERSION_GREATER_EQUAL "6.3") if(QT_VERSION VERSION_GREATER_EQUAL "6.3")
qt_standard_project_setup() qt_standard_project_setup()
qt_policy(SET QTP0001 NEW) qt_policy(SET QTP0001 NEW)
@ -19,6 +21,12 @@ if(APPLE)
set(CMAKE_OSX_ARCHITECTURES "arm64;x86_64" CACHE STRING "" FORCE) set(CMAKE_OSX_ARCHITECTURES "arm64;x86_64" CACHE STRING "" FORCE)
endif() endif()
set(FRAMELESSHELPER_BUILD_STATIC ON)
set(FRAMELESSHELPER_NO_SUMMARY OFF)
set(FRAMELESSHELPER_NO_DEBUG_OUTPUT ON)
set(FRAMELESSHELPER_BUILD_WIDGETS OFF)
add_subdirectory(3rdparty/framelesshelper)
find_package(Qt6 COMPONENTS Core Quick Qml REQUIRED) find_package(Qt6 COMPONENTS Core Quick Qml REQUIRED)
set(version_str "${PROJECT_VERSION_MAJOR},${PROJECT_VERSION_MINOR},${PROJECT_VERSION_PATCH}") set(version_str "${PROJECT_VERSION_MAJOR},${PROJECT_VERSION_MINOR},${PROJECT_VERSION_PATCH}")
@ -44,14 +52,14 @@ set(
qml/RibbonText.qml qml/RibbonTextBoxMenu.qml qml/RibbonPopup.qml qml/RibbonText.qml qml/RibbonTextBoxMenu.qml qml/RibbonPopup.qml
qml/RibbonPopupDialog.qml qml/RibbonLineEdit.qml qml/RibbonTextEdit.qml qml/RibbonPopupDialog.qml qml/RibbonLineEdit.qml qml/RibbonTextEdit.qml
qml/RibbonComboBox.qml qml/RibbonSpinBox.qml qml/RibbonScrollIndicator.qml qml/RibbonComboBox.qml qml/RibbonSpinBox.qml qml/RibbonScrollIndicator.qml
qml/RibbonScrollBar.qml qml/RibbonScrollBar.qml qml/RibbonWindow.qml
) )
foreach(qmlfile ${qml_files}) foreach(qmlfile ${qml_files})
string(REPLACE "qml/" "" fixedfile ${qmlfile}) string(REPLACE "qml/" "" fixedfile ${qmlfile})
set_source_files_properties(${qmlfile} PROPERTIES QT_RESOURCE_ALIAS ${fixedfile}) set_source_files_properties(${qmlfile} PROPERTIES QT_RESOURCE_ALIAS ${fixedfile})
endforeach(qmlfile) endforeach(qmlfile)
message(${RIBBONUI_QML_PLUGIN_DIRECTORY})
qt_add_library(${PROJECT_NAME} ${LIB_TYPE}) qt_add_library(${PROJECT_NAME} ${LIB_TYPE})
qt_add_qml_module(${PROJECT_NAME} qt_add_qml_module(${PROJECT_NAME}
PLUGIN_TARGET ${PLUGIN_TARGET_NAME} PLUGIN_TARGET ${PLUGIN_TARGET_NAME}
@ -64,13 +72,38 @@ qt_add_qml_module(${PROJECT_NAME}
RESOURCE_PREFIX "/qt/qml/" RESOURCE_PREFIX "/qt/qml/"
) )
if (MINGW)
set_target_properties(${PROJECT_NAME} PROPERTIES PREFIX "")
endif()
if (MSVC)
set_target_properties(${PROJECT_NAME} PROPERTIES DEBUG_POSTFIX "d")
endif()
if (RIBBONUI_BUILD_STATIC_LIB)
target_compile_definitions(${PROJECT_NAME} PRIVATE
RIBBONUI_BUILD_STATIC_LIB
)
endif()
target_compile_definitions(${PROJECT_NAME} target_compile_definitions(${PROJECT_NAME}
PRIVATE $<$<OR:$<CONFIG:Debug>,$<CONFIG:RelWithDebInfo>>:QT_QML_DEBUG>) PRIVATE $<$<OR:$<CONFIG:Debug>,$<CONFIG:RelWithDebInfo>>:QT_QML_DEBUG>
RIBBONUI_LIBRARY
)
target_link_libraries(${PROJECT_NAME} PRIVATE target_link_libraries(${PROJECT_NAME} PRIVATE
Qt::Quick Qt::Quick
Qt::CorePrivate Qt::CorePrivate
Qt::QuickPrivate Qt::QuickPrivate
Qt::QmlPrivate Qt::QmlPrivate
) )
target_link_libraries(${PROJECT_NAME} PUBLIC
FramelessHelper::Core
FramelessHelper::Quick
)
target_include_directories(${PROJECT_NAME} PUBLIC
${PROJECT_SOURCE_DIR}
${PROJECT_SOURCE_DIR}/3rdparty/framelesshelper/include
)
install(DIRECTORY ${RIBBONUI_QML_PLUGIN_DIRECTORY} DESTINATION ${CMAKE_INSTALL_PREFIX}/imports)
target_include_directories(${PROJECT_NAME} PUBLIC ${CMAKE_CURRENT_SOURCE_DIR})

View File

@ -5,6 +5,18 @@
#include <QtQml/qqml.h> #include <QtQml/qqml.h>
#include <QtQml/qqmlregistration.h> #include <QtQml/qqmlregistration.h>
#ifndef RIBBONUI_API
# ifdef RIBBONUI_BUILD_STATIC_LIB
# define RIBBONUI_API
# else // RIBBONUI_BUILD_STATIC_LIB
# ifdef RIBBONUI_LIBRARY
# define RIBBONUI_API Q_DECL_EXPORT
# else // RIBBONUI_LIBRARY
# define RIBBONUI_API Q_DECL_IMPORT
# endif // RIBBONUI_LIBRARY
# endif // RIBBONUI_BUILD_STATIC_LIB
#endif // RIBBONUI_API
namespace RibbonIconsFilledEnum { namespace RibbonIconsFilledEnum {
Q_NAMESPACE Q_NAMESPACE
enum class RibbonIcons_Filled{ enum class RibbonIcons_Filled{

View File

@ -10,18 +10,18 @@ ScrollBar {
implicitHeight: Math.max(implicitBackgroundHeight + topInset + bottomInset, implicitHeight: Math.max(implicitBackgroundHeight + topInset + bottomInset,
implicitContentHeight + topPadding + bottomPadding) implicitContentHeight + topPadding + bottomPadding)
verticalPadding: (control.vertical ? 8 + 5 : 0) + (18 - 8) / 2 verticalPadding: control.hovered || control.pressed ? (control.vertical ? 8 + 5 : 0) + (18 - 8) / 2 : 2
horizontalPadding: (control.vertical ? 0 : 8 + 5) + (18 - 8) / 2 horizontalPadding: control.hovered || control.pressed ? (control.vertical ? 0 : 8 + 5) + (18 - 8) / 2 : 2
visible: control.policy !== ScrollBar.AlwaysOff visible: control.policy !== ScrollBar.AlwaysOff
minimumSize: orientation === Qt.Horizontal ? height / width : width / height minimumSize: orientation === Qt.Horizontal ? height / width : width / height
contentItem: Rectangle { contentItem: Rectangle {
implicitWidth: 8 implicitWidth: control.hovered || control.pressed ? 8 : 4
implicitHeight: 8 implicitHeight: control.hovered || control.pressed ? 8 : 4
visible: control.size < 1.0 visible: control.size < 1.0
radius: width / 2 radius: width / 2
color: RibbonTheme.dark_mode ? hover_handler.hovered ? '#D6D6D6' : hover_handler.hovered && control.pressed ? '#E5E5E5' : '#999999' color: RibbonTheme.dark_mode ? hover_handler.hovered ? '#D6D6D6' : hover_handler.hovered && control.pressed ? '#E5E5E5' : '#999999'
: hover_handler.hovered ? '#424242' : hover_handler.hovered && control.pressed ? '#333333' : '#707070' : hover_handler.hovered ? '#424242' : hover_handler.hovered && control.pressed ? '#333333' : '#707070'
opacity: 0.0 opacity: 0.0
states: State { states: State {
@ -38,21 +38,41 @@ ScrollBar {
} }
} }
Behavior on implicitWidth {
SequentialAnimation {
PauseAnimation { duration: hover_handler.hovered ? 0 : 300 }
NumberAnimation {
duration: 200
easing.type: Easing.OutSine
}
}
}
Behavior on implicitHeight {
SequentialAnimation {
PauseAnimation { duration: hover_handler.hovered ? 0 : 300 }
NumberAnimation {
duration: 200
easing.type: Easing.OutSine
}
}
}
HoverHandler{ HoverHandler{
id:hover_handler id:hover_handler
} }
} }
background: Rectangle{ background: Rectangle{
implicitWidth: 18 implicitWidth: control.hovered || control.pressed ? 18 : 0
implicitHeight: 18 implicitHeight: control.hovered || control.pressed ? 18 : 0
color: RibbonTheme.dark_mode ? '#141414' : '#F5F5F5' color: RibbonTheme.dark_mode ? '#141414' : '#F5F5F5'
opacity: 0.0 opacity: 0.0
radius: implicitWidth / 2 radius: implicitWidth / 2
visible: control.contentItem.visible visible: control.contentItem.visible
states: State { states: State {
name: "active" name: "active"
when: control.active when: control.active && control.hovered
PropertyChanges { control.background.opacity: 0.75 } PropertyChanges { control.background.opacity: 0.75 }
} }
@ -60,9 +80,14 @@ ScrollBar {
Transition { Transition {
from: "active" from: "active"
SequentialAnimation { SequentialAnimation {
PauseAnimation { duration: 450 }
NumberAnimation { target: control.background; duration: 200; property: "opacity"; to: 0.0 } NumberAnimation { target: control.background; duration: 200; property: "opacity"; to: 0.0 }
} }
},
Transition {
to: "active"
SequentialAnimation {
NumberAnimation { target: control.background; duration: 200; property: "opacity";}
}
} }
] ]
@ -76,7 +101,7 @@ ScrollBar {
onClicked: control.decrease() onClicked: control.decrease()
Component.onCompleted: setup() Component.onCompleted: setup()
ribbon_icon.filled: true ribbon_icon.filled: true
ribbon_icon.icon_size: 14 ribbon_icon.icon_size: 15
ribbon_icon.color: RibbonTheme.dark_mode ? hovered ? '#D6D6D6' : pressed ? '#E5E5E5' : '#999999' ribbon_icon.color: RibbonTheme.dark_mode ? hovered ? '#D6D6D6' : pressed ? '#E5E5E5' : '#999999'
: hovered ? '#424242' : pressed ? '#333333' : '#707070' : hovered ? '#424242' : pressed ? '#333333' : '#707070'
Connections{ Connections{
@ -116,7 +141,7 @@ ScrollBar {
onClicked: control.increase() onClicked: control.increase()
Component.onCompleted: setup() Component.onCompleted: setup()
ribbon_icon.filled: true ribbon_icon.filled: true
ribbon_icon.icon_size: 14 ribbon_icon.icon_size: 15
ribbon_icon.color: RibbonTheme.dark_mode ? hovered ? '#D6D6D6' : pressed ? '#E5E5E5' : '#999999' ribbon_icon.color: RibbonTheme.dark_mode ? hovered ? '#D6D6D6' : pressed ? '#E5E5E5' : '#999999'
: hovered ? '#424242' : pressed ? '#333333' : '#707070' : hovered ? '#424242' : pressed ? '#333333' : '#707070'
Connections{ Connections{
@ -146,4 +171,20 @@ ScrollBar {
} }
} }
} }
Behavior on verticalPadding {
enabled: control.hovered
NumberAnimation {
duration: 100
easing.type: Easing.OutSine
}
}
Behavior on horizontalPadding {
enabled: control.hovered
NumberAnimation {
duration: 100
easing.type: Easing.OutSine
}
}
} }

View File

@ -10,11 +10,11 @@ ScrollIndicator {
implicitHeight: Math.max(implicitBackgroundHeight + topInset + bottomInset, implicitHeight: Math.max(implicitBackgroundHeight + topInset + bottomInset,
implicitContentHeight + topPadding + bottomPadding) implicitContentHeight + topPadding + bottomPadding)
padding: (control.background.implicitWidth - control.contentItem.implicitWidth)/2 padding: control.hovered ? (control.background.implicitWidth - control.contentItem.implicitWidth)/2 : 2
contentItem: Rectangle { contentItem: Rectangle {
implicitWidth: 8 implicitWidth: control.hovered ? 8 : 4
implicitHeight: 8 implicitHeight: control.hovered ? 8 : 4
color: RibbonTheme.dark_mode ? '#999999' : '#707070' color: RibbonTheme.dark_mode ? '#999999' : '#707070'
visible: control.size < 1.0 visible: control.size < 1.0
@ -31,16 +31,35 @@ ScrollIndicator {
Transition { Transition {
from: "active" from: "active"
SequentialAnimation { SequentialAnimation {
PauseAnimation { duration: 450 }
NumberAnimation { target: control.contentItem; duration: 200; property: "opacity"; to: 0.0 } NumberAnimation { target: control.contentItem; duration: 200; property: "opacity"; to: 0.0 }
} }
} }
] ]
Behavior on implicitWidth {
SequentialAnimation {
PauseAnimation { duration: control.hovered ? 0 : 300 }
NumberAnimation {
duration: 50
easing.type: Easing.OutSine
}
}
}
Behavior on implicitHeight {
SequentialAnimation {
PauseAnimation { duration: control.hovered ? 0 : 300 }
NumberAnimation {
duration: 100
easing.type: Easing.OutSine
}
}
}
} }
background: Rectangle{ background: Rectangle{
implicitWidth: 18 implicitWidth: control.hovered ? 18 : 0
implicitHeight: 18 implicitHeight: control.hovered ? 18 : 0
color: RibbonTheme.dark_mode ? '#141414' : '#F5F5F5' color: RibbonTheme.dark_mode ? '#141414' : '#F5F5F5'
opacity: 0.0 opacity: 0.0
radius: implicitWidth / 2 radius: implicitWidth / 2
@ -48,7 +67,7 @@ ScrollIndicator {
states: State { states: State {
name: "active" name: "active"
when: control.active when: control.active && control.hovered
PropertyChanges { control.background.opacity: 0.75 } PropertyChanges { control.background.opacity: 0.75 }
} }
@ -56,9 +75,14 @@ ScrollIndicator {
Transition { Transition {
from: "active" from: "active"
SequentialAnimation { SequentialAnimation {
PauseAnimation { duration: 450 }
NumberAnimation { target: control.background; duration: 200; property: "opacity"; to: 0.0 } NumberAnimation { target: control.background; duration: 200; property: "opacity"; to: 0.0 }
} }
},
Transition {
to: "active"
SequentialAnimation {
NumberAnimation { target: control.background; duration: 200; property: "opacity";}
}
} }
] ]
} }

View File

@ -21,3 +21,20 @@ RibbonUI* RibbonUI::instance(){
} }
return singleton; return singleton;
} }
void RibbonUI::init()
{
qputenv("QT_QUICK_CONTROLS_STYLE","Basic");
FramelessHelper::Quick::initialize();
#ifdef Q_OS_WIN
FramelessConfig::instance()->set(Global::Option::ForceHideWindowFrameBorder);
#endif
FramelessConfig::instance()->set(Global::Option::DisableLazyInitializationForMicaMaterial);
FramelessConfig::instance()->set(Global::Option::CenterWindowBeforeShow);
FramelessConfig::instance()->set(Global::Option::EnableBlurBehindWindow);
}
void RibbonUI::registerTypes(QQmlEngine *qmlEngine)
{
FramelessHelper::Quick::registerTypes(qmlEngine);
}

View File

@ -3,7 +3,10 @@
#include <QQuickItem> #include <QQuickItem>
#include "definitions.h" #include "definitions.h"
#include <FramelessHelper/Quick/framelessquickmodule.h>
#include <FramelessHelper/Core/private/framelessconfig_p.h>
FRAMELESSHELPER_USE_NAMESPACE
class RibbonUI : public QQuickItem class RibbonUI : public QQuickItem
{ {
Q_OBJECT Q_OBJECT
@ -15,6 +18,8 @@ class RibbonUI : public QQuickItem
public: public:
static RibbonUI* instance(); static RibbonUI* instance();
static RibbonUI* create(QQmlEngine *qmlEngine, QJSEngine *jsEngine){return instance();} static RibbonUI* create(QQmlEngine *qmlEngine, QJSEngine *jsEngine){return instance();}
RIBBONUI_API static void init();
RIBBONUI_API static void registerTypes(QQmlEngine *qmlEngine);
private: private:
explicit RibbonUI(QQuickItem *parent = nullptr); explicit RibbonUI(QQuickItem *parent = nullptr);
Q_DISABLE_COPY_MOVE(RibbonUI) Q_DISABLE_COPY_MOVE(RibbonUI)