File indexing completed on 2024-04-21 04:32:12

0001 /*
0002  * Copyright (C) 2010-2015 by Stephen Allewell
0003  * steve.allewell@gmail.com
0004  *
0005  * This program is free software; you can redistribute it and/or modify
0006  * it under the terms of the GNU General Public License as published by
0007  * the Free Software Foundation; either version 2 of the License, or
0008  * (at your option) any later version.
0009  */
0010 
0011 #include "PaletteManagerDlg.h"
0012 
0013 #include <QBitmap>
0014 #include <QDesktopWidget>
0015 #include <QPainter>
0016 #include <QScreen>
0017 #include <QWidget>
0018 
0019 #include <KCharSelect>
0020 #include <KHelpClient>
0021 #include <KLocalizedString>
0022 #include <KMessageBox>
0023 
0024 #include "CalibrateFlossDlg.h"
0025 #include "Commands.h"
0026 #include "Floss.h"
0027 #include "FlossScheme.h"
0028 #include "MainWindow.h"
0029 #include "NewFlossDlg.h"
0030 #include "SchemeManager.h"
0031 #include "SymbolLibrary.h"
0032 #include "SymbolManager.h"
0033 #include "SymbolSelectorDlg.h"
0034 #include "configuration.h"
0035 
0036 const uchar pickColorCursorMask[] = {
0037     0x18, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x18, 0x00,
0038     0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff,
0039     0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff,
0040     0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff,
0041     0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff,
0042 };
0043 
0044 PaletteManagerDlg::PaletteManagerDlg(QWidget *parent, Document *document)
0045     : QDialog(parent)
0046     , m_document(document)
0047     , m_dialogPalette(m_document->pattern()->palette())
0048     , m_flossUsage(document->pattern()->stitches().flossUsage())
0049     , m_scheme(SchemeManager::scheme(m_dialogPalette.schemeName()))
0050     , m_symbolSelectorDlg(nullptr)
0051 {
0052     setWindowTitle(i18n("Palette Manager"));
0053     ui.setupUi(this);
0054 
0055     ui.SymbolLibrary->insertItems(0, SymbolManager::libraries());
0056     ui.SymbolLibrary->setCurrentItem(m_dialogPalette.symbolLibrary());
0057 
0058     fillLists();
0059 }
0060 
0061 PaletteManagerDlg::~PaletteManagerDlg()
0062 {
0063     delete m_symbolSelectorDlg;
0064 }
0065 
0066 const DocumentPalette &PaletteManagerDlg::palette() const
0067 {
0068     return m_dialogPalette;
0069 }
0070 
0071 void PaletteManagerDlg::hideEvent(QHideEvent *event)
0072 {
0073     KConfigGroup(KSharedConfig::openConfig(), QStringLiteral("DialogSizes")).writeEntry(QStringLiteral("PaletteManagerDlg"), size());
0074 
0075     QDialog::hideEvent(event);
0076 }
0077 
0078 void PaletteManagerDlg::showEvent(QShowEvent *event)
0079 {
0080     QDialog::showEvent(event);
0081 
0082     if (KConfigGroup(KSharedConfig::openConfig(), QStringLiteral("DialogSizes")).hasKey(QStringLiteral("PaletteManagerDlg"))) {
0083         resize(KConfigGroup(KSharedConfig::openConfig(), QStringLiteral("DialogSizes")).readEntry(QStringLiteral("PaletteManagerDlg"), QSize()));
0084     }
0085 }
0086 
0087 void PaletteManagerDlg::on_ColorList_currentRowChanged(int currentRow)
0088 {
0089     ui.AddFloss->setEnabled((currentRow != -1) && symbolsAvailable());
0090 }
0091 
0092 int mapStyleToIndex(Qt::PenStyle style)
0093 {
0094     int index = 0;
0095 
0096     if (style == Qt::DashLine) {
0097         index = 1;
0098     }
0099 
0100     if (style == Qt::DotLine) {
0101         index = 2;
0102     }
0103 
0104     if (style == Qt::DashDotLine) {
0105         index = 3;
0106     }
0107 
0108     if (style == Qt::DashDotDotLine) {
0109         index = 4;
0110     }
0111 
0112     return index;
0113 }
0114 
0115 void PaletteManagerDlg::on_CurrentList_currentRowChanged(int currentRow)
0116 {
0117     if (currentRow != -1) {
0118         int i = paletteIndex(ui.CurrentList->currentItem()->data(Qt::UserRole).toString());
0119         const DocumentFloss *floss = m_dialogPalette.flosses().value(i);
0120         ui.StitchStrands->setCurrentIndex(floss->stitchStrands() - 1);
0121         ui.BackstitchStrands->setCurrentIndex(floss->backstitchStrands() - 1);
0122         Symbol symbol = SymbolManager::library(m_dialogPalette.symbolLibrary())->symbol(m_dialogPalette.flosses().value(i)->stitchSymbol());
0123         ui.StitchSymbol->setIcon(SymbolListWidget::createIcon(symbol, 22));
0124         ui.BackstitchSymbol->setCurrentIndex(mapStyleToIndex(floss->backstitchSymbol()));
0125         ui.StitchStrands->setEnabled(true);
0126         ui.BackstitchStrands->setEnabled(true);
0127         ui.StitchSymbol->setEnabled(true);
0128         ui.BackstitchSymbol->setEnabled(true);
0129         ui.ClearUnused->setEnabled(true);
0130 
0131         if (m_flossUsage.contains(i) && m_flossUsage[i].totalStitches() != 0) {
0132             ui.RemoveFloss->setEnabled(false);
0133         } else {
0134             ui.RemoveFloss->setEnabled(true);
0135         }
0136     } else {
0137         ui.RemoveFloss->setEnabled(false);
0138         ui.StitchStrands->setEnabled(false);
0139         ui.BackstitchStrands->setEnabled(false);
0140         ui.StitchSymbol->setEnabled(false);
0141         ui.BackstitchSymbol->setEnabled(false);
0142         ui.ClearUnused->setEnabled(false);
0143     }
0144 
0145     if (symbolsAvailable()) {
0146         ui.AddFloss->setEnabled(ui.ColorList->currentRow() != -1);
0147         ui.AddFloss->setToolTip(QString());
0148     } else {
0149         ui.AddFloss->setEnabled(false);
0150         ui.AddFloss->setToolTip(QString(i18n("There are no more symbols available.")));
0151     }
0152 }
0153 
0154 void PaletteManagerDlg::on_AddFloss_clicked(bool)
0155 {
0156     QListWidgetItem *listWidgetItem = ui.ColorList->takeItem(ui.ColorList->currentRow());
0157     m_dialogPalette.add(listWidgetItem->data(Qt::DecorationRole).value<QColor>());
0158     insertListWidgetItem(ui.CurrentList, listWidgetItem);
0159     ui.CurrentList->scrollToItem(listWidgetItem, QAbstractItemView::PositionAtCenter);
0160     ui.CurrentList->setCurrentItem(listWidgetItem);
0161 }
0162 
0163 void PaletteManagerDlg::on_RemoveFloss_clicked(bool)
0164 {
0165     QListWidgetItem *listWidgetItem = ui.CurrentList->takeItem(ui.CurrentList->currentRow());
0166     int i = paletteIndex(listWidgetItem->data(Qt::UserRole).toString());
0167     m_dialogPalette.remove(i);
0168 
0169     insertListWidgetItem(ui.ColorList, listWidgetItem);
0170     ui.ColorList->scrollToItem(listWidgetItem, QAbstractItemView::PositionAtCenter);
0171     ui.ColorList->setCurrentItem(listWidgetItem);
0172 }
0173 
0174 void PaletteManagerDlg::on_StitchStrands_activated(int index)
0175 {
0176     m_dialogPalette.floss(paletteIndex(ui.CurrentList->currentItem()->data(Qt::UserRole).toString()))->setStitchStrands(index + 1);
0177 }
0178 
0179 void PaletteManagerDlg::on_BackstitchStrands_activated(int index)
0180 {
0181     m_dialogPalette.floss(paletteIndex(ui.CurrentList->currentItem()->data(Qt::UserRole).toString()))->setBackstitchStrands(index + 1);
0182 }
0183 
0184 void PaletteManagerDlg::on_SymbolLibrary_activated(const QString &library)
0185 {
0186     m_dialogPalette.setSymbolLibrary(library);
0187 
0188     if (library != m_dialogPalette.symbolLibrary()) {
0189         // Can't change the library because there aren't enough symbols available
0190         // Show a warning and reset the current library in the selection
0191         KMessageBox::information(this, QString(i18n("The selected symbol library does not have enough symbols for the flosses in the palette.")));
0192         ui.SymbolLibrary->setCurrentItem(m_dialogPalette.symbolLibrary());
0193     } else if (m_symbolSelectorDlg) {
0194         delete m_symbolSelectorDlg;
0195         m_symbolSelectorDlg = new SymbolSelectorDlg(this, library);
0196     }
0197 
0198     on_CurrentList_currentRowChanged(ui.CurrentList->currentRow());
0199 }
0200 
0201 void PaletteManagerDlg::on_StitchSymbol_clicked(bool)
0202 {
0203     int i = paletteIndex(ui.CurrentList->currentItem()->data(Qt::UserRole).toString());
0204 
0205     if (m_symbolSelectorDlg == nullptr) {
0206         m_symbolSelectorDlg = new SymbolSelectorDlg(this, m_dialogPalette.symbolLibrary());
0207     }
0208 
0209     m_symbolSelectorDlg->setSelectedSymbol(m_dialogPalette.flosses().value(i)->stitchSymbol(), m_dialogPalette.usedSymbols());
0210 
0211     if (m_symbolSelectorDlg->exec() == QDialog::Accepted) {
0212         m_dialogPalette.floss(i)->setStitchSymbol(m_symbolSelectorDlg->selectedSymbol());
0213         ui.StitchSymbol->setIcon(
0214             SymbolListWidget::createIcon(SymbolManager::library(m_dialogPalette.symbolLibrary())->symbol(m_dialogPalette.flosses().value(i)->stitchSymbol()),
0215                                          22));
0216     }
0217 }
0218 
0219 void PaletteManagerDlg::on_BackstitchSymbol_activated(int index)
0220 {
0221     Qt::PenStyle style = Qt::SolidLine;
0222 
0223     if (index == 1) {
0224         style = Qt::DashLine;
0225     } else if (index == 2) {
0226         style = Qt::DotLine;
0227     } else if (index == 3) {
0228         style = Qt::DashDotLine;
0229     } else if (index == 4) {
0230         style = Qt::DashDotDotLine;
0231     }
0232 
0233     m_dialogPalette.floss(paletteIndex(ui.CurrentList->currentItem()->data(Qt::UserRole).toString()))->setBackstitchSymbol(style);
0234 }
0235 
0236 void PaletteManagerDlg::on_NewFloss_clicked(bool)
0237 {
0238     QPointer<NewFlossDlg> newFlossDlg = new NewFlossDlg(this, m_scheme);
0239 
0240     if (newFlossDlg->exec()) {
0241         Floss *floss = newFlossDlg->floss();
0242 
0243         if (floss) {
0244             QListWidgetItem *listWidgetItem = new QListWidgetItem;
0245             listWidgetItem->setText(QString::fromLatin1("%1 %2").arg(floss->name(), floss->description()));
0246             listWidgetItem->setData(Qt::DecorationRole, QColor(floss->color()));
0247             listWidgetItem->setData(Qt::UserRole, QString(floss->name()));
0248 
0249             if (contains(floss->name())) {
0250                 insertListWidgetItem(ui.CurrentList, listWidgetItem);
0251 
0252                 if (m_flossUsage.contains(paletteIndex(floss->name())) && m_flossUsage[paletteIndex(floss->name())].totalStitches()) {
0253                     listWidgetItem->setForeground(QBrush(Qt::gray));
0254                 }
0255             } else {
0256                 insertListWidgetItem(ui.ColorList, listWidgetItem);
0257             }
0258         }
0259     }
0260 
0261     delete newFlossDlg;
0262 }
0263 
0264 void PaletteManagerDlg::on_ClearUnused_clicked(bool)
0265 {
0266     for (int row = 0; row < ui.CurrentList->count();) {
0267         ui.CurrentList->setCurrentRow(row);
0268         QListWidgetItem *listWidgetItem = ui.CurrentList->currentItem();
0269         int i = paletteIndex(listWidgetItem->data(Qt::UserRole).toString());
0270 
0271         if (!m_flossUsage.contains(i) || m_flossUsage[i].totalStitches() == 0) {
0272             on_RemoveFloss_clicked(true);
0273         } else {
0274             row++;
0275         }
0276     }
0277 }
0278 
0279 void PaletteManagerDlg::on_Calibrate_clicked(bool)
0280 {
0281     QPointer<CalibrateFlossDlg> calibrateFlossDlg = new CalibrateFlossDlg(this, m_dialogPalette.schemeName());
0282 
0283     if (calibrateFlossDlg->exec() == QDialog::Accepted) {
0284         fillLists();
0285     }
0286 }
0287 
0288 void PaletteManagerDlg::on_PickColor_clicked()
0289 {
0290     setMouseTracking(true);
0291     setCursor(Qt::CrossCursor);
0292     grabMouse();
0293 }
0294 
0295 void PaletteManagerDlg::mouseMoveEvent(QMouseEvent *event)
0296 {
0297     QPoint hotSpot = event->globalPos();
0298     QColor color(QGuiApplication::primaryScreen()->grabWindow(0, hotSpot.x(), hotSpot.y(), 1, 1).toImage().pixel(0, 0));
0299     QPixmap pixmap(32, 32);
0300     pixmap.fill(color);
0301 
0302     QPainter painter(&pixmap);
0303     painter.setRenderHint(QPainter::Antialiasing, false);
0304     painter.drawLine(3, 0, 3, 7);
0305     painter.drawLine(4, 0, 4, 7);
0306     painter.drawLine(0, 3, 7, 3);
0307     painter.drawLine(0, 4, 7, 4);
0308     painter.drawRect(8, 8, 23, 23);
0309     painter.end();
0310 
0311     pixmap.setMask(QBitmap().fromData(QSize(32, 32), pickColorCursorMask, QImage::Format_Mono));
0312     setCursor(QCursor(pixmap, 4, 4));
0313 }
0314 
0315 void PaletteManagerDlg::mouseReleaseEvent(QMouseEvent *event)
0316 {
0317     releaseMouse();
0318     setCursor(Qt::ArrowCursor);
0319     setMouseTracking(false);
0320 
0321     QColor color(QGuiApplication::primaryScreen()->grabWindow(0).toImage().pixel(event->globalPos()));
0322     Floss *floss = m_scheme->convert(color);
0323 
0324     QList<QListWidgetItem *> foundItems = ui.CurrentList->findItems(floss->name(), Qt::MatchStartsWith);
0325 
0326     if (foundItems.count()) {
0327         ui.CurrentList->setCurrentItem(foundItems.at(0));
0328         ui.CurrentList->setFocus();
0329     } else {
0330         foundItems = ui.ColorList->findItems(floss->name(), Qt::MatchStartsWith);
0331 
0332         if (foundItems.count()) {
0333             ui.ColorList->setCurrentItem(foundItems.at(0));
0334             ui.ColorList->setFocus();
0335         }
0336     }
0337 }
0338 
0339 void PaletteManagerDlg::on_DialogButtonBox_accepted()
0340 {
0341     accept();
0342 }
0343 
0344 void PaletteManagerDlg::on_DialogButtonBox_rejected()
0345 {
0346     reject();
0347 }
0348 
0349 void PaletteManagerDlg::on_DialogButtonBox_helpRequested()
0350 {
0351     KHelpClient::invokeHelp(QStringLiteral("PaletteManagerDialog"), QStringLiteral("kxstitch"));
0352 }
0353 
0354 void PaletteManagerDlg::fillLists()
0355 {
0356     ui.ColorList->clear();
0357     ui.CurrentList->clear();
0358     ui.CurrentScheme->setText(m_scheme->schemeName());
0359 
0360     foreach (const Floss *floss, m_scheme->flosses()) {
0361         QListWidgetItem *listWidgetItem = new QListWidgetItem;
0362         listWidgetItem->setText(QString::fromLatin1("%1 %2").arg(floss->name(), floss->description()));
0363         listWidgetItem->setData(Qt::DecorationRole, QColor(floss->color()));
0364         listWidgetItem->setData(Qt::UserRole, QString(floss->name()));
0365 
0366         if (contains(floss->name())) {
0367             insertListWidgetItem(ui.CurrentList, listWidgetItem);
0368 
0369             if (m_flossUsage.contains(paletteIndex(floss->name())) && m_flossUsage[paletteIndex(floss->name())].totalStitches()) {
0370                 listWidgetItem->setForeground(QBrush(Qt::gray));
0371             }
0372         } else {
0373             insertListWidgetItem(ui.ColorList, listWidgetItem);
0374         }
0375     }
0376 
0377     /* The following should have worked, but setting the currentRow to -1 doesn't emit
0378         the signal and consequently doesn't call the slot
0379 
0380     ui.CurrentList->setCurrentRow(ui.CurrentList->count()?0:-1);
0381     ui.ColorList->setCurrentRow(ui.ColorList->count()?0:-1);
0382     */
0383 
0384     if (ui.CurrentList->count()) {
0385         ui.CurrentList->setCurrentRow(0);
0386     } else {
0387         on_CurrentList_currentRowChanged(-1);
0388     }
0389 
0390     if (ui.ColorList->count()) {
0391         ui.ColorList->setCurrentRow(0);
0392     } else {
0393         on_ColorList_currentRowChanged(-1);
0394     }
0395 }
0396 
0397 void PaletteManagerDlg::insertListWidgetItem(QListWidget *listWidget, QListWidgetItem *listWidgetItem)
0398 {
0399     int rows = listWidget->count();
0400 
0401     for (int row = 0; row < rows; row++) {
0402         if (listWidgetItem->data(Qt::UserRole).toInt() < listWidget->item(row)->data(Qt::UserRole).toInt()) {
0403             do {
0404                 QListWidgetItem *oldListWidgetItem = listWidget->item(row);
0405                 listWidget->insertItem(row, listWidgetItem);
0406                 listWidgetItem = oldListWidgetItem;
0407             } while (++row < rows);
0408         }
0409     }
0410 
0411     listWidget->addItem(listWidgetItem);
0412 }
0413 
0414 bool PaletteManagerDlg::contains(const QString &flossName) const
0415 {
0416     for (QMap<int, DocumentFloss *>::const_iterator i = m_dialogPalette.flosses().constBegin(); i != m_dialogPalette.flosses().constEnd(); ++i) {
0417         if (flossName == i.value()->flossName()) {
0418             return true;
0419         }
0420     }
0421 
0422     return false;
0423 }
0424 
0425 int PaletteManagerDlg::paletteIndex(const QString &flossName) const
0426 {
0427     for (QMap<int, DocumentFloss *>::const_iterator i = m_dialogPalette.flosses().constBegin(); i != m_dialogPalette.flosses().constEnd(); ++i) {
0428         if (flossName == i.value()->flossName()) {
0429             return i.key();
0430         }
0431     }
0432 
0433     return -1;
0434 }
0435 
0436 bool PaletteManagerDlg::symbolsAvailable() const
0437 {
0438     return (SymbolManager::library(m_dialogPalette.symbolLibrary())->indexes().count() > m_dialogPalette.flosses().count());
0439 }
0440 
0441 #include "moc_PaletteManagerDlg.cpp"