File indexing completed on 2024-12-22 04:13:15

0001 /*
0002  *  SPDX-FileCopyrightText: 2011 Silvio Heinrich <plassy@web.de>
0003  *
0004  *  SPDX-License-Identifier: GPL-2.0-or-later
0005  */
0006 
0007 #include "kis_widget_chooser.h"
0008 
0009 #include <kis_icon.h>
0010 
0011 #include <QGridLayout>
0012 #include <QHBoxLayout>
0013 #include <QToolButton>
0014 #include <QApplication>
0015 #include <QDesktopWidget>
0016 #include <QFrame>
0017 #include <QLabel>
0018 #include <QButtonGroup>
0019 #include <QStylePainter>
0020 #include <QStyleOption>
0021 
0022 #include "kis_config.h"
0023 
0024 KisWidgetChooser::KisWidgetChooser(int id, QWidget* parent)
0025     : QFrame(parent)
0026     , m_chooserid(id)
0027 {
0028     m_acceptIcon  = KisIconUtils::loadIcon("list-add");
0029     m_buttons     = new QButtonGroup();
0030     m_popup       = new QFrame(0, Qt::Popup);
0031     m_arrowButton = new QToolButton();
0032 
0033     m_popup->setFrameStyle(QFrame::Panel|QFrame::Raised);
0034     m_arrowButton->setFixedWidth(m_arrowButton->sizeHint().height());
0035     m_arrowButton->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Minimum);
0036     m_arrowButton->setAutoRaise(true);
0037     updateArrowIcon();
0038 
0039     connect(m_arrowButton, SIGNAL(clicked(bool)), SLOT(slotButtonPressed()));
0040 }
0041 
0042 KisWidgetChooser::~KisWidgetChooser()
0043 {
0044     delete m_buttons;
0045     delete m_popup;
0046     delete m_arrowButton;
0047 }
0048 
0049 void KisWidgetChooser::updateArrowIcon()
0050 {
0051     QImage image(16, 16, QImage::Format_ARGB32);
0052     image.fill(0);
0053 
0054     QStylePainter painter(&image, this);
0055     QStyleOption  option;
0056 
0057     option.rect    = image.rect();
0058     option.palette = palette();
0059     option.state   = QStyle::State_Enabled;
0060     option.palette.setBrush(QPalette::ButtonText, option.palette.text());
0061 
0062     painter.setBrush(option.palette.text().color());
0063     painter.setPen(option.palette.text().color());
0064     painter.drawPrimitive(QStyle::PE_IndicatorArrowDown, option);
0065     painter.end(); // Otherwise there will always be a copy
0066 
0067     m_arrowButton->setIcon(QIcon(QPixmap::fromImage(image)));
0068 }
0069 
0070 void KisWidgetChooser::addLabelWidget(const QString& id, const QString& label, QWidget* widget)
0071 {
0072     removeWidget(id);
0073 
0074     if (label.isEmpty()) {
0075         m_widgets.push_back(Data(id, widget, 0));
0076     }
0077     else {
0078         m_widgets.push_back(Data(id, widget, new QLabel(label)));
0079     }
0080 
0081     delete m_popup->layout();
0082     m_popup->setLayout(createPopupLayout());
0083     m_popup->adjustSize();
0084 
0085     delete QWidget::layout();
0086     QWidget::setLayout(createLayout());
0087 }
0088 
0089 QLayout* KisWidgetChooser::createLayout()
0090 {
0091     QHBoxLayout* layout = new QHBoxLayout();
0092     layout->setContentsMargins(0, 0, 0, 0);
0093     layout->setSpacing(0);
0094     layout->addWidget(m_arrowButton);
0095 
0096     for(Iterator i=m_widgets.begin(); i!=m_widgets.end(); ++i) {
0097         if(i->chosen) {
0098             if (i->label) {
0099                 layout->addWidget(i->label);
0100             }
0101             layout->addWidget(i->widget);
0102             break;
0103         }
0104     }
0105     return layout;
0106 }
0107 
0108 QLayout* KisWidgetChooser::createPopupLayout()
0109 {
0110     QGridLayout* layout = new QGridLayout();
0111     int          row    = 0;
0112     int          idx    = 0;
0113 
0114     layout->setContentsMargins(0, 0, 0, 0);
0115     layout->setSpacing(0);
0116 
0117     QButtonGroup*           group   = new QButtonGroup();
0118     QList<QAbstractButton*> buttons = m_buttons->buttons();
0119 
0120     for(Iterator i=m_widgets.begin(); i!=m_widgets.end(); ++i) {
0121         if(!i->chosen) {
0122             if(row == buttons.size()) {
0123                 QToolButton* bn = new QToolButton();
0124 
0125                 m_acceptIcon  = KisIconUtils::loadIcon("list-add");
0126                 bn->setIcon(m_acceptIcon);
0127                 bn->setAutoRaise(true);
0128                 buttons.push_back(bn);
0129             }
0130 
0131             if (i->label) {
0132                 layout->addWidget(i->label    , row, 0);
0133                 layout->addWidget(i->widget   , row, 1);
0134                 layout->addWidget(buttons[row], row, 2);
0135             }
0136             else {
0137                 layout->addWidget(i->widget   , row, 0);
0138                 layout->addWidget(buttons[row], row, 1);
0139             }
0140             group->addButton(buttons[row], idx);
0141             ++row;
0142         }
0143 
0144         ++idx;
0145     }
0146 
0147     for(int i=row; i<buttons.size(); ++i)
0148         delete buttons[i];
0149 
0150     delete m_buttons;
0151 
0152     m_buttons = group;
0153     connect(m_buttons, SIGNAL(buttonClicked(int)), SLOT(slotWidgetChosen(int)));
0154 
0155     return layout;
0156 }
0157 
0158 void KisWidgetChooser::removeWidget(const QString& id)
0159 {
0160     Iterator data = std::find(m_widgets.begin(), m_widgets.end(), Data(id));
0161 
0162     if(data != m_widgets.end()) {
0163         if(!data->chosen) {
0164             delete m_popup->layout();
0165             m_popup->setLayout(createPopupLayout());
0166             m_popup->adjustSize();
0167         }
0168         else delete QWidget::layout();
0169 
0170         if (data->label) {
0171             delete data->label;
0172         }
0173         delete data->widget;
0174         m_widgets.erase(data);
0175     }
0176 }
0177 
0178 QWidget* KisWidgetChooser::chooseWidget(const QString& id)
0179 {
0180     QWidget* chosenWidget = 0;
0181 
0182     for(Iterator i=m_widgets.begin(); i!=m_widgets.end(); ++i) {
0183         if(i->id == id) {
0184             chosenWidget = i->widget;
0185             i->chosen    = true;
0186         }
0187         else i->chosen = false;
0188     }
0189 
0190     delete m_popup->layout();
0191     m_popup->setLayout(createPopupLayout());
0192     m_popup->adjustSize();
0193 
0194     delete QWidget::layout();
0195     QWidget::setLayout(createLayout());
0196 
0197     KisConfig cfg(false);
0198     cfg.setToolbarSlider(m_chooserid, id);
0199 
0200     return chosenWidget;
0201 }
0202 
0203 QWidget* KisWidgetChooser::getWidget(const QString& id) const
0204 {
0205     ConstIterator data = std::find(m_widgets.begin(), m_widgets.end(), Data(id));
0206 
0207     if(data != m_widgets.end())
0208         return data->widget;
0209 
0210     return 0;
0211 }
0212 
0213 void KisWidgetChooser::showPopupWidget()
0214 {
0215     QSize popSize = m_popup->size();
0216     QRect popupRect(QFrame::mapToGlobal(QPoint(-1, QFrame::height())), popSize);
0217 
0218     // Get the available geometry of the screen which contains this KisPopupButton
0219     QRect screenRect = QApplication::desktop()->availableGeometry(this);
0220 
0221     // Make sure the popup is not drawn outside the screen area
0222     if(popupRect.right() > screenRect.right())
0223         popupRect.translate(screenRect.right() - popupRect.right(), 0);
0224     if(popupRect.left() < screenRect.left())
0225         popupRect.translate(screenRect.left() - popupRect.left(), 0);
0226     if(popupRect.bottom() > screenRect.bottom())
0227         popupRect.translate(0, -popupRect.height());
0228 
0229     m_popup->setGeometry(popupRect);
0230     m_popup->show();
0231 }
0232 
0233 
0234 void KisWidgetChooser::updateThemedIcons()
0235 {
0236     for (int i = 0; i < m_buttons->buttons().length(); i++) {
0237          if ( m_buttons->button(i)) {
0238               m_buttons->button(i)->setIcon(KisIconUtils::loadIcon("list-add"));
0239          }
0240     }
0241 }
0242 
0243 void KisWidgetChooser::slotButtonPressed()
0244 {
0245     showPopupWidget();
0246 }
0247 
0248 void KisWidgetChooser::slotWidgetChosen(int index)
0249 {
0250     chooseWidget(m_widgets[index].id);
0251     m_popup->hide();
0252 }
0253 
0254 
0255 void KisWidgetChooser::changeEvent(QEvent *e)
0256 {
0257     QFrame::changeEvent(e);
0258 
0259     switch (e->type()) {
0260     case QEvent::StyleChange:
0261     case QEvent::PaletteChange:
0262     case QEvent::EnabledChange:
0263         updateArrowIcon();
0264         break;
0265     default:
0266         ;
0267     }
0268 }