File indexing completed on 2024-05-19 04:29:28
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_editable(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_editable) { 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_editable); 0063 m_closeIconLabel->setMaximumSize(QSize(1, 1) * m_size); 0064 0065 connect(m_closeIconLabel, &QAbstractButton::clicked, this, [&]() { 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, bool createNew) 0117 : QToolButton(parent), 0118 m_createNew(createNew) 0119 { 0120 setPopupMode(QToolButton::InstantPopup); 0121 setIcon(KisIconUtils::loadIcon("list-add")); 0122 setToolTip(i18n("Assign to tag")); 0123 setContentsMargins(0, 0, 0, 0); 0124 QSize defaultSize = QSize(1, 1)*m_size; 0125 setMinimumSize(defaultSize); 0126 setMaximumSize(defaultSize); 0127 0128 connect(this, SIGNAL(triggered(QAction*)), SLOT(slotAddNewTag(QAction*))); 0129 0130 if (m_createNew) { 0131 UserInputTagAction *newTag = new UserInputTagAction(this); 0132 newTag->setCloseParentOnTrigger(false); 0133 0134 connect(newTag, SIGNAL(triggered(QString)), this, SLOT(slotCreateNewTag(QString)), Qt::UniqueConnection); 0135 m_createNewTagAction = newTag; 0136 } else { 0137 m_noTags = new QAction("No tags present"); 0138 QFont font = m_noTags->font(); 0139 font.setItalic(true); 0140 m_noTags->setFont(font); 0141 } 0142 0143 } 0144 0145 WdgAddTagButton::~WdgAddTagButton() 0146 { 0147 0148 } 0149 0150 void WdgAddTagButton::setAvailableTagsList(QList<KoID> ¬Selected) 0151 { 0152 QList<QAction*> actionsToRemove = actions(); 0153 Q_FOREACH(QAction* action, actionsToRemove) { 0154 removeAction(action); 0155 } 0156 0157 Q_FOREACH(KoID tag, notSelected) { 0158 QAction* action = new QAction(tag.name()); 0159 action->setData(QVariant::fromValue<KoID>(tag)); 0160 addAction(action); 0161 } 0162 0163 QAction *separator = new QAction(this); 0164 separator->setSeparator(true); 0165 addAction(separator); 0166 0167 if (m_createNew) { 0168 addAction(m_createNewTagAction); 0169 setDefaultAction(0); 0170 } else { 0171 if (notSelected.count() == 0) { 0172 addAction(m_noTags); 0173 } 0174 } 0175 } 0176 0177 void WdgAddTagButton::slotFinishLastAction() 0178 { 0179 if (m_lastAction == CreateNewTag) { 0180 emit sigCreateNewTag(m_lastTagToCreate); 0181 } else { 0182 emit sigAddNewTag(m_lastTagToAdd); 0183 } 0184 } 0185 0186 void WdgAddTagButton::slotAddNewTag(QAction *action) 0187 { 0188 if (action == m_createNewTagAction) { 0189 m_lastTagToCreate = action->data().toString(); 0190 m_lastAction = CreateNewTag; 0191 slotFinishLastAction(); 0192 KisSignalsBlocker b(m_createNewTagAction); 0193 m_createNewTagAction->setText(""); 0194 } else if (!action->data().isNull() && action->data().canConvert<KoID>()) { 0195 m_lastTagToAdd = action->data().value<KoID>(); 0196 m_lastAction = AddNewTag; 0197 slotFinishLastAction(); 0198 } 0199 0200 0201 if (this->menu()) { 0202 this->menu()->close(); 0203 } 0204 } 0205 0206 void WdgAddTagButton::slotCreateNewTag(QString tagName) 0207 { 0208 m_lastTagToCreate = tagName; 0209 m_lastAction = CreateNewTag; 0210 slotFinishLastAction(); 0211 KisSignalsBlocker b(m_createNewTagAction); 0212 m_createNewTagAction->setText(""); 0213 0214 0215 if (this->menu()) { 0216 this->menu()->close(); 0217 } 0218 } 0219 0220 void WdgAddTagButton::paintEvent(QPaintEvent *event) 0221 { 0222 Q_UNUSED(event); 0223 0224 QPainter painter(this); 0225 painter.setRenderHint(QPainter::Antialiasing); 0226 QPainterPath path; 0227 path.addRoundedRect(this->rect(), 6, 6); 0228 painter.fillPath(path, qApp->palette().light()); 0229 painter.setPen(QPen(qApp->palette().windowText(), painter.pen().widthF())); 0230 QIcon icon = this->icon(); 0231 QSize size = this->rect().size()*0.6; 0232 0233 QSize iconSize = icon.actualSize(size); 0234 QPixmap pix = icon.pixmap(iconSize); 0235 QSize realSize = iconSize.scaled(iconSize, Qt::KeepAspectRatio);//pix.rect().size(); 0236 qreal hack = 0.5; 0237 QPointF p = this->rect().topLeft() + QPointF(this->rect().width()/2 - realSize.width()/2 - hack, this->rect().height()/2 - realSize.height()/2 - hack); 0238 painter.setOpacity(!isEnabled() ? 0.3 : 1.0); 0239 painter.drawPixmap(p, pix); 0240 painter.setOpacity(1.0); 0241 } 0242 0243 KisTagSelectionWidget::KisTagSelectionWidget(QWidget *parent, bool createNew) 0244 : QWidget(parent), 0245 m_createNew(createNew) 0246 { 0247 m_layout = new KisWrappableHBoxLayout(this); 0248 m_addTagButton = new WdgAddTagButton(this, m_createNew); 0249 0250 m_layout->addWidget(m_addTagButton); 0251 connect(m_addTagButton, SIGNAL(sigCreateNewTag(QString)), this, SIGNAL(sigCreateNewTag(QString)), Qt::UniqueConnection); 0252 connect(m_addTagButton, SIGNAL(sigAddNewTag(KoID)), this, SIGNAL(sigAddTagToSelection(KoID)), Qt::UniqueConnection); 0253 0254 setLayout(m_layout); 0255 } 0256 0257 KisTagSelectionWidget::~KisTagSelectionWidget() 0258 { 0259 0260 } 0261 0262 void KisTagSelectionWidget::setTagList(bool editable, QList<KoID> &selected, QList<KoID> ¬Selected) 0263 { 0264 QList<KoID> semiSelected; 0265 setTagList(editable, selected, notSelected, semiSelected); 0266 } 0267 0268 void KisTagSelectionWidget::setTagList(bool editable, QList<KoID> &selected, QList<KoID> ¬Selected, QList<KoID> &semiSelected) 0269 { 0270 m_editable = editable; 0271 QLayoutItem *item; 0272 0273 disconnect(m_addTagButton, SIGNAL(sigCreateNewTag(QString)), this, SIGNAL(sigCreateNewTag(QString))); 0274 disconnect(m_addTagButton, SIGNAL(sigAddNewTag(KoID)), this, SIGNAL(sigAddTagToSelection(KoID))); 0275 0276 while((item = m_layout->takeAt(0))) { 0277 if (item->widget()) { 0278 if (!dynamic_cast<WdgAddTagButton*>(item->widget())) { 0279 delete item->widget(); 0280 } 0281 } 0282 delete item; 0283 } 0284 0285 0286 WdgAddTagButton* addTagButton = dynamic_cast<WdgAddTagButton*>(m_addTagButton); 0287 KIS_SAFE_ASSERT_RECOVER_RETURN(addTagButton); 0288 addTagButton->setAvailableTagsList(notSelected); 0289 0290 Q_FOREACH(KoID tag, selected) { 0291 WdgCloseableLabel* label = new WdgCloseableLabel(tag, m_editable, false, this); 0292 connect(label, SIGNAL(sigRemoveTagFromSelection(KoID)), this, SLOT(slotRemoveTagFromSelection(KoID)), Qt::UniqueConnection); 0293 m_layout->addWidget(label); 0294 } 0295 0296 Q_FOREACH(KoID tag, semiSelected) { 0297 WdgCloseableLabel* label = new WdgCloseableLabel(tag, m_editable, true, this); 0298 connect(label, SIGNAL(sigRemoveTagFromSelection(KoID)), this, SLOT(slotRemoveTagFromSelection(KoID)), Qt::UniqueConnection); 0299 m_layout->addWidget(label); 0300 } 0301 0302 m_layout->addWidget(m_addTagButton); 0303 m_addTagButton->setVisible(m_editable); 0304 0305 0306 connect(m_addTagButton, SIGNAL(sigCreateNewTag(QString)), this, SIGNAL(sigCreateNewTag(QString)), Qt::UniqueConnection); 0307 connect(m_addTagButton, SIGNAL(sigAddNewTag(KoID)), this, SIGNAL(sigAddTagToSelection(KoID)), Qt::UniqueConnection); 0308 0309 if (m_editable) { 0310 } 0311 0312 if (layout()) { 0313 layout()->invalidate(); 0314 } 0315 } 0316 0317 void KisTagSelectionWidget::slotAddTagToSelection(QAction *action) 0318 { 0319 if (!action) return; 0320 0321 if (!action->data().isNull()) { 0322 KoID custom = action->data().value <KoID>(); 0323 emit sigAddTagToSelection(custom); 0324 } 0325 } 0326 0327 void KisTagSelectionWidget::slotRemoveTagFromSelection(KoID tag) 0328 { 0329 emit sigRemoveTagFromSelection(tag); 0330 }