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> ¬Selected) 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> ¬Selected) 0248 { 0249 QList<KoID> semiSelected; 0250 setTagList(editable, selected, notSelected, semiSelected); 0251 } 0252 0253 void KisTagSelectionWidget::setTagList(bool editable, QList<KoID> &selected, QList<KoID> ¬Selected, 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 }