File indexing completed on 2024-05-19 04:29:25
0001 /* 0002 * SPDX-FileCopyrightText: 2016 Dmitry Kazakov <dimula73@gmail.com> 0003 * SPDX-FileCopyrightText: 2022 Halla Rempt <halla@valdyas.org> 0004 * SPDX-License-Identifier: GPL-2.0-or-later 0005 */ 0006 0007 #include "kis_palette_view.h" 0008 0009 #include <QWheelEvent> 0010 #include <QHeaderView> 0011 #include <QFormLayout> 0012 #include <QLabel> 0013 #include <QLineEdit> 0014 #include <QCheckBox> 0015 #include <QComboBox> 0016 #include <QMenu> 0017 0018 #include <KConfigGroup> 0019 #include <KSharedConfig> 0020 #include <KLocalizedString> 0021 0022 #include <kis_icon_utils.h> 0023 0024 #include <KisKineticScroller.h> 0025 0026 #include <KoDialog.h> 0027 #include <KoColorDisplayRendererInterface.h> 0028 0029 #include "KisPaletteDelegate.h" 0030 #include "KisPaletteModel.h" 0031 #include "kis_color_button.h" 0032 #include <KisSwatch.h> 0033 #include <KisResourceModel.h> 0034 #include <kis_debug.h> 0035 #include <KisResourceUserOperations.h> 0036 0037 int KisPaletteView::MINIMUM_ROW_HEIGHT = 10; 0038 0039 struct KisPaletteView::Private 0040 { 0041 QPointer<KisPaletteModel> model; 0042 }; 0043 0044 KisPaletteView::KisPaletteView(QWidget *parent) 0045 : QTableView(parent) 0046 , d(new Private) 0047 { 0048 setItemDelegate(new KisPaletteDelegate(this)); 0049 0050 setShowGrid(true); 0051 setDropIndicatorShown(true); 0052 setDragDropMode(QAbstractItemView::DragDrop); 0053 setSelectionMode(QAbstractItemView::SingleSelection); 0054 setDragEnabled(true); 0055 setAcceptDrops(false); 0056 0057 /* 0058 * without this, a cycle might be created: 0059 * the view stretches to right border, and this make it need a scroll bar; 0060 * after the bar is added, the view shrinks to the bar, and this makes it 0061 * no longer need the bar any more, and the bar is removed again 0062 */ 0063 setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOn); 0064 0065 // set the size of swatches 0066 horizontalHeader()->setVisible(false); 0067 verticalHeader()->setVisible(false); 0068 horizontalHeader()->setSectionResizeMode(QHeaderView::Stretch); 0069 horizontalHeader()->setMinimumSectionSize(MINIMUM_ROW_HEIGHT); 0070 verticalHeader()->setSectionResizeMode(QHeaderView::Fixed); 0071 verticalHeader()->setMinimumSectionSize(MINIMUM_ROW_HEIGHT); 0072 0073 connect(horizontalHeader(), SIGNAL(sectionResized(int,int,int)), 0074 SLOT(slotHorizontalHeaderResized(int,int,int))); 0075 setAutoFillBackground(true); 0076 0077 QScroller *scroller = KisKineticScroller::createPreconfiguredScroller(this); 0078 if (scroller) { 0079 connect(scroller, SIGNAL(stateChanged(QScroller::State)), 0080 this, SLOT(slotScrollerStateChanged(QScroller::State))); 0081 } 0082 0083 connect(this, SIGNAL(clicked(QModelIndex)), SLOT(slotCurrentSelectionChanged(QModelIndex))); 0084 } 0085 0086 KisPaletteView::~KisPaletteView() 0087 { 0088 } 0089 0090 void KisPaletteView::setCrossedKeyword(const QString &value) 0091 { 0092 KisPaletteDelegate *delegate = 0093 dynamic_cast<KisPaletteDelegate*>(itemDelegate()); 0094 KIS_ASSERT_RECOVER_RETURN(delegate); 0095 0096 delegate->setCrossedKeyword(value); 0097 } 0098 0099 bool KisPaletteView::addEntryWithDialog(KoColor color) 0100 { 0101 KoDialog dialog; 0102 dialog.setWindowTitle(i18nc("@title:dialog", "Add a new Color Swatch")); 0103 QFormLayout *editableItems = new QFormLayout(dialog.mainWidget()); 0104 0105 QComboBox *cmbGroups = new QComboBox; 0106 QString defaultGroupName = i18nc("Name for default swatch group", "Default"); 0107 cmbGroups->addItem(defaultGroupName); 0108 cmbGroups->addItems(d->model->colorSet()->swatchGroupNames()); 0109 QLineEdit *lnIDName = new QLineEdit; 0110 QLineEdit *lnName = new QLineEdit; 0111 KisColorButton *bnColor = new KisColorButton; 0112 QCheckBox *chkSpot = new QCheckBox; 0113 chkSpot->setToolTip(i18nc("@info:tooltip", "A spot color is a color that the printer is able to print without mixing the paints it has available to it. The opposite is called a process color.")); 0114 editableItems->addRow(i18n("Swatch Group:"), cmbGroups); 0115 editableItems->addRow(i18n("Swatch ID:"), lnIDName); 0116 editableItems->addRow(i18n("Color swatch name:"), lnName); 0117 editableItems->addRow(i18nc("Color as the Color of a Swatch in a Palette", "Color:"), bnColor); 0118 editableItems->addRow(i18n("Spot color:"), chkSpot); 0119 cmbGroups->setCurrentIndex(0); 0120 lnName->setText(i18nc("Prefix of a color swatch default name, as in Color 1","Color")+" " + QString::number(d->model->colorSet()->colorCount()+1)); 0121 lnIDName->setText(QString::number(d->model->colorSet()->colorCount() + 1)); 0122 bnColor->setColor(color); 0123 chkSpot->setChecked(false); 0124 0125 if (dialog.exec() == KoDialog::Accepted) { 0126 QString groupName = cmbGroups->currentText(); 0127 if (groupName == defaultGroupName) { 0128 groupName = QString(); 0129 } 0130 KisSwatch newEntry; 0131 newEntry.setColor(bnColor->color()); 0132 newEntry.setName(lnName->text()); 0133 newEntry.setId(lnIDName->text()); 0134 newEntry.setSpotColor(chkSpot->isChecked()); 0135 d->model->addSwatch(newEntry, groupName); 0136 saveModification(); 0137 return true; 0138 } 0139 0140 return false; 0141 } 0142 0143 bool KisPaletteView::addGroupWithDialog() 0144 { 0145 KoDialog dialog; 0146 dialog.setWindowTitle(i18nc("@title:dialog","Add a new group")); 0147 QFormLayout *editableItems = new QFormLayout(dialog.mainWidget()); 0148 QLineEdit *lnName = new QLineEdit(); 0149 lnName->setText(i18nc("Part of default name for a new group", "Color Group")+""+QString::number(d->model->colorSet()->swatchGroupNames().size()+1)); 0150 editableItems->addRow(i18nc("Name for a group", "Name"), lnName); 0151 0152 if (dialog.exec() == KoDialog::Accepted) { 0153 d->model->addGroup(lnName->text()); 0154 saveModification(); 0155 return true; 0156 } 0157 return false; 0158 } 0159 0160 bool KisPaletteView::removeEntryWithDialog(QModelIndex index) 0161 { 0162 bool keepColors = false; 0163 if (qvariant_cast<bool>(index.data(KisPaletteModel::IsGroupNameRole))) { 0164 KoDialog dialog; 0165 dialog.setWindowTitle(i18nc("@title:dialog","Removing Group")); 0166 QFormLayout *editableItems = new QFormLayout(dialog.mainWidget()); 0167 QCheckBox *chkKeep = new QCheckBox(); 0168 editableItems->addRow(i18nc("Shows up when deleting a swatch group", "Keep the Colors"), chkKeep); 0169 0170 if (dialog.exec() != KoDialog::Accepted) { return false; } 0171 keepColors = chkKeep->isChecked(); 0172 } 0173 d->model->removeSwatch(index, keepColors); 0174 0175 saveModification(); 0176 0177 return true; 0178 } 0179 0180 void KisPaletteView::selectClosestColor(const KoColor &color) 0181 { 0182 KoColorSetSP colorSet = d->model->colorSet(); 0183 if (!colorSet || !colorSet->valid() || currentIndex().row() < 0) { 0184 return; 0185 } 0186 0187 //also don't select if the color is the same as the current selection 0188 if (d->model->getSwatch(currentIndex()).color() == color) { 0189 return; 0190 } 0191 0192 selectionModel()->clearSelection(); 0193 QModelIndex index = d->model->indexForClosest(color); 0194 0195 selectionModel()->setCurrentIndex(index, QItemSelectionModel::Select); 0196 } 0197 0198 const KoColor KisPaletteView::closestColor(const KoColor &color) const 0199 { 0200 QModelIndex index = d->model->indexForClosest(color); 0201 KisSwatch swatch = d->model->getSwatch(index); 0202 return swatch.color(); 0203 } 0204 0205 void KisPaletteView::slotFGColorChanged(const KoColor &color) 0206 { 0207 selectClosestColor(color); 0208 } 0209 0210 void KisPaletteView::setPaletteModel(KisPaletteModel *model) 0211 { 0212 if (d->model) { 0213 disconnect(d->model, 0, this, 0); 0214 } 0215 d->model = model; 0216 setModel(model); 0217 slotAdditionalGuiUpdate(); 0218 0219 connect(model, SIGNAL(sigPaletteModified()), SLOT(slotAdditionalGuiUpdate())); 0220 connect(model, SIGNAL(sigPaletteChanged()), SLOT(slotAdditionalGuiUpdate())); 0221 } 0222 0223 KisPaletteModel* KisPaletteView::paletteModel() const 0224 { 0225 return d->model; 0226 } 0227 0228 void KisPaletteView::setAllowModification(bool allow) 0229 { 0230 setAcceptDrops(allow); 0231 } 0232 0233 void KisPaletteView::slotHorizontalHeaderResized(int, int, int newSize) 0234 { 0235 resizeRows(newSize); 0236 slotAdditionalGuiUpdate(); 0237 } 0238 0239 void KisPaletteView::resizeRows(int newSize) 0240 { 0241 verticalHeader()->setDefaultSectionSize(newSize); 0242 verticalHeader()->resizeSections(QHeaderView::Fixed); 0243 } 0244 0245 void KisPaletteView::saveModification() 0246 { 0247 KisResourceUserOperations::updateResourceWithUserInput(this, d->model->colorSet()); 0248 } 0249 0250 void KisPaletteView::removeSelectedEntry() 0251 { 0252 if (selectedIndexes().size() <= 0) { 0253 return; 0254 } 0255 d->model->removeSwatch(currentIndex()); 0256 } 0257 0258 void KisPaletteView::slotAdditionalGuiUpdate() 0259 { 0260 if (!d->model->colorSet()) return; 0261 0262 clearSpans(); 0263 resizeRows(verticalHeader()->defaultSectionSize()); 0264 0265 // int row = -1; 0266 0267 for (const QString &groupName : d->model->colorSet()->swatchGroupNames()) { 0268 if (groupName.isEmpty()) continue; 0269 0270 // KisSwatchGroupSP group = d->model->colorSet()->getGroup(groupName); 0271 // row += group->rowCount() + 1; 0272 // setSpan(row, 0, 1, d->model->columnCount()); 0273 // setRowHeight(row, fontMetrics().lineSpacing() + 6); 0274 // verticalHeader()->resizeSection(row, fontMetrics().lineSpacing() + 6); 0275 0276 0277 int rowNumber = d->model->colorSet()->startRowForGroup(groupName); 0278 setSpan(rowNumber, 0, 1, d->model->columnCount()); 0279 setRowHeight(rowNumber, fontMetrics().lineSpacing() + 6); 0280 verticalHeader()->resizeSection(rowNumber, fontMetrics().lineSpacing() + 6); 0281 } 0282 emit sigPaletteUpdatedFromModel(); 0283 } 0284 0285 void KisPaletteView::slotCurrentSelectionChanged(const QModelIndex &newCurrent) 0286 { 0287 if (!newCurrent.isValid()) { return; } 0288 0289 const bool isGroupName = newCurrent.data(KisPaletteModel::IsGroupNameRole).toBool(); 0290 const bool isCheckSlot = newCurrent.data(KisPaletteModel::CheckSlotRole).toBool(); 0291 0292 const KisSwatch newEntry = d->model->getSwatch(newCurrent); 0293 0294 emit sigIndexSelected(newCurrent); 0295 if (isGroupName) { 0296 return; 0297 } 0298 0299 if (isCheckSlot) { 0300 emit sigColorSelected(newEntry.color()); 0301 } 0302 } 0303 0304 void KisPaletteView::setDisplayRenderer(const KoColorDisplayRendererInterface *displayRenderer) 0305 { 0306 Q_ASSERT(d->model); 0307 d->model->setDisplayRenderer(displayRenderer); 0308 } 0309