instAdmin/Cpp/GisDes/SaRibbon/SARibbonBar/SARibbonPannelLayout.cpp

953 lines
34 KiB
C++
Raw Normal View History

2024-10-29 22:24:50 +08:00
#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 actionnullptr指针即可SARibbonPannel不会对QAction的所有权进行管理
* @param action
* @note OptionAction直接传入nullptr即可
* @note SARibbonPannel不对QAction的destroy进行关联action进行deletenullptr给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)
*
* QActionSARibbonToolButtonSARibbonToolButton的类型参考SARibbonPannelItem::RowProportion
* @param action
* @param rp
* @return SARibbonPannelItem
* @note SARibbonPannelItem最终都会携带一个widgetQWidgetAction的话使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();
}