instAdmin/Cpp/GisDes/SaRibbon/SARibbonBar/SARibbonPannel.cpp
2024-10-29 22:24:50 +08:00

1014 lines
28 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#include "SARibbonPannel.h"
#include "SARibbonCategory.h"
#include "SARibbonElementManager.h"
#include "SARibbonGallery.h"
#include "SARibbonPannelLayout.h"
#include "SARibbonPannelOptionButton.h"
#include "SARibbonToolButton.h"
#include <QAction>
#include <QApplication>
#include <QDebug>
#include <QFontMetrics>
#include <QGridLayout>
#include <QIcon>
#include <QMenu>
#include <QPainter>
#include <QResizeEvent>
#include <QWidgetAction>
#ifndef SARibbonPannel_DEBUG_PRINT
#define SARibbonPannel_DEBUG_PRINT 0
#endif
#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)
//===============================================================
// SARibbonPannelLabel
//===============================================================
SARibbonPannelLabel::SARibbonPannelLabel(QWidget* parent) : QLabel(parent)
{
}
//===============================================================
// SARibbonPannel::PrivateData
//===============================================================
class SARibbonPannel::PrivateData
{
SA_RIBBON_DECLARE_PUBLIC(SARibbonPannel)
public:
PrivateData(SARibbonPannel* p);
// 根据m_pannelLayoutMode返回gridLayout应该增加的行数
int rowadded();
void createLayout();
// 获取layout
SARibbonPannelLayout* pannelLayout() const;
// 返回最后一个添加的action对应的button前提是最后一个是toolbutton否则返回nullptr
SARibbonToolButton* lastAddActionButton();
// 重置labe的字体这个主要是为了让pannel的标题字体能适应标题高度
void resetTitleLabelFont();
// 标题
QString pannelName() const;
void setPannelName(const QString& title);
public:
bool m_isCanCustomize { true }; ///< 记录是否可自定义
SARibbonPannel::PannelLayoutMode m_pannelLayoutMode { SARibbonPannel::ThreeRowMode }; ///< pannel的布局模式默认为3行模式ThreeRowMode
SARibbonPannelOptionButton* m_optionActionButton { nullptr }; ///< 标题栏的y距离
SARibbonPannelLabel* m_label { nullptr };
};
SARibbonPannel::PrivateData::PrivateData(SARibbonPannel* p) : q_ptr(p)
{
createLayout();
}
int SARibbonPannel::PrivateData::rowadded()
{
switch (m_pannelLayoutMode) {
case SARibbonPannel::ThreeRowMode:
return (2);
case SARibbonPannel::TwoRowMode:
return (3);
default:
break;
}
return (2);
}
void SARibbonPannel::PrivateData::createLayout()
{
m_label = new SARibbonPannelLabel(q_ptr);
m_label->setAlignment(Qt::AlignCenter);
SARibbonPannelLayout* lay = new SARibbonPannelLayout(q_ptr);
lay->setPannelTitleLabel(m_label);
lay->setSpacing(2);
lay->setContentsMargins(2, 2, 2, 2);
}
SARibbonPannelLayout* SARibbonPannel::PrivateData::pannelLayout() const
{
return qobject_cast< SARibbonPannelLayout* >(q_ptr->layout());
}
SARibbonToolButton* SARibbonPannel::PrivateData::lastAddActionButton()
{
if (SARibbonPannelLayout* lay = pannelLayout()) {
return (qobject_cast< SARibbonToolButton* >(lay->lastWidget()));
}
return (nullptr);
}
/**
* @brief 重置label的字体
*
* @note 此函数必须在布局设置后调用
*/
void SARibbonPannel::PrivateData::resetTitleLabelFont()
{
if (SARibbonPannelLayout* lay = pannelLayout()) {
int h = lay->pannelTitleHeight();
QFont f = q_ptr->font();
f.setPixelSize(h * 0.8);
if (m_label) {
m_label->setFont(f);
}
}
}
QString SARibbonPannel::PrivateData::pannelName() const
{
if (m_label) {
return m_label->text();
}
return (QString());
}
void SARibbonPannel::PrivateData::setPannelName(const QString& title)
{
if (m_label) {
m_label->setText(title);
}
}
//==================================================
// SARibbonPannel
//==================================================
SARibbonPannel::SARibbonPannel(QWidget* parent) : QFrame(parent), d_ptr(new SARibbonPannel::PrivateData(this))
{
setPannelLayoutMode(ThreeRowMode);
}
SARibbonPannel::SARibbonPannel(const QString& name, QWidget* parent)
: QFrame(parent), d_ptr(new SARibbonPannel::PrivateData(this))
{
setPannelLayoutMode(ThreeRowMode);
setPannelName(name);
}
SARibbonPannel::~SARibbonPannel()
{
}
/**
* @brief 把action的行属性设置进action中action自身携带了行属性
* @param action
* @param rp
*/
void SARibbonPannel::setActionRowProportionProperty(QAction* action, SARibbonPannelItem::RowProportion rp)
{
Q_CHECK_PTR(action);
action->setProperty(SA_ActionPropertyName_RowProportion, static_cast< int >(rp));
}
/**
* @brief 获取action的行属性
* @param action
* @return
*/
SARibbonPannelItem::RowProportion SARibbonPannel::getActionRowProportionProperty(QAction* action)
{
bool isok = false;
int r = action->property(SA_ActionPropertyName_RowProportion).toInt(&isok);
if (isok) {
return (static_cast< SARibbonPannelItem::RowProportion >(r));
}
return (SARibbonPannelItem::Large);
}
/**
* @brief 设置action的ToolButtonPopupMode属性
* @param action
* @param popMode
*/
void SARibbonPannel::setActionToolButtonPopupModeProperty(QAction* action, QToolButton::ToolButtonPopupMode popMode)
{
Q_CHECK_PTR(action);
action->setProperty(SA_ActionPropertyName_ToolButtonPopupMode, static_cast< int >(popMode));
}
/**
* @brief 获取action的ToolButtonPopupMode属性
* @param action
* @return
*/
QToolButton::ToolButtonPopupMode SARibbonPannel::getActionToolButtonPopupModeProperty(QAction* action)
{
bool isok = false;
int r = action->property(SA_ActionPropertyName_ToolButtonPopupMode).toInt(&isok);
if (isok) {
return (static_cast< QToolButton::ToolButtonPopupMode >(r));
}
return (QToolButton::InstantPopup);
}
/**
* @brief 设置action的ToolButtonStyle属性
* @param action
* @param buttonStyle
*/
void SARibbonPannel::setActionToolButtonStyleProperty(QAction* action, Qt::ToolButtonStyle buttonStyle)
{
Q_CHECK_PTR(action);
action->setProperty(SA_ActionPropertyName_ToolButtonStyle, static_cast< int >(buttonStyle));
}
/**
* @brief 获取action的ToolButtonStyle属性
* @param action
* @return
*/
Qt::ToolButtonStyle SARibbonPannel::getActionToolButtonStyleProperty(QAction* action)
{
bool isok = false;
int r = action->property(SA_ActionPropertyName_ToolButtonStyle).toInt(&isok);
if (isok) {
return (static_cast< Qt::ToolButtonStyle >(r));
}
return (Qt::ToolButtonIconOnly);
}
/**
* @brief 添加action
*
* action实际对应了一个toolbutton如果想找到对应的toolbutton使用@ref actionToRibbonToolButton
* @param action
* @param rp 指定action的行占比
* @param popMode 菜单弹出样式
*/
void SARibbonPannel::addAction(QAction* action, SARibbonPannelItem::RowProportion rp)
{
Q_CHECK_PTR(action);
setActionRowProportionProperty(action, rp);
addAction(action);
}
/**
* @brief 添加一个action
* @param act
* @param popMode 按钮的样式
* @param rp action在pannel中的占位情况默认是大图标
*/
void SARibbonPannel::addAction(QAction* act, QToolButton::ToolButtonPopupMode popMode, SARibbonPannelItem::RowProportion rp)
{
Q_CHECK_PTR(act);
setActionRowProportionProperty(act, rp);
setActionToolButtonPopupModeProperty(act, popMode);
addAction(act);
}
/**
@brief 添加大图标
action实际对应了一个toolbutton如果想找到对应的toolbutton使用@ref actionToRibbonToolButton
@param action
*/
void SARibbonPannel::addLargeAction(QAction* action)
{
addAction(action, SARibbonPannelItem::Large);
}
/**
@brief 在三栏模式下强制加为2栏action
@note 在两行模式下Medium和Small等价
主要应用在ThreeRowMode下
action实际对应了一个toolbutton如果想找到对应的toolbutton使用@ref actionToRibbonToolButton
@param action
*/
void SARibbonPannel::addMediumAction(QAction* action)
{
addAction(action, SARibbonPannelItem::Medium);
}
/**
@brief 添加小图标
action实际对应了一个toolbutton如果想找到对应的toolbutton使用@ref actionToRibbonToolButton
@param action
*/
void SARibbonPannel::addSmallAction(QAction* action)
{
addAction(action, SARibbonPannelItem::Small);
}
void SARibbonPannel::addSmallAction(QAction* action, QToolButton::ToolButtonPopupMode popMode)
{
addAction(action, popMode, SARibbonPannelItem::Small);
}
void SARibbonPannel::addLargeAction(QAction* action, QToolButton::ToolButtonPopupMode popMode)
{
addAction(action, popMode, SARibbonPannelItem::Large);
}
void SARibbonPannel::addMediumAction(QAction* action, QToolButton::ToolButtonPopupMode popMode)
{
addAction(action, popMode, SARibbonPannelItem::Medium);
}
/**
* @brief 生成并添加一个action
*
* 如果不对此action做操作SARibbonPannel将管理此action
*
* @note action的父对象将设置为SARibbonPannelSARibbonPannel在删除时将会删除子对象会把这个action也删除
* 如果不想此action也删除需要对action重新设置父对象
*
* @param text action的文字
* @param icon action的图标
* @param popMode 按钮的样式
* @param rp action在pannel中的占位情况默认是大图标
* @return 返回添加的action
*/
QAction* SARibbonPannel::addAction(const QString& text,
const QIcon& icon,
QToolButton::ToolButtonPopupMode popMode,
SARibbonPannelItem::RowProportion rp)
{
QAction* action = new QAction(icon, text, this);
addAction(action, popMode, rp);
return (action);
}
/**
* @brief 添加一个普通菜单
* @param menu
* @param rp
* @param popMode,菜单弹出模式默认InstantPopup模式
* @return
*/
void SARibbonPannel::addMenu(QMenu* menu, SARibbonPannelItem::RowProportion rp, QToolButton::ToolButtonPopupMode popMode)
{
Q_CHECK_PTR(menu);
QAction* action = menu->menuAction();
action->setIcon(menu->icon());
action->setText(menu->title());
action->setObjectName("action." + menu->objectName());
addAction(action, popMode, rp);
}
void SARibbonPannel::addLargeMenu(QMenu* menu, QToolButton::ToolButtonPopupMode popMode)
{
addMenu(menu, SARibbonPannelItem::Large, popMode);
}
void SARibbonPannel::addSmallMenu(QMenu* menu, QToolButton::ToolButtonPopupMode popMode)
{
addMenu(menu, SARibbonPannelItem::Small, popMode);
}
/**
* @brief 添加窗口
*
* @param w
* @param rp
* @return 返回action(QWidgetAction)
* @note SARibbonPannel并不会管理此窗口内存在delete SARibbonPannel时此窗口如果父对象不是SARibbonPannel将不会被删除
*/
QAction* SARibbonPannel::addWidget(QWidget* w, SARibbonPannelItem::RowProportion rp)
{
QWidgetAction* action = new QWidgetAction(this);
action->setDefaultWidget(w);
action->setIcon(w->windowIcon());
action->setText(w->windowTitle());
action->setObjectName("action." + w->objectName());
w->setAttribute(Qt::WA_Hover);
setActionRowProportionProperty(action, rp);
addAction(action);
return (action);
}
/**
* @brief 添加窗口,占用ribbon的一行
* @param w
* @return 返回action(QWidgetAction)
*/
QAction* SARibbonPannel::addSmallWidget(QWidget* w)
{
return (addWidget(w, SARibbonPannelItem::Small));
}
/**
* @brief 添加窗口,占用ribbon的一行
* @param w
* @return
*/
QAction* SARibbonPannel::addMediumWidget(QWidget* w)
{
return (addWidget(w, SARibbonPannelItem::Medium));
}
/**
* @brief 添加窗口,占用所有行
* @param w
* @return 返回action(QWidgetAction)
*/
QAction* SARibbonPannel::addLargeWidget(QWidget* w)
{
return (addWidget(w, SARibbonPannelItem::Large));
}
/**
* @brief SARibbonPannel::addGallery
* @return
* @note SARibbonPannel将拥有SARibbonGallery的管理权
*/
SARibbonGallery* SARibbonPannel::addGallery(bool expanding)
{
SARibbonGallery* gallery = RibbonSubElementFactory->createRibbonGallery(this);
addWidget(gallery, SARibbonPannelItem::Large);
if (expanding) {
setExpanding(expanding);
}
return (gallery);
}
/**
* @brief 添加分割线
* @param top 上边距 @default 6
* @param bottom 下边距 @default 6
*/
QAction* SARibbonPannel::addSeparator()
{
QAction* action = new QAction(this);
action->setSeparator(true);
setActionRowProportionProperty(action, SARibbonPannelItem::Large);
addAction(action);
return (action);
}
/**
* @brief 从pannel中把action对应的button提取出来如果action没有对应的button就返回nullptr
* @param action
* @return 如果action没有对应的button就返回nullptr
*/
SARibbonToolButton* SARibbonPannel::actionToRibbonToolButton(QAction* action)
{
#if 0
SARibbonPannelLayout* lay = qobject_cast< SARibbonPannelLayout* >(layout());
if (lay) {
int index = lay->indexOf(action);
if (index == -1) {
return (nullptr);
}
QLayoutItem* item = lay->takeAt(index);
SARibbonToolButton* btn = qobject_cast< SARibbonToolButton* >(item ? item->widget() : nullptr);
return (btn);
}
return (nullptr);
#else
for (auto obj : qAsConst(children())) {
if (obj->isWidgetType()) {
if (SARibbonToolButton* btn = qobject_cast< SARibbonToolButton* >(obj)) {
if (btn->defaultAction() == action) {
return btn;
}
}
}
}
return (nullptr);
#endif
}
/**
* @brief 获取pannel下面的所有toolbutton
* @return
*/
QList< SARibbonToolButton* > SARibbonPannel::ribbonToolButtons() const
{
const QObjectList& objs = children();
QList< SARibbonToolButton* > res;
for (QObject* o : objs) {
SARibbonToolButton* b = qobject_cast< SARibbonToolButton* >(o);
if (b) {
res.append(b);
}
}
return (res);
}
/**
* @brief 设置PannelLayoutMode
* @param mode
*/
void SARibbonPannel::setPannelLayoutMode(SARibbonPannel::PannelLayoutMode mode)
{
if (d_ptr->m_pannelLayoutMode == mode) {
return;
}
d_ptr->m_pannelLayoutMode = mode;
updateItemGeometry();
}
SARibbonPannel::PannelLayoutMode SARibbonPannel::pannelLayoutMode() const
{
return (d_ptr->m_pannelLayoutMode);
}
/**
* @brief 添加操作action如果要去除传入nullptr指针即可SARibbonPannel不会对QAction的所有权进行管理
* @param action
* @note 要去除OptionAction直接传入nullptr即可
* @note SARibbonPannel不对QAction的destroy进行关联如果外部对action进行delete需要先传入nullptr给addOptionAction
*/
void SARibbonPannel::setOptionAction(QAction* action)
{
if (SARibbonPannelLayout* lay = pannelLayout()) {
lay->setOptionAction(action);
}
}
/**
* @brief 判断是否存在OptionAction
* @return 存在返回true
*/
bool SARibbonPannel::isHaveOptionAction() const
{
if (SARibbonPannelLayout* lay = pannelLayout()) {
return lay->isHaveOptionAction();
}
return false;
}
QSize SARibbonPannel::sizeHint() const
{
int shWidth = 500;
int shHeight = 100;
if (QLayout* lay = layout()) {
QSize laySize = layout()->sizeHint();
shWidth = laySize.width();
shHeight = laySize.height();
}
return QSize(shWidth, shHeight);
}
QSize SARibbonPannel::minimumSizeHint() const
{
return (layout()->minimumSize());
}
void SARibbonPannel::setToolButtonIconSize(const QSize& s)
{
if (SARibbonPannelLayout* lay = pannelLayout()) {
lay->setToolButtonIconSize(s);
}
// 对已经管理的QToolButton设置为iconsize
iterate([ s ](SARibbonToolButton* t) -> bool {
t->setIconSize(s);
return true;
});
}
QSize SARibbonPannel::toolButtonIconSize() const
{
if (SARibbonPannelLayout* lay = pannelLayout()) {
return lay->toolButtonIconSize();
}
return QSize();
}
/**
* @brief 遍历SARibbonPannel下的所有RibbonToolButton执行函数指针(bool(SARibbonRibbonToolButton*))函数指针返回false则停止迭代
* @param fp
* @return 返回false说明迭代中途退出返回true则表示迭代完全
*/
bool SARibbonPannel::iterate(SARibbonPannel::FpRibbonToolButtonIterate fp)
{
const QObjectList& ols = children();
for (QObject* obj : ols) {
if (SARibbonToolButton* t = qobject_cast< SARibbonToolButton* >(obj)) {
if (!fp(t)) {
return false;
}
}
}
return true;
}
/**
* @brief 把pannel设置为扩展模式此时会撑大水平区域
* @param isExpanding
*/
void SARibbonPannel::setExpanding(bool isExpanding)
{
setSizePolicy(isExpanding ? QSizePolicy::Expanding : QSizePolicy::Preferred, QSizePolicy::Fixed);
}
/**
* @brief 判断此pannel是否为水平扩展模式
* @return 是扩展模式返回true
*/
bool SARibbonPannel::isExpanding() const
{
QSizePolicy sp = sizePolicy();
return (sp.horizontalPolicy() == QSizePolicy::Expanding);
}
/**
@brief 设置标题栏的高度
@param h
*/
void SARibbonPannel::setTitleHeight(int h)
{
if (SARibbonPannelLayout* lay = pannelLayout()) {
lay->setPannelTitleHeight(h);
}
}
/**
* @brief 标题栏高度
* @return
*/
int SARibbonPannel::titleHeight() const
{
if (SARibbonPannelLayout* lay = pannelLayout()) {
return lay->pannelTitleHeight();
}
return -1;
}
/**
* @brief 判断是否显示标题,只有标题的高度被设置,才会显示标题
* @return
*/
bool SARibbonPannel::isEnableShowTitle() const
{
if (SARibbonPannelLayout* lay = pannelLayout()) {
return lay->isEnableShowPannelTitle();
}
return false;
}
/**
* @brief 是否显示标题显示标题后标题的高度需要设置默认高度为15
* @param on
*/
void SARibbonPannel::setEnableShowTitle(bool on)
{
if (SARibbonPannelLayout* lay = pannelLayout()) {
return lay->setEnableShowPannelTitle(on);
}
}
/**
* @brief action对应的布局index此操作一般用于移动其他意义不大
* @param act
* @return 没有查到返回-1
*/
int SARibbonPannel::actionIndex(QAction* act) const
{
if (SARibbonPannelLayout* lay = pannelLayout()) {
return (lay->indexByAction(act));
}
return (-1);
}
/**
* @brief 移动action
* @param from 要移动action的位置通过@ref actionIndex 获取
* @param to 要移动的位置
*/
void SARibbonPannel::moveAction(int from, int to)
{
if (SARibbonPannelLayout* lay = pannelLayout()) {
return (lay->move(from, to));
}
updateGeometry(); // 通知layout进行重新布局
}
/**
* @brief 判断是否可以自定义
* @return
*/
bool SARibbonPannel::isCanCustomize() const
{
return (d_ptr->m_isCanCustomize);
}
/**
* @brief 设置是否可以自定义
* @param b
*/
void SARibbonPannel::setCanCustomize(bool b)
{
d_ptr->m_isCanCustomize = b;
}
/**
* @brief pannel名称
* @return
*/
QString SARibbonPannel::pannelName() const
{
return (d_ptr->pannelName());
}
/**
* @brief pannel的名称
* @param title 标题
* @note 此函数会触发@sa pannelNameChanged 信号
*/
void SARibbonPannel::setPannelName(const QString& title)
{
QString oldName = pannelName();
if (oldName != title) {
d_ptr->setPannelName(title);
Q_EMIT pannelNameChanged(title);
}
}
/**
* @brief 获取大图标的高度
* @return
*/
int SARibbonPannel::largeButtonHeight() const
{
const QMargins& mag = contentsMargins();
return height() - mag.top() - mag.bottom() - titleHeight();
}
/**
* @brief 获取pannel layout
* @return
*/
SARibbonPannelLayout* SARibbonPannel::pannelLayout() const
{
return d_ptr->pannelLayout();
}
/**
* @brief 更新布局
*/
void SARibbonPannel::updateItemGeometry()
{
#if SA_DEBUG_PRINT_SIZE_HINT
qDebug() << "SARibbonPannel updateItemGeometry,pannelName=" << pannelName();
#endif
// 此函数需要添加否则SARibbonBar::setEnableWordWrap无法刷新按钮
resetToolButtonSize();
if (SARibbonPannelLayout* lay = pannelLayout()) {
lay->updateGeomArray();
}
}
/**
@brief 获取category指针如果没有parent或者不在category管理返回nullptr
@return
*/
SARibbonCategory* SARibbonPannel::category() const
{
return qobject_cast< SARibbonCategory* >(parent());
}
/**
@brief 获取ribbonBar指针如果没有返回nullptr
@return
*/
SARibbonBar* SARibbonPannel::ribbonBar() const
{
if (SARibbonCategory* c = category()) {
return c->ribbonBar();
}
return nullptr;
}
/**
* @brief 设置按钮之间的间隔
* @param n
*/
void SARibbonPannel::setSpacing(int n)
{
if (auto lay = layout()) {
lay->setSpacing(n);
}
}
/**
* @brief 按钮之间的间隔
* @return
*/
int SARibbonPannel::spacing() const
{
if (auto lay = layout()) {
return lay->spacing();
}
return 0;
}
/**
* @brief pannel高度推荐
* @param fm
* @param layMode
* @param pannelTitleHeight
* @return
*/
int SARibbonPannel::pannelHeightHint(const QFontMetrics& fm, PannelLayoutMode layMode, int pannelTitleHeight)
{
int textH = fm.lineSpacing(); // 这里用linespace因为在换行的情况下行距是不可忽略的ribbon的大按钮默认是2行
switch (layMode) {
case SARibbonPannel::ThreeRowMode: {
// 5.5=3*1.6+1 (三行),1是给panneltitle预留的
return textH * 4.8 + pannelTitleHeight;
} break;
case SARibbonPannel::TwoRowMode: {
// 3=2*1.6
return textH * 3.2 + pannelTitleHeight;
} break;
default: {
qWarning() << "unknow SARibbonPannel::PannelLayoutMode:" << layMode;
}
}
return (textH * 4.8 + pannelTitleHeight);
}
/**
* @brief 重置按钮的尺寸,在布局改变后(尤其高度变更),按钮的尺寸需要手动变更
*/
void SARibbonPannel::resetToolButtonSize()
{
QList< SARibbonToolButton* > btns = ribbonToolButtons();
for (SARibbonToolButton* b : qAsConst(btns)) {
if ((nullptr == b)) {
continue;
}
b->updateRect();
}
}
bool SARibbonPannel::event(QEvent* e)
{
#if SA_DEBUG_PRINT_EVENT
if (e->type() != QEvent::Paint) {
qDebug() << "SARibbonPannel event(" << e->type() << "),name=" << pannelName();
}
#endif
// if (SARibbonPannelLayout* lay = pannelLayout()) {
// if (lay->isDirty() && e->type() == QEvent::LayoutRequest) {
// if (QWidget* parw = parentWidget()) {
// if (QLayout* pl = parw->layout()) {
// pl->invalidate();
// }
// }
// lay->m_dirty = false;
// }
// }
return QWidget::event(e);
}
/**
* @brief 处理action的事件
*
* 这里处理了ActionAddedActionChangedActionRemoved三个事件
*
* ActionAdded时向布局请求添加action布局中同时触发了@ref SARibbonPannelLayout::createItem 函数
* 此函数用于生成窗口例如QRibbonToolButton
*
* ActionChanged时会让布局重新计算尺寸并向category请求重新布局有可能category的所有要重新调整尺寸
*
* ActionRemoved会移除布局管理的QLayoutItem并进行内存清理这时窗口也会隐藏同时销毁
*
* @param e
* @note 所有action事件都会向category请求重新布局
*
*/
void SARibbonPannel::actionEvent(QActionEvent* e)
{
QAction* action = e->action();
QWidgetAction* widgetAction = qobject_cast< QWidgetAction* >(action);
switch (e->type()) {
case QEvent::ActionAdded: {
SARibbonPannelLayout* lay = pannelLayout();
if (nullptr != widgetAction) {
if (widgetAction->parent() != this) {
widgetAction->setParent(this);
}
}
int index = layout()->count();
if (e->before()) {
// 说明是插入
index = lay->indexByAction(e->before());
if (-1 == index) {
index = layout()->count(); // 找不到的时候就插入到最后
}
}
lay->insertAction(index, action, getActionRowProportionProperty(action));
// 由于pannel的尺寸发生变化需要让category也调整
// if (QWidget* parw = parentWidget()) {
// if (QLayout* pl = parw->layout()) {
// pl->invalidate();
// }
// }
} break;
case QEvent::ActionChanged: {
// 让布局重新绘制
layout()->invalidate();
// updateGeometry();
// 由于pannel的尺寸发生变化需要让category也调整
if (QWidget* parw = parentWidget()) {
if (QLayout* pl = parw->layout()) {
pl->invalidate();
}
//! 强制发送一个resizeevent让Category能重绘如果没有这个函数发现Category的layout虽然设置了invalidate标记缓存失效
//! 但并没有按顺序在pannel尺寸更新后更新Category的尺寸导致有些pannel的尺寸识别出现异常
//! 重打印信息上看pannel的尺寸有进行更新category的尺寸也进行了更新但更新的次数和调用invalidate的次数不一样需要手动触发ResizeEvent
//! 尝试过调用QEvent::LayoutRequest没有效果
//! @code
//! QEvent* el = new QEvent(QEvent::LayoutRequest);
//! QApplication::postEvent(parw, el);
//! @endcode
//!
//! 调用parw->updateGeometry();也没有效果目前看使用resizeevent是最有效果的
//!
QResizeEvent* ersize = new QResizeEvent(parw->size(), QSize());
QApplication::postEvent(parw, ersize);
}
} break;
case QEvent::ActionRemoved: {
SARibbonPannelLayout* lay = pannelLayout();
action->disconnect(this);
int index = lay->indexByAction(action);
if (index != -1) {
QLayoutItem* item = lay->takeAt(index);
delete item;
}
// 由于pannel的尺寸发生变化需要让category也调整
// if (QWidget* parw = parentWidget()) {
// if (QLayout* pl = parw->layout()) {
// pl->invalidate();
// }
// }
} break;
default:
break;
}
}
/**
* @brief 追踪字体改变事件把新字体设置到childwidget中
* @param e
*/
void SARibbonPannel::changeEvent(QEvent* e)
{
if (nullptr == e) {
return;
}
if (e->type() == QEvent::FontChange) {
QFont f = font();
QList< QWidget* > listWidgets = findChildren< QWidget* >();
for (QWidget* w : listWidgets) {
w->setFont(f);
}
if (QLayout* lay = layout()) {
lay->invalidate();
}
d_ptr->resetTitleLabelFont();
}
QWidget::changeEvent(e);
}
/**
* @brief 获取布局item
* @return
*/
const QList< SARibbonPannelItem* >& SARibbonPannel::ribbonPannelItem() const
{
return (pannelLayout()->mItems);
}
/**
* @brief 获取最近添加的按钮
* @return 刚才添加的按钮的指针
*/
SARibbonToolButton* SARibbonPannel::lastAddActionButton()
{
return d_ptr->lastAddActionButton();
}