10#include <QStyleOption>
11#include <QStyleOptionFocusRect>
12#include <QStyleOptionToolButton>
13#include <QStylePainter>
14#include <QApplication>
20class QxToolButtonPrivate
23 QxToolButtonPrivate();
25 QStyle *style()
const;
26 QStyle::PrimitiveElement indicatorArrowType()
const;
27 int pixelMetric(QStyle::PixelMetric metric,
const QStyleOption *toolbutton,
const QWidget *widget)
const;
29 void drawArrow(
const QStyleOptionToolButton *toolbutton,
const QRect &rect, QPainter *painter,
30 const QWidget *w)
const;
32 void splitString(
const QString &str, QString &strFirstRow, QString &strSecondRow)
const;
33 void drawToolButton(
const QStyleOptionToolButton *opt, QPainter *p,
const QWidget *widget);
34 void drawToolButtonLabel(
const QStyleOption *opt, QPainter *p,
const QWidget *w);
35 QRect subControlRect(QStyle::ComplexControl cc,
const QStyleOptionComplex *opt, QStyle::SubControl sc,
36 const QWidget *widget)
const;
38 bool hasMenu(
const QStyleOptionToolButton *toolbutton)
const;
40 Qt::ArrowType m_menuArrowType;
41 QxToolButton::MenuArea m_menuArea;
47 bool m_forceDefaultShowMenu;
50QxToolButtonPrivate::QxToolButtonPrivate()
51 : m_menuArrowType(Qt::DownArrow)
52 , m_menuArea(QxToolButton::BottomMenuArea)
55 , m_forceDefaultShowMenu(false)
59QStyle *QxToolButtonPrivate::style()
const
64QStyle::PrimitiveElement QxToolButtonPrivate::indicatorArrowType()
const
66 switch (m_menuArrowType) {
68 return QStyle::PE_IndicatorArrowLeft;
70 return QStyle::PE_IndicatorArrowRight;
72 return QStyle::PE_IndicatorArrowUp;
75 return QStyle::PE_IndicatorArrowDown;
79int QxToolButtonPrivate::pixelMetric(QStyle::PixelMetric metric,
const QStyleOption *opt,
const QWidget *widget)
const
82 int mbi = style()->pixelMetric(metric, opt, widget);
89void QxToolButtonPrivate::drawArrow(
const QStyleOptionToolButton *toolbutton,
const QRect &rect, QPainter *p,
90 const QWidget *w)
const
92 QStyle::PrimitiveElement pe;
94 switch (toolbutton->arrowType) {
96 pe = QStyle::PE_IndicatorArrowLeft;
99 pe = QStyle::PE_IndicatorArrowRight;
102 pe = QStyle::PE_IndicatorArrowUp;
105 pe = QStyle::PE_IndicatorArrowDown;
111 QStyleOptionToolButton arrowOpt;
112 arrowOpt.rect = rect;
113 arrowOpt.palette = toolbutton->palette;
114 arrowOpt.state = toolbutton->state;
115 style()->drawPrimitive(pe, &arrowOpt, p, w);
118void QxToolButtonPrivate::splitString(
const QString &str, QString &strFirstRow, QString &strSecondRow)
const
121 strSecondRow.clear();
123 QStringList strList = str.split(
'\n');
124 if (strList.count() == 1) {
127 strFirstRow = strList.at(0);
128 strSecondRow = strList.at(1);
131void QxToolButtonPrivate::drawToolButton(
const QStyleOptionToolButton *opt, QPainter *p,
const QWidget *widget)
133 const QStyleOptionToolButton *toolbutton = opt;
135 menuarea = subControlRect(QStyle::CC_ToolButton, toolbutton, QStyle::SC_ToolButtonMenu, widget);
137 QStyle::State bflags = toolbutton->state & ~QStyle::State_Sunken;
138 if (bflags & QStyle::State_AutoRaise) {
139 if (!(bflags & QStyle::State_MouseOver) || !(bflags & QStyle::State_Enabled))
140 bflags &= ~QStyle::State_Raised;
142 QStyle::State mflags = bflags;
143 if (toolbutton->state & QStyle::State_Sunken) {
144 if (toolbutton->activeSubControls & QStyle::SC_ToolButton)
145 bflags |= QStyle::State_Sunken;
146 mflags |= QStyle::State_Sunken;
150 style()->drawPrimitive(QStyle::PE_PanelButtonTool, toolbutton, p, widget);
152 if (toolbutton->state & QStyle::State_HasFocus) {
153 QStyleOptionFocusRect fr;
154 fr.QStyleOption::operator=(*toolbutton);
155 fr.rect.adjust(3, 3, -3, -3);
156 if (toolbutton->features & QStyleOptionToolButton::MenuButtonPopup)
157 fr.rect.adjust(0, 0, -pixelMetric(QStyle::PM_MenuButtonIndicator, toolbutton, widget), 0);
158 style()->drawPrimitive(QStyle::PE_FrameFocusRect, &fr, p, widget);
162 QStyleOptionToolButton label = *toolbutton;
163 label.state = bflags;
164 drawToolButtonLabel(&label, p, widget);
167 if (toolbutton->subControls & QStyle::SC_ToolButtonMenu) {
168 QStyleOption tool(0);
169 tool.palette = toolbutton->palette;
174 if (toolbutton->toolButtonStyle == Qt::ToolButtonTextUnderIcon && m_menuArea == QxToolButton::BottomMenuArea) {
175 QString strFirstRow, strSecondRow;
176 splitString(toolbutton->text, strFirstRow, strSecondRow);
177 int height = toolbutton->fontMetrics.height();
180 QRect(QPoint(strSecondRow.isEmpty() ? toolbutton->rect.width() / 2 - 2 : toolbutton->rect.right() - 7,
181 m_textRect.top() + height * 3 / 2 - mbi / 2),
184 int mbi = pixelMetric(QStyle::PM_MenuButtonIndicator, toolbutton, widget);
185 rcArrow = QRect(ir.right() - mbi - 1,
186 toolbutton->rect.top() + (ir.height() - mbi) / 2 + ((ir.height() - mbi) % 2), mbi, mbi);
190 style()->drawPrimitive(indicatorArrowType(), &tool, p, widget);
191 }
else if (toolbutton->features & QStyleOptionToolButton::HasMenu) {
192 QStyleOptionToolButton newBtn = *toolbutton;
193 if (toolbutton->toolButtonStyle == Qt::ToolButtonTextUnderIcon && m_menuArea == QxToolButton::BottomMenuArea) {
194 QString strFirstRow, strSecondRow;
195 splitString(toolbutton->text, strFirstRow, strSecondRow);
196 int height = toolbutton->fontMetrics.height();
199 QRect(QPoint(strSecondRow.isEmpty() ? toolbutton->rect.width() / 2 - 2 : toolbutton->rect.right() - 8,
200 m_textRect.top() + height * 3 / 2 - mbi / 2),
204 int mbi = pixelMetric(QStyle::PM_MenuButtonIndicator, toolbutton, widget);
205 newBtn.rect = QRect(ir.right() - mbi - 1,
206 toolbutton->rect.top() + (ir.height() - mbi) / 2 + ((ir.height() - mbi) % 2), mbi, mbi);
208 style()->drawPrimitive(indicatorArrowType(), &newBtn, p, widget);
212void QxToolButtonPrivate::drawToolButtonLabel(
const QStyleOption *opt, QPainter *p,
const QWidget *w)
214 const QStyleOptionToolButton *toolbutton = qstyleoption_cast<const QStyleOptionToolButton *>(opt);
215 QRect rect = toolbutton->rect;
216 p->setFont(toolbutton->font);
218 m_iconRect = QRect();
219 m_textRect = QRect();
222 bool hasArrow = toolbutton->features & QStyleOptionToolButton::Arrow;
223 if (((!hasArrow && toolbutton->icon.isNull()) && !toolbutton->text.isEmpty()) ||
224 toolbutton->toolButtonStyle == Qt::ToolButtonTextOnly) {
225 int alignment = Qt::AlignCenter | Qt::TextShowMnemonic;
226 if (!style()->styleHint(QStyle::SH_UnderlineShortcut, opt, w))
227 alignment |= Qt::TextHideMnemonic;
228 QRect rectText = rect;
229 if (hasMenu(toolbutton)) {
230 int mbi = pixelMetric(QStyle::PM_MenuButtonIndicator, opt, w);
231 rectText.adjust(0, 0, -mbi, 0);
233 m_textRect = rectText;
234 style()->drawItemText(p, rect, alignment, toolbutton->palette, opt->state & QStyle::State_Enabled,
235 toolbutton->text, QPalette::ButtonText);
238 QSize pmSize = toolbutton->iconSize;
239 if (pmSize.width() > qMin(rect.width(), rect.height())) {
240 const int iconExtent = style()->pixelMetric(QStyle::PM_SmallIconSize);
241 pmSize = QSize(iconExtent, iconExtent);
244 if (!toolbutton->icon.isNull()) {
245 QIcon::State state = toolbutton->state & QStyle::State_On ? QIcon::On : QIcon::Off;
247 if (!(toolbutton->state & QStyle::State_Enabled)) {
248 mode = QIcon::Disabled;
249 }
else if ((opt->state & QStyle::State_MouseOver) && (opt->state & QStyle::State_AutoRaise)) {
250 mode = QIcon::Active;
252 mode = QIcon::Normal;
254 pm = toolbutton->icon.pixmap(toolbutton->rect.size().boundedTo(pmSize), mode, state);
255 pmSize = pm.size() / pm.devicePixelRatio();
258 if (toolbutton->toolButtonStyle != Qt::ToolButtonIconOnly) {
259 p->setFont(toolbutton->font);
260 QRect pr = rect, tr = rect;
262 int alignment = Qt::TextShowMnemonic;
263 if (!style()->styleHint(QStyle::SH_UnderlineShortcut, opt, w))
264 alignment |= Qt::TextHideMnemonic;
266 if (toolbutton->toolButtonStyle == Qt::ToolButtonTextUnderIcon) {
267 pr.setHeight(pmSize.height() + 6);
268 tr.adjust(0, pr.height() - 1, 0, -3);
270 style()->drawItemPixmap(p, pr, Qt::AlignCenter, pm);
272 drawArrow(toolbutton, pr, p, w);
274 alignment |= Qt::AlignCenter;
276 pr.setWidth(pmSize.width() + 8);
277 tr.adjust(pr.width(), 0, 0, 0);
279 style()->drawItemPixmap(p, QStyle::visualRect(opt->direction, rect, pr), Qt::AlignCenter, pm);
281 drawArrow(toolbutton, pr, p, w);
283 alignment |= Qt::AlignLeft | Qt::AlignVCenter;
286 QRect rcText(QStyle::visualRect(opt->direction, rect, tr));
287 if (toolbutton->toolButtonStyle == Qt::ToolButtonTextUnderIcon) {
288 QString strFirstRow, strSecondRow;
289 splitString(toolbutton->text, strFirstRow, strSecondRow);
291 int height = toolbutton->fontMetrics.height();
293 QRect rcFirstRowText(QPoint(rcText.left(), rcText.top() + 1),
294 QPoint(rcText.right(), rcText.top() + height + 1));
297 if (m_menuArea != QxToolButton::BottomMenuArea && strSecondRow.isEmpty()) {
298 rcFirstRowText = rcText;
301 if (!strFirstRow.isEmpty()) {
302 style()->drawItemText(p, rcFirstRowText, alignment, toolbutton->palette,
303 toolbutton->state & QStyle::State_Enabled, strFirstRow, QPalette::ButtonText);
306 if (!strSecondRow.isEmpty()) {
307 int left = rcText.left();
308 if (toolbutton->subControls & QStyle::SC_ToolButtonMenu ||
309 toolbutton->features & QStyleOptionToolButton::HasMenu)
310 left = opt->rect.left() - 5;
313 QRect rcSecondRowText(QPoint(left, rcText.top() + height + 1),
314 QPoint(rcText.right(), rcText.top() + height * 2 + 2));
315 style()->drawItemText(p, rcSecondRowText, alignment, toolbutton->palette,
316 toolbutton->state & QStyle::State_Enabled, strSecondRow,
317 QPalette::ButtonText);
320 style()->drawItemText(p, rcText, alignment, toolbutton->palette,
321 toolbutton->state & QStyle::State_Enabled, toolbutton->text,
322 QPalette::ButtonText);
328 if (hasMenu(toolbutton)) {
329 int mbi = pixelMetric(QStyle::PM_MenuButtonIndicator, opt, w);
330 pr.setWidth(pr.width() - mbi);
334 drawArrow(toolbutton, rect, p, w);
336 QRect ir = m_forceCenter ? rect : m_iconRect;
337 style()->drawItemPixmap(p, ir, Qt::AlignCenter, pm);
343QRect QxToolButtonPrivate::subControlRect(QStyle::ComplexControl cc,
const QStyleOptionComplex *opt,
344 QStyle::SubControl sc,
const QWidget *widget)
const
347 case QStyle::CC_ToolButton:
348 if (
const QStyleOptionToolButton *tb = qstyleoption_cast<const QStyleOptionToolButton *>(opt)) {
349 int mbi = pixelMetric(QStyle::PM_MenuButtonIndicator, tb, widget);
350 QRect ret = tb->rect;
352 case QStyle::SC_ToolButton:
353 if ((tb->features & (QStyleOptionToolButton::MenuButtonPopup | QStyleOptionToolButton::PopupDelay)) ==
354 QStyleOptionToolButton::MenuButtonPopup)
355 ret.adjust(0, 0, -mbi, 0);
357 case QStyle::SC_ToolButtonMenu:
358 if ((tb->features & (QStyleOptionToolButton::MenuButtonPopup | QStyleOptionToolButton::PopupDelay)) ==
359 QStyleOptionToolButton::MenuButtonPopup)
360 ret.adjust(ret.width() - mbi - 2, 0, 0, 0);
365 return style()->visualRect(tb->direction, tb->rect, ret);
371 return style()->subControlRect(cc, opt, sc, widget);
374bool QxToolButtonPrivate::hasMenu(
const QStyleOptionToolButton *toolbutton)
const
376 if ((toolbutton->subControls & QStyle::SC_ToolButtonMenu) ||
377 (toolbutton->features & QStyleOptionToolButton::HasMenu)) {
383QxToolButton::QxToolButton(QWidget *parent)
384 : QToolButton(parent)
385 , d(new QxToolButtonPrivate())
388 setAttribute(Qt::WA_StyledBackground,
true);
390 setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Preferred);
413 return d->m_menuArrowType;
418 if (d->m_menuArrowType == type) {
421 d->m_menuArrowType = type;
429 return d->m_menuArea;
434 if (d->m_menuArea == area || toolButtonStyle() != Qt::ToolButtonTextUnderIcon) {
437 d->m_menuArea = area;
445 QSize sz = QToolButton::sizeHint();
446 QStyleOptionToolButton opt;
447 initStyleOption(&opt);
451 QString textButton = opt.text;
453 if (opt.toolButtonStyle != Qt::ToolButtonTextOnly) {
454 QSize icon = opt.iconSize;
455 QAction *action = defaultAction();
456 if (action && !action->icon().isNull())
457 icon = action->icon().actualSize(opt.iconSize);
462 bool indicatorCenter =
false;
464 QToolButton::ToolButtonPopupMode mode = QToolButton::popupMode();
466 if (opt.toolButtonStyle != Qt::ToolButtonIconOnly) {
467 if (opt.toolButtonStyle == Qt::ToolButtonTextUnderIcon) {
468 QString strFirstRow, strSecondRow;
469 d->splitString(textButton, strFirstRow, strSecondRow);
472 if (!strFirstRow.isEmpty())
473 textFirstSize = opt.fontMetrics.size(Qt::TextShowMnemonic, strFirstRow);
475 if (!strSecondRow.isEmpty()) {
476 QSize textSecondSize = opt.fontMetrics.size(Qt::TextShowMnemonic, strSecondRow);
477 textFirstSize.setWidth(qMax(textFirstSize.width(), textSecondSize.width()));
481 if (isBottomMenuArea && strSecondRow.isEmpty()) {
482 indicatorCenter = opt.features & QStyleOptionToolButton::HasMenu;
483 h += opt.fontMetrics.height();
487 if (textFirstSize.width() > w)
488 w = textFirstSize.width();
490 w += mode == QToolButton::MenuButtonPopup ? 4 : 10;
493 QSize textSize = opt.fontMetrics.size(Qt::TextShowMnemonic, textButton);
494#if QT_VERSION < QT_VERSION_CHECK(5, 11, 0)
495 textSize.setWidth(textSize.width() + opt.fontMetrics.width(QLatin1Char(
' ')) * 2);
497 textSize.setWidth(textSize.width() + opt.fontMetrics.horizontalAdvance(QLatin1Char(
' ')) * 2);
501 if (opt.toolButtonStyle == Qt::ToolButtonTextBesideIcon) {
502 w += textSize.width() + 6;
504 if (textSize.height() > h)
505 h = textSize.height();
507 w = textSize.width() + 4;
514 if (d->hasMenu(&opt)) {
519 opt.rect.setSize(QSize(w, h));
521 if ((mode == QToolButton::MenuButtonPopup || d->hasMenu(&opt)) && !indicatorCenter) {
522 int mbi = d->pixelMetric(QStyle::PM_MenuButtonIndicator, &opt,
this);
525 if ((opt.toolButtonStyle != Qt::ToolButtonTextBesideIcon &&
526 opt.toolButtonStyle != Qt::ToolButtonTextUnderIcon) ||
527 (!isBottomMenuArea && opt.toolButtonStyle == Qt::ToolButtonTextUnderIcon)) {
528 if (d->m_forceCenter) {
534#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
535 return QSize(w, h).expandedTo(QApplication::globalStrut());
543 if (d->m_forceCenter == b) {
546 d->m_forceCenter = b;
555 if (d->m_forceDefaultShowMenu == b) {
558 d->m_forceDefaultShowMenu = b;
563 QToolButton::setToolButtonStyle(style);
564 if (style == Qt::ToolButtonTextUnderIcon) {
577 QStyleOptionToolButton opt;
578 initStyleOption(&opt);
580 opt.state |= QStyle::State_Sunken | QStyle::State_Raised;
582 d->drawToolButton(&opt, &p,
this);
587 if (e->button() == Qt::LeftButton && popupMode() == MenuButtonPopup) {
588 if (d->m_forceDefaultShowMenu) {
589 QRect outRect = d->m_iconRect;
590 if (toolButtonStyle() == Qt::ToolButtonTextOnly) {
591 outRect = d->m_textRect;
593 if (outRect.isValid() && !outRect.contains(e->pos())) {
599 if (d->m_menuArea ==
RightMenuArea && d->m_menuArrowType == Qt::RightArrow) {
600 QStyleOptionToolButton opt;
601 initStyleOption(&opt);
602 QRect popupr = d->subControlRect(QStyle::CC_ToolButton, &opt, QStyle::SC_ToolButtonMenu,
this);
603 if (popupr.isValid() && popupr.contains(e->pos())) {
604 QAction *action = defaultAction();
605 if (action && action->menu()) {
606 d->m_showMenu =
true;
609 pos.setX(pos.x() - e->pos().x() + width());
610 pos.setY(pos.y() - e->pos().y());
611 action->menu()->exec(pos);
612 d->m_showMenu =
false;
620 QToolButton::mousePressEvent(e);
QPoint globalMousePos(const QMouseEvent *event)
#define QX_APP_END_NAMESPACE
#define QX_APP_BEGIN_NAMESPACE