#include "ContentView.h" #include "UI/LassoControls.h" #include "UI/EffectsSheet.h" #include "UI/FilterSheet.h" #include "UI/HueSaturationSheet.h" #include "UI/LevelsSheet.h" #include "UI/RawDevelopSheet.h" #include #include #include void ContentView::synchronizePanels() { // A panel opens with its edit; close and Escape cancel. if (m_levelsShown != m_session.levels().has_value()) { m_levelsShown = m_session.levels().has_value(); if (m_levelsShown) { m_levelsPanel.onClose = [this] { m_session.cancelLevels(); }; m_levelsPanel.show(QStringLiteral("Levels"), new LevelsSheet(m_session)); } else { m_levelsPanel.close(); } } if (m_hueSaturationShown != m_session.hueSaturation().has_value()) { m_hueSaturationShown = m_session.hueSaturation().has_value(); if (m_hueSaturationShown) { m_adjustmentPanel.onClose = [this] { m_session.cancelHueSaturation(); }; m_adjustmentPanel.show(QStringLiteral("Hue/Saturation"), new HueSaturationSheet(m_session)); } else { m_adjustmentPanel.close(); } } // Swift's onChange of the amount's question: a sheet per question. if (m_selectionAmountShown != m_session.selectionAmountOperation()) { m_selectionAmountShown = m_session.selectionAmountOperation(); if (m_selectionAmountShown) { m_selectionAmountPanel.onClose = [this] { m_session.setSelectionAmountOperation(std::nullopt); }; m_selectionAmountPanel.show(rawValue(*m_selectionAmountShown) + QStringLiteral(" Selection"), new SelectionAmountSheet(m_session, *m_selectionAmountShown)); } else { m_selectionAmountPanel.close(); } } if (m_filterShown != m_session.filterEdit().has_value()) { m_filterShown = m_session.filterEdit().has_value(); if (m_filterShown) { m_filterPanel.onClose = [this] { m_session.cancelFilter(); }; m_filterPanel.show(rawValue(m_session.filterEdit()->kind), new FilterSheet(m_session)); } else { m_filterPanel.close(); } } // Swift's onChange of the layers: a vanished effect's panel goes. if (const std::optional editing = m_session.effectsEditing()) { const std::vector &layers = m_session.document() ? m_session.document()->layers : std::vector(); const int index = indexOf(layers, editing->layerID); if (index < 0 || !layers[size_t(index)].effects || !layers[size_t(index)].effects->contains(editing->kind)) { if (m_session.colorPicker() && m_session.colorPicker()->target.kind == ColorPickerTarget::Kind::effect) m_session.closeColorPicker(false); m_session.setEffectsEditing(std::nullopt); m_session.setEffectsEditingOriginal(std::nullopt); } } // Swift's onChange of effectsEditing: a panel for each choice. if (m_effectsShown != m_session.effectsEditing()) { m_effectsShown = m_session.effectsEditing(); if (m_effectsShown) { m_effectsPanel.onClose = [this] { m_session.finishEffectsEditing(false); }; m_effectsPanel.show(rawValue(m_effectsShown->kind), new EffectsSheet(m_session, m_effectsShown->kind)); } else { m_effectsPanel.close(); } } } void ContentView::showImporter() { if (!m_session.showsImporter()) { // Dismissed from elsewhere, as a cleared binding dismisses Swift's. if (QFileDialog *panel = std::exchange(m_importer, nullptr)) panel->reject(); return; } if (m_importer) return; m_importer = new QFileDialog(this); m_importer->setAttribute(Qt::WA_DeleteOnClose); m_importer->setFileMode(QFileDialog::ExistingFiles); m_importer->setNameFilter(QStringLiteral("Images (*.jpg *.jpeg *.png *.heic *.tif *.tiff *.psd %1)").arg(RawImporter::globs().join(' '))); connect(m_importer, &QDialog::finished, this, [this, panel = m_importer.data()](int result) { // Ours no longer: the flag must not reject it again. if (m_importer != panel) return; m_importer = nullptr; m_session.setShowsImporter(false); if (result == QDialog::Accepted) m_session.importImages(panel->selectedUrls()); }); m_importer->open(); } void ContentView::showAlert(QPointer &alert, const QString &title, const std::optional &message, const std::function &dismiss) { if (!message) { if (QMessageBox *shown = std::exchange(alert, nullptr)) shown->reject(); return; } // SwiftUI's alert shows its message as it stands. if (alert) { alert->setInformativeText(*message); return; } alert = new QMessageBox(this); alert->setAttribute(Qt::WA_DeleteOnClose); alert->setIcon(QMessageBox::Warning); alert->setText(title); alert->setInformativeText(*message); alert->addButton(QStringLiteral("OK"), QMessageBox::AcceptRole); connect(alert, &QDialog::finished, this, [&alert, shown = alert.data(), dismiss] { if (alert != shown) return; alert = nullptr; dismiss(); }); alert->open(); } void ContentView::showConversionSheet() { const std::optional &request = m_session.conversionRequest(); if (!m_session.showsConversionSheet() || !request) { // Ours no longer, so the close answers nothing. if (QDialog *shown = std::exchange(m_conversionSheet, nullptr)) shown->reject(); return; } if (m_conversionSheet && m_conversionShown == *request) return; m_conversionShown = *request; if (!m_conversionSheet) { m_conversionSheet = new QDialog(this); m_conversionSheet->setObjectName(QStringLiteral("conversionSheet")); m_conversionSheet->setAttribute(Qt::WA_DeleteOnClose); auto *layout = new QVBoxLayout(m_conversionSheet); layout->setContentsMargins(0, 0, 0, 0); // Escape and the close button cancel, as Swift's dismissal. connect(m_conversionSheet, &QDialog::finished, this, [this, shown = m_conversionSheet.data()] { if (m_conversionSheet != shown) return; m_session.finishConversion(false); }); } // Reading gives way to the list: new content. for (PSDConversionSheet *old : m_conversionSheet->findChildren(Qt::FindDirectChildrenOnly)) { old->hide(); old->deleteLater(); } m_conversionSheet->setWindowTitle(request->title); m_conversionSheet->layout()->addWidget(new PSDConversionSheet(*request, [this](bool confirmed) { m_session.finishConversion(confirmed); }, m_conversionSheet)); m_conversionSheet->open(); } void ContentView::showRawDevelopSheet() { const std::optional &request = m_session.rawDevelop(); if (!request) { // Ours no longer, so the close answers nothing. if (QDialog *shown = std::exchange(m_rawSheet, nullptr)) shown->reject(); return; } if (m_rawSheet) return; m_rawSheet = new QDialog(this); m_rawSheet->setObjectName(QStringLiteral("rawDevelopSheet")); m_rawSheet->setAttribute(Qt::WA_DeleteOnClose); m_rawSheet->setWindowTitle(QStringLiteral("Develop RAW")); auto *layout = new QVBoxLayout(m_rawSheet); layout->setContentsMargins(0, 0, 0, 0); layout->setSizeConstraint(QLayout::SetFixedSize); // Escape and the close button cancel, as Swift's dismissal. connect(m_rawSheet, &QDialog::finished, this, [this, shown = m_rawSheet.data()] { if (m_rawSheet == shown) m_session.finishRawDevelop(std::nullopt); }); layout->addWidget(new RawDevelopSheet(*request, [this](std::optional settings) { m_session.finishRawDevelop(settings); }, m_rawSheet)); m_rawSheet->open(); }