493 lines
13 KiB
C++
493 lines
13 KiB
C++
#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)
|
||
{
|
||
}
|
||
|
||
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);
|
||
}
|
||
}
|
||
}
|
||
}
|