File indexing completed on 2024-05-12 04:58:28

0001 /* ============================================================
0002 * Falkon - Qt web browser
0003 * Copyright (C) 2010-2018 David Rosca <nowrep@gmail.com>
0004 *
0005 * This program is free software: you can redistribute it and/or modify
0006 * it under the terms of the GNU General Public License as published by
0007 * the Free Software Foundation, either version 3 of the License, or
0008 * (at your option) any later version.
0009 *
0010 * This program is distributed in the hope that it will be useful,
0011 * but WITHOUT ANY WARRANTY; without even the implied warranty of
0012 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
0013 * GNU General Public License for more details.
0014 *
0015 * You should have received a copy of the GNU General Public License
0016 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
0017 * ============================================================ */
0018 #include "toolbutton.h"
0019 
0020 #include <QMenu>
0021 #include <QStyle>
0022 #include <QPainter>
0023 #include <QMouseEvent>
0024 #include <QApplication>
0025 #include <QStyleOptionToolButton>
0026 
0027 ToolButton::ToolButton(QWidget* parent)
0028     : QToolButton(parent)
0029     , m_menu(nullptr)
0030 {
0031     setMinimumWidth(16);
0032 
0033     QStyleOptionToolButton opt;
0034     initStyleOption(&opt);
0035 
0036     m_pressTimer.setSingleShot(true);
0037     m_pressTimer.setInterval(QApplication::style()->styleHint(QStyle::SH_ToolButton_PopupDelay, &opt, this));
0038     connect(&m_pressTimer, SIGNAL(timeout()), this, SLOT(showMenu()));
0039 }
0040 
0041 QImage ToolButton::multiIcon() const
0042 {
0043     return m_multiIcon;
0044 }
0045 
0046 void ToolButton::setMultiIcon(const QImage &image)
0047 {
0048     m_options |= MultiIconOption;
0049     m_multiIcon = image;
0050     setFixedSize(m_multiIcon.width(), m_multiIcon.height() / 4);
0051 
0052     update();
0053 }
0054 
0055 QString ToolButton::themeIcon() const
0056 {
0057     return m_themeIcon;
0058 }
0059 
0060 void ToolButton::setThemeIcon(const QString &icon)
0061 {
0062     const QIcon ic = QIcon::fromTheme(icon);
0063     if (!ic.isNull()) {
0064         m_themeIcon = icon;
0065         setIcon(QIcon::fromTheme(m_themeIcon));
0066     }
0067 }
0068 
0069 QIcon ToolButton::fallbackIcon() const
0070 {
0071     return icon();
0072 }
0073 
0074 void ToolButton::setFallbackIcon(const QIcon &fallbackIcon)
0075 {
0076     if (icon().isNull())
0077         setIcon(fallbackIcon);
0078 }
0079 
0080 QIcon ToolButton::icon() const
0081 {
0082     return QToolButton::icon();
0083 }
0084 
0085 void ToolButton::setIcon(const QIcon &icon)
0086 {
0087     if (m_options & MultiIconOption)
0088         setFixedSize(sizeHint());
0089 
0090     m_options &= ~MultiIconOption;
0091     QToolButton::setIcon(icon);
0092 }
0093 
0094 QMenu* ToolButton::menu() const
0095 {
0096     return m_menu;
0097 }
0098 
0099 void ToolButton::setMenu(QMenu* menu)
0100 {
0101     Q_ASSERT(menu);
0102 
0103     if (m_menu)
0104         disconnect(m_menu, &QMenu::aboutToHide, this, &ToolButton::menuAboutToHide);
0105 
0106     m_menu = menu;
0107     connect(m_menu, &QMenu::aboutToHide, this, &ToolButton::menuAboutToHide);
0108 }
0109 
0110 bool ToolButton::showMenuInside() const
0111 {
0112     return m_options & ShowMenuInsideOption;
0113 }
0114 
0115 void ToolButton::setShowMenuInside(bool enable)
0116 {
0117     if (enable)
0118         m_options |= ShowMenuInsideOption;
0119     else
0120         m_options &= ~ShowMenuInsideOption;
0121 }
0122 
0123 bool ToolButton::showMenuOnRightClick() const
0124 {
0125     return m_options & ShowMenuOnRightClick;
0126 }
0127 
0128 void ToolButton::setShowMenuOnRightClick(bool enable)
0129 {
0130     m_options.setFlag(ShowMenuOnRightClick, enable);
0131 }
0132 
0133 bool ToolButton::toolbarButtonLook() const
0134 {
0135     return m_options & ToolBarLookOption;
0136 }
0137 
0138 void ToolButton::setToolbarButtonLook(bool enable)
0139 {
0140     if (enable) {
0141         m_options |= ToolBarLookOption;
0142 
0143         QStyleOption opt;
0144         opt.initFrom(this);
0145         int size = style()->pixelMetric(QStyle::PM_ToolBarIconSize, &opt, this);
0146         setIconSize(QSize(size, size));
0147     }
0148     else {
0149         m_options &= ~ToolBarLookOption;
0150     }
0151 
0152     setProperty("toolbar-look", QVariant(enable));
0153     style()->unpolish(this);
0154     style()->polish(this);
0155 }
0156 
0157 void ToolButton::menuAboutToHide()
0158 {
0159     setDown(false);
0160     Q_EMIT aboutToHideMenu();
0161 }
0162 
0163 void ToolButton::showMenu()
0164 {
0165     if (!m_menu || m_menu->isVisible())
0166         return;
0167 
0168     Q_EMIT aboutToShowMenu();
0169 
0170     QPoint pos;
0171 
0172     if (m_options & ShowMenuInsideOption) {
0173         pos = mapToGlobal(rect().bottomRight());
0174         if (QApplication::layoutDirection() == Qt::RightToLeft)
0175             pos.setX(pos.x() - rect().width());
0176         else
0177             pos.setX(pos.x() - m_menu->sizeHint().width());
0178     }
0179     else {
0180         pos = mapToGlobal(rect().bottomLeft());
0181     }
0182 
0183     m_menu->popup(pos);
0184 }
0185 
0186 void ToolButton::mousePressEvent(QMouseEvent* e)
0187 {
0188     if (e->buttons() == Qt::LeftButton && popupMode() == QToolButton::DelayedPopup)
0189         m_pressTimer.start();
0190 
0191     if (e->buttons() == Qt::LeftButton && menu() && popupMode() == QToolButton::InstantPopup) {
0192         setDown(true);
0193         showMenu();
0194     }
0195     else if (e->buttons() == Qt::RightButton && menu() && m_options & ShowMenuOnRightClick) {
0196         setDown(true);
0197         showMenu();
0198     } else {
0199         QToolButton::mousePressEvent(e);
0200     }
0201 }
0202 
0203 void ToolButton::mouseReleaseEvent(QMouseEvent* e)
0204 {
0205     m_pressTimer.stop();
0206 
0207     if (e->button() == Qt::MiddleButton && rect().contains(e->pos())) {
0208         Q_EMIT middleMouseClicked();
0209         setDown(false);
0210     }
0211     else if (e->button() == Qt::LeftButton && rect().contains(e->pos()) && e->modifiers() == Qt::ControlModifier) {
0212         Q_EMIT controlClicked();
0213         setDown(false);
0214     } else {
0215         QToolButton::mouseReleaseEvent(e);
0216     }
0217 }
0218 
0219 void ToolButton::mouseDoubleClickEvent(QMouseEvent* e)
0220 {
0221     QToolButton::mouseDoubleClickEvent(e);
0222 
0223     m_pressTimer.stop();
0224 
0225     if (e->buttons() == Qt::LeftButton) {
0226         Q_EMIT doubleClicked();
0227     }
0228 }
0229 
0230 void ToolButton::contextMenuEvent(QContextMenuEvent *e)
0231 {
0232     // Block to prevent showing both context menu and button menu
0233     if (menu() && m_options & ShowMenuOnRightClick)
0234         return;
0235 
0236     QToolButton::contextMenuEvent(e);
0237 }
0238 
0239 void ToolButton::paintEvent(QPaintEvent* e)
0240 {
0241     if (!(m_options & MultiIconOption)) {
0242         QToolButton::paintEvent(e);
0243         return;
0244     }
0245 
0246     QPainter p(this);
0247 
0248     const int w = m_multiIcon.width();
0249     const int h4 = m_multiIcon.height() / 4;
0250 
0251     if (!isEnabled())
0252         p.drawImage(0, 0, m_multiIcon, 0, h4 * 3, w, h4);
0253     else if (isDown())
0254         p.drawImage(0, 0, m_multiIcon, 0, h4 * 2, w, h4);
0255     else if (underMouse())
0256         p.drawImage(0, 0, m_multiIcon, 0, h4 * 1, w, h4);
0257     else
0258         p.drawImage(0, 0, m_multiIcon, 0, h4 * 0, w, h4);
0259 }