14#include <QApplication>
16#include <QFontMetrics>
21#include <QResizeEvent>
22#include <QWidgetAction>
26#ifndef QX_RIBBON_PROP_ROW_PROPORTION
27#define QX_RIBBON_PROP_ROW_PROPORTION "_qx_RibbonGroupRowProportion"
30#define HELP_DRAW_RECT(p, rect) \
33 QPen _pen(Qt::DashLine); \
34 _pen.setColor(Qt::blue); \
36 p.setBrush(QBrush()); \
41RibbonGroupOptionButton::RibbonGroupOptionButton(QWidget *parent)
46 setToolButtonStyle(Qt::ToolButtonIconOnly);
48 setIconSize(QSize(10, 10));
49 setIcon(QIcon(
":/image/res/group_option.png"));
54 connect(
this, &RibbonGroupOptionButton::clicked, action, &QAction::trigger);
63 , m_isCanCustomize(true)
72 m_layout->setContentsMargins(2, 2, 2, 2);
79 return qobject_cast<RibbonButton *>(w);
88 QList<RibbonButton *> btns = q->ribbonButtons();
138 return windowTitle();
148 setWindowTitle(
title);
227 QWidget::addAction(action);
229 return d->lastAddedButton();
278 QWidget::addAction(act);
281 btn->setPopupMode(popMode);
302 QAction *action =
new QAction(icon,
text,
this);
320 QAction *action = menu->menuAction();
325 btn->setPopupMode(popMode);
354 btn->setPopupMode(QToolButton::MenuButtonPopup);
379 QWidgetAction *action =
new QWidgetAction(
this);
382 action->setDefaultWidget(w);
383 w->setAttribute(Qt::WA_Hover);
385 QWidget::addAction(action);
442 QAction *action =
new QAction(
this);
444 action->setSeparator(
true);
446 QWidget::addAction(action);
447 QWidget *w = d->m_layout->lastWidget();
463 if (index < 0 || index >= cnt) {
479 int index = lay->
indexOf(action);
483 QLayoutItem *item = lay->
itemAt(index);
485 return qobject_cast<RibbonButton *>(item->widget());
493 const QObjectList &objs = children();
494 QList<RibbonButton *> res;
496 for (QObject *o : objs) {
508 return (d->m_optionActionButton !=
Q_NULLPTR);
521 if (d->m_optionActionButton) {
522 delete d->m_optionActionButton;
527 if (
Q_NULLPTR == d->m_optionActionButton) {
532 d->m_optionActionButton->connectAction(action);
545 return d->m_layout->indexOf(act);
556 d->m_layout->move(from, to);
563 return d->m_groupLayoutMode;
569 if (d->m_groupLayoutMode == mode) {
572 d->m_groupLayoutMode = mode;
580 layout()->setSpacing(
isTwoRow() ? 4 : 2);
583 d->resetLargeToolButtonStyle();
594 return (
isTwoRow() ? QSize(12, 12) : QSize(16, 16));
600 QSize laySize = layout()->sizeHint();
601 int maxWidth = laySize.width() + 2;
604 QFontMetrics fm = fontMetrics();
605 QSize titleSize = fm.size(Qt::TextShowMnemonic,
groupName());
606 if (d->m_optionActionButton) {
608 titleSize.setWidth(titleSize.width() + d->m_optionActionButton->width() + 4);
610 maxWidth = qMax(maxWidth, titleSize.width());
612 return QSize(maxWidth, laySize.height());
617 return layout()->minimumSize();
626 QSizePolicy sp = sizePolicy();
628 return (sp.horizontalPolicy() == QSizePolicy::Expanding);
637 setSizePolicy(expanding ? QSizePolicy::Expanding : QSizePolicy::Preferred, QSizePolicy::Fixed);
643 return d->m_isCanCustomize;
649 d->m_isCanCustomize = b;
709#ifdef QX_RIBBON_DEBUG_HELP_DRAW
717 if (d->m_optionActionButton) {
718 r = QRect(1, height() - th, width() - d->m_optionActionButton->width() - 4, th);
720 r = QRect(1, height() - th, width(), th);
722 p.drawText(r, Qt::AlignCenter,
groupName());
723#ifdef QX_RIBBON_DEBUG_HELP_DRAW
728 QWidget::paintEvent(event);
735 if (d->m_optionActionButton) {
737 d->m_optionActionButton->move(width() - d->m_optionActionButton->width() - 2,
739 (
titleHeight() - d->m_optionActionButton->height()) / 2);
741 d->m_optionActionButton->move(width() - d->m_optionActionButton->width(),
742 height() - d->m_optionActionButton->height());
747 return QWidget::resizeEvent(event);
769 QAction *action =
event->action();
771 switch (event->type()) {
772 case QEvent::ActionAdded: {
774 int index = layout()->
count();
775 if (event->before()) {
779 index = layout()->count();
784 if (parentWidget()) {
785 QApplication::postEvent(parentWidget(),
new QEvent(QEvent::LayoutRequest));
789 case QEvent::ActionChanged: {
791 layout()->invalidate();
793 if (parentWidget()) {
794 QApplication::postEvent(parentWidget(),
new QEvent(QEvent::LayoutRequest));
798 case QEvent::ActionRemoved: {
800 action->disconnect(
this);
801 int index = lay->
indexOf(action);
803 QLayoutItem *item = lay->
takeAt(index);
807 if (parentWidget()) {
808 QApplication::postEvent(parentWidget(),
new QEvent(QEvent::LayoutRequest));
821 setFixedHeight(height);
829 setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Expanding);
835 return QSize(6, height());
841 m_bottomMargin = bottom;
847 QPainter painter(
this);
849 painter.setPen(palette().
window().color().darker(114));
850 int x1 = rect().center().x();
852 painter.drawLine(QPoint(x1, rect().top() + m_topMargin), QPoint(x1, rect().bottom() - m_bottomMargin));
是对 group 所有子窗口的抽象,参考 qt 的 toolbar
RibbonGroup::RowProportion rowProportion
行的占比,ribbon中有large,medium和small三种占比,见 RibbonGroup::RowProportion
QLayoutItem * takeAt(int index) override
virtual int indexOf(QAction *action) const
通过action查找索引,用于actionEvent添加action用
const QList< RibbonGroupItem * > & ribbonGroupItems() const
RibbonGroupItem * groupItem(QAction *action) const
int count() const override
QWidget * lastWidget() const
获取最后生成的窗口
void invalidate() override
static int calcLargeHeight(const QRect &setrect, const RibbonGroup *group)
计算大图标的高度
void insertAction(int index, QAction *act, RibbonGroup::RowProportion rp=RibbonGroup::Auto)
RibbonGroup主要通过此函数来添加action
QLayoutItem * itemAt(int index) const override
void resetLargeToolButtonStyle()
重置大按钮的类型
static int s_groupTitleHeight
group标题栏的全局高度,默认为21
RibbonGroup::GroupLayoutMode m_groupLayoutMode
group的布局模式,默认为3行模式ThreeRowMode
static bool s_titleVisible
const QList< RibbonGroupItem * > & ribbonGroupItems() const
获取布局item
RibbonGroupLayout * m_layout
RibbonButton * lastAddedButton()
group 用于对 ribbon 页窗口中的控件进行分组
bool hasOptionAction() const
QAction * addSmallWidget(QWidget *w)
添加窗口,占用ribbon的一行
QAction * addSeparator(int top=6, int bottom=6)
添加分割线
void setGroupLayoutMode(GroupLayoutMode mode)
virtual void actionEvent(QActionEvent *event) override
处理action的事件
void addOptionAction(QAction *action)
添加操作action,如果要去除,传入Q_NULLPTR指针即可,RibbonGroup不会对QAction的所有权进行管理
static bool titleVisible()
static int groupTitleHeight()
定义所有的 group 的标题栏高度,有别于
void setActionRowProportion(QAction *action, RibbonGroup::RowProportion rp)
设置action的行行为,行属性决定了ribbon group的显示方式
RibbonButton * addSmallMenu(QMenu *menu, QToolButton::ToolButtonPopupMode popMode=QToolButton::InstantPopup)
QString groupName() const
static void setActionRowProportionProperty(QAction *action, RibbonGroup::RowProportion rp)
把action的行属性设置进action中,action自身携带了行属性
virtual QSize minimumSizeHint() const override
RibbonButton * ribbonButtonByIndex(int index) const
static void setGroupTitleHeight(int h)
设置 group 的全局高度,此函数是个全局的影响
QList< RibbonButton * > ribbonButtons() const
QAction * addMediumWidget(QWidget *w)
添加窗口,占用ribbon的一行
RibbonButton * addAction(QAction *action, RibbonGroup::RowProportion rp)
添加action
virtual void resizeEvent(QResizeEvent *event) override
void moveAction(int from, int to)
移动action
RibbonButton * ribbonButtonForAction(QAction *action) const
从group中把action对应的button提取出来,如果action没有对应的button,就返回Q_NULLPTR
void setTitle(const QString &title)
virtual QSize sizeHint() const override
void setExpanding(bool expanding=true)
把group设置为扩展模式,此时会撑大水平区域
RibbonButton * addSmallAction(QAction *action)
添加小图标
RibbonGroup(QWidget *parent=Q_NULLPTR)
bool isCanCustomize() const
bool isExpanding() const
判断此group是否为(水平)扩展模式
static RibbonGroup::RowProportion getActionRowProportionProperty(QAction *action)
获取action的行属性
int largeHeight() const
获取大图标的高度
RibbonButton * addMenu(QMenu *menu, RibbonGroup::RowProportion rp, QToolButton::ToolButtonPopupMode popMode=QToolButton::InstantPopup)
添加一个普通菜单
int ribbonButtonCount() const
RibbonButton * addActionMenu(QAction *action, QMenu *menu, RibbonGroup::RowProportion rp)
添加一个ActionMenu
GroupLayoutMode groupLayoutMode() const
QAction * addLargeWidget(QWidget *w)
添加窗口,占用所有行
RibbonGallery * addGallery()
RibbonGroup::addGallery
QAction * addWidget(QWidget *w, RibbonGroup::RowProportion rp)
添加窗口
void setCanCustomize(bool b)
RibbonButton * addLargeAction(QAction *action)
添加大图标
RibbonButton * addLargeActionMenu(QAction *action, QMenu *menu)
添加action menu,action menu是一个特殊的menu,即可点击触发action,也可弹出菜单
int actionIndex(QAction *act) const
action对应的布局index,此操作一般用于移动,其他意义不大
@ ThreeRowMode
三行布局模式,office就是三行布局模式,group能布置3行小toolbutton,默认模式
@ TwoRowMode
两行布局模式,wps的后续布局模式就是两行布局模式,group能布置2行小toolbutton
void setGroupName(const QString &title)
设置group的标题
static void setTitleVisible(bool visible)
@ Medium
中占比,在 RibbonGroup::groupLayoutMode 为 RibbonGroup::ThreeRowMode 时才会起作用, 且要同一列里两个都是 Medium 时,会在三行中占据两行
@ Small
小占比,占RibbonGroup的一行,Medium在不满足条件时也会变为Small,但不会变为Large
@ Large
大占比,一个widget的高度会充满整个group
RibbonButton * addLargeMenu(QMenu *menu, QToolButton::ToolButtonPopupMode popMode=QToolButton::InstantPopup)
RibbonButton * addMediumAction(QAction *action)
在三栏模式下,强制加为2栏action
virtual void paintEvent(QPaintEvent *event) override
virtual QSize optionActionButtonSize() const
void updateItemGeometry()
void paintEvent(QPaintEvent *event) override
RibbonSeparator(int height, QWidget *parent=Q_NULLPTR)
virtual QSize sizeHint() const override
void setTopBottomMargins(int top, int bottom)
#define QX_INIT_PRIVATE(Class)
#define Q_NULLPTR
Copyleft (C) 2025 maminjie canpool@163.com SPDX-License-Identifier: MulanPSL-2.0
#define QX_FINI_PRIVATE()
#define QX_RIBBON_END_NAMESPACE
#define QX_RIBBON_BEGIN_NAMESPACE
#define HELP_DRAW_RECT(p, rect)
#define QX_RIBBON_PROP_ROW_PROPORTION
#define RibbonElementStyleOpt