File indexing completed on 2024-05-12 16:02:04

0001 /*
0002  * SPDX-FileCopyrightText: 2021 Agata Cacko <cacko.azh@gmail.com>
0003  * SPDX-FileCopyrightText: 2021 L. E. Segovia <amy@amyspark.me>
0004  *
0005  * SPDX-License-Identifier: LGPL-2.0-or-later
0006  */
0007 
0008 #include "KisTagSelectionWidget.h"
0009 
0010 #include <QProcessEnvironment>
0011 #include <QFileInfo>
0012 #include <QMessageBox>
0013 #include <QStandardPaths>
0014 #include <QGridLayout>
0015 #include <QTableWidget>
0016 #include <QPainter>
0017 #include <QListWidget>
0018 #include <QAction>
0019 #include <QMouseEvent>
0020 #include <QMenu>
0021 #include <QPair>
0022 #include <QApplication>
0023 #include <QInputDialog>
0024 #include <QPainterPath>
0025 
0026 #include <KoFileDialog.h>
0027 #include <kis_icon.h>
0028 #include <KoID.h>
0029 
0030 #include <kis_debug.h>
0031 #include <kis_global.h>
0032 #include <TagActions.h>
0033 
0034 #include <KisWrappableHBoxLayout.h>
0035 #include <kis_signals_blocker.h>
0036 
0037 
0038 #include "kis_icon.h"
0039 
0040 
0041 WdgCloseableLabel::WdgCloseableLabel(KoID tag, bool editable, bool semiSelected, QWidget *parent)
0042     : QWidget(parent)
0043     , m_editble(editable)
0044     , m_semiSelected(semiSelected)
0045     , m_tag(tag)
0046 {
0047     QHBoxLayout *layout = new QHBoxLayout(this);
0048     layout->setContentsMargins(8, 0, 0, 0);
0049     layout->setSpacing(2);
0050 
0051     m_textLabel = new QLabel(parent);
0052     m_textLabel->setText(tag.name());
0053     m_textLabel->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Fixed);
0054     layout->addWidget(m_textLabel);
0055     layout->insertStretch(2, 1);
0056     if (m_editble) {
0057         m_closeIconLabel = new QPushButton(parent);
0058         m_closeIconLabel->setFlat(true);
0059         m_closeIconLabel->setIcon(KisIconUtils::loadIcon("docker_close"));
0060         m_closeIconLabel->setToolTip(i18n("Remove from tag"));
0061         m_closeIconLabel->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Preferred);
0062         m_closeIconLabel->setEnabled(m_editble);
0063         m_closeIconLabel->setMaximumSize(QSize(1, 1) * m_size);
0064 
0065         connect(m_closeIconLabel, &QAbstractButton::clicked, [&]() {
0066             emit sigRemoveTagFromSelection(m_tag);
0067         });
0068         layout->addWidget(m_closeIconLabel);
0069     }
0070     setLayout(layout);
0071 }
0072 
0073 WdgCloseableLabel::~WdgCloseableLabel()
0074 {
0075 
0076 }
0077 
0078 void WdgCloseableLabel::paintEvent(QPaintEvent *event)
0079 {
0080     QPainter painter(this);
0081 
0082     QColor backGroundColor = qApp->palette().light().color();
0083     QColor foregroundColor = qApp->palette().windowText().color();
0084     qreal r1 = 0.65;
0085     qreal r2 = 1 - r1;
0086     QColor outlineColor = QColor::fromRgb(256*(r1*backGroundColor.redF() + r2*foregroundColor.redF()),
0087                                           256*(r1*backGroundColor.greenF() + r2*foregroundColor.greenF()),
0088                                           256*(r1*backGroundColor.blueF() + r2*foregroundColor.blueF()));
0089 
0090 
0091     QBrush windowB = qApp->palette().window();
0092     QBrush windowTextB = qApp->palette().windowText();
0093 
0094     QWidget::paintEvent(event);
0095     painter.setRenderHint(QPainter::Antialiasing);
0096     QPainterPath path;
0097     path.addRoundedRect(this->rect(), 6, 6);
0098 
0099     // good color:
0100     painter.fillPath(path, qApp->palette().light());
0101 
0102     if (m_semiSelected) {
0103 
0104         QPen penwt = QPen(outlineColor, 1);
0105         penwt.setStyle(Qt::DashLine);
0106 
0107         QPainterPath outlinePath;
0108         outlinePath.addRoundedRect(this->rect().adjusted(1, 1, -1, -1), 4, 4);
0109 
0110         painter.setPen(penwt);
0111         painter.drawPath(outlinePath);
0112     }
0113 
0114 }
0115 
0116 WdgAddTagButton::WdgAddTagButton(QWidget *parent)
0117     : QToolButton(parent)
0118 {
0119     setPopupMode(QToolButton::InstantPopup);
0120     setIcon(KisIconUtils::loadIcon("list-add"));
0121     setToolTip(i18n("Assign to tag"));
0122     setContentsMargins(0, 0, 0, 0);
0123     QSize defaultSize = QSize(1, 1)*m_size;
0124     setMinimumSize(defaultSize);
0125     setMaximumSize(defaultSize);
0126 
0127     connect(this, SIGNAL(triggered(QAction*)), SLOT(slotAddNewTag(QAction*)));
0128 
0129     UserInputTagAction *newTag = new UserInputTagAction(this);
0130     newTag->setCloseParentOnTrigger(false);
0131 
0132     connect(newTag, SIGNAL(triggered(QString)), this, SLOT(slotCreateNewTag(QString)), Qt::UniqueConnection);
0133     m_createNewTagAction = newTag;
0134 
0135 }
0136 
0137 WdgAddTagButton::~WdgAddTagButton()
0138 {
0139 
0140 }
0141 
0142 void WdgAddTagButton::setAvailableTagsList(QList<KoID> &notSelected)
0143 {
0144     QList<QAction*> actionsToRemove = actions();
0145     Q_FOREACH(QAction* action, actionsToRemove) {
0146         removeAction(action);
0147     }
0148 
0149     Q_FOREACH(KoID tag, notSelected) {
0150         QAction* action = new QAction(tag.name());
0151         action->setData(QVariant::fromValue<KoID>(tag));
0152         addAction(action);
0153     }
0154 
0155     QAction *separator = new QAction(this);
0156     separator->setSeparator(true);
0157     addAction(separator);
0158 
0159     addAction(m_createNewTagAction);
0160     setDefaultAction(0);
0161 }
0162 
0163 void WdgAddTagButton::slotFinishLastAction()
0164 {
0165     if (m_lastAction == CreateNewTag) {
0166         emit sigCreateNewTag(m_lastTagToCreate);
0167     } else {
0168         emit sigAddNewTag(m_lastTagToAdd);
0169     }
0170 }
0171 
0172 void WdgAddTagButton::slotAddNewTag(QAction *action)
0173 {
0174     if (action == m_createNewTagAction) {
0175         m_lastTagToCreate = action->data().toString();
0176         m_lastAction = CreateNewTag;
0177         slotFinishLastAction();
0178         KisSignalsBlocker b(m_createNewTagAction);
0179         m_createNewTagAction->setText("");
0180     } else if (!action->data().isNull() && action->data().canConvert<KoID>()) {
0181         m_lastTagToAdd = action->data().value<KoID>();
0182         m_lastAction = AddNewTag;
0183         slotFinishLastAction();
0184     }
0185 
0186 
0187     if (this->menu()) {
0188         this->menu()->close();
0189     }
0190 }
0191 
0192 void WdgAddTagButton::slotCreateNewTag(QString tagName)
0193 {
0194     m_lastTagToCreate = tagName;
0195     m_lastAction = CreateNewTag;
0196     slotFinishLastAction();
0197     KisSignalsBlocker b(m_createNewTagAction);
0198     m_createNewTagAction->setText("");
0199 
0200 
0201     if (this->menu()) {
0202         this->menu()->close();
0203     }
0204 }
0205 
0206 void WdgAddTagButton::paintEvent(QPaintEvent *event)
0207 {
0208     Q_UNUSED(event);
0209 
0210     QPainter painter(this);
0211     painter.setRenderHint(QPainter::Antialiasing);
0212     QPainterPath path;
0213     path.addRoundedRect(this->rect(), 6, 6);
0214     painter.fillPath(path, qApp->palette().light());
0215     painter.setPen(QPen(qApp->palette().windowText(), painter.pen().widthF()));
0216     QIcon icon = this->icon();
0217     QSize size = this->rect().size()*0.6;
0218 
0219     QSize iconSize = icon.actualSize(size);
0220     QPixmap pix = icon.pixmap(iconSize);
0221     QSize realSize = iconSize.scaled(iconSize, Qt::KeepAspectRatio);//pix.rect().size();
0222     qreal hack = 0.5;
0223     QPointF p = this->rect().topLeft() + QPointF(this->rect().width()/2 - realSize.width()/2 - hack, this->rect().height()/2 - realSize.height()/2 - hack);
0224     painter.setOpacity(!isEnabled() ? 0.3 : 1.0);
0225     painter.drawPixmap(p, pix);
0226     painter.setOpacity(1.0);
0227 }
0228 
0229 KisTagSelectionWidget::KisTagSelectionWidget(QWidget *parent)
0230     : QWidget(parent)
0231 {
0232     m_layout = new KisWrappableHBoxLayout(this);
0233     m_addTagButton = new WdgAddTagButton(this);
0234 
0235     m_layout->addWidget(m_addTagButton);
0236     connect(m_addTagButton, SIGNAL(sigCreateNewTag(QString)), this, SIGNAL(sigCreateNewTag(QString)), Qt::UniqueConnection);
0237     connect(m_addTagButton, SIGNAL(sigAddNewTag(KoID)), this, SIGNAL(sigAddTagToSelection(KoID)), Qt::UniqueConnection);
0238 
0239     setLayout(m_layout);
0240 }
0241 
0242 KisTagSelectionWidget::~KisTagSelectionWidget()
0243 {
0244 
0245 }
0246 
0247 void KisTagSelectionWidget::setTagList(bool editable, QList<KoID> &selected, QList<KoID> &notSelected)
0248 {
0249     QList<KoID> semiSelected;
0250     setTagList(editable, selected, notSelected, semiSelected);
0251 }
0252 
0253 void KisTagSelectionWidget::setTagList(bool editable, QList<KoID> &selected, QList<KoID> &notSelected, QList<KoID> &semiSelected)
0254 {
0255     m_editable = editable;
0256     QLayoutItem *item;
0257 
0258     disconnect(m_addTagButton, SIGNAL(sigCreateNewTag(QString)), this, SIGNAL(sigCreateNewTag(QString)));
0259     disconnect(m_addTagButton, SIGNAL(sigAddNewTag(KoID)), this, SIGNAL(sigAddTagToSelection(KoID)));
0260 
0261     while((item = m_layout->takeAt(0))) {
0262         if (item->widget()) {
0263             if (!dynamic_cast<WdgAddTagButton*>(item->widget())) {
0264                 delete item->widget();
0265             }
0266         }
0267         delete item;
0268     }
0269 
0270 
0271     WdgAddTagButton* addTagButton = dynamic_cast<WdgAddTagButton*>(m_addTagButton);
0272     addTagButton->setAvailableTagsList(notSelected);
0273 
0274     Q_FOREACH(KoID tag, selected) {
0275         WdgCloseableLabel* label = new WdgCloseableLabel(tag, m_editable, false, this);
0276         connect(label, SIGNAL(sigRemoveTagFromSelection(KoID)), this, SLOT(slotRemoveTagFromSelection(KoID)), Qt::UniqueConnection);
0277         m_layout->addWidget(label);
0278     }
0279 
0280     Q_FOREACH(KoID tag, semiSelected) {
0281         WdgCloseableLabel* label = new WdgCloseableLabel(tag, m_editable, true, this);
0282         connect(label, SIGNAL(sigRemoveTagFromSelection(KoID)), this, SLOT(slotRemoveTagFromSelection(KoID)), Qt::UniqueConnection);
0283         m_layout->addWidget(label);
0284     }
0285 
0286     m_layout->addWidget(m_addTagButton);
0287     m_addTagButton->setVisible(m_editable);
0288 
0289 
0290     connect(m_addTagButton, SIGNAL(sigCreateNewTag(QString)), this, SIGNAL(sigCreateNewTag(QString)), Qt::UniqueConnection);
0291     connect(m_addTagButton, SIGNAL(sigAddNewTag(KoID)), this, SIGNAL(sigAddTagToSelection(KoID)), Qt::UniqueConnection);
0292 
0293     if (m_editable) {
0294     }
0295 
0296     if (layout()) {
0297         layout()->invalidate();
0298     }
0299 }
0300 
0301 void KisTagSelectionWidget::slotAddTagToSelection(QAction *action)
0302 {
0303     if (!action) return;
0304 
0305     if (!action->data().isNull()) {
0306         KoID custom = action->data().value <KoID>();
0307         emit sigAddTagToSelection(custom);
0308     }
0309 }
0310 
0311 void KisTagSelectionWidget::slotRemoveTagFromSelection(KoID tag)
0312 {
0313     emit sigRemoveTagFromSelection(tag);
0314 }