Initial commit of BudgetPro
This commit is contained in:
@@ -0,0 +1,4 @@
|
||||
add_subdirectory(SARibbonBar)
|
||||
#if(BUILD_DESIGNERPLUGIN)
|
||||
# add_subdirectory(DesignerPlugin)
|
||||
#endif()
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,51 @@
|
||||
#-------------------------------------------------
|
||||
#
|
||||
# 此文件给SARibbon静态编译使用
|
||||
# 适用于SARibbon.h/SARibbon.cpp这两个文件
|
||||
# 如果使用动态库,不要使用此文件
|
||||
#
|
||||
#
|
||||
# 使用方法见例子:src\example\SimpleExample\
|
||||
#
|
||||
#-------------------------------------------------
|
||||
|
||||
|
||||
######################################
|
||||
# Config | 配置
|
||||
######################################
|
||||
#SA_RIBBON_CONFIG 用于定义一些编译选项:
|
||||
# SA_RIBBON_CONFIG+=use_frameless
|
||||
# 此选项将使用frameless第三方库,这个选项在SARibbonBar.pri中会自动判断,如果,达到frameless的使用要求将会自动定义
|
||||
# frameless第三方库必须C++17且只有几个版本的qt可用,目前支持(qt5.14,qt5.15,qt6.4以上)
|
||||
# 除了上诉版本SA_RIBBON_CONFIG中不会加入use_frameless
|
||||
# frameless库能实现Ubuntu下和mac下的显示,同时多屏幕的支持也较好
|
||||
# 使用frameless库,需要定义QWindowKit的安装目录,默认在SARIBBON_BIN_DIR
|
||||
# SA_RIBBON_QWindowKit_Install_DIR = $$SARIBBON_BIN_DIR
|
||||
######################################
|
||||
# 集成模式默认不使用frameless,如果使用,需要自己引入qwk依赖
|
||||
SA_RIBBON_CONFIG -= use_frameless
|
||||
|
||||
|
||||
# 这里判断SA_RIBBON_CONFIG是否包含use_frameless,如果包含将引入frameless库,并定义SARIBBON_USE_3RDPARTY_FRAMELESSHELPER为1
|
||||
contains( SA_RIBBON_CONFIG, use_frameless ) {
|
||||
!contains(CONFIG,C++17){
|
||||
CONFIG += c++17
|
||||
}
|
||||
# 定义SARIBBON_USE_3RDPARTY_FRAMELESSHELPER为1
|
||||
DEFINES += SARIBBON_USE_3RDPARTY_FRAMELESSHELPER=1
|
||||
}else{
|
||||
DEFINES += SARIBBON_USE_3RDPARTY_FRAMELESSHELPER=0
|
||||
}
|
||||
|
||||
|
||||
SOURCES += \
|
||||
$$PWD/SARibbon.cpp
|
||||
|
||||
HEADERS += \
|
||||
$$PWD/SARibbon.h
|
||||
|
||||
RESOURCES += \
|
||||
$$PWD/SARibbonBar/resource.qrc
|
||||
|
||||
INCLUDEPATH += $$PWD
|
||||
DEPENDPATH += $$PWD
|
||||
@@ -0,0 +1,59 @@
|
||||
|
||||
# Cmake的命令不区分打下写,例如message,set等命令;但Cmake的变量区分大小写
|
||||
# 为统一风格,本项目的Cmake命令全部采用小写,变量全部采用大写加下划线组合。
|
||||
|
||||
cmake_minimum_required(VERSION 3.5)
|
||||
project(SARibbon-3rdparty-build
|
||||
LANGUAGES CXX
|
||||
DESCRIPTION "SARibbon : 3rdparty build"
|
||||
)
|
||||
|
||||
set(CMAKE_CXX_STANDARD 17)
|
||||
set(CMAKE_CXX_STANDARD_REQUIRED ON)
|
||||
if(MSVC)
|
||||
# CMAKE_CXX_STANDARD对有些版本的msvc无效
|
||||
set(CMAKE_CXX_FLAGS"${CMAKE_CXX_FLAGS} /std:c++17")
|
||||
endif()
|
||||
# 编译错误error C2039: “max”: 不是“std”的成员
|
||||
# 避免和min/max宏冲突
|
||||
add_definitions(-DNOMINMAX)
|
||||
|
||||
########################################################
|
||||
# 安装路径设置
|
||||
########################################################
|
||||
# load Qt library, minimum version required is 5.12
|
||||
# cn:Qt库加载,最低版本要求为5.12
|
||||
set(SARIBBON_MIN_QT_VERSION 5.12)
|
||||
find_package(QT NAMES Qt6 Qt5 COMPONENTS Core REQUIRED)
|
||||
find_package(Qt${QT_VERSION_MAJOR} ${SARIBBON_MIN_QT_VERSION} COMPONENTS
|
||||
Core
|
||||
Gui
|
||||
Widgets
|
||||
REQUIRED
|
||||
)
|
||||
# 平台判断
|
||||
if("${CMAKE_SIZEOF_VOID_P}" STREQUAL "4")
|
||||
set(SARIBBON_PLATFORM "x86")
|
||||
else()
|
||||
set(SARIBBON_PLATFORM "x64")
|
||||
endif()
|
||||
# The bin file directory is one level above the current directory
|
||||
# cn:bin文件目录在当前目录的上上一级
|
||||
set(SARIBBON_BIN_NAME bin_qt${QT_VERSION}_${CMAKE_CXX_COMPILER_ID}_${SARIBBON_PLATFORM})
|
||||
set(SARIBBON_BIN_DIR ${CMAKE_CURRENT_LIST_DIR}/../../../${SARIBBON_BIN_NAME})
|
||||
# windows系统下,默认直接安装到当前文件夹下
|
||||
if(WIN32)
|
||||
set(CMAKE_INSTALL_PREFIX "${SARIBBON_BIN_DIR}")
|
||||
endif()
|
||||
########################################################
|
||||
# 第三方库参数设置
|
||||
########################################################
|
||||
#
|
||||
set(QWINDOWKIT_BUILD_WIDGETS ON CACHE BOOL "force set QWINDOWKIT_BUILD_WIDGETS ON" FORCE)
|
||||
set(QWINDOWKIT_BUILD_EXAMPLES OFF CACHE BOOL "force set QWINDOWKIT_BUILD_EXAMPLES OFF" FORCE)
|
||||
set(QWINDOWKIT_BUILD_QUICK OFF CACHE BOOL "force set QWINDOWKIT_BUILD_QUICK OFF" FORCE)
|
||||
set(QWINDOWKIT_INSTALL ON CACHE BOOL "force set QWINDOWKIT_INSTALL ON" FORCE)
|
||||
########################################################
|
||||
# 安装第三方库
|
||||
########################################################
|
||||
add_subdirectory(qwindowkit)
|
||||
@@ -0,0 +1,6 @@
|
||||
# 这里演示如何再windows下通过命令行编译
|
||||
# 如果你的操作系统安装了很多版本的qt和vs,你可以参考下面的命令,这里演示使用vs2017 qt5.14.2来编译qwk,
|
||||
# qwk要求的cmake版本比较高,vs2017的默认cmake是不支持,这里做个演示如何通过命令行编译,具体路径需要实际使用时更改
|
||||
"C:\Program Files (x86)\cmake3.27.9\bin\cmake.exe" -B build -S . -G "Visual Studio 15 2017" -A x64 -DQt5_DIR="C:\Qt\Qt5.14.2\5.14.2\msvc2017_64\lib\cmake\Qt5"
|
||||
"C:\Program Files (x86)\cmake3.27.9\bin\cmake.exe" --build build --target install --config Debug
|
||||
"C:\Program Files (x86)\cmake3.27.9\bin\cmake.exe" --build build --target install --config Release
|
||||
@@ -0,0 +1,289 @@
|
||||
cmake_minimum_required(VERSION 3.5)
|
||||
project(SARibbonBar LANGUAGES CXX VERSION ${SARIBBON_VERSION})
|
||||
set(SARIBBON_LIB_NAME SARibbonBar)
|
||||
message(STATUS "SARIBBON_LIB_NAME=${SARIBBON_LIB_NAME}")
|
||||
set(CMAKE_INCLUDE_CURRENT_DIR ON)
|
||||
|
||||
#################################################
|
||||
# SAColorWidgets相关
|
||||
# https://github.com/czyt1988/SAColorWidgets
|
||||
#################################################
|
||||
SET(SACOLOR_DIR ${CMAKE_CURRENT_SOURCE_DIR}/colorWidgets)
|
||||
SET(SACOLOR_HEADER_FILES
|
||||
${SACOLOR_DIR}/SAColorWidgetsGlobal.h
|
||||
${SACOLOR_DIR}/SAColorToolButton.h
|
||||
${SACOLOR_DIR}/SAColorGridWidget.h
|
||||
${SACOLOR_DIR}/SAColorPaletteGridWidget.h
|
||||
${SACOLOR_DIR}/SAColorMenu.h
|
||||
)
|
||||
SET(SACOLOR_SOURCE_FILES
|
||||
${SACOLOR_DIR}/SAColorToolButton.cpp
|
||||
${SACOLOR_DIR}/SAColorGridWidget.cpp
|
||||
${SACOLOR_DIR}/SAColorPaletteGridWidget.cpp
|
||||
${SACOLOR_DIR}/SAColorMenu.cpp
|
||||
)
|
||||
|
||||
#################################################
|
||||
# SARibbonBar相关
|
||||
#################################################
|
||||
|
||||
|
||||
# header files
|
||||
# cn:头文件
|
||||
SET(SARIBBON_HEADER_FILES
|
||||
SARibbonBarVersionInfo.h
|
||||
SARibbonGlobal.h
|
||||
SAFramelessHelper.h
|
||||
SARibbonActionsManager.h
|
||||
SARibbonBar.h
|
||||
SARibbonCustomizeData.h
|
||||
SARibbonCustomizeDialog.h
|
||||
SARibbonCustomizeWidget.h
|
||||
SARibbonMainWindow.h
|
||||
SARibbonWidget.h
|
||||
SARibbonSystemButtonBar.h
|
||||
SARibbonApplicationButton.h
|
||||
SARibbonTabBar.h
|
||||
SARibbonCategory.h
|
||||
SARibbonContextCategory.h
|
||||
SARibbonPannel.h
|
||||
SARibbonToolButton.h
|
||||
SARibbonMenu.h
|
||||
SARibbonPannelOptionButton.h
|
||||
SARibbonSeparatorWidget.h
|
||||
SARibbonCategoryLayout.h
|
||||
SARibbonGallery.h
|
||||
SARibbonControlButton.h
|
||||
SARibbonGalleryGroup.h
|
||||
SARibbonGalleryItem.h
|
||||
SARibbonComboBox.h
|
||||
SARibbonElementFactory.h
|
||||
SARibbonElementManager.h
|
||||
SARibbonLineEdit.h
|
||||
SARibbonCheckBox.h
|
||||
SARibbonButtonGroupWidget.h
|
||||
SARibbonStackedWidget.h
|
||||
SARibbonQuickAccessBar.h
|
||||
SARibbonCtrlContainer.h
|
||||
SARibbonPannelLayout.h
|
||||
SARibbonPannelItem.h
|
||||
SARibbonLineWidgetContainer.h
|
||||
SARibbonColorToolButton.h
|
||||
)
|
||||
|
||||
# source files
|
||||
# cn:cpp文件
|
||||
SET(SARIBBON_SOURCE_FILES
|
||||
SAFramelessHelper.cpp
|
||||
SARibbonActionsManager.cpp
|
||||
SARibbonBar.cpp
|
||||
SARibbonCustomizeData.cpp
|
||||
SARibbonCustomizeDialog.cpp
|
||||
SARibbonCustomizeWidget.cpp
|
||||
SARibbonMainWindow.cpp
|
||||
SARibbonWidget.cpp
|
||||
SARibbonSystemButtonBar.cpp
|
||||
SARibbonApplicationButton.cpp
|
||||
SARibbonTabBar.cpp
|
||||
SARibbonCategory.cpp
|
||||
SARibbonContextCategory.cpp
|
||||
SARibbonPannel.cpp
|
||||
SARibbonToolButton.cpp
|
||||
SARibbonMenu.cpp
|
||||
SARibbonPannelOptionButton.cpp
|
||||
SARibbonSeparatorWidget.cpp
|
||||
SARibbonCategoryLayout.cpp
|
||||
SARibbonGallery.cpp
|
||||
SARibbonControlButton.cpp
|
||||
SARibbonGalleryGroup.cpp
|
||||
SARibbonGalleryItem.cpp
|
||||
SARibbonComboBox.cpp
|
||||
SARibbonElementFactory.cpp
|
||||
SARibbonElementManager.cpp
|
||||
SARibbonLineEdit.cpp
|
||||
SARibbonCheckBox.cpp
|
||||
SARibbonButtonGroupWidget.cpp
|
||||
SARibbonStackedWidget.cpp
|
||||
SARibbonQuickAccessBar.cpp
|
||||
SARibbonCtrlContainer.cpp
|
||||
SARibbonPannelLayout.cpp
|
||||
SARibbonPannelItem.cpp
|
||||
SARibbonLineWidgetContainer.cpp
|
||||
SARibbonColorToolButton.cpp
|
||||
)
|
||||
|
||||
# resource files
|
||||
# cn:资源文件
|
||||
SET(SARIBBON_RESOURCE_FILES
|
||||
resource.qrc
|
||||
)
|
||||
|
||||
################################################################
|
||||
|
||||
add_library(${SARIBBON_LIB_NAME} SHARED
|
||||
${SARIBBON_HEADER_FILES}
|
||||
${SARIBBON_SOURCE_FILES}
|
||||
${SARIBBON_RESOURCE_FILES}
|
||||
${SACOLOR_HEADER_FILES}
|
||||
${SACOLOR_SOURCE_FILES}
|
||||
)
|
||||
add_library(${SARIBBON_LIB_NAME}::${SARIBBON_LIB_NAME} ALIAS ${SARIBBON_LIB_NAME})
|
||||
#################################################
|
||||
# Qt相关的依赖
|
||||
#################################################
|
||||
target_link_libraries(${SARIBBON_LIB_NAME} PUBLIC
|
||||
Qt${QT_VERSION_MAJOR}::Core
|
||||
Qt${QT_VERSION_MAJOR}::Gui
|
||||
Qt${QT_VERSION_MAJOR}::Widgets)
|
||||
message(STATUS "link ${SARIBBON_LIB_NAME} PUBLIC Qt${QT_VERSION_MAJOR}::Core Qt${QT_VERSION_MAJOR}::Gui Qt${QT_VERSION_MAJOR}::Widgets")
|
||||
|
||||
#################################################
|
||||
# frameless相关的依赖
|
||||
# qwindowkit库 https://github.com/stdware/qwindowkit
|
||||
#################################################
|
||||
# Qt X11Extras was first introduced in 5.1 and got removed in 6.0
|
||||
# But it was again brought back as a private feature of QtGui in 6.2
|
||||
if(_SARIBBON_USE_FRAMELESS_LIB)
|
||||
find_package(QWindowKit REQUIRED)
|
||||
target_link_libraries(${SARIBBON_LIB_NAME} PRIVATE QWindowKit::Widgets)
|
||||
message(STATUS "link ${SARIBBON_LIB_NAME} PRIVATE QWindowKit::Widgets")
|
||||
endif()
|
||||
#################################################
|
||||
include(GNUInstallDirs)
|
||||
set_target_properties(${SARIBBON_LIB_NAME} PROPERTIES
|
||||
AUTOMOC ON
|
||||
AUTOUIC ON
|
||||
AUTORCC ON
|
||||
CXX_EXTENSIONS OFF
|
||||
DEBUG_POSTFIX ${CMAKE_DEBUG_POSTFIX}
|
||||
VERSION ${SARIBBON_VERSION}
|
||||
EXPORT_NAME ${SARIBBON_LIB_NAME}
|
||||
ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/${CMAKE_INSTALL_LIBDIR}"
|
||||
LIBRARY_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/${CMAKE_INSTALL_LIBDIR}"
|
||||
RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/${CMAKE_INSTALL_BINDIR}"
|
||||
)
|
||||
# 构建库定义的宏,此宏必须为PRIVATE
|
||||
target_compile_definitions(${SARIBBON_LIB_NAME} PRIVATE SA_RIBBON_BAR_MAKE_LIB)
|
||||
message(STATUS "macros predefined:#define SA_RIBBON_BAR_MAKE_LIB")
|
||||
# 使用SAColorWidgets但不作为库使用定义的宏,此宏必须为PRIVATE
|
||||
target_compile_definitions(${SARIBBON_LIB_NAME} PRIVATE SA_COLOR_WIDGETS_MAKE_LIB)
|
||||
message(STATUS "macros predefined:#define SA_COLOR_WIDGETS_MAKE_LIB")
|
||||
if(_SARIBBON_USE_FRAMELESS_LIB)
|
||||
#使用frameless必须设置SARIBBON_USE_3RDPARTY_FRAMELESSHELPER宏为1,此宏必须为PUBLIC
|
||||
target_compile_definitions(${SARIBBON_LIB_NAME} PUBLIC SARIBBON_USE_3RDPARTY_FRAMELESSHELPER=1)
|
||||
message(STATUS "macros predefined:#define SARIBBON_USE_3RDPARTY_FRAMELESSHELPER 1")
|
||||
if(SARIBBON_ENABLE_SNAPLAYOUT)
|
||||
# 是否开启windows11的snap layout效果,目前这个在不同qt版本下有bug
|
||||
target_compile_definitions(${SARIBBON_LIB_NAME} PUBLIC SARIBBON_ENABLE_SNAP_LAYOUT=1)
|
||||
message(STATUS "macros predefined:#define SARIBBON_ENABLE_SNAP_LAYOUT 1")
|
||||
else()
|
||||
target_compile_definitions(${SARIBBON_LIB_NAME} PUBLIC SARIBBON_ENABLE_SNAP_LAYOUT=0)
|
||||
message(STATUS "macros predefined:#define SARIBBON_ENABLE_SNAP_LAYOUT 0")
|
||||
endif()
|
||||
else()
|
||||
#不使用frameless必须设置SARIBBON_USE_3RDPARTY_FRAMELESSHELPER宏为0,此宏必须为PUBLIC
|
||||
target_compile_definitions(${SARIBBON_LIB_NAME} PUBLIC SARIBBON_USE_3RDPARTY_FRAMELESSHELPER=0)
|
||||
message(STATUS "macros predefined:#define SARIBBON_USE_3RDPARTY_FRAMELESSHELPER 0")
|
||||
endif()
|
||||
|
||||
target_include_directories(${SARIBBON_LIB_NAME} PUBLIC
|
||||
$<INSTALL_INTERFACE:include/${SARIBBON_LIB_NAME}>
|
||||
$<BUILD_INTERFACE:${CMAKE_CURRENT_LIST_DIR}>
|
||||
)
|
||||
if(MSVC)
|
||||
# To unbreak std::min/max
|
||||
target_compile_definitions(${SARIBBON_LIB_NAME} PRIVATE NOMINMAX)
|
||||
message(STATUS "macros predefined:#define NOMINMAX")
|
||||
endif()
|
||||
|
||||
# ------------------------------- install script -------------------------------
|
||||
|
||||
# 头文件
|
||||
install(FILES
|
||||
${SARIBBON_HEADER_FILES}
|
||||
DESTINATION include/${SARIBBON_LIB_NAME}
|
||||
COMPONENT headers
|
||||
)
|
||||
# SAColorWidget的头文件
|
||||
install(FILES
|
||||
${SACOLOR_HEADER_FILES}
|
||||
DESTINATION include/${SARIBBON_LIB_NAME}/colorWidgets
|
||||
COMPONENT headers
|
||||
)
|
||||
|
||||
# 生成单一文件
|
||||
# 单一文件是把整个SARibbon打包为一个h和一个cpp,方便集成
|
||||
set(SARIBBON_AMALGAMATE_FILES
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/../SARibbon.h
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/../SARibbon.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/../SARibbon.pri
|
||||
)
|
||||
install(FILES
|
||||
${SARIBBON_AMALGAMATE_FILES}
|
||||
DESTINATION ${SARIBBON_LIB_NAME}_amalgamate
|
||||
)
|
||||
# 复制resource目录到install/amalgamate目录
|
||||
install(DIRECTORY
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/resource
|
||||
DESTINATION ${SARIBBON_LIB_NAME}_amalgamate/SARibbonBar
|
||||
)
|
||||
# resource.qrc
|
||||
install(FILES
|
||||
${SARIBBON_RESOURCE_FILES}
|
||||
DESTINATION ${SARIBBON_LIB_NAME}_amalgamate/SARibbonBar
|
||||
)
|
||||
# 复制3rdparty目录到install/amalgamate目录
|
||||
install(DIRECTORY
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/3rdparty
|
||||
DESTINATION ${SARIBBON_LIB_NAME}_amalgamate/SARibbonBar
|
||||
)
|
||||
|
||||
|
||||
include(CMakePackageConfigHelpers)
|
||||
|
||||
# SARibbonBarConfig.cmake.in中,会让此变量和“${PACKAGE_PREFIX_DIR}/”进行拼接,也就是${PACKAGE_PREFIX_DIR}/@SARIBBON_LIB_INCLUDE_INSTALL_DIR@
|
||||
# PACKAGE_PREFIX_DIR等于${CMAKE_CURRENT_LIST_DIR}/../..
|
||||
# 最终变为${CMAKE_CURRENT_LIST_DIR}/../../include
|
||||
# 注意此处是替换,不要出现引号
|
||||
set(SARIBBON_LIB_INCLUDE_INSTALL_DIR include/${SARIBBON_LIB_NAME})
|
||||
write_basic_package_version_file(
|
||||
${CMAKE_CURRENT_BINARY_DIR}/${SARIBBON_LIB_NAME}ConfigVersion.cmake
|
||||
VERSION ${SARIBBON_VERSION}
|
||||
COMPATIBILITY SameMajorVersion
|
||||
)
|
||||
configure_package_config_file(
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/SARibbonBarConfig.cmake.in"
|
||||
"${CMAKE_CURRENT_BINARY_DIR}/${SARIBBON_LIB_NAME}Config.cmake"
|
||||
INSTALL_DESTINATION lib/cmake/${SARIBBON_LIB_NAME}
|
||||
PATH_VARS SARIBBON_LIB_INCLUDE_INSTALL_DIR
|
||||
)
|
||||
|
||||
install(TARGETS ${SARIBBON_LIB_NAME}
|
||||
EXPORT ${SARIBBON_LIB_NAME}Targets
|
||||
RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
|
||||
LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
|
||||
ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}
|
||||
INCLUDES DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/${SARIBBON_LIB_NAME}
|
||||
)
|
||||
install(EXPORT ${SARIBBON_LIB_NAME}Targets
|
||||
FILE ${SARIBBON_LIB_NAME}Targets.cmake
|
||||
NAMESPACE ${SARIBBON_LIB_NAME}::
|
||||
DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/${SARIBBON_LIB_NAME}
|
||||
)
|
||||
|
||||
install(FILES
|
||||
"${CMAKE_CURRENT_BINARY_DIR}/${SARIBBON_LIB_NAME}Config.cmake"
|
||||
"${CMAKE_CURRENT_BINARY_DIR}/${SARIBBON_LIB_NAME}ConfigVersion.cmake"
|
||||
DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/${SARIBBON_LIB_NAME}
|
||||
)
|
||||
|
||||
# 资源文件生成
|
||||
|
||||
if(WIN32)
|
||||
create_win32_resource_version(
|
||||
TARGET ${SARIBBON_LIB_NAME}
|
||||
FILENAME ${SARIBBON_LIB_NAME}
|
||||
EXT "dll"
|
||||
DESCRIPTION "Ribbon control library for Qt"
|
||||
)
|
||||
endif()
|
||||
@@ -0,0 +1,616 @@
|
||||
#include "SAFramelessHelper.h"
|
||||
#include <QRect>
|
||||
#include <QRubberBand>
|
||||
#include <QMouseEvent>
|
||||
#include <QHoverEvent>
|
||||
#include <QApplication>
|
||||
#include <QDebug>
|
||||
#include "SARibbonMainWindow.h"
|
||||
class SAPrivateFramelessWidgetData;
|
||||
|
||||
/*****
|
||||
* FramelessHelperPrivate
|
||||
* 存储界面对应的数据集合,以及是否可移动、可缩放属性
|
||||
*****/
|
||||
class SAFramelessHelper::PrivateData
|
||||
{
|
||||
SA_RIBBON_DECLARE_PUBLIC(SAFramelessHelper)
|
||||
friend class SAPrivateFramelessWidgetData;
|
||||
|
||||
public:
|
||||
PrivateData(SAFramelessHelper* p);
|
||||
QHash< QWidget*, SAPrivateFramelessWidgetData* > m_widgetDataHash;
|
||||
bool m_bWidgetMovable { true };
|
||||
bool m_bWidgetResizable { true };
|
||||
bool m_bRubberBandOnResize { true };
|
||||
bool m_bRubberBandOnMove { true };
|
||||
};
|
||||
|
||||
SAFramelessHelper::PrivateData::PrivateData(SAFramelessHelper* p) : q_ptr(p)
|
||||
{
|
||||
}
|
||||
|
||||
/*****
|
||||
* CursorPosCalculator
|
||||
* 计算鼠标是否位于左、上、右、下、左上角、左下角、右上角、右下角
|
||||
*****/
|
||||
class SAPrivateFramelessCursorPosCalculator
|
||||
{
|
||||
public:
|
||||
explicit SAPrivateFramelessCursorPosCalculator();
|
||||
void reset();
|
||||
void recalculate(const QPoint& globalMousePos, const QRect& frameRect);
|
||||
|
||||
public:
|
||||
bool mIsOnEdges { true };
|
||||
bool mIsOnLeftEdge { true };
|
||||
bool mIsOnRightEdge { true };
|
||||
bool mIsOnTopEdge { true };
|
||||
bool mIsOnBottomEdge { true };
|
||||
bool mIsOnTopLeftEdge { true };
|
||||
bool mIsOnBottomLeftEdge { true };
|
||||
bool mIsOnTopRightEdge { true };
|
||||
bool mIsOnBottomRightEdge { true };
|
||||
|
||||
static int s_borderWidth;
|
||||
static int s_titleHeight;
|
||||
};
|
||||
|
||||
int SAPrivateFramelessCursorPosCalculator::s_borderWidth = 5;
|
||||
int SAPrivateFramelessCursorPosCalculator::s_titleHeight = 30;
|
||||
|
||||
/***** CursorPosCalculator *****/
|
||||
SAPrivateFramelessCursorPosCalculator::SAPrivateFramelessCursorPosCalculator()
|
||||
{
|
||||
reset();
|
||||
}
|
||||
|
||||
void SAPrivateFramelessCursorPosCalculator::reset()
|
||||
{
|
||||
mIsOnEdges = false;
|
||||
mIsOnLeftEdge = false;
|
||||
mIsOnRightEdge = false;
|
||||
mIsOnTopEdge = false;
|
||||
mIsOnBottomEdge = false;
|
||||
mIsOnTopLeftEdge = false;
|
||||
mIsOnBottomLeftEdge = false;
|
||||
mIsOnTopRightEdge = false;
|
||||
mIsOnBottomRightEdge = false;
|
||||
}
|
||||
|
||||
void SAPrivateFramelessCursorPosCalculator::recalculate(const QPoint& gMousePos, const QRect& frameRect)
|
||||
{
|
||||
int globalMouseX = gMousePos.x();
|
||||
int globalMouseY = gMousePos.y();
|
||||
|
||||
int frameX = frameRect.x();
|
||||
int frameY = frameRect.y();
|
||||
|
||||
int frameWidth = frameRect.width();
|
||||
int frameHeight = frameRect.height();
|
||||
|
||||
mIsOnLeftEdge = (globalMouseX >= frameX && globalMouseX <= frameX + s_borderWidth);
|
||||
|
||||
mIsOnRightEdge = (globalMouseX >= frameX + frameWidth - s_borderWidth && globalMouseX <= frameX + frameWidth);
|
||||
|
||||
mIsOnTopEdge = (globalMouseY >= frameY && globalMouseY <= frameY + s_borderWidth);
|
||||
|
||||
mIsOnBottomEdge = (globalMouseY >= frameY + frameHeight - s_borderWidth && globalMouseY <= frameY + frameHeight);
|
||||
|
||||
mIsOnTopLeftEdge = mIsOnTopEdge && mIsOnLeftEdge;
|
||||
mIsOnBottomLeftEdge = mIsOnBottomEdge && mIsOnLeftEdge;
|
||||
mIsOnTopRightEdge = mIsOnTopEdge && mIsOnRightEdge;
|
||||
mIsOnBottomRightEdge = mIsOnBottomEdge && mIsOnRightEdge;
|
||||
|
||||
mIsOnEdges = mIsOnLeftEdge || mIsOnRightEdge || mIsOnTopEdge || mIsOnBottomEdge;
|
||||
}
|
||||
|
||||
/*****
|
||||
* WidgetData
|
||||
* 更新鼠标样式、移动窗体、缩放窗体
|
||||
*****/
|
||||
class SAPrivateFramelessWidgetData
|
||||
{
|
||||
public:
|
||||
explicit SAPrivateFramelessWidgetData(SAFramelessHelper::PrivateData* pd, QWidget* pTopLevelWidget);
|
||||
~SAPrivateFramelessWidgetData();
|
||||
QWidget* widget();
|
||||
|
||||
// 处理鼠标事件-划过、按下、释放、移动
|
||||
bool handleWidgetEvent(QEvent* event);
|
||||
|
||||
// 更新橡皮筋状态
|
||||
void updateRubberBandStatus();
|
||||
|
||||
private:
|
||||
// 更新鼠标样式
|
||||
void updateCursorShape(const QPoint& gMousePos);
|
||||
|
||||
// 重置窗体大小
|
||||
void resizeWidget(const QPoint& gMousePos);
|
||||
|
||||
// 移动窗体
|
||||
void moveWidget(const QPoint& gMousePos);
|
||||
|
||||
// 处理鼠标按下
|
||||
bool handleMousePressEvent(QMouseEvent* event);
|
||||
|
||||
// 处理鼠标释放
|
||||
bool handleMouseReleaseEvent(QMouseEvent* event);
|
||||
|
||||
// 处理鼠标移动
|
||||
bool handleMouseMoveEvent(QMouseEvent* event);
|
||||
|
||||
// 处理鼠标离开
|
||||
bool handleLeaveEvent(QEvent* event);
|
||||
|
||||
// 处理鼠标进入
|
||||
bool handleHoverMoveEvent(QHoverEvent* event);
|
||||
|
||||
// 处理鼠标双击事件
|
||||
bool handleDoubleClickedMouseEvent(QMouseEvent* event);
|
||||
|
||||
private:
|
||||
SAFramelessHelper::PrivateData* d;
|
||||
QRubberBand* m_pRubberBand;
|
||||
QWidget* m_pWidget;
|
||||
QPoint m_ptDragPos;
|
||||
SAPrivateFramelessCursorPosCalculator m_pressedMousePos;
|
||||
SAPrivateFramelessCursorPosCalculator m_moveMousePos;
|
||||
bool m_bLeftButtonPressed;
|
||||
bool m_bCursorShapeChanged;
|
||||
bool m_bLeftButtonTitlePressed;
|
||||
Qt::WindowFlags m_windowFlags;
|
||||
};
|
||||
|
||||
/***** WidgetData *****/
|
||||
SAPrivateFramelessWidgetData::SAPrivateFramelessWidgetData(SAFramelessHelper::PrivateData* pd, QWidget* pTopLevelWidget)
|
||||
{
|
||||
d = pd;
|
||||
m_pWidget = pTopLevelWidget;
|
||||
m_bLeftButtonPressed = false;
|
||||
m_bCursorShapeChanged = false;
|
||||
m_bLeftButtonTitlePressed = false;
|
||||
m_pRubberBand = NULL;
|
||||
|
||||
m_windowFlags = m_pWidget->windowFlags();
|
||||
m_pWidget->setMouseTracking(true);
|
||||
m_pWidget->setAttribute(Qt::WA_Hover, true);
|
||||
|
||||
updateRubberBandStatus();
|
||||
}
|
||||
|
||||
SAPrivateFramelessWidgetData::~SAPrivateFramelessWidgetData()
|
||||
{
|
||||
m_pWidget->setMouseTracking(false);
|
||||
m_pWidget->setWindowFlags(m_windowFlags);
|
||||
m_pWidget->setAttribute(Qt::WA_Hover, false);
|
||||
|
||||
delete m_pRubberBand;
|
||||
m_pRubberBand = NULL;
|
||||
}
|
||||
|
||||
QWidget* SAPrivateFramelessWidgetData::widget()
|
||||
{
|
||||
return (m_pWidget);
|
||||
}
|
||||
|
||||
bool SAPrivateFramelessWidgetData::handleWidgetEvent(QEvent* event)
|
||||
{
|
||||
switch (event->type()) {
|
||||
case QEvent::MouseButtonPress:
|
||||
return (handleMousePressEvent(static_cast< QMouseEvent* >(event)));
|
||||
|
||||
case QEvent::MouseButtonRelease:
|
||||
return (handleMouseReleaseEvent(static_cast< QMouseEvent* >(event)));
|
||||
|
||||
case QEvent::MouseMove:
|
||||
return (handleMouseMoveEvent(static_cast< QMouseEvent* >(event)));
|
||||
|
||||
case QEvent::Leave:
|
||||
return (handleLeaveEvent(static_cast< QMouseEvent* >(event)));
|
||||
|
||||
case QEvent::HoverMove:
|
||||
return (handleHoverMoveEvent(static_cast< QHoverEvent* >(event)));
|
||||
|
||||
case QEvent::MouseButtonDblClick:
|
||||
return (handleDoubleClickedMouseEvent(static_cast< QMouseEvent* >(event)));
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return (false);
|
||||
}
|
||||
|
||||
void SAPrivateFramelessWidgetData::updateRubberBandStatus()
|
||||
{
|
||||
if (d->m_bRubberBandOnMove || d->m_bRubberBandOnResize) {
|
||||
if (NULL == m_pRubberBand) {
|
||||
m_pRubberBand = new QRubberBand(QRubberBand::Rectangle);
|
||||
}
|
||||
} else {
|
||||
delete m_pRubberBand;
|
||||
m_pRubberBand = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
void SAPrivateFramelessWidgetData::updateCursorShape(const QPoint& gMousePos)
|
||||
{
|
||||
if (m_pWidget->isFullScreen() || m_pWidget->isMaximized()) {
|
||||
if (m_bCursorShapeChanged) {
|
||||
m_pWidget->unsetCursor();
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
m_moveMousePos.recalculate(gMousePos, m_pWidget->frameGeometry());
|
||||
|
||||
if (m_moveMousePos.mIsOnTopLeftEdge || m_moveMousePos.mIsOnBottomRightEdge) {
|
||||
m_pWidget->setCursor(Qt::SizeFDiagCursor);
|
||||
m_bCursorShapeChanged = true;
|
||||
} else if (m_moveMousePos.mIsOnTopRightEdge || m_moveMousePos.mIsOnBottomLeftEdge) {
|
||||
m_pWidget->setCursor(Qt::SizeBDiagCursor);
|
||||
m_bCursorShapeChanged = true;
|
||||
} else if (m_moveMousePos.mIsOnLeftEdge || m_moveMousePos.mIsOnRightEdge) {
|
||||
m_pWidget->setCursor(Qt::SizeHorCursor);
|
||||
m_bCursorShapeChanged = true;
|
||||
} else if (m_moveMousePos.mIsOnTopEdge || m_moveMousePos.mIsOnBottomEdge) {
|
||||
m_pWidget->setCursor(Qt::SizeVerCursor);
|
||||
m_bCursorShapeChanged = true;
|
||||
} else {
|
||||
if (m_bCursorShapeChanged) {
|
||||
m_pWidget->unsetCursor();
|
||||
m_bCursorShapeChanged = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void SAPrivateFramelessWidgetData::resizeWidget(const QPoint& gMousePos)
|
||||
{
|
||||
QRect origRect;
|
||||
|
||||
if (d->m_bRubberBandOnResize) {
|
||||
origRect = m_pRubberBand->frameGeometry();
|
||||
} else {
|
||||
origRect = m_pWidget->frameGeometry();
|
||||
}
|
||||
|
||||
int left = origRect.left();
|
||||
int top = origRect.top();
|
||||
int right = origRect.right();
|
||||
int bottom = origRect.bottom();
|
||||
|
||||
origRect.getCoords(&left, &top, &right, &bottom);
|
||||
|
||||
int minWidth = m_pWidget->minimumWidth();
|
||||
int minHeight = m_pWidget->minimumHeight();
|
||||
|
||||
if (m_pressedMousePos.mIsOnTopLeftEdge) {
|
||||
left = gMousePos.x();
|
||||
top = gMousePos.y();
|
||||
} else if (m_pressedMousePos.mIsOnBottomLeftEdge) {
|
||||
left = gMousePos.x();
|
||||
bottom = gMousePos.y();
|
||||
} else if (m_pressedMousePos.mIsOnTopRightEdge) {
|
||||
right = gMousePos.x();
|
||||
top = gMousePos.y();
|
||||
} else if (m_pressedMousePos.mIsOnBottomRightEdge) {
|
||||
right = gMousePos.x();
|
||||
bottom = gMousePos.y();
|
||||
} else if (m_pressedMousePos.mIsOnLeftEdge) {
|
||||
left = gMousePos.x();
|
||||
} else if (m_pressedMousePos.mIsOnRightEdge) {
|
||||
right = gMousePos.x();
|
||||
} else if (m_pressedMousePos.mIsOnTopEdge) {
|
||||
top = gMousePos.y();
|
||||
} else if (m_pressedMousePos.mIsOnBottomEdge) {
|
||||
bottom = gMousePos.y();
|
||||
}
|
||||
|
||||
QRect newRect(QPoint(left, top), QPoint(right, bottom));
|
||||
|
||||
if (newRect.isValid()) {
|
||||
if (minWidth > newRect.width()) {
|
||||
if (left != origRect.left()) {
|
||||
newRect.setLeft(origRect.left());
|
||||
} else {
|
||||
newRect.setRight(origRect.right());
|
||||
}
|
||||
}
|
||||
if (minHeight > newRect.height()) {
|
||||
if (top != origRect.top()) {
|
||||
newRect.setTop(origRect.top());
|
||||
} else {
|
||||
newRect.setBottom(origRect.bottom());
|
||||
}
|
||||
}
|
||||
|
||||
if (d->m_bRubberBandOnResize) {
|
||||
m_pRubberBand->setGeometry(newRect);
|
||||
} else {
|
||||
m_pWidget->setGeometry(newRect);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void SAPrivateFramelessWidgetData::moveWidget(const QPoint& gMousePos)
|
||||
{
|
||||
if (d->m_bRubberBandOnMove) {
|
||||
m_pRubberBand->move(gMousePos - m_ptDragPos);
|
||||
} else {
|
||||
m_pWidget->move(gMousePos - m_ptDragPos);
|
||||
}
|
||||
}
|
||||
|
||||
bool SAPrivateFramelessWidgetData::handleMousePressEvent(QMouseEvent* event)
|
||||
{
|
||||
if (event->button() == Qt::LeftButton) {
|
||||
m_bLeftButtonPressed = true;
|
||||
m_bLeftButtonTitlePressed = event->pos().y() < m_moveMousePos.s_titleHeight;
|
||||
|
||||
QRect frameRect = m_pWidget->frameGeometry();
|
||||
auto gp = SA_MOUSEEVENT_GLOBALPOS_POINT(event);
|
||||
m_pressedMousePos.recalculate(gp, frameRect);
|
||||
|
||||
m_ptDragPos = gp - frameRect.topLeft();
|
||||
|
||||
if (m_pressedMousePos.mIsOnEdges) {
|
||||
if (m_pWidget->isMaximized()) {
|
||||
// 窗口在最大化状态时,点击边界不做任何处理
|
||||
return (false);
|
||||
}
|
||||
if (d->m_bRubberBandOnResize) {
|
||||
m_pRubberBand->setGeometry(frameRect);
|
||||
m_pRubberBand->show();
|
||||
return (true);
|
||||
}
|
||||
} else if (d->m_bRubberBandOnMove && m_bLeftButtonTitlePressed) {
|
||||
if (m_pWidget->isMaximized()) {
|
||||
// 窗口在最大化状态时,点击标题栏不做任何处理
|
||||
return (false);
|
||||
}
|
||||
m_pRubberBand->setGeometry(frameRect);
|
||||
m_pRubberBand->show();
|
||||
return (true);
|
||||
}
|
||||
}
|
||||
return (false);
|
||||
}
|
||||
|
||||
bool SAPrivateFramelessWidgetData::handleMouseReleaseEvent(QMouseEvent* event)
|
||||
{
|
||||
if (event->button() == Qt::LeftButton) {
|
||||
m_bLeftButtonPressed = false;
|
||||
m_bLeftButtonTitlePressed = false;
|
||||
m_pressedMousePos.reset();
|
||||
if (m_pRubberBand && m_pRubberBand->isVisible()) {
|
||||
m_pRubberBand->hide();
|
||||
m_pWidget->setGeometry(m_pRubberBand->geometry());
|
||||
return (true);
|
||||
}
|
||||
}
|
||||
return (false);
|
||||
}
|
||||
|
||||
bool SAPrivateFramelessWidgetData::handleMouseMoveEvent(QMouseEvent* event)
|
||||
{
|
||||
QPoint p = SA_MOUSEEVENT_GLOBALPOS_POINT(event);
|
||||
if (m_bLeftButtonPressed) {
|
||||
if (d->m_bWidgetResizable && m_pressedMousePos.mIsOnEdges) {
|
||||
if (m_pWidget->isMaximized()) {
|
||||
// 窗口在最大化状态时,点击边界不做任何处理
|
||||
return (false);
|
||||
}
|
||||
resizeWidget(p);
|
||||
return (true);
|
||||
} else if (d->m_bWidgetMovable && m_bLeftButtonTitlePressed) {
|
||||
if (m_pWidget->isMaximized()) {
|
||||
// 先求出窗口到鼠标的相对位置
|
||||
QRect normalGeometry = m_pWidget->normalGeometry();
|
||||
m_pWidget->showNormal();
|
||||
p.ry() -= 10;
|
||||
p.rx() -= (normalGeometry.width() / 2);
|
||||
m_pWidget->move(p);
|
||||
// 这时要重置m_ptDragPos
|
||||
m_ptDragPos = QPoint(normalGeometry.width() / 2, 10);
|
||||
return (true);
|
||||
}
|
||||
moveWidget(p);
|
||||
return (true);
|
||||
}
|
||||
return (false);
|
||||
} else if (d->m_bWidgetResizable) {
|
||||
updateCursorShape(p);
|
||||
}
|
||||
return (false);
|
||||
}
|
||||
|
||||
bool SAPrivateFramelessWidgetData::handleLeaveEvent(QEvent* event)
|
||||
{
|
||||
Q_UNUSED(event)
|
||||
if (!m_bLeftButtonPressed) {
|
||||
m_pWidget->unsetCursor();
|
||||
return (true);
|
||||
}
|
||||
return (false);
|
||||
}
|
||||
|
||||
bool SAPrivateFramelessWidgetData::handleHoverMoveEvent(QHoverEvent* event)
|
||||
{
|
||||
if (d->m_bWidgetResizable) {
|
||||
updateCursorShape(m_pWidget->mapToGlobal(SA_HOVEREVENT_POS_POINT(event)));
|
||||
}
|
||||
return (false);
|
||||
}
|
||||
|
||||
bool SAPrivateFramelessWidgetData::handleDoubleClickedMouseEvent(QMouseEvent* event)
|
||||
{
|
||||
if (event->button() == Qt::LeftButton) {
|
||||
if (m_pWidget) {
|
||||
SARibbonMainWindow* mainwindow = qobject_cast< SARibbonMainWindow* >(m_pWidget);
|
||||
if (mainwindow) {
|
||||
if (mainwindow->windowFlags() & Qt::WindowMaximizeButtonHint) {
|
||||
// 在最大化按钮显示时才进行shownormal处理
|
||||
bool titlePressed = event->pos().y() < m_moveMousePos.s_titleHeight;
|
||||
if (titlePressed) {
|
||||
if (m_pWidget->isMaximized()) {
|
||||
m_pWidget->showNormal();
|
||||
} else {
|
||||
m_pWidget->showMaximized();
|
||||
}
|
||||
return (true);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return (false);
|
||||
}
|
||||
|
||||
//===================================================
|
||||
// SAFramelessHelper
|
||||
//===================================================
|
||||
SAFramelessHelper::SAFramelessHelper(QObject* parent) : QObject(parent), d_ptr(new SAFramelessHelper::PrivateData(this))
|
||||
{
|
||||
d_ptr->m_bWidgetMovable = true;
|
||||
d_ptr->m_bWidgetResizable = true;
|
||||
d_ptr->m_bRubberBandOnResize = false;
|
||||
d_ptr->m_bRubberBandOnMove = false;
|
||||
if (parent) {
|
||||
QWidget* w = qobject_cast< QWidget* >(parent);
|
||||
if (w) {
|
||||
w->setWindowFlags(w->windowFlags() | Qt::FramelessWindowHint);
|
||||
setWidgetMovable(true); // 设置窗体可移动
|
||||
setWidgetResizable(true); // 设置窗体可缩放
|
||||
setRubberBandOnMove(false); // 设置橡皮筋效果-可移动
|
||||
setRubberBandOnResize(true); // 设置橡皮筋效果-可缩放
|
||||
activateOn(w); // 激活当前窗体
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
SAFramelessHelper::~SAFramelessHelper()
|
||||
{
|
||||
QList< QWidget* > keys = d_ptr->m_widgetDataHash.keys();
|
||||
int size = keys.size();
|
||||
|
||||
for (int i = 0; i < size; ++i) {
|
||||
delete d_ptr->m_widgetDataHash.take(keys[ i ]);
|
||||
}
|
||||
}
|
||||
|
||||
bool SAFramelessHelper::eventFilter(QObject* obj, QEvent* event)
|
||||
{
|
||||
switch (event->type()) {
|
||||
case QEvent::MouseMove:
|
||||
case QEvent::HoverMove:
|
||||
case QEvent::MouseButtonPress:
|
||||
case QEvent::MouseButtonRelease:
|
||||
case QEvent::MouseButtonDblClick:
|
||||
case QEvent::Leave: {
|
||||
SAPrivateFramelessWidgetData* data = d_ptr->m_widgetDataHash.value(static_cast< QWidget* >(obj));
|
||||
if (data) {
|
||||
return (data->handleWidgetEvent(event));
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return (QObject::eventFilter(obj, event));
|
||||
}
|
||||
|
||||
void SAFramelessHelper::activateOn(QWidget* topLevelWidget)
|
||||
{
|
||||
if (!d_ptr->m_widgetDataHash.contains(topLevelWidget)) {
|
||||
SAPrivateFramelessWidgetData* data = new SAPrivateFramelessWidgetData(d_ptr.get(), topLevelWidget);
|
||||
d_ptr->m_widgetDataHash.insert(topLevelWidget, data);
|
||||
|
||||
topLevelWidget->installEventFilter(this);
|
||||
}
|
||||
}
|
||||
|
||||
void SAFramelessHelper::removeFrom(QWidget* topLevelWidget)
|
||||
{
|
||||
SAPrivateFramelessWidgetData* data = d_ptr->m_widgetDataHash.take(topLevelWidget);
|
||||
|
||||
if (data) {
|
||||
topLevelWidget->removeEventFilter(this);
|
||||
delete data;
|
||||
}
|
||||
}
|
||||
|
||||
void SAFramelessHelper::setRubberBandOnMove(bool movable)
|
||||
{
|
||||
d_ptr->m_bRubberBandOnMove = movable;
|
||||
QList< SAPrivateFramelessWidgetData* > list = d_ptr->m_widgetDataHash.values();
|
||||
|
||||
foreach (SAPrivateFramelessWidgetData* data, list) {
|
||||
data->updateRubberBandStatus();
|
||||
}
|
||||
}
|
||||
|
||||
void SAFramelessHelper::setWidgetMovable(bool movable)
|
||||
{
|
||||
d_ptr->m_bWidgetMovable = movable;
|
||||
}
|
||||
|
||||
void SAFramelessHelper::setWidgetResizable(bool resizable)
|
||||
{
|
||||
d_ptr->m_bWidgetResizable = resizable;
|
||||
}
|
||||
|
||||
void SAFramelessHelper::setRubberBandOnResize(bool resizable)
|
||||
{
|
||||
d_ptr->m_bRubberBandOnResize = resizable;
|
||||
QList< SAPrivateFramelessWidgetData* > list = d_ptr->m_widgetDataHash.values();
|
||||
|
||||
foreach (SAPrivateFramelessWidgetData* data, list) {
|
||||
data->updateRubberBandStatus();
|
||||
}
|
||||
}
|
||||
|
||||
void SAFramelessHelper::setBorderWidth(int width)
|
||||
{
|
||||
if (width > 0) {
|
||||
SAPrivateFramelessCursorPosCalculator::s_borderWidth = width;
|
||||
}
|
||||
}
|
||||
|
||||
void SAFramelessHelper::setTitleHeight(int height)
|
||||
{
|
||||
if (height > 0) {
|
||||
SAPrivateFramelessCursorPosCalculator::s_titleHeight = height;
|
||||
}
|
||||
}
|
||||
|
||||
bool SAFramelessHelper::widgetMovable()
|
||||
{
|
||||
return (d_ptr->m_bWidgetMovable);
|
||||
}
|
||||
|
||||
bool SAFramelessHelper::widgetResizable()
|
||||
{
|
||||
return (d_ptr->m_bWidgetResizable);
|
||||
}
|
||||
|
||||
bool SAFramelessHelper::rubberBandOnMove()
|
||||
{
|
||||
return (d_ptr->m_bRubberBandOnMove);
|
||||
}
|
||||
|
||||
bool SAFramelessHelper::rubberBandOnResisze()
|
||||
{
|
||||
return (d_ptr->m_bRubberBandOnResize);
|
||||
}
|
||||
|
||||
uint SAFramelessHelper::borderWidth()
|
||||
{
|
||||
return (SAPrivateFramelessCursorPosCalculator::s_borderWidth);
|
||||
}
|
||||
|
||||
uint SAFramelessHelper::titleHeight()
|
||||
{
|
||||
return (SAPrivateFramelessCursorPosCalculator::s_titleHeight);
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
#ifndef SAFRAMELESSHELPER_H
|
||||
#define SAFRAMELESSHELPER_H
|
||||
|
||||
#include "SARibbonGlobal.h"
|
||||
#include <QObject>
|
||||
|
||||
class QWidget;
|
||||
|
||||
class SA_RIBBON_EXPORT SAFramelessHelper : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
SA_RIBBON_DECLARE_PRIVATE(SAFramelessHelper)
|
||||
friend class SAPrivateFramelessWidgetData;
|
||||
|
||||
public:
|
||||
explicit SAFramelessHelper(QObject* parent);
|
||||
~SAFramelessHelper();
|
||||
// 激活窗体
|
||||
void activateOn(QWidget* topLevelWidget);
|
||||
|
||||
// 移除窗体
|
||||
void removeFrom(QWidget* topLevelWidget);
|
||||
|
||||
// 设置窗体移动
|
||||
void setWidgetMovable(bool movable);
|
||||
|
||||
// 设置窗体缩放
|
||||
void setWidgetResizable(bool resizable);
|
||||
|
||||
// 设置橡皮筋移动
|
||||
void setRubberBandOnMove(bool movable);
|
||||
|
||||
// 设置橡皮筋缩放
|
||||
void setRubberBandOnResize(bool resizable);
|
||||
|
||||
// 设置边框的宽度
|
||||
void setBorderWidth(int width);
|
||||
|
||||
// 设置标题栏高度
|
||||
void setTitleHeight(int height);
|
||||
bool widgetResizable();
|
||||
bool widgetMovable();
|
||||
bool rubberBandOnMove();
|
||||
bool rubberBandOnResisze();
|
||||
uint borderWidth();
|
||||
uint titleHeight();
|
||||
|
||||
protected:
|
||||
// 事件过滤,进行移动、缩放等
|
||||
virtual bool eventFilter(QObject* obj, QEvent* event);
|
||||
};
|
||||
|
||||
#endif // FRAMELESSHELPER_H
|
||||
@@ -0,0 +1,638 @@
|
||||
#include "SARibbonActionsManager.h"
|
||||
#include <QMap>
|
||||
#include <QHash>
|
||||
#include <QDebug>
|
||||
#include <QWidgetAction>
|
||||
#include "SARibbonBar.h"
|
||||
|
||||
class SARibbonActionsManager::PrivateData
|
||||
{
|
||||
SA_RIBBON_DECLARE_PUBLIC(SARibbonActionsManager)
|
||||
public:
|
||||
PrivateData(SARibbonActionsManager* p);
|
||||
void clear();
|
||||
|
||||
QMap< int, QList< QAction* > > mTagToActions; ///< tag : QList<QAction*>
|
||||
QMap< int, QString > mTagToName; ///< tag对应的名字
|
||||
QHash< QString, QAction* > mKeyToAction; ///< key对应action
|
||||
QMap< QAction*, QString > mActionToKey; ///< action对应key
|
||||
QMap< int, SARibbonCategory* > mTagToCategory; ///< 仅仅在autoRegisteActions函数会有用
|
||||
int mSale; ///< 盐用于生成固定的id,在用户不主动设置key时,id基于msale生成,只要SARibbonActionsManager的调用registeAction顺序不变,生成的id都不变,因为它是基于自增实现的
|
||||
};
|
||||
|
||||
SARibbonActionsManager::PrivateData::PrivateData(SARibbonActionsManager* p) : q_ptr(p), mSale(0)
|
||||
{
|
||||
}
|
||||
|
||||
void SARibbonActionsManager::PrivateData::clear()
|
||||
{
|
||||
mTagToActions.clear();
|
||||
mTagToName.clear();
|
||||
mKeyToAction.clear();
|
||||
mActionToKey.clear();
|
||||
mTagToCategory.clear();
|
||||
mSale = 0;
|
||||
}
|
||||
|
||||
SARibbonActionsManager::SARibbonActionsManager(SARibbonBar* bar)
|
||||
: QObject(bar), d_ptr(new SARibbonActionsManager::PrivateData(this))
|
||||
{
|
||||
autoRegisteActions(bar);
|
||||
}
|
||||
|
||||
SARibbonActionsManager::~SARibbonActionsManager()
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 设置tag对应的名字,通过这个可以得到tag和文本的映射
|
||||
* @param tag
|
||||
* @param name
|
||||
* @note 在支持多语言的环境下,在语言切换时需要重新设置,以更新名字
|
||||
*/
|
||||
void SARibbonActionsManager::setTagName(int tag, const QString& name)
|
||||
{
|
||||
d_ptr->mTagToName[ tag ] = name;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 获取tag对应的中文名字
|
||||
* @param tag
|
||||
* @return
|
||||
*/
|
||||
QString SARibbonActionsManager::tagName(int tag) const
|
||||
{
|
||||
return (d_ptr->mTagToName.value(tag, ""));
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 移除tag
|
||||
* @note 注意,这个函数非常耗时
|
||||
* @param tag
|
||||
*/
|
||||
void SARibbonActionsManager::removeTag(int tag)
|
||||
{
|
||||
QList< QAction* > oldacts = actions(tag);
|
||||
|
||||
// 开始移除
|
||||
d_ptr->mTagToActions.remove(tag);
|
||||
d_ptr->mTagToName.remove(tag);
|
||||
// 开始查找需要移出总表的action
|
||||
QList< QAction* > needRemoveAct;
|
||||
QList< QAction* > total;
|
||||
|
||||
for (auto i = d_ptr->mTagToActions.begin(); i != d_ptr->mTagToActions.end(); ++i) {
|
||||
total += i.value();
|
||||
}
|
||||
for (QAction* a : qAsConst(oldacts)) {
|
||||
if (!total.contains(a)) {
|
||||
needRemoveAct.append(a);
|
||||
}
|
||||
}
|
||||
// 从总表移除action
|
||||
for (QAction* a : qAsConst(needRemoveAct)) {
|
||||
auto i = d_ptr->mActionToKey.find(a);
|
||||
if (i != d_ptr->mActionToKey.end()) {
|
||||
d_ptr->mKeyToAction.remove(i.value());
|
||||
d_ptr->mActionToKey.erase(i);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 把action注册到管理器中,实现action的管理
|
||||
* @param act
|
||||
* @param tag tag是可以按照位进行叠加,见 @ref ActionTag 如果
|
||||
* 要定义自己的标签,建议定义大于@ref ActionTag::UserDefineActionTag 的值,
|
||||
* registeAction的tag是直接记录进去的,如果要多个标签并存,在registe之前先或好tag
|
||||
* @param key key是action对应的key,一个key只对应一个action,是查找action的关键
|
||||
* ,默认情况为一个QString(),这时key是QAction的objectName
|
||||
* @param enableEmit 控制是否发射@ref actionTagChanged 信号
|
||||
* @note 同一个action多次注册不同的tag可以通过tag索引到action,但通过action只能索引到最后一个注册的tag
|
||||
* @note tag的新增会触发actionTagChanged信号
|
||||
*/
|
||||
bool SARibbonActionsManager::registeAction(QAction* act, int tag, const QString& key, bool enableEmit)
|
||||
{
|
||||
if (nullptr == act) {
|
||||
return (false);
|
||||
}
|
||||
QString k = key;
|
||||
|
||||
if (k.isEmpty()) {
|
||||
k = QString("id_%1_%2").arg(d_ptr->mSale++).arg(act->objectName());
|
||||
}
|
||||
if (d_ptr->mKeyToAction.contains(k)) {
|
||||
qWarning() << "key: "
|
||||
<< k << " have been exist,you can set key in an unique value when use SARibbonActionsManager::registeAction";
|
||||
return (false);
|
||||
}
|
||||
d_ptr->mKeyToAction[ k ] = act;
|
||||
d_ptr->mActionToKey[ act ] = k;
|
||||
// 记录tag 对 action
|
||||
bool isneedemit = !(d_ptr->mTagToActions.contains(tag)); // 记录是否需要发射信号
|
||||
d_ptr->mTagToActions[ tag ].append(act);
|
||||
// 绑定槽
|
||||
connect(act, &QObject::destroyed, this, &SARibbonActionsManager::onActionDestroyed);
|
||||
if (isneedemit && enableEmit) {
|
||||
// 说明新增tag
|
||||
Q_EMIT actionTagChanged(tag, false);
|
||||
}
|
||||
return (true);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 取消action的注册
|
||||
*
|
||||
* 如果tag对应的最后一个action被撤销,tag也将一块删除
|
||||
* @param act
|
||||
* @note tag的删除会触发actionTagChanged信号
|
||||
* @note 如果action关联了多个tag,这些tag里的action都会被删除,对应的key也同理
|
||||
*/
|
||||
void SARibbonActionsManager::unregisteAction(QAction* act, bool enableEmit)
|
||||
{
|
||||
if (nullptr == act) {
|
||||
return;
|
||||
}
|
||||
// 绑定槽
|
||||
disconnect(act, &QObject::destroyed, this, &SARibbonActionsManager::onActionDestroyed);
|
||||
removeAction(act, enableEmit);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 移除action
|
||||
*
|
||||
* 仅移除内存内容
|
||||
* @param act
|
||||
* @param enableEmit
|
||||
*/
|
||||
void SARibbonActionsManager::removeAction(QAction* act, bool enableEmit)
|
||||
{
|
||||
QList< int > deletedTags; // 记录删除的tag,用于触发actionTagChanged
|
||||
QMap< int, QList< QAction* > > tagToActions; ///< tag : QList<QAction*>
|
||||
|
||||
for (auto i = d_ptr->mTagToActions.begin(); i != d_ptr->mTagToActions.end(); ++i) {
|
||||
// 把不是act的内容转移到tagToActions和tagToActionKeys中,之后再和m_d里的替换
|
||||
auto tmpi = tagToActions.insert(i.key(), QList< QAction* >());
|
||||
int count = 0;
|
||||
for (int j = 0; j < i.value().size(); ++j) {
|
||||
if (i.value()[ j ] != act) {
|
||||
tmpi.value().append(act);
|
||||
++count;
|
||||
}
|
||||
}
|
||||
if (0 == count) {
|
||||
// 说明这个tag没有内容
|
||||
tagToActions.erase(tmpi);
|
||||
deletedTags.append(i.key());
|
||||
}
|
||||
}
|
||||
// 删除mKeyToAction
|
||||
QString key = d_ptr->mActionToKey.value(act);
|
||||
|
||||
d_ptr->mActionToKey.remove(act);
|
||||
d_ptr->mKeyToAction.remove(key);
|
||||
|
||||
// 置换
|
||||
d_ptr->mTagToActions.swap(tagToActions);
|
||||
// 发射信号
|
||||
if (enableEmit) {
|
||||
for (int tagdelete : qAsConst(deletedTags)) {
|
||||
Q_EMIT actionTagChanged(tagdelete, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 等同actions
|
||||
* @param tag
|
||||
* @return
|
||||
*/
|
||||
QList< QAction* >& SARibbonActionsManager::filter(int tag)
|
||||
{
|
||||
return (actions(tag));
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 根据tag得到actions
|
||||
* @param tag
|
||||
* @return
|
||||
*/
|
||||
QList< QAction* >& SARibbonActionsManager::actions(int tag)
|
||||
{
|
||||
return (d_ptr->mTagToActions[ tag ]);
|
||||
}
|
||||
|
||||
const QList< QAction* > SARibbonActionsManager::actions(int tag) const
|
||||
{
|
||||
return (d_ptr->mTagToActions[ tag ]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 获取所有的标签
|
||||
* @return
|
||||
*/
|
||||
QList< int > SARibbonActionsManager::actionTags() const
|
||||
{
|
||||
return (d_ptr->mTagToActions.keys());
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 通过key获取action
|
||||
* @param key
|
||||
* @return 如果没有key,返回nullptr
|
||||
*/
|
||||
QAction* SARibbonActionsManager::action(const QString& key) const
|
||||
{
|
||||
return (d_ptr->mKeyToAction.value(key, nullptr));
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 通过action找到key
|
||||
* @param act
|
||||
* @return 如果找不到,返回QString()
|
||||
*/
|
||||
QString SARibbonActionsManager::key(QAction* act) const
|
||||
{
|
||||
return (d_ptr->mActionToKey.value(act, QString()));
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 返回所有管理的action数
|
||||
* @return
|
||||
*/
|
||||
int SARibbonActionsManager::count() const
|
||||
{
|
||||
return (d_ptr->mKeyToAction.size());
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 返回所有管理的actions
|
||||
* @return
|
||||
*/
|
||||
QList< QAction* > SARibbonActionsManager::allActions() const
|
||||
{
|
||||
return (d_ptr->mKeyToAction.values());
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 自动加载SARibbonBar的action
|
||||
* 此函数会遍历@ref SARibbonBar的父窗口(一般是SARibbonMainWindow)下的所有子object,找到action注册,
|
||||
* 并会遍历所有@ref SARibbonCategory,把SARibbonCategory下的action按SARibbonCategory的title name进行分类
|
||||
*
|
||||
* 此函数会把所有category下的action生成tag并注册,返回的QMap<int, SARibbonCategory *>是记录了category对应的tag
|
||||
*
|
||||
* 此函数还会把SARibbonBar的父窗口(一般是SARibbonMainWindow)下面的action,但不在任何一个category下的作为NotInRibbonCategoryTag标签注册,默认名字会赋予not
|
||||
* in ribbon, 可以通过@ref setTagName 改变
|
||||
*
|
||||
* @param w
|
||||
* @return
|
||||
* @note 此函数的调用最好在category设置了标题后调用,因为会以category的标题作为标签的命名
|
||||
*/
|
||||
QMap< int, SARibbonCategory* > SARibbonActionsManager::autoRegisteActions(SARibbonBar* bar)
|
||||
{
|
||||
QMap< int, SARibbonCategory* > res;
|
||||
// 先遍历SARibbonBar的父窗口(一般是SARibbonMainWindow)下的所有子对象,把所有action找到
|
||||
QWidget* parWidget = bar->parentWidget();
|
||||
QSet< QAction* > mainwindowActions;
|
||||
if (parWidget) {
|
||||
for (QObject* o : qAsConst(parWidget->children())) {
|
||||
if (QAction* a = qobject_cast< QAction* >(o)) {
|
||||
// 说明是action
|
||||
if (!a->objectName().isEmpty()) {
|
||||
mainwindowActions.insert(a);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// 开始遍历每个category,加入action
|
||||
|
||||
if (nullptr == bar) {
|
||||
// 非ribbon模式,直接退出
|
||||
return (res);
|
||||
}
|
||||
QSet< QAction* > categoryActions;
|
||||
QList< SARibbonCategory* > categorys = bar->categoryPages();
|
||||
int tag = AutoCategoryDistinguishBeginTag;
|
||||
|
||||
for (SARibbonCategory* c : qAsConst(categorys)) {
|
||||
QList< SARibbonPannel* > pannels = c->pannelList();
|
||||
for (SARibbonPannel* p : qAsConst(pannels)) {
|
||||
categoryActions += autoRegisteWidgetActions(p, tag, false);
|
||||
}
|
||||
setTagName(tag, c->categoryName());
|
||||
res[ tag ] = c;
|
||||
++tag;
|
||||
}
|
||||
// 找到不在功能区的actions
|
||||
QSet< QAction* > notincategory = mainwindowActions - categoryActions;
|
||||
|
||||
for (QAction* a : qAsConst(notincategory)) {
|
||||
if (!a->objectName().isEmpty()) {
|
||||
registeAction(a, NotInRibbonCategoryTag, a->objectName(), false);
|
||||
}
|
||||
}
|
||||
if (notincategory.size() > 0) {
|
||||
setTagName(NotInRibbonCategoryTag, tr("not in ribbon"));
|
||||
}
|
||||
for (auto i = res.begin(); i != res.end(); ++i) {
|
||||
connect(i.value(), &SARibbonCategory::categoryNameChanged, this, &SARibbonActionsManager::onCategoryTitleChanged);
|
||||
}
|
||||
d_ptr->mTagToCategory = res;
|
||||
return (res);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 自动加载action
|
||||
* @param w
|
||||
* @param tag
|
||||
* @param enableEmit
|
||||
* @return 返回成功加入SARibbonActionsManager管理的action
|
||||
*/
|
||||
QSet< QAction* > SARibbonActionsManager::autoRegisteWidgetActions(QWidget* w, int tag, bool enableEmit)
|
||||
{
|
||||
QSet< QAction* > res;
|
||||
QList< QAction* > was = w->actions();
|
||||
|
||||
for (QAction* a : qAsConst(was)) {
|
||||
if (res.contains(a) || a->objectName().isEmpty()) {
|
||||
// 重复内容不重复加入
|
||||
// 没有object name不加入
|
||||
continue;
|
||||
}
|
||||
if (registeAction(a, tag, a->objectName(), enableEmit)) {
|
||||
res.insert(a);
|
||||
}
|
||||
}
|
||||
return (res);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 根据标题查找action
|
||||
* @param text
|
||||
* @return
|
||||
*/
|
||||
QList< QAction* > SARibbonActionsManager::search(const QString& text)
|
||||
{
|
||||
QList< QAction* > res;
|
||||
|
||||
if (text.isEmpty()) {
|
||||
return (res);
|
||||
}
|
||||
QStringList kws = text.split(" ");
|
||||
|
||||
if (kws.isEmpty()) {
|
||||
kws.append(text);
|
||||
}
|
||||
QList< QAction* > acts = d_ptr->mActionToKey.keys();
|
||||
|
||||
for (const QString& k : qAsConst(kws)) {
|
||||
for (auto i = d_ptr->mActionToKey.begin(); i != d_ptr->mActionToKey.end(); ++i) {
|
||||
if (i.key()->text().contains(k, Qt::CaseInsensitive)) {
|
||||
res.append(i.key());
|
||||
}
|
||||
}
|
||||
}
|
||||
return (res);
|
||||
}
|
||||
|
||||
void SARibbonActionsManager::clear()
|
||||
{
|
||||
d_ptr->clear();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief action 被delete时,将触发此槽把管理的action删除
|
||||
* @param o
|
||||
* @note 这个函数不会触发actionTagChanged信号
|
||||
*/
|
||||
void SARibbonActionsManager::onActionDestroyed(QObject* o)
|
||||
{
|
||||
QAction* act = static_cast< QAction* >(o);
|
||||
|
||||
removeAction(act, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief autoRegisteActions函数会关联此槽,在标签内容改变时改变tag 对应 文本
|
||||
* @param title
|
||||
*/
|
||||
void SARibbonActionsManager::onCategoryTitleChanged(const QString& title)
|
||||
{
|
||||
SARibbonCategory* c = qobject_cast< SARibbonCategory* >(sender());
|
||||
|
||||
if (nullptr == c) {
|
||||
return;
|
||||
}
|
||||
int tag = d_ptr->mTagToCategory.key(c, -1);
|
||||
|
||||
if (tag == -1) {
|
||||
return;
|
||||
}
|
||||
setTagName(tag, title);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
/// SARibbonActionsModel
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
class SARibbonActionsManagerModel::PrivateData
|
||||
{
|
||||
SA_RIBBON_DECLARE_PUBLIC(SARibbonActionsManagerModel)
|
||||
public:
|
||||
PrivateData(SARibbonActionsManagerModel* p);
|
||||
void updateRef();
|
||||
int count() const;
|
||||
QAction* at(int index);
|
||||
bool isNull() const;
|
||||
|
||||
public:
|
||||
SARibbonActionsManager* mMgr { nullptr };
|
||||
int mTag { SARibbonActionsManager::CommonlyUsedActionTag };
|
||||
QString mSeatchText;
|
||||
QList< QAction* > mActions;
|
||||
};
|
||||
|
||||
SARibbonActionsManagerModel::PrivateData::PrivateData(SARibbonActionsManagerModel* p) : q_ptr(p)
|
||||
{
|
||||
}
|
||||
|
||||
void SARibbonActionsManagerModel::PrivateData::updateRef()
|
||||
{
|
||||
if (isNull()) {
|
||||
return;
|
||||
}
|
||||
if (!mSeatchText.isEmpty()) {
|
||||
mActions = mMgr->search(mSeatchText);
|
||||
} else {
|
||||
mActions = mMgr->actions(mTag);
|
||||
}
|
||||
}
|
||||
|
||||
int SARibbonActionsManagerModel::PrivateData::count() const
|
||||
{
|
||||
if (isNull()) {
|
||||
return (0);
|
||||
}
|
||||
return (mActions.size());
|
||||
}
|
||||
|
||||
QAction* SARibbonActionsManagerModel::PrivateData::at(int index)
|
||||
{
|
||||
if (isNull()) {
|
||||
return (nullptr);
|
||||
}
|
||||
if (index >= count()) {
|
||||
return (nullptr);
|
||||
}
|
||||
return (mActions.at(index));
|
||||
}
|
||||
|
||||
bool SARibbonActionsManagerModel::PrivateData::isNull() const
|
||||
{
|
||||
return (mMgr == nullptr);
|
||||
}
|
||||
|
||||
//===================================================
|
||||
// SARibbonActionsManagerModel
|
||||
//===================================================
|
||||
|
||||
SARibbonActionsManagerModel::SARibbonActionsManagerModel(QObject* p)
|
||||
: QAbstractListModel(p), d_ptr(new SARibbonActionsManagerModel::PrivateData(this))
|
||||
{
|
||||
}
|
||||
|
||||
SARibbonActionsManagerModel::SARibbonActionsManagerModel(SARibbonActionsManager* m, QObject* p)
|
||||
: QAbstractListModel(p), d_ptr(new SARibbonActionsManagerModel::PrivateData(this))
|
||||
{
|
||||
setupActionsManager(m);
|
||||
}
|
||||
|
||||
SARibbonActionsManagerModel::~SARibbonActionsManagerModel()
|
||||
{
|
||||
}
|
||||
|
||||
int SARibbonActionsManagerModel::rowCount(const QModelIndex& parent) const
|
||||
{
|
||||
if (parent.isValid()) { // 非顶层
|
||||
return (0);
|
||||
}
|
||||
// 顶层
|
||||
return (d_ptr->count());
|
||||
}
|
||||
|
||||
QVariant SARibbonActionsManagerModel::headerData(int section, Qt::Orientation orientation, int role) const
|
||||
{
|
||||
Q_UNUSED(section);
|
||||
if (role != Qt::DisplayRole) {
|
||||
return (QVariant());
|
||||
}
|
||||
if (Qt::Horizontal == orientation) {
|
||||
return (tr("action name"));
|
||||
}
|
||||
return (QVariant());
|
||||
}
|
||||
|
||||
Qt::ItemFlags SARibbonActionsManagerModel::flags(const QModelIndex& index) const
|
||||
{
|
||||
if (!index.isValid()) {
|
||||
return (Qt::NoItemFlags);
|
||||
}
|
||||
return (Qt::ItemIsSelectable | Qt::ItemIsEnabled);
|
||||
}
|
||||
|
||||
QVariant SARibbonActionsManagerModel::data(const QModelIndex& index, int role) const
|
||||
{
|
||||
QAction* act = indexToAction(index);
|
||||
|
||||
if (nullptr == act) {
|
||||
return (QVariant());
|
||||
}
|
||||
|
||||
switch (role) {
|
||||
case Qt::DisplayRole: {
|
||||
QString str = act->text();
|
||||
if (!str.isEmpty()) {
|
||||
return str;
|
||||
}
|
||||
// 如果文本为空,一般是没有设置文本,或者是窗口,如果是窗口,那么用windowtitle作为文本
|
||||
if (QWidgetAction* wa = qobject_cast< QWidgetAction* >(act)) {
|
||||
if (QWidget* w = wa->defaultWidget()) {
|
||||
str = w->windowTitle();
|
||||
}
|
||||
}
|
||||
return str;
|
||||
}
|
||||
case Qt::DecorationRole:
|
||||
return (act->icon());
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return (QVariant());
|
||||
}
|
||||
|
||||
void SARibbonActionsManagerModel::setFilter(int tag)
|
||||
{
|
||||
d_ptr->mTag = tag;
|
||||
update();
|
||||
}
|
||||
|
||||
void SARibbonActionsManagerModel::update()
|
||||
{
|
||||
beginResetModel();
|
||||
d_ptr->updateRef();
|
||||
endResetModel();
|
||||
}
|
||||
|
||||
void SARibbonActionsManagerModel::setupActionsManager(SARibbonActionsManager* m)
|
||||
{
|
||||
d_ptr->mMgr = m;
|
||||
d_ptr->mTag = SARibbonActionsManager::CommonlyUsedActionTag;
|
||||
d_ptr->mActions = m->filter(d_ptr->mTag);
|
||||
connect(m, &SARibbonActionsManager::actionTagChanged, this, &SARibbonActionsManagerModel::onActionTagChanged);
|
||||
update();
|
||||
}
|
||||
|
||||
void SARibbonActionsManagerModel::uninstallActionsManager()
|
||||
{
|
||||
if (!d_ptr->isNull()) {
|
||||
disconnect(
|
||||
d_ptr->mMgr, &SARibbonActionsManager::actionTagChanged, this, &SARibbonActionsManagerModel::onActionTagChanged);
|
||||
d_ptr->mMgr = nullptr;
|
||||
d_ptr->mTag = SARibbonActionsManager::CommonlyUsedActionTag;
|
||||
}
|
||||
update();
|
||||
}
|
||||
|
||||
QAction* SARibbonActionsManagerModel::indexToAction(QModelIndex index) const
|
||||
{
|
||||
if (!index.isValid()) {
|
||||
return (nullptr);
|
||||
}
|
||||
if (index.row() >= d_ptr->count()) {
|
||||
return (nullptr);
|
||||
}
|
||||
return (d_ptr->at(index.row()));
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 查找
|
||||
* @param text
|
||||
*/
|
||||
void SARibbonActionsManagerModel::search(const QString& text)
|
||||
{
|
||||
d_ptr->mSeatchText = text;
|
||||
update();
|
||||
}
|
||||
|
||||
void SARibbonActionsManagerModel::onActionTagChanged(int tag, bool isdelete)
|
||||
{
|
||||
if (isdelete && (tag == d_ptr->mTag)) {
|
||||
d_ptr->mTag = SARibbonActionsManager::UnknowActionTag;
|
||||
update();
|
||||
} else {
|
||||
if (tag == d_ptr->mTag) {
|
||||
update();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,147 @@
|
||||
#ifndef SARIBBONACTIONSMANAGER_H
|
||||
#define SARIBBONACTIONSMANAGER_H
|
||||
#include "SARibbonGlobal.h"
|
||||
#include <QObject>
|
||||
#include <QAbstractListModel>
|
||||
#include <QAction>
|
||||
#include <QMap>
|
||||
#include <QString>
|
||||
#include <QSet>
|
||||
class SARibbonBar;
|
||||
class SARibbonCategory;
|
||||
|
||||
/**
|
||||
* @brief 用于管理SARibbon的所有Action
|
||||
*
|
||||
* SARibbonActionsManager维护着两个表,一个是tag(标签)对应的Action list,
|
||||
* 一个是所有接受SARibbonActionsManager管理的action list。
|
||||
*
|
||||
* SARibbonActionsManager的标签对应一组actions,每个标签对应的action可以重复出现,
|
||||
* 但SARibbonActionsManager维护的action list里只有一份action,不会重复出现。
|
||||
*
|
||||
* tag用于对action list分组,每个tag的实体名字通过@ref setTagName 进行设置,在语言变化时需要及时调用
|
||||
* setTagName设置新的标签对应的文本。
|
||||
*
|
||||
* SARibbonActionsManager默认预设了6个常用标签见@ref SARibbonActionsManager::ActionTag ,用户自定义标签需要在
|
||||
* SARibbonActionsManager::UserDefineActionTag值的基础上进行累加。
|
||||
*
|
||||
* @ref filter (等同@ref actions )函数用于提取标签管理的action list,@ref allActions 函数返回SARibbonActionsManager
|
||||
* 管理的所有标签。
|
||||
*
|
||||
* 通过@ref autoRegisteActions 函数可以快速的建立action的管理,此函数会遍历@ref SARibbonBar下所有@ref SARibbonPannel 添加的action,并给予Category建立tag,正常使用用户仅需关注此autoRegisteActions函数即可
|
||||
*
|
||||
*
|
||||
*/
|
||||
class SA_RIBBON_EXPORT SARibbonActionsManager : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
SA_RIBBON_DECLARE_PRIVATE(SARibbonActionsManager)
|
||||
friend class SARibbonActionsManagerModel;
|
||||
|
||||
public:
|
||||
/**
|
||||
* @brief 定义action的标签
|
||||
*/
|
||||
enum ActionTag
|
||||
{
|
||||
UnknowActionTag = 0, ///< 未知的tag
|
||||
CommonlyUsedActionTag = 0x01, ///< 预设tag-常用命令
|
||||
NotInFunctionalAreaActionTag = 0x02, ///< 预设tag-不在功能区命令
|
||||
AutoCategoryDistinguishBeginTag = 0x1000, ///< 自动按Category划分的标签起始,在@ref autoRegisteActions 函数会用到
|
||||
AutoCategoryDistinguishEndTag = 0x2000, ///< 自动按Category划分的标签结束,在@ref autoRegisteActions 函数会用到
|
||||
NotInRibbonCategoryTag = 0x2001, ///< 不在功能区的标签@ref autoRegisteActions 函数会遍历所有category的action
|
||||
UserDefineActionTag = 0x8000 ///< 自定义标签,所有用户自定义tag要大于此tag
|
||||
};
|
||||
explicit SARibbonActionsManager(SARibbonBar* bar);
|
||||
~SARibbonActionsManager();
|
||||
//设置tag对应的名字
|
||||
void setTagName(int tag, const QString& name);
|
||||
|
||||
//获取tag对应的名字
|
||||
QString tagName(int tag) const;
|
||||
|
||||
//移除tag,注意,这个函数非常耗时
|
||||
void removeTag(int tag);
|
||||
|
||||
//注册action
|
||||
bool registeAction(QAction* act, int tag, const QString& key = QString(), bool enableEmit = true);
|
||||
|
||||
//取消action的注册
|
||||
void unregisteAction(QAction* act, bool enableEmit = true);
|
||||
|
||||
//过滤得到actions对应的引用,实际是一个迭代器
|
||||
QList< QAction* >& filter(int tag);
|
||||
|
||||
//通过tag筛选出系列action
|
||||
QList< QAction* >& actions(int tag);
|
||||
const QList< QAction* > actions(int tag) const;
|
||||
|
||||
//获取所有的标签
|
||||
QList< int > actionTags() const;
|
||||
|
||||
//通过key获取action
|
||||
QAction* action(const QString& key) const;
|
||||
|
||||
//通过action找到key
|
||||
QString key(QAction* act) const;
|
||||
|
||||
//返回所有管理的action数
|
||||
int count() const;
|
||||
|
||||
//返回所有管理的actions
|
||||
QList< QAction* > allActions() const;
|
||||
|
||||
//自动加载action,返回tag对应的Category指针
|
||||
QMap< int, SARibbonCategory* > autoRegisteActions(SARibbonBar* bar);
|
||||
|
||||
//自动加载widget下的actions函数返回的action,返回加载的数量,这些
|
||||
QSet< QAction* > autoRegisteWidgetActions(QWidget* w, int tag, bool enableEmit = false);
|
||||
|
||||
//根据标题查找action
|
||||
QList< QAction* > search(const QString& text);
|
||||
|
||||
//清除
|
||||
void clear();
|
||||
|
||||
Q_SIGNALS:
|
||||
|
||||
/**
|
||||
* @brief 标签变化触发的信号,变化包括新增和删除
|
||||
*/
|
||||
void actionTagChanged(int tag, bool isdelete);
|
||||
|
||||
private Q_SLOTS:
|
||||
void onActionDestroyed(QObject* o);
|
||||
void onCategoryTitleChanged(const QString& title);
|
||||
|
||||
private:
|
||||
void removeAction(QAction* act, bool enableEmit = true);
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief SARibbonActionsManager 对应的model
|
||||
*/
|
||||
class SA_RIBBON_EXPORT SARibbonActionsManagerModel : public QAbstractListModel
|
||||
{
|
||||
Q_OBJECT
|
||||
SA_RIBBON_DECLARE_PRIVATE(SARibbonActionsManagerModel)
|
||||
public:
|
||||
explicit SARibbonActionsManagerModel(QObject* p = nullptr);
|
||||
explicit SARibbonActionsManagerModel(SARibbonActionsManager* m, QObject* p = nullptr);
|
||||
~SARibbonActionsManagerModel();
|
||||
virtual int rowCount(const QModelIndex& parent) const override;
|
||||
virtual QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const override;
|
||||
virtual Qt::ItemFlags flags(const QModelIndex& index) const override;
|
||||
virtual QVariant data(const QModelIndex& index, int role) const override;
|
||||
void setFilter(int tag);
|
||||
void update();
|
||||
void setupActionsManager(SARibbonActionsManager* m);
|
||||
void uninstallActionsManager();
|
||||
QAction* indexToAction(QModelIndex index) const;
|
||||
void search(const QString& text);
|
||||
|
||||
private Q_SLOTS:
|
||||
void onActionTagChanged(int tag, bool isdelete);
|
||||
};
|
||||
|
||||
#endif // SARIBBONACTIONSMANAGER_H
|
||||
@@ -0,0 +1,33 @@
|
||||
#include "SARibbonApplicationButton.h"
|
||||
|
||||
SARibbonApplicationButton::SARibbonApplicationButton(QWidget* parent) : QToolButton(parent)
|
||||
{
|
||||
setFocusPolicy(Qt::NoFocus);
|
||||
setAutoRaise(true);
|
||||
setPopupMode(QToolButton::InstantPopup);
|
||||
setToolButtonStyle(Qt::ToolButtonTextBesideIcon);
|
||||
}
|
||||
|
||||
SARibbonApplicationButton::SARibbonApplicationButton(const QString& text, QWidget* parent) : QToolButton(parent)
|
||||
{
|
||||
setFocusPolicy(Qt::NoFocus);
|
||||
setAutoRaise(true);
|
||||
setPopupMode(QToolButton::InstantPopup);
|
||||
setToolButtonStyle(Qt::ToolButtonTextBesideIcon);
|
||||
setText(text);
|
||||
}
|
||||
|
||||
SARibbonApplicationButton::SARibbonApplicationButton(const QIcon& icon, const QString& text, QWidget* parent)
|
||||
: QToolButton(parent)
|
||||
{
|
||||
setFocusPolicy(Qt::NoFocus);
|
||||
setAutoRaise(true);
|
||||
setPopupMode(QToolButton::InstantPopup);
|
||||
setToolButtonStyle(Qt::ToolButtonTextBesideIcon);
|
||||
setIcon(icon);
|
||||
setText(text);
|
||||
}
|
||||
|
||||
SARibbonApplicationButton::~SARibbonApplicationButton()
|
||||
{
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
#ifndef SARIBBONAPPLICATIONBUTTON_H
|
||||
#define SARIBBONAPPLICATIONBUTTON_H
|
||||
#include <QToolButton>
|
||||
#include "SARibbonGlobal.h"
|
||||
|
||||
/**
|
||||
* @brief The SARibbonApplicationButton class
|
||||
*
|
||||
* 默认的plicationButton,可以通过样式指定不一样的ApplicationButton
|
||||
*/
|
||||
class SA_RIBBON_EXPORT SARibbonApplicationButton : public QToolButton
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit SARibbonApplicationButton(QWidget* parent = nullptr);
|
||||
explicit SARibbonApplicationButton(const QString& text, QWidget* parent = nullptr);
|
||||
explicit SARibbonApplicationButton(const QIcon& icon, const QString& text, QWidget* parent = nullptr);
|
||||
~SARibbonApplicationButton();
|
||||
};
|
||||
|
||||
#endif // SARIBBONAPPLICATIONBUTTON_H
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,459 @@
|
||||
#ifndef SARIBBONBAR_H
|
||||
#define SARIBBONBAR_H
|
||||
#include "SARibbonCategory.h"
|
||||
#include "SARibbonContextCategory.h"
|
||||
#include "SARibbonGlobal.h"
|
||||
#include <QMenuBar>
|
||||
#include <QScopedPointer>
|
||||
#include <QVariant>
|
||||
|
||||
class QAction;
|
||||
class QAbstractButton;
|
||||
class SARibbonElementFactory;
|
||||
class SARibbonTabBar;
|
||||
class SARibbonButtonGroupWidget;
|
||||
class SARibbonQuickAccessBar;
|
||||
class SARibbonStackedWidget;
|
||||
|
||||
/**
|
||||
@brief SARibbonBar继承于QMenuBar,在SARibbonMainWindow中直接替换了原来的QMenuBar
|
||||
|
||||
通过setRibbonStyle函数设置ribbon的风格:
|
||||
|
||||
@code
|
||||
void setRibbonStyle(RibbonStyles v);
|
||||
@endcode
|
||||
|
||||
SARibbonBar参考office和wps,提供了四种风格的Ribbon模式,@ref SARibbonBar::RibbonStyles
|
||||
|
||||
如果想ribbon占用的空间足够小,WpsLiteStyleTwoRow模式能比OfficeStyle节省35%的高度空间
|
||||
|
||||
如何生成ribbon?先看看一个传统的Menu/ToolBar是如何生成的:
|
||||
|
||||
@code
|
||||
void MainWindow::MainWindow()
|
||||
{
|
||||
QMenu *fileMenu = menuBar()->addMenu(tr("&File"));
|
||||
QToolBar *fileToolBar = addToolBar(tr("File"));
|
||||
//生成action
|
||||
QAction *newAct = new QAction(newIcon, tr("&New"), this);
|
||||
fileMenu->addAction(newAct);
|
||||
fileToolBar->addAction(newAct);
|
||||
|
||||
QAction *openAct = new QAction(openIcon, tr("&Open..."), this);
|
||||
fileMenu->addAction(openAct);
|
||||
fileToolBar->addAction(openAct);
|
||||
}
|
||||
@endcode
|
||||
|
||||
传统的Menu/ToolBar主要通过QMenu的addMenu添加菜单,通过QMainWindow::addToolBar生成QToolBar,
|
||||
再把QAction设置进QMenu和QToolBar中
|
||||
|
||||
SARibbonBar和传统方法相似,不过相对于传统的Menu/ToolBar QMenu和QToolBar是平级的,
|
||||
Ribbon是有明显的层级关系,SARibbonBar下面是 @ref SARibbonCategory,
|
||||
SARibbonCategory下面是@ref SARibbonPannel ,SARibbonPannel下面是@ref SARibbonToolButton ,
|
||||
SARibbonToolButton管理着QAction
|
||||
|
||||
因此,生成一个ribbon只需以下几个函数:
|
||||
@code
|
||||
SARibbonCategory * SARibbonBar::addCategoryPage(const QString& title);
|
||||
SARibbonPannel * SARibbonCategory::addPannel(const QString& title);
|
||||
SARibbonToolButton * SARibbonPannel::addLargeAction(QAction *action);
|
||||
SARibbonToolButton * SARibbonPannel::addSmallAction(QAction *action);
|
||||
@endcode
|
||||
|
||||
因此生成步骤如下:
|
||||
|
||||
@code
|
||||
//成员变量
|
||||
SARibbonCategory* categoryMain;
|
||||
SARibbonPannel* FilePannel;
|
||||
|
||||
//建立ui
|
||||
void setupRibbonUi()
|
||||
{
|
||||
......
|
||||
//ribbonwindow为SARibbonMainWindow
|
||||
SARibbonBar* ribbon = ribbonwindow->ribbonBar();
|
||||
ribbon->setRibbonStyle(SARibbonBar::WpsLiteStyle);
|
||||
//添加一个Main标签
|
||||
categoryMain = ribbon->addCategoryPage(QStringLiteral("Main"));
|
||||
//Main标签下添加一个File Pannel
|
||||
FilePannel = categoryMain->addPannel(QStringLiteral("FilePannel"));
|
||||
//开始为File Pannel添加action
|
||||
FilePannel->addLargeAction(actionNew);
|
||||
FilePannel->addLargeAction(actionOpen);
|
||||
FilePannel->addLargeAction(actionSave);
|
||||
FilePannel->addSmallAction(actionImportMesh);
|
||||
FilePannel->addSmallAction(actionImportGeometry);
|
||||
}
|
||||
@endcode
|
||||
*/
|
||||
class SA_RIBBON_EXPORT SARibbonBar : public QMenuBar
|
||||
{
|
||||
Q_OBJECT
|
||||
SA_RIBBON_DECLARE_PRIVATE(SARibbonBar)
|
||||
friend class SARibbonMainWindow;
|
||||
friend class SARibbonSystemButtonBar;
|
||||
Q_PROPERTY(RibbonStyles ribbonStyle READ currentRibbonStyle WRITE setRibbonStyle)
|
||||
Q_PROPERTY(bool minimumMode READ isMinimumMode WRITE setMinimumMode)
|
||||
Q_PROPERTY(bool minimumModeButton READ haveShowMinimumModeButton WRITE showMinimumModeButton)
|
||||
Q_PROPERTY(QColor windowTitleTextColor READ windowTitleTextColor WRITE setWindowTitleTextColor)
|
||||
Q_PROPERTY(QColor tabBarBaseLineColor READ tabBarBaseLineColor WRITE setTabBarBaseLineColor)
|
||||
Q_PROPERTY(Qt::Alignment windowTitleAligment READ windowTitleAligment WRITE setWindowTitleAligment)
|
||||
Q_PROPERTY(bool enableWordWrap READ isEnableWordWrap WRITE setEnableWordWrap)
|
||||
Q_PROPERTY(bool enableShowPannelTitle READ isEnableShowPannelTitle WRITE setEnableShowPannelTitle)
|
||||
Q_PROPERTY(bool tabOnTitle READ isTabOnTitle WRITE setTabOnTitle)
|
||||
Q_PROPERTY(SARibbonPannel::PannelLayoutMode pannelLayoutMode READ pannelLayoutMode WRITE setPannelLayoutMode)
|
||||
|
||||
public:
|
||||
enum RibbonStyleFlag
|
||||
{
|
||||
RibbonStyleLoose = 0x0001, // bit:0000 0001
|
||||
RibbonStyleCompact = 0x0002, // bit:0000 0010
|
||||
RibbonStyleThreeRow = 0x0010, // bit:0001 0000
|
||||
RibbonStyleTwoRow = 0x0020, // bit:0010 0000
|
||||
|
||||
RibbonStyleLooseThreeRow = RibbonStyleLoose | RibbonStyleThreeRow, ///< 宽松结构,3行模式
|
||||
RibbonStyleCompactThreeRow = RibbonStyleCompact | RibbonStyleThreeRow, ///< 紧凑结构,3行模式
|
||||
RibbonStyleLooseTwoRow = RibbonStyleLoose | RibbonStyleTwoRow, ///< 宽松结构,2行模式
|
||||
RibbonStyleCompactTwoRow = RibbonStyleCompact | RibbonStyleTwoRow ///< 紧凑结构,2行模式
|
||||
};
|
||||
Q_ENUM(RibbonStyleFlag)
|
||||
Q_DECLARE_FLAGS(RibbonStyles, RibbonStyleFlag)
|
||||
Q_FLAG(RibbonStyles)
|
||||
|
||||
/**
|
||||
* @brief 定义当前ribbon 的状态
|
||||
*/
|
||||
enum RibbonMode
|
||||
{
|
||||
MinimumRibbonMode, ///< 缩小模式
|
||||
NormalRibbonMode ///< 正常模式
|
||||
};
|
||||
Q_ENUM(RibbonMode)
|
||||
|
||||
using FpCategoryIterate = std::function< bool(SARibbonCategory*) >;
|
||||
using FpPannelIterate = SARibbonCategory::FpPannelIterate;
|
||||
|
||||
public:
|
||||
// 判断RibbonStyle是否为2行模式
|
||||
static bool isTwoRowStyle(RibbonStyles s);
|
||||
static bool isThreeRowStyle(RibbonStyles s);
|
||||
// 判断是否是office样式
|
||||
static bool isLooseStyle(RibbonStyles s);
|
||||
static bool isCompactStyle(RibbonStyles s);
|
||||
// 获取版本信息
|
||||
static QString versionString();
|
||||
|
||||
// 获取默认的上下文标签颜色列表
|
||||
static QList< QColor > defaultContextCategoryColorList();
|
||||
|
||||
//
|
||||
static void initHighDpi();
|
||||
|
||||
public:
|
||||
// 构造函数
|
||||
explicit SARibbonBar(QWidget* parent = nullptr);
|
||||
~SARibbonBar();
|
||||
// 获取applicationButton
|
||||
QAbstractButton* applicationButton();
|
||||
|
||||
// 设置applicationButton
|
||||
void setApplicationButton(QAbstractButton* btn);
|
||||
|
||||
// 获取tabbar
|
||||
SARibbonTabBar* ribbonTabBar();
|
||||
|
||||
// 添加一个标签
|
||||
SARibbonCategory* addCategoryPage(const QString& title);
|
||||
void addCategoryPage(SARibbonCategory* category);
|
||||
|
||||
// 为了支持Qt designer,添加的一个重载函数
|
||||
Q_INVOKABLE void addCategoryPage(QWidget* category);
|
||||
|
||||
// 添加一个category,category的位置在index,如果当前category数量少于index,将插入到最后
|
||||
SARibbonCategory* insertCategoryPage(const QString& title, int index);
|
||||
void insertCategoryPage(SARibbonCategory* category, int index);
|
||||
|
||||
// 通过名字查找Category
|
||||
SARibbonCategory* categoryByName(const QString& title) const;
|
||||
|
||||
// 通过ObjectName查找Category
|
||||
SARibbonCategory* categoryByObjectName(const QString& objname) const;
|
||||
|
||||
// 通过索引找到category,如果超过索引范围,会返回nullptr
|
||||
SARibbonCategory* categoryByIndex(int index) const;
|
||||
|
||||
// 隐藏category,并不会删除或者取走,只是隐藏
|
||||
void hideCategory(SARibbonCategory* category);
|
||||
|
||||
// 显示被隐藏的category
|
||||
void showCategory(SARibbonCategory* category);
|
||||
|
||||
// 判断这个category是否在显示状态,也就是tabbar有这个category
|
||||
bool isCategoryVisible(const SARibbonCategory* c) const;
|
||||
|
||||
// 获取category的索引
|
||||
int categoryIndex(const SARibbonCategory* c) const;
|
||||
|
||||
// 移动一个Category从from index到to index
|
||||
void moveCategory(int from, int to);
|
||||
|
||||
// 获取当前显示的所有的SARibbonCategory,包含未显示的SARibbonContextCategory的SARibbonCategory也一并返回
|
||||
QList< SARibbonCategory* > categoryPages(bool getAll = true) const;
|
||||
|
||||
// 移除SARibbonCategory
|
||||
void removeCategory(SARibbonCategory* category);
|
||||
|
||||
// 添加一个上下文标签
|
||||
SARibbonContextCategory* addContextCategory(const QString& title,
|
||||
const QColor& color = QColor(),
|
||||
const QVariant& id = QVariant());
|
||||
void addContextCategory(SARibbonContextCategory* context);
|
||||
|
||||
// 显示一个上下文标签
|
||||
void showContextCategory(SARibbonContextCategory* context);
|
||||
|
||||
// 隐藏一个上下文标签
|
||||
void hideContextCategory(SARibbonContextCategory* context);
|
||||
|
||||
// 判断上下文是否是在显示状态
|
||||
bool isContextCategoryVisible(SARibbonContextCategory* context);
|
||||
|
||||
// 设置上下文标签的显示或隐藏
|
||||
void setContextCategoryVisible(SARibbonContextCategory* context, bool visible);
|
||||
|
||||
// 获取所有的上下文标签
|
||||
QList< SARibbonContextCategory* > contextCategoryList() const;
|
||||
|
||||
// 移除ContextCategory
|
||||
void destroyContextCategory(SARibbonContextCategory* context);
|
||||
|
||||
// 设置为隐藏模式
|
||||
void setMinimumMode(bool isHide);
|
||||
|
||||
// 当前Ribbon是否是隐藏模式
|
||||
bool isMinimumMode() const;
|
||||
|
||||
// 设置显示隐藏ribbon按钮
|
||||
void showMinimumModeButton(bool isShow = true);
|
||||
|
||||
// 是否显示隐藏ribbon按钮
|
||||
bool haveShowMinimumModeButton() const;
|
||||
|
||||
// 隐藏ribbon对应的action
|
||||
QAction* minimumModeAction() const;
|
||||
|
||||
// 当前的模式
|
||||
RibbonMode currentRibbonState() const;
|
||||
|
||||
// ribbon tab的高度
|
||||
int tabBarHeight() const;
|
||||
void setTabBarHeight(int h, bool resizeByNow = true);
|
||||
|
||||
// 标题栏的高度
|
||||
int titleBarHeight() const;
|
||||
void setTitleBarHeight(int h, bool resizeByNow = true);
|
||||
|
||||
// category的高度
|
||||
int categoryHeight() const;
|
||||
void setCategoryHeight(int h, bool resizeByNow = true);
|
||||
|
||||
// 获取正常模式下的mainBar的高度
|
||||
int normalModeMainBarHeight() const;
|
||||
|
||||
// 最小模式下的MainBar高度
|
||||
int minimumModeMainBarHeight() const;
|
||||
|
||||
// 激活tabbar右边的按钮群
|
||||
SARibbonButtonGroupWidget* activeRightButtonGroup();
|
||||
|
||||
// 右侧按钮群
|
||||
SARibbonButtonGroupWidget* rightButtonGroup();
|
||||
|
||||
// 激活QuickAccessBar
|
||||
SARibbonQuickAccessBar* activeQuickAccessBar();
|
||||
|
||||
// 快速响应栏
|
||||
SARibbonQuickAccessBar* quickAccessBar();
|
||||
|
||||
// 设置ribbon的风格
|
||||
void setRibbonStyle(RibbonStyles v);
|
||||
RibbonStyles currentRibbonStyle() const;
|
||||
|
||||
// 设置当前ribbon的index
|
||||
void setCurrentIndex(int index);
|
||||
|
||||
// 返回当前的tab索引
|
||||
int currentIndex();
|
||||
|
||||
// 确保标签显示出来
|
||||
void raiseCategory(SARibbonCategory* category);
|
||||
|
||||
// 判断当前的行数
|
||||
bool isTwoRowStyle() const;
|
||||
bool isThreeRowStyle() const;
|
||||
|
||||
// 判断当前的样式
|
||||
bool isLooseStyle() const;
|
||||
bool isCompactStyle() const;
|
||||
|
||||
// 更新ribbon的布局数据,此函数适用于一些关键性尺寸变化,换起ribbon下面元素的布局,在发现刷新问题时,可以调用此函数
|
||||
void updateRibbonGeometry();
|
||||
|
||||
// 设置pannel的模式
|
||||
SARibbonPannel::PannelLayoutMode pannelLayoutMode() const;
|
||||
void setPannelLayoutMode(SARibbonPannel::PannelLayoutMode m);
|
||||
|
||||
// 设置tab在title上面,这样可以省略title区域
|
||||
void setTabOnTitle(bool on);
|
||||
bool isTabOnTitle() const;
|
||||
|
||||
// tabbar 底部会绘制一条线条,此接口定义线条颜色
|
||||
void setTabBarBaseLineColor(const QColor& clr);
|
||||
QColor tabBarBaseLineColor() const;
|
||||
|
||||
// 设置标题颜色,如果不设置标题颜色,默认是SARibbonBar的qss的color属性
|
||||
void setWindowTitleTextColor(const QColor& clr);
|
||||
QColor windowTitleTextColor() const;
|
||||
|
||||
// 设置标题的对齐方式
|
||||
void setWindowTitleAligment(Qt::Alignment al);
|
||||
Qt::Alignment windowTitleAligment() const;
|
||||
|
||||
// 设置按钮允许换行,注意图标大小是由文字决定的,两行文字会让图标变小,如果想图标变大,文字不换行是最好的
|
||||
void setEnableWordWrap(bool on);
|
||||
bool isEnableWordWrap() const;
|
||||
|
||||
// 设置pannel的标题栏高度
|
||||
int pannelTitleHeight() const;
|
||||
void setPannelTitleHeight(int h);
|
||||
|
||||
// 设置pannel是否显示标题栏
|
||||
bool isEnableShowPannelTitle() const;
|
||||
void setEnableShowPannelTitle(bool on);
|
||||
|
||||
// 设置pannel的spacing
|
||||
void setPannelSpacing(int n);
|
||||
int pannelSpacing() const;
|
||||
|
||||
// 设置pannel按钮的icon尺寸,large action不受此尺寸影响
|
||||
void setPannelToolButtonIconSize(const QSize& s);
|
||||
QSize pannelToolButtonIconSize() const;
|
||||
|
||||
// 获取SARibbonStackedWidget,谨慎使用此函数
|
||||
SARibbonStackedWidget* ribbonStackedWidget();
|
||||
|
||||
// 设置是否显示标题
|
||||
void setTitleVisible(bool on = false);
|
||||
bool isTitleVisible() const;
|
||||
|
||||
// 上下文标签的颜色列表,上下文标签显示的时候,会从颜色列表中取颜色进行标签的渲染
|
||||
void setContextCategoryColorList(const QList< QColor >& cls);
|
||||
QList< QColor > contextCategoryColorList() const;
|
||||
|
||||
// 设置context category 标题的文字颜色
|
||||
void setContextCategoryTitleTextColor(const QColor& clr);
|
||||
QColor contextCategoryTitleTextColor() const;
|
||||
|
||||
// 设置ribbon的对齐方式
|
||||
void setRibbonAlignment(SARibbonAlignment al);
|
||||
SARibbonAlignment ribbonAlignment() const;
|
||||
|
||||
// 此函数会遍历SARibbonBar下的所有Category,执行函数指针(bool(SARibbonCategory*)),函数指针返回false则停止迭代
|
||||
bool iterate(FpCategoryIterate fp);
|
||||
// 此函数会遍历SARibbonBar下的所有Category,并迭代所有的pannel,执行函数指针(bool(SARibbonPannel*)),函数指针返回false则停止迭代
|
||||
bool iterate(FpPannelIterate fp);
|
||||
|
||||
// 设置边角widget可见性,对于mdi窗口,会出现TopLeftCorner和TopRightCorner两个corner widget
|
||||
void setCornerWidgetVisible(bool on, Qt::Corner c = Qt::TopLeftCorner);
|
||||
Q_SIGNALS:
|
||||
|
||||
/**
|
||||
@brief 应用按钮点击响应 - 左上角的按钮,通过关联此信号触发应用按钮点击的效果
|
||||
|
||||
例如想点击按钮后弹出一个全屏的窗口(如office这些)
|
||||
*/
|
||||
void applicationButtonClicked();
|
||||
|
||||
/**
|
||||
@brief 标签页变化触发的信号
|
||||
@param index
|
||||
*/
|
||||
void currentRibbonTabChanged(int index);
|
||||
|
||||
/**
|
||||
@brief ribbon的状态发生了变化后触发此信号
|
||||
@param nowState 变更之后的ribbon状态
|
||||
*/
|
||||
void ribbonModeChanged(SARibbonBar::RibbonMode nowState);
|
||||
|
||||
/**
|
||||
@brief ribbon的状态发生了变化后触发此信号
|
||||
@param nowStyle 变更之后的ribbon样式
|
||||
*/
|
||||
void ribbonStyleChanged(SARibbonBar::RibbonStyles nowStyle);
|
||||
|
||||
/**
|
||||
@brief 标题栏高度发生了变化的信号
|
||||
@param oldHeight
|
||||
@param newHeight
|
||||
*/
|
||||
void titleBarHeightChanged(int oldHeight, int newHeight);
|
||||
|
||||
/**
|
||||
* @brief 参考QToolBar::actionTriggered的信号
|
||||
* @param action
|
||||
*/
|
||||
void actionTriggered(QAction* action);
|
||||
|
||||
protected:
|
||||
bool eventFilter(QObject* obj, QEvent* e) override;
|
||||
// 根据情况重置tabbar的宽度,主要针对wps模式
|
||||
int calcMinTabBarWidth() const;
|
||||
// 更新
|
||||
void updateCategoryTitleToTabName();
|
||||
// 告知WindowButtonGroup的尺寸
|
||||
void setWindowButtonGroupSize(const QSize& s);
|
||||
protected Q_SLOTS:
|
||||
void onWindowTitleChanged(const QString& title);
|
||||
void onWindowIconChanged(const QIcon& i);
|
||||
void onCategoryWindowTitleChanged(const QString& title);
|
||||
void onStackWidgetHided();
|
||||
virtual void onCurrentRibbonTabChanged(int index);
|
||||
virtual void onCurrentRibbonTabClicked(int index);
|
||||
virtual void onCurrentRibbonTabDoubleClicked(int index);
|
||||
void onContextsCategoryPageAdded(SARibbonCategory* category);
|
||||
void onContextsCategoryCategoryNameChanged(SARibbonCategory* category, const QString& title);
|
||||
void onTabMoved(int from, int to);
|
||||
|
||||
private:
|
||||
int tabIndex(SARibbonCategory* obj);
|
||||
void resizeAll();
|
||||
void resizeInLooseStyle();
|
||||
void resizeInCompactStyle();
|
||||
void paintInLooseStyle();
|
||||
void paintInCompactStyle();
|
||||
void resizeStackedContainerWidget();
|
||||
|
||||
// 刷新所有ContextCategoryManagerData,这个在单独一个Category删除时调用
|
||||
void updateContextCategoryManagerData();
|
||||
void synchronousCategoryData(bool autoUpdate = true);
|
||||
|
||||
protected:
|
||||
virtual void paintEvent(QPaintEvent* e) override;
|
||||
virtual void resizeEvent(QResizeEvent* e) override;
|
||||
virtual void moveEvent(QMoveEvent* e) override;
|
||||
virtual void changeEvent(QEvent* e) override;
|
||||
virtual bool event(QEvent* e) override;
|
||||
virtual void paintTabbarBaseLine(QPainter& painter);
|
||||
virtual void paintWindowTitle(QPainter& painter, const QString& title, const QRect& titleRegion);
|
||||
virtual void paintContextCategoryTab(QPainter& painter, const QString& title, const QRect& contextRect, const QColor& color);
|
||||
#if SA_DEBUG_PRINT_SARIBBONBAR
|
||||
SA_RIBBON_EXPORT friend QDebug operator<<(QDebug debug, const SARibbonBar& ribbon);
|
||||
#endif
|
||||
};
|
||||
Q_DECLARE_OPERATORS_FOR_FLAGS(SARibbonBar::RibbonStyles)
|
||||
|
||||
#endif // SARIBBONBAR_H
|
||||
@@ -0,0 +1,123 @@
|
||||
|
||||
|
||||
# 这里要做如下改动:
|
||||
# 1.framelesshelper/qmake/inc/core/framelesshelper.config中的FRAMELESSHELPER_FEATURE_static_build设置为-1
|
||||
# 2.要预定义FRAMELESSHELPER_CORE_LIBRARY宏,这样才能导出符号
|
||||
# 3.要预定义FRAMELESSHELPER_WIDGETS_LIBRARY宏,这样才能导出符号
|
||||
contains( SA_RIBBON_CONFIG, use_frameless ) {
|
||||
message("use frameless lib,compile with c+=17")
|
||||
# 引入第三方库frameless后,必须要求c++17
|
||||
!contains(CONFIG,C++17){
|
||||
CONFIG += c++17
|
||||
}
|
||||
!exists($$SA_RIBBON_QWindowKit_Install_DIR){
|
||||
message("SA_RIBBON_QWindowKit_Install_DIR not define,set to $$SARIBBON_BIN_DIR")
|
||||
SA_RIBBON_QWindowKit_Install_DIR = $$SARIBBON_BIN_DIR
|
||||
}
|
||||
SA_RIBBON_QWindowKit_QMake_DIR = $$SA_RIBBON_QWindowKit_Install_DIR/share/QWindowKit/qmake
|
||||
include($$SA_RIBBON_QWindowKit_QMake_DIR/QWKCore.pri)
|
||||
include($$SA_RIBBON_QWindowKit_QMake_DIR/QWKWidgets.pri)
|
||||
# 定义SARIBBON_USE_3RDPARTY_FRAMELESSHELPER=1是的使用framelss库
|
||||
DEFINES += SARIBBON_USE_3RDPARTY_FRAMELESSHELPER=1
|
||||
contains( SA_RIBBON_CONFIG, enable_snap_layout ) {
|
||||
DEFINES += SARIBBON_ENABLE_SNAP_LAYOUT=1
|
||||
}
|
||||
}else{
|
||||
message("do not use_frameless lib,compile with c+=14")
|
||||
!contains(CONFIG,C++14){
|
||||
CONFIG += c++14
|
||||
}
|
||||
DEFINES += SARIBBON_USE_3RDPARTY_FRAMELESSHELPER=0
|
||||
}
|
||||
message("SA_RIBBON_CONFIG="$${SA_RIBBON_CONFIG})
|
||||
#-------------------------------------------------
|
||||
#
|
||||
# SARibbon的文件
|
||||
#
|
||||
#-------------------------------------------------
|
||||
|
||||
SOURCES += \
|
||||
$$PWD/SAFramelessHelper.cpp \
|
||||
$$PWD/SARibbonActionsManager.cpp \
|
||||
$$PWD/SARibbonBar.cpp \
|
||||
$$PWD/SARibbonColorToolButton.cpp \
|
||||
$$PWD/SARibbonCustomizeData.cpp \
|
||||
$$PWD/SARibbonCustomizeDialog.cpp \
|
||||
$$PWD/SARibbonCustomizeWidget.cpp \
|
||||
$$PWD/SARibbonElementFactory.cpp \
|
||||
$$PWD/SARibbonMainWindow.cpp \
|
||||
$$PWD/SARibbonSystemButtonBar.cpp \
|
||||
$$PWD/SARibbonApplicationButton.cpp \
|
||||
$$PWD/SARibbonTabBar.cpp \
|
||||
$$PWD/SARibbonCategory.cpp \
|
||||
$$PWD/SARibbonContextCategory.cpp \
|
||||
$$PWD/SARibbonPannel.cpp \
|
||||
$$PWD/SARibbonToolButton.cpp \
|
||||
$$PWD/SARibbonMenu.cpp \
|
||||
$$PWD/SARibbonPannelOptionButton.cpp \
|
||||
$$PWD/SARibbonSeparatorWidget.cpp \
|
||||
$$PWD/SARibbonCategoryLayout.cpp \
|
||||
$$PWD/SARibbonGallery.cpp \
|
||||
$$PWD/SARibbonControlButton.cpp \
|
||||
$$PWD/SARibbonGalleryGroup.cpp \
|
||||
$$PWD/SARibbonGalleryItem.cpp \
|
||||
$$PWD/SARibbonComboBox.cpp \
|
||||
$$PWD/SARibbonElementManager.cpp \
|
||||
$$PWD/SARibbonLineEdit.cpp \
|
||||
$$PWD/SARibbonCheckBox.cpp \
|
||||
$$PWD/SARibbonButtonGroupWidget.cpp \
|
||||
$$PWD/SARibbonStackedWidget.cpp \
|
||||
$$PWD/SARibbonQuickAccessBar.cpp \
|
||||
$$PWD/SARibbonCtrlContainer.cpp \
|
||||
$$PWD/SARibbonPannelLayout.cpp \
|
||||
$$PWD/SARibbonPannelItem.cpp \
|
||||
$$PWD/SARibbonLineWidgetContainer.cpp \
|
||||
$$PWD/SARibbonWidget.cpp
|
||||
|
||||
HEADERS += \
|
||||
$$PWD/SAFramelessHelper.h \
|
||||
$$PWD/SARibbonActionsManager.h \
|
||||
$$PWD/SARibbonBar.h \
|
||||
$$PWD/SARibbonColorToolButton.h \
|
||||
$$PWD/SARibbonCustomizeData.h \
|
||||
$$PWD/SARibbonCustomizeDialog.h \
|
||||
$$PWD/SARibbonCustomizeWidget.h \
|
||||
$$PWD/SARibbonElementFactory.h \
|
||||
$$PWD/SARibbonMainWindow.h \
|
||||
$$PWD/SARibbonSystemButtonBar.h \
|
||||
$$PWD/SARibbonApplicationButton.h \
|
||||
$$PWD/SARibbonTabBar.h \
|
||||
$$PWD/SARibbonCategory.h \
|
||||
$$PWD/SARibbonContextCategory.h \
|
||||
$$PWD/SARibbonPannel.h \
|
||||
$$PWD/SARibbonToolButton.h \
|
||||
$$PWD/SARibbonMenu.h \
|
||||
$$PWD/SARibbonGlobal.h \
|
||||
$$PWD/SARibbonPannelOptionButton.h \
|
||||
$$PWD/SARibbonSeparatorWidget.h \
|
||||
$$PWD/SARibbonCategoryLayout.h \
|
||||
$$PWD/SARibbonGallery.h \
|
||||
$$PWD/SARibbonControlButton.h \
|
||||
$$PWD/SARibbonGalleryGroup.h \
|
||||
$$PWD/SARibbonGalleryItem.h \
|
||||
$$PWD/SARibbonComboBox.h \
|
||||
$$PWD/SARibbonElementManager.h \
|
||||
$$PWD/SARibbonLineEdit.h \
|
||||
$$PWD/SARibbonCheckBox.h \
|
||||
$$PWD/SARibbonButtonGroupWidget.h \
|
||||
$$PWD/SARibbonStackedWidget.h \
|
||||
$$PWD/SARibbonQuickAccessBar.h \
|
||||
$$PWD/SARibbonCtrlContainer.h \
|
||||
$$PWD/SARibbonPannelLayout.h \
|
||||
$$PWD/SARibbonPannelItem.h \
|
||||
$$PWD/SARibbonLineWidgetContainer.h \
|
||||
$$PWD/SARibbonWidget.h
|
||||
|
||||
RESOURCES += \
|
||||
$$PWD/resource.qrc
|
||||
|
||||
# 加入SAColorWidgets组件
|
||||
include($$PWD/colorWidgets/SAColorWidgets.pri)
|
||||
|
||||
INCLUDEPATH += $$PWD
|
||||
DEPENDPATH += $$PWD
|
||||
@@ -0,0 +1,22 @@
|
||||
#-------------------------------------------------
|
||||
#
|
||||
# Project created by QtCreator 2017-09-21T14:04:12
|
||||
#
|
||||
#-------------------------------------------------
|
||||
|
||||
QT += core gui
|
||||
|
||||
TEMPLATE = lib
|
||||
|
||||
DEFINES += SA_RIBBON_BAR_MAKE_LIB #定义此宏将构建库
|
||||
DEFINES += SA_COLOR_WIDGETS_MAKE_LIB #定义此宏将构建ColorWidgets库
|
||||
#DEFINES += SA_RIBBON_DEBUG_HELP_DRAW # 此宏将绘制辅助线用于调试
|
||||
|
||||
greaterThan(QT_MAJOR_VERSION, 4): QT += widgets
|
||||
include($$PWD/../../common.pri)
|
||||
|
||||
TARGET = $${SARIBBON_LIB_NAME}
|
||||
DESTDIR = $${SARIBBON_BIN_DIR}/bin
|
||||
|
||||
|
||||
include($$PWD/SARibbonBar.pri)
|
||||
@@ -0,0 +1,15 @@
|
||||
# This module defines
|
||||
# @PROJECT_NAME@_FOUND, if false, do not try to link to @PROJECT_NAME@
|
||||
# @PROJECT_NAME@_INCLUDE_DIR, where to find the headers
|
||||
# @PROJECT_NAME@_LIBRARIES, where to find the libs
|
||||
@PACKAGE_INIT@
|
||||
|
||||
set (PackageName @SARIBBON_LIB_NAME@)
|
||||
set (@SARIBBON_LIB_NAME@_VERSION @SARIBBON_VERSION@)
|
||||
|
||||
include ( ${CMAKE_CURRENT_LIST_DIR}/${PackageName}Targets.cmake )
|
||||
set_and_check ( ${PackageName}_INCLUDE_DIR ${PACKAGE_PREFIX_DIR}/@SARIBBON_LIB_INCLUDE_INSTALL_DIR@ )
|
||||
set ( ${PackageName}_LIBRARIES)
|
||||
list ( APPEND ${PackageName}_LIBRARIES ${PackageName})
|
||||
|
||||
check_required_components(${PackageName})
|
||||
@@ -0,0 +1,33 @@
|
||||
#ifndef SARIBBONVERSIONINFO_H
|
||||
#define SARIBBONVERSIONINFO_H
|
||||
/**
|
||||
* @file 此文档由cmake根据SARibbonBarVersionInfo.h.in自动生成,任何在此文件上的改动都将覆写
|
||||
*/
|
||||
|
||||
/**
|
||||
* @def ribbon的数字版本 {MAJ}.MIN.PAT
|
||||
*/
|
||||
#ifndef SA_RIBBON_BAR_VERSION_MAJ
|
||||
#define SA_RIBBON_BAR_VERSION_MAJ 2
|
||||
#endif
|
||||
/**
|
||||
* @def ribbon的数字版本 MAJ.{MIN}.PAT
|
||||
*/
|
||||
#ifndef SA_RIBBON_BAR_VERSION_MIN
|
||||
#define SA_RIBBON_BAR_VERSION_MIN 2
|
||||
#endif
|
||||
/**
|
||||
* @def ribbon的数字版本 MAJ.MIN.{PAT}
|
||||
*/
|
||||
#ifndef SA_RIBBON_BAR_VERSION_PAT
|
||||
#define SA_RIBBON_BAR_VERSION_PAT 5
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @def 版本号(字符串)
|
||||
*/
|
||||
#ifndef SARIBBON_VERSION
|
||||
#define SARIBBON_VERSION "2.2.5"
|
||||
#endif
|
||||
|
||||
#endif // SARIBBONVERSIONINFO_H
|
||||
@@ -0,0 +1,33 @@
|
||||
#ifndef SARIBBONVERSIONINFO_H
|
||||
#define SARIBBONVERSIONINFO_H
|
||||
/**
|
||||
* @file 此文档由cmake根据SARibbonBarVersionInfo.h.in自动生成,任何在此文件上的改动都将覆写
|
||||
*/
|
||||
|
||||
/**
|
||||
* @def ribbon的数字版本 {MAJ}.MIN.PAT
|
||||
*/
|
||||
#ifndef SA_RIBBON_BAR_VERSION_MAJ
|
||||
#define SA_RIBBON_BAR_VERSION_MAJ @SARIBBON_VERSION_MAJOR@
|
||||
#endif
|
||||
/**
|
||||
* @def ribbon的数字版本 MAJ.{MIN}.PAT
|
||||
*/
|
||||
#ifndef SA_RIBBON_BAR_VERSION_MIN
|
||||
#define SA_RIBBON_BAR_VERSION_MIN @SARIBBON_VERSION_MINOR@
|
||||
#endif
|
||||
/**
|
||||
* @def ribbon的数字版本 MAJ.MIN.{PAT}
|
||||
*/
|
||||
#ifndef SA_RIBBON_BAR_VERSION_PAT
|
||||
#define SA_RIBBON_BAR_VERSION_PAT @SARIBBON_VERSION_PATCH@
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @def 版本号(字符串)
|
||||
*/
|
||||
#ifndef SARIBBON_VERSION
|
||||
#cmakedefine SARIBBON_VERSION "@SARIBBON_VERSION@"
|
||||
#endif
|
||||
|
||||
#endif // SARIBBONVERSIONINFO_H
|
||||
@@ -0,0 +1,260 @@
|
||||
#include "SARibbonButtonGroupWidget.h"
|
||||
#include <QHBoxLayout>
|
||||
#include <QDebug>
|
||||
#include <QMargins>
|
||||
#include <QChildEvent>
|
||||
#include <QActionEvent>
|
||||
#include <QWidgetAction>
|
||||
#include <QApplication>
|
||||
#include "SARibbonControlButton.h"
|
||||
#include "SARibbonElementManager.h"
|
||||
#include "SARibbonSeparatorWidget.h"
|
||||
#include "SARibbonPannel.h"
|
||||
|
||||
//===================================================
|
||||
// SARibbonButtonGroupWidget::PrivateData
|
||||
//===================================================
|
||||
class SARibbonButtonGroupWidget::PrivateData
|
||||
{
|
||||
SA_RIBBON_DECLARE_PUBLIC(SARibbonButtonGroupWidget)
|
||||
public:
|
||||
PrivateData(SARibbonButtonGroupWidget* p);
|
||||
void init();
|
||||
void removeAction(QAction* a);
|
||||
|
||||
public:
|
||||
QSize mIconSize { 20, 20 };
|
||||
};
|
||||
|
||||
SARibbonButtonGroupWidget::PrivateData::PrivateData(SARibbonButtonGroupWidget* p) : q_ptr(p)
|
||||
{
|
||||
}
|
||||
|
||||
void SARibbonButtonGroupWidget::PrivateData::init()
|
||||
{
|
||||
QHBoxLayout* layout = new QHBoxLayout(q_ptr);
|
||||
// 上下保留一点间隙
|
||||
layout->setContentsMargins(0, 0, 0, 0);
|
||||
layout->setSpacing(1);
|
||||
q_ptr->setSizePolicy(QSizePolicy::Maximum, QSizePolicy::Maximum);
|
||||
}
|
||||
|
||||
void SARibbonButtonGroupWidget::PrivateData::removeAction(QAction* a)
|
||||
{
|
||||
QLayout* lay = q_ptr->layout();
|
||||
int c = lay->count();
|
||||
QList< QLayoutItem* > willRemoveItems;
|
||||
for (int i = 0; i < c; ++i) {
|
||||
QLayoutItem* item = lay->itemAt(i);
|
||||
SARibbonControlButton* btn = qobject_cast< SARibbonControlButton* >(item->widget());
|
||||
if (nullptr == btn) {
|
||||
continue;
|
||||
}
|
||||
if (a == btn->defaultAction()) {
|
||||
willRemoveItems.push_back(item);
|
||||
}
|
||||
}
|
||||
// 从尾部删除
|
||||
for (auto i = willRemoveItems.rbegin(); i != willRemoveItems.rend(); ++i) {
|
||||
lay->removeItem(*i);
|
||||
}
|
||||
}
|
||||
|
||||
//===================================================
|
||||
// SARibbonButtonGroupWidget
|
||||
//===================================================
|
||||
|
||||
SARibbonButtonGroupWidget::SARibbonButtonGroupWidget(QWidget* parent)
|
||||
: QFrame(parent), d_ptr(new SARibbonButtonGroupWidget::PrivateData(this))
|
||||
{
|
||||
d_ptr->init();
|
||||
}
|
||||
|
||||
SARibbonButtonGroupWidget::~SARibbonButtonGroupWidget()
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 设置图标尺寸
|
||||
* @param iconSize
|
||||
*/
|
||||
void SARibbonButtonGroupWidget::setIconSize(const QSize& ic)
|
||||
{
|
||||
d_ptr->mIconSize = ic;
|
||||
iterate([ ic ](SARibbonControlButton* btn) -> bool {
|
||||
btn->setIconSize(ic);
|
||||
return true;
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 图标尺寸
|
||||
* @return
|
||||
*/
|
||||
QSize SARibbonButtonGroupWidget::iconSize() const
|
||||
{
|
||||
return d_ptr->mIconSize;
|
||||
}
|
||||
|
||||
QAction* SARibbonButtonGroupWidget::addAction(QAction* a, Qt::ToolButtonStyle buttonStyle, QToolButton::ToolButtonPopupMode popMode)
|
||||
{
|
||||
SARibbonPannel::setActionToolButtonStyleProperty(a, buttonStyle);
|
||||
SARibbonPannel::setActionToolButtonPopupModeProperty(a, popMode);
|
||||
QWidget::addAction(a);
|
||||
return (a);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 生成action
|
||||
* @note action的所有权归SARibbonButtonGroupWidget
|
||||
* @param text
|
||||
* @param icon
|
||||
* @param popMode
|
||||
* @return
|
||||
*/
|
||||
QAction* SARibbonButtonGroupWidget::addAction(const QString& text, const QIcon& icon, Qt::ToolButtonStyle buttonStyle, QToolButton::ToolButtonPopupMode popMode)
|
||||
{
|
||||
QAction* a = new QAction(icon, text, this);
|
||||
addAction(a, buttonStyle, popMode);
|
||||
return (a);
|
||||
}
|
||||
|
||||
QAction* SARibbonButtonGroupWidget::addMenu(QMenu* menu, Qt::ToolButtonStyle buttonStyle, QToolButton::ToolButtonPopupMode popMode)
|
||||
{
|
||||
QAction* a = menu->menuAction();
|
||||
addAction(a, buttonStyle, popMode);
|
||||
return (a);
|
||||
}
|
||||
|
||||
QAction* SARibbonButtonGroupWidget::addSeparator()
|
||||
{
|
||||
QAction* a = new QAction(this);
|
||||
|
||||
a->setSeparator(true);
|
||||
addAction(a);
|
||||
return (a);
|
||||
}
|
||||
|
||||
QAction* SARibbonButtonGroupWidget::addWidget(QWidget* w)
|
||||
{
|
||||
QWidgetAction* a = new QWidgetAction(this);
|
||||
|
||||
a->setDefaultWidget(w);
|
||||
w->setAttribute(Qt::WA_Hover);
|
||||
addAction(a);
|
||||
return (a);
|
||||
}
|
||||
|
||||
SARibbonControlButton* SARibbonButtonGroupWidget::actionToRibbonControlToolButton(QAction* action)
|
||||
{
|
||||
SARibbonControlButton* res = nullptr;
|
||||
iterate([ &res, action ](SARibbonControlButton* btn) -> bool {
|
||||
if (btn->defaultAction() == action) {
|
||||
res = btn;
|
||||
return false; // 返回false退出迭代
|
||||
}
|
||||
return true;
|
||||
});
|
||||
return (res);
|
||||
}
|
||||
|
||||
QSize SARibbonButtonGroupWidget::sizeHint() const
|
||||
{
|
||||
return (layout()->sizeHint());
|
||||
}
|
||||
|
||||
QSize SARibbonButtonGroupWidget::minimumSizeHint() const
|
||||
{
|
||||
return (layout()->minimumSize());
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 此函数会遍历SARibbonButtonGroupWidget下的所有SARibbonControlButton,执行函数指针(bool(SARibbonControlButton*)),函数指针返回false则停止迭代
|
||||
* @param fp
|
||||
* @return 中途迭代退出返回false
|
||||
*/
|
||||
bool SARibbonButtonGroupWidget::iterate(SARibbonButtonGroupWidget::FpButtonIterate fp)
|
||||
{
|
||||
QLayout* lay = layout();
|
||||
int c = lay->count();
|
||||
for (int i = 0; i < c; ++i) {
|
||||
auto item = lay->itemAt(i);
|
||||
if (!item) {
|
||||
continue;
|
||||
}
|
||||
SARibbonControlButton* btn = qobject_cast< SARibbonControlButton* >(item->widget());
|
||||
if (!btn) {
|
||||
continue;
|
||||
}
|
||||
if (!fp(btn)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 处理action的事件
|
||||
*
|
||||
* 这里处理了ActionAdded,ActionChanged,ActionRemoved三个事件
|
||||
* ActionAdded时会生成窗口
|
||||
* @param e
|
||||
*/
|
||||
void SARibbonButtonGroupWidget::actionEvent(QActionEvent* e)
|
||||
{
|
||||
QAction* a = e->action();
|
||||
if (!a) {
|
||||
return;
|
||||
}
|
||||
|
||||
switch (e->type()) {
|
||||
case QEvent::ActionAdded: {
|
||||
QWidget* w = nullptr;
|
||||
if (QWidgetAction* widgetAction = qobject_cast< QWidgetAction* >(a)) {
|
||||
widgetAction->setParent(this);
|
||||
w = widgetAction->requestWidget(this);
|
||||
if (w != nullptr) {
|
||||
w->setAttribute(Qt::WA_LayoutUsesWidgetRect);
|
||||
w->show();
|
||||
}
|
||||
} else if (a->isSeparator()) {
|
||||
SARibbonSeparatorWidget* sp = RibbonSubElementFactory->createRibbonSeparatorWidget(this);
|
||||
w = sp;
|
||||
}
|
||||
// 不是widget,自动生成ButtonTyle
|
||||
if (!w) {
|
||||
SARibbonControlButton* button = RibbonSubElementFactory->createRibbonControlButton(this);
|
||||
button->setAutoRaise(true);
|
||||
button->setIconSize(d_ptr->mIconSize);
|
||||
button->setFocusPolicy(Qt::NoFocus);
|
||||
button->setDefaultAction(a);
|
||||
// 属性设置
|
||||
QToolButton::ToolButtonPopupMode popMode = SARibbonPannel::getActionToolButtonPopupModeProperty(a);
|
||||
button->setPopupMode(popMode);
|
||||
Qt::ToolButtonStyle buttonStyle = SARibbonPannel::getActionToolButtonStyleProperty(a);
|
||||
button->setToolButtonStyle(buttonStyle);
|
||||
// 根据QAction的属性设置按钮的大小
|
||||
|
||||
connect(button, &SARibbonToolButton::triggered, this, &SARibbonButtonGroupWidget::actionTriggered);
|
||||
w = button;
|
||||
}
|
||||
layout()->addWidget(w);
|
||||
updateGeometry();
|
||||
} break;
|
||||
|
||||
case QEvent::ActionChanged: {
|
||||
// 让布局重新绘制
|
||||
layout()->invalidate();
|
||||
updateGeometry();
|
||||
} break;
|
||||
|
||||
case QEvent::ActionRemoved: {
|
||||
d_ptr->removeAction(e->action());
|
||||
updateGeometry();
|
||||
} break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
QFrame::actionEvent(e);
|
||||
}
|
||||
@@ -0,0 +1,58 @@
|
||||
#ifndef SARIBBONBUTTONGROUPWIDGET_H
|
||||
#define SARIBBONBUTTONGROUPWIDGET_H
|
||||
#include "SARibbonGlobal.h"
|
||||
#include <QToolButton>
|
||||
#include <QMenu>
|
||||
#include <QFrame>
|
||||
class SARibbonControlButton;
|
||||
/**
|
||||
* @brief 用于管理一组Action,类似于QToolBar
|
||||
*/
|
||||
class SA_RIBBON_EXPORT SARibbonButtonGroupWidget : public QFrame
|
||||
{
|
||||
Q_OBJECT
|
||||
SA_RIBBON_DECLARE_PRIVATE(SARibbonButtonGroupWidget)
|
||||
public:
|
||||
using FpButtonIterate = std::function< bool(SARibbonControlButton*) >;
|
||||
|
||||
public:
|
||||
explicit SARibbonButtonGroupWidget(QWidget* parent = nullptr);
|
||||
~SARibbonButtonGroupWidget();
|
||||
|
||||
// 图标尺寸
|
||||
void setIconSize(const QSize& ic);
|
||||
QSize iconSize() const;
|
||||
// 生成并添加一个action
|
||||
QAction* addAction(QAction* a,
|
||||
Qt::ToolButtonStyle buttonStyle = Qt::ToolButtonIconOnly,
|
||||
QToolButton::ToolButtonPopupMode popMode = QToolButton::DelayedPopup);
|
||||
QAction* addAction(const QString& text,
|
||||
const QIcon& icon,
|
||||
Qt::ToolButtonStyle buttonStyle = Qt::ToolButtonIconOnly,
|
||||
QToolButton::ToolButtonPopupMode popMode = QToolButton::DelayedPopup);
|
||||
QAction* addMenu(QMenu* menu,
|
||||
Qt::ToolButtonStyle buttonStyle = Qt::ToolButtonIconOnly,
|
||||
QToolButton::ToolButtonPopupMode popMode = QToolButton::InstantPopup);
|
||||
QAction* addSeparator();
|
||||
QAction* addWidget(QWidget* w);
|
||||
// 从ButtonGroupWidget中把action对应的button提取出来,如果action没有对应的button,就返回nullptr
|
||||
SARibbonControlButton* actionToRibbonControlToolButton(QAction* action);
|
||||
|
||||
QSize sizeHint() const override;
|
||||
QSize minimumSizeHint() const override;
|
||||
|
||||
public:
|
||||
bool iterate(FpButtonIterate fp);
|
||||
Q_SIGNALS:
|
||||
|
||||
/**
|
||||
* @brief 参考QToolBar::actionTriggered的信号
|
||||
* @param action
|
||||
*/
|
||||
void actionTriggered(QAction* action);
|
||||
|
||||
protected:
|
||||
virtual void actionEvent(QActionEvent* e) override;
|
||||
};
|
||||
|
||||
#endif // SARIBBONBUTTONGROUPWIDGET_H
|
||||
@@ -0,0 +1,741 @@
|
||||
#include "SARibbonCategory.h"
|
||||
#include <QList>
|
||||
#include <QResizeEvent>
|
||||
#include <QPainter>
|
||||
#include <QLinearGradient>
|
||||
#include <QDebug>
|
||||
#include <QApplication>
|
||||
#include <QHBoxLayout>
|
||||
#include <QList>
|
||||
#include <QMap>
|
||||
#include <QResizeEvent>
|
||||
#include "SARibbonCategoryLayout.h"
|
||||
#include "SARibbonElementManager.h"
|
||||
|
||||
///
|
||||
/// \brief ribbon页的代理类
|
||||
/// 如果需要修改重绘SARibbonCategory,可以通过设置SARibbonCategory::setProxy
|
||||
///
|
||||
class SARibbonCategory::PrivateData
|
||||
{
|
||||
SA_RIBBON_DECLARE_PUBLIC(SARibbonCategory)
|
||||
public:
|
||||
PrivateData(SARibbonCategory* p);
|
||||
|
||||
SARibbonPannel* addPannel(const QString& title);
|
||||
SARibbonPannel* insertPannel(const QString& title, int index);
|
||||
void addPannel(SARibbonPannel* pannel);
|
||||
void insertPannel(int index, SARibbonPannel* pannel);
|
||||
|
||||
// 把pannel从Category中移除,不会销毁,此时pannel的所有权归还操作者
|
||||
bool takePannel(SARibbonPannel* pannel);
|
||||
|
||||
// 移除Pannel,Category会直接回收SARibbonPannel内存
|
||||
bool removePannel(SARibbonPannel* pannel);
|
||||
SARibbonCategory* ribbonCategory();
|
||||
const SARibbonCategory* ribbonCategory() const;
|
||||
|
||||
// 返回所有的Pannel
|
||||
QList< SARibbonPannel* > pannelList();
|
||||
|
||||
// 更新item的布局,此函数会调用doItemLayout
|
||||
void updateItemGeometry();
|
||||
|
||||
void doWheelEvent(QWheelEvent* event);
|
||||
// 初始化
|
||||
void init(SARibbonCategory* c);
|
||||
|
||||
public:
|
||||
bool mEnableShowPannelTitle { true }; ///< 是否运行pannel的标题栏显示
|
||||
int mPannelTitleHeight { 15 }; ///< pannel的标题栏默认高度
|
||||
bool mIsContextCategory { false }; ///< 标记是否是上下文标签
|
||||
bool mIsCanCustomize { true }; ///< 标记是否可以自定义
|
||||
int mPannelSpacing { 0 }; ///< pannel的spacing
|
||||
QSize mPannelToolButtonSize { 22, 22 }; ///< 记录pannel的默认图标大小
|
||||
SARibbonPannel::PannelLayoutMode mDefaultPannelLayoutMode { SARibbonPannel::ThreeRowMode };
|
||||
};
|
||||
SARibbonCategory::PrivateData::PrivateData(SARibbonCategory* p) : q_ptr(p)
|
||||
{
|
||||
}
|
||||
|
||||
SARibbonPannel* SARibbonCategory::PrivateData::addPannel(const QString& title)
|
||||
{
|
||||
if (SARibbonCategoryLayout* lay = q_ptr->categoryLayout()) {
|
||||
SARibbonPannel* p = insertPannel(title, lay->pannelCount());
|
||||
return p;
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
SARibbonPannel* SARibbonCategory::PrivateData::insertPannel(const QString& title, int index)
|
||||
{
|
||||
SARibbonPannel* pannel = RibbonSubElementFactory->createRibbonPannel(ribbonCategory());
|
||||
|
||||
pannel->setPannelName(title);
|
||||
pannel->setObjectName(title);
|
||||
insertPannel(index, pannel);
|
||||
return (pannel);
|
||||
}
|
||||
|
||||
void SARibbonCategory::PrivateData::addPannel(SARibbonPannel* pannel)
|
||||
{
|
||||
if (SARibbonCategoryLayout* lay = q_ptr->categoryLayout()) {
|
||||
insertPannel(lay->pannelCount(), pannel);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 插入pannel到layout
|
||||
*
|
||||
* 所有的添加操作最终会调用此函数
|
||||
* @param index
|
||||
* @param pannel
|
||||
*/
|
||||
void SARibbonCategory::PrivateData::insertPannel(int index, SARibbonPannel* pannel)
|
||||
{
|
||||
if (nullptr == pannel) {
|
||||
return;
|
||||
}
|
||||
SARibbonCategoryLayout* lay = qobject_cast< SARibbonCategoryLayout* >(q_ptr->layout());
|
||||
if (nullptr == lay) {
|
||||
return;
|
||||
}
|
||||
if (pannel->parentWidget() != q_ptr) {
|
||||
pannel->setParent(q_ptr);
|
||||
}
|
||||
// 同步状态
|
||||
pannel->setEnableShowTitle(mEnableShowPannelTitle);
|
||||
pannel->setTitleHeight(mPannelTitleHeight);
|
||||
pannel->setPannelLayoutMode(mDefaultPannelLayoutMode);
|
||||
pannel->setSpacing(mPannelSpacing);
|
||||
pannel->setToolButtonIconSize(mPannelToolButtonSize);
|
||||
index = qMax(0, index);
|
||||
index = qMin(lay->pannelCount(), index);
|
||||
lay->insertPannel(index, pannel);
|
||||
pannel->setVisible(true);
|
||||
|
||||
QObject::connect(pannel, &SARibbonPannel::actionTriggered, ribbonCategory(), &SARibbonCategory::actionTriggered);
|
||||
}
|
||||
|
||||
bool SARibbonCategory::PrivateData::takePannel(SARibbonPannel* pannel)
|
||||
{
|
||||
SARibbonCategoryLayout* lay = qobject_cast< SARibbonCategoryLayout* >(q_ptr->layout());
|
||||
if (nullptr == lay) {
|
||||
return false;
|
||||
}
|
||||
return lay->takePannel(pannel);
|
||||
}
|
||||
|
||||
bool SARibbonCategory::PrivateData::removePannel(SARibbonPannel* pannel)
|
||||
{
|
||||
if (takePannel(pannel)) {
|
||||
pannel->hide();
|
||||
pannel->deleteLater();
|
||||
return (true);
|
||||
}
|
||||
return (false);
|
||||
}
|
||||
|
||||
QList< SARibbonPannel* > SARibbonCategory::PrivateData::pannelList()
|
||||
{
|
||||
if (SARibbonCategoryLayout* lay = q_ptr->categoryLayout()) {
|
||||
return lay->pannelList();
|
||||
}
|
||||
return QList< SARibbonPannel* >();
|
||||
}
|
||||
|
||||
SARibbonCategory* SARibbonCategory::PrivateData::ribbonCategory()
|
||||
{
|
||||
return (q_ptr);
|
||||
}
|
||||
|
||||
const SARibbonCategory* SARibbonCategory::PrivateData::ribbonCategory() const
|
||||
{
|
||||
return (q_ptr);
|
||||
}
|
||||
|
||||
void SARibbonCategory::PrivateData::updateItemGeometry()
|
||||
{
|
||||
#if SA_DEBUG_PRINT_SIZE_HINT
|
||||
qDebug() << "SARibbonCategory::PrivateData::updateItemGeometry,categoryName=" << q_ptr->categoryName();
|
||||
#endif
|
||||
SARibbonCategoryLayout* lay = qobject_cast< SARibbonCategoryLayout* >(q_ptr->layout());
|
||||
if (!lay) {
|
||||
return;
|
||||
}
|
||||
const QList< SARibbonPannel* > pannels = lay->pannelList();
|
||||
for (auto pannel : pannels) {
|
||||
pannel->updateItemGeometry();
|
||||
}
|
||||
lay->updateGeometryArr();
|
||||
return;
|
||||
}
|
||||
|
||||
void SARibbonCategory::PrivateData::doWheelEvent(QWheelEvent* event)
|
||||
{
|
||||
SARibbonCategoryLayout* lay = q_ptr->categoryLayout();
|
||||
if (nullptr == lay) {
|
||||
return;
|
||||
}
|
||||
QSize contentSize = lay->categoryContentSize();
|
||||
// 求总宽
|
||||
int totalWidth = lay->categoryTotalWidth();
|
||||
|
||||
if (totalWidth > contentSize.width()) {
|
||||
// 这个时候滚动有效
|
||||
int scrollpix = 40;
|
||||
// Qt6 取消了QWheelEvent::delta函数
|
||||
// 是要下面方法可兼容qt5/6
|
||||
QPoint numPixels = event->pixelDelta();
|
||||
QPoint numDegrees = event->angleDelta() / 8;
|
||||
if (!numPixels.isNull()) {
|
||||
if (numDegrees.y() < 0) {
|
||||
scrollpix = -scrollpix;
|
||||
}
|
||||
} else if (!numDegrees.isNull()) {
|
||||
if (numDegrees.y() < 0) {
|
||||
scrollpix = -scrollpix;
|
||||
}
|
||||
}
|
||||
lay->scroll(scrollpix);
|
||||
} else {
|
||||
// 这时候无需处理事件,把滚动事件上发让父级也能接收
|
||||
event->ignore();
|
||||
// 如滚动过就还原
|
||||
if (lay->isScrolled()) {
|
||||
lay->scroll(0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void SARibbonCategory::PrivateData::init(SARibbonCategory* c)
|
||||
{
|
||||
c->setLayout(new SARibbonCategoryLayout(c));
|
||||
c->connect(c, &SARibbonCategory::windowTitleChanged, c, &SARibbonCategory::categoryNameChanged);
|
||||
}
|
||||
|
||||
//----------------------------------------------------
|
||||
// SARibbonCategory
|
||||
//----------------------------------------------------
|
||||
|
||||
SARibbonCategory::SARibbonCategory(QWidget* p) : QFrame(p), d_ptr(new SARibbonCategory::PrivateData(this))
|
||||
{
|
||||
d_ptr->init(this);
|
||||
}
|
||||
|
||||
SARibbonCategory::SARibbonCategory(const QString& name, QWidget* p)
|
||||
: QFrame(p), d_ptr(new SARibbonCategory::PrivateData(this))
|
||||
{
|
||||
setCategoryName(name);
|
||||
d_ptr->init(this);
|
||||
}
|
||||
|
||||
SARibbonCategory::~SARibbonCategory()
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief category的名字,等同windowTitle函数
|
||||
* @return
|
||||
*/
|
||||
QString SARibbonCategory::categoryName() const
|
||||
{
|
||||
return (windowTitle());
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 设置category名字,等同setWindowTitle
|
||||
* @param title
|
||||
*/
|
||||
void SARibbonCategory::setCategoryName(const QString& title)
|
||||
{
|
||||
setWindowTitle(title);
|
||||
}
|
||||
|
||||
bool SARibbonCategory::event(QEvent* e)
|
||||
{
|
||||
#if SA_DEBUG_PRINT_EVENT
|
||||
if (e->type() != QEvent::Paint) {
|
||||
qDebug() << "SARibbonCategory event(" << e->type() << "),name=" << categoryName();
|
||||
}
|
||||
#endif
|
||||
return QWidget::event(e);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief pannel的模式
|
||||
* @return
|
||||
*/
|
||||
SARibbonPannel::PannelLayoutMode SARibbonCategory::pannelLayoutMode() const
|
||||
{
|
||||
return (d_ptr->mDefaultPannelLayoutMode);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 设置pannel的模式
|
||||
*
|
||||
* 在@ref SARibbonBar 调用@ref SARibbonBar::setRibbonStyle 函数时,会对所有的SARibbonCategory调用此函数
|
||||
* 把新的SARibbonPannel::PannelLayoutMode设置进去
|
||||
* @param m
|
||||
*/
|
||||
void SARibbonCategory::setPannelLayoutMode(SARibbonPannel::PannelLayoutMode m)
|
||||
{
|
||||
d_ptr->mDefaultPannelLayoutMode = m;
|
||||
iterate([ m ](SARibbonPannel* p) -> bool {
|
||||
p->setPannelLayoutMode(m);
|
||||
return true;
|
||||
});
|
||||
updateItemGeometry();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 添加pannel
|
||||
*
|
||||
* @note pannel的所有权由SARibbonCategory来管理,请不要在外部对其进行销毁
|
||||
* @param title pannel的标题,在office/wps的三行模式下会显示在pannel的下方
|
||||
* @return 返回生成的@ref SARibbonPannel 指针
|
||||
* @see 对SARibbonPannel的其他操作,参考 @ref SARibbonCategory::takePannel
|
||||
*/
|
||||
SARibbonPannel* SARibbonCategory::addPannel(const QString& title)
|
||||
{
|
||||
return (d_ptr->addPannel(title));
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 添加pannel
|
||||
* @param pannel pannel的所有权SARibbonCategory来管理
|
||||
*/
|
||||
void SARibbonCategory::addPannel(SARibbonPannel* pannel)
|
||||
{
|
||||
d_ptr->addPannel(pannel);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief qt designer专用
|
||||
* @param pannel
|
||||
*/
|
||||
void SARibbonCategory::addPannel(QWidget* pannel)
|
||||
{
|
||||
SARibbonPannel* p = qobject_cast< SARibbonPannel* >(pannel);
|
||||
if (p) {
|
||||
addPannel(p);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 新建一个pannel,并插入到index位置
|
||||
* @param title pannel的title
|
||||
* @param index 插入的位置,如果index超出category里pannel的个数,将插入到最后
|
||||
* @return 返回生成的@ref SARibbonPannel 指针
|
||||
* @note 如果
|
||||
*/
|
||||
SARibbonPannel* SARibbonCategory::insertPannel(const QString& title, int index)
|
||||
{
|
||||
return (d_ptr->insertPannel(title, index));
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 通过名字查找pannel
|
||||
* @param title
|
||||
* @return 如果有重名,只会返回第一个符合条件的
|
||||
*/
|
||||
SARibbonPannel* SARibbonCategory::pannelByName(const QString& title) const
|
||||
{
|
||||
if (SARibbonCategoryLayout* lay = categoryLayout()) {
|
||||
return lay->pannelByName(title);
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 通过ObjectName查找pannel
|
||||
* @param objname
|
||||
* @return
|
||||
*/
|
||||
SARibbonPannel* SARibbonCategory::pannelByObjectName(const QString& objname) const
|
||||
{
|
||||
if (SARibbonCategoryLayout* lay = categoryLayout()) {
|
||||
return lay->pannelByObjectName(objname);
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 通过索引找到pannel,如果超过索引范围,会返回nullptr
|
||||
* @param index
|
||||
* @return 如果超过索引范围,会返回nullptr
|
||||
*/
|
||||
SARibbonPannel* SARibbonCategory::pannelByIndex(int index) const
|
||||
{
|
||||
if (SARibbonCategoryLayout* lay = categoryLayout()) {
|
||||
return lay->pannelByIndex(index);
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 查找pannel对应的索引
|
||||
* @param p
|
||||
* @return 如果找不到,返回-1
|
||||
*/
|
||||
int SARibbonCategory::pannelIndex(SARibbonPannel* p) const
|
||||
{
|
||||
if (SARibbonCategoryLayout* lay = categoryLayout()) {
|
||||
return lay->pannelIndex(p);
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 移动一个Pannel从from index到to index
|
||||
* @param from 要移动pannel的index
|
||||
* @param to 要移动到的位置
|
||||
*/
|
||||
void SARibbonCategory::movePannel(int from, int to)
|
||||
{
|
||||
if (from == to) {
|
||||
return;
|
||||
}
|
||||
if (to < 0) {
|
||||
to = 0;
|
||||
}
|
||||
if (to >= pannelCount()) {
|
||||
to = pannelCount() - 1;
|
||||
}
|
||||
if (SARibbonCategoryLayout* lay = categoryLayout()) {
|
||||
lay->movePannel(from, to);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 把pannel脱离SARibbonCategory的管理
|
||||
* @param pannel 需要提取的pannel
|
||||
* @return 成功返回true,否则返回false
|
||||
*/
|
||||
bool SARibbonCategory::takePannel(SARibbonPannel* pannel)
|
||||
{
|
||||
return (d_ptr->takePannel(pannel));
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 移除Pannel,Category会直接回收SARibbonPannel内存
|
||||
* @param pannel 需要移除的pannel
|
||||
* @note 移除后pannel为野指针,一般操作完建议把pannel指针设置为nullptr
|
||||
*
|
||||
* 此操作等同于:
|
||||
*
|
||||
* @code
|
||||
* SARibbonPannel* pannel;
|
||||
* ...
|
||||
* category->takePannel(pannel);
|
||||
* pannel->hide();
|
||||
* pannel->deleteLater();
|
||||
* @endcode
|
||||
*/
|
||||
bool SARibbonCategory::removePannel(SARibbonPannel* pannel)
|
||||
{
|
||||
return (d_ptr->removePannel(pannel));
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 移除pannel
|
||||
* @param index pannel的索引,如果超出会返回false
|
||||
* @return 成功返回true
|
||||
*/
|
||||
bool SARibbonCategory::removePannel(int index)
|
||||
{
|
||||
SARibbonPannel* p = pannelByIndex(index);
|
||||
|
||||
if (nullptr == p) {
|
||||
return (false);
|
||||
}
|
||||
return (removePannel(p));
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 返回Category下的所有pannel
|
||||
* @return
|
||||
*/
|
||||
QList< SARibbonPannel* > SARibbonCategory::pannelList() const
|
||||
{
|
||||
return (d_ptr->pannelList());
|
||||
}
|
||||
|
||||
QSize SARibbonCategory::sizeHint() const
|
||||
{
|
||||
if (SARibbonCategoryLayout* lay = categoryLayout()) {
|
||||
return lay->sizeHint();
|
||||
}
|
||||
return QSize(1000, 100);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 如果是ContextCategory,此函数返回true
|
||||
* @return
|
||||
*/
|
||||
bool SARibbonCategory::isContextCategory() const
|
||||
{
|
||||
return (d_ptr->mIsContextCategory);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 返回pannel的个数
|
||||
* @return
|
||||
*/
|
||||
int SARibbonCategory::pannelCount() const
|
||||
{
|
||||
if (SARibbonCategoryLayout* lay = categoryLayout()) {
|
||||
return lay->pannelCount();
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 判断是否可以自定义
|
||||
* @return
|
||||
*/
|
||||
bool SARibbonCategory::isCanCustomize() const
|
||||
{
|
||||
return (d_ptr->mIsCanCustomize);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 设置是否可以自定义
|
||||
* @param b
|
||||
*/
|
||||
void SARibbonCategory::setCanCustomize(bool b)
|
||||
{
|
||||
d_ptr->mIsCanCustomize = b;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief pannel标题栏的高度
|
||||
* @return
|
||||
*/
|
||||
int SARibbonCategory::pannelTitleHeight() const
|
||||
{
|
||||
return d_ptr->mPannelTitleHeight;
|
||||
}
|
||||
/**
|
||||
* @brief 设置pannel的高度
|
||||
* @param h
|
||||
*/
|
||||
void SARibbonCategory::setPannelTitleHeight(int h)
|
||||
{
|
||||
d_ptr->mPannelTitleHeight = h;
|
||||
iterate([ h ](SARibbonPannel* p) -> bool {
|
||||
p->setTitleHeight(h);
|
||||
return true;
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 是否pannel显示标题栏
|
||||
* @return
|
||||
*/
|
||||
bool SARibbonCategory::isEnableShowPannelTitle() const
|
||||
{
|
||||
return d_ptr->mEnableShowPannelTitle;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 设置显示pannel标题
|
||||
* @param on
|
||||
*/
|
||||
void SARibbonCategory::setEnableShowPannelTitle(bool on)
|
||||
{
|
||||
d_ptr->mEnableShowPannelTitle = on;
|
||||
iterate([ on ](SARibbonPannel* p) -> bool {
|
||||
p->setEnableShowTitle(on);
|
||||
return true;
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 获取对应的ribbonbar
|
||||
* @return 如果没有加入ribbonbar的管理,此值为null
|
||||
*/
|
||||
SARibbonBar* SARibbonCategory::ribbonBar() const
|
||||
{
|
||||
// 第一个par是stackwidget
|
||||
if (QWidget* par = parentWidget()) {
|
||||
// 理论此时是ribbonbar
|
||||
par = par->parentWidget();
|
||||
while (par) {
|
||||
if (SARibbonBar* ribbon = qobject_cast< SARibbonBar* >(par)) {
|
||||
return ribbon;
|
||||
}
|
||||
par = par->parentWidget();
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 刷新category的布局,适用于改变ribbon的模式之后调用
|
||||
*/
|
||||
void SARibbonCategory::updateItemGeometry()
|
||||
{
|
||||
#if SA_DEBUG_PRINT_SIZE_HINT
|
||||
qDebug() << "SARibbonCategory name=" << categoryName() << " updateItemGeometry";
|
||||
#endif
|
||||
d_ptr->updateItemGeometry();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 此函数会遍历Category下的所有pannel,执行函数指针
|
||||
* @param fp 函数指针返回false则停止迭代
|
||||
* @return 返回false代表没有迭代完所有的category,中途接收到回调函数的false返回而中断迭代
|
||||
*/
|
||||
bool SARibbonCategory::iterate(FpPannelIterate fp)
|
||||
{
|
||||
const QList< SARibbonPannel* > ps = pannelList();
|
||||
for (SARibbonPannel* p : ps) {
|
||||
if (!fp(p)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
@brief 设置Category的对齐方式
|
||||
@param al
|
||||
*/
|
||||
void SARibbonCategory::setCategoryAlignment(SARibbonAlignment al)
|
||||
{
|
||||
SARibbonCategoryLayout* lay = qobject_cast< SARibbonCategoryLayout* >(layout());
|
||||
if (lay) {
|
||||
lay->setCategoryAlignment(al);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@brief Category的对齐方式
|
||||
@return
|
||||
*/
|
||||
SARibbonAlignment SARibbonCategory::categoryAlignment() const
|
||||
{
|
||||
SARibbonCategoryLayout* lay = qobject_cast< SARibbonCategoryLayout* >(layout());
|
||||
if (lay) {
|
||||
return lay->categoryAlignment();
|
||||
}
|
||||
return SARibbonAlignment::AlignLeft;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 设置pannel的spacing
|
||||
* @param n
|
||||
*/
|
||||
void SARibbonCategory::setPannelSpacing(int n)
|
||||
{
|
||||
d_ptr->mPannelSpacing = n;
|
||||
iterate([ n ](SARibbonPannel* pannel) -> bool {
|
||||
if (pannel) {
|
||||
pannel->setSpacing(n);
|
||||
}
|
||||
return true;
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief pannel的spacing
|
||||
* @return
|
||||
*/
|
||||
int SARibbonCategory::pannelSpacing() const
|
||||
{
|
||||
return d_ptr->mPannelSpacing;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 设置pannel按钮的icon尺寸,large action不受此尺寸影响
|
||||
* @param s
|
||||
*/
|
||||
void SARibbonCategory::setPannelToolButtonIconSize(const QSize& s)
|
||||
{
|
||||
d_ptr->mPannelToolButtonSize = s;
|
||||
iterate([ s ](SARibbonPannel* pannel) -> bool {
|
||||
if (pannel) {
|
||||
pannel->setToolButtonIconSize(s);
|
||||
}
|
||||
return true;
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief pannel按钮的icon尺寸,large action不受此尺寸影响
|
||||
* @return
|
||||
*/
|
||||
QSize SARibbonCategory::pannelToolButtonIconSize() const
|
||||
{
|
||||
return d_ptr->mPannelToolButtonSize;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 在超出边界情况下,滚轮可滚动pannel
|
||||
* @param event
|
||||
*/
|
||||
void SARibbonCategory::wheelEvent(QWheelEvent* event)
|
||||
{
|
||||
d_ptr->doWheelEvent(event);
|
||||
}
|
||||
|
||||
void SARibbonCategory::changeEvent(QEvent* event)
|
||||
{
|
||||
switch (event->type()) {
|
||||
case QEvent::StyleChange: {
|
||||
if (layout()) {
|
||||
#if SA_DEBUG_PRINT_SIZE_HINT
|
||||
qDebug() << "SARibbonCategory changeEvent(StyleChange),categoryName=" << categoryName();
|
||||
#endif
|
||||
layout()->invalidate();
|
||||
}
|
||||
} break;
|
||||
case QEvent::FontChange: {
|
||||
#if SA_DEBUG_PRINT_SIZE_HINT
|
||||
qDebug() << "SARibbonCategory changeEvent(FontChange),categoryName=" << categoryName();
|
||||
#endif
|
||||
QFont f = font();
|
||||
iterate([ f ](SARibbonPannel* p) -> bool {
|
||||
p->setFont(f);
|
||||
return true;
|
||||
});
|
||||
if (layout()) {
|
||||
layout()->invalidate();
|
||||
}
|
||||
} break;
|
||||
default:
|
||||
break;
|
||||
};
|
||||
return QWidget::changeEvent(event);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 标记这个是上下文标签
|
||||
* @param isContextCategory
|
||||
*/
|
||||
void SARibbonCategory::markIsContextCategory(bool isContextCategory)
|
||||
{
|
||||
d_ptr->mIsContextCategory = isContextCategory;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 获取SARibbonCategoryLayoutlayout
|
||||
* @return
|
||||
*/
|
||||
SARibbonCategoryLayout* SARibbonCategory::categoryLayout() const
|
||||
{
|
||||
return qobject_cast< SARibbonCategoryLayout* >(layout());
|
||||
}
|
||||
|
||||
//===================================================
|
||||
// SARibbonCategoryScrollButton
|
||||
//===================================================
|
||||
SARibbonCategoryScrollButton::SARibbonCategoryScrollButton(Qt::ArrowType arr, QWidget* p) : QToolButton(p)
|
||||
{
|
||||
setArrowType(arr);
|
||||
}
|
||||
|
||||
SARibbonCategoryScrollButton::~SARibbonCategoryScrollButton()
|
||||
{
|
||||
}
|
||||
@@ -0,0 +1,164 @@
|
||||
#ifndef SARIBBONCATEGORY_H
|
||||
#define SARIBBONCATEGORY_H
|
||||
#include "SARibbonGlobal.h"
|
||||
#include <QFrame>
|
||||
#include "SARibbonPannel.h"
|
||||
#include <QScopedPointer>
|
||||
#include <QPushButton>
|
||||
#include <QWheelEvent>
|
||||
|
||||
class QAction;
|
||||
class QHBoxLayout;
|
||||
class QWheelEvent;
|
||||
class SARibbonBar;
|
||||
class SARibbonCategoryLayout;
|
||||
/**
|
||||
* @brief 一项ribbon tab页
|
||||
* @note SARibbonCategory的windowTitle影响了其在SARibbonBar的标签显示,
|
||||
* 如果要改标签名字,直接调用SARibbonCategory的setWindowTitle函数
|
||||
*/
|
||||
class SA_RIBBON_EXPORT SARibbonCategory : public QFrame
|
||||
{
|
||||
Q_OBJECT
|
||||
SA_RIBBON_DECLARE_PRIVATE(SARibbonCategory)
|
||||
friend class SARibbonBar;
|
||||
friend class SARibbonContextCategory;
|
||||
Q_PROPERTY(bool isCanCustomize READ isCanCustomize WRITE setCanCustomize)
|
||||
Q_PROPERTY(QString categoryName READ categoryName WRITE setCategoryName)
|
||||
public:
|
||||
using FpPannelIterate = std::function< bool(SARibbonPannel*) >;
|
||||
|
||||
public:
|
||||
explicit SARibbonCategory(QWidget* p = nullptr);
|
||||
explicit SARibbonCategory(const QString& name, QWidget* p = nullptr);
|
||||
~SARibbonCategory();
|
||||
|
||||
// category的名字
|
||||
QString categoryName() const;
|
||||
|
||||
// 设置category名字,等同setWindowTitle
|
||||
void setCategoryName(const QString& title);
|
||||
|
||||
// 设置pannel的模式
|
||||
SARibbonPannel::PannelLayoutMode pannelLayoutMode() const;
|
||||
void setPannelLayoutMode(SARibbonPannel::PannelLayoutMode m);
|
||||
|
||||
// 添加pannel
|
||||
SARibbonPannel* addPannel(const QString& title);
|
||||
|
||||
// 添加pannel
|
||||
void addPannel(SARibbonPannel* pannel);
|
||||
|
||||
// qt designer专用
|
||||
Q_INVOKABLE void addPannel(QWidget* pannel);
|
||||
|
||||
// 插入pannel
|
||||
SARibbonPannel* insertPannel(const QString& title, int index);
|
||||
|
||||
// 通过名字查找pannel
|
||||
SARibbonPannel* pannelByName(const QString& title) const;
|
||||
|
||||
// 通过ObjectName查找pannel
|
||||
SARibbonPannel* pannelByObjectName(const QString& objname) const;
|
||||
|
||||
// 通过索引找到pannel,如果超过索引范围,会返回nullptr
|
||||
SARibbonPannel* pannelByIndex(int index) const;
|
||||
|
||||
// 查找pannel的index
|
||||
int pannelIndex(SARibbonPannel* p) const;
|
||||
|
||||
// 移动一个Pannel从from index到to index
|
||||
void movePannel(int from, int to);
|
||||
|
||||
// 把pannel从Category中移除,不会销毁,此时pannel的所有权归还操作者
|
||||
bool takePannel(SARibbonPannel* pannel);
|
||||
|
||||
// 移除Pannel,Category会直接回收SARibbonPannel内存
|
||||
bool removePannel(SARibbonPannel* pannel);
|
||||
bool removePannel(int index);
|
||||
|
||||
// 返回所有的Pannel
|
||||
QList< SARibbonPannel* > pannelList() const;
|
||||
|
||||
//
|
||||
QSize sizeHint() const Q_DECL_OVERRIDE;
|
||||
|
||||
// 如果是ContextCategory,此函数返回true
|
||||
bool isContextCategory() const;
|
||||
|
||||
// pannel的个数
|
||||
int pannelCount() const;
|
||||
|
||||
// 判断是否可以自定义
|
||||
bool isCanCustomize() const;
|
||||
void setCanCustomize(bool b);
|
||||
|
||||
// 设置pannel的标题栏高度
|
||||
int pannelTitleHeight() const;
|
||||
void setPannelTitleHeight(int h);
|
||||
|
||||
// 设置pannel是否显示标题栏
|
||||
bool isEnableShowPannelTitle() const;
|
||||
void setEnableShowPannelTitle(bool on);
|
||||
|
||||
// 设置Category的对齐方式
|
||||
void setCategoryAlignment(SARibbonAlignment al);
|
||||
SARibbonAlignment categoryAlignment() const;
|
||||
|
||||
// 设置pannel的spacing
|
||||
void setPannelSpacing(int n);
|
||||
int pannelSpacing() const;
|
||||
|
||||
// 设置pannel按钮的icon尺寸,large action不受此尺寸影响
|
||||
void setPannelToolButtonIconSize(const QSize& s);
|
||||
QSize pannelToolButtonIconSize() const;
|
||||
|
||||
// 获取对应的ribbonbar,如果没有加入ribbonbar的管理,此值为null
|
||||
SARibbonBar* ribbonBar() const;
|
||||
|
||||
// 刷新category的尺寸布局
|
||||
void updateItemGeometry();
|
||||
|
||||
// 此函数会遍历Category下的所有pannel,执行函数指针,函数指针返回false则停止迭代
|
||||
bool iterate(FpPannelIterate fp);
|
||||
Q_SIGNALS:
|
||||
/**
|
||||
* @brief category标题发生了改变信号
|
||||
* @param n
|
||||
*/
|
||||
void categoryNameChanged(const QString& n);
|
||||
|
||||
/**
|
||||
* @brief 参考QToolBar::actionTriggered的信号
|
||||
* @param action
|
||||
*/
|
||||
void actionTriggered(QAction* action);
|
||||
|
||||
protected:
|
||||
virtual bool event(QEvent* e) override;
|
||||
// 处理滚轮事件
|
||||
void wheelEvent(QWheelEvent* event) override;
|
||||
//
|
||||
void changeEvent(QEvent* event) override;
|
||||
|
||||
// 标记这个是上下文标签
|
||||
void markIsContextCategory(bool isContextCategory = true);
|
||||
|
||||
// 获取SARibbonCategoryLayoutlayout
|
||||
SARibbonCategoryLayout* categoryLayout() const;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief SARibbonCategory无法完全显示时,显示的调整按钮
|
||||
*
|
||||
* 重新定义是为了防止被外部的样式影响,同时可以使用SARibbonCategoryScrollButton的样式定义
|
||||
*/
|
||||
class SA_RIBBON_EXPORT SARibbonCategoryScrollButton : public QToolButton
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit SARibbonCategoryScrollButton(Qt::ArrowType arr, QWidget* p = nullptr);
|
||||
~SARibbonCategoryScrollButton();
|
||||
};
|
||||
|
||||
#endif // SARIBBONCATEGORY_H
|
||||
@@ -0,0 +1,723 @@
|
||||
#include "SARibbonCategoryLayout.h"
|
||||
#include <QLayoutItem>
|
||||
#include "SARibbonPannel.h"
|
||||
#include "SARibbonElementManager.h"
|
||||
#include "SARibbonSeparatorWidget.h"
|
||||
#include <QApplication>
|
||||
#include <QDebug>
|
||||
|
||||
#ifndef SARibbonCategoryLayout_DEBUG_PRINT
|
||||
#define SARibbonCategoryLayout_DEBUG_PRINT 1
|
||||
#endif
|
||||
/**
|
||||
* @brief The SARibbonCategoryLayoutPrivate class
|
||||
*/
|
||||
class SARibbonCategoryLayout::PrivateData
|
||||
{
|
||||
SA_RIBBON_DECLARE_PUBLIC(SARibbonCategoryLayout)
|
||||
public:
|
||||
PrivateData(SARibbonCategoryLayout* p);
|
||||
// 计算所有元素的sizehint总宽度
|
||||
int totalSizeHintWidth() const;
|
||||
|
||||
public:
|
||||
bool mDirty { true };
|
||||
bool mIsRightScrollBtnShow { false }; ///< 标记右滚动按钮是否需要显示
|
||||
bool mIsLeftScrollBtnShow { false }; ///< 标记左滚动按钮是否需要显示
|
||||
SARibbonCategoryScrollButton* mLeftScrollBtn { nullptr }; ///< 在区域无法显示时显示的按钮
|
||||
SARibbonCategoryScrollButton* mRightScrollBtn { nullptr }; ///< 在区域无法显示时显示的按钮
|
||||
int mTotalWidth { 0 };
|
||||
int mXBase { 0 };
|
||||
QSize mSizeHint;
|
||||
QSize mMinSizeHint;
|
||||
QList< SARibbonCategoryLayoutItem* > mItemList;
|
||||
SARibbonAlignment mCategoryAlignment { SARibbonAlignment::AlignLeft }; ///< 对齐方式
|
||||
};
|
||||
|
||||
//=============================================================
|
||||
// SARibbonCategoryLayoutPrivate
|
||||
//=============================================================
|
||||
|
||||
SARibbonCategoryLayout::PrivateData::PrivateData(SARibbonCategoryLayout* p) : q_ptr(p)
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 计算所有元素的SizeHint宽度总和
|
||||
* @return
|
||||
*/
|
||||
int SARibbonCategoryLayout::PrivateData::totalSizeHintWidth() const
|
||||
{
|
||||
int total = 0;
|
||||
QMargins mag = q_ptr->contentsMargins();
|
||||
#if SA_DEBUG_PRINT_SIZE_HINT
|
||||
int debug_i__ = 0;
|
||||
QString debug_totalSizeHintWidth__;
|
||||
#endif
|
||||
if (!mag.isNull()) {
|
||||
total += (mag.left() + mag.right());
|
||||
}
|
||||
// 先计算总长
|
||||
for (SARibbonCategoryLayoutItem* item : qAsConst(mItemList)) {
|
||||
if (item->isEmpty()) {
|
||||
// 如果是hide就直接跳过
|
||||
#if SARibbonCategoryLayout_DEBUG_PRINT && SA_DEBUG_PRINT_SIZE_HINT
|
||||
++debug_i__;
|
||||
debug_totalSizeHintWidth__ += QString(" [%1](%2)is empty skip\n")
|
||||
.arg(debug_i__)
|
||||
.arg(item->toPannelWidget()->pannelName());
|
||||
#endif
|
||||
continue;
|
||||
}
|
||||
// 这里要使用widget()->sizeHint(),因为pannel的标题会影总体布局,此处需要修改
|
||||
// TODO
|
||||
QSize pannelSize = item->widget()->sizeHint();
|
||||
QSize SeparatorSize(0, 0);
|
||||
if (item->separatorWidget) {
|
||||
SeparatorSize = item->separatorWidget->sizeHint();
|
||||
}
|
||||
total += pannelSize.width();
|
||||
total += SeparatorSize.width();
|
||||
#if SARibbonCategoryLayout_DEBUG_PRINT && SA_DEBUG_PRINT_SIZE_HINT
|
||||
++debug_i__;
|
||||
debug_totalSizeHintWidth__ += QString("|-[%1]pannelSize=(%2,%3),SeparatorSize=(%4,%5),name=(%6) \n")
|
||||
.arg(debug_i__)
|
||||
.arg(pannelSize.width())
|
||||
.arg(pannelSize.height())
|
||||
.arg(SeparatorSize.width())
|
||||
.arg(SeparatorSize.height())
|
||||
.arg(item->toPannelWidget()->pannelName());
|
||||
#endif
|
||||
}
|
||||
#if SARibbonCategoryLayout_DEBUG_PRINT && SA_DEBUG_PRINT_SIZE_HINT
|
||||
qDebug() << "SARibbonCategoryLayout.totalSizeHintWidth=" << total;
|
||||
qDebug().noquote() << debug_totalSizeHintWidth__;
|
||||
#endif
|
||||
return (total);
|
||||
}
|
||||
|
||||
//=============================================================
|
||||
// SARibbonCategoryLayout
|
||||
//=============================================================
|
||||
|
||||
SARibbonCategoryLayout::SARibbonCategoryLayout(SARibbonCategory* parent)
|
||||
: QLayout(parent), d_ptr(new SARibbonCategoryLayout::PrivateData(this))
|
||||
{
|
||||
setContentsMargins(1, 1, 1, 1);
|
||||
d_ptr->mLeftScrollBtn = new SARibbonCategoryScrollButton(Qt::LeftArrow, parent);
|
||||
d_ptr->mRightScrollBtn = new SARibbonCategoryScrollButton(Qt::RightArrow, parent);
|
||||
d_ptr->mLeftScrollBtn->setVisible(false);
|
||||
d_ptr->mRightScrollBtn->setVisible(false);
|
||||
connect(d_ptr->mLeftScrollBtn, &QToolButton::clicked, this, &SARibbonCategoryLayout::onLeftScrollButtonClicked);
|
||||
connect(d_ptr->mRightScrollBtn, &QToolButton::clicked, this, &SARibbonCategoryLayout::onRightScrollButtonClicked);
|
||||
}
|
||||
|
||||
SARibbonCategoryLayout::~SARibbonCategoryLayout()
|
||||
{
|
||||
while (auto item = takePannelItem(0)) {
|
||||
delete item;
|
||||
}
|
||||
}
|
||||
|
||||
SARibbonCategory* SARibbonCategoryLayout::ribbonCategory() const
|
||||
{
|
||||
return (qobject_cast< SARibbonCategory* >(parentWidget()));
|
||||
}
|
||||
|
||||
void SARibbonCategoryLayout::addItem(QLayoutItem* item)
|
||||
{
|
||||
Q_UNUSED(item);
|
||||
qWarning() << tr("in SARibbonCategoryLayout cannot addItem,use addPannel instead");
|
||||
invalidate();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 返回pannel的layout
|
||||
* @param index 索引
|
||||
* @return
|
||||
* @note 注意,pannel是和分割线一起的,但这个只返回一个pannel对应的layout
|
||||
*/
|
||||
QLayoutItem* SARibbonCategoryLayout::itemAt(int index) const
|
||||
{
|
||||
SARibbonCategoryLayoutItem* item = d_ptr->mItemList.value(index, nullptr);
|
||||
|
||||
return (item);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 提取layout
|
||||
* @param index
|
||||
* @return
|
||||
*/
|
||||
QLayoutItem* SARibbonCategoryLayout::takeAt(int index)
|
||||
{
|
||||
QLayoutItem* r = takePannelItem(index);
|
||||
invalidate();
|
||||
return r;
|
||||
}
|
||||
|
||||
SARibbonCategoryLayoutItem* SARibbonCategoryLayout::takePannelItem(int index)
|
||||
{
|
||||
if ((index >= 0) && (index < d_ptr->mItemList.size())) {
|
||||
SARibbonCategoryLayoutItem* item = d_ptr->mItemList.takeAt(index);
|
||||
if (item->widget()) {
|
||||
item->widget()->hide();
|
||||
}
|
||||
if (item->separatorWidget) {
|
||||
item->separatorWidget->hide();
|
||||
}
|
||||
return (item);
|
||||
}
|
||||
return (nullptr);
|
||||
}
|
||||
|
||||
SARibbonCategoryLayoutItem* SARibbonCategoryLayout::takePannelItem(SARibbonPannel* pannel)
|
||||
{
|
||||
for (int i = 0; i < d_ptr->mItemList.size(); ++i) {
|
||||
SARibbonCategoryLayoutItem* item = d_ptr->mItemList[ i ];
|
||||
if (item->widget() == pannel) {
|
||||
return (takePannelItem(i));
|
||||
}
|
||||
}
|
||||
return (nullptr);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 移除pannel,对应的分割线也会删除
|
||||
* @param pannel
|
||||
* @return
|
||||
*/
|
||||
bool SARibbonCategoryLayout::takePannel(SARibbonPannel* pannel)
|
||||
{
|
||||
SARibbonCategoryLayoutItem* i = takePannelItem(pannel);
|
||||
if (i) {
|
||||
SARibbonSeparatorWidget* sp = i->separatorWidget;
|
||||
if (sp) {
|
||||
sp->deleteLater();
|
||||
}
|
||||
delete i;
|
||||
invalidate();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
int SARibbonCategoryLayout::count() const
|
||||
{
|
||||
return (d_ptr->mItemList.size());
|
||||
}
|
||||
|
||||
void SARibbonCategoryLayout::addPannel(SARibbonPannel* pannel)
|
||||
{
|
||||
insertPannel(d_ptr->mItemList.count(), pannel);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 插入一个pannel
|
||||
* @param index 索引
|
||||
* @param pannel
|
||||
* @return 返回对应的分割线SARibbonSeparatorWidget
|
||||
* @note 在SARibbonCategoryLayout的布局中,一个pannel会携带一个分割线
|
||||
*/
|
||||
void SARibbonCategoryLayout::insertPannel(int index, SARibbonPannel* pannel)
|
||||
{
|
||||
index = qMax(0, index);
|
||||
index = qMin(d_ptr->mItemList.count(), index);
|
||||
SARibbonCategoryLayoutItem* item = new SARibbonCategoryLayoutItem(pannel);
|
||||
|
||||
// 分割线
|
||||
item->separatorWidget = RibbonSubElementFactory->createRibbonSeparatorWidget(parentWidget());
|
||||
// 插入list中
|
||||
d_ptr->mItemList.insert(index, item);
|
||||
// 标记需要重新计算尺寸
|
||||
invalidate();
|
||||
}
|
||||
|
||||
QSize SARibbonCategoryLayout::sizeHint() const
|
||||
{
|
||||
if (d_ptr->mSizeHint.isNull()) {
|
||||
SARibbonCategoryLayout* that = const_cast< SARibbonCategoryLayout* >(this);
|
||||
that->updateGeometryArr();
|
||||
}
|
||||
return (d_ptr->mSizeHint);
|
||||
}
|
||||
|
||||
QSize SARibbonCategoryLayout::minimumSize() const
|
||||
{
|
||||
if (d_ptr->mMinSizeHint.isNull()) {
|
||||
SARibbonCategoryLayout* that = const_cast< SARibbonCategoryLayout* >(this);
|
||||
that->updateGeometryArr();
|
||||
}
|
||||
return (d_ptr->mMinSizeHint);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief SARibbonCategory充满整个stacked widget
|
||||
* @return
|
||||
*/
|
||||
Qt::Orientations SARibbonCategoryLayout::expandingDirections() const
|
||||
{
|
||||
return (Qt::Horizontal | Qt::Vertical);
|
||||
}
|
||||
|
||||
void SARibbonCategoryLayout::invalidate()
|
||||
{
|
||||
d_ptr->mDirty = true;
|
||||
QLayout::invalidate();
|
||||
}
|
||||
/**
|
||||
* @brief category的内容尺寸(把margins减去)
|
||||
* @return
|
||||
*/
|
||||
QSize SARibbonCategoryLayout::categoryContentSize() const
|
||||
{
|
||||
SARibbonCategory* category = ribbonCategory();
|
||||
QSize s = category->size();
|
||||
QMargins mag = contentsMargins();
|
||||
if (!mag.isNull()) {
|
||||
s.rheight() -= (mag.top() + mag.bottom());
|
||||
s.rwidth() -= (mag.right() + mag.left());
|
||||
}
|
||||
return (s);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 更新尺寸
|
||||
*/
|
||||
void SARibbonCategoryLayout::updateGeometryArr()
|
||||
{
|
||||
SARibbonCategory* category = ribbonCategory();
|
||||
if (nullptr == category) {
|
||||
return;
|
||||
}
|
||||
int categoryWidth = category->width();
|
||||
QMargins mag = contentsMargins();
|
||||
int height = category->height();
|
||||
int y = 0;
|
||||
|
||||
if (!mag.isNull()) {
|
||||
y = mag.top();
|
||||
height -= (mag.top() + mag.bottom());
|
||||
// categoryWidth不能把mag减去,减去后会导致categoryWidth不是实际的categoryWidth
|
||||
// categoryWidth -= (mag.right() + mag.left());
|
||||
}
|
||||
// total 是总宽,不是x坐标系,x才是坐标系
|
||||
int total = d_ptr->totalSizeHintWidth();
|
||||
|
||||
// 扩展的宽度
|
||||
int expandWidth = 0;
|
||||
|
||||
// 如果total < categoryWidth,m_d->mXBase可以设置为0
|
||||
// 判断是否超过总长度
|
||||
#if SARibbonCategoryLayout_DEBUG_PRINT && SA_DEBUG_PRINT_SIZE_HINT
|
||||
qDebug() << "SARibbonCategoryLayout::updateGeometryArr"
|
||||
<< "\n|-category name=" << category->categoryName() //
|
||||
<< "\n|-category height=" << height //
|
||||
<< "\n|-totalSizeHintWidth=" << total //
|
||||
<< "\n|-y=" << y //
|
||||
<< "\n|-expandWidth:" << expandWidth //
|
||||
<< "\n|-mag=" << mag;
|
||||
#endif
|
||||
if (total > categoryWidth) {
|
||||
// 超过总长度,需要显示滚动按钮
|
||||
if (0 == d_ptr->mXBase) {
|
||||
// 已经移动到最左,需要可以向右移动
|
||||
d_ptr->mIsRightScrollBtnShow = true;
|
||||
d_ptr->mIsLeftScrollBtnShow = false;
|
||||
} else if (d_ptr->mXBase <= (categoryWidth - total)) {
|
||||
// 已经移动到最右,需要可以向左移动
|
||||
d_ptr->mIsRightScrollBtnShow = false;
|
||||
d_ptr->mIsLeftScrollBtnShow = true;
|
||||
} else {
|
||||
// 移动到中间两边都可以动
|
||||
d_ptr->mIsRightScrollBtnShow = true;
|
||||
d_ptr->mIsLeftScrollBtnShow = true;
|
||||
}
|
||||
} else {
|
||||
// 说明total 小于 categoryWidth
|
||||
// 记录可以扩展的数量
|
||||
int canExpandingCount = 0;
|
||||
d_ptr->mIsRightScrollBtnShow = false;
|
||||
d_ptr->mIsLeftScrollBtnShow = false;
|
||||
// 这个是避免一开始totalWidth > categorySize.width(),通过滚动按钮调整了m_d->mBaseX
|
||||
// 随之调整了窗体尺寸,调整后totalWidth < categorySize.width()导致category在原来位置
|
||||
// 无法显示,必须这里把mBaseX设置为0
|
||||
|
||||
d_ptr->mXBase = 0;
|
||||
//
|
||||
|
||||
for (SARibbonCategoryLayoutItem* item : qAsConst(d_ptr->mItemList)) {
|
||||
if (SARibbonPannel* p = qobject_cast< SARibbonPannel* >(item->widget())) {
|
||||
if (p->isExpanding()) {
|
||||
// pannel可扩展
|
||||
++canExpandingCount;
|
||||
}
|
||||
}
|
||||
}
|
||||
// 计算可扩展的宽度
|
||||
if (canExpandingCount > 0) {
|
||||
expandWidth = (categoryWidth - total) / canExpandingCount;
|
||||
} else {
|
||||
expandWidth = 0;
|
||||
}
|
||||
}
|
||||
int x = d_ptr->mXBase;
|
||||
if ((categoryAlignment() == SARibbonAlignment::AlignCenter) && (total < categoryWidth) && (0 == expandWidth)) {
|
||||
// 如果是居中对齐,同时没有伸缩的pannel,同时总宽度没有超过category的宽度
|
||||
x = (categoryWidth - total) / 2;
|
||||
}
|
||||
total = 0; // total重新计算
|
||||
// 先按照sizeHint设置所有的尺寸
|
||||
for (SARibbonCategoryLayoutItem* item : qAsConst(d_ptr->mItemList)) {
|
||||
if (item->isEmpty()) {
|
||||
// 如果是hide就直接跳过
|
||||
if (item->separatorWidget) {
|
||||
// pannel hide分割线也要hide
|
||||
item->separatorWidget->hide();
|
||||
}
|
||||
item->mWillSetGeometry = QRect(0, 0, 0, 0);
|
||||
item->mWillSetSeparatorGeometry = QRect(0, 0, 0, 0);
|
||||
continue;
|
||||
}
|
||||
SARibbonPannel* p = item->toPannelWidget();
|
||||
if (nullptr == p) {
|
||||
qDebug() << "unknow widget in SARibbonCategoryLayout";
|
||||
continue;
|
||||
}
|
||||
// p->layout()->update();
|
||||
QSize pannelSize = p->sizeHint();
|
||||
QSize SeparatorSize(0, 0);
|
||||
if (item->separatorWidget) {
|
||||
SeparatorSize = item->separatorWidget->sizeHint();
|
||||
}
|
||||
if (p->isExpanding()) {
|
||||
// 可扩展,就把pannel扩展到最大
|
||||
pannelSize.setWidth(pannelSize.width() + expandWidth);
|
||||
}
|
||||
int w = pannelSize.width();
|
||||
|
||||
item->mWillSetGeometry = QRect(x, y, w, height);
|
||||
x += w;
|
||||
total += w;
|
||||
w = SeparatorSize.width();
|
||||
item->mWillSetSeparatorGeometry = QRect(x, y, w, height);
|
||||
x += w;
|
||||
total += w;
|
||||
}
|
||||
d_ptr->mTotalWidth = total;
|
||||
d_ptr->mSizeHint = QSize(d_ptr->mTotalWidth, height);
|
||||
d_ptr->mMinSizeHint = QSize(categoryWidth, height);
|
||||
#if SARibbonCategoryLayout_DEBUG_PRINT && SA_DEBUG_PRINT_SIZE_HINT
|
||||
qDebug() << "SARibbonCategoryLayout updateGeometryArr,SizeHint=" << d_ptr->mSizeHint
|
||||
<< ",Category name=" << category->categoryName();
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 执行layout调整
|
||||
*/
|
||||
void SARibbonCategoryLayout::doLayout()
|
||||
{
|
||||
if (d_ptr->mDirty) {
|
||||
updateGeometryArr();
|
||||
}
|
||||
SARibbonCategory* category = ribbonCategory();
|
||||
// 两个滚动按钮的位置永远不变
|
||||
d_ptr->mLeftScrollBtn->setGeometry(0, 0, 12, category->height());
|
||||
d_ptr->mRightScrollBtn->setGeometry(category->width() - 12, 0, 12, category->height());
|
||||
QList< QWidget* > showWidgets, hideWidgets;
|
||||
#if SARibbonCategoryLayout_DEBUG_PRINT && SA_DEBUG_PRINT_SIZE_HINT
|
||||
int debug_i__(0);
|
||||
qDebug() << "SARibbonCategoryLayout::doLayout(),name=" << category->categoryName();
|
||||
#endif
|
||||
for (SARibbonCategoryLayoutItem* item : qAsConst(d_ptr->mItemList)) {
|
||||
if (item->isEmpty()) {
|
||||
hideWidgets << item->widget();
|
||||
if (item->separatorWidget) {
|
||||
hideWidgets << item->separatorWidget;
|
||||
}
|
||||
#if SARibbonCategoryLayout_DEBUG_PRINT && SA_DEBUG_PRINT_SIZE_HINT
|
||||
qDebug() << "|-[" << debug_i__ << "]pannelName(" << item->toPannelWidget()->pannelName() << ",will hide";
|
||||
++debug_i__;
|
||||
#endif
|
||||
} else {
|
||||
//! 这里不能用item->setGeometry(item->mWillSetGeometry);这样会得到一个很奇怪的显示效果
|
||||
//! 就是窗口的最左边不会移出去,而是把最右边压缩,
|
||||
item->widget()->setGeometry(item->mWillSetGeometry);
|
||||
// item->widget()->setFixedSize(item->mWillSetGeometry.size());
|
||||
// item->widget()->move(item->mWillSetGeometry.topLeft());
|
||||
// item->setGeometry(item->mWillSetGeometry);
|
||||
showWidgets << item->widget();
|
||||
if (item->separatorWidget) {
|
||||
item->separatorWidget->setGeometry(item->mWillSetSeparatorGeometry);
|
||||
showWidgets << item->separatorWidget;
|
||||
}
|
||||
#if SARibbonCategoryLayout_DEBUG_PRINT && SA_DEBUG_PRINT_SIZE_HINT
|
||||
qDebug() << "|-[" << debug_i__ << "]pannelName(" << item->toPannelWidget()->pannelName()
|
||||
<< "),willSetGeometry:" << item->mWillSetGeometry
|
||||
<< ",WillSetSeparatorGeometry:" << item->mWillSetSeparatorGeometry;
|
||||
++debug_i__;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
d_ptr->mRightScrollBtn->setVisible(d_ptr->mIsRightScrollBtnShow);
|
||||
d_ptr->mLeftScrollBtn->setVisible(d_ptr->mIsLeftScrollBtnShow);
|
||||
if (d_ptr->mIsRightScrollBtnShow) {
|
||||
d_ptr->mRightScrollBtn->raise();
|
||||
}
|
||||
if (d_ptr->mIsLeftScrollBtnShow) {
|
||||
d_ptr->mLeftScrollBtn->raise();
|
||||
}
|
||||
// 不在上面那里进行show和hide因为这会触发SARibbonPannelLayout的重绘,导致循环绘制,非常影响效率
|
||||
for (QWidget* w : qAsConst(showWidgets)) {
|
||||
if (!w->isVisible()) {
|
||||
w->show();
|
||||
}
|
||||
}
|
||||
for (QWidget* w : qAsConst(hideWidgets)) {
|
||||
if (w->isVisible()) {
|
||||
w->hide();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 返回所有pannels
|
||||
* @return
|
||||
*/
|
||||
QList< SARibbonPannel* > SARibbonCategoryLayout::pannels() const
|
||||
{
|
||||
QList< SARibbonPannel* > res;
|
||||
|
||||
for (SARibbonCategoryLayoutItem* item : qAsConst(d_ptr->mItemList)) {
|
||||
SARibbonPannel* p = item->toPannelWidget();
|
||||
res.append(p);
|
||||
}
|
||||
return (res);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 通过ObjectName查找pannel
|
||||
* @param objname
|
||||
* @return
|
||||
*/
|
||||
SARibbonPannel* SARibbonCategoryLayout::pannelByObjectName(const QString& objname) const
|
||||
{
|
||||
for (SARibbonCategoryLayoutItem* item : d_ptr->mItemList) {
|
||||
if (SARibbonPannel* pannel = item->toPannelWidget()) {
|
||||
if (pannel->objectName() == objname) {
|
||||
return pannel;
|
||||
}
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 通过名字查找pannel
|
||||
* @param title
|
||||
* @return 如果有重名,只会返回第一个符合条件的
|
||||
*/
|
||||
SARibbonPannel* SARibbonCategoryLayout::pannelByName(const QString& pannelname) const
|
||||
{
|
||||
for (SARibbonCategoryLayoutItem* item : qAsConst(d_ptr->mItemList)) {
|
||||
if (SARibbonPannel* pannel = item->toPannelWidget()) {
|
||||
if (pannel->pannelName() == pannelname) {
|
||||
return (pannel);
|
||||
}
|
||||
}
|
||||
}
|
||||
return (nullptr);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 通过索引找到pannel,如果超过索引范围,会返回nullptr
|
||||
* @param i
|
||||
* @return
|
||||
*/
|
||||
SARibbonPannel* SARibbonCategoryLayout::pannelByIndex(int i) const
|
||||
{
|
||||
if (i >= 0 && i < d_ptr->mItemList.size()) {
|
||||
return d_ptr->mItemList[ i ]->toPannelWidget();
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 移动pannel
|
||||
* @param from
|
||||
* @param to
|
||||
*/
|
||||
void SARibbonCategoryLayout::movePannel(int from, int to)
|
||||
{
|
||||
d_ptr->mItemList.move(from, to);
|
||||
doLayout();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 返回pannel的个数
|
||||
* @return
|
||||
*/
|
||||
int SARibbonCategoryLayout::pannelCount() const
|
||||
{
|
||||
return d_ptr->mItemList.size();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 查找pannel对应的索引
|
||||
* @param p
|
||||
* @return 如果找不到,返回-1
|
||||
*/
|
||||
int SARibbonCategoryLayout::pannelIndex(SARibbonPannel* p) const
|
||||
{
|
||||
int c = pannelCount();
|
||||
|
||||
for (int i = 0; i < c; ++i) {
|
||||
if (d_ptr->mItemList[ i ]->toPannelWidget() == p) {
|
||||
return (i);
|
||||
}
|
||||
}
|
||||
return (-1);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 获取所有的pannel
|
||||
* @return
|
||||
*/
|
||||
QList< SARibbonPannel* > SARibbonCategoryLayout::pannelList() const
|
||||
{
|
||||
QList< SARibbonPannel* > res;
|
||||
|
||||
for (SARibbonCategoryLayoutItem* i : qAsConst(d_ptr->mItemList)) {
|
||||
if (SARibbonPannel* p = i->toPannelWidget()) {
|
||||
res.append(p);
|
||||
}
|
||||
}
|
||||
return (res);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 执行滚动
|
||||
* @param px
|
||||
*/
|
||||
void SARibbonCategoryLayout::scroll(int px)
|
||||
{
|
||||
QSize contentSize = categoryContentSize();
|
||||
d_ptr->mXBase += px;
|
||||
if (d_ptr->mXBase > 0) {
|
||||
d_ptr->mXBase = 0;
|
||||
} else if ((d_ptr->mXBase + d_ptr->mTotalWidth) < contentSize.width()) {
|
||||
d_ptr->mXBase = contentSize.width() - d_ptr->mTotalWidth;
|
||||
}
|
||||
invalidate();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 判断是否滚动过
|
||||
* @return
|
||||
*/
|
||||
bool SARibbonCategoryLayout::isScrolled() const
|
||||
{
|
||||
return (d_ptr->mXBase != 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 这个宽度是实际内容的宽度,有可能大于size.width,也有可能小于
|
||||
* @return
|
||||
*/
|
||||
int SARibbonCategoryLayout::categoryTotalWidth() const
|
||||
{
|
||||
return d_ptr->mTotalWidth;
|
||||
}
|
||||
|
||||
/**
|
||||
@brief 设置Category的对齐方式
|
||||
|
||||
居中对齐会让pannel以居中进行对齐
|
||||
@param al
|
||||
*/
|
||||
void SARibbonCategoryLayout::setCategoryAlignment(SARibbonAlignment al)
|
||||
{
|
||||
d_ptr->mCategoryAlignment = al;
|
||||
}
|
||||
|
||||
/**
|
||||
@brief Category的对齐方式
|
||||
@return
|
||||
*/
|
||||
SARibbonAlignment SARibbonCategoryLayout::categoryAlignment() const
|
||||
{
|
||||
return d_ptr->mCategoryAlignment;
|
||||
}
|
||||
|
||||
void SARibbonCategoryLayout::onLeftScrollButtonClicked()
|
||||
{
|
||||
SARibbonCategory* category = qobject_cast< SARibbonCategory* >(parentWidget());
|
||||
int width = category->width();
|
||||
// 求总宽
|
||||
int totalWidth = d_ptr->mTotalWidth;
|
||||
|
||||
if (totalWidth > width) {
|
||||
int tmp = d_ptr->mXBase + width;
|
||||
if (tmp > 0) {
|
||||
tmp = 0;
|
||||
}
|
||||
d_ptr->mXBase = tmp;
|
||||
} else {
|
||||
d_ptr->mXBase = 0;
|
||||
}
|
||||
invalidate();
|
||||
}
|
||||
|
||||
void SARibbonCategoryLayout::onRightScrollButtonClicked()
|
||||
{
|
||||
SARibbonCategory* category = qobject_cast< SARibbonCategory* >(parentWidget());
|
||||
int width = category->width();
|
||||
// 求总宽
|
||||
int totalWidth = d_ptr->mTotalWidth;
|
||||
|
||||
if (totalWidth > width) {
|
||||
int tmp = d_ptr->mXBase - width;
|
||||
if (tmp < (width - totalWidth)) {
|
||||
tmp = width - totalWidth;
|
||||
}
|
||||
d_ptr->mXBase = tmp;
|
||||
} else {
|
||||
d_ptr->mXBase = 0;
|
||||
}
|
||||
invalidate();
|
||||
}
|
||||
|
||||
void SARibbonCategoryLayout::setGeometry(const QRect& rect)
|
||||
{
|
||||
QRect old = geometry();
|
||||
if (old == rect) {
|
||||
return;
|
||||
}
|
||||
#if SARibbonCategoryLayout_DEBUG_PRINT && SA_DEBUG_PRINT_SIZE_HINT
|
||||
qDebug() << "===========SARibbonCategoryLayout.setGeometry(" << rect << "(" << ribbonCategory()->categoryName()
|
||||
<< ")=======";
|
||||
#endif
|
||||
QLayout::setGeometry(rect);
|
||||
d_ptr->mDirty = false;
|
||||
updateGeometryArr();
|
||||
doLayout();
|
||||
}
|
||||
//=============================================================
|
||||
// SARibbonCategoryLayoutItem
|
||||
//=============================================================
|
||||
|
||||
SARibbonCategoryLayoutItem::SARibbonCategoryLayoutItem(SARibbonPannel* w) : QWidgetItem(w)
|
||||
{
|
||||
separatorWidget = nullptr;
|
||||
}
|
||||
|
||||
SARibbonCategoryLayoutItem::~SARibbonCategoryLayoutItem()
|
||||
{
|
||||
}
|
||||
|
||||
SARibbonPannel* SARibbonCategoryLayoutItem::toPannelWidget()
|
||||
{
|
||||
return qobject_cast< SARibbonPannel* >(widget());
|
||||
}
|
||||
@@ -0,0 +1,95 @@
|
||||
#ifndef SARIBBONCATEGORYLAYOUT_H
|
||||
#define SARIBBONCATEGORYLAYOUT_H
|
||||
#include "SARibbonGlobal.h"
|
||||
#include <QLayout>
|
||||
#include <QList>
|
||||
#include <QMap>
|
||||
#include "SARibbonCategory.h"
|
||||
|
||||
class SARibbonPannel;
|
||||
class SARibbonCategoryLayoutItem;
|
||||
class SARibbonSeparatorWidget;
|
||||
|
||||
/**
|
||||
* @brief The SARibbonCategoryLayout class
|
||||
*/
|
||||
class SA_RIBBON_EXPORT SARibbonCategoryLayout : public QLayout
|
||||
{
|
||||
Q_OBJECT
|
||||
SA_RIBBON_DECLARE_PRIVATE(SARibbonCategoryLayout)
|
||||
public:
|
||||
explicit SARibbonCategoryLayout(SARibbonCategory* parent);
|
||||
~SARibbonCategoryLayout();
|
||||
|
||||
SARibbonCategory* ribbonCategory() const;
|
||||
|
||||
virtual void addItem(QLayoutItem* item) override;
|
||||
virtual QLayoutItem* itemAt(int index) const override;
|
||||
virtual QLayoutItem* takeAt(int index) override;
|
||||
SARibbonCategoryLayoutItem* takePannelItem(int index);
|
||||
SARibbonCategoryLayoutItem* takePannelItem(SARibbonPannel* pannel);
|
||||
bool takePannel(SARibbonPannel* pannel);
|
||||
virtual int count() const override;
|
||||
void setGeometry(const QRect& rect) override;
|
||||
QSize sizeHint() const override;
|
||||
QSize minimumSize() const override;
|
||||
Qt::Orientations expandingDirections() const override;
|
||||
void invalidate() override;
|
||||
// 追加一个pannel
|
||||
void addPannel(SARibbonPannel* pannel);
|
||||
// 插入一个pannel
|
||||
void insertPannel(int index, SARibbonPannel* pannel);
|
||||
//
|
||||
QSize categoryContentSize() const;
|
||||
// 更新尺寸
|
||||
void updateGeometryArr();
|
||||
|
||||
// 执行位置调整
|
||||
void doLayout();
|
||||
|
||||
// 返回所有pannels
|
||||
QList< SARibbonPannel* > pannels() const;
|
||||
|
||||
// 通过obj name获取pannel
|
||||
SARibbonPannel* pannelByObjectName(const QString& objname) const;
|
||||
// 通过pannel name获取pannel
|
||||
SARibbonPannel* pannelByName(const QString& pannelname) const;
|
||||
// 通过索引找到pannel,如果超过索引范围,会返回nullptr
|
||||
SARibbonPannel* pannelByIndex(int i) const;
|
||||
// 移动pannel
|
||||
void movePannel(int from, int to);
|
||||
// pannel的数量
|
||||
int pannelCount() const;
|
||||
// pannel的索引
|
||||
int pannelIndex(SARibbonPannel* p) const;
|
||||
// 获取所有的pannel
|
||||
QList< SARibbonPannel* > pannelList() const;
|
||||
// 执行滚轮事件
|
||||
void scroll(int px);
|
||||
// 判断是否有滚动过
|
||||
bool isScrolled() const;
|
||||
// category的总宽度
|
||||
int categoryTotalWidth() const;
|
||||
// 设置Category的对齐方式
|
||||
void setCategoryAlignment(SARibbonAlignment al);
|
||||
SARibbonAlignment categoryAlignment() const;
|
||||
private Q_SLOTS:
|
||||
void onLeftScrollButtonClicked();
|
||||
void onRightScrollButtonClicked();
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief SARibbonCategoryLayoutItem,用于标识SARibbonCategoryLayout的item
|
||||
*/
|
||||
class SA_RIBBON_EXPORT SARibbonCategoryLayoutItem : public QWidgetItem
|
||||
{
|
||||
public:
|
||||
explicit SARibbonCategoryLayoutItem(SARibbonPannel* w);
|
||||
~SARibbonCategoryLayoutItem();
|
||||
SARibbonSeparatorWidget* separatorWidget;
|
||||
// 把内部的widget转换为pannel
|
||||
SARibbonPannel* toPannelWidget();
|
||||
QRect mWillSetGeometry; ///< pannel将要设置的Geometry
|
||||
QRect mWillSetSeparatorGeometry; ///< pannel将要设置的Separator的Geometry
|
||||
};
|
||||
#endif // SARIBBONCATEGORYLAYOUT_H
|
||||
@@ -0,0 +1,17 @@
|
||||
#include "SARibbonCheckBox.h"
|
||||
#include <QStyleOption>
|
||||
|
||||
SARibbonCheckBox::SARibbonCheckBox(QWidget *parent)
|
||||
: QCheckBox(parent)
|
||||
{
|
||||
}
|
||||
|
||||
SARibbonCheckBox::SARibbonCheckBox(const QString &text, QWidget *parent)
|
||||
: QCheckBox(text, parent)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
SARibbonCheckBox::~SARibbonCheckBox()
|
||||
{
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
#ifndef SARIBBONCHECKBOX_H
|
||||
#define SARIBBONCHECKBOX_H
|
||||
#include "SARibbonGlobal.h"
|
||||
#include <QCheckBox>
|
||||
|
||||
/**
|
||||
* @brief The SARibbonCheckBox class
|
||||
*/
|
||||
class SA_RIBBON_EXPORT SARibbonCheckBox : public QCheckBox
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit SARibbonCheckBox(QWidget *parent = nullptr);
|
||||
explicit SARibbonCheckBox(const QString &text, QWidget *parent = nullptr);
|
||||
~SARibbonCheckBox();
|
||||
};
|
||||
|
||||
#endif // SARIBBONCHECKBOX_H
|
||||
@@ -0,0 +1,208 @@
|
||||
#include "SARibbonColorToolButton.h"
|
||||
#include <QStylePainter>
|
||||
#include <QStyleOptionToolButton>
|
||||
#include <QDebug>
|
||||
#include "colorWidgets/SAColorMenu.h"
|
||||
//===================================================
|
||||
// SARibbonColorToolButton::PrivateData
|
||||
//===================================================
|
||||
const int c_ribbonbutton_color_height = 5; ///< 颜色块的高度
|
||||
|
||||
class SARibbonColorToolButton::PrivateData
|
||||
{
|
||||
SA_RIBBON_DECLARE_PUBLIC(SARibbonColorToolButton)
|
||||
public:
|
||||
PrivateData(SARibbonColorToolButton* p);
|
||||
QPixmap createIconPixmap(const QStyleOptionToolButton& opt, const QSize& iconsize) const;
|
||||
QIcon createColorIcon(const QColor& c, const QSize& size) const;
|
||||
|
||||
public:
|
||||
QColor mColor; ///< 记录颜色
|
||||
SARibbonColorToolButton::ColorStyle mColorStyle { SARibbonColorToolButton::ColorUnderIcon }; ///< 颜色显示样式
|
||||
QIcon mOldIcon; ///< 记录旧的icon
|
||||
};
|
||||
|
||||
SARibbonColorToolButton::PrivateData::PrivateData(SARibbonColorToolButton* p) : q_ptr(p)
|
||||
{
|
||||
}
|
||||
|
||||
QPixmap SARibbonColorToolButton::PrivateData::createIconPixmap(const QStyleOptionToolButton& opt, const QSize& iconsize) const
|
||||
{
|
||||
if (opt.icon.isNull()) { // 没有有图标
|
||||
return QPixmap();
|
||||
}
|
||||
// 有icon,在icon下方加入颜色
|
||||
QIcon::State state = (opt.state & QStyle::State_On) ? QIcon::On : QIcon::Off;
|
||||
QIcon::Mode mode;
|
||||
if (!(opt.state & QStyle::State_Enabled)) {
|
||||
mode = QIcon::Disabled;
|
||||
} else if ((opt.state & QStyle::State_MouseOver) && (opt.state & QStyle::State_AutoRaise)) {
|
||||
mode = QIcon::Active;
|
||||
} else {
|
||||
mode = QIcon::Normal;
|
||||
}
|
||||
QSize realIconSize = iconsize - QSize(0, c_ribbonbutton_color_height + 1);
|
||||
QPixmap pixmap = opt.icon.pixmap(q_ptr->window()->windowHandle(), realIconSize, mode, state);
|
||||
QPixmap res(pixmap.size() + QSize(4, c_ribbonbutton_color_height + 4)); // 宽度上,颜色块多出2px
|
||||
res.fill(Qt::transparent);
|
||||
QPainter painter(&res);
|
||||
int xpixmap = (res.width() - pixmap.width()) / 2;
|
||||
int ypixmap = (res.height() - c_ribbonbutton_color_height - 2 - pixmap.height()) / 2; // 这里要减去2而不是1,这样奇数偶数都不会影响
|
||||
int w = pixmap.width();
|
||||
int h = pixmap.height();
|
||||
QRect rpixmap = QRect(xpixmap, ypixmap, w, h);
|
||||
painter.drawPixmap(rpixmap, pixmap);
|
||||
QRect colorRect = rpixmap.adjusted(0, h + 1, 0, c_ribbonbutton_color_height + 1);
|
||||
if (mColor.isValid()) {
|
||||
painter.fillRect(colorRect, mColor);
|
||||
} else {
|
||||
QPen pen(Qt::red, 1, Qt::SolidLine, Qt::RoundCap);
|
||||
painter.setPen(pen);
|
||||
painter.setRenderHint(QPainter::SmoothPixmapTransform, true);
|
||||
painter.setRenderHint(QPainter::Antialiasing, true);
|
||||
int ss = colorRect.width() / 3;
|
||||
painter.drawLine(QPoint(colorRect.x() + ss, colorRect.bottom()), QPoint(colorRect.right() - ss, colorRect.top()));
|
||||
pen.setColor(Qt::black);
|
||||
painter.setPen(pen);
|
||||
painter.drawRect(colorRect);
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
QIcon SARibbonColorToolButton::PrivateData::createColorIcon(const QColor& c, const QSize& size) const
|
||||
{
|
||||
QPixmap res(size);
|
||||
res.fill(Qt::transparent);
|
||||
QPainter painter(&res);
|
||||
if (c.isValid()) {
|
||||
painter.fillRect(QRect(1, 1, res.height() - 2, res.width() - 2), c);
|
||||
} else {
|
||||
QPen pen(Qt::black, 1, Qt::SolidLine, Qt::RoundCap);
|
||||
painter.setPen(pen);
|
||||
painter.drawRect(QRect(1, 1, res.height() - 2, res.width() - 2));
|
||||
pen.setColor(Qt::red);
|
||||
painter.setPen(pen);
|
||||
painter.setRenderHint(QPainter::SmoothPixmapTransform, true);
|
||||
painter.setRenderHint(QPainter::Antialiasing, true);
|
||||
painter.drawLine(QPoint(1, size.height()), QPoint(size.width() - 1, 1));
|
||||
}
|
||||
return QIcon(res);
|
||||
}
|
||||
|
||||
//===================================================
|
||||
// SARibbonColorToolButton
|
||||
//===================================================
|
||||
|
||||
SARibbonColorToolButton::SARibbonColorToolButton(QWidget* parent)
|
||||
: SARibbonToolButton(parent), d_ptr(new SARibbonColorToolButton::PrivateData(this))
|
||||
{
|
||||
connect(this, &QAbstractButton::clicked, this, &SARibbonColorToolButton::onButtonClicked);
|
||||
}
|
||||
|
||||
SARibbonColorToolButton::SARibbonColorToolButton(QAction* defaultAction, QWidget* parent)
|
||||
: SARibbonToolButton(defaultAction, parent), d_ptr(new SARibbonColorToolButton::PrivateData(this))
|
||||
{
|
||||
connect(this, &QAbstractButton::clicked, this, &SARibbonColorToolButton::onButtonClicked);
|
||||
}
|
||||
|
||||
SARibbonColorToolButton::~SARibbonColorToolButton()
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 获取按钮维护的颜色
|
||||
* @return
|
||||
*/
|
||||
QColor SARibbonColorToolButton::color() const
|
||||
{
|
||||
return d_ptr->mColor;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 设置颜色显示的样式
|
||||
* @param s
|
||||
*/
|
||||
void SARibbonColorToolButton::setColorStyle(SARibbonColorToolButton::ColorStyle s)
|
||||
{
|
||||
if (d_ptr->mColorStyle == s) {
|
||||
return;
|
||||
}
|
||||
d_ptr->mColorStyle = s;
|
||||
if (ColorUnderIcon == s) {
|
||||
setIcon(d_ptr->mOldIcon);
|
||||
} else {
|
||||
d_ptr->mOldIcon = icon();
|
||||
setIcon(d_ptr->createColorIcon(d_ptr->mColor, QSize(32, 32)));
|
||||
}
|
||||
repaint();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 颜色显示的样式
|
||||
* @return
|
||||
*/
|
||||
SARibbonColorToolButton::ColorStyle SARibbonColorToolButton::colorStyle() const
|
||||
{
|
||||
return d_ptr->mColorStyle;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 建立标准的颜色菜单
|
||||
* @return
|
||||
*/
|
||||
SAColorMenu* SARibbonColorToolButton::setupStandardColorMenu()
|
||||
{
|
||||
setPopupMode(QToolButton::MenuButtonPopup);
|
||||
SAColorMenu* m = new SAColorMenu(this);
|
||||
m->enableNoneColorAction(true);
|
||||
QAction* customColor = m->customColorAction();
|
||||
if (customColor) {
|
||||
customColor->setIcon(QIcon(":/image/resource/define-color.svg"));
|
||||
}
|
||||
connect(m, &SAColorMenu::selectedColor, this, &SARibbonColorToolButton::setColor);
|
||||
setMenu(m);
|
||||
|
||||
updateRect();
|
||||
return m;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 设置按钮的颜色
|
||||
*
|
||||
* 此时会生成一个新的icon
|
||||
* @note 会发射@sa colorChanged 信号
|
||||
* @param c
|
||||
*/
|
||||
void SARibbonColorToolButton::setColor(const QColor& c)
|
||||
{
|
||||
if (d_ptr->mColor != c) {
|
||||
d_ptr->mColor = c;
|
||||
if (ColorFillToIcon == colorStyle()) {
|
||||
setIcon(d_ptr->createColorIcon(c, QSize(32, 32)));
|
||||
}
|
||||
repaint();
|
||||
Q_EMIT colorChanged(c);
|
||||
}
|
||||
}
|
||||
|
||||
void SARibbonColorToolButton::onButtonClicked(bool checked)
|
||||
{
|
||||
Q_EMIT colorClicked(d_ptr->mColor, checked);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 重写paintIcon函数,把颜色加到icon下面
|
||||
* @param p
|
||||
* @param opt
|
||||
* @param iconDrawRect
|
||||
*/
|
||||
void SARibbonColorToolButton::paintIcon(QPainter& p, const QStyleOptionToolButton& opt, const QRect& iconDrawRect)
|
||||
{
|
||||
if (ColorUnderIcon == colorStyle()) {
|
||||
// 有icon
|
||||
QPixmap pm = d_ptr->createIconPixmap(opt, iconDrawRect.size());
|
||||
style()->drawItemPixmap(&p, iconDrawRect, Qt::AlignCenter, pm);
|
||||
} else {
|
||||
SARibbonToolButton::paintIcon(p, opt, iconDrawRect);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,55 @@
|
||||
#ifndef SARIBBONCOLORTOOLBUTTON_H
|
||||
#define SARIBBONCOLORTOOLBUTTON_H
|
||||
#include "SARibbonToolButton.h"
|
||||
#include "SARibbonGlobal.h"
|
||||
class SAColorMenu;
|
||||
/**
|
||||
* @brief Refer to the color setting button in the office, which can display the color below the icon(参考office的颜色设置按钮,可以显示颜色在图标下方)
|
||||
*/
|
||||
class SA_RIBBON_EXPORT SARibbonColorToolButton : public SARibbonToolButton
|
||||
{
|
||||
Q_OBJECT
|
||||
SA_RIBBON_DECLARE_PRIVATE(SARibbonColorToolButton)
|
||||
public:
|
||||
/**
|
||||
* @brief 颜色样式
|
||||
*/
|
||||
enum ColorStyle
|
||||
{
|
||||
ColorUnderIcon, ///< 颜色在icon下方,这个要求必须设置icon
|
||||
ColorFillToIcon ///< 颜色作为icon,这个模式下在setColor会自动生成一个颜色icon替换掉原来的icon,因此setIcon函数没有作用
|
||||
};
|
||||
|
||||
public:
|
||||
explicit SARibbonColorToolButton(QWidget* parent = nullptr);
|
||||
explicit SARibbonColorToolButton(QAction* defaultAction, QWidget* parent = nullptr);
|
||||
~SARibbonColorToolButton();
|
||||
// 获取颜色
|
||||
QColor color() const;
|
||||
// 设置颜色显示方案
|
||||
void setColorStyle(ColorStyle s);
|
||||
ColorStyle colorStyle() const;
|
||||
// 建立标准的颜色菜单
|
||||
SAColorMenu* setupStandardColorMenu();
|
||||
public Q_SLOTS:
|
||||
// 设置颜色,会发射colorChanged信号
|
||||
void setColor(const QColor& c);
|
||||
private Q_SLOTS:
|
||||
void onButtonClicked(bool checked = false);
|
||||
Q_SIGNALS:
|
||||
/**
|
||||
* @brief 颜色被点击的响应
|
||||
* @param color
|
||||
*/
|
||||
void colorClicked(const QColor& color, bool checked = false);
|
||||
/**
|
||||
* @brief 颜色改变信号
|
||||
* @param color
|
||||
*/
|
||||
void colorChanged(const QColor& color);
|
||||
|
||||
protected:
|
||||
void paintIcon(QPainter& p, const QStyleOptionToolButton& opt, const QRect& iconDrawRect);
|
||||
};
|
||||
|
||||
#endif // SARIBBONCOLORTOOLBUTTON_H
|
||||
@@ -0,0 +1,11 @@
|
||||
#include "SARibbonComboBox.h"
|
||||
|
||||
|
||||
SARibbonComboBox::SARibbonComboBox(QWidget *parent)
|
||||
: QComboBox(parent)
|
||||
{
|
||||
}
|
||||
|
||||
SARibbonComboBox::~SARibbonComboBox()
|
||||
{
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
#ifndef SARIBBONCOMBOBOX_H
|
||||
#define SARIBBONCOMBOBOX_H
|
||||
#include "SARibbonGlobal.h"
|
||||
#include <QComboBox>
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @brief QComboBox的Ribbon显示,可以显示QIcon和windowTitle在左侧
|
||||
*/
|
||||
class SA_RIBBON_EXPORT SARibbonComboBox : public QComboBox
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit SARibbonComboBox(QWidget *parent = nullptr);
|
||||
~SARibbonComboBox();
|
||||
};
|
||||
|
||||
#endif // SARIBBONCOMBOBOX_H
|
||||
@@ -0,0 +1,212 @@
|
||||
#include "SARibbonContextCategory.h"
|
||||
#include <QList>
|
||||
#include <QVariant>
|
||||
#include "SARibbonElementManager.h"
|
||||
#include <QDebug>
|
||||
|
||||
/**
|
||||
* @brief The SARibbonCategoryData class
|
||||
*/
|
||||
class SAPrivateRibbonCategoryData
|
||||
{
|
||||
public:
|
||||
SARibbonCategory* categoryPage;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief The SARibbonContextCategoryPrivate class
|
||||
*/
|
||||
class SARibbonContextCategory::PrivateData
|
||||
{
|
||||
SA_RIBBON_DECLARE_PUBLIC(SARibbonContextCategory)
|
||||
public:
|
||||
PrivateData(SARibbonContextCategory* p);
|
||||
|
||||
public:
|
||||
QList< SAPrivateRibbonCategoryData > mCategoryDataList;
|
||||
QVariant mContextID;
|
||||
QColor mContextColor;
|
||||
QString mContextTitle;
|
||||
};
|
||||
SARibbonContextCategory::PrivateData::PrivateData(SARibbonContextCategory* p) : q_ptr(p)
|
||||
{
|
||||
}
|
||||
|
||||
//===================================================
|
||||
// SARibbonContextCategory
|
||||
//===================================================
|
||||
SARibbonContextCategory::SARibbonContextCategory(QWidget* parent)
|
||||
: QObject(parent), d_ptr(new SARibbonContextCategory::PrivateData(this))
|
||||
{
|
||||
}
|
||||
|
||||
SARibbonContextCategory::~SARibbonContextCategory()
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 添加标签
|
||||
* @param title 标签名字
|
||||
*/
|
||||
SARibbonCategory* SARibbonContextCategory::addCategoryPage(const QString& title)
|
||||
{
|
||||
SARibbonCategory* category = RibbonSubElementFactory->createRibbonCategory(parentWidget());
|
||||
category->setCategoryName(title);
|
||||
addCategoryPage(category);
|
||||
return (category);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 添加标签
|
||||
* @param page
|
||||
*/
|
||||
void SARibbonContextCategory::addCategoryPage(SARibbonCategory* category)
|
||||
{
|
||||
if (isHaveCategory(category)) {
|
||||
// cn:SARibbonContextCategory已经持有标签:%1,将跳过
|
||||
qWarning() << tr("SARibbonContextCategory have category %1,will skip").arg(category->categoryName());
|
||||
return;
|
||||
}
|
||||
category->markIsContextCategory(true);
|
||||
connect(category, &SARibbonCategory::categoryNameChanged, this, &SARibbonContextCategory::onCategoryTitleChanged);
|
||||
SAPrivateRibbonCategoryData catData;
|
||||
catData.categoryPage = category;
|
||||
d_ptr->mCategoryDataList.append(catData);
|
||||
category->installEventFilter(this);
|
||||
Q_EMIT categoryPageAdded(category);
|
||||
}
|
||||
|
||||
int SARibbonContextCategory::categoryCount() const
|
||||
{
|
||||
return (d_ptr->mCategoryDataList.count());
|
||||
}
|
||||
|
||||
void SARibbonContextCategory::setId(const QVariant& id)
|
||||
{
|
||||
d_ptr->mContextID = id;
|
||||
}
|
||||
|
||||
QVariant SARibbonContextCategory::id() const
|
||||
{
|
||||
return (d_ptr->mContextID);
|
||||
}
|
||||
|
||||
void SARibbonContextCategory::setContextColor(const QColor color)
|
||||
{
|
||||
d_ptr->mContextColor = color;
|
||||
}
|
||||
|
||||
QColor SARibbonContextCategory::contextColor() const
|
||||
{
|
||||
return (d_ptr->mContextColor);
|
||||
}
|
||||
|
||||
QWidget* SARibbonContextCategory::parentWidget() const
|
||||
{
|
||||
return (qobject_cast< QWidget* >(parent()));
|
||||
}
|
||||
|
||||
bool SARibbonContextCategory::eventFilter(QObject* watched, QEvent* e)
|
||||
{
|
||||
if (nullptr == watched) {
|
||||
return (false);
|
||||
}
|
||||
switch (e->type()) {
|
||||
case QEvent::Close: {
|
||||
SARibbonCategory* c = qobject_cast< SARibbonCategory* >(watched);
|
||||
if (c) {
|
||||
#ifdef SA_RIBBON_DEBUG_HELP_DRAW
|
||||
qDebug() << " -----------> close event";
|
||||
#endif
|
||||
takeCategory(c);
|
||||
}
|
||||
} break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return (false);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 获取上下文标签的标题
|
||||
* @return
|
||||
*/
|
||||
QString SARibbonContextCategory::contextTitle() const
|
||||
{
|
||||
return (d_ptr->mContextTitle);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 设置上下文标签的标题,标题仅在office模式下显示 @ref SARibbonBar::RibbonStyle
|
||||
* @param contextTitle
|
||||
* @note 此函数会触发信号@sa contextTitleChanged
|
||||
*/
|
||||
void SARibbonContextCategory::setContextTitle(const QString& contextTitle)
|
||||
{
|
||||
d_ptr->mContextTitle = contextTitle;
|
||||
Q_EMIT contextTitleChanged(contextTitle);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 获取对应的tab页
|
||||
* @param index
|
||||
* @return
|
||||
*/
|
||||
SARibbonCategory* SARibbonContextCategory::categoryPage(int index)
|
||||
{
|
||||
return (d_ptr->mCategoryDataList[ index ].categoryPage);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 获取所有的SARibbonCategory*
|
||||
* @return
|
||||
*/
|
||||
QList< SARibbonCategory* > SARibbonContextCategory::categoryList() const
|
||||
{
|
||||
QList< SARibbonCategory* > res;
|
||||
|
||||
for (const SAPrivateRibbonCategoryData& c : qAsConst(d_ptr->mCategoryDataList)) {
|
||||
res.append(c.categoryPage);
|
||||
}
|
||||
return (res);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 移除这个category,这时SARibbonContextCategory不再管理这个category
|
||||
* @param category
|
||||
* @return 成功移除返回true
|
||||
*/
|
||||
bool SARibbonContextCategory::takeCategory(SARibbonCategory* category)
|
||||
{
|
||||
for (int i = 0; i < d_ptr->mCategoryDataList.size(); ++i) {
|
||||
if (d_ptr->mCategoryDataList[ i ].categoryPage == category) {
|
||||
d_ptr->mCategoryDataList.takeAt(i);
|
||||
return (true);
|
||||
}
|
||||
}
|
||||
return (false);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 判断上下文是否维护了此SARibbonCategory
|
||||
* @param category
|
||||
* @return
|
||||
*/
|
||||
bool SARibbonContextCategory::isHaveCategory(SARibbonCategory* category) const
|
||||
{
|
||||
for (int i = 0; i < d_ptr->mCategoryDataList.size(); ++i) {
|
||||
if (d_ptr->mCategoryDataList[ i ].categoryPage == category) {
|
||||
return (true);
|
||||
}
|
||||
}
|
||||
return (false);
|
||||
}
|
||||
|
||||
void SARibbonContextCategory::onCategoryTitleChanged(const QString& title)
|
||||
{
|
||||
SARibbonCategory* category = qobject_cast< SARibbonCategory* >(sender());
|
||||
if (category) {
|
||||
Q_EMIT categoryTitleChanged(category, title);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,80 @@
|
||||
#ifndef SARIBBONCONTEXTCATEGORY_H
|
||||
#define SARIBBONCONTEXTCATEGORY_H
|
||||
#include "SARibbonGlobal.h"
|
||||
#include "SARibbonCategory.h"
|
||||
#include <QWidget>
|
||||
|
||||
/**
|
||||
* @brief 管理上下文标签的类
|
||||
*/
|
||||
class SA_RIBBON_EXPORT SARibbonContextCategory : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
SA_RIBBON_DECLARE_PRIVATE(SARibbonContextCategory)
|
||||
public:
|
||||
explicit SARibbonContextCategory(QWidget* parent = nullptr);
|
||||
~SARibbonContextCategory();
|
||||
//上下文目录添加下属目录
|
||||
SARibbonCategory* addCategoryPage(const QString& title);
|
||||
void addCategoryPage(SARibbonCategory* category);
|
||||
//获取上下文标签下管理的标签个数
|
||||
int categoryCount() const;
|
||||
|
||||
//设置id
|
||||
void setId(const QVariant& id);
|
||||
QVariant id() const;
|
||||
|
||||
//设置上下文颜色
|
||||
void setContextColor(const QColor color);
|
||||
QColor contextColor() const;
|
||||
|
||||
//上下文标签的内容
|
||||
QString contextTitle() const;
|
||||
void setContextTitle(const QString& contextTitle);
|
||||
|
||||
//获取对应的tab页
|
||||
SARibbonCategory* categoryPage(int index);
|
||||
|
||||
//获取所有的SARibbonCategory*
|
||||
QList< SARibbonCategory* > categoryList() const;
|
||||
|
||||
//移除category
|
||||
bool takeCategory(SARibbonCategory* category);
|
||||
|
||||
//判断上下文是否维护了此SARibbonCategory
|
||||
bool isHaveCategory(SARibbonCategory* category) const;
|
||||
Q_SIGNALS:
|
||||
/**
|
||||
* @brief 标签加入上下文
|
||||
* @param category
|
||||
*/
|
||||
void categoryPageAdded(SARibbonCategory* category);
|
||||
|
||||
/**
|
||||
* @brief 标签从上下文移除
|
||||
* @param category
|
||||
*/
|
||||
void categoryPageRemoved(SARibbonCategory* category);
|
||||
|
||||
/**
|
||||
* @brief 上下文的标题发生改变
|
||||
* @param title
|
||||
*/
|
||||
void contextTitleChanged(const QString& title);
|
||||
|
||||
/**
|
||||
* @brief 上下文标签维护的标签页名字发生了改变
|
||||
* @param category 发生改变的上下文标签页
|
||||
* @param title 新名字
|
||||
*/
|
||||
void categoryTitleChanged(SARibbonCategory* category, const QString& title);
|
||||
private Q_SLOTS:
|
||||
void onCategoryTitleChanged(const QString& title);
|
||||
|
||||
protected:
|
||||
//获取父级窗口
|
||||
QWidget* parentWidget() const;
|
||||
virtual bool eventFilter(QObject* watched, QEvent* e) override;
|
||||
};
|
||||
|
||||
#endif // SARIBBONCONTEXTCATEGORY_H
|
||||
@@ -0,0 +1,16 @@
|
||||
#include "SARibbonControlButton.h"
|
||||
|
||||
SARibbonControlButton::SARibbonControlButton(QWidget* parent) : QToolButton(parent)
|
||||
{
|
||||
}
|
||||
|
||||
SARibbonControlButton::~SARibbonControlButton()
|
||||
{
|
||||
}
|
||||
SARibbonControlToolButton::SARibbonControlToolButton(QWidget* parent) : QToolButton(parent)
|
||||
{
|
||||
}
|
||||
|
||||
SARibbonControlToolButton::~SARibbonControlToolButton()
|
||||
{
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
#ifndef SARIBBONCONTROLBUTTON_H
|
||||
#define SARIBBONCONTROLBUTTON_H
|
||||
#include <QToolButton>
|
||||
#include "SARibbonGlobal.h"
|
||||
#include "SARibbonToolButton.h"
|
||||
|
||||
/**
|
||||
* @brief 用于SARibbonGallery的control button
|
||||
*
|
||||
* 为了防止外部qss的影响,单独继承一个类
|
||||
*/
|
||||
class SA_RIBBON_EXPORT SARibbonControlButton : public QToolButton
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit SARibbonControlButton(QWidget* parent = nullptr);
|
||||
~SARibbonControlButton();
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief 用于SARibbonButtonGroupWidget的control button
|
||||
*
|
||||
* 为了防止SARibbonToolButton qss的影响,单独继承一个类
|
||||
*/
|
||||
class SA_RIBBON_EXPORT SARibbonControlToolButton : public QToolButton
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit SARibbonControlToolButton(QWidget* parent = nullptr);
|
||||
~SARibbonControlToolButton();
|
||||
};
|
||||
|
||||
#endif // SARIBBONPANNELTOOLBUTTON_H
|
||||
@@ -0,0 +1,169 @@
|
||||
#include "SARibbonCtrlContainer.h"
|
||||
#include <QHBoxLayout>
|
||||
#include <QPainter>
|
||||
#include <QPaintEvent>
|
||||
#include <QStylePainter>
|
||||
#include <QDebug>
|
||||
#include <QLabel>
|
||||
#include <QApplication>
|
||||
#include <QScreen>
|
||||
/**
|
||||
* @brief The SARibbonCtrlContainerPrivate class
|
||||
*/
|
||||
class SARibbonCtrlContainer::PrivateData
|
||||
{
|
||||
SA_RIBBON_DECLARE_PUBLIC(SARibbonCtrlContainer)
|
||||
public:
|
||||
QWidget* mContainerWidget { nullptr };
|
||||
QHBoxLayout* mHorizontalLayout { nullptr };
|
||||
QLabel* mLabelPixmap { nullptr };
|
||||
QLabel* mLabelText { nullptr };
|
||||
QSize mIconSize { 24, 24 };
|
||||
QIcon mIcon;
|
||||
PrivateData(SARibbonCtrlContainer* p) : q_ptr(p)
|
||||
{
|
||||
mHorizontalLayout = new QHBoxLayout(p);
|
||||
mHorizontalLayout->setSpacing(0);
|
||||
mHorizontalLayout->setObjectName(QString::fromUtf8("horizontalLayout"));
|
||||
mHorizontalLayout->setContentsMargins(0, 0, 0, 0);
|
||||
|
||||
mLabelPixmap = new QLabel(p);
|
||||
mLabelPixmap->setObjectName(QString::fromUtf8("labelPixmap"));
|
||||
mLabelPixmap->setAlignment(Qt::AlignCenter);
|
||||
mHorizontalLayout->addWidget(mLabelPixmap);
|
||||
|
||||
mLabelText = new QLabel(p);
|
||||
mLabelText->setObjectName(QString::fromUtf8("labelText"));
|
||||
mHorizontalLayout->addWidget(mLabelText);
|
||||
}
|
||||
|
||||
void setContainerWidget(QWidget* w)
|
||||
{
|
||||
if (mContainerWidget) {
|
||||
// 原来有widget
|
||||
QWidget* oldwidget = mContainerWidget;
|
||||
takeContainerWidget(oldwidget);
|
||||
oldwidget->deleteLater();
|
||||
}
|
||||
mContainerWidget = w;
|
||||
if (!w) {
|
||||
return;
|
||||
}
|
||||
if (w->parent() != q_ptr) {
|
||||
w->setParent(q_ptr);
|
||||
}
|
||||
// ContainerWidget永远在最右边
|
||||
mHorizontalLayout->insertWidget(mHorizontalLayout->count(), w);
|
||||
QSizePolicy sizePolicy(QSizePolicy::Expanding, QSizePolicy::Preferred);
|
||||
sizePolicy.setHorizontalStretch(0);
|
||||
sizePolicy.setVerticalStretch(0);
|
||||
w->setSizePolicy(sizePolicy);
|
||||
}
|
||||
|
||||
void takeContainerWidget(QWidget* w)
|
||||
{
|
||||
int i = mHorizontalLayout->indexOf(w);
|
||||
if (i >= 0) {
|
||||
QLayoutItem* item = mHorizontalLayout->takeAt(i);
|
||||
delete item;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
//===================================================
|
||||
// SARibbonCtrlContainer
|
||||
//===================================================
|
||||
SARibbonCtrlContainer::SARibbonCtrlContainer(QWidget* parent)
|
||||
: QWidget(parent), d_ptr(new SARibbonCtrlContainer::PrivateData(this))
|
||||
{
|
||||
}
|
||||
|
||||
SARibbonCtrlContainer::~SARibbonCtrlContainer()
|
||||
{
|
||||
}
|
||||
|
||||
QWidget* SARibbonCtrlContainer::containerWidget()
|
||||
{
|
||||
return (d_ptr->mContainerWidget);
|
||||
}
|
||||
|
||||
const QWidget* SARibbonCtrlContainer::containerWidget() const
|
||||
{
|
||||
return (d_ptr->mContainerWidget);
|
||||
}
|
||||
|
||||
void SARibbonCtrlContainer::setEnableShowIcon(bool b)
|
||||
{
|
||||
d_ptr->mLabelPixmap->setVisible(b);
|
||||
}
|
||||
|
||||
void SARibbonCtrlContainer::setEnableShowTitle(bool b)
|
||||
{
|
||||
d_ptr->mLabelText->setVisible(b);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 判断是否存在容器窗口
|
||||
* @return
|
||||
*/
|
||||
bool SARibbonCtrlContainer::hasContainerWidget() const
|
||||
{
|
||||
return (d_ptr->mContainerWidget != nullptr);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 设置图标
|
||||
* @param i
|
||||
*/
|
||||
void SARibbonCtrlContainer::setIcon(const QIcon& i)
|
||||
{
|
||||
d_ptr->mIcon = i;
|
||||
QPixmap pixmap = i.pixmap(d_ptr->mIconSize);
|
||||
d_ptr->mLabelPixmap->setPixmap(pixmap);
|
||||
}
|
||||
|
||||
void SARibbonCtrlContainer::setIcon(const QPixmap& pixmap)
|
||||
{
|
||||
d_ptr->mLabelPixmap->setPixmap(pixmap);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 获取图标
|
||||
* @return
|
||||
*/
|
||||
QIcon SARibbonCtrlContainer::icon() const
|
||||
{
|
||||
return d_ptr->mIcon;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 设置文字
|
||||
* @param t
|
||||
*/
|
||||
void SARibbonCtrlContainer::setText(const QString& t)
|
||||
{
|
||||
d_ptr->mLabelText->setText(t);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 获取文字
|
||||
* @return
|
||||
*/
|
||||
QString SARibbonCtrlContainer::text() const
|
||||
{
|
||||
return d_ptr->mLabelText->text();
|
||||
}
|
||||
|
||||
void SARibbonCtrlContainer::setContainerWidget(QWidget* w)
|
||||
{
|
||||
d_ptr->setContainerWidget(w);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 获取显示icon的窗口
|
||||
* @return
|
||||
*/
|
||||
QWidget* SARibbonCtrlContainer::iconWidget() const
|
||||
{
|
||||
return d_ptr->mLabelPixmap;
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
#ifndef SARIBBONCTROLCONTAINER_H
|
||||
#define SARIBBONCTROLCONTAINER_H
|
||||
#include "SARibbonGlobal.h"
|
||||
#include <QWidget>
|
||||
#include <QScopedPointer>
|
||||
class QStyleOption;
|
||||
|
||||
/**
|
||||
* @brief 用于装载一个窗体的容器,这个窗体会布满整个SARibbonCtrlContainer,但会预留空间显示icon或者title
|
||||
*
|
||||
* ----------------------
|
||||
* |icon|text| widget |
|
||||
* ----------------------
|
||||
*/
|
||||
class SA_RIBBON_EXPORT SARibbonCtrlContainer : public QWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
SA_RIBBON_DECLARE_PRIVATE(SARibbonCtrlContainer)
|
||||
public:
|
||||
explicit SARibbonCtrlContainer(QWidget* parent = nullptr);
|
||||
~SARibbonCtrlContainer();
|
||||
|
||||
void setEnableShowIcon(bool b);
|
||||
void setEnableShowTitle(bool b);
|
||||
// 判断是否存在容器窗口
|
||||
bool hasContainerWidget() const;
|
||||
// 图标
|
||||
void setIcon(const QIcon& i);
|
||||
void setIcon(const QPixmap& pixmap);
|
||||
QIcon icon() const;
|
||||
// 图标
|
||||
void setText(const QString& t);
|
||||
QString text() const;
|
||||
// 设置窗口
|
||||
void setContainerWidget(QWidget* w);
|
||||
QWidget* containerWidget();
|
||||
const QWidget* containerWidget() const;
|
||||
// 获取线索icon的窗口
|
||||
QWidget* iconWidget() const;
|
||||
};
|
||||
|
||||
#endif // SARIBBONCTROLCONTAINER_H
|
||||
@@ -0,0 +1,704 @@
|
||||
#include "SARibbonCustomizeData.h"
|
||||
#include "SARibbonBar.h"
|
||||
#include <QDebug>
|
||||
#include <QObject>
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
/// SARibbonCustomizeData
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
SARibbonCustomizeData::SARibbonCustomizeData()
|
||||
: indexValue(-1)
|
||||
, actionRowProportionValue(SARibbonPannelItem::Large)
|
||||
, mType(UnknowActionType)
|
||||
, mActionsManagerPointer(nullptr)
|
||||
{
|
||||
}
|
||||
|
||||
SARibbonCustomizeData::SARibbonCustomizeData(ActionType type, SARibbonActionsManager* mgr)
|
||||
: indexValue(-1), actionRowProportionValue(SARibbonPannelItem::Large), mType(type), mActionsManagerPointer(mgr)
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 获取CustomizeData的action type
|
||||
* @return
|
||||
*/
|
||||
SARibbonCustomizeData::ActionType SARibbonCustomizeData::actionType() const
|
||||
{
|
||||
return (mType);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 设置CustomizeData的action type
|
||||
* @param a
|
||||
*/
|
||||
void SARibbonCustomizeData::setActionType(SARibbonCustomizeData::ActionType a)
|
||||
{
|
||||
mType = a;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 判断是否是一个正常的CustomizeData
|
||||
*
|
||||
* 实际逻辑actionType() != UnknowActionType
|
||||
* @return 有用的CustomizeData返回true
|
||||
*/
|
||||
bool SARibbonCustomizeData::isValid() const
|
||||
{
|
||||
return (actionType() != UnknowActionType);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 应用SARibbonCustomizeData到SARibbonBar
|
||||
* @param m
|
||||
* @return 如果应用失败,返回false,如果actionType==UnknowActionType直接返回false
|
||||
*/
|
||||
bool SARibbonCustomizeData::apply(SARibbonBar* bar) const
|
||||
{
|
||||
if (nullptr == bar) {
|
||||
return (false);
|
||||
}
|
||||
switch (actionType()) {
|
||||
case UnknowActionType:
|
||||
return (false);
|
||||
|
||||
case AddCategoryActionType: {
|
||||
// 添加标签
|
||||
SARibbonCategory* c = bar->insertCategoryPage(keyValue, indexValue);
|
||||
if (nullptr == c) {
|
||||
return (false);
|
||||
}
|
||||
c->setObjectName(categoryObjNameValue);
|
||||
SARibbonCustomizeData::setCanCustomize(c);
|
||||
return (true);
|
||||
}
|
||||
|
||||
case AddPannelActionType: {
|
||||
// 添加pannel
|
||||
SARibbonCategory* c = bar->categoryByObjectName(categoryObjNameValue);
|
||||
if (nullptr == c) {
|
||||
return (false);
|
||||
}
|
||||
SARibbonPannel* p = c->insertPannel(keyValue, indexValue);
|
||||
p->setObjectName(pannelObjNameValue);
|
||||
SARibbonCustomizeData::setCanCustomize(p);
|
||||
return (true);
|
||||
}
|
||||
|
||||
case AddActionActionType: {
|
||||
if (nullptr == mActionsManagerPointer) {
|
||||
return (false);
|
||||
}
|
||||
SARibbonCategory* c = bar->categoryByObjectName(categoryObjNameValue);
|
||||
if (nullptr == c) {
|
||||
return (false);
|
||||
}
|
||||
SARibbonPannel* pannel = c->pannelByObjectName(pannelObjNameValue);
|
||||
if (nullptr == pannel) {
|
||||
return (false);
|
||||
}
|
||||
QAction* act = mActionsManagerPointer->action(keyValue);
|
||||
if (nullptr == act) {
|
||||
return (false);
|
||||
}
|
||||
SARibbonCustomizeData::setCanCustomize(act);
|
||||
pannel->addAction(act, actionRowProportionValue);
|
||||
return (true);
|
||||
}
|
||||
|
||||
case RemoveCategoryActionType: {
|
||||
SARibbonCategory* c = bar->categoryByObjectName(categoryObjNameValue);
|
||||
if (nullptr == c) {
|
||||
return (false);
|
||||
}
|
||||
bar->removeCategory(c);
|
||||
return (true);
|
||||
}
|
||||
|
||||
case RemovePannelActionType: {
|
||||
SARibbonCategory* c = bar->categoryByObjectName(categoryObjNameValue);
|
||||
if (nullptr == c) {
|
||||
return (false);
|
||||
}
|
||||
SARibbonPannel* pannel = c->pannelByObjectName(pannelObjNameValue);
|
||||
if (nullptr == pannel) {
|
||||
return (false);
|
||||
}
|
||||
c->removePannel(pannel);
|
||||
return (true);
|
||||
}
|
||||
|
||||
case RemoveActionActionType: {
|
||||
SARibbonCategory* c = bar->categoryByObjectName(categoryObjNameValue);
|
||||
if (nullptr == c) {
|
||||
return (false);
|
||||
}
|
||||
SARibbonPannel* pannel = c->pannelByObjectName(pannelObjNameValue);
|
||||
if (nullptr == pannel) {
|
||||
return (false);
|
||||
}
|
||||
QAction* act = mActionsManagerPointer->action(keyValue);
|
||||
if (nullptr == act) {
|
||||
return (false);
|
||||
}
|
||||
pannel->removeAction(act);
|
||||
return (true);
|
||||
}
|
||||
|
||||
case ChangeCategoryOrderActionType: {
|
||||
SARibbonCategory* c = bar->categoryByObjectName(categoryObjNameValue);
|
||||
if (nullptr == c) {
|
||||
return (false);
|
||||
}
|
||||
int currentindex = bar->categoryIndex(c);
|
||||
if (-1 == currentindex) {
|
||||
return (false);
|
||||
}
|
||||
int toindex = currentindex + indexValue;
|
||||
bar->moveCategory(currentindex, toindex);
|
||||
return (true);
|
||||
}
|
||||
|
||||
case ChangePannelOrderActionType: {
|
||||
SARibbonCategory* c = bar->categoryByObjectName(categoryObjNameValue);
|
||||
if (nullptr == c) {
|
||||
return (false);
|
||||
}
|
||||
SARibbonPannel* pannel = c->pannelByObjectName(pannelObjNameValue);
|
||||
if (nullptr == pannel) {
|
||||
return (false);
|
||||
}
|
||||
int pannelIndex = c->pannelIndex(pannel);
|
||||
if (-1 == pannelIndex) {
|
||||
return (false);
|
||||
}
|
||||
c->movePannel(pannelIndex, pannelIndex + indexValue);
|
||||
return (true);
|
||||
}
|
||||
|
||||
case ChangeActionOrderActionType: {
|
||||
SARibbonCategory* c = bar->categoryByObjectName(categoryObjNameValue);
|
||||
if (nullptr == c) {
|
||||
return (false);
|
||||
}
|
||||
SARibbonPannel* pannel = c->pannelByObjectName(pannelObjNameValue);
|
||||
if (nullptr == pannel) {
|
||||
return (false);
|
||||
}
|
||||
QAction* act = mActionsManagerPointer->action(keyValue);
|
||||
if (nullptr == act) {
|
||||
return (false);
|
||||
}
|
||||
int actindex = pannel->actionIndex(act);
|
||||
if (actindex <= -1) {
|
||||
return (false);
|
||||
}
|
||||
pannel->moveAction(actindex, actindex + indexValue);
|
||||
return (true);
|
||||
}
|
||||
|
||||
case RenameCategoryActionType: {
|
||||
SARibbonCategory* c = bar->categoryByObjectName(categoryObjNameValue);
|
||||
if (nullptr == c) {
|
||||
return (false);
|
||||
}
|
||||
c->setCategoryName(keyValue);
|
||||
return (true);
|
||||
}
|
||||
|
||||
case RenamePannelActionType: {
|
||||
SARibbonCategory* c = bar->categoryByObjectName(categoryObjNameValue);
|
||||
if (nullptr == c) {
|
||||
return (false);
|
||||
}
|
||||
SARibbonPannel* pannel = c->pannelByObjectName(pannelObjNameValue);
|
||||
if (nullptr == pannel) {
|
||||
return (false);
|
||||
}
|
||||
pannel->setPannelName(keyValue);
|
||||
return (true);
|
||||
}
|
||||
|
||||
case VisibleCategoryActionType: {
|
||||
SARibbonCategory* c = bar->categoryByObjectName(categoryObjNameValue);
|
||||
if (nullptr == c) {
|
||||
return (false);
|
||||
}
|
||||
if (1 == indexValue) {
|
||||
bar->showCategory(c);
|
||||
} else {
|
||||
bar->hideCategory(c);
|
||||
}
|
||||
return (true);
|
||||
}
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return (false);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 获取actionmanager指针
|
||||
* @return
|
||||
*/
|
||||
SARibbonActionsManager* SARibbonCustomizeData::actionManager()
|
||||
{
|
||||
return (mActionsManagerPointer);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 设置ActionsManager
|
||||
* @param mgr
|
||||
*/
|
||||
void SARibbonCustomizeData::setActionsManager(SARibbonActionsManager* mgr)
|
||||
{
|
||||
mActionsManagerPointer = mgr;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 创建一个AddCategoryActionType的SARibbonCustomizeData
|
||||
* @param title category 的标题
|
||||
* @param index category要插入的位置
|
||||
* @param objName category的object name
|
||||
* @return 返回AddCategoryActionType的SARibbonCustomizeData
|
||||
*/
|
||||
SARibbonCustomizeData SARibbonCustomizeData::makeAddCategoryCustomizeData(const QString& title, int index, const QString& objName)
|
||||
{
|
||||
SARibbonCustomizeData d(AddCategoryActionType);
|
||||
|
||||
d.indexValue = index;
|
||||
d.keyValue = title;
|
||||
d.categoryObjNameValue = objName;
|
||||
return (d);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 创建一个AddPannelActionType的SARibbonCustomizeData
|
||||
* @param title pannel的标题
|
||||
* @param index pannel的index
|
||||
* @param categoryobjName pannel的category的objectname
|
||||
* @param objName pannel的objname
|
||||
* @return 返回AddPannelActionType的SARibbonCustomizeData
|
||||
*/
|
||||
SARibbonCustomizeData SARibbonCustomizeData::makeAddPannelCustomizeData(const QString& title,
|
||||
int index,
|
||||
const QString& categoryobjName,
|
||||
const QString& objName)
|
||||
{
|
||||
SARibbonCustomizeData d(AddPannelActionType);
|
||||
|
||||
d.indexValue = index;
|
||||
d.keyValue = title;
|
||||
d.pannelObjNameValue = objName;
|
||||
d.categoryObjNameValue = categoryobjName;
|
||||
return (d);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 添加action
|
||||
* @param key action的索引
|
||||
* @param mgr action管理器
|
||||
* @param rp 定义action的占位情况
|
||||
* @param categoryObjName action添加到的category的objname
|
||||
* @param pannelObjName action添加到的category下的pannel的objname
|
||||
* @param index action添加到的pannel的索引
|
||||
* @return
|
||||
*/
|
||||
SARibbonCustomizeData SARibbonCustomizeData::makeAddActionCustomizeData(const QString& key,
|
||||
SARibbonActionsManager* mgr,
|
||||
SARibbonPannelItem::RowProportion rp,
|
||||
const QString& categoryObjName,
|
||||
const QString& pannelObjName)
|
||||
{
|
||||
SARibbonCustomizeData d(AddActionActionType, mgr);
|
||||
|
||||
d.keyValue = key;
|
||||
d.categoryObjNameValue = categoryObjName;
|
||||
d.pannelObjNameValue = pannelObjName;
|
||||
d.actionRowProportionValue = rp;
|
||||
|
||||
return (d);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 创建一个RenameCategoryActionType的SARibbonCustomizeData
|
||||
* @param newname 新名字
|
||||
* @param index category的索引
|
||||
* @return 返回RenameCategoryActionType的SARibbonCustomizeData
|
||||
*/
|
||||
SARibbonCustomizeData SARibbonCustomizeData::makeRenameCategoryCustomizeData(const QString& newname,
|
||||
const QString& categoryobjName)
|
||||
{
|
||||
SARibbonCustomizeData d(RenameCategoryActionType);
|
||||
|
||||
if (categoryobjName.isEmpty()) {
|
||||
qDebug() << QObject::tr("SARibbon Warning !!! customize rename category,"
|
||||
"but get an empty category object name,"
|
||||
"if you want to customize SARibbon,"
|
||||
"please make sure every element has been set object name.");
|
||||
}
|
||||
d.keyValue = newname;
|
||||
d.categoryObjNameValue = categoryobjName;
|
||||
return (d);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 创建一个RenamePannelActionType的SARibbonCustomizeData
|
||||
* @param newname pannel的名字
|
||||
* @param indexValue pannel的索引
|
||||
* @param categoryobjName pannel对应的category的object name
|
||||
* @return 返回RenamePannelActionType的SARibbonCustomizeData
|
||||
*/
|
||||
SARibbonCustomizeData SARibbonCustomizeData::makeRenamePannelCustomizeData(const QString& newname,
|
||||
const QString& categoryobjName,
|
||||
const QString& pannelObjName)
|
||||
{
|
||||
SARibbonCustomizeData d(RenamePannelActionType);
|
||||
|
||||
if (pannelObjName.isEmpty() || categoryobjName.isEmpty()) {
|
||||
qDebug() << QObject::tr("SARibbon Warning !!! customize rename pannel,"
|
||||
"but get an empty category/pannel object name,"
|
||||
"if you want to customize SARibbon,"
|
||||
"please make sure every element has been set object name.");
|
||||
}
|
||||
d.keyValue = newname;
|
||||
d.pannelObjNameValue = pannelObjName;
|
||||
d.categoryObjNameValue = categoryobjName;
|
||||
return (d);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 对应ChangeCategoryOrderActionType
|
||||
* @param categoryobjName 需要移动的categoryobjName
|
||||
* @param moveindex 移动位置,-1代表向上(向左)移动一个位置,1带表向下(向右)移动一个位置
|
||||
* @return
|
||||
*/
|
||||
SARibbonCustomizeData SARibbonCustomizeData::makeChangeCategoryOrderCustomizeData(const QString& categoryobjName,
|
||||
int moveindex)
|
||||
{
|
||||
SARibbonCustomizeData d(ChangeCategoryOrderActionType);
|
||||
|
||||
if (categoryobjName.isEmpty()) {
|
||||
qDebug() << QObject::tr("SARibbon Warning !!! customize change category order,"
|
||||
"but get an empty category object name,"
|
||||
"if you want to customize SARibbon,"
|
||||
"please make sure every element has been set object name.");
|
||||
}
|
||||
d.categoryObjNameValue = categoryobjName;
|
||||
d.indexValue = moveindex;
|
||||
return (d);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 对应ChangePannelOrderActionType
|
||||
* @param categoryobjName 需要移动的pannel对应的categoryobjName
|
||||
* @param pannelObjName 需要移动的pannelObjName
|
||||
* @param moveindex 移动位置,-1代表向上(向左)移动一个位置,1带表向下(向右)移动一个位置
|
||||
* @return
|
||||
*/
|
||||
SARibbonCustomizeData SARibbonCustomizeData::makeChangePannelOrderCustomizeData(const QString& categoryobjName,
|
||||
const QString& pannelObjName,
|
||||
int moveindex)
|
||||
{
|
||||
SARibbonCustomizeData d(ChangePannelOrderActionType);
|
||||
|
||||
if (categoryobjName.isEmpty() || pannelObjName.isEmpty()) {
|
||||
qDebug() << QObject::tr("SARibbon Warning !!! customize change pannel order,"
|
||||
"but get an empty category/pannel object name,"
|
||||
"if you want to customize SARibbon,"
|
||||
"please make sure every element has been set object name.");
|
||||
}
|
||||
d.categoryObjNameValue = categoryobjName;
|
||||
d.pannelObjNameValue = pannelObjName;
|
||||
d.indexValue = moveindex;
|
||||
return (d);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 对应ChangeActionOrderActionType
|
||||
* @param categoryobjName 需要移动的pannel对应的categoryobjName
|
||||
* @param pannelObjName 需要移动的pannelObjName
|
||||
* @param key SARibbonActionsManager管理的key名
|
||||
* @param mgr SARibbonActionsManager指针
|
||||
* @param moveindex 移动位置,-1代表向上(向左)移动一个位置,1带表向下(向右)移动一个位置
|
||||
* @return
|
||||
*/
|
||||
SARibbonCustomizeData SARibbonCustomizeData::makeChangeActionOrderCustomizeData(const QString& categoryobjName,
|
||||
const QString& pannelObjName,
|
||||
const QString& key,
|
||||
SARibbonActionsManager* mgr,
|
||||
int moveindex)
|
||||
{
|
||||
SARibbonCustomizeData d(ChangeActionOrderActionType, mgr);
|
||||
|
||||
if (categoryobjName.isEmpty() || pannelObjName.isEmpty() || key.isEmpty()) {
|
||||
qDebug() << QObject::tr("SARibbon Warning !!! customize change action order,"
|
||||
"but get an empty category/pannel/action object name,"
|
||||
"if you want to customize SARibbon,"
|
||||
"please make sure every element has been set object name.");
|
||||
}
|
||||
d.categoryObjNameValue = categoryobjName;
|
||||
d.pannelObjNameValue = pannelObjName;
|
||||
d.keyValue = key;
|
||||
d.indexValue = moveindex;
|
||||
return (d);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 对应RemoveCategoryActionType
|
||||
* @param categoryobjName 需要移除的objname
|
||||
* @return
|
||||
*/
|
||||
SARibbonCustomizeData SARibbonCustomizeData::makeRemoveCategoryCustomizeData(const QString& categoryobjName)
|
||||
{
|
||||
SARibbonCustomizeData d(RemoveCategoryActionType);
|
||||
|
||||
if (categoryobjName.isEmpty()) {
|
||||
qDebug() << QObject::tr("SARibbon Warning !!! customize remove category,"
|
||||
"but get an empty category object name,"
|
||||
"if you want to customize SARibbon,"
|
||||
"please make sure every element has been set object name.");
|
||||
}
|
||||
d.categoryObjNameValue = categoryobjName;
|
||||
return (d);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 对应RemovePannelActionType
|
||||
* @param categoryobjName pannel对应的category的obj name
|
||||
* @param pannelObjName pannel对应的 obj name
|
||||
* @return
|
||||
*/
|
||||
SARibbonCustomizeData SARibbonCustomizeData::makeRemovePannelCustomizeData(const QString& categoryobjName,
|
||||
const QString& pannelObjName)
|
||||
{
|
||||
SARibbonCustomizeData d(RemovePannelActionType);
|
||||
|
||||
if (categoryobjName.isEmpty() || pannelObjName.isEmpty()) {
|
||||
qDebug() << QObject::tr("SARibbon Warning !!! customize remove pannel,"
|
||||
"but get an empty category/pannel object name,"
|
||||
"if you want to customize SARibbon,"
|
||||
"please make sure every element has been set object name.");
|
||||
}
|
||||
d.categoryObjNameValue = categoryobjName;
|
||||
d.pannelObjNameValue = pannelObjName;
|
||||
return (d);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 对应RemoveActionActionType
|
||||
* @param categoryobjName pannel对应的category的obj name
|
||||
* @param pannelObjName pannel对应的 obj name
|
||||
* @param key SARibbonActionsManager管理的key名
|
||||
* @param mgr SARibbonActionsManager指针
|
||||
* @return
|
||||
*/
|
||||
SARibbonCustomizeData SARibbonCustomizeData::makeRemoveActionCustomizeData(const QString& categoryobjName,
|
||||
const QString& pannelObjName,
|
||||
const QString& key,
|
||||
SARibbonActionsManager* mgr)
|
||||
{
|
||||
SARibbonCustomizeData d(RemoveActionActionType, mgr);
|
||||
|
||||
if (categoryobjName.isEmpty() || pannelObjName.isEmpty() || key.isEmpty()) {
|
||||
qDebug() << QObject::tr("SARibbon Warning !!! customize remove action,"
|
||||
"but get an empty category/pannel/action object name,"
|
||||
"if you want to customize SARibbon,"
|
||||
"please make sure every element has been set object name.");
|
||||
}
|
||||
d.categoryObjNameValue = categoryobjName;
|
||||
d.pannelObjNameValue = pannelObjName;
|
||||
d.keyValue = key;
|
||||
return (d);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief SARibbonCustomizeData::makeVisibleCategoryCustomizeData
|
||||
* @param categoryobjName
|
||||
* @param isShow
|
||||
* @return
|
||||
*/
|
||||
SARibbonCustomizeData SARibbonCustomizeData::makeVisibleCategoryCustomizeData(const QString& categoryobjName, bool isShow)
|
||||
{
|
||||
SARibbonCustomizeData d(VisibleCategoryActionType);
|
||||
|
||||
if (categoryobjName.isEmpty()) {
|
||||
qDebug() << QObject::tr("SARibbon Warning !!! customize visible category,"
|
||||
"but get an empty category object name,"
|
||||
"if you want to customize SARibbon,"
|
||||
"please make sure every element has been set object name.");
|
||||
}
|
||||
d.categoryObjNameValue = categoryobjName;
|
||||
d.indexValue = isShow ? 1 : 0;
|
||||
return (d);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 判断外置属性,是否允许自定义
|
||||
* @param obj
|
||||
* @return
|
||||
*/
|
||||
bool SARibbonCustomizeData::isCanCustomize(QObject* obj)
|
||||
{
|
||||
QVariant v = obj->property(SA_RIBBON_BAR_PROP_CAN_CUSTOMIZE);
|
||||
|
||||
if (v.isValid()) {
|
||||
return (v.toBool());
|
||||
}
|
||||
return (false);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 设置外置属性允许自定义
|
||||
* @param obj
|
||||
* @param canbe
|
||||
*/
|
||||
void SARibbonCustomizeData::setCanCustomize(QObject* obj, bool canbe)
|
||||
{
|
||||
obj->setProperty(SA_RIBBON_BAR_PROP_CAN_CUSTOMIZE, canbe);
|
||||
}
|
||||
|
||||
QList< SARibbonCustomizeData > remove_indexs(const QList< SARibbonCustomizeData >& csd, const QList< int >& willremoveIndex);
|
||||
|
||||
QList< SARibbonCustomizeData > remove_indexs(const QList< SARibbonCustomizeData >& csd, const QList< int >& willremoveIndex)
|
||||
{
|
||||
QList< SARibbonCustomizeData > res;
|
||||
|
||||
for (int i = 0; i < csd.size(); ++i) {
|
||||
if (!willremoveIndex.contains(i)) {
|
||||
res << csd[ i ];
|
||||
}
|
||||
}
|
||||
return (res);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 对QList<SARibbonCustomizeData>进行简化操作
|
||||
*
|
||||
* 此函数会执行如下操作:
|
||||
* 1、针对同一个category/pannel连续出现的添加和删除操作进行移除(前一步添加,后一步删除)
|
||||
*
|
||||
* 2、针对VisibleCategoryActionType,对于连续出现的操作只保留最后一步
|
||||
*
|
||||
* 3、针对RenameCategoryActionType和RenamePannelActionType操作,只保留最后一个
|
||||
*
|
||||
* 4、针对连续的ChangeCategoryOrderActionType,ChangePannelOrderActionType,ChangeActionOrderActionType进行合并为一个动作,
|
||||
* 如果合并后原地不动,则删除
|
||||
*
|
||||
* @param csd
|
||||
* @return 返回简化的QList<SARibbonCustomizeData>
|
||||
*/
|
||||
QList< SARibbonCustomizeData > SARibbonCustomizeData::simplify(const QList< SARibbonCustomizeData >& csd)
|
||||
{
|
||||
int size = csd.size();
|
||||
|
||||
if (size <= 1) {
|
||||
return (csd);
|
||||
}
|
||||
QList< SARibbonCustomizeData > res;
|
||||
QList< int > willremoveIndex; // 记录要删除的index
|
||||
|
||||
//! 首先针对连续出现的添加和删除操作进行优化
|
||||
for (int i = 1; i < size; ++i) {
|
||||
if ((csd[ i - 1 ].actionType() == AddCategoryActionType) && (csd[ i ].actionType() == RemoveCategoryActionType)) {
|
||||
if (csd[ i - 1 ].categoryObjNameValue == csd[ i ].categoryObjNameValue) {
|
||||
willremoveIndex << i - 1 << i;
|
||||
}
|
||||
} else if ((csd[ i - 1 ].actionType() == AddPannelActionType) && (csd[ i ].actionType() == RemovePannelActionType)) {
|
||||
if ((csd[ i - 1 ].pannelObjNameValue == csd[ i ].pannelObjNameValue)
|
||||
&& (csd[ i - 1 ].categoryObjNameValue == csd[ i ].categoryObjNameValue)) {
|
||||
willremoveIndex << i - 1 << i;
|
||||
}
|
||||
} else if ((csd[ i - 1 ].actionType() == AddActionActionType) && (csd[ i ].actionType() == RemoveActionActionType)) {
|
||||
if ((csd[ i - 1 ].keyValue == csd[ i ].keyValue)
|
||||
&& (csd[ i - 1 ].pannelObjNameValue == csd[ i ].pannelObjNameValue)
|
||||
&& (csd[ i - 1 ].categoryObjNameValue == csd[ i ].categoryObjNameValue)) {
|
||||
willremoveIndex << i - 1 << i;
|
||||
}
|
||||
}
|
||||
}
|
||||
res = remove_indexs(csd, willremoveIndex);
|
||||
willremoveIndex.clear();
|
||||
|
||||
//! 筛选VisibleCategoryActionType,对于连续出现的操作只保留最后一步
|
||||
size = res.size();
|
||||
for (int i = 1; i < size; ++i) {
|
||||
if ((res[ i - 1 ].actionType() == VisibleCategoryActionType)
|
||||
&& (res[ i ].actionType() == VisibleCategoryActionType)) {
|
||||
if (res[ i - 1 ].categoryObjNameValue == res[ i ].categoryObjNameValue) {
|
||||
// 要保证操作的是同一个内容
|
||||
willremoveIndex << i - 1; // 删除前一个只保留最后一个
|
||||
}
|
||||
}
|
||||
}
|
||||
res = remove_indexs(res, willremoveIndex);
|
||||
willremoveIndex.clear();
|
||||
|
||||
//! 针对RenameCategoryActionType和RenamePannelActionType操作,只需保留最后一个
|
||||
size = res.size();
|
||||
for (int i = 0; i < size; ++i) {
|
||||
if (res[ i ].actionType() == RenameCategoryActionType) {
|
||||
// 向后查询,如果查询到有同一个Category改名,把这个索引加入删除队列
|
||||
for (int j = i + 1; j < size; ++j) {
|
||||
if ((res[ j ].actionType() == RenameCategoryActionType)
|
||||
&& (res[ i ].categoryObjNameValue == res[ j ].categoryObjNameValue)) {
|
||||
willremoveIndex << i;
|
||||
}
|
||||
}
|
||||
} else if (res[ i ].actionType() == RenamePannelActionType) {
|
||||
// 向后查询,如果查询到有同一个pannel改名,把这个索引加入删除队列
|
||||
for (int j = i + 1; j < size; ++j) {
|
||||
if ((res[ j ].actionType() == RenamePannelActionType)
|
||||
&& (res[ i ].pannelObjNameValue == res[ j ].pannelObjNameValue)
|
||||
&& (res[ i ].categoryObjNameValue == res[ j ].categoryObjNameValue)) {
|
||||
willremoveIndex << i;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
res = remove_indexs(res, willremoveIndex);
|
||||
willremoveIndex.clear();
|
||||
|
||||
//! 针对连续的ChangeCategoryOrderActionType,ChangePannelOrderActionType,ChangeActionOrderActionType进行合并
|
||||
size = res.size();
|
||||
for (int i = 1; i < size; ++i) {
|
||||
if ((res[ i - 1 ].actionType() == ChangeCategoryOrderActionType)
|
||||
&& (res[ i ].actionType() == ChangeCategoryOrderActionType)
|
||||
&& (res[ i - 1 ].categoryObjNameValue == res[ i ].categoryObjNameValue)) {
|
||||
// 说明连续两个顺序调整,把前一个indexvalue和后一个indexvalue相加,前一个删除
|
||||
res[ i ].indexValue += res[ i - 1 ].indexValue;
|
||||
willremoveIndex << i - 1;
|
||||
} else if ((res[ i - 1 ].actionType() == ChangePannelOrderActionType)
|
||||
&& (res[ i ].actionType() == ChangePannelOrderActionType)
|
||||
&& (res[ i - 1 ].pannelObjNameValue == res[ i ].pannelObjNameValue)
|
||||
&& (res[ i - 1 ].categoryObjNameValue == res[ i ].categoryObjNameValue)) {
|
||||
// 说明连续两个顺序调整,把前一个indexvalue和后一个indexvalue相加,前一个删除
|
||||
res[ i ].indexValue += res[ i - 1 ].indexValue;
|
||||
willremoveIndex << i - 1;
|
||||
} else if ((res[ i - 1 ].actionType() == ChangeActionOrderActionType)
|
||||
&& (res[ i ].actionType() == ChangeActionOrderActionType) && (res[ i - 1 ].keyValue == res[ i ].keyValue)
|
||||
&& (res[ i - 1 ].pannelObjNameValue == res[ i ].pannelObjNameValue)
|
||||
&& (res[ i - 1 ].categoryObjNameValue == res[ i ].categoryObjNameValue)) {
|
||||
// 说明连续两个顺序调整,把前一个indexvalue和后一个indexvalue相加,前一个删除
|
||||
res[ i ].indexValue += res[ i - 1 ].indexValue;
|
||||
willremoveIndex << i - 1;
|
||||
}
|
||||
}
|
||||
res = remove_indexs(res, willremoveIndex);
|
||||
willremoveIndex.clear();
|
||||
|
||||
//! 上一步操作可能会产生indexvalue为0的情况,此操作把indexvalue为0的删除
|
||||
size = res.size();
|
||||
for (int i = 0; i < size; ++i) {
|
||||
if ((res[ i ].actionType() == ChangeCategoryOrderActionType) || (res[ i ].actionType() == ChangePannelOrderActionType)
|
||||
|| (res[ i ].actionType() == ChangeActionOrderActionType)) {
|
||||
if (0 == res[ i ].indexValue) {
|
||||
willremoveIndex << i;
|
||||
}
|
||||
}
|
||||
}
|
||||
res = remove_indexs(res, willremoveIndex);
|
||||
willremoveIndex.clear();
|
||||
return (res);
|
||||
}
|
||||
@@ -0,0 +1,152 @@
|
||||
#ifndef SARIBBONCUSTOMIZEDATA_H
|
||||
#define SARIBBONCUSTOMIZEDATA_H
|
||||
#include "SARibbonGlobal.h"
|
||||
#include "SARibbonActionsManager.h"
|
||||
#include "SARibbonPannel.h"
|
||||
#include <QList>
|
||||
class SARibbonBar;
|
||||
class SARibbonMainWindow;
|
||||
|
||||
/**
|
||||
* @brief 记录所有自定义操作的数据类
|
||||
* @note 此数据依赖于@ref SARibbonActionsManager 要在SARibbonActionsManager之后使用此类
|
||||
*/
|
||||
class SA_RIBBON_EXPORT SARibbonCustomizeData
|
||||
{
|
||||
public:
|
||||
enum ActionType
|
||||
{
|
||||
UnknowActionType = 0, ///< 未知操作
|
||||
AddCategoryActionType, ///< 添加category操作(1)
|
||||
AddPannelActionType, ///< 添加pannel操作(2)
|
||||
AddActionActionType, ///< 添加action操作(3)
|
||||
RemoveCategoryActionType, ///< 删除category操作(4)
|
||||
RemovePannelActionType, ///< 删除pannel操作(5)
|
||||
RemoveActionActionType, ///< 删除action操作(6)
|
||||
ChangeCategoryOrderActionType, ///< 改变category顺序的操作(7)
|
||||
ChangePannelOrderActionType, ///< 改变pannel顺序的操作(8)
|
||||
ChangeActionOrderActionType, ///< 改变action顺序的操作(9)
|
||||
RenameCategoryActionType, ///< 对category更名操作(10)
|
||||
RenamePannelActionType, ///< 对Pannel更名操作(11)
|
||||
VisibleCategoryActionType ///< 对category执行隐藏/显示操作(12)
|
||||
};
|
||||
SARibbonCustomizeData();
|
||||
SARibbonCustomizeData(ActionType type, SARibbonActionsManager* mgr = nullptr);
|
||||
// 获取CustomizeData的action type
|
||||
ActionType actionType() const;
|
||||
|
||||
// 设置CustomizeData的action type
|
||||
void setActionType(ActionType a);
|
||||
|
||||
// 判断是否是一个正常的CustomizeData
|
||||
bool isValid() const;
|
||||
|
||||
// 应用SARibbonCustomizeData
|
||||
bool apply(SARibbonBar* bar) const;
|
||||
|
||||
// 获取actionmanager指针
|
||||
SARibbonActionsManager* actionManager();
|
||||
|
||||
// 设置ActionsManager
|
||||
void setActionsManager(SARibbonActionsManager* mgr);
|
||||
|
||||
// 对应AddCategoryActionType
|
||||
static SARibbonCustomizeData makeAddCategoryCustomizeData(const QString& title, int index, const QString& objName);
|
||||
|
||||
// 对应AddPannelActionType
|
||||
static SARibbonCustomizeData makeAddPannelCustomizeData(const QString& title,
|
||||
int index,
|
||||
const QString& categoryobjName,
|
||||
const QString& objName);
|
||||
|
||||
// 对应AddActionActionType
|
||||
static SARibbonCustomizeData makeAddActionCustomizeData(const QString& key,
|
||||
SARibbonActionsManager* mgr,
|
||||
SARibbonPannelItem::RowProportion rp,
|
||||
const QString& categoryObjName,
|
||||
const QString& pannelObjName);
|
||||
|
||||
// 对应RenameCategoryActionType
|
||||
static SARibbonCustomizeData makeRenameCategoryCustomizeData(const QString& newname, const QString& categoryobjName);
|
||||
|
||||
// 对应RenamePannelActionType
|
||||
static SARibbonCustomizeData makeRenamePannelCustomizeData(const QString& newname,
|
||||
const QString& categoryobjName,
|
||||
const QString& pannelObjName);
|
||||
|
||||
// 对应RemoveCategoryActionType
|
||||
static SARibbonCustomizeData makeRemoveCategoryCustomizeData(const QString& categoryobjName);
|
||||
|
||||
// 对应ChangeCategoryOrderActionType
|
||||
static SARibbonCustomizeData makeChangeCategoryOrderCustomizeData(const QString& categoryobjName, int moveindex);
|
||||
|
||||
// 对应ChangePannelOrderActionType
|
||||
static SARibbonCustomizeData makeChangePannelOrderCustomizeData(const QString& categoryobjName,
|
||||
const QString& pannelObjName,
|
||||
int moveindex);
|
||||
|
||||
// 对应ChangeActionOrderActionType
|
||||
static SARibbonCustomizeData makeChangeActionOrderCustomizeData(const QString& categoryobjName,
|
||||
const QString& pannelObjName,
|
||||
const QString& key,
|
||||
SARibbonActionsManager* mgr,
|
||||
int moveindex);
|
||||
|
||||
// 对应RemovePannelActionType
|
||||
static SARibbonCustomizeData makeRemovePannelCustomizeData(const QString& categoryobjName, const QString& pannelObjName);
|
||||
|
||||
// 对应RemoveActionActionType
|
||||
static SARibbonCustomizeData makeRemoveActionCustomizeData(const QString& categoryobjName,
|
||||
const QString& pannelObjName,
|
||||
const QString& key,
|
||||
SARibbonActionsManager* mgr);
|
||||
|
||||
// 对应VisibleCategoryActionType
|
||||
static SARibbonCustomizeData makeVisibleCategoryCustomizeData(const QString& categoryobjName, bool isShow);
|
||||
|
||||
// 判断是否可以自定义,如果某个action不想被编辑,可以通过此函数设置
|
||||
static bool isCanCustomize(QObject* obj);
|
||||
static void setCanCustomize(QObject* obj, bool canbe = true);
|
||||
|
||||
// 对QList<SARibbonCustomizeData>进行简化
|
||||
static QList< SARibbonCustomizeData > simplify(const QList< SARibbonCustomizeData >& csd);
|
||||
|
||||
public:
|
||||
/**
|
||||
* @brief 记录顺序的参数
|
||||
*
|
||||
* 在actionType==AddCategoryActionType时,此参数记录Category的insert位置,
|
||||
* 在actionType==AddPannelActionType时,此参数记录pannel的insert位置,
|
||||
* 在actionType==AddActionActionType时,此参数记录pannel的insert位置
|
||||
*/
|
||||
int indexValue;
|
||||
|
||||
/**
|
||||
* @brief 记录标题、索引等参数
|
||||
*
|
||||
* 在actionType==AddCategoryActionType时,key为category标题,
|
||||
* 在actionType==AddPannelActionType时,key为pannel标题,
|
||||
* 在actionType==AddActionActionType时,key为action的查询依据,基于SARibbonActionsManager::action查询
|
||||
*/
|
||||
QString keyValue;
|
||||
|
||||
/**
|
||||
* @brief 记录categoryObjName,用于定位Category
|
||||
*/
|
||||
QString categoryObjNameValue;
|
||||
|
||||
/**
|
||||
* @brief 记录pannelObjName,saribbon的Customize索引大部分基于objname
|
||||
*/
|
||||
QString pannelObjNameValue;
|
||||
|
||||
SARibbonPannelItem::RowProportion actionRowProportionValue; ///< 行的占比,ribbon中有large,media和small三种占比,见@ref RowProportion
|
||||
private:
|
||||
ActionType mType; ///< 标记这个data是category还是pannel亦或是action
|
||||
SARibbonActionsManager* mActionsManagerPointer;
|
||||
};
|
||||
Q_DECLARE_METATYPE(SARibbonCustomizeData)
|
||||
|
||||
typedef QList< SARibbonCustomizeData > SARibbonCustomizeDataList;
|
||||
|
||||
#endif // SARIBBONCUSTOMIZEDATA_H
|
||||
@@ -0,0 +1,187 @@
|
||||
#include "SARibbonCustomizeDialog.h"
|
||||
#include <QApplication>
|
||||
#include <QPushButton>
|
||||
#include <QVBoxLayout>
|
||||
#include <QSpacerItem>
|
||||
|
||||
/**
|
||||
* @brief The SARibbonCustomizeDialogUi class
|
||||
*/
|
||||
class SARibbonCustomizeDialogUi {
|
||||
public:
|
||||
SARibbonCustomizeWidget *customWidget;
|
||||
QVBoxLayout *verticalLayoutMain;
|
||||
QHBoxLayout *horizontalLayoutButtonGroup;
|
||||
QPushButton *pushButtonCancel;
|
||||
QPushButton *pushButtonOk;
|
||||
QSpacerItem *spacerItemleft;
|
||||
void setupUi(SARibbonMainWindow *ribbonWindow, QWidget *customizeDialog)
|
||||
{
|
||||
if (customizeDialog->objectName().isEmpty()) {
|
||||
customizeDialog->setObjectName(QStringLiteral("SARibbonCustomizeDialog"));
|
||||
}
|
||||
customizeDialog->resize(800, 600);
|
||||
verticalLayoutMain = new QVBoxLayout(customizeDialog);
|
||||
verticalLayoutMain->setObjectName(QStringLiteral("verticalLayoutMain"));
|
||||
|
||||
customWidget = new SARibbonCustomizeWidget(ribbonWindow, customizeDialog);
|
||||
customWidget->setObjectName(QStringLiteral("customWidget"));
|
||||
verticalLayoutMain->addWidget(customWidget);
|
||||
|
||||
horizontalLayoutButtonGroup = new QHBoxLayout();
|
||||
horizontalLayoutButtonGroup->setObjectName(QStringLiteral("horizontalLayoutButtonGroup"));
|
||||
|
||||
spacerItemleft = new QSpacerItem(40, 20, QSizePolicy::Expanding, QSizePolicy::Minimum);
|
||||
horizontalLayoutButtonGroup->addItem(spacerItemleft);
|
||||
|
||||
pushButtonCancel = new QPushButton(customizeDialog);
|
||||
pushButtonCancel->setObjectName(QStringLiteral("pushButtonCancel"));
|
||||
horizontalLayoutButtonGroup->addWidget(pushButtonCancel);
|
||||
|
||||
pushButtonOk = new QPushButton(customizeDialog);
|
||||
pushButtonOk->setObjectName(QStringLiteral("pushButtonCancel"));
|
||||
horizontalLayoutButtonGroup->addWidget(pushButtonOk);
|
||||
verticalLayoutMain->addItem(horizontalLayoutButtonGroup);
|
||||
retranslateUi(customizeDialog);
|
||||
}
|
||||
|
||||
|
||||
void retranslateUi(QWidget *customizeDialog)
|
||||
{
|
||||
customizeDialog->setWindowTitle(QApplication::translate("SARibbonCustomizeDialog", "Customize Dialog", Q_NULLPTR));
|
||||
pushButtonCancel->setText(QApplication::translate("SARibbonCustomizeDialog", "Cancel", Q_NULLPTR));
|
||||
pushButtonOk->setText(QApplication::translate("SARibbonCustomizeDialog", "OK", Q_NULLPTR));
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
|
||||
SARibbonCustomizeDialog::SARibbonCustomizeDialog(SARibbonMainWindow *ribbonWindow, QWidget *p, Qt::WindowFlags f)
|
||||
: QDialog(p, f)
|
||||
, ui(new SARibbonCustomizeDialogUi)
|
||||
{
|
||||
ui->setupUi(ribbonWindow, this);
|
||||
initConnection();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief 设置action管理器
|
||||
*
|
||||
* 等同@ref SARibbonCustomizeWidget::setupActionsManager
|
||||
* @param mgr
|
||||
*/
|
||||
SARibbonCustomizeDialog::~SARibbonCustomizeDialog()
|
||||
{
|
||||
}
|
||||
void SARibbonCustomizeDialog::setupActionsManager(SARibbonActionsManager *mgr)
|
||||
{
|
||||
ui->customWidget->setupActionsManager(mgr);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief //判断用户是否有要存储的内容,对应save动作
|
||||
* @return
|
||||
*/
|
||||
bool SARibbonCustomizeDialog::isApplied() const
|
||||
{
|
||||
return ui->customWidget->isApplied();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 判断用户是否有改动内容,对应apply动作
|
||||
* @return
|
||||
*/
|
||||
bool SARibbonCustomizeDialog::isCached() const
|
||||
{
|
||||
return ui->customWidget->isCached();
|
||||
}
|
||||
|
||||
|
||||
void SARibbonCustomizeDialog::initConnection()
|
||||
{
|
||||
connect(ui->pushButtonOk, &QPushButton::clicked, this, &QDialog::accept);
|
||||
connect(ui->pushButtonCancel, &QPushButton::clicked, this, &QDialog::reject);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief 等同SARibbonCustomizeWidget::applys
|
||||
*
|
||||
* @ref SARibbonCustomizeWidget::applys
|
||||
* @return
|
||||
*/
|
||||
bool SARibbonCustomizeDialog::applys()
|
||||
{
|
||||
return ui->customWidget->applys();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief 清除所有动作
|
||||
*
|
||||
* @ref SARibbonCustomizeWidget::clear
|
||||
*/
|
||||
void SARibbonCustomizeDialog::clear()
|
||||
{
|
||||
ui->customWidget->clear();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief 转换为xml
|
||||
*
|
||||
* @ref SARibbonCustomizeWidget::toXml
|
||||
* @param xml
|
||||
* @return
|
||||
*/
|
||||
bool SARibbonCustomizeDialog::toXml(QXmlStreamWriter *xml) const
|
||||
{
|
||||
return (ui->customWidget->toXml(xml));
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief 等同SARibbonCustomizeWidget::toXml
|
||||
* @ref SARibbonCustomizeWidget::toXml
|
||||
* @param xmlpath
|
||||
* @return
|
||||
*/
|
||||
bool SARibbonCustomizeDialog::toXml(const QString& xmlpath) const
|
||||
{
|
||||
return (ui->customWidget->toXml(xmlpath));
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief 等同SARibbonCustomizeWidget::fromXml
|
||||
* @param xml
|
||||
*/
|
||||
void SARibbonCustomizeDialog::fromXml(QXmlStreamReader *xml)
|
||||
{
|
||||
ui->customWidget->fromXml(xml);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief 等同SARibbonCustomizeWidget::fromXml
|
||||
* @param xmlpath
|
||||
*/
|
||||
void SARibbonCustomizeDialog::fromXml(const QString& xmlpath)
|
||||
{
|
||||
ui->customWidget->fromXml(xmlpath);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief 返回SARibbonCustomizeWidget窗口指针
|
||||
*
|
||||
* 通过SARibbonCustomizeWidget窗口可以操作更多的内容
|
||||
*
|
||||
* @return SARibbonCustomizeWidget指针,参考@ref SARibbonCustomizeWidget
|
||||
*/
|
||||
SARibbonCustomizeWidget *SARibbonCustomizeDialog::customizeWidget() const
|
||||
{
|
||||
return (ui->customWidget);
|
||||
}
|
||||
@@ -0,0 +1,58 @@
|
||||
#ifndef SARIBBONCUSTOMIZEDIALOG_H
|
||||
#define SARIBBONCUSTOMIZEDIALOG_H
|
||||
#include "SARibbonGlobal.h"
|
||||
#include <QDialog>
|
||||
#include "SARibbonCustomizeWidget.h"
|
||||
class SARibbonActionsManager;
|
||||
class SARibbonCustomizeDialogUi;
|
||||
class QXmlStreamWriter;
|
||||
|
||||
|
||||
/**
|
||||
* @brief SARibbonCustomizeWidget的对话框封装
|
||||
*
|
||||
* 此功能依赖于@ref SARibbonActionsManager ,SARibbonActionsManager建议作为mianwindow的成员变量,
|
||||
* SARibbonActionsManager可以快速绑定所有QAction,详细见SARibbonActionsManager的说明
|
||||
*
|
||||
* @note SARibbon的自定义是基于步骤的,如果在窗口生成前调用了@ref sa_apply_customize_from_xml_file 类似函数
|
||||
* 那么在对话框生成前为了保证同步需要调用@ref SARibbonCustomizeDialog::fromXml 同步配置文件,这样再次修改后的配置文件就一致
|
||||
*/
|
||||
class SA_RIBBON_EXPORT SARibbonCustomizeDialog : public QDialog
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit SARibbonCustomizeDialog(SARibbonMainWindow *ribbonWindow, QWidget *p = nullptr, Qt::WindowFlags f = Qt::WindowFlags());
|
||||
~SARibbonCustomizeDialog();
|
||||
//设置action管理器
|
||||
void setupActionsManager(SARibbonActionsManager *mgr);
|
||||
|
||||
//判断用户是否有要存储的内容,对应save动作
|
||||
bool isApplied() const;
|
||||
|
||||
//判断用户是否有改动内容,对应apply动作
|
||||
bool isCached() const;
|
||||
|
||||
//应用所有的设定
|
||||
bool applys();
|
||||
|
||||
//清除所有动作
|
||||
void clear();
|
||||
|
||||
//转换为xml
|
||||
bool toXml(QXmlStreamWriter *xml) const;
|
||||
bool toXml(const QString& xmlpath) const;
|
||||
|
||||
//从xml中加载QList<SARibbonCustomizeData>,对于基于配置文件的设置,对话框显示前建议调用此函数,保证叠加设置的正确记录
|
||||
void fromXml(QXmlStreamReader *xml);
|
||||
void fromXml(const QString& xmlpath);
|
||||
|
||||
//返回SARibbonCustomizeWidget窗口指针
|
||||
SARibbonCustomizeWidget *customizeWidget() const;
|
||||
|
||||
private:
|
||||
void initConnection();
|
||||
|
||||
SARibbonCustomizeDialogUi *ui;
|
||||
};
|
||||
|
||||
#endif // SARIBBONCUSTOMIZEDIALOG_H
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,209 @@
|
||||
#ifndef SARIBBONCUSTOMIZEWIDGET_H
|
||||
#define SARIBBONCUSTOMIZEWIDGET_H
|
||||
#include "SARibbonGlobal.h"
|
||||
#include <QWidget>
|
||||
#include "SARibbonActionsManager.h"
|
||||
#include "SARibbonPannel.h"
|
||||
#include "SARibbonCustomizeData.h"
|
||||
|
||||
// SARibbonCustomizeWidget 特有
|
||||
class SARibbonCustomizeWidgetUi;
|
||||
class SARibbonMainWindow;
|
||||
class SARibbonBar;
|
||||
//
|
||||
class QStandardItemModel;
|
||||
class QStandardItem;
|
||||
class QAbstractButton;
|
||||
//
|
||||
class QXmlStreamWriter;
|
||||
class QXmlStreamReader;
|
||||
|
||||
/**
|
||||
* @brief 自定义界面窗口
|
||||
*
|
||||
* @note SARibbon的自定义是基于步骤的,如果在窗口生成前调用了@ref sa_apply_customize_from_xml_file 类似函数
|
||||
* 那么在对话框生成前为了保证同步需要调用@ref SARibbonCustomizeWidget::fromXml 同步配置文件,这样再次修改后的配置文件就一致
|
||||
*/
|
||||
class SA_RIBBON_EXPORT SARibbonCustomizeWidget : public QWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
SA_RIBBON_DECLARE_PRIVATE(SARibbonCustomizeWidget)
|
||||
public:
|
||||
//保留接口
|
||||
explicit SARibbonCustomizeWidget(SARibbonMainWindow* ribbonWindow, QWidget* parent = nullptr, Qt::WindowFlags f = Qt::WindowFlags());
|
||||
//对于不使用SARibbonMainWindow的情况,使用此构造函数
|
||||
explicit SARibbonCustomizeWidget(SARibbonBar* ribbonbar, QWidget* parent = nullptr, Qt::WindowFlags f = Qt::WindowFlags());
|
||||
~SARibbonCustomizeWidget();
|
||||
|
||||
/**
|
||||
* @brief 定义ribbon树的显示类型
|
||||
*/
|
||||
enum RibbonTreeShowType
|
||||
{
|
||||
ShowAllCategory, ///< 显示所有Category,包括contextcategory
|
||||
ShowMainCategory ///< 显示主要的category,不包含上下文
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief QStandardItem对应的role
|
||||
*/
|
||||
enum ItemRole
|
||||
{
|
||||
LevelRole = Qt::UserRole + 1, ///< 代表这是层级,有0:category 1:pannel 2:item
|
||||
PointerRole = Qt::UserRole + 2, ///< 代表这是存放指针。根据LevelRole来进行转
|
||||
CanCustomizeRole = Qt::UserRole + 3, ///< 代表个item是可以自定义的.bool
|
||||
CustomizeRole = Qt::UserRole + 4, ///< 代表这个是自定义的item,bool,主要用于那些自己添加的标签和pannel,有此角色必有CanCustomizeRole
|
||||
CustomizeObjNameRole = Qt::UserRole + 5 ///< 记录了临时的自定义内容的obj名 QString
|
||||
};
|
||||
|
||||
//设置action管理器
|
||||
void setupActionsManager(SARibbonActionsManager* mgr);
|
||||
|
||||
//判断用户是否有要存储的内容,对应save动作
|
||||
bool isApplied() const;
|
||||
|
||||
//判断用户是否有改动内容,对应apply动作
|
||||
bool isCached() const;
|
||||
|
||||
//获取model
|
||||
const QStandardItemModel* model() const;
|
||||
|
||||
//根据当前的radiobutton选项来更新model
|
||||
void updateModel();
|
||||
|
||||
//更新model
|
||||
void updateModel(RibbonTreeShowType type);
|
||||
|
||||
//应用所有的设定
|
||||
bool applys();
|
||||
|
||||
//转换为xml
|
||||
bool toXml(QXmlStreamWriter* xml) const;
|
||||
bool toXml(const QString& xmlpath) const;
|
||||
|
||||
//从xml中加载QList<SARibbonCustomizeData>,对于基于配置文件的设置,对话框显示前建议调用此函数,保证叠加设置的正确记录
|
||||
void fromXml(QXmlStreamReader* xml);
|
||||
void fromXml(const QString& xmlpath);
|
||||
|
||||
//应用xml配置,可以结合customize_datas_from_xml和customize_datas_apply函数
|
||||
static bool fromXml(QXmlStreamReader* xml, SARibbonBar* bar, SARibbonActionsManager* mgr);
|
||||
|
||||
//缓存应用的动作,这些动作不会被clear清除,用于本地存储
|
||||
void makeActionsApplied();
|
||||
|
||||
//清除applied的动作,cancel操作后需要清空已应用的动作
|
||||
void clearApplied();
|
||||
//清除缓存动作,在执行applys函数后,如果要继续调用,应该clear,否则会导致异常
|
||||
void clearCache();
|
||||
//清除所有动作,不包含本地读取的数据
|
||||
void clear();
|
||||
|
||||
protected:
|
||||
//把QList<SARibbonCustomizeData>进行裁剪,把一些动作合并
|
||||
void simplify();
|
||||
|
||||
SARibbonPannelItem::RowProportion selectedRowProportion() const;
|
||||
|
||||
QAction* selectedAction() const;
|
||||
QAction* itemToAction(QStandardItem* item) const;
|
||||
|
||||
QStandardItem* selectedItem() const;
|
||||
|
||||
//获取选中的ribbon tree 的level
|
||||
int selectedRibbonLevel() const;
|
||||
|
||||
//根据选中的item判断
|
||||
int itemLevel(QStandardItem* item) const;
|
||||
|
||||
//设置某个item被选中
|
||||
void setSelectItem(QStandardItem* item, bool ensureVisible = true);
|
||||
|
||||
//判断itemn能否改动,可以改动返回true
|
||||
bool isItemCanCustomize(QStandardItem* item) const;
|
||||
bool isSelectedItemCanCustomize() const;
|
||||
|
||||
//判断item是否是自定义的item
|
||||
bool isCustomizeItem(QStandardItem* item) const;
|
||||
bool isSelectedItemIsCustomize() const;
|
||||
|
||||
//删除一个item
|
||||
void removeItem(QStandardItem* item);
|
||||
|
||||
private Q_SLOTS:
|
||||
void onComboBoxActionIndexCurrentIndexChanged(int index);
|
||||
void onRadioButtonGroupButtonClicked(QAbstractButton* b);
|
||||
void onPushButtonNewCategoryClicked();
|
||||
void onPushButtonNewPannelClicked();
|
||||
void onPushButtonRenameClicked();
|
||||
void onPushButtonAddClicked();
|
||||
void onPushButtonDeleteClicked();
|
||||
void onListViewSelectClicked(const QModelIndex& index);
|
||||
void onTreeViewResultClicked(const QModelIndex& index);
|
||||
void onToolButtonUpClicked();
|
||||
void onToolButtonDownClicked();
|
||||
void onItemChanged(QStandardItem* item);
|
||||
void onLineEditSearchActionTextEdited(const QString& text);
|
||||
void onPushButtonResetClicked();
|
||||
|
||||
private:
|
||||
void init(SARibbonBar* ribbonbar);
|
||||
void initConnection();
|
||||
|
||||
private:
|
||||
SARibbonCustomizeWidgetUi* ui;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief 转换为xml
|
||||
*
|
||||
* 此函数仅会写element,不会写document相关内容,因此如果需要写document,
|
||||
* 需要在此函数前调用QXmlStreamWriter::writeStartDocument(),在此函数后调用QXmlStreamWriter::writeEndDocument()
|
||||
* @param xml QXmlStreamWriter指针
|
||||
* @note 注意,在传入QXmlStreamWriter之前,需要设置编码为utf-8:xml->setCodec("utf-8");
|
||||
* @note 由于QXmlStreamWriter在QString作为io时,是不支持编码的,而此又无法保证自定义过程不出现中文字符,
|
||||
* 因此,QXmlStreamWriter不应该通过QString进行构造,如果需要用到string,也需要通过QByteArray构造,如:
|
||||
* @param cds 基于QList<SARibbonCustomizeData>生成的步骤
|
||||
* @return 如果出现异常,返回false,如果没有自定义数据也会返回false
|
||||
*/
|
||||
bool SA_RIBBON_EXPORT sa_customize_datas_to_xml(QXmlStreamWriter* xml, const QList< SARibbonCustomizeData >& cds);
|
||||
|
||||
/**
|
||||
* @brief 通过xml获取QList<SARibbonCustomizeData>
|
||||
* @param xml
|
||||
* @return QList<SARibbonCustomizeData>
|
||||
*/
|
||||
QList< SARibbonCustomizeData > SA_RIBBON_EXPORT sa_customize_datas_from_xml(QXmlStreamReader* xml, SARibbonActionsManager* mgr);
|
||||
|
||||
/**
|
||||
* @brief 应用QList<SARibbonCustomizeData>
|
||||
* @param cds
|
||||
* @param w SARibbonBar指针
|
||||
* @return 成功应用的个数
|
||||
*/
|
||||
int SA_RIBBON_EXPORT sa_customize_datas_apply(const QList< SARibbonCustomizeData >& cds, SARibbonBar* w);
|
||||
|
||||
/**
|
||||
* @brief 反向取消应用
|
||||
* @param cds
|
||||
* @param w SARibbonBar指针
|
||||
* @return 成功应用的个数
|
||||
*/
|
||||
int SA_RIBBON_EXPORT sa_customize_datas_reverse(const QList< SARibbonCustomizeData >& cds, SARibbonBar* w);
|
||||
|
||||
/**
|
||||
* @brief 直接加载xml自定义ribbon配置文件用于ribbon的自定义显示
|
||||
* @param filePath xml配置文件
|
||||
* @param w 主窗体
|
||||
* @param mgr action管理器
|
||||
* @return 成功返回true
|
||||
* @note 重复加载一个配置文件会发生异常,为了避免此类事件发生,一般通过一个变量保证只加载一次,如:
|
||||
* @code
|
||||
* static bool has_call = false;
|
||||
* if (!has_call) {
|
||||
* has_call = sa_apply_customize_from_xml_file("customize.xml", this, m_actMgr);
|
||||
* }
|
||||
* @endcode
|
||||
*/
|
||||
bool SA_RIBBON_EXPORT sa_apply_customize_from_xml_file(const QString& filePath, SARibbonBar* bar, SARibbonActionsManager* mgr);
|
||||
|
||||
#endif // SARIBBONCUSTOMIZEWIDGET_H
|
||||
@@ -0,0 +1,118 @@
|
||||
#include "SARibbonElementFactory.h"
|
||||
#include <QApplication>
|
||||
#include <QFontMetrics>
|
||||
#include "SARibbonApplicationButton.h"
|
||||
#include "SARibbonBar.h"
|
||||
#include "SARibbonTabBar.h"
|
||||
#include "SARibbonCategory.h"
|
||||
#include "SARibbonContextCategory.h"
|
||||
#include "SARibbonSeparatorWidget.h"
|
||||
#include "SARibbonGallery.h"
|
||||
#include "SARibbonGalleryGroup.h"
|
||||
#include "SARibbonToolButton.h"
|
||||
#include "SARibbonControlButton.h"
|
||||
#include "SARibbonButtonGroupWidget.h"
|
||||
#include "SARibbonStackedWidget.h"
|
||||
#include "SARibbonQuickAccessBar.h"
|
||||
#include "SARibbonPannelOptionButton.h"
|
||||
#include "SARibbonPannelLayout.h"
|
||||
#include "SARibbonSystemButtonBar.h"
|
||||
|
||||
SARibbonElementFactory::SARibbonElementFactory()
|
||||
{
|
||||
}
|
||||
|
||||
SARibbonElementFactory::~SARibbonElementFactory()
|
||||
{
|
||||
}
|
||||
|
||||
SARibbonBar* SARibbonElementFactory::createRibbonBar(QWidget* parent)
|
||||
{
|
||||
return (new SARibbonBar(parent));
|
||||
}
|
||||
|
||||
SARibbonTabBar* SARibbonElementFactory::createRibbonTabBar(QWidget* parent)
|
||||
{
|
||||
return (new SARibbonTabBar(parent));
|
||||
}
|
||||
|
||||
SARibbonApplicationButton* SARibbonElementFactory::createRibbonApplicationButton(QWidget* parent)
|
||||
{
|
||||
return (new SARibbonApplicationButton(parent));
|
||||
}
|
||||
|
||||
SARibbonCategory* SARibbonElementFactory::createRibbonCategory(QWidget* parent)
|
||||
{
|
||||
return (new SARibbonCategory(parent));
|
||||
}
|
||||
|
||||
SARibbonContextCategory* SARibbonElementFactory::createRibbonContextCategory(QWidget* parent)
|
||||
{
|
||||
return (new SARibbonContextCategory(parent));
|
||||
}
|
||||
|
||||
SARibbonPannel* SARibbonElementFactory::createRibbonPannel(QWidget* parent)
|
||||
{
|
||||
return (new SARibbonPannel(parent));
|
||||
}
|
||||
|
||||
SARibbonSeparatorWidget* SARibbonElementFactory::createRibbonSeparatorWidget(QWidget* parent)
|
||||
{
|
||||
return (new SARibbonSeparatorWidget(parent));
|
||||
}
|
||||
|
||||
SARibbonGallery* SARibbonElementFactory::createRibbonGallery(QWidget* parent)
|
||||
{
|
||||
return (new SARibbonGallery(parent));
|
||||
}
|
||||
|
||||
SARibbonGalleryGroup* SARibbonElementFactory::createRibbonGalleryGroup(QWidget* parent)
|
||||
{
|
||||
return (new SARibbonGalleryGroup(parent));
|
||||
}
|
||||
|
||||
SARibbonToolButton* SARibbonElementFactory::createRibbonToolButton(QWidget* parent)
|
||||
{
|
||||
return (new SARibbonToolButton(parent));
|
||||
}
|
||||
|
||||
SARibbonControlButton* SARibbonElementFactory::createRibbonControlButton(QWidget* parent)
|
||||
{
|
||||
return (new SARibbonControlButton(parent));
|
||||
}
|
||||
|
||||
SARibbonControlToolButton* SARibbonElementFactory::createRibbonControlToolButton(QWidget* parent)
|
||||
{
|
||||
return (new SARibbonControlToolButton(parent));
|
||||
}
|
||||
|
||||
SARibbonStackedWidget* SARibbonElementFactory::createRibbonStackedWidget(SARibbonBar* parent)
|
||||
{
|
||||
return (new SARibbonStackedWidget(parent));
|
||||
}
|
||||
|
||||
SARibbonButtonGroupWidget* SARibbonElementFactory::craeteButtonGroupWidget(QWidget* parent)
|
||||
{
|
||||
return (new SARibbonButtonGroupWidget(parent));
|
||||
}
|
||||
|
||||
SARibbonQuickAccessBar* SARibbonElementFactory::createQuickAccessBar(QWidget* parent)
|
||||
{
|
||||
return (new SARibbonQuickAccessBar(parent));
|
||||
}
|
||||
|
||||
SARibbonSystemButtonBar* SARibbonElementFactory::createWindowButtonGroup(QWidget* parent)
|
||||
{
|
||||
return (new SARibbonSystemButtonBar(parent));
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 创建SARibbonPannelOptionButton
|
||||
* @param pannel 附属的pannel
|
||||
* @return
|
||||
* @sa SARibbonPannelOptionButton
|
||||
*/
|
||||
SARibbonPannelOptionButton* SARibbonElementFactory::createRibbonPannelOptionButton(SARibbonPannel* pannel)
|
||||
{
|
||||
return (new SARibbonPannelOptionButton(pannel));
|
||||
}
|
||||
@@ -0,0 +1,59 @@
|
||||
#ifndef SARIBBONELEMENTFACTORY_H
|
||||
#define SARIBBONELEMENTFACTORY_H
|
||||
#include "SARibbonGlobal.h"
|
||||
#include <QColor>
|
||||
#include <QMargins>
|
||||
#include <QSize>
|
||||
#include <QScopedPointer>
|
||||
#include "SARibbonBar.h"
|
||||
#include "SARibbonPannel.h"
|
||||
class QWidget;
|
||||
class SARibbonBar;
|
||||
class SARibbonTabBar;
|
||||
class SARibbonApplicationButton;
|
||||
class SARibbonCategory;
|
||||
class SARibbonContextCategory;
|
||||
class SARibbonPannel;
|
||||
class SARibbonSeparatorWidget;
|
||||
class SARibbonGallery;
|
||||
class SARibbonGalleryGroup;
|
||||
class SARibbonToolButton;
|
||||
class SARibbonControlButton;
|
||||
class SARibbonControlToolButton;
|
||||
class SARibbonButtonGroupWidget;
|
||||
class SARibbonStackedWidget;
|
||||
class SARibbonQuickAccessBar;
|
||||
class SARibbonPannelOptionButton;
|
||||
class SARibbonSystemButtonBar;
|
||||
|
||||
///
|
||||
/// \brief SARibbon的子元素创建的工厂,SARibbon内部创建子元素都通过SARibbonElementFactory来创建
|
||||
///
|
||||
/// 由于SARibbonBar是一个复合控件,很多子窗口组合而成,有些部件的创建如果想继承,那么就需要这个工厂类来处理
|
||||
/// 如SARibbonCategory,可以重载此类的createRibbonCategory,返回重载的类的实例
|
||||
///
|
||||
class SA_RIBBON_EXPORT SARibbonElementFactory
|
||||
{
|
||||
public:
|
||||
SARibbonElementFactory();
|
||||
virtual ~SARibbonElementFactory();
|
||||
virtual SARibbonBar* createRibbonBar(QWidget* parent);
|
||||
virtual SARibbonTabBar* createRibbonTabBar(QWidget* parent);
|
||||
virtual SARibbonApplicationButton* createRibbonApplicationButton(QWidget* parent);
|
||||
virtual SARibbonCategory* createRibbonCategory(QWidget* parent);
|
||||
virtual SARibbonContextCategory* createRibbonContextCategory(QWidget* parent);
|
||||
virtual SARibbonPannel* createRibbonPannel(QWidget* parent);
|
||||
virtual SARibbonSeparatorWidget* createRibbonSeparatorWidget(QWidget* parent);
|
||||
virtual SARibbonGallery* createRibbonGallery(QWidget* parent);
|
||||
virtual SARibbonGalleryGroup* createRibbonGalleryGroup(QWidget* parent);
|
||||
virtual SARibbonToolButton* createRibbonToolButton(QWidget* parent);
|
||||
virtual SARibbonControlButton* createRibbonControlButton(QWidget* parent);
|
||||
virtual SARibbonControlToolButton* createRibbonControlToolButton(QWidget* parent);
|
||||
virtual SARibbonStackedWidget* createRibbonStackedWidget(SARibbonBar* parent);
|
||||
virtual SARibbonButtonGroupWidget* craeteButtonGroupWidget(QWidget* parent);
|
||||
virtual SARibbonQuickAccessBar* createQuickAccessBar(QWidget* parent);
|
||||
virtual SARibbonSystemButtonBar* createWindowButtonGroup(QWidget* parent);
|
||||
virtual SARibbonPannelOptionButton* createRibbonPannelOptionButton(SARibbonPannel* pannel);
|
||||
};
|
||||
|
||||
#endif // SARIBBONELEMENTFACTORY_H
|
||||
@@ -0,0 +1,27 @@
|
||||
#include "SARibbonElementManager.h"
|
||||
|
||||
SARibbonElementManager::SARibbonElementManager()
|
||||
{
|
||||
mFactory.reset(new SARibbonElementFactory());
|
||||
}
|
||||
|
||||
SARibbonElementManager::~SARibbonElementManager()
|
||||
{
|
||||
}
|
||||
|
||||
SARibbonElementManager* SARibbonElementManager::instance()
|
||||
{
|
||||
static SARibbonElementManager s_instance;
|
||||
|
||||
return (&(s_instance));
|
||||
}
|
||||
|
||||
SARibbonElementFactory* SARibbonElementManager::factory()
|
||||
{
|
||||
return (mFactory.data());
|
||||
}
|
||||
|
||||
void SARibbonElementManager::setupFactory(SARibbonElementFactory* fac)
|
||||
{
|
||||
mFactory.reset(fac);
|
||||
}
|
||||
@@ -0,0 +1,52 @@
|
||||
#ifndef SARIBBONELEMENTMANAGER_H
|
||||
#define SARIBBONELEMENTMANAGER_H
|
||||
#include "SARibbonElementFactory.h"
|
||||
#include "SARibbonGlobal.h"
|
||||
|
||||
/**
|
||||
@brief 此类是一个全局单例,用于管理SARibbonElementFactory
|
||||
|
||||
如果你有自己的某个部件要重写,首先你需要有自己的ElementFactory
|
||||
@code
|
||||
class MyRibbonElementFactory : public SARibbonElementFactory{
|
||||
public:
|
||||
...
|
||||
virtual SARibbonPannel* createRibbonPannel(QWidget* parent){
|
||||
return new MyRibbonPannel(parent);
|
||||
}
|
||||
};
|
||||
@endcode
|
||||
|
||||
然后,你需要在ribbonbar创建之前把自己的ElementFactory设置进去
|
||||
|
||||
这个一般会在main函数中进行
|
||||
|
||||
@code
|
||||
SARibbonElementManager::instance()->setupFactory(new MyRibbonElementFactory);
|
||||
@endcode
|
||||
|
||||
这样,SARibbon创建的pannel就是你自己重写的MyRibbonPannel
|
||||
|
||||
*/
|
||||
class SA_RIBBON_EXPORT SARibbonElementManager
|
||||
{
|
||||
protected:
|
||||
SARibbonElementManager();
|
||||
|
||||
public:
|
||||
virtual ~SARibbonElementManager();
|
||||
static SARibbonElementManager* instance();
|
||||
SARibbonElementFactory* factory();
|
||||
void setupFactory(SARibbonElementFactory* fac);
|
||||
|
||||
private:
|
||||
QScopedPointer< SARibbonElementFactory > mFactory;
|
||||
};
|
||||
#ifndef RibbonSubElementMgr
|
||||
#define RibbonSubElementMgr SARibbonElementManager::instance()
|
||||
#endif
|
||||
#ifndef RibbonSubElementFactory
|
||||
#define RibbonSubElementFactory SARibbonElementManager::instance()->factory()
|
||||
#endif
|
||||
|
||||
#endif // SARIBBONELEMENTMANAGER_H
|
||||
@@ -0,0 +1,421 @@
|
||||
#include "SARibbonGallery.h"
|
||||
#include "SARibbonControlButton.h"
|
||||
#include <QIcon>
|
||||
#include <QApplication>
|
||||
#define ICON_ARROW_UP QIcon(":/image/resource/ArrowUp.png")
|
||||
#define ICON_ARROW_DOWN QIcon(":/image/resource/ArrowDown.png")
|
||||
#define ICON_ARROW_MORE QIcon(":/image/resource/ArrowMore.png")
|
||||
#include <QResizeEvent>
|
||||
#include <QDebug>
|
||||
#include <QVBoxLayout>
|
||||
#include <QScrollBar>
|
||||
#include <QLabel>
|
||||
#include "SARibbonElementManager.h"
|
||||
#include <QActionGroup>
|
||||
|
||||
/**
|
||||
* @brief The SARibbonGalleryPrivate class
|
||||
*/
|
||||
class SARibbonGallery::PrivateData
|
||||
{
|
||||
SA_RIBBON_DECLARE_PUBLIC(SARibbonGallery)
|
||||
public:
|
||||
static int sGalleryButtonMaximumWidth;
|
||||
SARibbonGalleryButton* mButtonUp { nullptr };
|
||||
SARibbonGalleryButton* mButtonDown { nullptr };
|
||||
SARibbonGalleryButton* mButtonMore { nullptr };
|
||||
#if 0
|
||||
SARibbonMenu *popupWidget;
|
||||
#else
|
||||
SARibbonGalleryViewport* mPopupWidget { nullptr };
|
||||
#endif
|
||||
SARibbonGalleryGroup* mViewportGroup { nullptr };
|
||||
QBoxLayout* mButtonLayout { nullptr };
|
||||
QBoxLayout* mLayout { nullptr };
|
||||
PrivateData(SARibbonGallery* p) : q_ptr(p)
|
||||
{
|
||||
}
|
||||
|
||||
void init()
|
||||
{
|
||||
mButtonUp = new SARibbonGalleryButton(q_ptr);
|
||||
mButtonDown = new SARibbonGalleryButton(q_ptr);
|
||||
mButtonMore = new SARibbonGalleryButton(q_ptr);
|
||||
mButtonUp->setToolButtonStyle(Qt::ToolButtonIconOnly);
|
||||
mButtonDown->setToolButtonStyle(Qt::ToolButtonIconOnly);
|
||||
mButtonMore->setToolButtonStyle(Qt::ToolButtonIconOnly);
|
||||
mButtonUp->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Expanding);
|
||||
mButtonDown->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Expanding);
|
||||
mButtonMore->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Expanding);
|
||||
mButtonUp->setObjectName(QStringLiteral("SARibbonGalleryButtonUp"));
|
||||
mButtonDown->setObjectName(QStringLiteral("SARibbonGalleryButtonDown"));
|
||||
mButtonMore->setObjectName(QStringLiteral("SARibbonGalleryButtonMore"));
|
||||
mButtonUp->setMaximumWidth(sGalleryButtonMaximumWidth);
|
||||
mButtonDown->setMaximumWidth(sGalleryButtonMaximumWidth);
|
||||
mButtonMore->setMaximumWidth(sGalleryButtonMaximumWidth);
|
||||
mButtonUp->setIcon(ICON_ARROW_UP);
|
||||
mButtonDown->setIcon(ICON_ARROW_DOWN);
|
||||
mButtonMore->setIcon(ICON_ARROW_MORE);
|
||||
q_ptr->connect(mButtonUp, &QAbstractButton::clicked, q_ptr, &SARibbonGallery::pageUp);
|
||||
q_ptr->connect(mButtonDown, &QAbstractButton::clicked, q_ptr, &SARibbonGallery::pageDown);
|
||||
q_ptr->connect(mButtonMore, &QAbstractButton::clicked, q_ptr, &SARibbonGallery::showMoreDetail);
|
||||
// 信号转发
|
||||
q_ptr->connect(q_ptr, &SARibbonGallery::triggered, q_ptr, &SARibbonGallery::onTriggered);
|
||||
mPopupWidget = nullptr;
|
||||
mViewportGroup = nullptr;
|
||||
mButtonLayout = new QBoxLayout(QBoxLayout::TopToBottom);
|
||||
mButtonLayout->setSpacing(0);
|
||||
mButtonLayout->setContentsMargins(0, 0, 0, 0);
|
||||
mButtonLayout->addWidget(mButtonUp);
|
||||
mButtonLayout->addWidget(mButtonDown);
|
||||
mButtonLayout->addWidget(mButtonMore);
|
||||
mLayout = new QBoxLayout(QBoxLayout::RightToLeft);
|
||||
mLayout->setSpacing(0);
|
||||
mLayout->setContentsMargins(0, 0, 0, 0);
|
||||
mLayout->addLayout(mButtonLayout);
|
||||
mLayout->addStretch();
|
||||
q_ptr->setLayout(mLayout);
|
||||
}
|
||||
|
||||
bool isValid() const
|
||||
{
|
||||
return (q_ptr != nullptr);
|
||||
}
|
||||
|
||||
void createPopupWidget()
|
||||
{
|
||||
if (nullptr == mPopupWidget) {
|
||||
#if 0
|
||||
popupWidget = new SARibbonMenu(Parent);
|
||||
#else
|
||||
mPopupWidget = new SARibbonGalleryViewport(q_ptr);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
void setViewPort(SARibbonGalleryGroup* v)
|
||||
{
|
||||
if (nullptr == mViewportGroup) {
|
||||
mViewportGroup = RibbonSubElementFactory->createRibbonGalleryGroup(q_ptr);
|
||||
mLayout->addWidget(mViewportGroup, 1);
|
||||
}
|
||||
mViewportGroup->setRecalcGridSizeBlock(true);
|
||||
mViewportGroup->setGalleryGroupStyle(v->galleryGroupStyle());
|
||||
mViewportGroup->setDisplayRow(v->displayRow());
|
||||
mViewportGroup->setSpacing(v->spacing());
|
||||
mViewportGroup->setGridMaximumWidth(v->gridMaximumWidth());
|
||||
mViewportGroup->setGridMinimumWidth(v->gridMinimumWidth());
|
||||
mViewportGroup->setRecalcGridSizeBlock(false);
|
||||
mViewportGroup->recalcGridSize(mViewportGroup->height());
|
||||
mViewportGroup->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
|
||||
mViewportGroup->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
|
||||
mViewportGroup->setModel(v->model());
|
||||
mViewportGroup->show();
|
||||
}
|
||||
};
|
||||
|
||||
// 静态变量初始化
|
||||
|
||||
/**
|
||||
* @brief SARibbonGalleryPrivate::sGalleryButtonMaximumWidth
|
||||
*/
|
||||
int SARibbonGallery::PrivateData::sGalleryButtonMaximumWidth = 15;
|
||||
|
||||
//===================================================
|
||||
// SARibbonGalleryButton
|
||||
//===================================================
|
||||
|
||||
SARibbonGalleryButton::SARibbonGalleryButton(QWidget* parent) : QToolButton(parent)
|
||||
{
|
||||
}
|
||||
|
||||
SARibbonGalleryButton::~SARibbonGalleryButton()
|
||||
{
|
||||
}
|
||||
//===================================================
|
||||
// SARibbonGalleryViewport
|
||||
//===================================================
|
||||
|
||||
SARibbonGalleryViewport::SARibbonGalleryViewport(QWidget* parent) : QWidget(parent)
|
||||
{
|
||||
setWindowFlags(Qt::Popup);
|
||||
QPalette pl = palette();
|
||||
pl.setBrush(QPalette::Window, pl.brush(QPalette::Base));
|
||||
setPalette(pl);
|
||||
m_layout = new QVBoxLayout(this);
|
||||
m_layout->setSpacing(0);
|
||||
m_layout->setContentsMargins(0, 0, 0, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 添加窗口不带标题
|
||||
* @param w
|
||||
*/
|
||||
void SARibbonGalleryViewport::addWidget(QWidget* w)
|
||||
{
|
||||
w->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Minimum);
|
||||
m_layout->addWidget(w);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 添加窗口,带标题
|
||||
* @param w
|
||||
* @param title
|
||||
*/
|
||||
void SARibbonGalleryViewport::addWidget(QWidget* w, const QString& title)
|
||||
{
|
||||
QLabel* label = new QLabel(this);
|
||||
label->setText(title);
|
||||
label->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Minimum);
|
||||
m_layout->addWidget(label);
|
||||
w->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Minimum);
|
||||
m_layout->addWidget(w);
|
||||
_widgetToTitleLable[ w ] = label;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 通过SARibbonGalleryGroup获取对应的标题,用户可以通过此函数设置QLabel的属性
|
||||
* @param g
|
||||
* @return 如果没有管理group,将返回nullptr
|
||||
*/
|
||||
QLabel* SARibbonGalleryViewport::titleLabel(QWidget* w)
|
||||
{
|
||||
return _widgetToTitleLable.value(w, nullptr);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 移除窗口
|
||||
* @param w
|
||||
*/
|
||||
void SARibbonGalleryViewport::removeWidget(QWidget* w)
|
||||
{
|
||||
QLabel* label = titleLabel(w);
|
||||
if (label) {
|
||||
m_layout->removeWidget(label);
|
||||
}
|
||||
m_layout->removeWidget(w);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief widget的标题改变
|
||||
* @param g
|
||||
* @param title
|
||||
*/
|
||||
void SARibbonGalleryViewport::onTitleChanged(QWidget* w, const QString& title)
|
||||
{
|
||||
QLabel* l = titleLabel(w);
|
||||
if (l) {
|
||||
l->setText(title);
|
||||
}
|
||||
}
|
||||
|
||||
//===================================================
|
||||
// SARibbonGallery
|
||||
//===================================================
|
||||
|
||||
SARibbonGallery::SARibbonGallery(QWidget* parent) : QFrame(parent), d_ptr(new SARibbonGallery::PrivateData(this))
|
||||
{
|
||||
d_ptr->init();
|
||||
setFrameShape(QFrame::Box);
|
||||
setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
|
||||
setMinimumWidth(200);
|
||||
}
|
||||
|
||||
SARibbonGallery::~SARibbonGallery()
|
||||
{
|
||||
}
|
||||
|
||||
QSize SARibbonGallery::sizeHint() const
|
||||
{
|
||||
return (QSize(100, 62));
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 获取一个空白SARibbonGalleryGroup
|
||||
* @return
|
||||
*/
|
||||
SARibbonGalleryGroup* SARibbonGallery::addGalleryGroup()
|
||||
{
|
||||
SARibbonGalleryGroup* group = RibbonSubElementFactory->createRibbonGalleryGroup(this);
|
||||
addGalleryGroup(group);
|
||||
return (group);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 添加一组SARibbonGalleryGroup
|
||||
* @param group
|
||||
*/
|
||||
void SARibbonGallery::addGalleryGroup(SARibbonGalleryGroup* group)
|
||||
{
|
||||
group->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Preferred);
|
||||
SARibbonGalleryViewport* viewport = ensureGetPopupViewPort();
|
||||
viewport->addWidget(group, group->groupTitle());
|
||||
connect(group, &QAbstractItemView::clicked, this, &SARibbonGallery::onItemClicked);
|
||||
connect(group, &SARibbonGalleryGroup::groupTitleChanged, this, [ group, viewport ](const QString& t) {
|
||||
viewport->onTitleChanged(group, t);
|
||||
});
|
||||
connect(group, &SARibbonGalleryGroup::triggered, this, &SARibbonGallery::triggered);
|
||||
connect(group, &SARibbonGalleryGroup::hovered, this, &SARibbonGallery::hovered);
|
||||
setCurrentViewGroup(group);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 添加一组actions
|
||||
* @param title actions组的名字
|
||||
* @param actions
|
||||
* @return 返回SARibbonGalleryGroup,用户可以通过修改SARibbonGalleryGroup属性控制其显示方法
|
||||
*/
|
||||
SARibbonGalleryGroup* SARibbonGallery::addCategoryActions(const QString& title, QList< QAction* > actions)
|
||||
{
|
||||
SARibbonGalleryGroup* group = RibbonSubElementFactory->createRibbonGalleryGroup(this);
|
||||
if (!title.isEmpty()) {
|
||||
group->setGroupTitle(title);
|
||||
}
|
||||
group->addActionItemList(actions);
|
||||
addGalleryGroup(group);
|
||||
return (group);
|
||||
}
|
||||
|
||||
void SARibbonGallery::setCurrentViewGroup(SARibbonGalleryGroup* group)
|
||||
{
|
||||
d_ptr->setViewPort(group);
|
||||
QApplication::postEvent(this, new QResizeEvent(size(), size()));
|
||||
}
|
||||
|
||||
SARibbonGalleryGroup* SARibbonGallery::currentViewGroup() const
|
||||
{
|
||||
return (d_ptr->mViewportGroup);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 获取弹出窗口
|
||||
* @return
|
||||
*/
|
||||
SARibbonGalleryViewport* SARibbonGallery::getPopupViewPort() const
|
||||
{
|
||||
return d_ptr->mPopupWidget;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 设置最右边三个控制按钮的最大宽度(默认15)
|
||||
* @param w
|
||||
*/
|
||||
void SARibbonGallery::setGalleryButtonMaximumWidth(int w)
|
||||
{
|
||||
SARibbonGallery::PrivateData::sGalleryButtonMaximumWidth = w;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 上翻页
|
||||
*/
|
||||
void SARibbonGallery::pageDown()
|
||||
{
|
||||
if (d_ptr->mViewportGroup) {
|
||||
QScrollBar* vscrollBar = d_ptr->mViewportGroup->verticalScrollBar();
|
||||
int v = vscrollBar->value();
|
||||
v += vscrollBar->singleStep();
|
||||
vscrollBar->setValue(v);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 下翻页
|
||||
*/
|
||||
void SARibbonGallery::pageUp()
|
||||
{
|
||||
if (d_ptr->mViewportGroup) {
|
||||
QScrollBar* vscrollBar = d_ptr->mViewportGroup->verticalScrollBar();
|
||||
int v = vscrollBar->value();
|
||||
v -= vscrollBar->singleStep();
|
||||
vscrollBar->setValue(v);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 显示更多触发,默认弹出内部管理的SARibbonGalleryViewport,用户可重载此函数实现自定义的弹出
|
||||
*/
|
||||
void SARibbonGallery::showMoreDetail()
|
||||
{
|
||||
if (nullptr == d_ptr->mPopupWidget) {
|
||||
return;
|
||||
}
|
||||
QSize popupMenuSize = d_ptr->mPopupWidget->sizeHint();
|
||||
QPoint start = mapToGlobal(QPoint(0, 0));
|
||||
|
||||
int width = d_ptr->mViewportGroup->width(); // viewport
|
||||
|
||||
width += qApp->style()->pixelMetric(QStyle::PM_ScrollBarExtent); // scrollbar
|
||||
d_ptr->mPopupWidget->setGeometry(start.x(), start.y(), width, popupMenuSize.height());
|
||||
d_ptr->mPopupWidget->show();
|
||||
}
|
||||
|
||||
void SARibbonGallery::onItemClicked(const QModelIndex& index)
|
||||
{
|
||||
QObject* obj = sender();
|
||||
SARibbonGalleryGroup* group = qobject_cast< SARibbonGalleryGroup* >(obj);
|
||||
if (group) {
|
||||
setCurrentViewGroup(group);
|
||||
SARibbonGalleryGroup* curGroup = currentViewGroup();
|
||||
curGroup->scrollTo(index);
|
||||
curGroup->setCurrentIndex(index);
|
||||
}
|
||||
}
|
||||
|
||||
void SARibbonGallery::onTriggered(QAction* action)
|
||||
{
|
||||
Q_UNUSED(action);
|
||||
// 点击后关闭弹出窗口
|
||||
if (d_ptr->mPopupWidget) {
|
||||
if (d_ptr->mPopupWidget->isVisible()) {
|
||||
d_ptr->mPopupWidget->hide();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
SARibbonGalleryViewport* SARibbonGallery::ensureGetPopupViewPort()
|
||||
{
|
||||
if (nullptr == d_ptr->mPopupWidget) {
|
||||
d_ptr->createPopupWidget();
|
||||
}
|
||||
return (d_ptr->mPopupWidget);
|
||||
}
|
||||
|
||||
void SARibbonGallery::resizeEvent(QResizeEvent* event)
|
||||
{
|
||||
QFrame::resizeEvent(event);
|
||||
// 对SARibbonGalleryViewport所有SARibbonGalleryGroup重置尺寸
|
||||
int h = layout()->contentsRect().height();
|
||||
if (d_ptr->mViewportGroup) {
|
||||
h = d_ptr->mViewportGroup->height();
|
||||
d_ptr->mViewportGroup->recalcGridSize();
|
||||
}
|
||||
if (d_ptr->mPopupWidget) {
|
||||
QLayout* lay = d_ptr->mPopupWidget->layout();
|
||||
if (!lay) {
|
||||
return;
|
||||
}
|
||||
int c = lay->count();
|
||||
for (int i = 0; i < c; ++i) {
|
||||
QLayoutItem* item = lay->itemAt(i);
|
||||
if (!item) {
|
||||
continue;
|
||||
}
|
||||
QWidget* w = item->widget();
|
||||
if (!w) {
|
||||
continue;
|
||||
}
|
||||
SARibbonGalleryGroup* g = qobject_cast< SARibbonGalleryGroup* >(w);
|
||||
if (!g) {
|
||||
continue;
|
||||
}
|
||||
g->recalcGridSize(h);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void SARibbonGallery::paintEvent(QPaintEvent* event)
|
||||
{
|
||||
QFrame::paintEvent(event);
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,125 @@
|
||||
#ifndef SARIBBONGALLERY_H
|
||||
#define SARIBBONGALLERY_H
|
||||
#include "SARibbonGlobal.h"
|
||||
#include <QFrame>
|
||||
#include <QToolButton>
|
||||
#include "SARibbonGalleryGroup.h"
|
||||
#include <QSizeGrip>
|
||||
class QLabel;
|
||||
class QVBoxLayout;
|
||||
class SARibbonGalleryViewport;
|
||||
|
||||
/**
|
||||
* @brief 针对SARibbonGallery控件的按钮
|
||||
*/
|
||||
class SA_RIBBON_EXPORT SARibbonGalleryButton : public QToolButton
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit SARibbonGalleryButton(QWidget* parent = nullptr);
|
||||
~SARibbonGalleryButton();
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Gallery控件
|
||||
*
|
||||
* Gallery控件是由一个当前激活的@sa SARibbonGalleryGroup 和弹出的 @sa SARibbonGalleryViewport 组成
|
||||
*
|
||||
* @sa SARibbonGalleryGroup 是继承@sa QListView actions通过icon展示出来,相关的属性可以按照QListView设置
|
||||
*
|
||||
* @sa SARibbonGalleryViewport 是一个内部有垂直布局的窗体,在弹出激活时,把管理的SARibbonGalleryGroup都展示出来
|
||||
*
|
||||
* 示例如下:
|
||||
* @code
|
||||
* SARibbonGallery* gallery = pannel1->addGallery();
|
||||
* QList< QAction* > galleryActions;
|
||||
* ...create many actions ...
|
||||
* SARibbonGalleryGroup* group1 = gallery->addCategoryActions(tr("Files"), galleryActions);
|
||||
* galleryActions.clear();
|
||||
* ...create many actions ...
|
||||
* gallery->addCategoryActions(tr("Apps"), galleryActions);
|
||||
* gallery->setCurrentViewGroup(group1);
|
||||
* @endcode
|
||||
*/
|
||||
class SA_RIBBON_EXPORT SARibbonGallery : public QFrame
|
||||
{
|
||||
Q_OBJECT
|
||||
SA_RIBBON_DECLARE_PRIVATE(SARibbonGallery)
|
||||
public:
|
||||
explicit SARibbonGallery(QWidget* parent = nullptr);
|
||||
virtual ~SARibbonGallery();
|
||||
virtual QSize sizeHint() const override;
|
||||
// 添加一个GalleryGroup
|
||||
SARibbonGalleryGroup* addGalleryGroup();
|
||||
// 添加一个GalleryGroup
|
||||
void addGalleryGroup(SARibbonGalleryGroup* group);
|
||||
// 快速添加一组actions
|
||||
SARibbonGalleryGroup* addCategoryActions(const QString& title, QList< QAction* > actions);
|
||||
// 设置当前显示的SARibbonGalleryGroup
|
||||
void setCurrentViewGroup(SARibbonGalleryGroup* group);
|
||||
// 获取当前显示的SARibbonGalleryGroup
|
||||
SARibbonGalleryGroup* currentViewGroup() const;
|
||||
// 获取弹出窗口指针
|
||||
SARibbonGalleryViewport* getPopupViewPort() const;
|
||||
|
||||
public:
|
||||
// 设置最右边三个控制按钮的最大宽度(默认15)
|
||||
static void setGalleryButtonMaximumWidth(int w);
|
||||
Q_SIGNALS:
|
||||
/**
|
||||
* @brief 转发管理的SARibbonGalleryGroup::triggered
|
||||
* 所有加入SARibbonGallery的action都会被一个QActionGroup管理,可以通过@sa getActionGroup 获取到对应的actiongroup
|
||||
* @param action
|
||||
*/
|
||||
void triggered(QAction* action);
|
||||
/**
|
||||
* @brief 转发管理的SARibbonGalleryGroup::hovered
|
||||
* @note 此属性需要确保SARibbonGalleryGroup::setMouseTracking(true)
|
||||
* @param action
|
||||
*/
|
||||
void hovered(QAction* action);
|
||||
|
||||
public Q_SLOTS:
|
||||
// 上翻页
|
||||
virtual void pageUp();
|
||||
// 下翻页
|
||||
virtual void pageDown();
|
||||
// 显示更多触发,默认弹出内部管理的SARibbonGalleryViewport,用户可重载此函数实现自定义的弹出
|
||||
virtual void showMoreDetail();
|
||||
protected Q_SLOTS:
|
||||
void onItemClicked(const QModelIndex& index);
|
||||
virtual void onTriggered(QAction* action);
|
||||
|
||||
private:
|
||||
SARibbonGalleryViewport* ensureGetPopupViewPort();
|
||||
|
||||
protected:
|
||||
void resizeEvent(QResizeEvent* event) override;
|
||||
void paintEvent(QPaintEvent* event) override;
|
||||
};
|
||||
|
||||
///
|
||||
/// \brief SARibbonGallery的Viewport class
|
||||
///
|
||||
class SARibbonGalleryViewport : public QWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
SARibbonGalleryViewport(QWidget* parent);
|
||||
// 添加窗口不带标题
|
||||
void addWidget(QWidget* w);
|
||||
// 添加窗口,带标题
|
||||
void addWidget(QWidget* w, const QString& title);
|
||||
// 通过SARibbonGalleryGroup获取对应的标题,用户可以通过此函数设置QLabel的属性
|
||||
QLabel* titleLabel(QWidget* w);
|
||||
// 移除窗口
|
||||
void removeWidget(QWidget* w);
|
||||
public Q_SLOTS:
|
||||
void onTitleChanged(QWidget* w, const QString& title);
|
||||
|
||||
private:
|
||||
QVBoxLayout* m_layout;
|
||||
QMap< QWidget*, QLabel* > _widgetToTitleLable; ///< QWidget和lable的对应
|
||||
};
|
||||
|
||||
#endif // SARIBBONGALLERY_H
|
||||
@@ -0,0 +1,496 @@
|
||||
#include "SARibbonGalleryGroup.h"
|
||||
#include <QPainter>
|
||||
#include <QDebug>
|
||||
#include <QActionGroup>
|
||||
#include <QItemSelectionModel>
|
||||
#include "SARibbonElementManager.h"
|
||||
/**
|
||||
* @brief The SARibbonGalleryGroupPrivate class
|
||||
*/
|
||||
class SARibbonGalleryGroup::PrivateData
|
||||
{
|
||||
public:
|
||||
SARibbonGalleryGroup* q_ptr;
|
||||
QString mGroupTitle;
|
||||
SARibbonGalleryGroup::GalleryGroupStyle mPreStyle { SARibbonGalleryGroup::IconWithText };
|
||||
SARibbonGalleryGroup::DisplayRow mDisplayRow { SARibbonGalleryGroup::DisplayOneRow };
|
||||
bool mBlockRecalc { false };
|
||||
int mGridMinimumWidth { 0 }; ///< grid最小宽度
|
||||
int mGridMaximumWidth { 0 }; ///< grid最大宽度
|
||||
QActionGroup* mActionGroup { nullptr }; ///< 所有GalleryGroup管理的actions都由这个actiongroup管理
|
||||
public:
|
||||
PrivateData(SARibbonGalleryGroup* p) : q_ptr(p)
|
||||
{
|
||||
mActionGroup = new QActionGroup(p);
|
||||
p->connect(mActionGroup, &QActionGroup::triggered, p, &SARibbonGalleryGroup::triggered);
|
||||
p->connect(mActionGroup, &QActionGroup::hovered, p, &SARibbonGalleryGroup::hovered);
|
||||
}
|
||||
};
|
||||
|
||||
//===================================================
|
||||
// SARibbonGalleryGroupItemDelegate
|
||||
//===================================================
|
||||
|
||||
SARibbonGalleryGroupItemDelegate::SARibbonGalleryGroupItemDelegate(SARibbonGalleryGroup* group, QObject* parent)
|
||||
: QStyledItemDelegate(parent), mGroup(group)
|
||||
{
|
||||
}
|
||||
|
||||
SARibbonGalleryGroupItemDelegate::~SARibbonGalleryGroupItemDelegate()
|
||||
{
|
||||
}
|
||||
|
||||
void SARibbonGalleryGroupItemDelegate::paint(QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex& index) const
|
||||
{
|
||||
if (nullptr == mGroup) {
|
||||
return;
|
||||
}
|
||||
switch (mGroup->galleryGroupStyle()) {
|
||||
case SARibbonGalleryGroup::IconWithText:
|
||||
paintIconWithText(painter, option, index);
|
||||
break;
|
||||
case SARibbonGalleryGroup::IconWithWordWrapText:
|
||||
paintIconWithTextWordWrap(painter, option, index);
|
||||
break;
|
||||
case SARibbonGalleryGroup::IconOnly:
|
||||
paintIconOnly(painter, option, index);
|
||||
break;
|
||||
default:
|
||||
paintIconWithText(painter, option, index);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void SARibbonGalleryGroupItemDelegate::paintIconOnly(QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex& index) const
|
||||
{
|
||||
QStyle* style = mGroup->style();
|
||||
int sp = mGroup->spacing();
|
||||
sp += 3;
|
||||
painter->save();
|
||||
painter->setClipRect(option.rect);
|
||||
style->drawPrimitive(QStyle::PE_PanelItemViewItem, &option, painter, mGroup);
|
||||
// draw the icon
|
||||
QRect iconRect = option.rect;
|
||||
|
||||
iconRect.adjust(sp, sp, -sp, -sp);
|
||||
QIcon ico = qvariant_cast< QIcon >(index.data(Qt::DecorationRole));
|
||||
|
||||
ico.paint(painter, iconRect, Qt::AlignCenter, QIcon::Normal, QIcon::On);
|
||||
painter->restore();
|
||||
}
|
||||
|
||||
void SARibbonGalleryGroupItemDelegate::paintIconWithText(QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex& index) const
|
||||
{
|
||||
QStyledItemDelegate::paint(painter, option, index);
|
||||
}
|
||||
|
||||
void SARibbonGalleryGroupItemDelegate::paintIconWithTextWordWrap(QPainter* painter,
|
||||
const QStyleOptionViewItem& option,
|
||||
const QModelIndex& index) const
|
||||
{
|
||||
QStyledItemDelegate::paint(painter, option, index);
|
||||
}
|
||||
|
||||
QSize SARibbonGalleryGroupItemDelegate::sizeHint(const QStyleOptionViewItem& option, const QModelIndex& index) const
|
||||
{
|
||||
Q_UNUSED(index);
|
||||
Q_UNUSED(option);
|
||||
return mGroup->gridSize();
|
||||
}
|
||||
|
||||
//===================================================
|
||||
// SARibbonGalleryGroupModel
|
||||
//===================================================
|
||||
|
||||
SARibbonGalleryGroupModel::SARibbonGalleryGroupModel(QObject* parent) : QAbstractListModel(parent)
|
||||
{
|
||||
}
|
||||
|
||||
SARibbonGalleryGroupModel::~SARibbonGalleryGroupModel()
|
||||
{
|
||||
clear();
|
||||
}
|
||||
|
||||
int SARibbonGalleryGroupModel::rowCount(const QModelIndex& parent) const
|
||||
{
|
||||
return (parent.isValid() ? 0 : mItems.size());
|
||||
}
|
||||
|
||||
Qt::ItemFlags SARibbonGalleryGroupModel::flags(const QModelIndex& index) const
|
||||
{
|
||||
if (!index.isValid() || (index.row() >= mItems.size())) {
|
||||
return (Qt::NoItemFlags);
|
||||
}
|
||||
return (mItems.at(index.row())->flags());
|
||||
}
|
||||
|
||||
QVariant SARibbonGalleryGroupModel::data(const QModelIndex& index, int role) const
|
||||
{
|
||||
if (!index.isValid() || (index.row() >= mItems.count())) {
|
||||
return (QVariant());
|
||||
}
|
||||
return (mItems.at(index.row())->data(role));
|
||||
}
|
||||
|
||||
QModelIndex SARibbonGalleryGroupModel::index(int row, int column, const QModelIndex& parent) const
|
||||
{
|
||||
if (hasIndex(row, column, parent)) {
|
||||
return (createIndex(row, column, mItems.at(row)));
|
||||
}
|
||||
return (QModelIndex());
|
||||
}
|
||||
|
||||
bool SARibbonGalleryGroupModel::setData(const QModelIndex& index, const QVariant& value, int role)
|
||||
{
|
||||
if (!index.isValid() || (index.row() >= mItems.count())) {
|
||||
return (false);
|
||||
}
|
||||
|
||||
mItems.at(index.row())->setData(role, value);
|
||||
return (true);
|
||||
}
|
||||
|
||||
void SARibbonGalleryGroupModel::clear()
|
||||
{
|
||||
beginResetModel();
|
||||
for (int i = 0; i < mItems.count(); ++i) {
|
||||
if (mItems.at(i)) {
|
||||
delete mItems.at(i);
|
||||
}
|
||||
}
|
||||
mItems.clear();
|
||||
endResetModel();
|
||||
}
|
||||
|
||||
SARibbonGalleryItem* SARibbonGalleryGroupModel::at(int row) const
|
||||
{
|
||||
return (mItems.value(row));
|
||||
}
|
||||
|
||||
void SARibbonGalleryGroupModel::insert(int row, SARibbonGalleryItem* item)
|
||||
{
|
||||
beginInsertRows(QModelIndex(), row, row);
|
||||
mItems.insert(row, item);
|
||||
endInsertRows();
|
||||
}
|
||||
|
||||
SARibbonGalleryItem* SARibbonGalleryGroupModel::take(int row)
|
||||
{
|
||||
if ((row < 0) || (row >= mItems.count())) {
|
||||
return (0);
|
||||
}
|
||||
|
||||
beginRemoveRows(QModelIndex(), row, row);
|
||||
SARibbonGalleryItem* item = mItems.takeAt(row);
|
||||
|
||||
endRemoveRows();
|
||||
return (item);
|
||||
}
|
||||
|
||||
void SARibbonGalleryGroupModel::append(SARibbonGalleryItem* item)
|
||||
{
|
||||
beginInsertRows(QModelIndex(), mItems.count(), mItems.count() + 1);
|
||||
mItems.append(item);
|
||||
endInsertRows();
|
||||
}
|
||||
|
||||
//===================================================
|
||||
// SARibbonGalleryGroup
|
||||
//===================================================
|
||||
SARibbonGalleryGroup::SARibbonGalleryGroup(QWidget* w)
|
||||
: QListView(w), d_ptr(new SARibbonGalleryGroup::PrivateData(this))
|
||||
{
|
||||
setViewMode(QListView::IconMode);
|
||||
setResizeMode(QListView::Adjust);
|
||||
setSelectionRectVisible(true);
|
||||
setUniformItemSizes(true);
|
||||
setSpacing(1);
|
||||
setItemDelegate(new SARibbonGalleryGroupItemDelegate(this, this));
|
||||
connect(this, &QAbstractItemView::clicked, this, &SARibbonGalleryGroup::onItemClicked);
|
||||
SARibbonGalleryGroupModel* m = new SARibbonGalleryGroupModel(this);
|
||||
setModel(m);
|
||||
}
|
||||
|
||||
SARibbonGalleryGroup::~SARibbonGalleryGroup()
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 是否禁止计算
|
||||
* @param on
|
||||
*/
|
||||
void SARibbonGalleryGroup::setRecalcGridSizeBlock(bool on)
|
||||
{
|
||||
d_ptr->mBlockRecalc = on;
|
||||
}
|
||||
|
||||
bool SARibbonGalleryGroup::isRecalcGridSizeBlock() const
|
||||
{
|
||||
return d_ptr->mBlockRecalc;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 重新计算grid和icon的尺寸
|
||||
*/
|
||||
void SARibbonGalleryGroup::recalcGridSize()
|
||||
{
|
||||
recalcGridSize(height());
|
||||
}
|
||||
|
||||
void SARibbonGalleryGroup::recalcGridSize(int galleryHeight)
|
||||
{
|
||||
if (isRecalcGridSizeBlock()) {
|
||||
return;
|
||||
}
|
||||
// 首先通过DisplayRow计算GridSize
|
||||
int dr = static_cast< int >(displayRow());
|
||||
if (dr < 1) {
|
||||
dr = 1;
|
||||
} else if (dr > 3) {
|
||||
dr = 3;
|
||||
}
|
||||
int h = galleryHeight / dr;
|
||||
if (h <= 1) {
|
||||
h = galleryHeight;
|
||||
}
|
||||
int w = h;
|
||||
if (gridMinimumWidth() > 0) {
|
||||
if (w < gridMinimumWidth()) {
|
||||
w = gridMinimumWidth();
|
||||
}
|
||||
}
|
||||
if (gridMaximumWidth() > 0) {
|
||||
if (w > gridMaximumWidth()) {
|
||||
w = gridMaximumWidth();
|
||||
}
|
||||
}
|
||||
setGridSize(QSize(w, h));
|
||||
// 在通过GalleryGroupStyle确定icon的尺寸
|
||||
const int shiftpix = 4; // 这个是移动像素,qt在鼠标移动到图标上时会移动一下,给用户明确的动态,导致如果布局很满会超出显示范围,因此要在此基础上缩放一点
|
||||
switch (galleryGroupStyle()) {
|
||||
case IconWithText: {
|
||||
int textHeight = fontMetrics().lineSpacing();
|
||||
int iconHeight = h - textHeight - 2 * spacing() - shiftpix;
|
||||
if (iconHeight > 0) {
|
||||
setIconSize(QSize(w - 2 * spacing() - shiftpix, iconHeight));
|
||||
} else {
|
||||
setIconSize(QSize(w - 2 * spacing() - shiftpix, h - 2 * spacing() - shiftpix));
|
||||
}
|
||||
break;
|
||||
}
|
||||
case IconWithWordWrapText: {
|
||||
int textHeight = fontMetrics().lineSpacing() * 2;
|
||||
int iconHeight = h - textHeight;
|
||||
if (iconHeight > 0) {
|
||||
setIconSize(QSize(w - 2 * spacing() - shiftpix, iconHeight - 2 * spacing() - shiftpix));
|
||||
} else {
|
||||
setIconSize(QSize(w - 2 * spacing() - shiftpix, h - 2 * spacing() - shiftpix));
|
||||
}
|
||||
break;
|
||||
}
|
||||
case IconOnly: {
|
||||
setIconSize(QSize(w - 2 * spacing() - shiftpix, h - 2 * spacing() - shiftpix));
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
setIconSize(QSize(w - 2 * spacing() - shiftpix, h - 2 * spacing() - shiftpix));
|
||||
break;
|
||||
}
|
||||
}
|
||||
#if 0
|
||||
qDebug() << "SARibbonGalleryGroup::recalcGridSize(" << galleryHeight << "): gridSize=" << gridSize()
|
||||
<< " iconSize=" << iconSize();
|
||||
#endif
|
||||
}
|
||||
|
||||
///
|
||||
/// \brief 设置默认的预设样式
|
||||
/// \param style
|
||||
///
|
||||
void SARibbonGalleryGroup::setGalleryGroupStyle(SARibbonGalleryGroup::GalleryGroupStyle style)
|
||||
{
|
||||
d_ptr->mPreStyle = style;
|
||||
if (style == IconWithWordWrapText) {
|
||||
setWordWrap(true);
|
||||
}
|
||||
recalcGridSize();
|
||||
}
|
||||
|
||||
SARibbonGalleryGroup::GalleryGroupStyle SARibbonGalleryGroup::galleryGroupStyle() const
|
||||
{
|
||||
return d_ptr->mPreStyle;
|
||||
}
|
||||
|
||||
void SARibbonGalleryGroup::addItem(const QString& text, const QIcon& icon)
|
||||
{
|
||||
if (nullptr == groupModel()) {
|
||||
return;
|
||||
}
|
||||
addItem(new SARibbonGalleryItem(text, icon));
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 添加一个条目
|
||||
*
|
||||
* @param item 条目的内存所有权归属SARibbonGalleryGroup管理
|
||||
*/
|
||||
void SARibbonGalleryGroup::addItem(SARibbonGalleryItem* item)
|
||||
{
|
||||
if (nullptr == groupModel()) {
|
||||
return;
|
||||
}
|
||||
groupModel()->append(item);
|
||||
}
|
||||
|
||||
void SARibbonGalleryGroup::addActionItem(QAction* act)
|
||||
{
|
||||
if (nullptr == groupModel()) {
|
||||
return;
|
||||
}
|
||||
d_ptr->mActionGroup->addAction(act);
|
||||
groupModel()->append(new SARibbonGalleryItem(act));
|
||||
}
|
||||
|
||||
void SARibbonGalleryGroup::addActionItemList(const QList< QAction* >& acts)
|
||||
{
|
||||
SARibbonGalleryGroupModel* model = groupModel();
|
||||
|
||||
if (nullptr == model) {
|
||||
return;
|
||||
}
|
||||
for (QAction* a : acts) {
|
||||
d_ptr->mActionGroup->addAction(a);
|
||||
}
|
||||
for (int i = 0; i < acts.size(); ++i) {
|
||||
model->append(new SARibbonGalleryItem(acts[ i ]));
|
||||
}
|
||||
}
|
||||
|
||||
///
|
||||
/// \brief 构建一个model,这个model的父类是SARibbonGalleryGroup,如果要共享model,需要手动处理model的父类
|
||||
///
|
||||
void SARibbonGalleryGroup::setupGroupModel()
|
||||
{
|
||||
setModel(new SARibbonGalleryGroupModel(this));
|
||||
}
|
||||
|
||||
SARibbonGalleryGroupModel* SARibbonGalleryGroup::groupModel()
|
||||
{
|
||||
return (qobject_cast< SARibbonGalleryGroupModel* >(model()));
|
||||
}
|
||||
|
||||
void SARibbonGalleryGroup::setGroupTitle(const QString& title)
|
||||
{
|
||||
d_ptr->mGroupTitle = title;
|
||||
Q_EMIT groupTitleChanged(d_ptr->mGroupTitle);
|
||||
}
|
||||
|
||||
QString SARibbonGalleryGroup::groupTitle() const
|
||||
{
|
||||
return (d_ptr->mGroupTitle);
|
||||
}
|
||||
|
||||
void SARibbonGalleryGroup::selectByIndex(int i)
|
||||
{
|
||||
SARibbonGalleryGroupModel* model = groupModel();
|
||||
|
||||
if (nullptr == model) {
|
||||
return;
|
||||
}
|
||||
QModelIndex ind = model->index(i, 0, QModelIndex());
|
||||
QItemSelectionModel* selmodel = selectionModel();
|
||||
|
||||
if (selmodel) {
|
||||
selmodel->select(ind, QItemSelectionModel::SelectCurrent);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 设置显示的行数
|
||||
* @param r
|
||||
*/
|
||||
void SARibbonGalleryGroup::setDisplayRow(DisplayRow r)
|
||||
{
|
||||
d_ptr->mDisplayRow = r;
|
||||
recalcGridSize();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Gallery显示的行数
|
||||
* @return
|
||||
*/
|
||||
SARibbonGalleryGroup::DisplayRow SARibbonGalleryGroup::displayRow() const
|
||||
{
|
||||
return d_ptr->mDisplayRow;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 设置grid最小的宽度,默认为0(不限制)
|
||||
* @param w
|
||||
*/
|
||||
void SARibbonGalleryGroup::setGridMinimumWidth(int w)
|
||||
{
|
||||
d_ptr->mGridMinimumWidth = w;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief grid最小的宽度,默认为0(不限制)
|
||||
* @return
|
||||
*/
|
||||
int SARibbonGalleryGroup::gridMinimumWidth() const
|
||||
{
|
||||
return d_ptr->mGridMinimumWidth;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 设置grid最大的宽度,默认为0(不限制)
|
||||
* @param w
|
||||
*/
|
||||
void SARibbonGalleryGroup::setGridMaximumWidth(int w)
|
||||
{
|
||||
d_ptr->mGridMaximumWidth = w;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief grid最大的的宽度,默认为0(不限制)
|
||||
* @param w
|
||||
*/
|
||||
int SARibbonGalleryGroup::gridMaximumWidth() const
|
||||
{
|
||||
return d_ptr->mGridMaximumWidth;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 获取SARibbonGalleryGroup管理的actiongroup
|
||||
* @return
|
||||
*/
|
||||
QActionGroup* SARibbonGalleryGroup::actionGroup() const
|
||||
{
|
||||
return d_ptr->mActionGroup;
|
||||
}
|
||||
|
||||
void SARibbonGalleryGroup::onItemClicked(const QModelIndex& index)
|
||||
{
|
||||
if (index.isValid()) {
|
||||
SARibbonGalleryItem* item = (SARibbonGalleryItem*)index.internalPointer();
|
||||
if (item) {
|
||||
QAction* act = item->action();
|
||||
if (act) {
|
||||
act->activate(QAction::Trigger);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void SARibbonGalleryGroup::onItemEntered(const QModelIndex& index)
|
||||
{
|
||||
if (index.isValid()) {
|
||||
SARibbonGalleryItem* item = (SARibbonGalleryItem*)index.internalPointer();
|
||||
if (item) {
|
||||
QAction* act = item->action();
|
||||
if (act) {
|
||||
act->activate(QAction::Hover);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,138 @@
|
||||
#ifndef SARIBBONGALLERYGROUP_H
|
||||
#define SARIBBONGALLERYGROUP_H
|
||||
#include "SARibbonGlobal.h"
|
||||
#include <QList>
|
||||
#include <QListView>
|
||||
#include <QStyledItemDelegate>
|
||||
#include "SARibbonGalleryItem.h"
|
||||
|
||||
///
|
||||
/// \brief SARibbonGalleryGroup对应的显示代理
|
||||
///
|
||||
class SA_RIBBON_EXPORT SARibbonGalleryGroupItemDelegate : public QStyledItemDelegate
|
||||
{
|
||||
public:
|
||||
explicit SARibbonGalleryGroupItemDelegate(SARibbonGalleryGroup* group, QObject* parent = nullptr);
|
||||
~SARibbonGalleryGroupItemDelegate();
|
||||
virtual void paint(QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex& index) const override;
|
||||
|
||||
virtual QSize sizeHint(const QStyleOptionViewItem& option, const QModelIndex& index) const override;
|
||||
virtual void paintIconOnly(QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex& index) const;
|
||||
virtual void paintIconWithText(QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex& index) const;
|
||||
virtual void paintIconWithTextWordWrap(QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex& index) const;
|
||||
|
||||
private:
|
||||
SARibbonGalleryGroup* mGroup;
|
||||
};
|
||||
|
||||
///
|
||||
/// \brief SARibbonGalleryGroup对应的model
|
||||
///
|
||||
class SA_RIBBON_EXPORT SARibbonGalleryGroupModel : public QAbstractListModel
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
SARibbonGalleryGroupModel(QObject* parent = Q_NULLPTR);
|
||||
~SARibbonGalleryGroupModel();
|
||||
virtual int rowCount(const QModelIndex& parent) const Q_DECL_OVERRIDE;
|
||||
virtual Qt::ItemFlags flags(const QModelIndex& index) const Q_DECL_OVERRIDE;
|
||||
virtual QVariant data(const QModelIndex& index, int role) const Q_DECL_OVERRIDE;
|
||||
virtual QModelIndex index(int row, int column, const QModelIndex& parent) const Q_DECL_OVERRIDE;
|
||||
virtual bool setData(const QModelIndex& index, const QVariant& value, int role) Q_DECL_OVERRIDE;
|
||||
void clear();
|
||||
SARibbonGalleryItem* at(int row) const;
|
||||
void insert(int row, SARibbonGalleryItem* item);
|
||||
SARibbonGalleryItem* take(int row);
|
||||
void append(SARibbonGalleryItem* item);
|
||||
|
||||
private:
|
||||
QList< SARibbonGalleryItem* > mItems;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Gallery的组
|
||||
*
|
||||
* 组负责显示管理Gallery Item
|
||||
*/
|
||||
class SA_RIBBON_EXPORT SARibbonGalleryGroup : public QListView
|
||||
{
|
||||
Q_OBJECT
|
||||
SA_RIBBON_DECLARE_PRIVATE(SARibbonGalleryGroup)
|
||||
public:
|
||||
/**
|
||||
* @brief GalleryGroup显示的样式
|
||||
*/
|
||||
enum GalleryGroupStyle
|
||||
{
|
||||
IconWithText, ///< 图标带文字
|
||||
IconWithWordWrapText, ///< 图标带文字,文字会换行显示,此模式只会对DisplayOneRow生效,如果不是DisplayOneRow,等同IconWithText
|
||||
IconOnly ///< 只有图标
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief 定义Gallery在一个pannel下面显示的图标行数
|
||||
*/
|
||||
enum DisplayRow
|
||||
{
|
||||
DisplayOneRow = 1, ///< 显示1行,默认
|
||||
DisplayTwoRow = 2,
|
||||
DisplayThreeRow = 3
|
||||
};
|
||||
|
||||
SARibbonGalleryGroup(QWidget* w = 0);
|
||||
|
||||
virtual ~SARibbonGalleryGroup();
|
||||
// 重新计算grid尺寸
|
||||
void setRecalcGridSizeBlock(bool on = true);
|
||||
bool isRecalcGridSizeBlock() const;
|
||||
void recalcGridSize();
|
||||
void recalcGridSize(int galleryHeight);
|
||||
// 设置显示的样式
|
||||
void setGalleryGroupStyle(GalleryGroupStyle style);
|
||||
GalleryGroupStyle galleryGroupStyle() const;
|
||||
// 添加一个item
|
||||
void addItem(const QString& text, const QIcon& icon);
|
||||
void addItem(SARibbonGalleryItem* item);
|
||||
// 以一个aciton作为item添加
|
||||
void addActionItem(QAction* act);
|
||||
void addActionItemList(const QList< QAction* >& acts);
|
||||
|
||||
// 构建一个model,这个model的父类是SARibbonGalleryGroup,如果要共享model,需要手动处理model的父类
|
||||
void setupGroupModel();
|
||||
SARibbonGalleryGroupModel* groupModel();
|
||||
// 标题
|
||||
void setGroupTitle(const QString& title);
|
||||
QString groupTitle() const;
|
||||
void selectByIndex(int i);
|
||||
// 设置显示的行数
|
||||
void setDisplayRow(DisplayRow r);
|
||||
DisplayRow displayRow() const;
|
||||
// 设置grid最小的宽度,默认为0(不限制),可以限定grid的宽度
|
||||
void setGridMinimumWidth(int w);
|
||||
int gridMinimumWidth() const;
|
||||
// 设置grid最大的宽度,默认为0(不限制),可以限定grid的宽度
|
||||
void setGridMaximumWidth(int w);
|
||||
int gridMaximumWidth() const;
|
||||
// 获取SARibbonGalleryGroup管理的actiongroup
|
||||
QActionGroup* actionGroup() const;
|
||||
private Q_SLOTS:
|
||||
void onItemClicked(const QModelIndex& index);
|
||||
void onItemEntered(const QModelIndex& index);
|
||||
Q_SIGNALS:
|
||||
void groupTitleChanged(const QString& title);
|
||||
/**
|
||||
* @brief 等同QActionGroup的triggered
|
||||
* 所有加入SARibbonGalleryGroup的action都会被一个QActionGroup管理,可以通过@sa getActionGroup 获取到对应的actiongroup
|
||||
* @param action
|
||||
*/
|
||||
void triggered(QAction* action);
|
||||
/**
|
||||
* @brief 等同QActionGroup的triggered
|
||||
* 所有加入SARibbonGalleryGroup的action都会被一个QActionGroup管理,可以通过@sa getActionGroup 获取到对应的actiongroup
|
||||
* @note 此属性需要通过QAbstractItemView::entered(const QModelIndex &index)激活,因此要保证设置了setMouseTracking(true)
|
||||
* @param action
|
||||
*/
|
||||
void hovered(QAction* action);
|
||||
};
|
||||
|
||||
#endif // SARIBBONGALLERYGROUP_H
|
||||
@@ -0,0 +1,163 @@
|
||||
#include "SARibbonGalleryItem.h"
|
||||
#include "SARibbonGalleryGroup.h"
|
||||
|
||||
SARibbonGalleryItem::SARibbonGalleryItem() : mFlags(Qt::ItemIsEnabled | Qt::ItemIsSelectable), mAction(nullptr)
|
||||
{
|
||||
}
|
||||
|
||||
SARibbonGalleryItem::SARibbonGalleryItem(const QString& text, const QIcon& icon)
|
||||
: mFlags(Qt::ItemIsEnabled | Qt::ItemIsSelectable), mAction(nullptr)
|
||||
{
|
||||
setText(text);
|
||||
setIcon(icon);
|
||||
setTextAlignment(Qt::AlignTop | Qt::AlignHCenter);
|
||||
}
|
||||
|
||||
SARibbonGalleryItem::SARibbonGalleryItem(QAction* act) : mFlags(Qt::ItemIsEnabled | Qt::ItemIsSelectable)
|
||||
{
|
||||
setTextAlignment(Qt::AlignTop | Qt::AlignHCenter);
|
||||
setAction(act);
|
||||
}
|
||||
|
||||
SARibbonGalleryItem::~SARibbonGalleryItem()
|
||||
{
|
||||
}
|
||||
|
||||
void SARibbonGalleryItem::setData(int role, const QVariant& data)
|
||||
{
|
||||
mDatas[ role ] = data;
|
||||
}
|
||||
|
||||
QVariant SARibbonGalleryItem::data(int role) const
|
||||
{
|
||||
if (mAction) {
|
||||
switch (role) {
|
||||
case Qt::DisplayRole:
|
||||
return (mAction->text());
|
||||
|
||||
case Qt::ToolTipRole:
|
||||
return (mAction->toolTip());
|
||||
|
||||
case Qt::DecorationRole:
|
||||
return (mAction->icon());
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
return (mDatas.value(role));
|
||||
}
|
||||
|
||||
void SARibbonGalleryItem::setText(const QString& text)
|
||||
{
|
||||
setData(Qt::DisplayRole, text);
|
||||
}
|
||||
|
||||
QString SARibbonGalleryItem::text() const
|
||||
{
|
||||
if (mAction) {
|
||||
return (mAction->text());
|
||||
}
|
||||
return (data(Qt::DisplayRole).toString());
|
||||
}
|
||||
|
||||
void SARibbonGalleryItem::setToolTip(const QString& text)
|
||||
{
|
||||
setData(Qt::ToolTipRole, text);
|
||||
}
|
||||
|
||||
QString SARibbonGalleryItem::toolTip() const
|
||||
{
|
||||
if (mAction) {
|
||||
return (mAction->toolTip());
|
||||
}
|
||||
return (data(Qt::ToolTipRole).toString());
|
||||
}
|
||||
|
||||
void SARibbonGalleryItem::setIcon(const QIcon& ico)
|
||||
{
|
||||
setData(Qt::DecorationRole, ico);
|
||||
}
|
||||
|
||||
QIcon SARibbonGalleryItem::icon() const
|
||||
{
|
||||
if (mAction) {
|
||||
return (mAction->icon());
|
||||
}
|
||||
return (qvariant_cast< QIcon >(data(Qt::DecorationRole)));
|
||||
}
|
||||
|
||||
bool SARibbonGalleryItem::isSelectable() const
|
||||
{
|
||||
return (mFlags & Qt::ItemIsSelectable);
|
||||
}
|
||||
|
||||
void SARibbonGalleryItem::setSelectable(bool isSelectable)
|
||||
{
|
||||
if (isSelectable) {
|
||||
mFlags |= Qt::ItemIsSelectable;
|
||||
} else {
|
||||
mFlags = (mFlags & (~Qt::ItemIsSelectable));
|
||||
}
|
||||
}
|
||||
|
||||
bool SARibbonGalleryItem::isEnable() const
|
||||
{
|
||||
if (mAction) {
|
||||
return (mAction->isEnabled());
|
||||
}
|
||||
return (mFlags & Qt::ItemIsEnabled);
|
||||
}
|
||||
|
||||
void SARibbonGalleryItem::setEnable(bool isEnable)
|
||||
{
|
||||
if (mAction) {
|
||||
mAction->setEnabled(isEnable);
|
||||
}
|
||||
|
||||
if (isEnable) {
|
||||
mFlags |= Qt::ItemIsEnabled;
|
||||
} else {
|
||||
mFlags = (mFlags & (~Qt::ItemIsEnabled));
|
||||
}
|
||||
}
|
||||
|
||||
void SARibbonGalleryItem::setFlags(Qt::ItemFlags flag)
|
||||
{
|
||||
mFlags = flag;
|
||||
if (mAction) {
|
||||
mAction->setEnabled(flag & Qt::ItemIsEnabled);
|
||||
}
|
||||
}
|
||||
|
||||
Qt::ItemFlags SARibbonGalleryItem::flags() const
|
||||
{
|
||||
return (mFlags);
|
||||
}
|
||||
|
||||
void SARibbonGalleryItem::setAction(QAction* act)
|
||||
{
|
||||
mAction = act;
|
||||
if (nullptr == mAction) {
|
||||
return;
|
||||
}
|
||||
if (act->isEnabled()) {
|
||||
mFlags |= Qt::ItemIsEnabled;
|
||||
} else {
|
||||
mFlags = (mFlags & (~Qt::ItemIsEnabled));
|
||||
}
|
||||
}
|
||||
|
||||
QAction* SARibbonGalleryItem::action()
|
||||
{
|
||||
return (mAction);
|
||||
}
|
||||
|
||||
void SARibbonGalleryItem::setTextAlignment(Qt::Alignment a)
|
||||
{
|
||||
setData(Qt::TextAlignmentRole, (int)a);
|
||||
}
|
||||
|
||||
Qt::Alignment SARibbonGalleryItem::textAlignment() const
|
||||
{
|
||||
return qvariant_cast< Qt::Alignment >(data(Qt::TextAlignmentRole));
|
||||
}
|
||||
@@ -0,0 +1,64 @@
|
||||
#ifndef SARIBBONGALLERYITEM_H
|
||||
#define SARIBBONGALLERYITEM_H
|
||||
#include "SARibbonGlobal.h"
|
||||
#include <QIcon>
|
||||
#include <QVariant>
|
||||
#include <QMap>
|
||||
#include <QAction>
|
||||
class SARibbonGalleryGroup;
|
||||
|
||||
///
|
||||
/// \brief 类似QStandardItem的GalleryItem
|
||||
///
|
||||
class SA_RIBBON_EXPORT SARibbonGalleryItem
|
||||
{
|
||||
friend class SARibbonGalleryGroupModel;
|
||||
|
||||
public:
|
||||
explicit SARibbonGalleryItem();
|
||||
explicit SARibbonGalleryItem(const QString& text, const QIcon& icon);
|
||||
explicit SARibbonGalleryItem(QAction* act);
|
||||
virtual ~SARibbonGalleryItem();
|
||||
// 设置角色
|
||||
void setData(int role, const QVariant& data);
|
||||
virtual QVariant data(int role) const;
|
||||
|
||||
// 设置文字描述
|
||||
void setText(const QString& text);
|
||||
QString text() const;
|
||||
|
||||
// 设置tooltip
|
||||
void setToolTip(const QString& text);
|
||||
QString toolTip() const;
|
||||
|
||||
// 设置图标
|
||||
void setIcon(const QIcon& ico);
|
||||
QIcon icon() const;
|
||||
|
||||
// 设置是否可见
|
||||
bool isSelectable() const;
|
||||
void setSelectable(bool isSelectable);
|
||||
|
||||
// 设置是否可选
|
||||
bool isEnable() const;
|
||||
void setEnable(bool isEnable);
|
||||
|
||||
// 设置item的flag
|
||||
void setFlags(Qt::ItemFlags flag);
|
||||
virtual Qt::ItemFlags flags() const;
|
||||
|
||||
// 设置action
|
||||
void setAction(QAction* act);
|
||||
QAction* action();
|
||||
|
||||
// 文字对齐方式
|
||||
void setTextAlignment(Qt::Alignment a);
|
||||
Qt::Alignment textAlignment() const;
|
||||
|
||||
private:
|
||||
QMap< int, QVariant > mDatas;
|
||||
Qt::ItemFlags mFlags;
|
||||
QAction* mAction;
|
||||
};
|
||||
|
||||
#endif // SARIBBONGALLERYITEM_H
|
||||
@@ -0,0 +1,149 @@
|
||||
#ifndef SARIBBONGLOBAL_H
|
||||
#define SARIBBONGLOBAL_H
|
||||
#include <memory>
|
||||
#include <QtGlobal>
|
||||
#include <QObject>
|
||||
#include "SARibbonBarVersionInfo.h"
|
||||
class QWidget;
|
||||
|
||||
#ifndef SA_RIBBON_BAR_NO_EXPORT
|
||||
#if defined(SA_RIBBON_BAR_MAKE_LIB) // 定义此宏将构建library
|
||||
#define SA_RIBBON_EXPORT Q_DECL_EXPORT
|
||||
#else
|
||||
#define SA_RIBBON_EXPORT Q_DECL_IMPORT
|
||||
#endif
|
||||
#endif
|
||||
#ifndef SA_RIBBON_EXPORT
|
||||
#define SA_RIBBON_EXPORT
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @def 模仿Q_DECLARE_PRIVATE,但不用前置声明而是作为一个内部类
|
||||
*/
|
||||
#ifndef SA_RIBBON_DECLARE_PRIVATE
|
||||
#define SA_RIBBON_DECLARE_PRIVATE(classname) \
|
||||
class PrivateData; \
|
||||
friend class classname::PrivateData; \
|
||||
std::unique_ptr< PrivateData > d_ptr;
|
||||
#endif
|
||||
/**
|
||||
* @def 模仿Q_DECLARE_PUBLIC
|
||||
*/
|
||||
#ifndef SA_RIBBON_DECLARE_PUBLIC
|
||||
#define SA_RIBBON_DECLARE_PUBLIC(classname) \
|
||||
friend class classname; \
|
||||
classname* q_ptr { nullptr }; \
|
||||
PrivateData(const PrivateData&) = delete; \
|
||||
PrivateData& operator=(const PrivateData&) = delete;
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief 定义Ribbon的对其方式,目前支持左对齐和居中对其
|
||||
*
|
||||
* @note 如果你编译器提示:成员声明的限定名称非法,那么留意一下文件换行是否为LF,如果是把文件换行改为CRLF
|
||||
*/
|
||||
enum class SARibbonAlignment
|
||||
{
|
||||
AlignLeft, ///< 左对齐,tab栏左对齐,同时category也是左对齐
|
||||
AlignCenter ///< 居中对其,tab栏居中对齐,同时category也是居中对齐
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief ribbon主题
|
||||
*
|
||||
* 注意,由于有些qss的尺寸,在C++代码中无法获取到,因此针对用户自定义的qss主题,有些尺寸是需要手动设置进去的
|
||||
*
|
||||
* 例如ribbon tab的margin信息,在QTabBar是无法获取到,而这个影响了SARibbonContextCategory的绘制,
|
||||
* 因此,在设置qss后需要针对margin信息重新设置进SARibbonTabBar中
|
||||
*/
|
||||
enum class SARibbonTheme
|
||||
{
|
||||
RibbonThemeOffice2013, ///< office2013主题
|
||||
RibbonThemeOffice2016Blue, ///< office2016-蓝色主题
|
||||
RibbonThemeOffice2021Blue, ///< office2021-蓝色主题
|
||||
RibbonThemeWindows7, ///< win7主题
|
||||
RibbonThemeDark, ///< 暗色主题
|
||||
RibbonThemeDark2
|
||||
};
|
||||
|
||||
/**
|
||||
* @def 属性,用于标记是否可以进行自定义,用于动态设置到@ref SARibbonCategory 和@ref SARibbonPannel
|
||||
* 值为bool,在为true时,可以通过@ref SARibbonCustomizeWidget 改变这个SARibbonCategory和SARibbonPannel的布局,
|
||||
* 默认不会有此属性,仅在有此属性且为true时才会在SARibbonCustomizeWidget中能显示为可设置
|
||||
*/
|
||||
#ifndef SA_RIBBON_BAR_PROP_CAN_CUSTOMIZE
|
||||
#define SA_RIBBON_BAR_PROP_CAN_CUSTOMIZE "_sa_isCanCustomize"
|
||||
#endif
|
||||
|
||||
#if (QT_VERSION >= QT_VERSION_CHECK(5, 11, 0))
|
||||
#ifndef SA_FONTMETRICS_WIDTH
|
||||
#define SA_FONTMETRICS_WIDTH(fm, str) fm.horizontalAdvance(str)
|
||||
#endif
|
||||
#else
|
||||
#ifndef SA_FONTMETRICS_WIDTH
|
||||
#define SA_FONTMETRICS_WIDTH(fm, str) fm.width(str)
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if (QT_VERSION >= QT_VERSION_CHECK(6, 0, 0))
|
||||
#ifndef SA_MOUSEEVENT_GLOBALPOS_POINT
|
||||
#define SA_MOUSEEVENT_GLOBALPOS_POINT(MouseEventPtr) MouseEventPtr->globalPosition().toPoint()
|
||||
#endif
|
||||
#else
|
||||
#ifndef SA_MOUSEEVENT_GLOBALPOS_POINT
|
||||
#define SA_MOUSEEVENT_GLOBALPOS_POINT(MouseEventPtr) MouseEventPtr->globalPos()
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if (QT_VERSION >= QT_VERSION_CHECK(6, 0, 0))
|
||||
#ifndef SA_HOVEREVENT_POS_POINT
|
||||
#define SA_HOVEREVENT_POS_POINT(HoverEventPtr) HoverEventPtr->position().toPoint()
|
||||
#endif
|
||||
#else
|
||||
#ifndef SA_HOVEREVENT_POS_POINT
|
||||
#define SA_HOVEREVENT_POS_POINT(HoverEventPtr) HoverEventPtr->pos()
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/**
|
||||
@def 定义此宏,将打印和尺寸刷新相关的信息
|
||||
|
||||
仅用于调试
|
||||
*/
|
||||
#ifndef SA_DEBUG_PRINT_SIZE_HINT
|
||||
#define SA_DEBUG_PRINT_SIZE_HINT 0
|
||||
#endif
|
||||
|
||||
/**
|
||||
@def 定义此宏,将打印事件
|
||||
|
||||
仅用于调试
|
||||
*/
|
||||
#ifndef SA_DEBUG_PRINT_EVENT
|
||||
#define SA_DEBUG_PRINT_EVENT 0
|
||||
#endif
|
||||
|
||||
/**
|
||||
@def 定义此宏,qDebug将支持SARibbonBar的属性打印
|
||||
|
||||
仅用于调试
|
||||
*/
|
||||
#ifndef SA_DEBUG_PRINT_SARIBBONBAR
|
||||
#define SA_DEBUG_PRINT_SARIBBONBAR 0
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief 全局的设置ribbon theme函数
|
||||
*
|
||||
* 之所以提供此函数,是因为在某些情况下,SARibbonBar不用在SARibbonMainWindow情况下的时候,也需要设置主题,
|
||||
* 但主题设置是在SARibbonMainWindow下的为了能在非SARibbonMainWindow下也能设置主题,这里提供@sa sa_set_ribbon_theme函数,
|
||||
* 可以这样使用:
|
||||
* @code
|
||||
* @endcode
|
||||
*
|
||||
* @param w
|
||||
* @param theme
|
||||
*/
|
||||
void SA_RIBBON_EXPORT sa_set_ribbon_theme(QWidget* w, SARibbonTheme theme);
|
||||
|
||||
#endif // SARIBBONGLOBAL_H
|
||||
@@ -0,0 +1,17 @@
|
||||
#include "SARibbonLineEdit.h"
|
||||
#include <QStyleOption>
|
||||
|
||||
SARibbonLineEdit::SARibbonLineEdit(QWidget *parent)
|
||||
: QLineEdit(parent)
|
||||
{
|
||||
}
|
||||
|
||||
SARibbonLineEdit::SARibbonLineEdit(const QString &text, QWidget *parent)
|
||||
: QLineEdit(text, parent)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
SARibbonLineEdit::~SARibbonLineEdit()
|
||||
{
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
#ifndef SARIBBONLINEEDIT_H
|
||||
#define SARIBBONLINEEDIT_H
|
||||
#include "SARibbonGlobal.h"
|
||||
#include <QLineEdit>
|
||||
|
||||
|
||||
/**
|
||||
* @brief The SARibbonLineEdit class
|
||||
*/
|
||||
class SA_RIBBON_EXPORT SARibbonLineEdit : public QLineEdit
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit SARibbonLineEdit(QWidget *parent = nullptr);
|
||||
explicit SARibbonLineEdit(const QString &text, QWidget *parent = nullptr);
|
||||
~SARibbonLineEdit();
|
||||
};
|
||||
|
||||
#endif // SARIBBONLINEEDIT_H
|
||||
@@ -0,0 +1,57 @@
|
||||
#include "SARibbonLineWidgetContainer.h"
|
||||
#include <QHBoxLayout>
|
||||
|
||||
SARibbonLineWidgetContainer::SARibbonLineWidgetContainer(QWidget *par) : QWidget(par)
|
||||
, m_innerWidget(nullptr)
|
||||
{
|
||||
m_labelPrefix = new QLabel(this);
|
||||
m_labelSuffix = new QLabel(this);
|
||||
QHBoxLayout *lay = new QHBoxLayout();
|
||||
|
||||
lay->setContentsMargins(0, 0, 0, 0);
|
||||
lay->setSpacing(0);
|
||||
lay->addWidget(m_labelPrefix);
|
||||
lay->addWidget(m_labelSuffix);
|
||||
setLayout(lay);
|
||||
}
|
||||
|
||||
SARibbonLineWidgetContainer::~SARibbonLineWidgetContainer()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
void SARibbonLineWidgetContainer::setWidget(QWidget *innerWidget)
|
||||
{
|
||||
QHBoxLayout *lay = static_cast<QHBoxLayout *>(layout());
|
||||
|
||||
if (m_innerWidget) {
|
||||
lay->replaceWidget(m_innerWidget, innerWidget);
|
||||
}else{
|
||||
lay->insertWidget(1, innerWidget);
|
||||
}
|
||||
m_innerWidget = innerWidget;
|
||||
}
|
||||
|
||||
|
||||
void SARibbonLineWidgetContainer::setPrefix(const QString& str)
|
||||
{
|
||||
m_labelPrefix->setText(str);
|
||||
}
|
||||
|
||||
|
||||
void SARibbonLineWidgetContainer::setSuffix(const QString& str)
|
||||
{
|
||||
m_labelSuffix->setText(str);
|
||||
}
|
||||
|
||||
|
||||
QLabel *SARibbonLineWidgetContainer::labelPrefix() const
|
||||
{
|
||||
return (m_labelPrefix);
|
||||
}
|
||||
|
||||
|
||||
QLabel *SARibbonLineWidgetContainer::labelSuffix() const
|
||||
{
|
||||
return (m_labelSuffix);
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
#ifndef SARIBBONLINEWIDGETCONTAINER_H
|
||||
#define SARIBBONLINEWIDGETCONTAINER_H
|
||||
|
||||
#include <QtCore/qglobal.h>
|
||||
#include <QWidget>
|
||||
#include <QLabel>
|
||||
#include "SARibbonGlobal.h"
|
||||
|
||||
/**
|
||||
* @brief 一个窗口容器,把窗口放置中间,前面后面都可以设置文本,主要用于放置在pannel上的小窗口
|
||||
*
|
||||
* 实现如下效果:
|
||||
*
|
||||
* PrefixLabel|_Widget_|SuffixLabel
|
||||
*
|
||||
*/
|
||||
class SA_RIBBON_EXPORT SARibbonLineWidgetContainer : public QWidget
|
||||
{
|
||||
public:
|
||||
explicit SARibbonLineWidgetContainer(QWidget* par = nullptr);
|
||||
~SARibbonLineWidgetContainer();
|
||||
//设置widget,不允许设置一个nullptr
|
||||
void setWidget(QWidget* innerWidget);
|
||||
|
||||
//设置前缀
|
||||
void setPrefix(const QString& str);
|
||||
|
||||
//设置后缀
|
||||
void setSuffix(const QString& str);
|
||||
|
||||
//前缀文本框
|
||||
QLabel* labelPrefix() const;
|
||||
|
||||
//后缀文本框
|
||||
QLabel* labelSuffix() const;
|
||||
|
||||
private:
|
||||
//两个文本
|
||||
QLabel* m_labelPrefix;
|
||||
QLabel* m_labelSuffix;
|
||||
QWidget* m_innerWidget;
|
||||
};
|
||||
|
||||
#endif // SARIBBONWIDGETCONTAINER_H
|
||||
@@ -0,0 +1,382 @@
|
||||
#include "SARibbonMainWindow.h"
|
||||
#include "SARibbonBar.h"
|
||||
#include "SARibbonElementManager.h"
|
||||
#include "SARibbonTabBar.h"
|
||||
#include <QApplication>
|
||||
#include <QDebug>
|
||||
#include <QFile>
|
||||
#include <QHash>
|
||||
#include <QWindowStateChangeEvent>
|
||||
#include <QScreen>
|
||||
|
||||
#include "SARibbonSystemButtonBar.h"
|
||||
#if SARIBBON_USE_3RDPARTY_FRAMELESSHELPER
|
||||
#include <QWKWidgets/widgetwindowagent.h>
|
||||
#include "SARibbonButtonGroupWidget.h"
|
||||
#include "SARibbonQuickAccessBar.h"
|
||||
#include "SARibbonStackedWidget.h"
|
||||
#else
|
||||
#include "SAFramelessHelper.h"
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief The SARibbonMainWindowPrivate class
|
||||
*/
|
||||
class SARibbonMainWindow::PrivateData
|
||||
{
|
||||
SA_RIBBON_DECLARE_PUBLIC(SARibbonMainWindow)
|
||||
public:
|
||||
PrivateData(SARibbonMainWindow* p);
|
||||
void installFrameless(SARibbonMainWindow* p);
|
||||
|
||||
public:
|
||||
SARibbonTheme mCurrentRibbonTheme { SARibbonTheme::RibbonThemeOffice2021Blue };
|
||||
SARibbonSystemButtonBar* mWindowButtonGroup { nullptr };
|
||||
#if SARIBBON_USE_3RDPARTY_FRAMELESSHELPER
|
||||
QWK::WidgetWindowAgent* mFramelessHelper { nullptr };
|
||||
#else
|
||||
SAFramelessHelper* mFramelessHelper { nullptr };
|
||||
#endif
|
||||
SARibbonMainWindowEventFilter* mEventFilter { nullptr };
|
||||
};
|
||||
|
||||
SARibbonMainWindow::PrivateData::PrivateData(SARibbonMainWindow* p) : q_ptr(p)
|
||||
{
|
||||
}
|
||||
|
||||
void SARibbonMainWindow::PrivateData::installFrameless(SARibbonMainWindow* p)
|
||||
{
|
||||
#if SARIBBON_USE_3RDPARTY_FRAMELESSHELPER
|
||||
mFramelessHelper = new QWK::WidgetWindowAgent(p);
|
||||
mFramelessHelper->setup(p);
|
||||
#else
|
||||
mFramelessHelper = new SAFramelessHelper(p);
|
||||
#endif
|
||||
}
|
||||
|
||||
//===================================================
|
||||
// SARibbonMainWindow
|
||||
//===================================================
|
||||
SARibbonMainWindow::SARibbonMainWindow(QWidget* parent, bool useRibbon, const Qt::WindowFlags flags)
|
||||
: QMainWindow(parent, flags), d_ptr(new SARibbonMainWindow::PrivateData(this))
|
||||
{
|
||||
connect(qApp, &QApplication::primaryScreenChanged, this, &SARibbonMainWindow::onPrimaryScreenChanged);
|
||||
if (useRibbon) {
|
||||
d_ptr->installFrameless(this);
|
||||
setRibbonBar(createRibbonBar());
|
||||
setRibbonTheme(ribbonTheme());
|
||||
}
|
||||
}
|
||||
|
||||
SARibbonMainWindow::~SARibbonMainWindow()
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 返回ribbonbar,如果不是使用ribbon模式,返回nullptr
|
||||
* @return
|
||||
*/
|
||||
SARibbonBar* SARibbonMainWindow::ribbonBar() const
|
||||
{
|
||||
return qobject_cast< SARibbonBar* >(menuWidget());
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 设置ribbonbar
|
||||
* @param bar
|
||||
*/
|
||||
void SARibbonMainWindow::setRibbonBar(SARibbonBar* ribbon)
|
||||
{
|
||||
QWidget* old = QMainWindow::menuWidget();
|
||||
if (old) {
|
||||
// 如果之前已经设置了menubar,要把之前的删除
|
||||
old->deleteLater();
|
||||
}
|
||||
QMainWindow::setMenuWidget(ribbon);
|
||||
const int th = ribbon->titleBarHeight();
|
||||
// 设置window按钮
|
||||
if (nullptr == d_ptr->mWindowButtonGroup) {
|
||||
d_ptr->mWindowButtonGroup = RibbonSubElementFactory->createWindowButtonGroup(this);
|
||||
// SARibbonSystemButtonBar的eventfilter捕获mainwindow的事件
|
||||
// 通过eventerfilter来处理mainwindow的事件,避免用户错误的继承resizeEvent导致systembar的位置异常
|
||||
installEventFilter(d_ptr->mWindowButtonGroup);
|
||||
}
|
||||
SARibbonSystemButtonBar* sysBar = d_ptr->mWindowButtonGroup;
|
||||
sysBar->setWindowStates(windowState());
|
||||
sysBar->setWindowTitleHeight(th);
|
||||
sysBar->raise(); // 确保sysbar在最顶层,避免第二次设置ribbonbar的时候,被ribbonbar覆盖了sysbar
|
||||
sysBar->show();
|
||||
#if SARIBBON_USE_3RDPARTY_FRAMELESSHELPER
|
||||
auto helper = d_ptr->mFramelessHelper;
|
||||
helper->setTitleBar(ribbon);
|
||||
// 以下这些窗口,需要允许点击
|
||||
helper->setHitTestVisible(sysBar); // IMPORTANT!
|
||||
helper->setHitTestVisible(ribbon->ribbonTabBar()); // IMPORTANT!
|
||||
helper->setHitTestVisible(ribbon->rightButtonGroup()); // IMPORTANT!
|
||||
helper->setHitTestVisible(ribbon->applicationButton()); // IMPORTANT!
|
||||
helper->setHitTestVisible(ribbon->quickAccessBar()); // IMPORTANT!
|
||||
helper->setHitTestVisible(ribbon->ribbonStackedWidget()); // IMPORTANT!
|
||||
#if SARIBBON_ENABLE_SNAP_LAYOUT
|
||||
if (sysBar->closeButton()) {
|
||||
helper->setSystemButton(QWK::WindowAgentBase::Close, sysBar->closeButton());
|
||||
}
|
||||
if (sysBar->minimizeButton()) {
|
||||
helper->setSystemButton(QWK::WindowAgentBase::Minimize, sysBar->minimizeButton());
|
||||
}
|
||||
if (sysBar->maximizeButton()) {
|
||||
helper->setSystemButton(QWK::WindowAgentBase::Maximize, sysBar->maximizeButton());
|
||||
}
|
||||
#endif
|
||||
#else
|
||||
// 捕获ribbonbar的事件
|
||||
ribbon->installEventFilter(this);
|
||||
// 设置窗体的标题栏高度
|
||||
d_ptr->mFramelessHelper->setTitleHeight(th);
|
||||
d_ptr->mFramelessHelper->setRubberBandOnResize(false);
|
||||
#endif
|
||||
if (!d_ptr->mEventFilter) {
|
||||
d_ptr->mEventFilter = new SARibbonMainWindowEventFilter(this);
|
||||
installEventFilter(d_ptr->mEventFilter);
|
||||
}
|
||||
// 最后要提升,否则新加入的会被覆盖
|
||||
if (d_ptr->mWindowButtonGroup) {
|
||||
d_ptr->mWindowButtonGroup->raise();
|
||||
}
|
||||
}
|
||||
|
||||
#if SARIBBON_USE_3RDPARTY_FRAMELESSHELPER
|
||||
|
||||
/**
|
||||
* @brief 如果ribbon中有自定义的窗口在标题栏等非点击区域加入后,想能点击,需要调用此接口告知可点击
|
||||
* @param w
|
||||
* @param visible
|
||||
*/
|
||||
void SARibbonMainWindow::setFramelessHitTestVisible(QWidget* w, bool visible)
|
||||
{
|
||||
auto helper = d_ptr->mFramelessHelper;
|
||||
helper->setHitTestVisible(const_cast<QWidget*>(w), visible);
|
||||
}
|
||||
#else
|
||||
|
||||
SAFramelessHelper* SARibbonMainWindow::framelessHelper()
|
||||
{
|
||||
return (d_ptr->mFramelessHelper);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
bool SARibbonMainWindow::eventFilter(QObject* obj, QEvent* e)
|
||||
{
|
||||
#if SARIBBON_USE_3RDPARTY_FRAMELESSHELPER
|
||||
#else
|
||||
// 这个过滤是为了把ribbonBar上的动作传递到mainwindow,再传递到frameless,
|
||||
// 由于ribbonbar会遮挡掉frameless的区域,导致frameless无法捕获这些消息
|
||||
// 因此必须ribbonBar()->installEventFilter(this);
|
||||
// 20240101发现installEventFilter后,SARibbonMainWindow没有执行这个回调
|
||||
if (obj == ribbonBar()) {
|
||||
switch (e->type()) {
|
||||
case QEvent::MouseButtonPress:
|
||||
case QEvent::MouseButtonRelease:
|
||||
case QEvent::MouseMove:
|
||||
case QEvent::Leave:
|
||||
case QEvent::HoverMove:
|
||||
case QEvent::MouseButtonDblClick:
|
||||
QApplication::sendEvent(this, e);
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
return (QMainWindow::eventFilter(obj, e));
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 获取系统按钮组,可以在此基础上添加其他按钮
|
||||
* @return
|
||||
*/
|
||||
SARibbonSystemButtonBar* SARibbonMainWindow::windowButtonBar() const
|
||||
{
|
||||
return d_ptr->mWindowButtonGroup;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 此函数仅用于控制最小最大化和关闭按钮的显示
|
||||
*/
|
||||
void SARibbonMainWindow::updateWindowFlag(Qt::WindowFlags flags)
|
||||
{
|
||||
if (SARibbonSystemButtonBar* g = d_ptr->mWindowButtonGroup) {
|
||||
g->updateWindowFlag(flags);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief SARibbonMainWindow::setRibbonTheme
|
||||
*
|
||||
* 注意主题在构造函数设置主题会不完全生效,使用QTimer投放到队列最后执行即可
|
||||
* @code
|
||||
* QTimer::singleShot(0, this, [ this ]() { this->setRibbonTheme(SARibbonMainWindow::RibbonThemeDark); });
|
||||
* @endcode
|
||||
* @param theme
|
||||
*/
|
||||
void SARibbonMainWindow::setRibbonTheme(SARibbonTheme theme)
|
||||
{
|
||||
sa_set_ribbon_theme(this, theme);
|
||||
d_ptr->mCurrentRibbonTheme = theme;
|
||||
if (SARibbonBar* bar = ribbonBar()) {
|
||||
auto theme = ribbonTheme();
|
||||
// 尺寸修正
|
||||
switch (theme) {
|
||||
case SARibbonTheme::RibbonThemeWindows7:
|
||||
case SARibbonTheme::RibbonThemeOffice2013:
|
||||
case SARibbonTheme::RibbonThemeOffice2016Blue:
|
||||
case SARibbonTheme::RibbonThemeDark:
|
||||
case SARibbonTheme::RibbonThemeDark2: {
|
||||
//! 在设置qss后需要针对margin信息重新设置进SARibbonTabBar中
|
||||
//! office2013.qss的margin信息如下设置
|
||||
//! margin-top: 0px;
|
||||
//! margin-right: 0px;
|
||||
//! margin-left: 5px;
|
||||
//! margin-bottom: 0px;
|
||||
SARibbonTabBar* tab = bar->ribbonTabBar();
|
||||
if (!tab) {
|
||||
break;
|
||||
}
|
||||
tab->setTabMargin(QMargins(5, 0, 0, 0));
|
||||
} break;
|
||||
case SARibbonTheme::RibbonThemeOffice2021Blue: {
|
||||
SARibbonTabBar* tab = bar->ribbonTabBar();
|
||||
if (!tab) {
|
||||
break;
|
||||
}
|
||||
//! 在设置qss后需要针对margin信息重新设置进SARibbonTabBar中
|
||||
//! office2021.qss的margin信息如下设置
|
||||
//! margin-top: 0px;
|
||||
//! margin-right: 5px;
|
||||
//! margin-left: 5px;
|
||||
//! margin-bottom: 0px;
|
||||
tab->setTabMargin(QMargins(5, 0, 5, 0));
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
// 上下文标签颜色设置,以及基线颜色设置
|
||||
switch (theme) {
|
||||
case SARibbonTheme::RibbonThemeWindows7:
|
||||
case SARibbonTheme::RibbonThemeOffice2013:
|
||||
case SARibbonTheme::RibbonThemeDark:
|
||||
bar->setContextCategoryColorList(QList< QColor >()); //< 设置空颜色列表会重置为默认色系
|
||||
break;
|
||||
case SARibbonTheme::RibbonThemeOffice2016Blue:
|
||||
bar->setContextCategoryColorList(QList< QColor >() << QColor(18, 64, 120)); //< 设置空颜色列表会重置为默认色系
|
||||
break;
|
||||
case SARibbonTheme::RibbonThemeOffice2021Blue:
|
||||
bar->setContextCategoryColorList(QList< QColor >() << QColor(209, 207, 209)); //< 设置空颜色列表会重置为默认色系
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
// 基线颜色设置
|
||||
if (SARibbonTheme::RibbonThemeOffice2013 == theme) {
|
||||
bar->setTabBarBaseLineColor(QColor(186, 201, 219));
|
||||
} else {
|
||||
bar->setTabBarBaseLineColor(QColor());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
SARibbonTheme SARibbonMainWindow::ribbonTheme() const
|
||||
{
|
||||
return (d_ptr->mCurrentRibbonTheme);
|
||||
}
|
||||
|
||||
bool SARibbonMainWindow::isUseRibbon() const
|
||||
{
|
||||
return (nullptr != ribbonBar());
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 创建ribbonbar的工厂函数
|
||||
*
|
||||
* 用户如果重写了SARibbonBar,可以通过重新此虚函数返回自己的Ribbon实例
|
||||
* @return
|
||||
*/
|
||||
SARibbonBar* SARibbonMainWindow::createRibbonBar()
|
||||
{
|
||||
SARibbonBar* bar = RibbonSubElementFactory->createRibbonBar(this);
|
||||
bar->setContentsMargins(3, 0, 3, 0);
|
||||
return bar;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 主屏幕切换触发的信号
|
||||
* @param screen
|
||||
*/
|
||||
void SARibbonMainWindow::onPrimaryScreenChanged(QScreen* screen)
|
||||
{
|
||||
Q_UNUSED(screen);
|
||||
// 主屏幕切换后,从新计算所有尺寸
|
||||
if (SARibbonBar* bar = ribbonBar()) {
|
||||
qDebug() << "Primary Screen Changed";
|
||||
bar->updateRibbonGeometry();
|
||||
}
|
||||
}
|
||||
|
||||
void sa_set_ribbon_theme(QWidget* w, SARibbonTheme theme)
|
||||
{
|
||||
QFile file;
|
||||
switch (theme) {
|
||||
case SARibbonTheme::RibbonThemeWindows7:
|
||||
file.setFileName(":/theme/resource/theme-win7.qss");
|
||||
break;
|
||||
case SARibbonTheme::RibbonThemeOffice2013:
|
||||
file.setFileName(":/theme/resource/theme-office2013.qss");
|
||||
break;
|
||||
case SARibbonTheme::RibbonThemeOffice2016Blue:
|
||||
file.setFileName(":/theme/resource/theme-office2016-blue.qss");
|
||||
break;
|
||||
case SARibbonTheme::RibbonThemeOffice2021Blue:
|
||||
file.setFileName(":/theme/resource/theme-office2021-blue.qss");
|
||||
break;
|
||||
case SARibbonTheme::RibbonThemeDark:
|
||||
file.setFileName(":/theme/resource/theme-dark.qss");
|
||||
break;
|
||||
case SARibbonTheme::RibbonThemeDark2:
|
||||
file.setFileName(":/theme/resource/theme-dark2.qss");
|
||||
break;
|
||||
default:
|
||||
file.setFileName(":/theme/resource/theme-office2013.qss");
|
||||
break;
|
||||
}
|
||||
if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) {
|
||||
return;
|
||||
}
|
||||
// 有反馈用qstring接住文件内容,再设置进去才能生效(qt5.7版本)
|
||||
QString qss = QString::fromUtf8(file.readAll());
|
||||
w->setStyleSheet(qss);
|
||||
}
|
||||
|
||||
//----------------------------------------------------
|
||||
// SARibbonMainWindowEventFilter
|
||||
//----------------------------------------------------
|
||||
SARibbonMainWindowEventFilter::SARibbonMainWindowEventFilter(QObject* par) : QObject(par)
|
||||
{
|
||||
}
|
||||
|
||||
SARibbonMainWindowEventFilter::~SARibbonMainWindowEventFilter()
|
||||
{
|
||||
}
|
||||
|
||||
bool SARibbonMainWindowEventFilter::eventFilter(QObject* obj, QEvent* e)
|
||||
{
|
||||
if (e) {
|
||||
if (e->type() == QEvent::Resize) {
|
||||
if (SARibbonMainWindow* m = qobject_cast< SARibbonMainWindow* >(obj)) {
|
||||
if (SARibbonBar* ribbon = m->ribbonBar()) {
|
||||
ribbon->setFixedWidth(m->size().width());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return QObject::eventFilter(obj, e);
|
||||
}
|
||||
@@ -0,0 +1,114 @@
|
||||
#ifndef SARIBBONMAINWINDOW_H
|
||||
#define SARIBBONMAINWINDOW_H
|
||||
#include "SARibbonGlobal.h"
|
||||
#include <QMainWindow>
|
||||
|
||||
#if !SARIBBON_USE_3RDPARTY_FRAMELESSHELPER
|
||||
class SAFramelessHelper;
|
||||
#endif
|
||||
class QAction;
|
||||
class SARibbonBar;
|
||||
class SARibbonSystemButtonBar;
|
||||
class QScreen;
|
||||
/**
|
||||
* @brief 如果要使用SARibbonBar,必须使用此类代替QMainWindow
|
||||
*
|
||||
* 由于ribbon的风格和传统的Toolbar风格差异较大,
|
||||
* SARibbonBar使用需要把原有的QMainWindow替换为SARibbonMainWindow,
|
||||
* SARibbonMainWindow是个无边框窗体,继承自QMainWindow(目前使用第三方的无边框方案https://github.com/wangwenx190/framelesshelper),
|
||||
* 其构造函数的参数useRibbon用于指定是否使用ribbon风格,默认为true
|
||||
*
|
||||
* @code
|
||||
* SARibbonMainWindow(QWidget* parent = nullptr,bool useRibbon = true);
|
||||
* @endcode
|
||||
*
|
||||
* 如果想换回非ribbon风格,只需要把useRibbon设置为false即可,
|
||||
* 成员函数isUseRibbon用于判断当前是否为ribbon模式,这个函数在兼容传统Toolbar风格和ribbon风格时非常有用
|
||||
*
|
||||
* 但这个不支持动态切换,因此,实际工程中,你若要进行切换,需要写配置文件,程序在构造时传入模式,
|
||||
* 并且,你的程序要做好判断,因为非Ribbon模式下,所有Ribbon相关的接口都会返回空指针
|
||||
*
|
||||
* @code
|
||||
* bool isUseRibbon() const;
|
||||
* @endcode
|
||||
*
|
||||
* @ref SARibbonMainWindow 提供了几种常用的ribbon样式
|
||||
* 通过@ref setRibbonTheme 可改变ribbon的样式,用户也可通过qss自己定义自己的样式
|
||||
*
|
||||
* 如果你自己继承了SARibbonBar,你可以通过@ref setRibbonBar 设置自己的ribbonbar进去
|
||||
*
|
||||
* 另外有个一个更加高效的方法,来实现自定义的Ribbon,就是继承一个@ref SARibbonElementFactory
|
||||
*
|
||||
* @code
|
||||
* class MyRibbonFactory:public SARibbonElementFactory{
|
||||
* ...
|
||||
* virtual SARibbonBar* createRibbonBar(QWidget* parent){
|
||||
* return new MyRibbonBar(parent);
|
||||
* }
|
||||
* };
|
||||
* @endcode
|
||||
*
|
||||
* SARibbonMainWindow生成之前(一般在main函数),设置元件工厂:
|
||||
*
|
||||
* @code
|
||||
* SARibbonElementManager::instance()->setupFactory(new MyRibbonFactory());
|
||||
* @endcode
|
||||
*
|
||||
* 此时,Ribbon的元素会通过MyRibbonFactory的接口来生成
|
||||
*/
|
||||
class SA_RIBBON_EXPORT SARibbonMainWindow : public QMainWindow
|
||||
{
|
||||
Q_OBJECT
|
||||
SA_RIBBON_DECLARE_PRIVATE(SARibbonMainWindow)
|
||||
friend class SARibbonBar;
|
||||
Q_PROPERTY(SARibbonTheme ribbonTheme READ ribbonTheme WRITE setRibbonTheme)
|
||||
|
||||
public:
|
||||
explicit SARibbonMainWindow(QWidget* parent = nullptr, bool useRibbon = true, const Qt::WindowFlags flags = {});
|
||||
~SARibbonMainWindow() override;
|
||||
// 返回SARibbonBar
|
||||
SARibbonBar* ribbonBar() const;
|
||||
// 设置ribbonbar
|
||||
void setRibbonBar(SARibbonBar* ribbon);
|
||||
#if !SARIBBON_USE_3RDPARTY_FRAMELESSHELPER
|
||||
// 返回SAFramelessHelper
|
||||
SAFramelessHelper* framelessHelper();
|
||||
#else
|
||||
// 如果ribbon中有自定义的窗口在标题栏等非点击区域加入后,想能点击,需要调用此接口告知可点击
|
||||
void setFramelessHitTestVisible(QWidget* w, bool visible = true);
|
||||
#endif
|
||||
// 此函数仅用于控制最小最大化和关闭按钮的显示
|
||||
void updateWindowFlag(Qt::WindowFlags flags);
|
||||
|
||||
// 注意主题在构造函数设置主题会不完全生效,使用QTimer投放到队列最后执行即可
|
||||
// QTimer::singleShot(0, this, [ this ]() { this->setRibbonTheme(SARibbonMainWindow::RibbonThemeDark); });
|
||||
void setRibbonTheme(SARibbonTheme theme);
|
||||
SARibbonTheme ribbonTheme() const;
|
||||
// 判断当前是否使用ribbon模式
|
||||
bool isUseRibbon() const;
|
||||
// 把ribbonbar的事件传递到frameless
|
||||
virtual bool eventFilter(QObject* obj, QEvent* e) Q_DECL_OVERRIDE;
|
||||
// 获取最大化,最小化,关闭按钮所在的bar。可以通过此函数在最大最小化按钮旁边设置内容
|
||||
SARibbonSystemButtonBar* windowButtonBar() const;
|
||||
|
||||
protected:
|
||||
// 创建ribbonbar的工厂函数
|
||||
SARibbonBar* createRibbonBar();
|
||||
private Q_SLOTS:
|
||||
void onPrimaryScreenChanged(QScreen* screen);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @brief 针对SARibbonMainWindow的事件处理器,主要处理systembar的位置调整
|
||||
*/
|
||||
class SA_RIBBON_EXPORT SARibbonMainWindowEventFilter : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit SARibbonMainWindowEventFilter(QObject* par);
|
||||
~SARibbonMainWindowEventFilter();
|
||||
virtual bool eventFilter(QObject* obj, QEvent* e) override;
|
||||
};
|
||||
|
||||
#endif // SARIBBONMAINWINDOW_H
|
||||
@@ -0,0 +1,50 @@
|
||||
#include "SARibbonMenu.h"
|
||||
#include <QWidgetAction>
|
||||
|
||||
SARibbonMenu::SARibbonMenu(QWidget *parent) : QMenu(parent)
|
||||
{
|
||||
setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
|
||||
}
|
||||
|
||||
|
||||
SARibbonMenu::SARibbonMenu(const QString& title, QWidget *parent) : QMenu(title, parent)
|
||||
{
|
||||
setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
|
||||
}
|
||||
|
||||
SARibbonMenu::~SARibbonMenu()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
QAction *SARibbonMenu::addRibbonMenu(SARibbonMenu *menu)
|
||||
{
|
||||
return (QMenu::addMenu(menu));
|
||||
}
|
||||
|
||||
|
||||
SARibbonMenu *SARibbonMenu::addRibbonMenu(const QString& title)
|
||||
{
|
||||
SARibbonMenu *menu = new SARibbonMenu(title, this);
|
||||
|
||||
return (menu);
|
||||
}
|
||||
|
||||
|
||||
SARibbonMenu *SARibbonMenu::addRibbonMenu(const QIcon& icon, const QString& title)
|
||||
{
|
||||
SARibbonMenu *menu = new SARibbonMenu(title, this);
|
||||
|
||||
menu->setIcon(icon);
|
||||
return (menu);
|
||||
}
|
||||
|
||||
|
||||
QAction *SARibbonMenu::addWidget(QWidget *w)
|
||||
{
|
||||
QWidgetAction *action = new QWidgetAction(this);
|
||||
|
||||
action->setDefaultWidget(w);
|
||||
addAction(action);
|
||||
return (action);
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
#ifndef SARIBBONMENU_H
|
||||
#define SARIBBONMENU_H
|
||||
#include "SARibbonGlobal.h"
|
||||
#include <QMenu>
|
||||
|
||||
///
|
||||
/// \brief 用在ribbon的menu
|
||||
/// 可以通过StyleSheet设置样式而不影响QMenu
|
||||
///
|
||||
class SA_RIBBON_EXPORT SARibbonMenu : public QMenu
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit SARibbonMenu(QWidget* parent = nullptr);
|
||||
explicit SARibbonMenu(const QString& title, QWidget* parent = nullptr);
|
||||
~SARibbonMenu();
|
||||
QAction* addRibbonMenu(SARibbonMenu* menu);
|
||||
SARibbonMenu* addRibbonMenu(const QString& title);
|
||||
SARibbonMenu* addRibbonMenu(const QIcon& icon, const QString& title);
|
||||
QAction* addWidget(QWidget* w);
|
||||
};
|
||||
|
||||
#endif // SARIBBONMENU_H
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,237 @@
|
||||
#ifndef SARIBBONPANNEL_H
|
||||
#define SARIBBONPANNEL_H
|
||||
#include "SARibbonGlobal.h"
|
||||
#include "SARibbonPannelItem.h"
|
||||
#include "SARibbonPannelLayout.h"
|
||||
#include "SARibbonToolButton.h"
|
||||
#include <QLayout>
|
||||
#include <QWidget>
|
||||
#include <QLabel>
|
||||
class SARibbonMenu;
|
||||
class SARibbonGallery;
|
||||
class QGridLayout;
|
||||
class SARibbonPannelOptionButton;
|
||||
class SARibbonPannelLayout;
|
||||
class SARibbonCategory;
|
||||
class SARibbonBar;
|
||||
|
||||
/**
|
||||
* @brief SARibbonPannel的标题label,此类用于qss
|
||||
*/
|
||||
class SA_RIBBON_EXPORT SARibbonPannelLabel : public QLabel
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
SARibbonPannelLabel(QWidget* parent = nullptr);
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief pannel页窗口,pannel是ribbon的面板用于承放控件
|
||||
*
|
||||
* ribbon的pannel分为两行模式和三行模式,以office为代表的ribbon为3行模式,以WPS为代表的“紧凑派”就是2行模式,
|
||||
* SARibbon可通过SARibbonBar的@ref SARibbonBar::RibbonStyle 来指定模式(通过函数@ref SARibbonBar::setRibbonStyle )
|
||||
*
|
||||
* 在pannel中,可以通过@ref setExpanding 函数指定pannel水平扩展,如果pannel里面没有能水平扩展的控件,将会留白,因此,
|
||||
* 建议在pannel里面有水平扩展的控件如(@ref SARibbonGallery )才指定这个函数
|
||||
*
|
||||
* pannel的布局通过@ref SARibbonPannelLayout 来实现,如果有其他布局,可以通过继承@ref
|
||||
* SARibbonElementCreateDelegate::createRibbonPannel 函数返回带有自己布局的pannel,但你必须继承对应的虚函数
|
||||
*/
|
||||
class SA_RIBBON_EXPORT SARibbonPannel : public QFrame
|
||||
{
|
||||
Q_OBJECT
|
||||
SA_RIBBON_DECLARE_PRIVATE(SARibbonPannel)
|
||||
friend class SARibbonCategory;
|
||||
friend class SARibbonCategoryPrivate;
|
||||
friend class SARibbonCustomizeWidgetPrivate;
|
||||
friend class SARibbonPannelLayout;
|
||||
Q_PROPERTY(bool isCanCustomize READ isCanCustomize WRITE setCanCustomize)
|
||||
Q_PROPERTY(bool isExpanding READ isExpanding WRITE setExpanding)
|
||||
Q_PROPERTY(QString pannelName READ pannelName WRITE setPannelName)
|
||||
public:
|
||||
enum PannelLayoutMode
|
||||
{
|
||||
ThreeRowMode, ///< 三行布局模式,office就是三行布局模式,pannel能布置3行小toolbutton,默认模式
|
||||
TwoRowMode ///< 两行布局模式,wps的后续布局模式就是两行布局模式,pannel能布置2行小toolbutton
|
||||
};
|
||||
Q_ENUM(PannelLayoutMode)
|
||||
public:
|
||||
using FpRibbonToolButtonIterate = std::function< bool(SARibbonToolButton*) >;
|
||||
|
||||
public:
|
||||
explicit SARibbonPannel(QWidget* parent = nullptr);
|
||||
explicit SARibbonPannel(const QString& name, QWidget* parent = nullptr);
|
||||
~SARibbonPannel() Q_DECL_OVERRIDE;
|
||||
using QWidget::addAction;
|
||||
|
||||
// 把action加入到pannel
|
||||
void addAction(QAction* action, SARibbonPannelItem::RowProportion rp);
|
||||
// 生成并添加一个action
|
||||
void addAction(QAction* act,
|
||||
QToolButton::ToolButtonPopupMode popMode,
|
||||
SARibbonPannelItem::RowProportion rp = SARibbonPannelItem::Large);
|
||||
// 把action加入到pannel,并以大图标显示
|
||||
void addLargeAction(QAction* action);
|
||||
// 把action加入到pannel,在三行模式下会以中图标显示
|
||||
void addMediumAction(QAction* action);
|
||||
// 把action加入到pannel,并以小图标显示
|
||||
void addSmallAction(QAction* action);
|
||||
|
||||
// 把action加入到pannel,并以小图标显示
|
||||
void addSmallAction(QAction* action, QToolButton::ToolButtonPopupMode popMode);
|
||||
// 把action加入到pannel,并以大图标显示
|
||||
void addLargeAction(QAction* action, QToolButton::ToolButtonPopupMode popMode);
|
||||
// 把action加入到pannel,在三行模式下会以中图标显示
|
||||
void addMediumAction(QAction* action, QToolButton::ToolButtonPopupMode popMode);
|
||||
|
||||
QAction* addAction(const QString& text,
|
||||
const QIcon& icon,
|
||||
QToolButton::ToolButtonPopupMode popMode,
|
||||
SARibbonPannelItem::RowProportion rp = SARibbonPannelItem::Large);
|
||||
|
||||
// 添加menu
|
||||
void addMenu(QMenu* menu,
|
||||
SARibbonPannelItem::RowProportion rp,
|
||||
QToolButton::ToolButtonPopupMode popMode = QToolButton::InstantPopup);
|
||||
|
||||
// 添加普通大菜单
|
||||
void addLargeMenu(QMenu* menu, QToolButton::ToolButtonPopupMode popMode = QToolButton::InstantPopup);
|
||||
|
||||
// 添加普通小按钮菜单
|
||||
void addSmallMenu(QMenu* menu, QToolButton::ToolButtonPopupMode popMode = QToolButton::InstantPopup);
|
||||
|
||||
// 添加窗口
|
||||
QAction* addWidget(QWidget* w, SARibbonPannelItem::RowProportion rp);
|
||||
|
||||
// 添加窗口,占用ribbon的一行
|
||||
QAction* addSmallWidget(QWidget* w);
|
||||
|
||||
// 添加窗口,占用ribbon的一行
|
||||
QAction* addMediumWidget(QWidget* w);
|
||||
|
||||
// 添加窗口,占用所有行
|
||||
QAction* addLargeWidget(QWidget* w);
|
||||
|
||||
// 添加一个Gallery
|
||||
SARibbonGallery* addGallery(bool expanding = true);
|
||||
|
||||
// 添加分割线
|
||||
QAction* addSeparator();
|
||||
|
||||
// 从pannel中把action对应的button提取出来,如果action没有对应的button,就返回nullptr
|
||||
SARibbonToolButton* actionToRibbonToolButton(QAction* action);
|
||||
|
||||
// 设置操作action,如果要去除,传入nullptr指针即可,SARibbonPannel不会对QAction的所有权进行管理
|
||||
// OptionAction也会触发actionTriggered信号
|
||||
void setOptionAction(QAction* action);
|
||||
|
||||
// 判断是否存在OptionAction
|
||||
bool isHaveOptionAction() const;
|
||||
|
||||
// 获取所有的buttons
|
||||
QList< SARibbonToolButton* > ribbonToolButtons() const;
|
||||
|
||||
// 获取PannelLayoutMode
|
||||
PannelLayoutMode pannelLayoutMode() const;
|
||||
void setPannelLayoutMode(PannelLayoutMode mode);
|
||||
// 更新按钮的尺寸,这个函数在pannel的布局状态变换后需要调用刷新
|
||||
void resetToolButtonSize();
|
||||
|
||||
// 判断是否为2行模式
|
||||
bool isTwoRow() const
|
||||
{
|
||||
return (TwoRowMode == pannelLayoutMode());
|
||||
}
|
||||
|
||||
// 把pannel设置为扩展模式,此时会撑大水平区域
|
||||
void setExpanding(bool isExpanding = true);
|
||||
|
||||
// 是否是扩展模式
|
||||
bool isExpanding() const;
|
||||
|
||||
// 标题栏高度
|
||||
void setTitleHeight(int h);
|
||||
int titleHeight() const;
|
||||
|
||||
// 是否显示标题,显示标题后,标题的高度需要设置,默认高度为15
|
||||
bool isEnableShowTitle() const;
|
||||
void setEnableShowTitle(bool on);
|
||||
|
||||
// action对应的布局index,此操作一般用于移动moveAction,其他意义不大
|
||||
int actionIndex(QAction* act) const;
|
||||
|
||||
// 移动action
|
||||
void moveAction(int from, int to);
|
||||
|
||||
// 判断是否可以自定义
|
||||
bool isCanCustomize() const;
|
||||
void setCanCustomize(bool b);
|
||||
|
||||
// 标题
|
||||
QString pannelName() const;
|
||||
void setPannelName(const QString& title);
|
||||
|
||||
// 大图标的高度
|
||||
int largeButtonHeight() const;
|
||||
// 获取布局对应的item,此函数目前仅仅在自定义过程中用到
|
||||
const QList< SARibbonPannelItem* >& ribbonPannelItem() const;
|
||||
// 获取pannel layout
|
||||
SARibbonPannelLayout* pannelLayout() const;
|
||||
// 更新布局
|
||||
void updateItemGeometry();
|
||||
// 获取category指针,如果没有parent,或者不在category管理,返回nullptr
|
||||
SARibbonCategory* category() const;
|
||||
// 获取ribbonBar指针,如果没有返回nullptr
|
||||
SARibbonBar* ribbonBar() const;
|
||||
// 设置按钮之间的间隔
|
||||
void setSpacing(int n);
|
||||
int spacing() const;
|
||||
//
|
||||
virtual QSize sizeHint() const Q_DECL_OVERRIDE;
|
||||
virtual QSize minimumSizeHint() const Q_DECL_OVERRIDE;
|
||||
// 设置按钮的icon尺寸,large action不受此尺寸影响
|
||||
void setToolButtonIconSize(const QSize& s);
|
||||
QSize toolButtonIconSize() const;
|
||||
// 此函数会遍历SARibbonPannel下的所有RibbonToolButton,执行函数指针(bool(SARibbonRibbonToolButton*)),函数指针返回false则停止迭代
|
||||
bool iterate(FpRibbonToolButtonIterate fp);
|
||||
|
||||
// 获取最近添加的按钮
|
||||
SARibbonToolButton* lastAddActionButton();
|
||||
|
||||
Q_SIGNALS:
|
||||
|
||||
/**
|
||||
* @brief 等同于QToolBar::actionTriggered
|
||||
* @param action
|
||||
*/
|
||||
void actionTriggered(QAction* action);
|
||||
|
||||
/**
|
||||
* @brief pannel的标题发生了改变
|
||||
* @param n
|
||||
*/
|
||||
void pannelNameChanged(const QString& n);
|
||||
|
||||
public:
|
||||
// pannel高度推荐
|
||||
static int pannelHeightHint(const QFontMetrics& fm, PannelLayoutMode layMode, int pannelTitleHeight);
|
||||
// 把action的行属性设置进action中,action自身携带了行属性
|
||||
static void setActionRowProportionProperty(QAction* action, SARibbonPannelItem::RowProportion rp);
|
||||
// 获取action的行属性
|
||||
static SARibbonPannelItem::RowProportion getActionRowProportionProperty(QAction* action);
|
||||
// 把action的PopupMode属性设置进action中,action自身携带了PopupMode属性
|
||||
static void setActionToolButtonPopupModeProperty(QAction* action, QToolButton::ToolButtonPopupMode popMode);
|
||||
// 获取action的PopupMode属性
|
||||
static QToolButton::ToolButtonPopupMode getActionToolButtonPopupModeProperty(QAction* action);
|
||||
// 把action的ToolButtonStyle属性设置进action中,action自身携带了ToolButtonStyle属性
|
||||
static void setActionToolButtonStyleProperty(QAction* action, Qt::ToolButtonStyle buttonStyle);
|
||||
// 获取action的ToolButtonStyle属性
|
||||
static Qt::ToolButtonStyle getActionToolButtonStyleProperty(QAction* action);
|
||||
|
||||
protected:
|
||||
virtual bool event(QEvent* e) Q_DECL_OVERRIDE;
|
||||
virtual void actionEvent(QActionEvent* e) Q_DECL_OVERRIDE;
|
||||
virtual void changeEvent(QEvent* e) Q_DECL_OVERRIDE;
|
||||
};
|
||||
|
||||
#endif // SARIBBONPANNEL_H
|
||||
@@ -0,0 +1,15 @@
|
||||
#include "SARibbonPannelItem.h"
|
||||
|
||||
SARibbonPannelItem::SARibbonPannelItem(QWidget* widget)
|
||||
: QWidgetItem(widget), rowIndex(-1), columnIndex(-1), action(nullptr), customWidget(false), rowProportion(Large)
|
||||
{
|
||||
}
|
||||
|
||||
SARibbonPannelItem::~SARibbonPannelItem()
|
||||
{
|
||||
}
|
||||
|
||||
bool SARibbonPannelItem::isEmpty() const
|
||||
{
|
||||
return (action == nullptr || !action->isVisible());
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
#ifndef SARIBBONPANNELITEM_H
|
||||
#define SARIBBONPANNELITEM_H
|
||||
#include "SARibbonGlobal.h"
|
||||
#include <QWidgetItem>
|
||||
#include <QAction>
|
||||
class SARibbonToolButton;
|
||||
/**
|
||||
* @brief 是对pannel所有子窗口的抽象,参考qt的toolbar
|
||||
*
|
||||
* 参考qt的toolbar,pannel所有子窗口内容都通过QAction进行抽象,包括gallery这些窗口,也是通过QAction进行抽象
|
||||
* QAction最终会转换为SARibbonPannelItem,每个SARibbonPannelItem都含有一个widget,SARibbonPannel的布局
|
||||
* 就基于SARibbonPannelItem
|
||||
*
|
||||
* 无窗口的action会在内部生成一个SARibbonToolButton,
|
||||
*/
|
||||
class SA_RIBBON_EXPORT SARibbonPannelItem : public QWidgetItem
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* @brief 定义了行的占比,ribbon中有large,media和small三种占比
|
||||
*/
|
||||
enum RowProportion
|
||||
{
|
||||
None, ///< 为定义占比,这时候将会依据expandingDirections来判断,如果能有Qt::Vertical,就等同于Large,否则就是Small
|
||||
Large, ///< 大占比,一个widget的高度会充满整个pannel
|
||||
Medium, ///< 中占比,在@ref SARibbonPannel::pannelLayoutMode 为 @ref SARibbonPannel::ThreeRowMode 时才会起作用,且要同一列里两个都是Medium时,会在三行中占据两行
|
||||
Small ///< 小占比,占SARibbonPannel的一行,Medium在不满足条件时也会变为Small,但不会变为Large
|
||||
};
|
||||
explicit SARibbonPannelItem(QWidget* widget);
|
||||
~SARibbonPannelItem();
|
||||
|
||||
bool isEmpty() const Q_DECL_OVERRIDE;
|
||||
|
||||
short rowIndex; ///< 记录当前item属于第几行,hide模式下为-1
|
||||
int columnIndex; ///< 记录当前item属于第几列,hide模式下为-1
|
||||
QRect itemWillSetGeometry; ///< 在调用SARibbonPannelLayout::updateGeomArray会更新这个此处,实际设置的时候会QWidgetItem::setGeometry设置Geometry
|
||||
QAction* action; /// < 记录action,参考QToolBarLayoutItem
|
||||
bool customWidget; ///< 对于没有窗口的action,实际也会有一个SARibbonToolButton,在销毁时要delete掉
|
||||
SARibbonPannelItem::RowProportion rowProportion; ///< 行的占比,ribbon中有large,media和small三种占比,见@ref RowProportion
|
||||
};
|
||||
#ifndef SA_ActionPropertyName_RowProportion
|
||||
#define SA_ActionPropertyName_RowProportion "_sa_RowProportion"
|
||||
#endif
|
||||
#ifndef SA_ActionPropertyName_ToolButtonPopupMode
|
||||
#define SA_ActionPropertyName_ToolButtonPopupMode "_sa_ToolButtonPopupMode"
|
||||
#endif
|
||||
#ifndef SA_ActionPropertyName_ToolButtonStyle
|
||||
#define SA_ActionPropertyName_ToolButtonStyle "_sa_ToolButtonStyle"
|
||||
#endif
|
||||
#endif // SARIBBONPANNELITEM_H
|
||||
@@ -0,0 +1,952 @@
|
||||
#include "SARibbonPannelLayout.h"
|
||||
#include "SARibbonPannelOptionButton.h"
|
||||
#include "SARibbonSeparatorWidget.h"
|
||||
#include "SARibbonElementManager.h"
|
||||
#include <QWidgetAction>
|
||||
#include <QQueue>
|
||||
#include "SARibbonPannel.h"
|
||||
#include "SARibbonPannelItem.h"
|
||||
#define SARibbonPannelLayout_DEBUG_PRINT 1
|
||||
#define HELP_DRAW_RECT(p, rect) \
|
||||
do { \
|
||||
p.save(); \
|
||||
QPen _pen(Qt::DashLine); \
|
||||
_pen.setColor(Qt::blue); \
|
||||
p.setPen(_pen); \
|
||||
p.setBrush(QBrush()); \
|
||||
p.drawRect(rect); \
|
||||
p.restore(); \
|
||||
} while (0)
|
||||
|
||||
SARibbonPannelLayout::SARibbonPannelLayout(QWidget* p) : QLayout(p), mColumnCount(0), mExpandFlag(false), mDirty(true)
|
||||
{
|
||||
setSpacing(1);
|
||||
SARibbonPannel* tb = qobject_cast< SARibbonPannel* >(p);
|
||||
|
||||
if (!tb) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
SARibbonPannelLayout::~SARibbonPannelLayout()
|
||||
{
|
||||
// 参考QToolBarLayout
|
||||
while (!mItems.isEmpty()) {
|
||||
SARibbonPannelItem* item = mItems.takeFirst();
|
||||
if (QWidgetAction* widgetAction = qobject_cast< QWidgetAction* >(item->action)) {
|
||||
if (item->customWidget) {
|
||||
widgetAction->releaseWidget(item->widget());
|
||||
}
|
||||
}
|
||||
delete item;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 通过action查找索引,用于actionEvent添加action用
|
||||
* @param action
|
||||
* @return 没有查到返回-1
|
||||
*/
|
||||
int SARibbonPannelLayout::indexByAction(QAction* action) const
|
||||
{
|
||||
for (int i = 0; i < mItems.count(); ++i) {
|
||||
if (mItems.at(i)->action == action) {
|
||||
return (i);
|
||||
}
|
||||
}
|
||||
return (-1);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 获取ribbonpannel
|
||||
* @return
|
||||
*/
|
||||
SARibbonPannel* SARibbonPannelLayout::ribbonPannel() const
|
||||
{
|
||||
return qobject_cast< SARibbonPannel* >(parentWidget());
|
||||
}
|
||||
|
||||
void SARibbonPannelLayout::addItem(QLayoutItem* item)
|
||||
{
|
||||
Q_UNUSED(item);
|
||||
qWarning("SARibbonPannelLayout::addItem(): please use addAction() instead");
|
||||
return;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief SARibbonPannel主要通过此函数来添加action
|
||||
* @param act
|
||||
* @param rp 布局策略
|
||||
*/
|
||||
void SARibbonPannelLayout::insertAction(int index, QAction* act, SARibbonPannelItem::RowProportion rp)
|
||||
{
|
||||
index = qMax(0, index);
|
||||
index = qMin(mItems.count(), index);
|
||||
SARibbonPannelItem* item = createItem(act, rp);
|
||||
|
||||
if (item) {
|
||||
mItems.insert(index, item);
|
||||
// 标记需要重新计算尺寸
|
||||
invalidate();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 添加操作action,如果要去除,传入nullptr指针即可,SARibbonPannel不会对QAction的所有权进行管理
|
||||
* @param action
|
||||
* @note 要去除OptionAction直接传入nullptr即可
|
||||
* @note SARibbonPannel不对QAction的destroy进行关联,如果外部对action进行delete,需要先传入nullptr给addOptionAction
|
||||
*/
|
||||
void SARibbonPannelLayout::setOptionAction(QAction* action)
|
||||
{
|
||||
SARibbonPannel* p = ribbonPannel();
|
||||
if (!p) {
|
||||
return;
|
||||
}
|
||||
if (action) {
|
||||
// 创建option action
|
||||
if (nullptr == mOptionActionBtn) {
|
||||
mOptionActionBtn = RibbonSubElementFactory->createRibbonPannelOptionButton(p);
|
||||
QObject::connect(mOptionActionBtn, &SARibbonToolButton::triggered, p, &SARibbonPannel::actionTriggered);
|
||||
// 确保m_optionActionBtn在label之上
|
||||
if (mTitleLabel) {
|
||||
mTitleLabel->stackUnder(mOptionActionBtn);
|
||||
}
|
||||
}
|
||||
mOptionActionBtn->setDefaultAction(action);
|
||||
if (action->icon().isNull()) {
|
||||
mOptionActionBtn->setIcon(QIcon(":/image/resource/ribbonPannelOptionButton.png"));
|
||||
}
|
||||
// 标记需要重新计算尺寸
|
||||
invalidate();
|
||||
} else {
|
||||
// 取消option action
|
||||
if (mOptionActionBtn) {
|
||||
mOptionActionBtn->hide();
|
||||
mOptionActionBtn->deleteLater();
|
||||
mOptionActionBtn = nullptr;
|
||||
// 标记需要重新计算尺寸
|
||||
invalidate();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 判断是否存在OptionAction
|
||||
* @return 存在返回true
|
||||
*/
|
||||
bool SARibbonPannelLayout::isHaveOptionAction() const
|
||||
{
|
||||
return (mOptionActionBtn != nullptr);
|
||||
}
|
||||
|
||||
QLayoutItem* SARibbonPannelLayout::itemAt(int index) const
|
||||
{
|
||||
if ((index < 0) || (index >= mItems.count())) {
|
||||
return (nullptr);
|
||||
}
|
||||
return (mItems.at(index));
|
||||
}
|
||||
|
||||
QLayoutItem* SARibbonPannelLayout::takeAt(int index)
|
||||
{
|
||||
if ((index < 0) || (index >= mItems.count())) {
|
||||
return (nullptr);
|
||||
}
|
||||
SARibbonPannelItem* item = mItems.takeAt(index);
|
||||
|
||||
QWidgetAction* widgetAction = qobject_cast< QWidgetAction* >(item->action);
|
||||
|
||||
if ((widgetAction != 0) && item->customWidget) {
|
||||
widgetAction->releaseWidget(item->widget());
|
||||
} else {
|
||||
// destroy the QToolButton/QToolBarSeparator
|
||||
item->widget()->hide();
|
||||
item->widget()->deleteLater();
|
||||
}
|
||||
|
||||
invalidate();
|
||||
return (item);
|
||||
}
|
||||
|
||||
int SARibbonPannelLayout::count() const
|
||||
{
|
||||
return (mItems.count());
|
||||
}
|
||||
|
||||
bool SARibbonPannelLayout::isEmpty() const
|
||||
{
|
||||
|
||||
return (mItems.isEmpty());
|
||||
}
|
||||
|
||||
void SARibbonPannelLayout::invalidate()
|
||||
{
|
||||
mDirty = true;
|
||||
QLayout::invalidate();
|
||||
}
|
||||
|
||||
Qt::Orientations SARibbonPannelLayout::expandingDirections() const
|
||||
{
|
||||
return (Qt::Horizontal);
|
||||
}
|
||||
|
||||
QSize SARibbonPannelLayout::minimumSize() const
|
||||
{
|
||||
return (mSizeHint);
|
||||
}
|
||||
|
||||
QSize SARibbonPannelLayout::sizeHint() const
|
||||
{
|
||||
#if SARibbonPannelLayout_DEBUG_PRINT && SA_DEBUG_PRINT_SIZE_HINT
|
||||
if (SARibbonPannel* pannel = ribbonPannel()) {
|
||||
qDebug() << "| |-SARibbonPannelLayout sizeHint,sizeHint = " << m_sizeHint;
|
||||
}
|
||||
#endif
|
||||
return (mSizeHint);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 通过action获取SARibbonPannelItem
|
||||
* @param action
|
||||
* @return 如果没有返回nullptr
|
||||
*/
|
||||
SARibbonPannelItem* SARibbonPannelLayout::pannelItem(QAction* action) const
|
||||
{
|
||||
int index = indexByAction(action);
|
||||
|
||||
if (index >= 0) {
|
||||
return (mItems[ index ]);
|
||||
}
|
||||
return (nullptr);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 获取最后一个添加的item
|
||||
* @return 如果没有返回nullptr
|
||||
*/
|
||||
SARibbonPannelItem* SARibbonPannelLayout::lastItem() const
|
||||
{
|
||||
if (mItems.isEmpty()) {
|
||||
return (nullptr);
|
||||
}
|
||||
return (mItems.last());
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 获取最后生成的窗口
|
||||
* @return 如果无窗口或者item为空,返回nullptr
|
||||
*/
|
||||
QWidget* SARibbonPannelLayout::lastWidget() const
|
||||
{
|
||||
SARibbonPannelItem* item = lastItem();
|
||||
|
||||
if (item) {
|
||||
return (item->widget());
|
||||
}
|
||||
return (nullptr);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 移动两个item
|
||||
* @param from
|
||||
* @param to
|
||||
* @note 移动完后所有都失效,需要重新布局
|
||||
*/
|
||||
void SARibbonPannelLayout::move(int from, int to)
|
||||
{
|
||||
if (from == to) {
|
||||
return;
|
||||
}
|
||||
if (to < 0) {
|
||||
to = 0;
|
||||
}
|
||||
if (to >= count()) {
|
||||
to = count() - 1;
|
||||
}
|
||||
mItems.move(from, to);
|
||||
invalidate();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 判断是否需要重新布局
|
||||
* @return
|
||||
*/
|
||||
bool SARibbonPannelLayout::isDirty() const
|
||||
{
|
||||
return (mDirty);
|
||||
}
|
||||
|
||||
void SARibbonPannelLayout::updateGeomArray()
|
||||
{
|
||||
updateGeomArray(geometry());
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 布局所有action
|
||||
*/
|
||||
void SARibbonPannelLayout::doLayout()
|
||||
{
|
||||
#if SARibbonPannelLayout_DEBUG_PRINT && SA_DEBUG_PRINT_SIZE_HINT
|
||||
if (SARibbonPannel* pannel = ribbonPannel()) {
|
||||
qDebug() << "| |-SARibbonPannelLayout layoutActions,pannel name = " << pannel->pannelName();
|
||||
}
|
||||
#endif
|
||||
if (isDirty()) {
|
||||
updateGeomArray();
|
||||
}
|
||||
QList< QWidget* > showWidgets, hideWidgets;
|
||||
SARibbonPannel* pannel = ribbonPannel();
|
||||
for (SARibbonPannelItem* item : qAsConst(mItems)) {
|
||||
if (item->isEmpty()) {
|
||||
hideWidgets << item->widget();
|
||||
} else {
|
||||
// 在category发现item->setGeometry有点奇怪的现象,这里统一使用item->widget->setgeo
|
||||
// item->setGeometry(item->itemWillSetGeometry);
|
||||
if (item->widget()) {
|
||||
item->widget()->setGeometry(item->itemWillSetGeometry);
|
||||
}
|
||||
showWidgets << item->widget();
|
||||
}
|
||||
}
|
||||
|
||||
// 不在上面那里进行show和hide因为这会触发SARibbonPannelLayout的重绘,导致循环绘制,非常影响效率
|
||||
for (QWidget* w : qAsConst(showWidgets)) {
|
||||
if (!w->isVisible())
|
||||
w->show();
|
||||
}
|
||||
for (QWidget* w : qAsConst(hideWidgets)) {
|
||||
if (w->isVisible())
|
||||
w->hide();
|
||||
}
|
||||
// 布局label
|
||||
if (mTitleLabel) {
|
||||
if (isEnableShowPannelTitle()) {
|
||||
mTitleLabel->setGeometry(mTitleLabelGeometry);
|
||||
if (!mTitleLabel->isVisibleTo(pannel)) {
|
||||
mTitleLabel->show();
|
||||
}
|
||||
} else {
|
||||
if (mTitleLabel->isVisibleTo(pannel)) {
|
||||
mTitleLabel->hide();
|
||||
}
|
||||
}
|
||||
}
|
||||
// 布局m_optionActionBtn
|
||||
if (mOptionActionBtn) {
|
||||
mOptionActionBtn->setGeometry(mOptionActionBtnGeometry);
|
||||
mOptionActionBtn->setIconSize(QSize(mOptionActionBtnGeometry.width(), mOptionActionBtnGeometry.height()));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 把action转换为item
|
||||
*
|
||||
* 此函数参考QToolBarItem *QToolBarLayout::createItem(QAction *action)
|
||||
*
|
||||
* 对于普通QAction,此函数会创建SARibbonToolButton,SARibbonToolButton的类型参考SARibbonPannelItem::RowProportion,
|
||||
* @param action
|
||||
* @param rp 行高占比情况
|
||||
* @return 转换的SARibbonPannelItem
|
||||
* @note 每个SARibbonPannelItem最终都会携带一个widget,传入的是QWidgetAction的话,会直接使用QWidgetAction带的widget,
|
||||
* 否则会内部生成一个SARibbonToolButton
|
||||
*
|
||||
*/
|
||||
SARibbonPannelItem* SARibbonPannelLayout::createItem(QAction* action, SARibbonPannelItem::RowProportion rp)
|
||||
{
|
||||
bool customWidget = false;
|
||||
QWidget* widget = nullptr;
|
||||
SARibbonPannel* pannel = qobject_cast< SARibbonPannel* >(parentWidget());
|
||||
|
||||
if (!pannel) {
|
||||
// 在没有pannel这个函数会返回nullptr
|
||||
return (nullptr);
|
||||
}
|
||||
if (QWidgetAction* widgetAction = qobject_cast< QWidgetAction* >(action)) {
|
||||
widget = widgetAction->requestWidget(pannel);
|
||||
if (widget != nullptr) {
|
||||
widget->setAttribute(Qt::WA_LayoutUsesWidgetRect);
|
||||
customWidget = true; // 标记为true,在移除的时候是不会对这个窗口进行删除,false默认会进行删除如SARibbonSeparatorWidget和SARibbonToolButton
|
||||
}
|
||||
} else if (action->isSeparator()) {
|
||||
SARibbonSeparatorWidget* sep = RibbonSubElementFactory->createRibbonSeparatorWidget(pannel);
|
||||
widget = sep;
|
||||
}
|
||||
// 不是widget,自动生成SARibbonToolbutton
|
||||
if (!widget) {
|
||||
SARibbonToolButton::RibbonButtonType buttonType = ((rp == SARibbonPannelItem::Large)
|
||||
? SARibbonToolButton::LargeButton
|
||||
: SARibbonToolButton::SmallButton);
|
||||
|
||||
SARibbonToolButton* button = RibbonSubElementFactory->createRibbonToolButton(pannel);
|
||||
button->setFocusPolicy(Qt::NoFocus);
|
||||
button->setButtonType(buttonType);
|
||||
button->setDefaultAction(action);
|
||||
button->setIconSize(mDefaultToolButtonIconSize);
|
||||
// 属性设置
|
||||
QToolButton::ToolButtonPopupMode popMode = SARibbonPannel::getActionToolButtonPopupModeProperty(action);
|
||||
button->setPopupMode(popMode);
|
||||
// 根据QAction的属性设置按钮的大小
|
||||
|
||||
QObject::connect(button, &SARibbonToolButton::triggered, pannel, &SARibbonPannel::actionTriggered);
|
||||
widget = button;
|
||||
}
|
||||
// 这时总会有widget
|
||||
widget->hide();
|
||||
SARibbonPannelItem* result = new SARibbonPannelItem(widget);
|
||||
|
||||
result->rowProportion = rp;
|
||||
result->customWidget = customWidget;
|
||||
result->action = action;
|
||||
return (result);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 更新尺寸
|
||||
*/
|
||||
void SARibbonPannelLayout::updateGeomArray(const QRect& setrect)
|
||||
{
|
||||
SARibbonPannel* pannel = qobject_cast< SARibbonPannel* >(parentWidget());
|
||||
|
||||
if (!pannel) {
|
||||
return;
|
||||
}
|
||||
|
||||
const int height = setrect.height();
|
||||
const QMargins& mag = contentsMargins();
|
||||
const int spacing = this->spacing();
|
||||
const int spacingRow = 1; // 高度间距,也就是行间距,不同行之间的距离
|
||||
int x = mag.left();
|
||||
const int yBegin = mag.top();
|
||||
int titleH = (mTitleHeight >= 0) ? mTitleHeight : 0; // 防止负数影响
|
||||
int titleSpace = (mTitleHeight >= 0) ? mTitleSpace : 0; // 对于没有标题的情况,spacing就不生效
|
||||
if (!isEnableShowPannelTitle()) {
|
||||
titleH = 0;
|
||||
titleSpace = 0;
|
||||
}
|
||||
// 获取pannel的布局模式 3行或者2行
|
||||
// rowcount 是ribbon的行,有2行和3行两种
|
||||
const short rowCount = (pannel->pannelLayoutMode() == SARibbonPannel::ThreeRowMode) ? 3 : 2;
|
||||
// largeHeight是对应large占比的高度
|
||||
const int largeHeight = height - mag.bottom() - mag.top() - titleH - titleSpace;
|
||||
const int yTitleBegin = height - mag.bottom() - titleH;
|
||||
mLargeHeight = largeHeight;
|
||||
// 计算smallHeight的高度
|
||||
const int smallHeight = (largeHeight - (rowCount - 1) * spacingRow) / rowCount;
|
||||
// Medium行的y位置
|
||||
const int yMediumRow0 = (2 == rowCount) ? yBegin : (yBegin + ((largeHeight - 2 * smallHeight) / 3));
|
||||
const int yMediumRow1 = (2 == rowCount) ? (yBegin + smallHeight + spacingRow)
|
||||
: (yBegin + ((largeHeight - 2 * smallHeight) / 3) * 2 + smallHeight);
|
||||
// Small行的y位置
|
||||
const int ySmallRow0 = yBegin;
|
||||
const int ySmallRow1 = yBegin + smallHeight + spacingRow;
|
||||
const int ySmallRow2 = yBegin + 2 * (smallHeight + spacingRow);
|
||||
// row用于记录下个item应该属于第几行,item->rowIndex用于记录当前处于第几行,
|
||||
// item->rowIndex主要用于SARibbonPannelItem::Medium
|
||||
short row = 0;
|
||||
int column = 0;
|
||||
// 记录每列最大的宽度
|
||||
int columMaxWidth = 0;
|
||||
// 记录总宽度
|
||||
int totalWidth = 0;
|
||||
|
||||
int itemCount = mItems.count();
|
||||
|
||||
#if SARibbonPannelLayout_DEBUG_PRINT && SA_DEBUG_PRINT_SIZE_HINT
|
||||
QString debug_print__log__;
|
||||
#endif
|
||||
// 本列第一、二行占比
|
||||
SARibbonPannelItem::RowProportion thisColumnRP0 = SARibbonPannelItem::None;
|
||||
SARibbonPannelItem* lastGeomItem = nullptr; // 记录最后一个设置位置的item
|
||||
for (int i = 0; i < itemCount; ++i) {
|
||||
SARibbonPannelItem* item = mItems.at(i);
|
||||
if (item->isEmpty()) {
|
||||
// 如果是hide就直接跳过
|
||||
item->rowIndex = -1;
|
||||
item->columnIndex = -1;
|
||||
continue;
|
||||
}
|
||||
|
||||
QSize hint = item->sizeHint();
|
||||
#if SARibbonPannelLayout_DEBUG_PRINT && SA_DEBUG_PRINT_SIZE_HINT
|
||||
if (SARibbonToolButton* tb = qobject_cast< SARibbonToolButton* >(item->widget())) {
|
||||
auto ss__ = tb->sizeHint();
|
||||
debug_print__log__ += QString("| | |-[%1]SARibbonToolButton.sizeHint=(%2,%3),ButtonText=%4\n")
|
||||
.arg(i)
|
||||
.arg(ss__.width())
|
||||
.arg(ss__.height())
|
||||
.arg(tb->text());
|
||||
}
|
||||
#endif
|
||||
Qt::Orientations exp = item->expandingDirections();
|
||||
if (item->widget()) {
|
||||
// 有窗口是水平扩展,则标记为扩展
|
||||
if ((item->widget()->sizePolicy().horizontalPolicy() & QSizePolicy::ExpandFlag)) {
|
||||
mExpandFlag = true;
|
||||
}
|
||||
}
|
||||
SARibbonPannelItem::RowProportion rp = item->rowProportion;
|
||||
if (SARibbonPannelItem::None == rp) {
|
||||
// 为定义行占比但是垂直扩展,就定义为Large占比,否则就是small占比
|
||||
if (exp & Qt::Vertical) {
|
||||
rp = SARibbonPannelItem::Large;
|
||||
} else {
|
||||
rp = SARibbonPannelItem::Small;
|
||||
}
|
||||
}
|
||||
// 开始根据占比和layoutmode来布局
|
||||
switch (rp) {
|
||||
case SARibbonPannelItem::Large: {
|
||||
// !!在Large,如果不是处于新列的第一行,就需要进行换列处理
|
||||
// 把large一直设置在下一列的开始
|
||||
if (row != 0) {
|
||||
x += (columMaxWidth + spacing);
|
||||
++column;
|
||||
}
|
||||
//
|
||||
item->rowIndex = 0;
|
||||
item->columnIndex = column;
|
||||
item->itemWillSetGeometry = QRect(x, yBegin, hint.width(), largeHeight);
|
||||
columMaxWidth = hint.width();
|
||||
// 换列,x自动递增到下个坐标,列数增加,行数归零,最大列宽归零
|
||||
x += (columMaxWidth + spacing);
|
||||
row = 0;
|
||||
columMaxWidth = 0;
|
||||
++column;
|
||||
} break;
|
||||
|
||||
case SARibbonPannelItem::Medium: {
|
||||
// 2行模式下Medium和small等价
|
||||
if (2 == rowCount) {
|
||||
if (0 == row) {
|
||||
item->rowIndex = 0;
|
||||
item->columnIndex = column;
|
||||
item->itemWillSetGeometry = QRect(x, yMediumRow0, hint.width(), smallHeight);
|
||||
thisColumnRP0 = SARibbonPannelItem::Medium;
|
||||
columMaxWidth = hint.width();
|
||||
// 下个row为1
|
||||
row = 1;
|
||||
// x不变
|
||||
} else {
|
||||
item->rowIndex = 1;
|
||||
item->columnIndex = column;
|
||||
item->itemWillSetGeometry = QRect(x, yMediumRow1, hint.width(), smallHeight);
|
||||
// 和上个进行比较得到最长宽度
|
||||
columMaxWidth = qMax(columMaxWidth, hint.width());
|
||||
// 换列,x自动递增到下个坐标,列数增加,行数归零,最大列宽归零
|
||||
x += (columMaxWidth + spacing);
|
||||
row = 0;
|
||||
columMaxWidth = 0;
|
||||
++column;
|
||||
}
|
||||
} else {
|
||||
// 3行模式
|
||||
if (0 == row) {
|
||||
item->rowIndex = 0;
|
||||
item->columnIndex = column;
|
||||
item->itemWillSetGeometry = QRect(x, yMediumRow0, hint.width(), smallHeight);
|
||||
thisColumnRP0 = SARibbonPannelItem::Medium;
|
||||
columMaxWidth = hint.width();
|
||||
row = 1;
|
||||
// x不变
|
||||
} else if (1 == row) {
|
||||
item->rowIndex = 1;
|
||||
item->columnIndex = column;
|
||||
item->itemWillSetGeometry = QRect(x, yMediumRow1, hint.width(), smallHeight);
|
||||
columMaxWidth = qMax(columMaxWidth, hint.width());
|
||||
// 换列,x自动递增到下个坐标,列数增加,行数归零,最大列宽归零
|
||||
x += (columMaxWidth + spacing);
|
||||
row = 0;
|
||||
columMaxWidth = 0;
|
||||
++column;
|
||||
} else {
|
||||
// 这种模式一般情况会发生在当前列前两行是Small,添加了一个Medium
|
||||
// 这时需要先换列
|
||||
// 换列,x自动递增到下个坐标,列数增加,行数归零,最大列宽归零
|
||||
x += (columMaxWidth + spacing);
|
||||
++column;
|
||||
// 换列后此时等价于0 == row
|
||||
item->rowIndex = 0;
|
||||
item->columnIndex = column;
|
||||
item->itemWillSetGeometry = QRect(x, yMediumRow0, hint.width(), smallHeight);
|
||||
thisColumnRP0 = SARibbonPannelItem::Medium;
|
||||
columMaxWidth = hint.width();
|
||||
row = 1;
|
||||
}
|
||||
}
|
||||
} break;
|
||||
|
||||
case SARibbonPannelItem::Small: {
|
||||
if (0 == row) {
|
||||
// 第一行
|
||||
item->rowIndex = 0;
|
||||
item->columnIndex = column;
|
||||
item->itemWillSetGeometry = QRect(x, ySmallRow0, hint.width(), smallHeight);
|
||||
thisColumnRP0 = SARibbonPannelItem::Small;
|
||||
columMaxWidth = hint.width();
|
||||
// 下个row为1
|
||||
row = 1;
|
||||
// x不变
|
||||
} else if (1 == row) {
|
||||
// 第二行
|
||||
item->rowIndex = 1;
|
||||
item->columnIndex = column;
|
||||
item->itemWillSetGeometry = QRect(x, ySmallRow1, hint.width(), smallHeight);
|
||||
if ((3 == rowCount) && (SARibbonPannelItem::Medium == thisColumnRP0)) {
|
||||
// 三行模式,并且第一行是Medium
|
||||
item->itemWillSetGeometry = QRect(x, yMediumRow1, hint.width(), smallHeight);
|
||||
}
|
||||
// 和上个进行比较得到最长宽度
|
||||
columMaxWidth = qMax(columMaxWidth, hint.width());
|
||||
// 这里要看两行还是三行,确定是否要换列
|
||||
if (2 == rowCount) {
|
||||
// 两行模式,换列
|
||||
// 换列,x自动递增到下个坐标,列数增加,行数归零,最大列宽归零
|
||||
x += (columMaxWidth + spacing);
|
||||
row = 0;
|
||||
columMaxWidth = 0;
|
||||
++column;
|
||||
} else {
|
||||
// 三行模式,继续增加行数
|
||||
row = 2;
|
||||
// x不变
|
||||
}
|
||||
if ((3 == rowCount) && (SARibbonPannelItem::Medium == thisColumnRP0)) {
|
||||
// 三行模式,并且第一行是Medium,换列
|
||||
// 换列,x自动递增到下个坐标,列数增加,行数归零,最大列宽归零
|
||||
x += (columMaxWidth + spacing);
|
||||
row = 0;
|
||||
columMaxWidth = 0;
|
||||
++column;
|
||||
}
|
||||
} else {
|
||||
// 第三行
|
||||
item->rowIndex = 2;
|
||||
item->columnIndex = column;
|
||||
item->itemWillSetGeometry = QRect(x, ySmallRow2, hint.width(), smallHeight);
|
||||
// 和上个进行比较得到最长宽度
|
||||
columMaxWidth = qMax(columMaxWidth, hint.width());
|
||||
// 换列,x自动递增到下个坐标,列数增加,行数归零,最大列宽归零
|
||||
x += (columMaxWidth + spacing);
|
||||
row = 0;
|
||||
columMaxWidth = 0;
|
||||
++column;
|
||||
}
|
||||
} break;
|
||||
|
||||
default:
|
||||
// 不可能出现
|
||||
break;
|
||||
}
|
||||
lastGeomItem = item;
|
||||
}
|
||||
// 最后一个元素,更新列数
|
||||
// 2022-06-20 此句本来在循环里面,如果最后一个元素隐藏,会导致无法到达此判断导致异常
|
||||
if (lastGeomItem) { // 最后一个元素,更新totalWidth
|
||||
if (lastGeomItem->columnIndex != column) {
|
||||
// 说明最后一个元素处于最后位置,触发了换列,此时真实列数需要减1,直接等于column索引
|
||||
mColumnCount = column;
|
||||
// 由于最后一个元素触发了换列,x值是新一列的位置,直接作为totalWidth要减去已经加入的spacing
|
||||
totalWidth = x - spacing + mag.right();
|
||||
} else {
|
||||
// 说明最后一个元素处于非最后位置,没有触发下一个换列,此时真实列数等于column索引+1
|
||||
mColumnCount = column + 1;
|
||||
// 由于最后一个元素未触发换列,需要计算totalWidth
|
||||
totalWidth = x + columMaxWidth + mag.right();
|
||||
}
|
||||
}
|
||||
|
||||
// 在设置完所有窗口后,再设置扩展属性的窗口
|
||||
if (totalWidth < setrect.width() && (setrect.width() - totalWidth) > 10) {
|
||||
// 说明可以设置扩展属性的窗口
|
||||
recalcExpandGeomArray(setrect);
|
||||
}
|
||||
// 布局label
|
||||
bool isTitleWidthThanPannel = false;
|
||||
if (isEnableShowPannelTitle()) {
|
||||
mTitleLabelGeometry.setRect(mag.left(), yTitleBegin, setrect.width() - mag.left() - mag.right(), titleH);
|
||||
// 这里要确认标题宽度是否大于totalWidth,如果大于,则要把标题的宽度作为totalwidth
|
||||
QFontMetrics fm = mTitleLabel->fontMetrics();
|
||||
int textWidth = SA_FONTMETRICS_WIDTH(fm, pannel->pannelName());
|
||||
textWidth += 4;
|
||||
if (totalWidth < textWidth) {
|
||||
totalWidth = textWidth;
|
||||
isTitleWidthThanPannel = true; // 说明标题的长度大于按钮布局的长度
|
||||
}
|
||||
}
|
||||
// 布局optionActionButton
|
||||
|
||||
if (isHaveOptionAction()) {
|
||||
QSize optBtnSize = optionActionButtonSize();
|
||||
if (isEnableShowPannelTitle()) {
|
||||
// 有标题
|
||||
mOptionActionBtnGeometry.setRect(mTitleLabelGeometry.right() - mTitleLabelGeometry.height(),
|
||||
mTitleLabelGeometry.y(),
|
||||
mTitleLabelGeometry.height(),
|
||||
mTitleLabelGeometry.height());
|
||||
|
||||
// 特殊情况,如果pannel的标题长度大于totalWidth,那么说明totalWidth比较短
|
||||
// 这时候,optionActionBtn的宽度要加上到标题宽度上
|
||||
if (isTitleWidthThanPannel) {
|
||||
// 由于文字是居中对齐,因此要扩展2个按钮的宽度
|
||||
totalWidth += (2 * titleH);
|
||||
}
|
||||
} else {
|
||||
// 无标题
|
||||
mOptionActionBtnGeometry.setRect(setrect.right() - optBtnSize.width() - mag.right(),
|
||||
setrect.bottom() - optBtnSize.height() - mag.bottom(),
|
||||
optBtnSize.width(),
|
||||
optBtnSize.height());
|
||||
totalWidth += optBtnSize.width();
|
||||
}
|
||||
}
|
||||
// 刷新sizeHint
|
||||
int heightHint = SARibbonPannel::pannelHeightHint(pannel->fontMetrics(), pannel->pannelLayoutMode(), titleH);
|
||||
this->mSizeHint = QSize(totalWidth, heightHint);
|
||||
#if SARibbonPannelLayout_DEBUG_PRINT && SA_DEBUG_PRINT_SIZE_HINT
|
||||
qDebug() << "| |-SARibbonPannelLayout updateGeomArray(" << setrect << "),pannel name = " << pannel->pannelName()
|
||||
<< "\n| | |-size hint =" << this->m_sizeHint //
|
||||
<< "\n| | |-totalWidth=" << totalWidth //
|
||||
<< "\n| | |-last x=" << x //
|
||||
<< "\n| | |-columMaxWidth=" << columMaxWidth //
|
||||
<< "\n| | |-spacing=" << spacing //
|
||||
<< "\n| | |-mag=" << mag //
|
||||
<< "\n| | |-largeHeight=" << largeHeight //
|
||||
<< "\n| | |-smallHeight=" << smallHeight //
|
||||
;
|
||||
qDebug().noquote() << debug_print__log__;
|
||||
#endif
|
||||
}
|
||||
|
||||
void SARibbonPannelLayout::recalcExpandGeomArray(const QRect& setrect)
|
||||
{
|
||||
// 计算能扩展的尺寸
|
||||
int expandwidth = setrect.width() - this->mSizeHint.width();
|
||||
|
||||
if (expandwidth <= 0) {
|
||||
// 没有必要设置
|
||||
return;
|
||||
}
|
||||
// 列扩展信息
|
||||
struct _columnExpandInfo
|
||||
{
|
||||
int oldColumnWidth = 0; ///< 原来的列宽
|
||||
int columnMaximumWidth = -1; ///< 列的最大宽度
|
||||
int columnExpandedWidth = 0; ///< 扩展后列的宽度
|
||||
QList< SARibbonPannelItem* > expandItems;
|
||||
};
|
||||
// 此变量用于记录可以水平扩展的列和控件,在布局结束后,如果还有空间,就把水平扩展的控件进行扩展
|
||||
QMap< int, _columnExpandInfo > columnExpandInfo;
|
||||
|
||||
for (SARibbonPannelItem* item : qAsConst(mItems)) {
|
||||
if ((!item->isEmpty()) && item->expandingDirections() & Qt::Horizontal) {
|
||||
// 只获取可见的
|
||||
QMap< int, _columnExpandInfo >::iterator i = columnExpandInfo.find(item->columnIndex);
|
||||
if (i == columnExpandInfo.end()) {
|
||||
i = columnExpandInfo.insert(item->columnIndex, _columnExpandInfo());
|
||||
}
|
||||
i.value().expandItems.append(item);
|
||||
}
|
||||
}
|
||||
if (columnExpandInfo.size() <= 0) {
|
||||
// 没有需要扩展的就退出
|
||||
return;
|
||||
}
|
||||
// 获取完可扩展的列和控件后,计算对应的列的尺寸
|
||||
// 计算能扩展的尺寸
|
||||
int oneColCanexpandWidth = expandwidth / columnExpandInfo.size();
|
||||
|
||||
for (QMap< int, _columnExpandInfo >::iterator i = columnExpandInfo.begin(); i != columnExpandInfo.end();) {
|
||||
int& oldColumnWidth = i.value().oldColumnWidth;
|
||||
int& columnMaximumWidth = i.value().columnMaximumWidth;
|
||||
this->columnWidthInfo(i.key(), oldColumnWidth, columnMaximumWidth);
|
||||
if ((oldColumnWidth <= 0) || (oldColumnWidth > columnMaximumWidth)) {
|
||||
// 如果小于0说明没有这个列,这种属于异常,删除继续
|
||||
// oldColumnWidth > columnMaximumWidth也是异常
|
||||
i = columnExpandInfo.erase(i);
|
||||
continue;
|
||||
}
|
||||
// 开始调整
|
||||
int colwidth = oneColCanexpandWidth + oldColumnWidth; // 先扩展了
|
||||
if (colwidth >= columnMaximumWidth) {
|
||||
// 过最大宽度要求
|
||||
i.value().columnExpandedWidth = columnMaximumWidth;
|
||||
} else {
|
||||
i.value().columnExpandedWidth = colwidth;
|
||||
}
|
||||
++i;
|
||||
}
|
||||
// 从新调整尺寸
|
||||
// 由于会涉及其他列的变更,因此需要所有都遍历一下
|
||||
for (auto i = columnExpandInfo.begin(); i != columnExpandInfo.end(); ++i) {
|
||||
int moveXLen = i.value().columnExpandedWidth - i.value().oldColumnWidth;
|
||||
for (SARibbonPannelItem* item : qAsConst(mItems)) {
|
||||
if (item->isEmpty() || (item->columnIndex < i.key())) {
|
||||
// 之前的列不用管
|
||||
continue;
|
||||
}
|
||||
if (item->columnIndex == i.key()) {
|
||||
// 此列的扩展
|
||||
if (i.value().expandItems.contains(item)) {
|
||||
// 此列需要扩展的item才扩展尺寸
|
||||
item->itemWillSetGeometry.setWidth(i.value().columnExpandedWidth);
|
||||
} else {
|
||||
// 此列不扩展的模块保持原来的尺寸
|
||||
continue;
|
||||
}
|
||||
} else {
|
||||
// 后面的移动
|
||||
item->itemWillSetGeometry.moveLeft(item->itemWillSetGeometry.x() + moveXLen);
|
||||
}
|
||||
}
|
||||
}
|
||||
#if SARibbonPannelLayout_DEBUG_PRINT && SA_DEBUG_PRINT_SIZE_HINT
|
||||
qDebug() << "| |-SARibbonPannelLayout recalcExpandGeomArray(" << setrect
|
||||
<< ") pannelName=" << ribbonPannel()->pannelName() //
|
||||
<< ",expandwidth=" << expandwidth //
|
||||
;
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 根据列数,计算窗口的宽度,以及最大宽度
|
||||
* @param colindex
|
||||
* @param width 如果传入没有这个列,返回-1
|
||||
* @param maximum 如果传入没有这个列,返回-1
|
||||
*/
|
||||
void SARibbonPannelLayout::columnWidthInfo(int colindex, int& width, int& maximum) const
|
||||
{
|
||||
width = -1;
|
||||
maximum = -1;
|
||||
for (SARibbonPannelItem* item : mItems) {
|
||||
if (!item->isEmpty() && (item->columnIndex == colindex)) {
|
||||
width = qMax(width, item->itemWillSetGeometry.width());
|
||||
maximum = qMax(maximum, item->widget()->maximumWidth());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
SARibbonPannelLabel* SARibbonPannelLayout::pannelTitleLabel() const
|
||||
{
|
||||
return mTitleLabel;
|
||||
}
|
||||
|
||||
void SARibbonPannelLayout::setToolButtonIconSize(const QSize& s)
|
||||
{
|
||||
mDefaultToolButtonIconSize = s;
|
||||
}
|
||||
|
||||
QSize SARibbonPannelLayout::toolButtonIconSize() const
|
||||
{
|
||||
return mDefaultToolButtonIconSize;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 获取optionAction 按钮尺寸
|
||||
* @return
|
||||
*/
|
||||
QSize SARibbonPannelLayout::optionActionButtonSize() const
|
||||
{
|
||||
return (isEnableShowPannelTitle() ? QSize(12, 12) : QSize(mTitleHeight, mTitleHeight));
|
||||
}
|
||||
|
||||
void SARibbonPannelLayout::setPannelTitleLabel(SARibbonPannelLabel* newTitleLabel)
|
||||
{
|
||||
mTitleLabel = newTitleLabel;
|
||||
// 确保m_optionActionBtn在label之上
|
||||
if (mOptionActionBtn) {
|
||||
if (mTitleLabel) {
|
||||
mTitleLabel->stackUnder(mOptionActionBtn);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 标题区域和按钮的间隔
|
||||
* @return
|
||||
*/
|
||||
int SARibbonPannelLayout::pannelTitleSpace() const
|
||||
{
|
||||
return mTitleSpace;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 设置标题区域和按钮的间隔
|
||||
* @param newTitleSpace
|
||||
*/
|
||||
void SARibbonPannelLayout::setPannelTitleSpace(int newTitleSpace)
|
||||
{
|
||||
if (mTitleSpace == newTitleSpace) {
|
||||
return;
|
||||
}
|
||||
mTitleSpace = newTitleSpace;
|
||||
invalidate();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 标题高度
|
||||
* @return
|
||||
*/
|
||||
int SARibbonPannelLayout::pannelTitleHeight() const
|
||||
{
|
||||
return mTitleHeight;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 设置标题高度
|
||||
* @param newTitleHeight
|
||||
*/
|
||||
void SARibbonPannelLayout::setPannelTitleHeight(int newTitleHeight)
|
||||
{
|
||||
if (mTitleHeight == newTitleHeight) {
|
||||
return;
|
||||
}
|
||||
mTitleHeight = newTitleHeight;
|
||||
invalidate();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 判断是否存在标题
|
||||
* @return
|
||||
*/
|
||||
bool SARibbonPannelLayout::isEnableShowPannelTitle() const
|
||||
{
|
||||
return mEnableShowTitle;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 设置显示标题
|
||||
* @param on
|
||||
*/
|
||||
void SARibbonPannelLayout::setEnableShowPannelTitle(bool on)
|
||||
{
|
||||
if (mEnableShowTitle == on) {
|
||||
return;
|
||||
}
|
||||
mEnableShowTitle = on;
|
||||
invalidate();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 大按钮的高度
|
||||
* @return
|
||||
*/
|
||||
int SARibbonPannelLayout::largeButtonHeight() const
|
||||
{
|
||||
return mLargeHeight;
|
||||
}
|
||||
|
||||
void SARibbonPannelLayout::setGeometry(const QRect& rect)
|
||||
{
|
||||
QRect old = geometry();
|
||||
if (old == rect) {
|
||||
return;
|
||||
}
|
||||
#if SARibbonPannelLayout_DEBUG_PRINT && SA_DEBUG_PRINT_SIZE_HINT
|
||||
qDebug() << "| |----->SARibbonPannelLayout.setGeometry(" << rect << "(" << ribbonPannel()->pannelName() << ")=======";
|
||||
#endif
|
||||
QLayout::setGeometry(rect);
|
||||
mDirty = false;
|
||||
updateGeomArray(rect);
|
||||
doLayout();
|
||||
}
|
||||
@@ -0,0 +1,113 @@
|
||||
#ifndef SARIBBONPANNELLAYOUT_H
|
||||
#define SARIBBONPANNELLAYOUT_H
|
||||
#include "SARibbonGlobal.h"
|
||||
#include <QLayout>
|
||||
#include "SARibbonPannelItem.h"
|
||||
class QToolButton;
|
||||
class SARibbonPannel;
|
||||
class SARibbonPannelLabel;
|
||||
/**
|
||||
* @brief 针对SARibbonPannel的布局
|
||||
*
|
||||
* SARibbonPannelLayout实际是一个列布局,每一列有2~3行,看窗口定占几行
|
||||
*
|
||||
* 核心函数: @ref SARibbonPannelLayout::createItem
|
||||
*
|
||||
* @note QLayout::contentsMargins 函数不会启作用,如果要设置contentsMargins,使用@sa setPannelContentsMargins
|
||||
*/
|
||||
class SA_RIBBON_EXPORT SARibbonPannelLayout : public QLayout
|
||||
{
|
||||
Q_OBJECT
|
||||
friend class SARibbonPannel;
|
||||
|
||||
public:
|
||||
explicit SARibbonPannelLayout(QWidget* p = nullptr);
|
||||
~SARibbonPannelLayout();
|
||||
// SARibbonPannelLayout additem 无效
|
||||
void addItem(QLayoutItem* item) Q_DECL_OVERRIDE;
|
||||
// QLayout 所必须的重载函数
|
||||
QLayoutItem* itemAt(int index) const Q_DECL_OVERRIDE;
|
||||
QLayoutItem* takeAt(int index) Q_DECL_OVERRIDE;
|
||||
int count() const Q_DECL_OVERRIDE;
|
||||
bool isEmpty() const Q_DECL_OVERRIDE;
|
||||
void invalidate() Q_DECL_OVERRIDE;
|
||||
Qt::Orientations expandingDirections() const Q_DECL_OVERRIDE;
|
||||
void setGeometry(const QRect& rect) Q_DECL_OVERRIDE;
|
||||
QSize minimumSize() const Q_DECL_OVERRIDE;
|
||||
QSize sizeHint() const Q_DECL_OVERRIDE;
|
||||
|
||||
// 获取ribbonpannel
|
||||
SARibbonPannel* ribbonPannel() const;
|
||||
// SARibbonPannel主要通过此函数来添加action
|
||||
void insertAction(int index, QAction* act, SARibbonPannelItem::RowProportion rp = SARibbonPannelItem::None);
|
||||
// 设置OptionAction,如果要去除,传入nullptr指针即可
|
||||
void setOptionAction(QAction* action);
|
||||
bool isHaveOptionAction() const;
|
||||
// 通过action获取SARibbonPannelItem
|
||||
SARibbonPannelItem* pannelItem(QAction* action) const;
|
||||
// 获取最后一个添加的item
|
||||
SARibbonPannelItem* lastItem() const;
|
||||
// 获取最后生成的窗口
|
||||
QWidget* lastWidget() const;
|
||||
// 移动两个item
|
||||
void move(int from, int to);
|
||||
// 判断是否需要重新布局
|
||||
bool isDirty() const;
|
||||
// 更新尺寸
|
||||
void updateGeomArray();
|
||||
// 通过action获取SARibbonPannelItem的索引
|
||||
int indexByAction(QAction* action) const;
|
||||
// 标题高度
|
||||
int pannelTitleHeight() const;
|
||||
void setPannelTitleHeight(int newTitleHeight);
|
||||
// 判断是否存在标题
|
||||
bool isEnableShowPannelTitle() const;
|
||||
void setEnableShowPannelTitle(bool on);
|
||||
// 返回大按钮的高度
|
||||
int largeButtonHeight() const;
|
||||
// 标题区域和按钮的间隔
|
||||
int pannelTitleSpace() const;
|
||||
void setPannelTitleSpace(int newTitleSpace);
|
||||
// pannel 标题的label
|
||||
SARibbonPannelLabel* pannelTitleLabel() const;
|
||||
// 设置按钮的icon尺寸,large action不受此尺寸影响
|
||||
void setToolButtonIconSize(const QSize& s);
|
||||
QSize toolButtonIconSize() const;
|
||||
|
||||
protected:
|
||||
// 获取optionAction 按钮尺寸
|
||||
QSize optionActionButtonSize() const;
|
||||
// 布局action
|
||||
void doLayout();
|
||||
// 把action转换为item,对于纯Action,此函数会创建SARibbonToolButton,
|
||||
// rp用于告诉Layout生成什么样的窗口,详细见SARibbonPannelItem::RowProportion
|
||||
SARibbonPannelItem* createItem(QAction* action, SARibbonPannelItem::RowProportion rp = SARibbonPannelItem::None);
|
||||
void updateGeomArray(const QRect& setrect);
|
||||
// 重新计算扩展条码,此函数必须在updateGeomArray函数之后调用
|
||||
void recalcExpandGeomArray(const QRect& setrect);
|
||||
// 返回optionActionButton的尺寸
|
||||
|
||||
private:
|
||||
// 根据列数,计算窗口的宽度,以及最大宽度
|
||||
void columnWidthInfo(int colindex, int& width, int& maximum) const;
|
||||
// 设置titlelabel
|
||||
void setPannelTitleLabel(SARibbonPannelLabel* newTitleLabel);
|
||||
|
||||
private:
|
||||
QList< SARibbonPannelItem* > mItems;
|
||||
int mColumnCount { 0 }; ///< 记录有多少列
|
||||
bool mExpandFlag { false }; ///< 标记是否是会扩展的
|
||||
QSize mSizeHint; ///< sizeHint返回的尺寸
|
||||
QSize mDefaultToolButtonIconSize { 22, 22 }; ///< 记录默认的按钮图标尺寸
|
||||
bool mDirty { true }; ///< 用于标记是否需要刷新元素,参考QToolBarLayout源码
|
||||
int mLargeHeight { 0 }; ///< 记录大图标的高度
|
||||
int mTitleHeight { 15 }; ///< 标题区域高度
|
||||
int mTitleSpace { 2 }; ///< 标题区域和按钮的间隔
|
||||
bool mEnableShowTitle { true }; ///< 是否运行显示pannel标题
|
||||
SARibbonPannelLabel* mTitleLabel { nullptr }; ///< titlelabel指针
|
||||
QRect mTitleLabelGeometry; ///< titlelabel的位置
|
||||
QToolButton* mOptionActionBtn { nullptr }; ///< optionAction对应的button
|
||||
QRect mOptionActionBtnGeometry; ///< optionAction的位置
|
||||
};
|
||||
|
||||
#endif // SARIBBONPANNELLAYOUT_H
|
||||
@@ -0,0 +1,16 @@
|
||||
#include "SARibbonPannelOptionButton.h"
|
||||
#include <QAction>
|
||||
|
||||
SARibbonPannelOptionButton::SARibbonPannelOptionButton(QWidget* parent) : QToolButton(parent)
|
||||
{
|
||||
setAutoRaise(true);
|
||||
setCheckable(false);
|
||||
setToolButtonStyle(Qt::ToolButtonIconOnly);
|
||||
setIconSize(QSize(10, 10));
|
||||
static QIcon s_default_icon = QIcon(":/image/resource/ribbonPannelOptionButton.png");
|
||||
setIcon(s_default_icon);
|
||||
}
|
||||
|
||||
SARibbonPannelOptionButton::~SARibbonPannelOptionButton()
|
||||
{
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
#ifndef SARIBBONPANNELOPTIONBUTTON_H
|
||||
#define SARIBBONPANNELOPTIONBUTTON_H
|
||||
#include <QToolButton>
|
||||
#include "SARibbonGlobal.h"
|
||||
class QAction;
|
||||
|
||||
/**
|
||||
* @brief Pannel右下角的操作按钮
|
||||
*
|
||||
* 此按钮和一个action关联,使用@ref SARibbonPannel::addOptionAction 函数用于生成此按钮,正常来说
|
||||
* 用户并不需要直接操作此类,仅仅用于样式设计
|
||||
* 如果一定要重载此按钮,可以通过重载@ref SARibbonElementFactory
|
||||
* 的 @ref SARibbonElementFactory::createRibbonPannelOptionButton来实现新的OptionButton
|
||||
*
|
||||
*/
|
||||
class SA_RIBBON_EXPORT SARibbonPannelOptionButton : public QToolButton
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit SARibbonPannelOptionButton(QWidget* parent = nullptr);
|
||||
~SARibbonPannelOptionButton();
|
||||
};
|
||||
|
||||
#endif // SAROBBONPANNELOPTIONBUTTON_H
|
||||
@@ -0,0 +1,92 @@
|
||||
#include "SARibbonQuickAccessBar.h"
|
||||
#include "SARibbonButtonGroupWidget.h"
|
||||
#include "SARibbonSeparatorWidget.h"
|
||||
#include <QGuiApplication>
|
||||
|
||||
/**
|
||||
* @brief The SARibbonQuickAccessBarPrivate class
|
||||
*/
|
||||
class SARibbonQuickAccessBar::PrivateData
|
||||
{
|
||||
SA_RIBBON_DECLARE_PUBLIC(SARibbonQuickAccessBar)
|
||||
public:
|
||||
PrivateData(SARibbonQuickAccessBar* p);
|
||||
|
||||
public:
|
||||
SARibbonButtonGroupWidget* mGroupWidget { nullptr };
|
||||
};
|
||||
|
||||
SARibbonQuickAccessBar::PrivateData::PrivateData(SARibbonQuickAccessBar* p) : q_ptr(p)
|
||||
{
|
||||
}
|
||||
|
||||
//===================================================
|
||||
// SARibbonQuickAccessBar
|
||||
//===================================================
|
||||
SARibbonQuickAccessBar::SARibbonQuickAccessBar(QWidget* parent)
|
||||
: SARibbonCtrlContainer(parent), d_ptr(new SARibbonQuickAccessBar::PrivateData(this))
|
||||
{
|
||||
d_ptr->mGroupWidget = new SARibbonButtonGroupWidget(this);
|
||||
d_ptr->mGroupWidget->setSizePolicy(QSizePolicy(QSizePolicy::Preferred, QSizePolicy::Expanding));
|
||||
setContainerWidget(d_ptr->mGroupWidget);
|
||||
}
|
||||
|
||||
SARibbonQuickAccessBar::~SARibbonQuickAccessBar()
|
||||
{
|
||||
}
|
||||
|
||||
void SARibbonQuickAccessBar::addSeparator()
|
||||
{
|
||||
d_ptr->mGroupWidget->addSeparator();
|
||||
}
|
||||
|
||||
void SARibbonQuickAccessBar::addAction(QAction* act, Qt::ToolButtonStyle buttonStyle, QToolButton::ToolButtonPopupMode popMode)
|
||||
{
|
||||
d_ptr->mGroupWidget->addAction(act, buttonStyle, popMode);
|
||||
}
|
||||
|
||||
void SARibbonQuickAccessBar::addWidget(QWidget* w)
|
||||
{
|
||||
d_ptr->mGroupWidget->addWidget(w);
|
||||
}
|
||||
|
||||
void SARibbonQuickAccessBar::addMenu(QMenu* m, Qt::ToolButtonStyle buttonStyle, QToolButton::ToolButtonPopupMode popMode)
|
||||
{
|
||||
d_ptr->mGroupWidget->addMenu(m, buttonStyle, popMode);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 获取内部管理的ButtonGroupWidget
|
||||
* @return
|
||||
*/
|
||||
SARibbonButtonGroupWidget* SARibbonQuickAccessBar::buttonGroupWidget()
|
||||
{
|
||||
return d_ptr->mGroupWidget;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 获取内部管理的ButtonGroupWidget
|
||||
* @return
|
||||
*/
|
||||
const SARibbonButtonGroupWidget* SARibbonQuickAccessBar::buttonGroupWidget() const
|
||||
{
|
||||
return d_ptr->mGroupWidget;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 图标尺寸
|
||||
* @param s
|
||||
*/
|
||||
void SARibbonQuickAccessBar::setIconSize(const QSize& s)
|
||||
{
|
||||
d_ptr->mGroupWidget->setIconSize(s);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief SARibbonQuickAccessBar::iconSize
|
||||
* @return
|
||||
*/
|
||||
QSize SARibbonQuickAccessBar::iconSize() const
|
||||
{
|
||||
return d_ptr->mGroupWidget->iconSize();
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
#ifndef SARIBBONQUICKACCESSBAR_H
|
||||
#define SARIBBONQUICKACCESSBAR_H
|
||||
#include "SARibbonGlobal.h"
|
||||
#include "SARibbonCtrlContainer.h"
|
||||
#include <QMenu>
|
||||
#include <QToolButton>
|
||||
class SARibbonToolButton;
|
||||
class SARibbonButtonGroupWidget;
|
||||
///
|
||||
/// \brief ribbon左上顶部的快速响应栏
|
||||
///
|
||||
class SA_RIBBON_EXPORT SARibbonQuickAccessBar : public SARibbonCtrlContainer
|
||||
{
|
||||
Q_OBJECT
|
||||
SA_RIBBON_DECLARE_PRIVATE(SARibbonQuickAccessBar)
|
||||
public:
|
||||
explicit SARibbonQuickAccessBar(QWidget* parent = nullptr);
|
||||
~SARibbonQuickAccessBar();
|
||||
void addSeparator();
|
||||
void addAction(QAction* act,
|
||||
Qt::ToolButtonStyle buttonStyle = Qt::ToolButtonIconOnly,
|
||||
QToolButton::ToolButtonPopupMode popMode = QToolButton::DelayedPopup);
|
||||
void addWidget(QWidget* w);
|
||||
void addMenu(QMenu* m,
|
||||
Qt::ToolButtonStyle buttonStyle = Qt::ToolButtonIconOnly,
|
||||
QToolButton::ToolButtonPopupMode popMode = QToolButton::InstantPopup);
|
||||
// 获取内部管理的ButtonGroupWidget
|
||||
SARibbonButtonGroupWidget* buttonGroupWidget();
|
||||
const SARibbonButtonGroupWidget* buttonGroupWidget() const;
|
||||
// 设置图标尺寸
|
||||
void setIconSize(const QSize& s);
|
||||
QSize iconSize() const;
|
||||
};
|
||||
|
||||
#endif // SARIBBONQUICKACCESSBAR_H
|
||||
@@ -0,0 +1,26 @@
|
||||
#include "SARibbonSeparatorWidget.h"
|
||||
#include <QApplication>
|
||||
#include <QScreen>
|
||||
#include <QStylePainter>
|
||||
#include <QPainter>
|
||||
#include <QDebug>
|
||||
|
||||
SARibbonSeparatorWidget::SARibbonSeparatorWidget(QWidget* parent) : QFrame(parent)
|
||||
{
|
||||
setFrameShape(QFrame::VLine);
|
||||
setFrameShadow(QFrame::Plain);
|
||||
|
||||
if(QScreen* screen = QApplication::primaryScreen()){
|
||||
qreal dpr = screen->physicalDotsPerInch() / screen->logicalDotsPerInch();
|
||||
int scaledLineWidth = qRound(1.0 * dpr); // 假设基础 lineWidth 是 1
|
||||
setLineWidth(scaledLineWidth);
|
||||
// qDebug() << "SARibbonSeparatorWidget:" << scaledLineWidth;
|
||||
}else{
|
||||
setLineWidth(1);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
SARibbonSeparatorWidget::~SARibbonSeparatorWidget()
|
||||
{
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
#ifndef SARIBBONSEPARATORWIDGET_H
|
||||
#define SARIBBONSEPARATORWIDGET_H
|
||||
#include "SARibbonGlobal.h"
|
||||
#include <QFrame>
|
||||
#include <QStyleOption>
|
||||
|
||||
///
|
||||
/// \brief 用于显示分割线
|
||||
///
|
||||
class SA_RIBBON_EXPORT SARibbonSeparatorWidget : public QFrame
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit SARibbonSeparatorWidget(QWidget* parent = nullptr);
|
||||
~SARibbonSeparatorWidget();
|
||||
};
|
||||
|
||||
#endif // SARIBBONSEPARATORWIDGET_H
|
||||
@@ -0,0 +1,115 @@
|
||||
#include "SARibbonStackedWidget.h"
|
||||
#include <QEventLoop>
|
||||
#include <QResizeEvent>
|
||||
#include <QMouseEvent>
|
||||
#include <QDebug>
|
||||
#include <QApplication>
|
||||
|
||||
/**
|
||||
* @brief The SARibbonStackedWidgetPrivate class
|
||||
*/
|
||||
class SARibbonStackedWidget::PrivateData
|
||||
{
|
||||
SA_RIBBON_DECLARE_PUBLIC(SARibbonStackedWidget)
|
||||
public:
|
||||
QEventLoop* eventLoop { nullptr };
|
||||
|
||||
public:
|
||||
PrivateData(SARibbonStackedWidget* p) : q_ptr(p)
|
||||
{
|
||||
}
|
||||
|
||||
void init()
|
||||
{
|
||||
// Parent->setFocusPolicy(Qt::StrongFocus);
|
||||
}
|
||||
};
|
||||
|
||||
SARibbonStackedWidget::SARibbonStackedWidget(QWidget* parent)
|
||||
: QStackedWidget(parent), d_ptr(new SARibbonStackedWidget::PrivateData(this))
|
||||
{
|
||||
d_ptr->init();
|
||||
setNormalMode();
|
||||
}
|
||||
|
||||
SARibbonStackedWidget::~SARibbonStackedWidget()
|
||||
{
|
||||
if (d_ptr->eventLoop) {
|
||||
d_ptr->eventLoop->exit();
|
||||
}
|
||||
}
|
||||
|
||||
void SARibbonStackedWidget::setPopupMode()
|
||||
{
|
||||
setMouseTracking(true);
|
||||
setWindowFlags(Qt::Popup | Qt::FramelessWindowHint);
|
||||
setFrameShape(QFrame::Panel);
|
||||
}
|
||||
|
||||
bool SARibbonStackedWidget::isPopupMode() const
|
||||
{
|
||||
return (windowFlags() & Qt::Popup);
|
||||
}
|
||||
|
||||
void SARibbonStackedWidget::setNormalMode()
|
||||
{
|
||||
if (d_ptr->eventLoop) {
|
||||
d_ptr->eventLoop->exit();
|
||||
d_ptr->eventLoop = nullptr;
|
||||
}
|
||||
setMouseTracking(false);
|
||||
setWindowFlags(Qt::Widget | Qt::FramelessWindowHint);
|
||||
setFrameShape(QFrame::NoFrame);
|
||||
}
|
||||
|
||||
bool SARibbonStackedWidget::isNormalMode() const
|
||||
{
|
||||
return (!isPopupMode());
|
||||
}
|
||||
|
||||
void SARibbonStackedWidget::exec()
|
||||
{
|
||||
show();
|
||||
if (!isPopupMode()) {
|
||||
d_ptr->eventLoop = nullptr;
|
||||
return;
|
||||
}
|
||||
QEventLoop event;
|
||||
|
||||
d_ptr->eventLoop = &event;
|
||||
event.exec();
|
||||
d_ptr->eventLoop = nullptr;
|
||||
}
|
||||
|
||||
void SARibbonStackedWidget::moveWidget(int from, int to)
|
||||
{
|
||||
QWidget* w = widget(from);
|
||||
|
||||
removeWidget(w);
|
||||
insertWidget(to, w);
|
||||
}
|
||||
|
||||
void SARibbonStackedWidget::hideEvent(QHideEvent* e)
|
||||
{
|
||||
if (isPopupMode()) {
|
||||
if (d_ptr->eventLoop) {
|
||||
d_ptr->eventLoop->exit();
|
||||
}
|
||||
}
|
||||
setFocus();
|
||||
Q_EMIT hidWindow();
|
||||
|
||||
QStackedWidget::hideEvent(e);
|
||||
}
|
||||
|
||||
void SARibbonStackedWidget::resizeEvent(QResizeEvent* e)
|
||||
{
|
||||
QStackedWidget::resizeEvent(e);
|
||||
for (int i = 0; i < count(); ++i) {
|
||||
if (i == currentIndex()) {
|
||||
continue;
|
||||
}
|
||||
QEvent* layE = new QEvent(QEvent::LayoutRequest);
|
||||
QApplication::postEvent(widget(i), layE);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
#ifndef SARIBBONSTACKEDWIDGET_H
|
||||
#define SARIBBONSTACKEDWIDGET_H
|
||||
#include <QStackedWidget>
|
||||
#include "SARibbonGlobal.h"
|
||||
class QHideEvent;
|
||||
class QResizeEvent;
|
||||
|
||||
/**
|
||||
* @brief 有qdialog功能的stackwidget,用于在最小化时stack能像dialog那样弹出来
|
||||
*/
|
||||
class SA_RIBBON_EXPORT SARibbonStackedWidget : public QStackedWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
SA_RIBBON_DECLARE_PRIVATE(SARibbonStackedWidget)
|
||||
public:
|
||||
explicit SARibbonStackedWidget(QWidget* parent);
|
||||
~SARibbonStackedWidget();
|
||||
void setPopupMode();
|
||||
bool isPopupMode() const;
|
||||
void setNormalMode();
|
||||
bool isNormalMode() const;
|
||||
void exec();
|
||||
|
||||
/**
|
||||
* @brief 类似tabbar的moveTab函数,交换两个窗口的index
|
||||
* @param from
|
||||
* @param to
|
||||
* @note 此操作会触发widgetRemoved(int index)信号
|
||||
*/
|
||||
void moveWidget(int from, int to);
|
||||
|
||||
protected:
|
||||
// void mouseReleaseEvent(QMouseEvent *e);
|
||||
void hideEvent(QHideEvent* e) Q_DECL_OVERRIDE;
|
||||
virtual void resizeEvent(QResizeEvent* e) Q_DECL_OVERRIDE;
|
||||
Q_SIGNALS:
|
||||
/**
|
||||
* @brief hidWindow
|
||||
*/
|
||||
void hidWindow();
|
||||
};
|
||||
|
||||
#endif // SARIBBONSTACKEDWIDGET_H
|
||||
@@ -0,0 +1,467 @@
|
||||
#include "SARibbonSystemButtonBar.h"
|
||||
#include <QToolButton>
|
||||
#include <QResizeEvent>
|
||||
#include <QStyle>
|
||||
#include <QDebug>
|
||||
#include <QScopedPointer>
|
||||
#include <QWindowStateChangeEvent>
|
||||
#include "SARibbonMainWindow.h"
|
||||
#include "SARibbonBar.h"
|
||||
#include "SARibbonElementManager.h"
|
||||
#include "SARibbonButtonGroupWidget.h"
|
||||
|
||||
// 为了避免使用此框架的app设置了全局的qpushbutton 的 qss样式影响此按钮,定义了一个类
|
||||
|
||||
/**
|
||||
* @brief The SARibbonSystemButtonBar class
|
||||
*/
|
||||
class SARibbonSystemButtonBar::PrivateData
|
||||
{
|
||||
SA_RIBBON_DECLARE_PUBLIC(SARibbonSystemButtonBar)
|
||||
public:
|
||||
SARibbonSystemToolButton* buttonClose { nullptr };
|
||||
SARibbonSystemToolButton* buttonMinimize { nullptr };
|
||||
SARibbonSystemToolButton* buttonMaximize { nullptr };
|
||||
int mCloseStretch { 4 };
|
||||
int mMaxStretch { 3 };
|
||||
int mMinStretch { 3 };
|
||||
int mWindowButtonWidth { 35 };
|
||||
int mTitleBarHeight { 28 };
|
||||
Qt::WindowFlags mFlags { Qt::WindowMinMaxButtonsHint | Qt::WindowCloseButtonHint };
|
||||
SARibbonButtonGroupWidget* mButtonGroup;
|
||||
|
||||
public:
|
||||
PrivateData(SARibbonSystemButtonBar* p) : q_ptr(p)
|
||||
{
|
||||
mButtonGroup = new SARibbonButtonGroupWidget(p);
|
||||
mButtonGroup->setObjectName("SASystemButtonGroup");
|
||||
}
|
||||
|
||||
void setupMinimizeButton(bool on)
|
||||
{
|
||||
SARibbonSystemButtonBar* par = q_ptr;
|
||||
|
||||
if (on) {
|
||||
if (buttonMinimize) {
|
||||
buttonMinimize->deleteLater();
|
||||
buttonMinimize = nullptr;
|
||||
}
|
||||
buttonMinimize = new SARibbonSystemToolButton(par);
|
||||
buttonMinimize->setObjectName(QStringLiteral("SAMinimizeWindowButton"));
|
||||
buttonMinimize->setFocusPolicy(Qt::NoFocus); // 避免铺抓到
|
||||
buttonMinimize->show();
|
||||
par->connect(buttonMinimize, &QAbstractButton::clicked, par, &SARibbonSystemButtonBar::minimizeWindow);
|
||||
} else {
|
||||
if (buttonMinimize) {
|
||||
buttonMinimize->deleteLater();
|
||||
buttonMinimize = nullptr;
|
||||
}
|
||||
}
|
||||
updateSize();
|
||||
}
|
||||
|
||||
void setupMaximizeButton(bool on)
|
||||
{
|
||||
SARibbonSystemButtonBar* par = q_ptr;
|
||||
|
||||
if (on) {
|
||||
if (buttonMaximize) {
|
||||
buttonMaximize->deleteLater();
|
||||
buttonMaximize = nullptr;
|
||||
}
|
||||
buttonMaximize = new SARibbonSystemToolButton(par);
|
||||
buttonMaximize->setObjectName(QStringLiteral("SAMaximizeWindowButton"));
|
||||
buttonMaximize->setCheckable(true);
|
||||
buttonMaximize->setFocusPolicy(Qt::NoFocus); // 避免铺抓到
|
||||
// buttonMaximize->setIconSize(buttonMaximize->size() * mIconscale);
|
||||
buttonMaximize->show();
|
||||
par->connect(buttonMaximize, &QAbstractButton::clicked, par, &SARibbonSystemButtonBar::maximizeWindow);
|
||||
} else {
|
||||
if (buttonMaximize) {
|
||||
buttonMaximize->deleteLater();
|
||||
;
|
||||
buttonMaximize = nullptr;
|
||||
}
|
||||
}
|
||||
updateSize();
|
||||
}
|
||||
|
||||
void setupCloseButton(bool on)
|
||||
{
|
||||
SARibbonSystemButtonBar* par = q_ptr;
|
||||
|
||||
if (on) {
|
||||
if (buttonClose) {
|
||||
buttonClose->deleteLater();
|
||||
buttonClose = nullptr;
|
||||
}
|
||||
buttonClose = new SARibbonSystemToolButton(par);
|
||||
buttonClose->setObjectName(QStringLiteral("SACloseWindowButton"));
|
||||
buttonClose->setFocusPolicy(Qt::NoFocus); // 避免铺抓到
|
||||
// buttonClose->setFlat(true);
|
||||
par->connect(buttonClose, &QAbstractButton::clicked, par, &SARibbonSystemButtonBar::closeWindow);
|
||||
// buttonClose->setIconSize(buttonClose->size() * mIconscale);
|
||||
buttonClose->show();
|
||||
} else {
|
||||
if (buttonClose) {
|
||||
buttonClose->deleteLater();
|
||||
;
|
||||
buttonClose = nullptr;
|
||||
}
|
||||
}
|
||||
updateSize();
|
||||
}
|
||||
|
||||
void updateSize()
|
||||
{
|
||||
resizeElement(q_ptr->size());
|
||||
}
|
||||
|
||||
void resizeElement(QSize size)
|
||||
{
|
||||
int x = size.width();
|
||||
if (buttonClose) {
|
||||
int w = closeButtonWidthHint();
|
||||
x -= w;
|
||||
buttonClose->setGeometry(x, 0, w, size.height());
|
||||
}
|
||||
if (buttonMaximize) {
|
||||
int w = maxButtonWidthHint();
|
||||
x -= w;
|
||||
buttonMaximize->setGeometry(x, 0, w, size.height());
|
||||
}
|
||||
if (buttonMinimize) {
|
||||
int w = minButtonWidthHint();
|
||||
x -= w;
|
||||
buttonMinimize->setGeometry(x, 0, w, size.height());
|
||||
}
|
||||
if (mButtonGroup) {
|
||||
mButtonGroup->setGeometry(0, 0, x, size.height());
|
||||
}
|
||||
}
|
||||
|
||||
int closeButtonWidthHint() const
|
||||
{
|
||||
qreal t = mCloseStretch + mMaxStretch + mMinStretch;
|
||||
return (mCloseStretch * (3 * mWindowButtonWidth)) / t;
|
||||
}
|
||||
|
||||
int maxButtonWidthHint() const
|
||||
{
|
||||
qreal t = mCloseStretch + mMaxStretch + mMinStretch;
|
||||
return (mMaxStretch * (3 * mWindowButtonWidth)) / t;
|
||||
}
|
||||
|
||||
int minButtonWidthHint() const
|
||||
{
|
||||
qreal t = mCloseStretch + mMaxStretch + mMinStretch;
|
||||
return (mMinStretch * (3 * mWindowButtonWidth)) / t;
|
||||
}
|
||||
|
||||
QSize sizeHint() const
|
||||
{
|
||||
int height = mTitleBarHeight;
|
||||
if (height < 20) {
|
||||
height = 20;
|
||||
}
|
||||
QSize res(0, 0);
|
||||
if (mButtonGroup) {
|
||||
res = mButtonGroup->sizeHint();
|
||||
}
|
||||
res.setHeight(height);
|
||||
if (buttonClose) {
|
||||
res.setWidth(res.width() + closeButtonWidthHint());
|
||||
}
|
||||
if (buttonMaximize) {
|
||||
res.setWidth(res.width() + maxButtonWidthHint());
|
||||
}
|
||||
if (buttonMinimize) {
|
||||
res.setWidth(res.width() + minButtonWidthHint());
|
||||
}
|
||||
return res;
|
||||
}
|
||||
};
|
||||
|
||||
//===================================================
|
||||
// SARibbonSystemToolButton
|
||||
//===================================================
|
||||
SARibbonSystemToolButton::SARibbonSystemToolButton(QWidget* p) : QToolButton(p)
|
||||
{
|
||||
setAutoRaise(true);
|
||||
}
|
||||
//===================================================
|
||||
// SARibbonSystemButtonBar
|
||||
//===================================================
|
||||
SARibbonSystemButtonBar::SARibbonSystemButtonBar(QWidget* parent)
|
||||
: QFrame(parent), d_ptr(new SARibbonSystemButtonBar::PrivateData(this))
|
||||
{
|
||||
updateWindowFlag();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 构造函数,强制使用flags,而不是用parent的flags进行构造
|
||||
* @param parent
|
||||
* @param flags
|
||||
*/
|
||||
SARibbonSystemButtonBar::SARibbonSystemButtonBar(QWidget* parent, Qt::WindowFlags flags)
|
||||
: QFrame(parent), d_ptr(new SARibbonSystemButtonBar::PrivateData(this))
|
||||
{
|
||||
d_ptr->mFlags = flags;
|
||||
updateWindowFlag();
|
||||
}
|
||||
|
||||
SARibbonSystemButtonBar::~SARibbonSystemButtonBar()
|
||||
{
|
||||
}
|
||||
|
||||
void SARibbonSystemButtonBar::setupMinimizeButton(bool on)
|
||||
{
|
||||
d_ptr->setupMinimizeButton(on);
|
||||
}
|
||||
|
||||
void SARibbonSystemButtonBar::setupMaximizeButton(bool on)
|
||||
{
|
||||
d_ptr->setupMaximizeButton(on);
|
||||
}
|
||||
|
||||
void SARibbonSystemButtonBar::setupCloseButton(bool on)
|
||||
{
|
||||
d_ptr->setupCloseButton(on);
|
||||
}
|
||||
|
||||
void SARibbonSystemButtonBar::updateWindowFlag()
|
||||
{
|
||||
QWidget* topedWidget = this;
|
||||
// 找到最顶层窗口
|
||||
while (topedWidget->parentWidget()) {
|
||||
topedWidget = topedWidget->parentWidget();
|
||||
}
|
||||
Qt::WindowFlags flags = topedWidget->windowFlags();
|
||||
updateWindowFlag(flags);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 此函数仅用于控制最小最大化和关闭按钮的显示
|
||||
* @param flags
|
||||
*/
|
||||
void SARibbonSystemButtonBar::updateWindowFlag(Qt::WindowFlags flags)
|
||||
{
|
||||
d_ptr->mFlags = flags;
|
||||
setupMinimizeButton(flags & Qt::WindowMinimizeButtonHint);
|
||||
setupMaximizeButton(flags & Qt::WindowMaximizeButtonHint);
|
||||
setupCloseButton(flags & Qt::WindowCloseButtonHint);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 设置按钮的宽度比例,最终按钮宽度将按照此比例进行设置
|
||||
* @param close 关闭按钮比例
|
||||
* @param max 最大化按钮比例
|
||||
* @param min 最小化按钮比例
|
||||
*/
|
||||
void SARibbonSystemButtonBar::setButtonWidthStretch(int close, int max, int min)
|
||||
{
|
||||
d_ptr->mMaxStretch = max;
|
||||
d_ptr->mMinStretch = min;
|
||||
d_ptr->mCloseStretch = close;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 标题栏高度
|
||||
*
|
||||
* 标题栏高度会影响sizeHint
|
||||
* @param h
|
||||
*/
|
||||
void SARibbonSystemButtonBar::setWindowTitleHeight(int h)
|
||||
{
|
||||
d_ptr->mTitleBarHeight = h;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 标题栏高度
|
||||
* @return
|
||||
*/
|
||||
int SARibbonSystemButtonBar::windowTitleHeight() const
|
||||
{
|
||||
return d_ptr->mTitleBarHeight;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 系统按钮的宽度
|
||||
* @param w
|
||||
*/
|
||||
void SARibbonSystemButtonBar::setWindowButtonWidth(int w)
|
||||
{
|
||||
d_ptr->mWindowButtonWidth = w;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 系统按钮的宽度
|
||||
* @param w
|
||||
*/
|
||||
int SARibbonSystemButtonBar::windowButtonWidth() const
|
||||
{
|
||||
return d_ptr->mWindowButtonWidth;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 设置窗口状态(最大最小化按钮状态)
|
||||
* @param s
|
||||
*/
|
||||
void SARibbonSystemButtonBar::setWindowStates(Qt::WindowStates s)
|
||||
{
|
||||
if (d_ptr->buttonMaximize) {
|
||||
bool on = s.testFlag(Qt::WindowMaximized);
|
||||
d_ptr->buttonMaximize->setChecked(on);
|
||||
d_ptr->buttonMaximize->setToolTip(on ? tr("Restore") : tr("Maximize"));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 此函数返回的flags仅包括 Qt::WindowCloseButtonHint,Qt::WindowMaximizeButtonHint,Qt::WindowMinimizeButtonHint
|
||||
* 三个
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
Qt::WindowFlags SARibbonSystemButtonBar::windowButtonFlags() const
|
||||
{
|
||||
Qt::WindowFlags f = Qt::Widget; // widget是000
|
||||
|
||||
if (d_ptr->mFlags & Qt::WindowCloseButtonHint) {
|
||||
f |= Qt::WindowCloseButtonHint;
|
||||
}
|
||||
if (d_ptr->mFlags & Qt::WindowMaximizeButtonHint) {
|
||||
f |= Qt::WindowMaximizeButtonHint;
|
||||
}
|
||||
if (d_ptr->mFlags & Qt::WindowMinimizeButtonHint) {
|
||||
f |= Qt::WindowMinimizeButtonHint;
|
||||
}
|
||||
|
||||
return (f);
|
||||
}
|
||||
|
||||
QSize SARibbonSystemButtonBar::sizeHint() const
|
||||
{
|
||||
return (d_ptr->sizeHint());
|
||||
}
|
||||
|
||||
bool SARibbonSystemButtonBar::eventFilter(QObject* obj, QEvent* event)
|
||||
{
|
||||
if (obj == parent()) {
|
||||
// SARibbonMainWindow的事件
|
||||
if (event->type() == QEvent::Resize) {
|
||||
SARibbonMainWindow* mainWindow = qobject_cast< SARibbonMainWindow* >(obj);
|
||||
if (!mainWindow) {
|
||||
// 所有事件都不消费
|
||||
return QFrame::eventFilter(obj, event);
|
||||
}
|
||||
SARibbonBar* ribbonBar = mainWindow->ribbonBar();
|
||||
if (!ribbonBar) {
|
||||
// 所有事件都不消费
|
||||
return QFrame::eventFilter(obj, event);
|
||||
}
|
||||
const int th = ribbonBar->titleBarHeight();
|
||||
if (th != height()) {
|
||||
setWindowTitleHeight(th);
|
||||
}
|
||||
QRect fr = mainWindow->geometry();
|
||||
QSize wgSizeHint = sizeHint();
|
||||
setGeometry(fr.width() - wgSizeHint.width(), 0, wgSizeHint.width(), wgSizeHint.height());
|
||||
// 把设置好的尺寸给ribbonbar
|
||||
ribbonBar->setWindowButtonGroupSize(size());
|
||||
} else if (event->type() == QEvent::WindowStateChange) {
|
||||
SARibbonMainWindow* mainWindow = qobject_cast< SARibbonMainWindow* >(obj);
|
||||
if (!mainWindow) {
|
||||
// 所有事件都不消费
|
||||
return QFrame::eventFilter(obj, event);
|
||||
}
|
||||
setWindowStates(mainWindow->windowState());
|
||||
}
|
||||
}
|
||||
return QFrame::eventFilter(obj, event);
|
||||
}
|
||||
|
||||
QAbstractButton* SARibbonSystemButtonBar::minimizeButton() const
|
||||
{
|
||||
return d_ptr->buttonMinimize;
|
||||
}
|
||||
|
||||
QAbstractButton* SARibbonSystemButtonBar::maximizeButton() const
|
||||
{
|
||||
return d_ptr->buttonMaximize;
|
||||
}
|
||||
|
||||
QAbstractButton* SARibbonSystemButtonBar::closeButton() const
|
||||
{
|
||||
return d_ptr->buttonClose;
|
||||
}
|
||||
|
||||
void SARibbonSystemButtonBar::setIconSize(const QSize& ic)
|
||||
{
|
||||
d_ptr->mButtonGroup->setIconSize(ic);
|
||||
}
|
||||
|
||||
QSize SARibbonSystemButtonBar::iconSize() const
|
||||
{
|
||||
return d_ptr->mButtonGroup->iconSize();
|
||||
}
|
||||
|
||||
QAction* SARibbonSystemButtonBar::addAction(QAction* a, Qt::ToolButtonStyle buttonStyle, QToolButton::ToolButtonPopupMode popMode)
|
||||
{
|
||||
return d_ptr->mButtonGroup->addAction(a, buttonStyle, popMode);
|
||||
}
|
||||
|
||||
QAction* SARibbonSystemButtonBar::addAction(const QString& text,
|
||||
const QIcon& icon,
|
||||
Qt::ToolButtonStyle buttonStyle,
|
||||
QToolButton::ToolButtonPopupMode popMode)
|
||||
{
|
||||
return d_ptr->mButtonGroup->addAction(text, icon, buttonStyle, popMode);
|
||||
}
|
||||
|
||||
QAction* SARibbonSystemButtonBar::addMenu(QMenu* menu, Qt::ToolButtonStyle buttonStyle, QToolButton::ToolButtonPopupMode popMode)
|
||||
{
|
||||
return d_ptr->mButtonGroup->addMenu(menu, buttonStyle, popMode);
|
||||
}
|
||||
|
||||
QAction* SARibbonSystemButtonBar::addSeparator()
|
||||
{
|
||||
return d_ptr->mButtonGroup->addSeparator();
|
||||
}
|
||||
|
||||
QAction* SARibbonSystemButtonBar::addWidget(QWidget* w)
|
||||
{
|
||||
return d_ptr->mButtonGroup->addWidget(w);
|
||||
}
|
||||
|
||||
void SARibbonSystemButtonBar::resizeEvent(QResizeEvent* e)
|
||||
{
|
||||
Q_UNUSED(e);
|
||||
d_ptr->resizeElement(size());
|
||||
}
|
||||
|
||||
void SARibbonSystemButtonBar::closeWindow()
|
||||
{
|
||||
if (parentWidget()) {
|
||||
parentWidget()->close();
|
||||
}
|
||||
}
|
||||
|
||||
void SARibbonSystemButtonBar::minimizeWindow()
|
||||
{
|
||||
if (parentWidget()) {
|
||||
parentWidget()->showMinimized();
|
||||
}
|
||||
}
|
||||
|
||||
void SARibbonSystemButtonBar::maximizeWindow()
|
||||
{
|
||||
QWidget* par = parentWidget();
|
||||
|
||||
if (par) {
|
||||
if (par->isMaximized()) {
|
||||
par->showNormal();
|
||||
} else {
|
||||
par->showMaximized();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,88 @@
|
||||
#ifndef SARIBBONSYSTEMBUTTONBAR_H
|
||||
#define SARIBBONSYSTEMBUTTONBAR_H
|
||||
#include "SARibbonGlobal.h"
|
||||
#include <QFrame>
|
||||
#include <QToolButton>
|
||||
|
||||
/**
|
||||
* @brief 窗口的最大最小化按钮
|
||||
* @note 内部有个SARibbonButtonGroupWidget,其ObjectName = SASystemButtonGroup
|
||||
* 如果需要qss,可以进行特化处理:
|
||||
*
|
||||
* @code
|
||||
* SARibbonButtonGroupWidget#SASystemButtonGroup
|
||||
* @endcode
|
||||
*
|
||||
*/
|
||||
class SA_RIBBON_EXPORT SARibbonSystemButtonBar : public QFrame
|
||||
{
|
||||
Q_OBJECT
|
||||
SA_RIBBON_DECLARE_PRIVATE(SARibbonSystemButtonBar)
|
||||
public:
|
||||
explicit SARibbonSystemButtonBar(QWidget* parent);
|
||||
explicit SARibbonSystemButtonBar(QWidget* parent, Qt::WindowFlags flags);
|
||||
~SARibbonSystemButtonBar();
|
||||
void setupMinimizeButton(bool on);
|
||||
void setupMaximizeButton(bool on);
|
||||
void setupCloseButton(bool on);
|
||||
// 以最顶层的widget的WindowFlag作为WindowFlag
|
||||
void updateWindowFlag();
|
||||
void updateWindowFlag(Qt::WindowFlags flags);
|
||||
// 设置按钮的宽度比例,最终按钮宽度将按照此比例进行设置
|
||||
void setButtonWidthStretch(int close = 4, int max = 3, int min = 3);
|
||||
// 标题栏高度
|
||||
void setWindowTitleHeight(int h);
|
||||
int windowTitleHeight() const;
|
||||
// 设置标准系统按钮的宽度
|
||||
void setWindowButtonWidth(int w);
|
||||
int windowButtonWidth() const;
|
||||
// 设置Qt::WindowStates
|
||||
void setWindowStates(Qt::WindowStates s);
|
||||
// 仅获取按钮的状态
|
||||
Qt::WindowFlags windowButtonFlags() const;
|
||||
// 三个标准系统窗口按钮
|
||||
QAbstractButton* minimizeButton() const;
|
||||
QAbstractButton* maximizeButton() const;
|
||||
QAbstractButton* closeButton() const;
|
||||
|
||||
// 图标尺寸
|
||||
void setIconSize(const QSize& ic);
|
||||
QSize iconSize() const;
|
||||
// 生成并添加一个action
|
||||
QAction* addAction(QAction* a,
|
||||
Qt::ToolButtonStyle buttonStyle = Qt::ToolButtonIconOnly,
|
||||
QToolButton::ToolButtonPopupMode popMode = QToolButton::DelayedPopup);
|
||||
QAction* addAction(const QString& text,
|
||||
const QIcon& icon,
|
||||
Qt::ToolButtonStyle buttonStyle = Qt::ToolButtonIconOnly,
|
||||
QToolButton::ToolButtonPopupMode popMode = QToolButton::DelayedPopup);
|
||||
QAction* addMenu(QMenu* menu,
|
||||
Qt::ToolButtonStyle buttonStyle = Qt::ToolButtonIconOnly,
|
||||
QToolButton::ToolButtonPopupMode popMode = QToolButton::InstantPopup);
|
||||
QAction* addSeparator();
|
||||
QAction* addWidget(QWidget* w);
|
||||
|
||||
virtual QSize sizeHint() const Q_DECL_OVERRIDE;
|
||||
// 捕获mainwindow的事件
|
||||
bool eventFilter(QObject* obj, QEvent* event) override;
|
||||
|
||||
protected:
|
||||
virtual void resizeEvent(QResizeEvent* e) Q_DECL_OVERRIDE;
|
||||
|
||||
protected Q_SLOTS:
|
||||
Q_SLOT void closeWindow();
|
||||
Q_SLOT void minimizeWindow();
|
||||
Q_SLOT void maximizeWindow();
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief The SARibbonSystemToolButton class
|
||||
*/
|
||||
class SARibbonSystemToolButton : public QToolButton
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
SARibbonSystemToolButton(QWidget* p = nullptr);
|
||||
};
|
||||
|
||||
#endif // SARIBBONSYSTEMBUTTONBAR_H
|
||||
@@ -0,0 +1,57 @@
|
||||
#include "SARibbonTabBar.h"
|
||||
#include <QStyleOptionTab>
|
||||
#include <QFontMetrics>
|
||||
|
||||
SARibbonTabBar::SARibbonTabBar(QWidget* parent) : QTabBar(parent), m_tabMargin(6, 0, 0, 0)
|
||||
{
|
||||
setExpanding(false);
|
||||
}
|
||||
|
||||
SARibbonTabBar::~SARibbonTabBar()
|
||||
{
|
||||
}
|
||||
|
||||
const QMargins& SARibbonTabBar::tabMargin() const
|
||||
{
|
||||
return (m_tabMargin);
|
||||
}
|
||||
|
||||
void SARibbonTabBar::setTabMargin(const QMargins& tabMargin)
|
||||
{
|
||||
m_tabMargin = tabMargin;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief tab的尺寸预估
|
||||
*
|
||||
* 有别于系统默认的tabbar,SARibbonTabBar的tab高度和tabbar高度一致,且不考虑纵向分布情况
|
||||
* @param index
|
||||
* @return
|
||||
*/
|
||||
QSize SARibbonTabBar::tabSizeHint(int index) const
|
||||
{
|
||||
if (index < 0) {
|
||||
return QSize();
|
||||
}
|
||||
QStyleOptionTab opt;
|
||||
initStyleOption(&opt, index);
|
||||
int hframe = style()->pixelMetric(QStyle::PM_TabBarTabHSpace, &opt, this);
|
||||
const QFontMetrics fm = fontMetrics();
|
||||
|
||||
int widgetWidth = 0;
|
||||
int padding = 0;
|
||||
if (!opt.leftButtonSize.isEmpty()) {
|
||||
padding += 4;
|
||||
widgetWidth += opt.leftButtonSize.width();
|
||||
}
|
||||
if (!opt.rightButtonSize.isEmpty()) {
|
||||
padding += 4;
|
||||
widgetWidth += opt.rightButtonSize.width();
|
||||
}
|
||||
if (!opt.icon.isNull()) {
|
||||
padding += 4;
|
||||
}
|
||||
const int textWidth = fm.size(Qt::TextShowMnemonic, opt.text).width();
|
||||
QSize csz = QSize(textWidth + opt.iconSize.width() + hframe + widgetWidth + padding, height());
|
||||
return style()->sizeFromContents(QStyle::CT_TabBarTab, &opt, csz, this);
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
#ifndef SARIBBONTABBAR_H
|
||||
#define SARIBBONTABBAR_H
|
||||
#include "SARibbonGlobal.h"
|
||||
#include <QTabBar>
|
||||
#include <QMargins>
|
||||
|
||||
/**
|
||||
* @brief The SARibbonTabBar class
|
||||
*/
|
||||
class SA_RIBBON_EXPORT SARibbonTabBar : public QTabBar
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit SARibbonTabBar(QWidget* parent = nullptr);
|
||||
~SARibbonTabBar();
|
||||
const QMargins& tabMargin() const;
|
||||
void setTabMargin(const QMargins& tabMargin);
|
||||
|
||||
protected:
|
||||
QSize tabSizeHint(int index) const;
|
||||
|
||||
private:
|
||||
QMargins m_tabMargin;
|
||||
};
|
||||
|
||||
#endif // SARIBBONTABBAR_H
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,92 @@
|
||||
#ifndef SARIBBONTOOLBUTTON_H
|
||||
#define SARIBBONTOOLBUTTON_H
|
||||
#include "SARibbonGlobal.h"
|
||||
#include <QToolButton>
|
||||
#include <QDebug>
|
||||
/**
|
||||
* @brief Ribbon界面适用的toolButton
|
||||
*
|
||||
* 相对于普通toolbutton,主要多了两个类型设置,@ref setButtonType 和 @ref setLargeButtonType
|
||||
*
|
||||
* @note @sa setIconSize 函数不在起作用,iconsize是根据当前尺寸动态调整的
|
||||
*/
|
||||
class SA_RIBBON_EXPORT SARibbonToolButton : public QToolButton
|
||||
{
|
||||
Q_OBJECT
|
||||
SA_RIBBON_DECLARE_PRIVATE(SARibbonToolButton)
|
||||
public:
|
||||
/**
|
||||
* @brief 按钮样式
|
||||
*/
|
||||
enum RibbonButtonType
|
||||
{
|
||||
LargeButton,
|
||||
SmallButton
|
||||
};
|
||||
Q_ENUM(RibbonButtonType)
|
||||
|
||||
public:
|
||||
explicit SARibbonToolButton(QWidget* parent = nullptr);
|
||||
explicit SARibbonToolButton(QAction* defaultAction, QWidget* parent = nullptr);
|
||||
~SARibbonToolButton();
|
||||
//标记按钮的样式,按钮的样式有不同的渲染方式
|
||||
RibbonButtonType buttonType() const;
|
||||
void setButtonType(const RibbonButtonType& buttonType);
|
||||
//是否是小按钮
|
||||
bool isSmallRibbonButton() const;
|
||||
//是否是大按钮
|
||||
bool isLargeRibbonButton() const;
|
||||
//最小尺寸提示
|
||||
virtual QSize minimumSizeHint() const Q_DECL_OVERRIDE;
|
||||
|
||||
//获取间距
|
||||
int spacing() const;
|
||||
//更新尺寸
|
||||
void updateRect();
|
||||
|
||||
virtual QSize sizeHint() const Q_DECL_OVERRIDE;
|
||||
|
||||
public:
|
||||
//在lite模式下是否允许文字换行
|
||||
static void setEnableWordWrap(bool on);
|
||||
static bool isEnableWordWrap();
|
||||
|
||||
protected:
|
||||
virtual void paintEvent(QPaintEvent* e) Q_DECL_OVERRIDE;
|
||||
virtual void resizeEvent(QResizeEvent* e) Q_DECL_OVERRIDE;
|
||||
virtual void mouseMoveEvent(QMouseEvent* e) Q_DECL_OVERRIDE;
|
||||
virtual void mousePressEvent(QMouseEvent* e) Q_DECL_OVERRIDE;
|
||||
virtual void mouseReleaseEvent(QMouseEvent* e) Q_DECL_OVERRIDE;
|
||||
virtual void focusOutEvent(QFocusEvent* e) Q_DECL_OVERRIDE;
|
||||
virtual void leaveEvent(QEvent* e) Q_DECL_OVERRIDE;
|
||||
virtual bool hitButton(const QPoint& pos) const Q_DECL_OVERRIDE;
|
||||
virtual bool event(QEvent* e) Q_DECL_OVERRIDE;
|
||||
//事件改变 - 主要为了捕获字体的改变
|
||||
virtual void changeEvent(QEvent* e) Q_DECL_OVERRIDE;
|
||||
virtual void actionEvent(QActionEvent* e) Q_DECL_OVERRIDE;
|
||||
|
||||
protected:
|
||||
//绘制按钮
|
||||
virtual void paintButton(QPainter& p, const QStyleOptionToolButton& opt);
|
||||
//绘制图标
|
||||
virtual void paintIcon(QPainter& p, const QStyleOptionToolButton& opt, const QRect& iconDrawRect);
|
||||
//绘制文本
|
||||
virtual void paintText(QPainter& p, const QStyleOptionToolButton& opt, const QRect& textDrawRect);
|
||||
//绘制Indicator
|
||||
virtual void paintIndicator(QPainter& p, const QStyleOptionToolButton& opt, const QRect& indicatorDrawRect);
|
||||
|
||||
private:
|
||||
static void drawArrow(const QStyle* style,
|
||||
const QStyleOptionToolButton* toolbutton,
|
||||
const QRect& rect,
|
||||
QPainter* painter,
|
||||
const QWidget* widget = 0);
|
||||
|
||||
protected:
|
||||
};
|
||||
|
||||
namespace SA
|
||||
{
|
||||
QDebug operator<<(QDebug debug, const QStyleOptionToolButton& opt);
|
||||
}
|
||||
#endif // SARIBBONTOOLBUTTON_H
|
||||
@@ -0,0 +1,227 @@
|
||||
#include "SARibbonWidget.h"
|
||||
#include "SARibbonBar.h"
|
||||
#include "SARibbonTabBar.h"
|
||||
#include <QApplication>
|
||||
#include <QDebug>
|
||||
#include <QFile>
|
||||
#include <QScreen>
|
||||
|
||||
/**
|
||||
* @brief The SARibbonWidget::PrivateData class
|
||||
*/
|
||||
class SARibbonWidget::PrivateData
|
||||
{
|
||||
SA_RIBBON_DECLARE_PUBLIC(SARibbonWidget)
|
||||
public:
|
||||
PrivateData(SARibbonWidget* p);
|
||||
void installFrameless(SARibbonWidget* p);
|
||||
|
||||
public:
|
||||
SARibbonTheme mCurrentRibbonTheme { SARibbonTheme::RibbonThemeOffice2021Blue };
|
||||
};
|
||||
|
||||
SARibbonWidget::PrivateData::PrivateData(SARibbonWidget* p) : q_ptr(p)
|
||||
{
|
||||
}
|
||||
|
||||
//===================================================
|
||||
// SARibbonWidget
|
||||
//===================================================
|
||||
SARibbonWidget::SARibbonWidget(QWidget* parent) : QWidget(parent), d_ptr(new SARibbonWidget::PrivateData(this))
|
||||
{
|
||||
// 直接创建SARibbonBar
|
||||
QVBoxLayout* verticalLayout = new QVBoxLayout(this);
|
||||
verticalLayout->setSpacing(1);
|
||||
verticalLayout->setObjectName("verticalLayout");
|
||||
verticalLayout->setContentsMargins(0, 0, 0, 0);
|
||||
SARibbonBar* ribbon = new SARibbonBar(this);
|
||||
setRibbonBar(ribbon);
|
||||
connect(qApp, &QApplication::primaryScreenChanged, this, &SARibbonWidget::onPrimaryScreenChanged);
|
||||
}
|
||||
|
||||
SARibbonWidget::~SARibbonWidget()
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 返回ribbonbar,如果不是使用ribbon模式,返回nullptr
|
||||
* @return
|
||||
*/
|
||||
SARibbonBar* SARibbonWidget::ribbonBar() const
|
||||
{
|
||||
QLayout* lay = layout();
|
||||
if (lay) {
|
||||
return qobject_cast< SARibbonBar* >(lay->menuBar());
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 设置ribbonbar
|
||||
* @param bar
|
||||
*/
|
||||
void SARibbonWidget::setRibbonBar(SARibbonBar* bar)
|
||||
{
|
||||
QLayout* lay = layout();
|
||||
if (lay) {
|
||||
lay->setMenuBar(bar);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief SARibbonMainWindow::setRibbonTheme
|
||||
*
|
||||
* 注意主题在构造函数设置主题会不完全生效,使用QTimer投放到队列最后执行即可
|
||||
* @code
|
||||
* QTimer::singleShot(0, this, [ this ]() { this->setRibbonTheme(SARibbonMainWindow::RibbonThemeDark); });
|
||||
* @endcode
|
||||
* @param theme
|
||||
*/
|
||||
void SARibbonWidget::setRibbonTheme(SARibbonTheme theme)
|
||||
{
|
||||
sa_set_ribbon_theme(this, theme);
|
||||
d_ptr->mCurrentRibbonTheme = theme;
|
||||
if (SARibbonBar* bar = ribbonBar()) {
|
||||
auto theme = ribbonTheme();
|
||||
// 尺寸修正
|
||||
switch (theme) {
|
||||
case SARibbonTheme::RibbonThemeWindows7:
|
||||
case SARibbonTheme::RibbonThemeOffice2013:
|
||||
case SARibbonTheme::RibbonThemeOffice2016Blue:
|
||||
case SARibbonTheme::RibbonThemeDark:
|
||||
case SARibbonTheme::RibbonThemeDark2: {
|
||||
//! 在设置qss后需要针对margin信息重新设置进SARibbonTabBar中
|
||||
//! office2013.qss的margin信息如下设置
|
||||
//! margin-top: 0px;
|
||||
//! margin-right: 0px;
|
||||
//! margin-left: 5px;
|
||||
//! margin-bottom: 0px;
|
||||
SARibbonTabBar* tab = bar->ribbonTabBar();
|
||||
if (!tab) {
|
||||
break;
|
||||
}
|
||||
tab->setTabMargin(QMargins(5, 0, 0, 0));
|
||||
} break;
|
||||
case SARibbonTheme::RibbonThemeOffice2021Blue: {
|
||||
SARibbonTabBar* tab = bar->ribbonTabBar();
|
||||
if (!tab) {
|
||||
break;
|
||||
}
|
||||
//! 在设置qss后需要针对margin信息重新设置进SARibbonTabBar中
|
||||
//! office2021.qss的margin信息如下设置
|
||||
//! margin-top: 0px;
|
||||
//! margin-right: 5px;
|
||||
//! margin-left: 5px;
|
||||
//! margin-bottom: 0px;
|
||||
tab->setTabMargin(QMargins(5, 0, 5, 0));
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
// 上下文标签颜色设置,以及基线颜色设置
|
||||
switch (theme) {
|
||||
case SARibbonTheme::RibbonThemeWindows7:
|
||||
case SARibbonTheme::RibbonThemeOffice2013:
|
||||
case SARibbonTheme::RibbonThemeDark:
|
||||
bar->setContextCategoryColorList(QList< QColor >()); //< 设置空颜色列表会重置为默认色系
|
||||
break;
|
||||
case SARibbonTheme::RibbonThemeOffice2016Blue:
|
||||
bar->setContextCategoryColorList(QList< QColor >() << QColor(18, 64, 120)); //< 设置空颜色列表会重置为默认色系
|
||||
break;
|
||||
case SARibbonTheme::RibbonThemeOffice2021Blue:
|
||||
bar->setContextCategoryColorList(QList< QColor >() << QColor(209, 207, 209)); //< 设置空颜色列表会重置为默认色系
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
// 基线颜色设置
|
||||
if (SARibbonTheme::RibbonThemeOffice2013 == theme) {
|
||||
bar->setTabBarBaseLineColor(QColor(186, 201, 219));
|
||||
} else {
|
||||
bar->setTabBarBaseLineColor(QColor());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
SARibbonTheme SARibbonWidget::ribbonTheme() const
|
||||
{
|
||||
return (d_ptr->mCurrentRibbonTheme);
|
||||
}
|
||||
|
||||
bool SARibbonWidget::isUseRibbon() const
|
||||
{
|
||||
return (nullptr != ribbonBar());
|
||||
}
|
||||
|
||||
/**
|
||||
@brief 设置窗口
|
||||
|
||||
@param 窗口指针
|
||||
@note 窗口的所有权归SARibbonWidget管理
|
||||
@sa widget
|
||||
@note 原来设置的窗口会被delete
|
||||
*/
|
||||
void SARibbonWidget::setWidget(QWidget* w)
|
||||
{
|
||||
QWidget* oldwidget = takeWidget();
|
||||
if (oldwidget) {
|
||||
oldwidget->hide();
|
||||
oldwidget->deleteLater();
|
||||
}
|
||||
if (QLayout* lay = layout()) {
|
||||
lay->addWidget(w);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@brief 获取设置的窗口
|
||||
|
||||
@return 如果没有,返回nullptr
|
||||
*/
|
||||
QWidget* SARibbonWidget::widget() const
|
||||
{
|
||||
QLayout* lay = layout();
|
||||
if (lay) {
|
||||
if (lay->count() == 0) {
|
||||
return nullptr;
|
||||
}
|
||||
return lay->itemAt(0)->widget();
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
QWidget* SARibbonWidget::takeWidget()
|
||||
{
|
||||
QLayout* lay = layout();
|
||||
if (nullptr == lay) {
|
||||
return nullptr;
|
||||
}
|
||||
if (lay->count() == 0) {
|
||||
return nullptr;
|
||||
}
|
||||
auto item = lay->itemAt(0);
|
||||
if (nullptr == item) {
|
||||
return nullptr;
|
||||
}
|
||||
lay->removeItem(item);
|
||||
auto w = item->widget();
|
||||
delete item;
|
||||
if (!w) {
|
||||
return nullptr;
|
||||
}
|
||||
return w;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 主屏幕切换触发的信号
|
||||
* @param screen
|
||||
*/
|
||||
void SARibbonWidget::onPrimaryScreenChanged(QScreen* screen)
|
||||
{
|
||||
Q_UNUSED(screen);
|
||||
// 主屏幕切换后,从新计算所有尺寸
|
||||
if (SARibbonBar* bar = ribbonBar()) {
|
||||
qDebug() << "Primary Screen Changed";
|
||||
bar->updateRibbonGeometry();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
#ifndef SARIBBONWIDGET_H
|
||||
#define SARIBBONWIDGET_H
|
||||
#include "SARibbonGlobal.h"
|
||||
#include <QWidget>
|
||||
|
||||
class SARibbonBar;
|
||||
class QScreen;
|
||||
/**
|
||||
* @brief 带SARibbonBar的Widget
|
||||
*
|
||||
* @note 注意,SARibbonWidget利用了布局来把ribbonbar放到最顶部,不要给此widget添加布局,否则会导致布局异常,
|
||||
* 正确的做法是把布局的窗口通过setWidget设置进SARibbonWidget
|
||||
*
|
||||
*/
|
||||
class SA_RIBBON_EXPORT SARibbonWidget : public QWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
SA_RIBBON_DECLARE_PRIVATE(SARibbonWidget)
|
||||
friend class SARibbonBar;
|
||||
Q_PROPERTY(SARibbonTheme ribbonTheme READ ribbonTheme WRITE setRibbonTheme)
|
||||
|
||||
public:
|
||||
explicit SARibbonWidget(QWidget* parent = nullptr);
|
||||
~SARibbonWidget();
|
||||
// 返回SARibbonBar
|
||||
SARibbonBar* ribbonBar() const;
|
||||
// 设置ribbonbar
|
||||
void setRibbonBar(SARibbonBar* bar);
|
||||
|
||||
// 注意主题在构造函数设置主题会不完全生效,使用QTimer投放到队列最后执行即可
|
||||
// QTimer::singleShot(0, this, [ this ]() { this->setRibbonTheme(SARibbonTheme::RibbonThemeDark); });
|
||||
void setRibbonTheme(SARibbonTheme theme);
|
||||
SARibbonTheme ribbonTheme() const;
|
||||
// 判断当前是否使用ribbon模式
|
||||
bool isUseRibbon() const;
|
||||
// 设置窗口
|
||||
void setWidget(QWidget* w);
|
||||
QWidget* widget() const;
|
||||
//
|
||||
QWidget* takeWidget();
|
||||
private Q_SLOTS:
|
||||
void onPrimaryScreenChanged(QScreen* screen);
|
||||
};
|
||||
|
||||
#endif // SARIBBONWIDGET_H
|
||||
@@ -0,0 +1,504 @@
|
||||
#include "SAColorGridWidget.h"
|
||||
#include "SAColorToolButton.h"
|
||||
#include <QGridLayout>
|
||||
#include <cmath>
|
||||
#include <QButtonGroup>
|
||||
|
||||
class SAColorGridWidget::PrivateData
|
||||
{
|
||||
SA_COLOR_WIDGETS_DECLARE_PUBLIC(SAColorGridWidget)
|
||||
public:
|
||||
PrivateData(SAColorGridWidget* p);
|
||||
// 获取ColorToolButton
|
||||
SAColorToolButton* getColorToolButtonAt(int index);
|
||||
SAColorToolButton* getColorToolButtonAt(int r, int c);
|
||||
SAColorToolButton* getCheckedButton() const;
|
||||
void updateGridColor(bool isRemoveSpacer = false);
|
||||
void updateGridColorSize();
|
||||
void updateGridColorCheckable();
|
||||
void iterationColorBtns(SAColorGridWidget::FunColorBtn fn);
|
||||
void removeAt(int r, int c);
|
||||
void setColorAt(const QColor& clr, int r, int c);
|
||||
bool isSpacer(int r, int c) const;
|
||||
|
||||
public:
|
||||
QList< QColor > mColors;
|
||||
QGridLayout* mGridLayout { nullptr };
|
||||
QButtonGroup* mButtonGroup { nullptr };
|
||||
QSize mIconSize { 16, 16 };
|
||||
int mColumnCount { 8 }; ///< 列数,行数量会根据列数量来匹配,如果设置-1或者0,说明不限定列数量,这样会只有一行
|
||||
bool mColorCheckable; ///< 设置颜色是否是checkable
|
||||
bool mHorizontalSpacerToRight { false }; ///< 最右边是否有弹簧
|
||||
};
|
||||
|
||||
SAColorGridWidget::PrivateData::PrivateData(SAColorGridWidget* p) : q_ptr(p)
|
||||
{
|
||||
mGridLayout = new QGridLayout(p);
|
||||
p->setLayout(mGridLayout);
|
||||
mGridLayout->setSpacing(0);
|
||||
mGridLayout->setContentsMargins(1, 1, 1, 1);
|
||||
mButtonGroup = new QButtonGroup(p);
|
||||
mButtonGroup->setExclusive(true);
|
||||
p->setMinimumHeight(mIconSize.height());
|
||||
p->setMinimumWidth(mIconSize.width());
|
||||
}
|
||||
|
||||
SAColorToolButton* SAColorGridWidget::PrivateData::getColorToolButtonAt(int index)
|
||||
{
|
||||
QLayoutItem* item = mGridLayout->itemAt(index);
|
||||
if (nullptr == item) {
|
||||
return nullptr;
|
||||
}
|
||||
return qobject_cast< SAColorToolButton* >(item->widget());
|
||||
}
|
||||
|
||||
SAColorToolButton* SAColorGridWidget::PrivateData::getColorToolButtonAt(int r, int c)
|
||||
{
|
||||
QLayoutItem* item = mGridLayout->itemAtPosition(r, c);
|
||||
if (nullptr == item) {
|
||||
return nullptr;
|
||||
}
|
||||
return qobject_cast< SAColorToolButton* >(item->widget());
|
||||
}
|
||||
|
||||
SAColorToolButton* SAColorGridWidget::PrivateData::getCheckedButton() const
|
||||
{
|
||||
return qobject_cast< SAColorToolButton* >(mButtonGroup->checkedButton());
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 根据mColors更新布局
|
||||
*/
|
||||
void SAColorGridWidget::PrivateData::updateGridColor(bool isRemoveSpacer)
|
||||
{
|
||||
int row = 1;
|
||||
int col = mColumnCount;
|
||||
if (col <= 0) {
|
||||
col = mColors.size();
|
||||
} else {
|
||||
row = std::ceil(mColors.size() / (float)col);
|
||||
}
|
||||
int index = 0;
|
||||
for (int r = 0; r < row; ++r) {
|
||||
for (int c = 0; c < col; ++c) {
|
||||
if (index < mColors.size()) {
|
||||
setColorAt(mColors[ index ], r, c);
|
||||
++index;
|
||||
} else {
|
||||
removeAt(r, c);
|
||||
}
|
||||
}
|
||||
}
|
||||
// 清除多余单元格
|
||||
int nowGridRow = mGridLayout->rowCount();
|
||||
int nowGridCol = mGridLayout->columnCount();
|
||||
if (nowGridRow > row) {
|
||||
// 多余的清除
|
||||
for (int r = row; r < nowGridRow; ++r) {
|
||||
for (int c = 0; c < nowGridCol; ++c) {
|
||||
removeAt(r, c);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (nowGridCol > col) {
|
||||
// 多余的列清除
|
||||
for (int r = 0; r < row; ++r) {
|
||||
for (int c = col; c < nowGridCol; ++c) {
|
||||
if (isRemoveSpacer) {
|
||||
removeAt(r, c);
|
||||
} else {
|
||||
if (!isSpacer(r, c)) {
|
||||
removeAt(r, c);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 更新colorsize
|
||||
*/
|
||||
void SAColorGridWidget::PrivateData::updateGridColorSize()
|
||||
{
|
||||
QSize s = mIconSize;
|
||||
iterationColorBtns([ s ](SAColorToolButton* btn) {
|
||||
if (btn) {
|
||||
btn->setIconSize(s);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
void SAColorGridWidget::PrivateData::updateGridColorCheckable()
|
||||
{
|
||||
bool v = mColorCheckable;
|
||||
iterationColorBtns([ v ](SAColorToolButton* btn) {
|
||||
if (btn) {
|
||||
btn->setCheckable(v);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 遍历所有的button
|
||||
* @param fn
|
||||
*/
|
||||
void SAColorGridWidget::PrivateData::iterationColorBtns(FunColorBtn fn)
|
||||
{
|
||||
int cnt = mGridLayout->count();
|
||||
for (int i = 0; i < cnt; ++i) {
|
||||
SAColorToolButton* tl = getColorToolButtonAt(i);
|
||||
fn(tl);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 删除网格窗口
|
||||
* @param r
|
||||
* @param c
|
||||
*/
|
||||
void SAColorGridWidget::PrivateData::removeAt(int r, int c)
|
||||
{
|
||||
QLayoutItem* item = mGridLayout->itemAtPosition(r, c);
|
||||
if (item) {
|
||||
QWidget* w = item->widget();
|
||||
mGridLayout->removeItem(item);
|
||||
delete item;
|
||||
if (w) {
|
||||
w->deleteLater();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void SAColorGridWidget::PrivateData::setColorAt(const QColor& clr, int r, int c)
|
||||
{
|
||||
QLayoutItem* item = mGridLayout->itemAtPosition(r, c);
|
||||
if (item) {
|
||||
SAColorToolButton* tl = qobject_cast< SAColorToolButton* >(item->widget());
|
||||
if (tl) {
|
||||
tl->setColor(clr);
|
||||
}
|
||||
} else {
|
||||
SAColorToolButton* tl = new SAColorToolButton(SAColorToolButton::NoColorMenu, q_ptr);
|
||||
tl->setToolButtonStyle(Qt::ToolButtonIconOnly);
|
||||
tl->setIconSize(mIconSize);
|
||||
tl->setMargins(QMargins(4, 4, 4, 4));
|
||||
tl->setColor(clr);
|
||||
tl->setCheckable(mColorCheckable);
|
||||
tl->setAutoRaise(true);
|
||||
mButtonGroup->addButton(tl, r + c);
|
||||
mGridLayout->addWidget(tl, r, c);
|
||||
}
|
||||
}
|
||||
|
||||
bool SAColorGridWidget::PrivateData::isSpacer(int r, int c) const
|
||||
{
|
||||
QLayoutItem* item = mGridLayout->itemAtPosition(r, c);
|
||||
if (item) {
|
||||
if (QSpacerItem* si = dynamic_cast< QSpacerItem* >(item)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
//==============================================================
|
||||
// SAColorGridWidget
|
||||
//==============================================================
|
||||
|
||||
SAColorGridWidget::SAColorGridWidget(QWidget* par) : QWidget(par), d_ptr(new SAColorGridWidget::PrivateData(this))
|
||||
{
|
||||
connect(d_ptr->mButtonGroup,
|
||||
QOverload< QAbstractButton* >::of(&QButtonGroup::buttonClicked),
|
||||
this,
|
||||
&SAColorGridWidget::onButtonClicked);
|
||||
connect(d_ptr->mButtonGroup,
|
||||
QOverload< QAbstractButton* >::of(&QButtonGroup::buttonPressed),
|
||||
this,
|
||||
&SAColorGridWidget::onButtonPressed);
|
||||
connect(d_ptr->mButtonGroup,
|
||||
QOverload< QAbstractButton* >::of(&QButtonGroup::buttonReleased),
|
||||
this,
|
||||
&SAColorGridWidget::onButtonReleased);
|
||||
connect(d_ptr->mButtonGroup,
|
||||
QOverload< QAbstractButton*, bool >::of(&QButtonGroup::buttonToggled),
|
||||
this,
|
||||
&SAColorGridWidget::onButtonToggled);
|
||||
}
|
||||
|
||||
SAColorGridWidget::~SAColorGridWidget()
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 设置列数,行数量会根据列数量来匹配,如果设置-1或者0,说明不限定列数量,这样会只有一行
|
||||
* @param c
|
||||
*/
|
||||
void SAColorGridWidget::setColumnCount(int c)
|
||||
{
|
||||
d_ptr->mColumnCount = c;
|
||||
d_ptr->updateGridColor(true);
|
||||
if (d_ptr->mHorizontalSpacerToRight) {
|
||||
setHorizontalSpacerToRight();
|
||||
}
|
||||
updateGeometry();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 设置颜色列表
|
||||
* @param c
|
||||
*/
|
||||
void SAColorGridWidget::setColorList(const QList< QColor >& cls)
|
||||
{
|
||||
d_ptr->mColors = cls;
|
||||
d_ptr->updateGridColor();
|
||||
updateGeometry();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 获取颜色列表
|
||||
* @return
|
||||
*/
|
||||
QList< QColor > SAColorGridWidget::getColorList() const
|
||||
{
|
||||
return d_ptr->mColors;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 获取间隔
|
||||
* @return
|
||||
*/
|
||||
int SAColorGridWidget::spacing() const
|
||||
{
|
||||
return d_ptr->mGridLayout->spacing();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 设置间隔
|
||||
* @param v
|
||||
*/
|
||||
void SAColorGridWidget::setSpacing(int v)
|
||||
{
|
||||
d_ptr->mGridLayout->setSpacing(v);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 获取颜色的数量
|
||||
* @return
|
||||
*/
|
||||
int SAColorGridWidget::colorCount() const
|
||||
{
|
||||
return d_ptr->mColors.size();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 设置图标 size
|
||||
* @return
|
||||
*/
|
||||
void SAColorGridWidget::setColorIconSize(const QSize& s)
|
||||
{
|
||||
d_ptr->mIconSize = s;
|
||||
setMinimumHeight(s.height());
|
||||
setMinimumWidth(s.width());
|
||||
d_ptr->updateGridColorSize();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 获取图标 size
|
||||
* @return
|
||||
*/
|
||||
QSize SAColorGridWidget::colorIconSize() const
|
||||
{
|
||||
return d_ptr->mIconSize;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 设置颜色是否是checkable
|
||||
*
|
||||
* checkable的颜色按钮是可checked的
|
||||
* @param on
|
||||
*/
|
||||
void SAColorGridWidget::setColorCheckable(bool on)
|
||||
{
|
||||
d_ptr->mColorCheckable = on;
|
||||
d_ptr->updateGridColorCheckable();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 颜色是否是checkable
|
||||
* @return
|
||||
*/
|
||||
bool SAColorGridWidget::isColorCheckable() const
|
||||
{
|
||||
return d_ptr->mColorCheckable;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 获取当前选中的颜色
|
||||
* @return
|
||||
*/
|
||||
QColor SAColorGridWidget::currentCheckedColor() const
|
||||
{
|
||||
QAbstractButton* btn = d_ptr->mButtonGroup->checkedButton();
|
||||
if (nullptr == btn) {
|
||||
return QColor();
|
||||
}
|
||||
SAColorToolButton* t = qobject_cast< SAColorToolButton* >(btn);
|
||||
if (nullptr == t) {
|
||||
return QColor();
|
||||
}
|
||||
return t->color();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 获取index对应的colorbutton
|
||||
* @param index
|
||||
* @return 如果没有返回nullptr
|
||||
*/
|
||||
SAColorToolButton* SAColorGridWidget::colorButton(int index) const
|
||||
{
|
||||
return d_ptr->getColorToolButtonAt(index);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 等同GridLayout的VerticalSpacing属性
|
||||
* @param v
|
||||
*/
|
||||
void SAColorGridWidget::setVerticalSpacing(int v)
|
||||
{
|
||||
d_ptr->mGridLayout->setVerticalSpacing(v);
|
||||
}
|
||||
/**
|
||||
* @brief 等同GridLayout的VerticalSpacing属性
|
||||
* @return
|
||||
*/
|
||||
int SAColorGridWidget::verticalSpacing() const
|
||||
{
|
||||
return d_ptr->mGridLayout->verticalSpacing();
|
||||
}
|
||||
/**
|
||||
* @brief 等同GridLayout的HorizontalSpacing属性
|
||||
* @param v
|
||||
*/
|
||||
void SAColorGridWidget::setHorizontalSpacing(int v)
|
||||
{
|
||||
d_ptr->mGridLayout->setHorizontalSpacing(v);
|
||||
}
|
||||
/**
|
||||
* @brief 等同GridLayout的HorizontalSpacing属性
|
||||
* @return
|
||||
*/
|
||||
int SAColorGridWidget::horizontalSpacing() const
|
||||
{
|
||||
return d_ptr->mGridLayout->horizontalSpacing();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 清除选中状态,这时没有颜色是选中的
|
||||
*/
|
||||
void SAColorGridWidget::clearCheckedState()
|
||||
{
|
||||
if (d_ptr->mButtonGroup->exclusive()) {
|
||||
SAColorToolButton* btn = d_ptr->getCheckedButton();
|
||||
if (btn) {
|
||||
d_ptr->mButtonGroup->setExclusive(false);
|
||||
btn->setChecked(false);
|
||||
d_ptr->mButtonGroup->setExclusive(true);
|
||||
}
|
||||
} else {
|
||||
d_ptr->iterationColorBtns([](SAColorToolButton* btn) {
|
||||
if (btn->isChecked()) {
|
||||
btn->setChecked(false);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
void SAColorGridWidget::iterationColorBtns(SAColorGridWidget::FunColorBtn fn)
|
||||
{
|
||||
d_ptr->iterationColorBtns(fn);
|
||||
}
|
||||
|
||||
void SAColorGridWidget::setRowMinimumHeight(int row, int minSize)
|
||||
{
|
||||
d_ptr->mGridLayout->setRowMinimumHeight(row, minSize);
|
||||
}
|
||||
|
||||
void SAColorGridWidget::setHorizontalSpacerToRight(bool on)
|
||||
{
|
||||
if (on) {
|
||||
QSpacerItem* horizontalSpacer = new QSpacerItem(40, 20, QSizePolicy::Expanding, QSizePolicy::Minimum);
|
||||
d_ptr->mGridLayout->addItem(horizontalSpacer, 0, d_ptr->mColumnCount, 1, 1);
|
||||
} else {
|
||||
d_ptr->removeAt(0, d_ptr->mColumnCount);
|
||||
}
|
||||
d_ptr->mHorizontalSpacerToRight = on;
|
||||
}
|
||||
|
||||
void SAColorGridWidget::onButtonClicked(QAbstractButton* btn)
|
||||
{
|
||||
SAColorToolButton* t = qobject_cast< SAColorToolButton* >(btn);
|
||||
if (t) {
|
||||
Q_EMIT colorClicked(t->color());
|
||||
}
|
||||
}
|
||||
|
||||
void SAColorGridWidget::onButtonPressed(QAbstractButton* btn)
|
||||
{
|
||||
SAColorToolButton* t = qobject_cast< SAColorToolButton* >(btn);
|
||||
if (t) {
|
||||
Q_EMIT colorPressed(t->color());
|
||||
}
|
||||
}
|
||||
|
||||
void SAColorGridWidget::onButtonToggled(QAbstractButton* btn, bool on)
|
||||
{
|
||||
SAColorToolButton* t = qobject_cast< SAColorToolButton* >(btn);
|
||||
if (t) {
|
||||
Q_EMIT colorToggled(t->color(), on);
|
||||
}
|
||||
}
|
||||
|
||||
QSize SAColorGridWidget::sizeHint() const
|
||||
{
|
||||
return d_ptr->mGridLayout->sizeHint();
|
||||
// int w = d_ptr->mIconSize.width() + d_ptr->mGridLayout->verticalSpacing();
|
||||
// int h = d_ptr->mIconSize.height();
|
||||
// if (d_ptr->mColumnCount > 0) {
|
||||
// h *= d_ptr->mColumnCount;
|
||||
// if (!d_ptr->mColors.empty()) {
|
||||
// int r = std::ceil(d_ptr->mColors.size() / (float)(d_ptr->mColumnCount));
|
||||
// if (r > 0) {
|
||||
// w *= r;
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// return QSize(w, h);
|
||||
}
|
||||
|
||||
void SAColorGridWidget::onButtonReleased(QAbstractButton* btn)
|
||||
{
|
||||
SAColorToolButton* t = qobject_cast< SAColorToolButton* >(btn);
|
||||
if (t) {
|
||||
Q_EMIT colorReleased(t->color());
|
||||
}
|
||||
}
|
||||
|
||||
namespace SA
|
||||
{
|
||||
|
||||
QList< QColor > getStandardColorList()
|
||||
{
|
||||
static QList< QColor > s_standardColorList({ QColor(192, 0, 0),
|
||||
QColor(255, 0, 0),
|
||||
QColor(255, 192, 0),
|
||||
QColor(255, 255, 0),
|
||||
QColor(146, 208, 80),
|
||||
QColor(0, 176, 80),
|
||||
QColor(0, 176, 240),
|
||||
QColor(0, 112, 192),
|
||||
QColor(0, 32, 96),
|
||||
QColor(112, 48, 160) });
|
||||
return s_standardColorList;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,93 @@
|
||||
#ifndef SACOLORGRIDWIDGET_H
|
||||
#define SACOLORGRIDWIDGET_H
|
||||
#include <QWidget>
|
||||
#include <functional>
|
||||
#include "SAColorWidgetsGlobal.h"
|
||||
class QAbstractButton;
|
||||
class SAColorToolButton;
|
||||
/**
|
||||
* @brief 一个grid的Color布局
|
||||
*
|
||||
* 一个形如下面的颜色grid:
|
||||
*
|
||||
* □□□□□□□□□
|
||||
*
|
||||
* □□□□□□□□□
|
||||
*
|
||||
* □□□□□□□□□
|
||||
*/
|
||||
class SA_COLOR_WIDGETS_API SAColorGridWidget : public QWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
SA_COLOR_WIDGETS_DECLARE_PRIVATE(SAColorGridWidget)
|
||||
Q_PROPERTY(int spacing READ spacing WRITE setSpacing)
|
||||
public:
|
||||
using FunColorBtn = std::function< void(SAColorToolButton*) >;
|
||||
|
||||
public:
|
||||
SAColorGridWidget(QWidget* par = nullptr);
|
||||
~SAColorGridWidget();
|
||||
// 设置列数,行数量会根据列数量来匹配,如果设置-1或者0,说明不限定列数量,这样会只有一行
|
||||
void setColumnCount(int c);
|
||||
int columnCount() const;
|
||||
// 设置当前的颜色列表
|
||||
void setColorList(const QList< QColor >& cls);
|
||||
QList< QColor > getColorList() const;
|
||||
// 间隔
|
||||
int spacing() const;
|
||||
void setSpacing(int v);
|
||||
// 获取颜色的数量
|
||||
int colorCount() const;
|
||||
// 图标的尺寸
|
||||
void setColorIconSize(const QSize& s);
|
||||
QSize colorIconSize() const;
|
||||
// 设置颜色是否是checkable
|
||||
void setColorCheckable(bool on = true);
|
||||
bool isColorCheckable() const;
|
||||
// 获取当前选中的颜色
|
||||
QColor currentCheckedColor() const;
|
||||
// 获取index对于的colorbutton
|
||||
SAColorToolButton* colorButton(int index) const;
|
||||
// 垂直间距
|
||||
void setVerticalSpacing(int v);
|
||||
int verticalSpacing() const;
|
||||
// 水平间距
|
||||
void setHorizontalSpacing(int v);
|
||||
int horizontalSpacing() const;
|
||||
// 清除当前选中状态,这时没有颜色是选中的
|
||||
void clearCheckedState();
|
||||
// 对所有的colorbtn就行遍历处理,可以通过此函数进行tooltip设置等操作
|
||||
void iterationColorBtns(FunColorBtn fn);
|
||||
// 设置行最小高度
|
||||
void setRowMinimumHeight(int row, int minSize);
|
||||
// 让颜色块左对齐
|
||||
void setHorizontalSpacerToRight(bool on = true);
|
||||
private Q_SLOTS:
|
||||
void onButtonClicked(QAbstractButton* btn);
|
||||
void onButtonPressed(QAbstractButton* btn);
|
||||
void onButtonReleased(QAbstractButton* btn);
|
||||
void onButtonToggled(QAbstractButton* btn, bool on);
|
||||
|
||||
Q_SIGNALS:
|
||||
/**
|
||||
* @brief 对于check模式,check的颜色触发的信号
|
||||
* @param c
|
||||
* @param on
|
||||
*/
|
||||
void colorClicked(const QColor& c);
|
||||
void colorPressed(const QColor& c);
|
||||
void colorReleased(const QColor& c);
|
||||
void colorToggled(const QColor& c, bool on);
|
||||
|
||||
public:
|
||||
virtual QSize sizeHint() const Q_DECL_OVERRIDE;
|
||||
};
|
||||
namespace SA
|
||||
{
|
||||
/**
|
||||
* @brief 获取标准色列表(一共10种颜色)
|
||||
* @return
|
||||
*/
|
||||
SA_COLOR_WIDGETS_API QList< QColor > getStandardColorList();
|
||||
}
|
||||
#endif // SACOLORGRIDWIDGET_H
|
||||
@@ -0,0 +1,260 @@
|
||||
#include "SAColorMenu.h"
|
||||
#include <QWidgetAction>
|
||||
#include <QColorDialog>
|
||||
#include <QDebug>
|
||||
#include <QLabel>
|
||||
#include <QGridLayout>
|
||||
#include <QPainter>
|
||||
#include "SAColorGridWidget.h"
|
||||
#include "SAColorPaletteGridWidget.h"
|
||||
#include "SAColorToolButton.h"
|
||||
class SAColorMenu::PrivateData
|
||||
{
|
||||
SA_COLOR_WIDGETS_DECLARE_PUBLIC(SAColorMenu)
|
||||
public:
|
||||
PrivateData(SAColorMenu* p);
|
||||
QColor getColorByDialog();
|
||||
void recordCustomColor(const QColor& c);
|
||||
QWidgetAction* addWidget(QWidget* w);
|
||||
//创建一个无颜色的icon
|
||||
QIcon createNoneColorIcon(QSize baseSize = QSize(32, 32));
|
||||
|
||||
public:
|
||||
QLabel* mTitleLabel { nullptr }; ///< 主题颜色标题
|
||||
QWidgetAction* mTitleLabelAction { nullptr };
|
||||
SAColorPaletteGridWidget* mThemeColorsWidget { nullptr }; ///< 主题颜色
|
||||
QWidgetAction* mThemeColorPaletteAction { nullptr }; ///< ThemeColorsPalette对应的action
|
||||
QAction* mCustomColorAction { nullptr }; ///< 自定义颜色action
|
||||
SAColorGridWidget* mCustomColorsWidget { nullptr }; ///< 自定义颜色记录
|
||||
QWidgetAction* mCustomColorsWidgetAction { nullptr }; ///< 自定义颜色窗口对应的action
|
||||
QAction* mNoneColorAction { nullptr }; ///< 无颜色action
|
||||
QList< QColor > mCustomColors;
|
||||
int mMaxCustomColorSize { 10 }; ///< 记录最多的自定义颜色数量
|
||||
QScopedPointer< QColorDialog > mColorDlg { nullptr }; ///<颜色对话框
|
||||
};
|
||||
|
||||
SAColorMenu::PrivateData::PrivateData(SAColorMenu* p) : q_ptr(p)
|
||||
{
|
||||
}
|
||||
|
||||
QColor SAColorMenu::PrivateData::getColorByDialog()
|
||||
{
|
||||
if (nullptr == mColorDlg) {
|
||||
mColorDlg.reset(new QColorDialog());
|
||||
}
|
||||
if (QDialog::Accepted == mColorDlg->exec()) {
|
||||
return mColorDlg->currentColor();
|
||||
}
|
||||
return QColor();
|
||||
}
|
||||
|
||||
void SAColorMenu::PrivateData::recordCustomColor(const QColor& c)
|
||||
{
|
||||
if (mCustomColors.size() < mMaxCustomColorSize) {
|
||||
mCustomColors.push_back(c);
|
||||
} else {
|
||||
//超过数量,就左移动
|
||||
for (int i = 1; i < mCustomColors.size(); ++i) {
|
||||
mCustomColors[ i - 1 ] = mCustomColors[ i ];
|
||||
}
|
||||
mCustomColors.back() = c;
|
||||
}
|
||||
}
|
||||
|
||||
QWidgetAction* SAColorMenu::PrivateData::addWidget(QWidget* w)
|
||||
{
|
||||
QWidgetAction* wa = new QWidgetAction(q_ptr);
|
||||
wa->setDefaultWidget(w);
|
||||
q_ptr->addAction(wa);
|
||||
return wa;
|
||||
}
|
||||
|
||||
QIcon SAColorMenu::PrivateData::createNoneColorIcon(QSize baseSize)
|
||||
{
|
||||
QPixmap pixmap(baseSize);
|
||||
pixmap.fill(Qt::transparent);
|
||||
QPainter p(&pixmap);
|
||||
SAColorToolButton::paintNoneColor(&p, QRect(0, 0, pixmap.width(), pixmap.height()).adjusted(1, 1, -1, -1));
|
||||
return QIcon(pixmap);
|
||||
}
|
||||
//===================================================
|
||||
// SAColorMenu
|
||||
//===================================================
|
||||
|
||||
SAColorMenu::SAColorMenu(QWidget* parent) : QMenu(parent), d_ptr(new SAColorMenu::PrivateData(this))
|
||||
{
|
||||
init(SA::getStandardColorList());
|
||||
}
|
||||
|
||||
SAColorMenu::SAColorMenu(const QString& title, QWidget* parent)
|
||||
: QMenu(title, parent), d_ptr(new SAColorMenu::PrivateData(this))
|
||||
{
|
||||
init(SA::getStandardColorList());
|
||||
}
|
||||
|
||||
SAColorMenu::~SAColorMenu()
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 快速绑定ColorToolButton
|
||||
* @param btn
|
||||
*/
|
||||
void SAColorMenu::bindToColorToolButton(SAColorToolButton* btn)
|
||||
{
|
||||
if (!btn) {
|
||||
return;
|
||||
}
|
||||
if (btn->menu() != this) {
|
||||
btn->setMenu(this);
|
||||
}
|
||||
connect(this, &SAColorMenu::selectedColor, btn, &SAColorToolButton::setColor);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief ThemeColorsPalette对应的action
|
||||
* @return
|
||||
*/
|
||||
QWidgetAction* SAColorMenu::themeColorsPaletteAction() const
|
||||
{
|
||||
return d_ptr->mThemeColorPaletteAction;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief CustomColorsWidget对应的action
|
||||
* @return
|
||||
*/
|
||||
QWidgetAction* SAColorMenu::getCustomColorsWidgetAction() const
|
||||
{
|
||||
return d_ptr->mCustomColorsWidgetAction;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 自定义颜色action
|
||||
* @return
|
||||
*/
|
||||
QAction* SAColorMenu::customColorAction() const
|
||||
{
|
||||
return d_ptr->mCustomColorAction;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 获取ThemeColorsPalette
|
||||
* @return
|
||||
*/
|
||||
SAColorPaletteGridWidget* SAColorMenu::colorPaletteGridWidget() const
|
||||
{
|
||||
return d_ptr->mThemeColorsWidget;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 获取自定义颜色grid
|
||||
* @return
|
||||
*/
|
||||
SAColorGridWidget* SAColorMenu::customColorsWidget() const
|
||||
{
|
||||
return d_ptr->mCustomColorsWidget;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 建立没有颜色的action,可以选择无颜色
|
||||
*
|
||||
* 无颜色选中会发射selectedColor(QColor())
|
||||
* @param on
|
||||
*/
|
||||
void SAColorMenu::enableNoneColorAction(bool on)
|
||||
{
|
||||
//无颜色默认是在自定义颜色的上方
|
||||
if (on) {
|
||||
if (d_ptr->mNoneColorAction) {
|
||||
if (actions().contains(d_ptr->mNoneColorAction)) {
|
||||
//已经包含了NoneColorAction,退出
|
||||
return;
|
||||
} else {
|
||||
insertAction(d_ptr->mCustomColorAction, d_ptr->mNoneColorAction);
|
||||
}
|
||||
} else {
|
||||
QIcon ic = d_ptr->createNoneColorIcon();
|
||||
d_ptr->mNoneColorAction = new QAction(ic, tr("None"), this);
|
||||
connect(d_ptr->mNoneColorAction, &QAction::triggered, this, &SAColorMenu::onNoneColorActionTriggered);
|
||||
insertAction(d_ptr->mCustomColorAction, d_ptr->mNoneColorAction);
|
||||
}
|
||||
} else {
|
||||
removeAction(d_ptr->mNoneColorAction);
|
||||
// remove后暂时不删除action
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 获取None Color Action
|
||||
*
|
||||
* @note 注意,enableNoneColorAction(true),之后才不是nullptr
|
||||
* @return 如果没有建立NoneColorAction,会返回nullptr
|
||||
*/
|
||||
QAction* SAColorMenu::noneColorAction() const
|
||||
{
|
||||
return d_ptr->mNoneColorAction;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 这是一个辅助槽函数,为了让用户自定义的其他action也能关联menu,可以调用此槽函数,实现selectedColor信号以及menu的隐藏
|
||||
* @param c
|
||||
*/
|
||||
void SAColorMenu::emitSelectedColor(const QColor& c)
|
||||
{
|
||||
Q_EMIT selectedColor(c);
|
||||
hide();
|
||||
}
|
||||
|
||||
void SAColorMenu::init(const QList< QColor >& themeCls)
|
||||
{
|
||||
d_ptr->mTitleLabel = new QLabel(this);
|
||||
d_ptr->mTitleLabel->setText(tr("Theme Colors"));
|
||||
d_ptr->mTitleLabelAction = d_ptr->addWidget(d_ptr->mTitleLabel);
|
||||
|
||||
d_ptr->mThemeColorsWidget = new SAColorPaletteGridWidget(themeCls, this);
|
||||
d_ptr->mThemeColorsWidget->setColorCheckable(false);
|
||||
d_ptr->mThemeColorPaletteAction = d_ptr->addWidget(d_ptr->mThemeColorsWidget);
|
||||
|
||||
d_ptr->mCustomColorAction = new QAction(tr("Custom Color"), this); // cn:自定义颜色
|
||||
addAction(d_ptr->mCustomColorAction);
|
||||
|
||||
QSize clrSize = d_ptr->mThemeColorsWidget->colorIconSize();
|
||||
d_ptr->mCustomColorsWidget = new SAColorGridWidget(this);
|
||||
d_ptr->mCustomColorsWidget->setRowMinimumHeight(0, clrSize.height());
|
||||
d_ptr->mCustomColorsWidget->setHorizontalSpacerToRight();
|
||||
d_ptr->mCustomColorsWidget->setColorIconSize(clrSize);
|
||||
d_ptr->mCustomColorsWidget->setColumnCount(d_ptr->mMaxCustomColorSize);
|
||||
d_ptr->mCustomColorsWidget->setColorCheckable(false);
|
||||
d_ptr->mCustomColorsWidgetAction = d_ptr->addWidget(d_ptr->mCustomColorsWidget);
|
||||
|
||||
connect(d_ptr->mCustomColorAction, &QAction::triggered, this, &SAColorMenu::onCustomColorActionTriggered);
|
||||
connect(d_ptr->mThemeColorsWidget, &SAColorPaletteGridWidget::colorClicked, this, &SAColorMenu::emitSelectedColor);
|
||||
connect(d_ptr->mCustomColorsWidget, &SAColorGridWidget::colorClicked, this, &SAColorMenu::emitSelectedColor);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 自定义颜色
|
||||
* @param on
|
||||
*/
|
||||
void SAColorMenu::onCustomColorActionTriggered(bool on)
|
||||
{
|
||||
Q_UNUSED(on);
|
||||
QColor c = d_ptr->getColorByDialog();
|
||||
if (c.isValid()) {
|
||||
d_ptr->recordCustomColor(c);
|
||||
d_ptr->mCustomColorsWidget->setColorList(d_ptr->mCustomColors);
|
||||
updateGeometry();
|
||||
emitSelectedColor(c);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 无颜色
|
||||
* @param on
|
||||
*/
|
||||
void SAColorMenu::onNoneColorActionTriggered(bool on)
|
||||
{
|
||||
Q_UNUSED(on);
|
||||
emitSelectedColor(QColor());
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
#ifndef SACOLORMENU_H
|
||||
#define SACOLORMENU_H
|
||||
#include <QMenu>
|
||||
#include "SAColorWidgetsGlobal.h"
|
||||
class QWidgetAction;
|
||||
class SAColorPaletteGridWidget;
|
||||
class SAColorGridWidget;
|
||||
class SAColorToolButton;
|
||||
/**
|
||||
* @brief 标准颜色菜单
|
||||
*/
|
||||
class SA_COLOR_WIDGETS_API SAColorMenu : public QMenu
|
||||
{
|
||||
Q_OBJECT
|
||||
SA_COLOR_WIDGETS_DECLARE_PRIVATE(SAColorMenu)
|
||||
public:
|
||||
explicit SAColorMenu(QWidget* parent = nullptr);
|
||||
explicit SAColorMenu(const QString& title, QWidget* parent = nullptr);
|
||||
~SAColorMenu();
|
||||
// 快速绑定colorbtn
|
||||
void bindToColorToolButton(SAColorToolButton* btn);
|
||||
// ThemeColorsPalette对应的action
|
||||
QWidgetAction* themeColorsPaletteAction() const;
|
||||
// CustomColorsWidget对应的action
|
||||
QWidgetAction* getCustomColorsWidgetAction() const;
|
||||
// 自定义颜色action
|
||||
QAction* customColorAction() const;
|
||||
// 获取ThemeColorsPalette
|
||||
SAColorPaletteGridWidget* colorPaletteGridWidget() const;
|
||||
// 获取自定义颜色grid
|
||||
SAColorGridWidget* customColorsWidget() const;
|
||||
// 构建无颜色action,默认无颜色action是没有的
|
||||
void enableNoneColorAction(bool on = true);
|
||||
// 获取None Color Action,注意,enableNoneColorAction(true),之后才不是nullptr
|
||||
QAction* noneColorAction() const;
|
||||
public Q_SLOTS:
|
||||
// 这是一个辅助槽函数,为了让用户自定义的其他action也能关联menu,可以调用此槽函数,实现selectedColor信号以及menu的隐藏
|
||||
void emitSelectedColor(const QColor& c);
|
||||
Q_SIGNALS:
|
||||
/**
|
||||
* @brief 选择了颜色触发的信号
|
||||
* @param c
|
||||
*/
|
||||
void selectedColor(const QColor& c);
|
||||
private Q_SLOTS:
|
||||
void onCustomColorActionTriggered(bool on);
|
||||
void onNoneColorActionTriggered(bool on);
|
||||
|
||||
private:
|
||||
void init(const QList< QColor >& themeCls);
|
||||
};
|
||||
|
||||
#endif // SACOLORMENU_H
|
||||
@@ -0,0 +1,171 @@
|
||||
#include "SAColorPaletteGridWidget.h"
|
||||
// Qt
|
||||
#include <QMenu>
|
||||
#include <QWidgetAction>
|
||||
#include <QVBoxLayout>
|
||||
#include <QColorDialog>
|
||||
// SA
|
||||
#include "SAColorGridWidget.h"
|
||||
class SAColorPaletteGridWidget::PrivateData
|
||||
{
|
||||
SA_COLOR_WIDGETS_DECLARE_PUBLIC(SAColorPaletteGridWidget)
|
||||
public:
|
||||
PrivateData(SAColorPaletteGridWidget* p);
|
||||
//生成color palette
|
||||
QList< QColor > makeColorPalette(const QList< QColor >& clrList) const;
|
||||
|
||||
public:
|
||||
QList< int > mFactor { 180, 160, 140, 75, 50 }; ///< palette的比例因子,将调用QColor的lighter函数执行
|
||||
QVBoxLayout* mLayout { nullptr }; ///< 垂直布局
|
||||
SAColorGridWidget* mMainColorList { nullptr }; ///< 这个用于显示标准颜色
|
||||
SAColorGridWidget* mPaletteColorGrid { nullptr }; ///< 这个用于生成3行亮色,2行暗色的palette
|
||||
};
|
||||
|
||||
SAColorPaletteGridWidget::PrivateData::PrivateData(SAColorPaletteGridWidget* p) : q_ptr(p)
|
||||
{
|
||||
mLayout = new QVBoxLayout(p);
|
||||
p->setLayout(mLayout);
|
||||
mMainColorList = new SAColorGridWidget(p);
|
||||
mPaletteColorGrid = new SAColorGridWidget(p);
|
||||
mLayout->addWidget(mMainColorList);
|
||||
mLayout->addWidget(mPaletteColorGrid);
|
||||
mLayout->setContentsMargins(1, 1, 1, 1);
|
||||
mLayout->setSpacing(8);
|
||||
QSizePolicy sizePolicy(QSizePolicy::Maximum, QSizePolicy::Maximum);
|
||||
mMainColorList->setSizePolicy(sizePolicy);
|
||||
mPaletteColorGrid->setSizePolicy(sizePolicy);
|
||||
mMainColorList->setColumnCount(0);
|
||||
mPaletteColorGrid->setVerticalSpacing(0);
|
||||
}
|
||||
|
||||
QList< QColor > SAColorPaletteGridWidget::PrivateData::makeColorPalette(const QList< QColor >& clrList) const
|
||||
{
|
||||
QList< QColor > res;
|
||||
for (int f : qAsConst(mFactor)) {
|
||||
for (const QColor& c : qAsConst(clrList)) {
|
||||
res.append(c.lighter(f));
|
||||
}
|
||||
}
|
||||
return res;
|
||||
}
|
||||
//==============================================================
|
||||
// name
|
||||
//==============================================================
|
||||
|
||||
/**
|
||||
* @brief 使用默认的标准颜色生成一个color palette
|
||||
* @param par
|
||||
*/
|
||||
SAColorPaletteGridWidget::SAColorPaletteGridWidget(QWidget* par) : QWidget(par), d_ptr(new PrivateData(this))
|
||||
{
|
||||
init();
|
||||
setColorList(SA::getStandardColorList());
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 根据指定的颜色生成一个color palette
|
||||
* @param cls
|
||||
* @param par
|
||||
*/
|
||||
SAColorPaletteGridWidget::SAColorPaletteGridWidget(const QList< QColor >& cls, QWidget* par)
|
||||
: QWidget(par), d_ptr(new PrivateData(this))
|
||||
{
|
||||
init();
|
||||
setColorList(cls);
|
||||
}
|
||||
|
||||
SAColorPaletteGridWidget::~SAColorPaletteGridWidget()
|
||||
{
|
||||
}
|
||||
void SAColorPaletteGridWidget::init()
|
||||
{
|
||||
connect(d_ptr->mMainColorList, &SAColorGridWidget::colorClicked, this, &SAColorPaletteGridWidget::onMainColorClicked);
|
||||
connect(d_ptr->mPaletteColorGrid, &SAColorGridWidget::colorClicked, this, &SAColorPaletteGridWidget::onPaletteColorClicked);
|
||||
QSizePolicy sizePolicy(QSizePolicy::Maximum, QSizePolicy::Maximum);
|
||||
setSizePolicy(sizePolicy);
|
||||
setColorIconSize(QSize(10, 10));
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 设置颜色系列,颜色系列的个数决定了主色卡的数量,palette色卡会根据factor进行生成
|
||||
* @param cls
|
||||
*/
|
||||
void SAColorPaletteGridWidget::setColorList(const QList< QColor >& cls)
|
||||
{
|
||||
d_ptr->mMainColorList->setColumnCount(0);
|
||||
d_ptr->mMainColorList->setColorList(cls);
|
||||
d_ptr->mPaletteColorGrid->setColumnCount(cls.size());
|
||||
d_ptr->mPaletteColorGrid->setColorList(d_ptr->makeColorPalette(cls));
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 获取颜色系列
|
||||
* @return
|
||||
*/
|
||||
QList< QColor > SAColorPaletteGridWidget::colorList() const
|
||||
{
|
||||
return d_ptr->mMainColorList->getColorList();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 设置颜色深浅比例factor,factor决定了palette的行数,factor有5个,就有5行
|
||||
*
|
||||
* 默认为{ 180, 160, 140, 75, 50 },相当于会有5行,每个系数会对标准颜色执行QColor::lighter操作
|
||||
* @param factor
|
||||
*/
|
||||
void SAColorPaletteGridWidget::setFactor(const QList< int >& factor)
|
||||
{
|
||||
d_ptr->mFactor = factor;
|
||||
d_ptr->mPaletteColorGrid->setColorList(d_ptr->makeColorPalette(d_ptr->mMainColorList->getColorList()));
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 获取色卡
|
||||
* @return
|
||||
*/
|
||||
QList< int > SAColorPaletteGridWidget::factor() const
|
||||
{
|
||||
return d_ptr->mFactor;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 设置颜色块的尺寸,默认为10*10
|
||||
* @param s
|
||||
*/
|
||||
void SAColorPaletteGridWidget::setColorIconSize(const QSize& s)
|
||||
{
|
||||
d_ptr->mMainColorList->setColorIconSize(s);
|
||||
d_ptr->mPaletteColorGrid->setColorIconSize(s);
|
||||
}
|
||||
|
||||
QSize SAColorPaletteGridWidget::colorIconSize() const
|
||||
{
|
||||
return d_ptr->mMainColorList->colorIconSize();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 设置颜色块是否能被checked
|
||||
* @param on
|
||||
*/
|
||||
void SAColorPaletteGridWidget::setColorCheckable(bool on)
|
||||
{
|
||||
d_ptr->mMainColorList->setColorCheckable(on);
|
||||
d_ptr->mPaletteColorGrid->setColorCheckable(on);
|
||||
}
|
||||
|
||||
bool SAColorPaletteGridWidget::isColorCheckable() const
|
||||
{
|
||||
return d_ptr->mMainColorList->isColorCheckable();
|
||||
}
|
||||
|
||||
void SAColorPaletteGridWidget::onMainColorClicked(const QColor& c)
|
||||
{
|
||||
d_ptr->mPaletteColorGrid->clearCheckedState();
|
||||
Q_EMIT colorClicked(c);
|
||||
}
|
||||
|
||||
void SAColorPaletteGridWidget::onPaletteColorClicked(const QColor& c)
|
||||
{
|
||||
d_ptr->mMainColorList->clearCheckedState();
|
||||
Q_EMIT colorClicked(c);
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
#ifndef SACOLORPALETTEGRIDWIDGET_H
|
||||
#define SACOLORPALETTEGRIDWIDGET_H
|
||||
#include <QWidget>
|
||||
#include "SAColorWidgetsGlobal.h"
|
||||
class QMenu;
|
||||
class SAColorToolButton;
|
||||
/**
|
||||
* @brief 类似office的颜色选择窗口,有一排标准色,下面有一个颜色板,有3行浅色,有2行深色
|
||||
*/
|
||||
class SA_COLOR_WIDGETS_API SAColorPaletteGridWidget : public QWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
SA_COLOR_WIDGETS_DECLARE_PRIVATE(SAColorPaletteGridWidget)
|
||||
public:
|
||||
SAColorPaletteGridWidget(QWidget* par = nullptr);
|
||||
SAColorPaletteGridWidget(const QList< QColor >& cls, QWidget* par = nullptr);
|
||||
~SAColorPaletteGridWidget();
|
||||
// 设置窗口维护的colorList
|
||||
void setColorList(const QList< QColor >& cls);
|
||||
QList< QColor > colorList() const;
|
||||
// 设置颜色深浅比例factor,默认为{ 180, 160, 140, 75, 50 }
|
||||
void setFactor(const QList< int >& factor);
|
||||
QList< int > factor() const;
|
||||
// 设置iconsize
|
||||
void setColorIconSize(const QSize& s);
|
||||
QSize colorIconSize() const;
|
||||
// 设置颜色是否是checkable
|
||||
void setColorCheckable(bool on = true);
|
||||
bool isColorCheckable() const;
|
||||
private Q_SLOTS:
|
||||
void onMainColorClicked(const QColor& c);
|
||||
void onPaletteColorClicked(const QColor& c);
|
||||
|
||||
private:
|
||||
void init();
|
||||
Q_SIGNALS:
|
||||
/**
|
||||
* @brief 对于check模式,check的颜色触发的信号
|
||||
* @param c
|
||||
* @param on
|
||||
*/
|
||||
void colorClicked(const QColor& c);
|
||||
};
|
||||
|
||||
#endif // SACOLORPALETTEGRIDWIDGET_H
|
||||
@@ -0,0 +1,631 @@
|
||||
#include "SAColorToolButton.h"
|
||||
#include <QApplication>
|
||||
#include <QPaintEvent>
|
||||
#include <QStylePainter>
|
||||
#include <QStyleOption>
|
||||
#include <QStyleOptionToolButton>
|
||||
#include <QResizeEvent>
|
||||
#include <QDebug>
|
||||
#include "SAColorMenu.h"
|
||||
|
||||
#define SAColorToolButton_DEBUG_PRINT 0
|
||||
class SAColorToolButton::PrivateData
|
||||
{
|
||||
SA_COLOR_WIDGETS_DECLARE_PUBLIC(SAColorToolButton)
|
||||
public:
|
||||
PrivateData(SAColorToolButton* p);
|
||||
void calcSizeOfToolButtonIconOnly(const QStyleOptionToolButton& opt, QRect& iconRect, QRect& textRect, QRect& colorRect);
|
||||
void calcSizeOfToolButtonTextOnly(const QStyleOptionToolButton& opt, QRect& iconRect, QRect& textRect, QRect& colorRect);
|
||||
void calcSizeOfToolButtonTextBesideIcon(const QStyleOptionToolButton& opt, QRect& iconRect, QRect& textRect, QRect& colorRect);
|
||||
void calcSizeOfToolButtonTextUnderIcon(const QStyleOptionToolButton& opt, QRect& iconRect, QRect& textRect, QRect& colorRect);
|
||||
QPixmap createIconPixmap(const QStyleOptionToolButton& opt, const QRect& iconRect);
|
||||
QRect getButtonRect(const QStyleOptionToolButton& opt);
|
||||
QRect getIndicatorRect(const QStyleOptionToolButton& opt);
|
||||
QStyle::State getButtonStyleState(const QStyleOptionToolButton& opt);
|
||||
QStyle::State getButtonMenuStyleState(const QStyleOptionToolButton& opt);
|
||||
void removeMenu();
|
||||
|
||||
public:
|
||||
QColor mColor { Qt::white };
|
||||
int mSpacing { 2 }; ///< 间隔
|
||||
QMargins mMargins { 3, 3, 3, 3 }; ///< box
|
||||
ColorToolButtonStyle mColorButtonStyle { WithColorMenu }; ///< 样式
|
||||
static int s_indicatorArrorWidth; ///< 菜单宽度
|
||||
};
|
||||
|
||||
int SAColorToolButton::PrivateData::s_indicatorArrorWidth = 8;
|
||||
|
||||
SAColorToolButton::PrivateData::PrivateData(SAColorToolButton* p) : q_ptr(p)
|
||||
{
|
||||
}
|
||||
|
||||
void SAColorToolButton::PrivateData::calcSizeOfToolButtonIconOnly(const QStyleOptionToolButton& opt,
|
||||
QRect& iconRect,
|
||||
QRect& textRect,
|
||||
QRect& colorRect)
|
||||
{
|
||||
// 确定文本区域
|
||||
textRect = QRect();
|
||||
QRect buttonRect = getButtonRect(opt);
|
||||
if (opt.icon.isNull()) {
|
||||
colorRect = buttonRect;
|
||||
iconRect = QRect();
|
||||
} else {
|
||||
QSize tmpSize = opt.iconSize;
|
||||
if (tmpSize.isNull()) {
|
||||
tmpSize = QSize(16, 16);
|
||||
}
|
||||
tmpSize = buttonRect.size().boundedTo(tmpSize);
|
||||
int colorHeight = tmpSize.height() / 4;
|
||||
int totalHeight = colorHeight + tmpSize.height() + mSpacing;
|
||||
if (totalHeight > buttonRect.height()) {
|
||||
// 过高,这时要通过高度反推tmpSize和colorHeight
|
||||
colorHeight = (buttonRect.height() - mSpacing) / 5;
|
||||
tmpSize.setHeight(colorHeight * 4);
|
||||
if (opt.iconSize.height() > 0) {
|
||||
tmpSize.setWidth(tmpSize.height() * opt.iconSize.width() / opt.iconSize.height()); // 等比例
|
||||
}
|
||||
tmpSize = buttonRect.size().boundedTo(tmpSize);
|
||||
}
|
||||
// 有icon,颜色位于图标下面
|
||||
int y = (buttonRect.height() - colorHeight - mSpacing - tmpSize.height()) / 2; //(ButtonHeight-TotalHeight)/2
|
||||
int x = (buttonRect.width() - tmpSize.width()) / 2;
|
||||
iconRect = QRect(buttonRect.left() + x, buttonRect.top() + y, tmpSize.width(), tmpSize.height());
|
||||
colorRect = QRect(iconRect.x(), iconRect.bottom() + mSpacing, iconRect.width(), colorHeight);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 纯文本情况,左边有5像素显示颜色
|
||||
* @param opt
|
||||
* @param iconRect
|
||||
* @param textRect
|
||||
* @param colorRect 左边有5像素显示颜色
|
||||
*/
|
||||
void SAColorToolButton::PrivateData::calcSizeOfToolButtonTextOnly(const QStyleOptionToolButton& opt,
|
||||
QRect& iconRect,
|
||||
QRect& textRect,
|
||||
QRect& colorRect)
|
||||
{
|
||||
QRect buttonRect = getButtonRect(opt);
|
||||
iconRect = QRect();
|
||||
QSize colorSize = opt.iconSize;
|
||||
if (colorSize.isNull()) {
|
||||
colorSize = QSize(16, 16);
|
||||
}
|
||||
colorSize = buttonRect.size().boundedTo(colorSize);
|
||||
colorRect = QRect(buttonRect.left(),
|
||||
buttonRect.top() + (buttonRect.height() - colorSize.height()) / 2,
|
||||
colorSize.width(),
|
||||
colorSize.height());
|
||||
textRect = buttonRect.adjusted(colorRect.right() + mSpacing, 0, 0, 0);
|
||||
}
|
||||
|
||||
void SAColorToolButton::PrivateData::calcSizeOfToolButtonTextBesideIcon(const QStyleOptionToolButton& opt,
|
||||
QRect& iconRect,
|
||||
QRect& textRect,
|
||||
QRect& colorRect)
|
||||
{
|
||||
QRect buttonRect = getButtonRect(opt);
|
||||
if (opt.icon.isNull()) {
|
||||
QSize colorSize = opt.iconSize;
|
||||
if (colorSize.isNull()) {
|
||||
colorSize = QSize(16, 16);
|
||||
}
|
||||
// 说明没有icon
|
||||
// 这时所有都是color
|
||||
// iconRect=Null
|
||||
colorSize = buttonRect.size().boundedTo(colorSize);
|
||||
iconRect = QRect();
|
||||
colorRect = QRect(buttonRect.left(),
|
||||
buttonRect.top() + (buttonRect.height() - colorSize.height()) / 2,
|
||||
colorSize.width(),
|
||||
colorSize.height());
|
||||
textRect = buttonRect.adjusted(colorRect.width() + mSpacing, 0, 0, 0);
|
||||
} else { // 有图标
|
||||
QSize tmpSize = opt.iconSize;
|
||||
if (tmpSize.isNull()) {
|
||||
tmpSize = QSize(16, 16);
|
||||
}
|
||||
tmpSize = buttonRect.size().boundedTo(tmpSize);
|
||||
int colorHeight = tmpSize.height() / 4;
|
||||
int totalHeight = colorHeight + tmpSize.height() + mSpacing;
|
||||
if (totalHeight > buttonRect.height()) {
|
||||
// 过高,这时要通过高度反推tmpSize和colorHeight
|
||||
colorHeight = (buttonRect.height() - mSpacing) / 5;
|
||||
tmpSize.setHeight(colorHeight * 4);
|
||||
tmpSize.setWidth(tmpSize.height()); // 对于异形也设置为正方行
|
||||
}
|
||||
// 有icon,颜色位于图标下面
|
||||
int y = (buttonRect.height() - colorHeight - mSpacing - tmpSize.height()) / 2; //(ButtonHeight-TotalHeight)/2
|
||||
iconRect = QRect(buttonRect.left(), buttonRect.top() + y, tmpSize.width(), tmpSize.height());
|
||||
colorRect = QRect(iconRect.x(), iconRect.bottom() + mSpacing, iconRect.width(), colorHeight);
|
||||
textRect = buttonRect.adjusted(iconRect.right() + mSpacing, 0, 0, 0);
|
||||
}
|
||||
}
|
||||
|
||||
void SAColorToolButton::PrivateData::calcSizeOfToolButtonTextUnderIcon(const QStyleOptionToolButton& opt,
|
||||
QRect& iconRect,
|
||||
QRect& textRect,
|
||||
QRect& colorRect)
|
||||
{
|
||||
QRect buttonRect = getButtonRect(opt);
|
||||
QSize tmpSize = opt.iconSize;
|
||||
if (tmpSize.isNull()) {
|
||||
tmpSize = QSize(16, 16);
|
||||
}
|
||||
// 获取字体高度
|
||||
int textHeight = opt.fontMetrics.height();
|
||||
tmpSize = buttonRect.size().boundedTo(tmpSize);
|
||||
if (opt.icon.isNull()) {
|
||||
int totalHeight = textHeight + opt.iconSize.height() + mSpacing;
|
||||
if (totalHeight < buttonRect.height()) {
|
||||
// 足够高
|
||||
colorRect = QRect(buttonRect.left() + (buttonRect.width() - tmpSize.width()) / 2,
|
||||
buttonRect.top() + (buttonRect.height() - totalHeight) / 2,
|
||||
tmpSize.width(),
|
||||
opt.iconSize.height());
|
||||
} else {
|
||||
// 空间不足
|
||||
colorRect = QRect(buttonRect.left() + (buttonRect.width() - tmpSize.width()) / 2,
|
||||
buttonRect.top() + mSpacing,
|
||||
tmpSize.width(),
|
||||
opt.iconSize.height());
|
||||
}
|
||||
iconRect = QRect();
|
||||
textRect = QRect(buttonRect.left(), colorRect.bottom() + mSpacing, buttonRect.width(), textHeight);
|
||||
|
||||
} else {
|
||||
// 有图标
|
||||
int colorHeight = tmpSize.height() / 4;
|
||||
int totalHeight = textHeight + opt.iconSize.height() + colorHeight + 2 * mSpacing;
|
||||
if (totalHeight < buttonRect.height()) {
|
||||
// 高度空间足够
|
||||
// 先布置icon
|
||||
iconRect = QRect(buttonRect.left() + (buttonRect.width() - tmpSize.width()) / 2,
|
||||
buttonRect.top() + (buttonRect.height() - totalHeight) / 2,
|
||||
tmpSize.width(),
|
||||
opt.iconSize.height());
|
||||
|
||||
} else {
|
||||
// 空间不足
|
||||
iconRect = QRect(buttonRect.left() + (buttonRect.width() - tmpSize.width()) / 2,
|
||||
buttonRect.top() + mSpacing,
|
||||
tmpSize.width(),
|
||||
opt.iconSize.height());
|
||||
}
|
||||
colorRect = QRect(iconRect.x(), iconRect.bottom() + mSpacing, iconRect.width(), colorHeight);
|
||||
textRect = QRect(buttonRect.left(), colorRect.bottom() + mSpacing, buttonRect.width(), textHeight);
|
||||
}
|
||||
}
|
||||
|
||||
QPixmap SAColorToolButton::PrivateData::createIconPixmap(const QStyleOptionToolButton& opt, const QRect& iconRect)
|
||||
{
|
||||
if (opt.icon.isNull()) {
|
||||
return (QPixmap());
|
||||
}
|
||||
// 有图标
|
||||
QIcon::State state = opt.state & QStyle::State_On ? QIcon::On : QIcon::Off;
|
||||
QIcon::Mode mode;
|
||||
if (!(opt.state & QStyle::State_Enabled)) {
|
||||
mode = QIcon::Disabled;
|
||||
} else if ((opt.state & QStyle::State_MouseOver) && (opt.state & QStyle::State_AutoRaise)) {
|
||||
mode = QIcon::Active;
|
||||
} else {
|
||||
mode = QIcon::Normal;
|
||||
}
|
||||
// return (opt.icon.pixmap(this->window()->windowHandle(), opt.rect.size().boundedTo(realConSize), mode, state));
|
||||
return (opt.icon.pixmap(iconRect.size(), mode, state));
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 获取按钮的矩形区域
|
||||
* @param opt
|
||||
* @return
|
||||
*/
|
||||
QRect SAColorToolButton::PrivateData::getButtonRect(const QStyleOptionToolButton& opt)
|
||||
{
|
||||
QRect btnRect = q_ptr->style()->subControlRect(QStyle::CC_ToolButton, &opt, QStyle::SC_ToolButton, q_ptr);
|
||||
return btnRect.marginsRemoved(mMargins);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 获取ToolButtonMenu的区域
|
||||
* @note 注意,如果不是QStyleOptionToolButton::MenuButtonPopup|QStyleOptionToolButton::HasMenu下调用此函数,返回的是QRect()
|
||||
* @param opt
|
||||
* @return
|
||||
*/
|
||||
QRect SAColorToolButton::PrivateData::getIndicatorRect(const QStyleOptionToolButton& opt)
|
||||
{
|
||||
if (opt.features & QStyleOptionToolButton::MenuButtonPopup || opt.features & QStyleOptionToolButton::HasMenu) {
|
||||
return q_ptr->style()->subControlRect(QStyle::CC_ToolButton, &opt, QStyle::SC_ToolButtonMenu, q_ptr);
|
||||
}
|
||||
return QRect();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 基于Qt qcommonStyle源码,对QStyleOptionToolButton的style修正
|
||||
* @param opt
|
||||
* @return
|
||||
*/
|
||||
QStyle::State SAColorToolButton::PrivateData::getButtonStyleState(const QStyleOptionToolButton& opt)
|
||||
{
|
||||
QStyle::State bflags = opt.state & ~QStyle::State_Sunken;
|
||||
if (bflags & QStyle::State_AutoRaise) {
|
||||
if (!(bflags & QStyle::State_MouseOver) || !(bflags & QStyle::State_Enabled)) {
|
||||
bflags &= ~QStyle::State_Raised;
|
||||
}
|
||||
}
|
||||
if (opt.state & QStyle::State_Sunken) {
|
||||
if (opt.activeSubControls & QStyle::SC_ToolButton) {
|
||||
bflags |= QStyle::State_Sunken;
|
||||
}
|
||||
}
|
||||
return bflags;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 基于Qt qcommonStyle源码,对QStyleOptionToolButton的style修正
|
||||
* @param opt
|
||||
* @return
|
||||
*/
|
||||
QStyle::State SAColorToolButton::PrivateData::getButtonMenuStyleState(const QStyleOptionToolButton& opt)
|
||||
{
|
||||
QStyle::State mflags = opt.state & ~QStyle::State_Sunken;
|
||||
if (mflags & QStyle::State_AutoRaise) {
|
||||
if (!(mflags & QStyle::State_MouseOver) || !(mflags & QStyle::State_Enabled)) {
|
||||
mflags &= ~QStyle::State_Raised;
|
||||
}
|
||||
}
|
||||
if (opt.state & QStyle::State_Sunken) {
|
||||
mflags |= QStyle::State_Sunken;
|
||||
}
|
||||
return mflags;
|
||||
}
|
||||
|
||||
void SAColorToolButton::PrivateData::removeMenu()
|
||||
{
|
||||
QMenu* m = q_ptr->menu();
|
||||
if (m) {
|
||||
q_ptr->setMenu(nullptr);
|
||||
m->deleteLater();
|
||||
}
|
||||
}
|
||||
|
||||
//==============================================================
|
||||
// SAColorToolButton
|
||||
//==============================================================
|
||||
|
||||
SAColorToolButton::SAColorToolButton(QWidget* parent) : QToolButton(parent), d_ptr(new PrivateData(this))
|
||||
{
|
||||
setColorToolButtonStyle(WithColorMenu);
|
||||
connect(this, &QToolButton::clicked, this, &SAColorToolButton::onButtonClicked);
|
||||
}
|
||||
|
||||
SAColorToolButton::SAColorToolButton(ColorToolButtonStyle style, QWidget* parent)
|
||||
: QToolButton(parent), d_ptr(new PrivateData(this))
|
||||
{
|
||||
setColorToolButtonStyle(style);
|
||||
connect(this, &QToolButton::clicked, this, &SAColorToolButton::onButtonClicked);
|
||||
}
|
||||
|
||||
SAColorToolButton::~SAColorToolButton()
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 获取颜色
|
||||
* @return
|
||||
*/
|
||||
QColor SAColorToolButton::color() const
|
||||
{
|
||||
return d_ptr->mColor;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 设置Margins
|
||||
* @param mg
|
||||
*/
|
||||
void SAColorToolButton::setMargins(const QMargins& mg)
|
||||
{
|
||||
d_ptr->mMargins = mg;
|
||||
repaint();
|
||||
}
|
||||
|
||||
QMargins SAColorToolButton::margins() const
|
||||
{
|
||||
return d_ptr->mMargins;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 绘制无颜色表示
|
||||
* @param p
|
||||
* @param colorRect 绘制的区域
|
||||
*/
|
||||
void SAColorToolButton::paintNoneColor(QPainter* p, const QRect& colorRect)
|
||||
{
|
||||
p->save();
|
||||
QPen pen(Qt::red, 1, Qt::SolidLine, Qt::RoundCap);
|
||||
p->setPen(pen);
|
||||
p->setRenderHint(QPainter::SmoothPixmapTransform, true);
|
||||
p->setRenderHint(QPainter::Antialiasing, true);
|
||||
int ss = colorRect.width() / 3;
|
||||
p->drawLine(QPoint(colorRect.x() + ss, colorRect.bottom()), QPoint(colorRect.right() - ss, colorRect.top()));
|
||||
pen.setColor(Qt::black);
|
||||
p->setPen(pen);
|
||||
p->drawRect(colorRect);
|
||||
p->restore();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 设置颜色按钮的样式
|
||||
* @param s
|
||||
*/
|
||||
void SAColorToolButton::setColorToolButtonStyle(ColorToolButtonStyle s)
|
||||
{
|
||||
if (NoColorMenu == s) {
|
||||
d_ptr->removeMenu();
|
||||
} else {
|
||||
createColorMenu();
|
||||
}
|
||||
d_ptr->mColorButtonStyle = s;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 颜色按钮的样式
|
||||
* @return
|
||||
*/
|
||||
SAColorToolButton::ColorToolButtonStyle SAColorToolButton::colorToolButtonStyle() const
|
||||
{
|
||||
return d_ptr->mColorButtonStyle;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 获取colorMenu
|
||||
*
|
||||
* @note 注意,这个函数很有可能会返回nullptr,如果ColorToolButtonStyle设置为NoColorMenu或者自己设置了菜单,此函数返回nullptr
|
||||
* @return SAColorMenu指针,如果没有,返回nullptr
|
||||
*/
|
||||
SAColorMenu* SAColorToolButton::colorMenu() const
|
||||
{
|
||||
return qobject_cast< SAColorMenu* >(menu());
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 建立标准的颜色菜单
|
||||
* @return
|
||||
*/
|
||||
SAColorMenu* SAColorToolButton::createColorMenu()
|
||||
{
|
||||
setPopupMode(QToolButton::InstantPopup);
|
||||
SAColorMenu* m = new SAColorMenu(this);
|
||||
m->enableNoneColorAction(true);
|
||||
QAction* customColor = m->customColorAction();
|
||||
if (customColor) {
|
||||
customColor->setIcon(QIcon(":/image/resource/define-color.svg"));
|
||||
}
|
||||
connect(m, &SAColorMenu::selectedColor, this, &SAColorToolButton::setColor);
|
||||
setMenu(m);
|
||||
return m;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 设置颜色
|
||||
* @note 会发射@sa colorChanged 信号
|
||||
* @param c
|
||||
*/
|
||||
void SAColorToolButton::setColor(const QColor& c)
|
||||
{
|
||||
if (d_ptr->mColor != c) {
|
||||
d_ptr->mColor = c;
|
||||
repaint();
|
||||
Q_EMIT colorChanged(c);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 计算各个基本组件的位置
|
||||
* @param opt
|
||||
* @param iconRect 图标区域
|
||||
* @param textRect 文本区域
|
||||
* @param colorRect 颜色区域
|
||||
*/
|
||||
void SAColorToolButton::calcRect(const QStyleOptionToolButton& opt, QRect& iconRect, QRect& textRect, QRect& colorRect)
|
||||
{
|
||||
switch (opt.toolButtonStyle) {
|
||||
case Qt::ToolButtonTextOnly:
|
||||
d_ptr->calcSizeOfToolButtonTextOnly(opt, iconRect, textRect, colorRect);
|
||||
break;
|
||||
case Qt::ToolButtonTextBesideIcon:
|
||||
d_ptr->calcSizeOfToolButtonTextBesideIcon(opt, iconRect, textRect, colorRect);
|
||||
break;
|
||||
case Qt::ToolButtonTextUnderIcon:
|
||||
d_ptr->calcSizeOfToolButtonTextUnderIcon(opt, iconRect, textRect, colorRect);
|
||||
break;
|
||||
case Qt::ToolButtonFollowStyle:
|
||||
case Qt::ToolButtonIconOnly:
|
||||
d_ptr->calcSizeOfToolButtonIconOnly(opt, iconRect, textRect, colorRect);
|
||||
break;
|
||||
default:
|
||||
d_ptr->calcSizeOfToolButtonIconOnly(opt, iconRect, textRect, colorRect);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void SAColorToolButton::paintEvent(QPaintEvent* e)
|
||||
{
|
||||
Q_UNUSED(e);
|
||||
QStylePainter p(this);
|
||||
|
||||
QStyleOptionToolButton opt;
|
||||
|
||||
initStyleOption(&opt);
|
||||
QRect iconRect, colorRect, textRect;
|
||||
calcRect(opt, iconRect, textRect, colorRect);
|
||||
paintButton(&p, opt);
|
||||
// 绘制图标
|
||||
paintIcon(&p, iconRect, opt);
|
||||
// 绘制文字
|
||||
paintText(&p, textRect, opt);
|
||||
// 绘制颜色
|
||||
paintColor(&p, colorRect, d_ptr->mColor, opt);
|
||||
}
|
||||
|
||||
void SAColorToolButton::resizeEvent(QResizeEvent* e)
|
||||
{
|
||||
// 在resizeevent计算绘图所需的尺寸,避免在绘图过程中实时绘制提高效率
|
||||
QToolButton::resizeEvent(e);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief sizeHint重载
|
||||
* @return
|
||||
*/
|
||||
QSize SAColorToolButton::sizeHint() const
|
||||
{
|
||||
ensurePolished();
|
||||
QStyleOptionToolButton opt;
|
||||
initStyleOption(&opt);
|
||||
int w = 0, h = 0;
|
||||
if (Qt::ToolButtonIconOnly == opt.toolButtonStyle || Qt::ToolButtonFollowStyle == opt.toolButtonStyle) {
|
||||
// 和文本无关
|
||||
w = opt.iconSize.width() + d_ptr->mMargins.left() + d_ptr->mMargins.right();
|
||||
h = opt.iconSize.height() + d_ptr->mMargins.top() + d_ptr->mMargins.bottom();
|
||||
} else if (Qt::ToolButtonTextOnly == opt.toolButtonStyle || Qt::ToolButtonTextBesideIcon == opt.toolButtonStyle) {
|
||||
QSize textSize = opt.fontMetrics.size(Qt::TextSingleLine | Qt::TextShowMnemonic, opt.text);
|
||||
textSize.setHeight(textSize.height() + 4);
|
||||
QSize iconSize = opt.iconSize;
|
||||
if (!opt.icon.isNull()) {
|
||||
// 有图标,要有iconsize高度的1/4给颜色
|
||||
iconSize.setHeight(iconSize.height() + iconSize.height() / 4 + d_ptr->mSpacing);
|
||||
}
|
||||
w = textSize.width() + d_ptr->mSpacing + iconSize.width() + d_ptr->mMargins.left() + d_ptr->mMargins.right();
|
||||
h = qMax(textSize.height(), iconSize.height()) + d_ptr->mMargins.top() + d_ptr->mMargins.bottom();
|
||||
} else if (Qt::ToolButtonTextUnderIcon == opt.toolButtonStyle) {
|
||||
QSize textSize = opt.fontMetrics.size(Qt::TextSingleLine | Qt::TextShowMnemonic, opt.text);
|
||||
textSize.setHeight(textSize.height() + 4);
|
||||
QSize iconSize = opt.iconSize;
|
||||
if (!opt.icon.isNull()) {
|
||||
// 有图标,要有iconsize高度的1/4给颜色
|
||||
iconSize.setHeight(iconSize.height() + iconSize.height() / 4 + d_ptr->mSpacing);
|
||||
}
|
||||
w = qMax(textSize.width(), iconSize.width()) + d_ptr->mMargins.left() + d_ptr->mMargins.right();
|
||||
h = textSize.height() + iconSize.height() + d_ptr->mSpacing + d_ptr->mMargins.top() + d_ptr->mMargins.bottom();
|
||||
}
|
||||
opt.rect.setSize(QSize(w, h)); // PM_MenuButtonIndicator depends on the height
|
||||
if (opt.features & QStyleOptionToolButton::MenuButtonPopup || opt.features & QStyleOptionToolButton::HasMenu) {
|
||||
w += style()->pixelMetric(QStyle::PM_MenuButtonIndicator, &opt, this);
|
||||
}
|
||||
//! Qt6.4 取消了QApplication::globalStrut
|
||||
return style()->sizeFromContents(QStyle::CT_ToolButton, &opt, QSize(w, h), this).expandedTo(QSize(2, 2));
|
||||
}
|
||||
|
||||
void SAColorToolButton::onButtonClicked(bool checked)
|
||||
{
|
||||
Q_EMIT colorClicked(color(), checked);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 绘制按钮
|
||||
* @param p
|
||||
* @param opt
|
||||
*/
|
||||
void SAColorToolButton::paintButton(QStylePainter* p, const QStyleOptionToolButton& opt)
|
||||
{
|
||||
bool autoRaise = opt.state & QStyle::State_AutoRaise;
|
||||
// 绘制按钮
|
||||
if (autoRaise) {
|
||||
style()->drawPrimitive(QStyle::PE_PanelButtonTool, &opt, p, this);
|
||||
} else {
|
||||
style()->drawPrimitive(QStyle::PE_PanelButtonBevel, &opt, p, this);
|
||||
}
|
||||
if (opt.features & QStyleOptionToolButton::MenuButtonPopup) {
|
||||
QStyleOption tool = opt;
|
||||
tool.state = d_ptr->getButtonMenuStyleState(opt);
|
||||
tool.rect = d_ptr->getIndicatorRect(opt);
|
||||
// if (tool.state & (QStyle::State_Sunken | QStyle::State_On | QStyle::State_Raised)) {
|
||||
// style()->drawPrimitive(QStyle::PE_IndicatorButtonDropDown, &tool, &p, this);
|
||||
// }
|
||||
style()->drawPrimitive(QStyle::PE_IndicatorArrowDown, &tool, p, this);
|
||||
}
|
||||
|
||||
// 绘制focus
|
||||
if (opt.state & QStyle::State_HasFocus) {
|
||||
QStyleOptionFocusRect fr;
|
||||
fr.QStyleOption::operator=(opt);
|
||||
fr.rect.adjust(3, 3, -3, -3);
|
||||
if (opt.features & QStyleOptionToolButton::MenuButtonPopup) {
|
||||
fr.rect.adjust(0, 0, style()->pixelMetric(QStyle::PM_MenuButtonIndicator, &opt, this), 0);
|
||||
}
|
||||
style()->drawPrimitive(QStyle::PE_FrameFocusRect, &fr, p, this);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 绘制icon
|
||||
* @param p
|
||||
* @param iconRect
|
||||
* @param opt icon信息从QStyleOptionToolButton获取
|
||||
*/
|
||||
void SAColorToolButton::paintIcon(QStylePainter* p, const QRect& iconRect, const QStyleOptionToolButton& opt)
|
||||
{
|
||||
if (!iconRect.isNull()) {
|
||||
QPixmap pm = d_ptr->createIconPixmap(opt, iconRect);
|
||||
style()->drawItemPixmap(p, iconRect, Qt::AlignCenter, pm);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 绘制文本
|
||||
* @param p
|
||||
* @param textRect
|
||||
* @param opt
|
||||
*/
|
||||
void SAColorToolButton::paintText(QStylePainter* p, const QRect& textRect, const QStyleOptionToolButton& opt)
|
||||
{
|
||||
if (opt.text.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
if (Qt::ToolButtonIconOnly == opt.toolButtonStyle) {
|
||||
return;
|
||||
}
|
||||
p->save();
|
||||
p->setFont(opt.font);
|
||||
int alignment = Qt::TextShowMnemonic;
|
||||
// 快捷键的下划线
|
||||
if (!style()->styleHint(QStyle::SH_UnderlineShortcut, &opt, this)) {
|
||||
alignment |= Qt::TextHideMnemonic;
|
||||
}
|
||||
alignment |= Qt::AlignHCenter | Qt::AlignVCenter;
|
||||
style()->drawItemText(p,
|
||||
QStyle::visualRect(opt.direction, opt.rect, textRect),
|
||||
alignment,
|
||||
opt.palette,
|
||||
opt.state & QStyle::State_Enabled,
|
||||
opt.text,
|
||||
QPalette::ButtonText);
|
||||
p->restore();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 绘制color
|
||||
* @param p
|
||||
* @param iconRect
|
||||
* @param opt
|
||||
*/
|
||||
void SAColorToolButton::paintColor(QStylePainter* p,
|
||||
const QRect& colorRect,
|
||||
const QColor& color,
|
||||
const QStyleOptionToolButton& opt)
|
||||
{
|
||||
Q_UNUSED(opt);
|
||||
if (colorRect.isNull()) {
|
||||
return;
|
||||
}
|
||||
// 绘制颜色
|
||||
if (color.isValid()) {
|
||||
p->fillRect(colorRect, color);
|
||||
} else {
|
||||
paintNoneColor(p, colorRect);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,105 @@
|
||||
#ifndef SACOLORTOOLBUTTON_H
|
||||
#define SACOLORTOOLBUTTON_H
|
||||
#include <QToolButton>
|
||||
#include "SAColorWidgetsGlobal.h"
|
||||
class QPaintEvent;
|
||||
class QResizeEvent;
|
||||
class QPainter;
|
||||
class QStylePainter;
|
||||
class SAColorMenu;
|
||||
/**
|
||||
* @brief 这是一个只显示颜色的toolbutton
|
||||
*
|
||||
*
|
||||
* 在ToolButtonIconOnly模式下,如果没有setIcon,则颜色占用所有区域,如下图所示
|
||||
*
|
||||
* ┌─────┐
|
||||
* │color│
|
||||
* └─────┘
|
||||
*
|
||||
* 如果在ToolButtonIconOnly模式下有图标,图标在上面显示,下面显示颜色,如下图所示
|
||||
*
|
||||
* ┌─────┐
|
||||
* │icon │
|
||||
* │color│
|
||||
* └─────┘
|
||||
*
|
||||
* 在ToolButtonTextBesideIcon,ToolButtonTextUnderIcon下,setIconSize 可以指定颜色的大小,
|
||||
* 但只在ToolButtonTextBesideIcon,ToolButtonTextUnderIcon下有效
|
||||
*
|
||||
* 如果没有设置图标,也就是setIcon(QIcon()),iconSize作为颜色块的大小
|
||||
*
|
||||
* ┌─────────┐
|
||||
* │┌─┐ │
|
||||
* │└─┘ │
|
||||
* └─────────┘
|
||||
*
|
||||
* 如果有图标,颜色条会在图标下方,为图标高度的1/4 为图标宽度一致,如若超过控件的大小,会自动缩小体积
|
||||
*
|
||||
*/
|
||||
class SA_COLOR_WIDGETS_API SAColorToolButton : public QToolButton
|
||||
{
|
||||
Q_OBJECT
|
||||
SA_COLOR_WIDGETS_DECLARE_PRIVATE(SAColorToolButton)
|
||||
public:
|
||||
/**
|
||||
* @brief 颜色按钮的内置样式
|
||||
* @param parent
|
||||
* @return
|
||||
*/
|
||||
enum ColorToolButtonStyle
|
||||
{
|
||||
WithColorMenu, ///< 默认会构建一个SAColorMenu
|
||||
NoColorMenu ///< 没有ColorMenu
|
||||
};
|
||||
|
||||
public:
|
||||
explicit SAColorToolButton(QWidget* parent = nullptr);
|
||||
explicit SAColorToolButton(ColorToolButtonStyle style, QWidget* parent = nullptr);
|
||||
~SAColorToolButton();
|
||||
// 获取颜色
|
||||
QColor color() const;
|
||||
// 设置Margins
|
||||
void setMargins(const QMargins& mg);
|
||||
QMargins margins() const;
|
||||
// 绘制无颜色
|
||||
static void paintNoneColor(QPainter* p, const QRect& colorRect);
|
||||
// 设置颜色按钮的样式
|
||||
void setColorToolButtonStyle(ColorToolButtonStyle s);
|
||||
ColorToolButtonStyle colorToolButtonStyle() const;
|
||||
// 获取colorMenu,注意,这个函数很有可能会返回nullptr,如果ColorToolButtonStyle设置为NoColorMenu或者自己设置了菜单,此函数返回nullptr
|
||||
SAColorMenu* colorMenu() const;
|
||||
// 建立标准的颜色菜单
|
||||
SAColorMenu* createColorMenu();
|
||||
public Q_SLOTS:
|
||||
// 设置颜色,会发射colorChanged信号
|
||||
void setColor(const QColor& c);
|
||||
|
||||
protected:
|
||||
// 获取关键的三个rect位置
|
||||
virtual void calcRect(const QStyleOptionToolButton& opt, QRect& iconRect, QRect& textRect, QRect& colorRect);
|
||||
virtual void paintButton(QStylePainter* p, const QStyleOptionToolButton& opt);
|
||||
virtual void paintIcon(QStylePainter* p, const QRect& iconRect, const QStyleOptionToolButton& opt);
|
||||
virtual void paintText(QStylePainter* p, const QRect& textRect, const QStyleOptionToolButton& opt);
|
||||
virtual void paintColor(QStylePainter* p, const QRect& colorRect, const QColor& color, const QStyleOptionToolButton& opt);
|
||||
|
||||
protected:
|
||||
virtual void paintEvent(QPaintEvent* e) Q_DECL_OVERRIDE;
|
||||
virtual void resizeEvent(QResizeEvent* e) Q_DECL_OVERRIDE;
|
||||
virtual QSize sizeHint() const Q_DECL_OVERRIDE;
|
||||
private Q_SLOTS:
|
||||
void onButtonClicked(bool checked = false);
|
||||
Q_SIGNALS:
|
||||
/**
|
||||
* @brief 颜色被点击的响应
|
||||
* @param color
|
||||
*/
|
||||
void colorClicked(const QColor& color, bool checked = false);
|
||||
/**
|
||||
* @brief 颜色改变信号
|
||||
* @param color
|
||||
*/
|
||||
void colorChanged(const QColor& color);
|
||||
};
|
||||
|
||||
#endif // SACOLORTOOLBUTTON_H
|
||||
@@ -0,0 +1,13 @@
|
||||
INCLUDEPATH += $$PWD
|
||||
HEADERS += \
|
||||
$$PWD/SAColorGridWidget.h \
|
||||
$$PWD/SAColorMenu.h \
|
||||
$$PWD/SAColorPaletteGridWidget.h \
|
||||
$$PWD/SAColorToolButton.h \
|
||||
$$PWD/SAColorWidgetsGlobal.h
|
||||
|
||||
SOURCES += \
|
||||
$$PWD/SAColorGridWidget.cpp \
|
||||
$$PWD/SAColorMenu.cpp \
|
||||
$$PWD/SAColorPaletteGridWidget.cpp \
|
||||
$$PWD/SAColorToolButton.cpp
|
||||
@@ -0,0 +1,58 @@
|
||||
#ifndef SACOLORWIDGETSGLOBAL_H
|
||||
#define SACOLORWIDGETSGLOBAL_H
|
||||
#include <QScopedPointer>
|
||||
|
||||
/**
|
||||
* @def color-widgets的数字版本 MAJ.MIN.PAT
|
||||
*/
|
||||
#ifndef SA_COLOR_WIDGETS_VERSION_MAJ
|
||||
#define SA_COLOR_WIDGETS_VERSION_MAJ 0
|
||||
#endif
|
||||
/**
|
||||
* @def color-widgets的数字版本 MAJ.MIN.PAT
|
||||
*/
|
||||
#ifndef SA_COLOR_WIDGETS_VERSION_MIN
|
||||
#define SA_COLOR_WIDGETS_VERSION_MIN 1
|
||||
#endif
|
||||
/**
|
||||
* @def color-widgets的数字版本 MAJ.MIN.PAT
|
||||
*/
|
||||
#ifndef SA_COLOR_WIDGETS_VERSION_PAT
|
||||
#define SA_COLOR_WIDGETS_VERSION_PAT 0
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @def 模仿Q_DECLARE_PRIVATE,但不用前置声明而是作为一个内部类
|
||||
*/
|
||||
#ifndef SA_COLOR_WIDGETS_DECLARE_PRIVATE
|
||||
#define SA_COLOR_WIDGETS_DECLARE_PRIVATE(classname) \
|
||||
class PrivateData; \
|
||||
friend class classname::PrivateData; \
|
||||
QScopedPointer< PrivateData > d_ptr;
|
||||
#endif
|
||||
/**
|
||||
* @def 模仿Q_DECLARE_PUBLIC
|
||||
*/
|
||||
#ifndef SA_COLOR_WIDGETS_DECLARE_PUBLIC
|
||||
#define SA_COLOR_WIDGETS_DECLARE_PUBLIC(classname) \
|
||||
friend class classname; \
|
||||
classname* q_ptr { nullptr };
|
||||
#endif
|
||||
|
||||
#ifndef SA_COLOR_WIDGETS_NO_DLL
|
||||
#if defined(SA_COLOR_WIDGETS_MAKE_LIB) // 定义此宏将构建library
|
||||
#ifndef SA_COLOR_WIDGETS_API
|
||||
#define SA_COLOR_WIDGETS_API Q_DECL_EXPORT
|
||||
#endif
|
||||
#else
|
||||
#ifndef SA_COLOR_WIDGETS_API
|
||||
#define SA_COLOR_WIDGETS_API Q_DECL_IMPORT
|
||||
#endif
|
||||
#endif
|
||||
#else
|
||||
#ifndef SA_COLOR_WIDGETS_API
|
||||
#define SA_COLOR_WIDGETS_API
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#endif // SACOLORWIDGETSGLOBAL_H
|
||||
@@ -0,0 +1,134 @@
|
||||
#include "Widget.h"
|
||||
#include "ui_Widget.h"
|
||||
#include <QMenu>
|
||||
#include <cstdlib>
|
||||
#include <iostream>
|
||||
#include <ctime>
|
||||
#include <QDebug>
|
||||
#include <random>
|
||||
|
||||
Widget::Widget(QWidget* parent) : QWidget(parent), ui(new Ui::Widget)
|
||||
{
|
||||
ui->setupUi(this);
|
||||
setColor(Qt::blue);
|
||||
|
||||
QMenu* menu = new QMenu(this);
|
||||
menu->addAction("1");
|
||||
menu->addAction("2");
|
||||
menu->addAction("3");
|
||||
menu->addAction("4");
|
||||
menu->addAction("5");
|
||||
|
||||
ui->toolButtonIconOnlyHaveIconMenuPopupMode->setMenu(menu);
|
||||
ui->toolButtonIconOnlyHaveIconMenuPopupMode2->setMenu(menu);
|
||||
ui->toolButtonIconOnlyHaveIconInstantPop->setMenu(menu);
|
||||
ui->toolButtonIconOnlyHaveIconInstantPop2->setMenu(menu);
|
||||
ui->toolButtonIconOnlyHaveIconDelayedPop->setMenu(menu);
|
||||
ui->toolButtonIconOnlyHaveIconDelayedPop2->setMenu(menu);
|
||||
|
||||
ui->toolButtonIconOnlyTextHaveIconMenuPopupMode->setMenu(menu);
|
||||
ui->toolButtonIconOnlyTextHaveIconMenuPopupMode_1->setMenu(menu);
|
||||
ui->toolButtonIconOnlyTextHaveIconDelayedPop->setMenu(menu);
|
||||
ui->toolButtonIconOnlyTextHaveIconDelayedPop_1->setMenu(menu);
|
||||
ui->toolButtonIconOnlyTextHaveIconInstantPop->setMenu(menu);
|
||||
ui->toolButtonIconOnlyTextHaveIconInstantPop_1->setMenu(menu);
|
||||
|
||||
//
|
||||
QList< QColor > clrs = SA::getStandardColorList();
|
||||
ui->colorGrid1->setColumnCount(0);
|
||||
ui->colorGrid1->setColorList(clrs);
|
||||
|
||||
QList< QColor > clrs2;
|
||||
for (int i = 0; i < 30; ++i) {
|
||||
clrs2.append(makeRandColor());
|
||||
}
|
||||
ui->colorGrid2->setColumnCount(5);
|
||||
ui->colorGrid2->setColorList(clrs2);
|
||||
|
||||
connect(ui->colorGrid1, &SAColorGridWidget::colorClicked, this, &Widget::onGridColorWidgetClicked);
|
||||
connect(ui->colorGrid2, &SAColorGridWidget::colorClicked, this, &Widget::onGridColorWidgetClicked);
|
||||
}
|
||||
|
||||
Widget::~Widget()
|
||||
{
|
||||
delete ui;
|
||||
}
|
||||
|
||||
QColor Widget::makeRandColor() const
|
||||
{
|
||||
static std::random_device s_rd;
|
||||
static std::mt19937 s_gen(s_rd());
|
||||
static std::uniform_int_distribution<> s_dis(0, 255);
|
||||
return QColor(s_dis(s_gen), s_dis(s_gen), s_dis(s_gen));
|
||||
}
|
||||
|
||||
void Widget::setColor(const QColor& clr)
|
||||
{
|
||||
ui->toolButtonIconOnlyNoIcon->setColor(clr);
|
||||
ui->toolButtonIconOnlyNoIcon2->setColor(clr);
|
||||
ui->toolButtonIconOnlyHaveIcon->setColor(clr);
|
||||
ui->toolButtonIconOnlyHaveIcon2->setColor(clr);
|
||||
ui->toolButtonIconOnlyHaveIconSmall->setColor(clr);
|
||||
ui->toolButtonIconOnlyHaveIconSmall2->setColor(clr);
|
||||
ui->toolButtonIconOnlyHaveIconLarge->setColor(clr);
|
||||
ui->toolButtonIconOnlyHaveIconLarge2->setColor(clr);
|
||||
ui->toolButtonIconOnlyHaveIconMenuPopupMode->setColor(clr);
|
||||
ui->toolButtonIconOnlyHaveIconMenuPopupMode2->setColor(clr);
|
||||
ui->toolButtonIconOnlyHaveIconInstantPop->setColor(clr);
|
||||
ui->toolButtonIconOnlyHaveIconInstantPop2->setColor(clr);
|
||||
ui->toolButtonIconOnlyHaveIconDelayedPop->setColor(clr);
|
||||
ui->toolButtonIconOnlyHaveIconDelayedPop2->setColor(clr);
|
||||
|
||||
// Text Only
|
||||
ui->toolButtonIconOnlyText->setColor(clr);
|
||||
ui->toolButtonIconOnlyText_1->setColor(clr);
|
||||
ui->toolButtonIconOnlyTextHaveIcon->setColor(clr);
|
||||
ui->toolButtonIconOnlyTextHaveIcon_1->setColor(clr);
|
||||
ui->toolButtonIconOnlyTextHaveIconSmall->setColor(clr);
|
||||
ui->toolButtonIconOnlyTextHaveIconSmall_1->setColor(clr);
|
||||
ui->toolButtonIconOnlyTextHaveIconLarge->setColor(clr);
|
||||
ui->toolButtonIconOnlyTextHaveIconLarge_1->setColor(clr);
|
||||
ui->toolButtonIconOnlyTextHaveIconMenuPopupMode->setColor(clr);
|
||||
ui->toolButtonIconOnlyTextHaveIconMenuPopupMode_1->setColor(clr);
|
||||
ui->toolButtonIconOnlyTextHaveIconDelayedPop->setColor(clr);
|
||||
ui->toolButtonIconOnlyTextHaveIconDelayedPop_1->setColor(clr);
|
||||
ui->toolButtonIconOnlyTextHaveIconInstantPop->setColor(clr);
|
||||
ui->toolButtonIconOnlyTextHaveIconInstantPop_1->setColor(clr);
|
||||
|
||||
// Text beside
|
||||
ui->toolButtonIconTextBeside->setColor(clr);
|
||||
ui->toolButtonIconTextBeside1->setColor(clr);
|
||||
ui->toolButtonTextBesideHaveIcon->setColor(clr);
|
||||
ui->toolButtonTextBesideHaveIcon1->setColor(clr);
|
||||
ui->toolButtonTextBesideHaveIconSmall->setColor(clr);
|
||||
ui->toolButtonTextBesideHaveIconSmall1->setColor(clr);
|
||||
ui->toolButtonTextBesideHaveIconLarge->setColor(clr);
|
||||
ui->toolButtonTextBesideHaveIconLarge1->setColor(clr);
|
||||
ui->toolButtonTextBesideHaveIconInstantPop->setColor(clr);
|
||||
ui->toolButtonTextBesideHaveIconInstantPop1->setColor(clr);
|
||||
ui->toolButtonTextBesideHaveIconDelayedPop->setColor(clr);
|
||||
ui->toolButtonTextBesideHaveIconDelayedPop1->setColor(clr);
|
||||
ui->toolButtonTextBesideMenuPopupMode->setColor(clr);
|
||||
ui->toolButtonTextBesideMenuPopupMode1->setColor(clr);
|
||||
|
||||
// TextUnderIcon
|
||||
ui->toolButtonTextUnderIcon->setColor(clr);
|
||||
ui->toolButtonTextUnderIcon1->setColor(clr);
|
||||
ui->toolButtonTextUnderIconHaveIcon->setColor(clr);
|
||||
ui->toolButtonTextUnderIconHaveIcon1->setColor(clr);
|
||||
ui->toolButtonTextUnderIconHaveIconSmall->setColor(clr);
|
||||
ui->toolButtonTextUnderIconHaveIconSmall1->setColor(clr);
|
||||
ui->toolButtonTextUnderIconHaveIconLarge->setColor(clr);
|
||||
ui->toolButtonTextUnderIconHaveIconLarge1->setColor(clr);
|
||||
ui->toolButtonTextUnderIconMenuPopupMode->setColor(clr);
|
||||
ui->toolButtonTextUnderIconMenuPopupMode1->setColor(clr);
|
||||
ui->toolButtonTextUnderIconInstantPop->setColor(clr);
|
||||
ui->toolButtonTextUnderIconInstantPop1->setColor(clr);
|
||||
ui->toolButtonTextUnderIconDelayedPop->setColor(clr);
|
||||
ui->toolButtonTextUnderIconDelayedPop1->setColor(clr);
|
||||
}
|
||||
|
||||
void Widget::onGridColorWidgetClicked(const QColor& c)
|
||||
{
|
||||
setColor(c);
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
#ifndef WIDGET_H
|
||||
#define WIDGET_H
|
||||
|
||||
#include <QWidget>
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
namespace Ui
|
||||
{
|
||||
class Widget;
|
||||
}
|
||||
QT_END_NAMESPACE
|
||||
|
||||
class Widget : public QWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
Widget(QWidget* parent = nullptr);
|
||||
~Widget();
|
||||
QColor makeRandColor() const;
|
||||
//
|
||||
void setColor(const QColor& clr);
|
||||
private Q_SLOTS:
|
||||
void onGridColorWidgetClicked(const QColor& c);
|
||||
|
||||
private:
|
||||
Ui::Widget* ui;
|
||||
};
|
||||
#endif // WIDGET_H
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,41 @@
|
||||
QT += core gui
|
||||
|
||||
greaterThan(QT_MAJOR_VERSION, 4): QT += widgets
|
||||
|
||||
CONFIG += c++17
|
||||
|
||||
# The following define makes your compiler emit warnings if you use
|
||||
# any Qt feature that has been marked deprecated (the exact warnings
|
||||
# depend on your compiler). Please consult the documentation of the
|
||||
# deprecated API in order to know how to port your code away from it.
|
||||
DEFINES += QT_DEPRECATED_WARNINGS
|
||||
|
||||
# You can also make your code fail to compile if it uses deprecated APIs.
|
||||
# In order to do so, uncomment the following line.
|
||||
# You can also select to disable deprecated APIs only up to a certain version of Qt.
|
||||
#DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0
|
||||
INCLUDEPATH += $$PWD/../
|
||||
SOURCES += \
|
||||
../SAColorGridWidget.cpp \
|
||||
../SAColorPaletteGridWidget.cpp \
|
||||
../SAColorToolButton.cpp \
|
||||
main.cpp \
|
||||
Widget.cpp
|
||||
|
||||
HEADERS += \
|
||||
../SAColorGridWidget.h \
|
||||
../SAColorPaletteGridWidget.h \
|
||||
../SAColorToolButton.h \
|
||||
../SAColorWidgetsGlobal.h \
|
||||
Widget.h
|
||||
|
||||
FORMS += \
|
||||
Widget.ui
|
||||
|
||||
# Default rules for deployment.
|
||||
qnx: target.path = /tmp/$${TARGET}/bin
|
||||
else: unix:!android: target.path = /opt/$${TARGET}/bin
|
||||
!isEmpty(target.path): INSTALLS += target
|
||||
|
||||
RESOURCES += \
|
||||
icon.qrc
|
||||
@@ -0,0 +1,5 @@
|
||||
<RCC>
|
||||
<qresource prefix="/colorWidgetTst">
|
||||
<file>icon/text.svg</file>
|
||||
</qresource>
|
||||
</RCC>
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user