From c15e8c3a5ba9629aaaf54cf19afeb26cd2a3e286 Mon Sep 17 00:00:00 2001 From: ArgonarioD Date: Sat, 18 Mar 2023 03:51:47 +0800 Subject: [PATCH] =?UTF-8?q?[style]=20=E9=87=8D=E6=96=B0=E8=AE=BE=E8=AE=A1?= =?UTF-8?q?=E4=BA=86LayerStyle=E5=9C=A8Layer=E4=B8=AD=E7=9A=84=E5=AD=98?= =?UTF-8?q?=E5=82=A8=E5=BD=A2=E5=BC=8F=20=E6=96=B0=E5=A2=9E=E4=BA=86LayerS?= =?UTF-8?q?tyleContainer=E7=B1=BB=EF=BC=8C=E4=BF=AE=E6=94=B9=E4=BA=86?= =?UTF-8?q?=E7=9B=B8=E5=85=B3=E4=BB=A3=E7=A0=81=20=E4=BF=AE=E6=94=B9?= =?UTF-8?q?=E4=BA=86=E9=83=A8=E5=88=86bad=20smells?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../LayerStyleDialog.cpp | 48 ++-- .../EditorWidgetComponent/LayerStyleDialog.h | 10 +- .../StrokeStyleWidget.cpp | 30 +- .../src/Editor/GraphicElement.cpp | 13 +- .../src/Editor/GraphicElement.h | 13 +- .../src/Editor/LayerStyle.cpp | 264 ++++++++++++------ .../src/Editor/LayerStyle.h | 72 +++-- .../src/Editor/LayerWrapper.cpp | 12 +- .../src/Editor/LayerWrapper.h | 3 +- .../src/Editor/RightBar/InfoDisplayWidget.cpp | 75 ++--- 10 files changed, 330 insertions(+), 210 deletions(-) diff --git a/ArchitectureColoredPainting/src/Editor/EditorWidgetComponent/LayerStyleDialog.cpp b/ArchitectureColoredPainting/src/Editor/EditorWidgetComponent/LayerStyleDialog.cpp index 478301a..33a3568 100644 --- a/ArchitectureColoredPainting/src/Editor/EditorWidgetComponent/LayerStyleDialog.cpp +++ b/ArchitectureColoredPainting/src/Editor/EditorWidgetComponent/LayerStyleDialog.cpp @@ -3,20 +3,18 @@ #include #include #include -#include -#include LayerStyleDialog::LayerStyleDialog( - QWidget* parent, - std::shared_ptr existedStyle, - std::vector>* excludeStyles -) : QDialog(parent) + LayerStyleContainer& styles, + std::shared_ptr existedStyle, + QWidget* parent +) : QDialog(parent), styles(&styles) { - QVBoxLayout* dialogLayout = new QVBoxLayout(this); + auto* dialogLayout = new QVBoxLayout(this); dialogLayout->setAlignment(Qt::AlignmentFlag::AlignHCenter); this->setLayout(dialogLayout); - if (existedStyle) + if (existedStyle) { this->modifyingStyle = existedStyle->clone(); @@ -28,28 +26,14 @@ LayerStyleDialog::LayerStyleDialog( } else { - std::unordered_set excludeStyleNames; - for(auto &style : *excludeStyles) - { - excludeStyleNames.insert(style->getStyleName()); - } + QStringList unusedStyleNames = styles.unusedStyleNames(); + auto* typeSelector = new QComboBox(this); - QComboBox* typeSelector = new QComboBox(this); - - for (auto& pair : LayerStyle::types) + if (!unusedStyleNames.empty()) { - if (!excludeStyleNames.contains(pair.first)) - { - typeSelector->addItem(pair.first); - if (!this->modifyingStyle) - { - this->modifyingStyle = std::move(pair.second()); - } - } - } + typeSelector->addItems(unusedStyleNames); + this->modifyingStyle = std::move(styles.makeUnusedStyle(unusedStyleNames[0])); - if (typeSelector->count() > 0) - { dialogLayout->addWidget(typeSelector); this->styleContainer = new QGridLayout(this); dialogLayout->addLayout(styleContainer); @@ -57,11 +41,11 @@ LayerStyleDialog::LayerStyleDialog( this->styleWidget = this->modifyingStyle->getInputWidget(); this->styleWidget->setParent(this); this->styleContainer->addWidget(styleWidget); - connect(typeSelector, QOverload::of(&QComboBox::currentIndexChanged), + connect(typeSelector, &QComboBox::currentTextChanged, this, &LayerStyleDialog::onStyleTypeSelectorChanged); } } - QDialogButtonBox* buttonBox = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel, this); + auto* buttonBox = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel, this); connect(buttonBox, &QDialogButtonBox::accepted, this, &LayerStyleDialog::accept); connect(buttonBox, &QDialogButtonBox::rejected, this, &LayerStyleDialog::reject); dialogLayout->addWidget(buttonBox); @@ -73,7 +57,7 @@ void LayerStyleDialog::accept() QDialog::accept(); } -void LayerStyleDialog::onStyleTypeSelectorChanged(int index) +void LayerStyleDialog::onStyleTypeSelectorChanged(const QString& current) { if (this->styleWidget) { @@ -81,8 +65,10 @@ void LayerStyleDialog::onStyleTypeSelectorChanged(int index) this->styleWidget->setParent(nullptr); delete styleWidget; } - this->modifyingStyle = std::move(LayerStyle::types[index].second()); + this->modifyingStyle = std::move(styles->makeUnusedStyle(current)); this->styleWidget = this->modifyingStyle->getInputWidget(); this->styleWidget->setParent(this); this->styleContainer->addWidget(styleWidget, 0, 0, 1, 1); + this->styleWidget->adjustSize(); + this->adjustSize(); } diff --git a/ArchitectureColoredPainting/src/Editor/EditorWidgetComponent/LayerStyleDialog.h b/ArchitectureColoredPainting/src/Editor/EditorWidgetComponent/LayerStyleDialog.h index 8246cca..b703e80 100644 --- a/ArchitectureColoredPainting/src/Editor/EditorWidgetComponent/LayerStyleDialog.h +++ b/ArchitectureColoredPainting/src/Editor/EditorWidgetComponent/LayerStyleDialog.h @@ -9,15 +9,17 @@ class LayerStyleDialog : public QDialog private: QWidget* styleWidget; QGridLayout* styleContainer; + LayerStyleContainer* styles; std::unique_ptr modifyingStyle; public: LayerStyleDialog( - QWidget* parent = nullptr, - std::shared_ptr existedStyle = nullptr, - std::vector>* excludeStyles = nullptr); + LayerStyleContainer& styles, + std::shared_ptr existedStyle = nullptr, + QWidget* parent = nullptr + ); std::shared_ptr layerStyle; private slots: - void onStyleTypeSelectorChanged(int index); + void onStyleTypeSelectorChanged(const QString& current); void accept() override; }; diff --git a/ArchitectureColoredPainting/src/Editor/EditorWidgetComponent/StrokeStyleWidget.cpp b/ArchitectureColoredPainting/src/Editor/EditorWidgetComponent/StrokeStyleWidget.cpp index 7e014db..670e185 100644 --- a/ArchitectureColoredPainting/src/Editor/EditorWidgetComponent/StrokeStyleWidget.cpp +++ b/ArchitectureColoredPainting/src/Editor/EditorWidgetComponent/StrokeStyleWidget.cpp @@ -2,8 +2,8 @@ #include "ColorPicker.h" #include #include +#include -#define radialStroke(stroke) std::dynamic_pointer_cast(stroke->materialStroke) constexpr int COLUMN_WIDTH = 0; constexpr int COLUMN_COLOR = 1; constexpr int COLUMN_METALLIC = 2; @@ -15,12 +15,12 @@ StrokeStyleWidget::StrokeStyleWidget( QWidget* parent ) : QWidget(parent), stroke(stroke) { - QVBoxLayout* viewLayout = new QVBoxLayout(this); + auto* viewLayout = new QVBoxLayout(this); this->setLayout(viewLayout); initStrokeSettings(); - QWidget* strokeProperties = new QWidget(this); - QHBoxLayout* strokePropertiesLayout = new QHBoxLayout(strokeProperties); + auto* strokeProperties = new QWidget(this); + auto* strokePropertiesLayout = new QHBoxLayout(strokeProperties); strokePropertiesLayout->setMargin(0); strokeProperties->setLayout(strokePropertiesLayout); @@ -38,7 +38,7 @@ StrokeStyleWidget::StrokeStyleWidget( void StrokeStyleWidget::initStrokeSettings() { this->enableGradual = new QtMaterialCheckBox(this); - enableGradual->setText(QStringLiteral("启用渐变")); + enableGradual->setText(QStringLiteral("渐变")); enableGradual->setChecked(radialStroke(stroke)->gradual); connect(enableGradual, &QtMaterialCheckBox::toggled, [this](bool checked) { radialStroke(this->stroke)->gradual = checked; @@ -72,7 +72,7 @@ void StrokeStyleWidget::initStrokeSettings() this->widthField = new QtMaterialTextField(this); widthField->setLabel(QStringLiteral("本侧描边宽度")); widthField->setText(QString::number(stroke->halfWidth)); - QDoubleValidator* widthValidator = new QDoubleValidator(0.1, std::numeric_limits::max(), 3, widthField); + auto* widthValidator = new QDoubleValidator(0.1, std::numeric_limits::max(), 3, widthField); widthValidator->setNotation(QDoubleValidator::StandardNotation); widthField->setValidator(widthValidator); connect(widthField, &QtMaterialTextField::textChanged, [this](const QString& changed) { @@ -106,8 +106,12 @@ void StrokeStyleWidget::initTable(std::shared_ptrsetBackgroundColor(QtMaterialStyle::instance().themeColor("primary1")); strokeTable->setSpan(row, 0, 1, 5); strokeTable->setCellWidget(row, 0, addButton); + strokeTable->setMinimumHeight(strokeTable->rowHeight(row) * 5); + strokeTable->setMinimumWidth(strokeTable->sizeHint().width()); + addButton->setFixedHeight(strokeTable->rowHeight(row)); connect(addButton, &QtMaterialRaisedButton::clicked, [this]() { handlingRowInsert = true; auto materialMap = &(radialStroke(this->stroke)->materialMap); @@ -129,37 +133,37 @@ void StrokeStyleWidget::initTable(std::shared_ptrstrokeTable->update(); handlingRowInsert = false; }); - connect(strokeTable, &QTableWidget::currentItemChanged, this, &StrokeStyleWidget::onCurrentItemChanged); connect(strokeTable, &QTableWidget::cellChanged, this, &StrokeStyleWidget::onCellChanged); } void StrokeStyleWidget::setTableRow(int row, float width, Renderer::Material& material) { - QTableWidgetItem* widthItem = new QTableWidgetItem; + auto* widthItem = new QTableWidgetItem; widthItem->setData(Qt::EditRole, width); strokeTable->setItem(row, COLUMN_WIDTH, widthItem); QColor* colorPtr = &(material.color); - QTableWidgetItem* colorItem = new QTableWidgetItem; + auto* colorItem = new QTableWidgetItem; colorItem->setData(Qt::DisplayRole, *colorPtr); strokeTable->setItem(row, COLUMN_COLOR, colorItem); - ColorPicker* colorPicker = new ColorPicker(*colorPtr, strokeTable); + auto* colorPicker = new ColorPicker(*colorPtr, strokeTable); strokeTable->setCellWidget(row, COLUMN_COLOR, colorPicker); connect(colorPicker, &ColorPicker::colorChanged, [this, colorPtr](QColor color) { *colorPtr = color; this->strokeTable->update(); }); - QTableWidgetItem* metallicItem = new QTableWidgetItem; + auto* metallicItem = new QTableWidgetItem; metallicItem->setData(Qt::EditRole, material.metallicF()); strokeTable->setItem(row, COLUMN_METALLIC, metallicItem); - QTableWidgetItem* roughnessItem = new QTableWidgetItem; + auto* roughnessItem = new QTableWidgetItem; roughnessItem->setData(Qt::EditRole, material.roughnessF()); strokeTable->setItem(row, COLUMN_ROUGHNESS, roughnessItem); - QtMaterialRaisedButton* removeButton = new QtMaterialRaisedButton("-", strokeTable); + auto* removeButton = new QtMaterialRaisedButton("-", strokeTable); + removeButton->setBackgroundColor(QtMaterialStyle::instance().themeColor("primary1")); removeButton->setFixedSize(20, 20); strokeTable->setCellWidget(row, COLUMN_OPERATIONS, removeButton); connect(removeButton, &QtMaterialRaisedButton::clicked, [this, row]() { diff --git a/ArchitectureColoredPainting/src/Editor/GraphicElement.cpp b/ArchitectureColoredPainting/src/Editor/GraphicElement.cpp index f515210..8896f9e 100644 --- a/ArchitectureColoredPainting/src/Editor/GraphicElement.cpp +++ b/ArchitectureColoredPainting/src/Editor/GraphicElement.cpp @@ -48,11 +48,11 @@ PixelPath GroupElement::getPaintObject() const } //TODO: apply styles and send back -PixelPath SimpleElement::getPaintObject(std::vector>* styles) const { +PixelPath SimpleElement::getPaintObject(const LayerStyleContainer& styles) const { return this->getPaintObject(); } -PixelPath GroupElement::getPaintObject(std::vector>* styles) const { +PixelPath GroupElement::getPaintObject(const LayerStyleContainer& styles) const { return getPaintObject(); } @@ -92,7 +92,7 @@ QJsonObject GroupElement::toJson() const return result; } -void SimpleElement::paint(QPainter* painter, QTransform transform, const vector>& styles) +void SimpleElement::paint(QPainter* painter, QTransform transform, const LayerStyleContainer& styles) { painter->save(); painter->setTransform(transform); @@ -102,9 +102,6 @@ void SimpleElement::paint(QPainter* painter, QTransform transform, const vector< } else { - std::shared_ptr style; - style = styles[0]; - double angle = atan(transform.m12() / transform.m11()); double maxScale; if (fabs(cos(angle))>1e-5) @@ -112,7 +109,7 @@ void SimpleElement::paint(QPainter* painter, QTransform transform, const vector< else maxScale = std::max(fabs(transform.m12() / sin(angle)), fabs(transform.m21() / sin(angle))); double pixelRatio = maxScale * QGuiApplication::primaryScreen()->devicePixelRatio(); - auto [img, mov] = Renderer::ElementRenderer::instance()->drawElement(painterPath, *style, pixelRatio); + auto [img, mov] = Renderer::ElementRenderer::instance()->drawElement(painterPath, styles, pixelRatio); transform.translate(mov.x(), mov.y()); painter->setTransform(transform.scale(1 / pixelRatio, 1 / pixelRatio)); painter->drawImage(0, 0, img); @@ -120,7 +117,7 @@ void SimpleElement::paint(QPainter* painter, QTransform transform, const vector< painter->restore(); } -void GroupElement::paint(QPainter* painter, QTransform transform, const vector>& styles) +void GroupElement::paint(QPainter* painter, QTransform transform, const LayerStyleContainer& styles) { sourceLayer->paint(painter, transform); } diff --git a/ArchitectureColoredPainting/src/Editor/GraphicElement.h b/ArchitectureColoredPainting/src/Editor/GraphicElement.h index d417e7e..12e2cfa 100644 --- a/ArchitectureColoredPainting/src/Editor/GraphicElement.h +++ b/ArchitectureColoredPainting/src/Editor/GraphicElement.h @@ -2,7 +2,6 @@ #include "LayerWrapper.h" #include "LayerStyle.h" -#include #include #include #include @@ -27,8 +26,8 @@ public: // TODO: 改为BitmapPath virtual QJsonObject toJson() const = 0; virtual PixelPath getPaintObject() const = 0; - virtual PixelPath getPaintObject(std::vector>*) const = 0; - virtual void paint(QPainter* painter, QTransform transform, const std::vector> &styles) = 0; + virtual PixelPath getPaintObject(const LayerStyleContainer& styles) const = 0; + virtual void paint(QPainter* painter, QTransform transform, const LayerStyleContainer& styles) = 0; virtual QPixmap getPreview(QSize size) = 0; }; @@ -47,8 +46,8 @@ public: SimpleElement(QString filePath); ~SimpleElement() = default; PixelPath getPaintObject() const override; - PixelPath getPaintObject(std::vector>*) const override; - void paint(QPainter* painter, QTransform transform, const std::vector> &styles) override; + PixelPath getPaintObject(const LayerStyleContainer& styles) const override; + void paint(QPainter* painter, QTransform transform, const LayerStyleContainer& styles) override; QPixmap getPreview(QSize size) override; }; @@ -63,9 +62,9 @@ public: GroupElement(FolderLayerWrapper* mSourceLayer); ~GroupElement() = default; PixelPath getPaintObject() const override; - PixelPath getPaintObject(std::vector>*) const override; + PixelPath getPaintObject(const LayerStyleContainer& styles) const override; void setSourceLayer(FolderLayerWrapper* sourceLayer); - void paint(QPainter* painter, QTransform transform, const std::vector> &styles) override; + void paint(QPainter* painter, QTransform transform, const LayerStyleContainer& styles) override; QPixmap getPreview(QSize size) override; }; diff --git a/ArchitectureColoredPainting/src/Editor/LayerStyle.cpp b/ArchitectureColoredPainting/src/Editor/LayerStyle.cpp index 215ec15..5be1b72 100644 --- a/ArchitectureColoredPainting/src/Editor/LayerStyle.cpp +++ b/ArchitectureColoredPainting/src/Editor/LayerStyle.cpp @@ -9,31 +9,29 @@ #include #include #include - -const std::vector()>>> LayerStyle::types = { - { - QStringLiteral("描边"), - []() { return std::make_unique(); } - }, - { - QStringLiteral("填充"), - []() { return std::make_unique(); } - } -}; +#define _USE_JOIN_VIEW_INPUT_RANGE +#include +#include std::vector StrokeElementLayerStyle::toBaseStyles() const { std::vector baseStyles; if (enableEachSideIndependent) { - baseStyles.push_back(Renderer::BaseStyle(std::make_shared(), - strokePair.first)); - baseStyles.push_back(Renderer::BaseStyle(std::make_shared(), - strokePair.second)); + if (!radialStroke(strokePair.first)->materialMap.empty()) + { + baseStyles.push_back(Renderer::BaseStyle(std::make_shared(), + strokePair.first)); + } + if (!radialStroke(strokePair.second)->materialMap.empty()) + { + baseStyles.push_back(Renderer::BaseStyle(std::make_shared(), + strokePair.second)); + } } - else + else if (!radialStroke(strokePair.first)->materialMap.empty()) { - auto material = std::shared_ptr(std::move(strokePair.first->clone())); + const auto material = std::shared_ptr(std::move(strokePair.first->clone())); std::dynamic_pointer_cast(material)->strokeType = Renderer::StrokeType::kBothSides; baseStyles.push_back(Renderer::BaseStyle(std::make_shared(), material)); @@ -41,50 +39,23 @@ std::vector StrokeElementLayerStyle::toBaseStyles() const return baseStyles; } -QString StrokeElementLayerStyle::getStyleName() const -{ - return QStringLiteral("描边"); -} - QWidget* StrokeElementLayerStyle::getInputWidget() { - if (this->strokePair.first == nullptr) - { - auto materialMap = std::map(); - this->strokePair.first = std::shared_ptr(new Renderer::MaterialStyleStroke( - 15, - Renderer::StrokeType::kLeftSide, Renderer::StrokeEndType::kFlat, - std::shared_ptr(new Renderer::StrokeRadialGradient( - materialMap, false - )) - )); - } - if (this->strokePair.second == nullptr) - { - auto materialMap = std::map(); - this->strokePair.second = std::shared_ptr(new Renderer::MaterialStyleStroke( - 15, - Renderer::StrokeType::kRightSide, Renderer::StrokeEndType::kFlat, - std::shared_ptr(new Renderer::StrokeRadialGradient( - materialMap, false - )) - )); - } - QWidget* w = new QWidget; - QListView* materialList = new QListView; + auto* w = new QWidget; + auto* materialList = new QListView; - QVBoxLayout* layout = new QVBoxLayout(w); + auto* layout = new QVBoxLayout(w); layout->setMargin(0); - StrokeStyleWidget* leftStrokeView = new StrokeStyleWidget(this->strokePair.first, w); + auto* leftStrokeView = new StrokeStyleWidget(this->strokePair.first, w); layout->addWidget(leftStrokeView); - - QtMaterialCheckBox* checkEachSideIndependent = new QtMaterialCheckBox(w); - checkEachSideIndependent->setText(QStringLiteral("启用两侧独立描边")); + + auto* checkEachSideIndependent = new QtMaterialCheckBox(w); + checkEachSideIndependent->setText(QStringLiteral("右侧独立描边")); checkEachSideIndependent->setChecked(enableEachSideIndependent); layout->addWidget(checkEachSideIndependent); - StrokeStyleWidget* rightStrokeView = new StrokeStyleWidget(this->strokePair.second, w); + auto* rightStrokeView = new StrokeStyleWidget(this->strokePair.second, w); layout->addWidget(rightStrokeView); rightStrokeView->setDisabled(!this->enableEachSideIndependent); @@ -97,39 +68,180 @@ QWidget* StrokeElementLayerStyle::getInputWidget() QWidget* StrokeElementLayerStyle::getListDisplayWidget() const { - QWidget* w = new QWidget; - QLabel* name = new QLabel(w); + auto* w = new QWidget; + auto* name = new QLabel(w); name->setText(QStringLiteral("描边")); - QHBoxLayout* layout = new QHBoxLayout(w); + auto* layout = new QHBoxLayout(w); layout->setMargin(0); layout->addWidget(name); return w; } +void LayerStyleContainer::computeNewHash() +{ + hash = 0; + for (auto& f : styles + | std::views::values + | std::views::transform(&LayerStyle::toBaseStyles) + | std::views::join + | std::views::transform(&Renderer::BaseStyle::material) + | std::views::transform(&MaterialStyle::encoded) + | std::views::join) + { + const unsigned int u = *reinterpret_cast(&f); + hash ^= u + 0x9e3779b9 + (hash << 6) + (hash >> 2); + } +} + +LayerStyleContainer LayerStyleContainer::fromJson(const QJsonArray& jsonArray) +{ + LayerStyleContainer container; + for (const auto& style : jsonArray) + { + container.useStyle(LayerStyle::fromJson(style.toObject())); + } + return container; +} + +LayerStyleContainer::LayerStyleContainer() : hash(0) +{ + unusedStyles = { { + StrokeElementLayerStyle::displayName(), + [] { return std::make_unique(); } + }, + { + FillElementLayerStyle::displayName(), + [] { return std::make_unique(); } + } }; +} + +std::vector LayerStyleContainer::toBaseStyles() const +{ + std::vector result; + for (const auto& style : styles | std::views::values) + { + auto baseStyles = style->toBaseStyles(); + result.insert(result.end(), + std::make_move_iterator(baseStyles.begin()), + std::make_move_iterator(baseStyles.end())); + } + return result; +} + +QJsonArray LayerStyleContainer::toJson() const +{ + QJsonArray json; + for (const auto& style : styles | std::views::values) + { + json.append(style->toJson()); + } + return json; +} + +QStringList LayerStyleContainer::unusedStyleNames() const +{ + QStringList result; + for(const auto& name : unusedStyles | std::views::keys) + { + result << name; + } + return result; +} + +std::unique_ptr LayerStyleContainer::makeUnusedStyle(const QString& styleName) const +{ + return unusedStyles.at(styleName)(); +} + +bool LayerStyleContainer::empty() const +{ + return styles.empty(); +} + +bool LayerStyleContainer::full() const +{ + return unusedStyles.empty(); +} + +std::map>::iterator LayerStyleContainer::begin() +{ + return styles.begin(); +} + +std::map>::iterator LayerStyleContainer::end() +{ + return styles.end(); +} + +bool LayerStyleContainer::useStyle(const std::shared_ptr& style) +{ + auto styleNode = unusedStyles.extract(style->getDisplayName()); + if (styleNode.empty()) + { + return false; + } + styles[styleNode.key()] = style; + usedStyles.insert(std::move(styleNode)); + return true; +} + +bool LayerStyleContainer::dropStyle(const QString& styleName) +{ + auto styleNode = usedStyles.extract(styleName); + if (styleNode.empty()) + { + return false; + } + styles.erase(styleName); + unusedStyles.insert(std::move(styleNode)); + return true; +} + +inline size_t LayerStyleContainer::getHash() const +{ + return hash; +} + +StrokeElementLayerStyle::StrokeElementLayerStyle() +{ + const auto materialMap = std::map(); + this->strokePair.first = std::make_shared( + 7, + Renderer::StrokeType::kLeftSide, Renderer::StrokeEndType::kFlat, + std::make_shared(materialMap, false) + ); + + this->strokePair.second = std::make_shared( + 7, + Renderer::StrokeType::kRightSide, Renderer::StrokeEndType::kFlat, + std::make_shared(materialMap, false) + ); + +} + StrokeElementLayerStyle::StrokeElementLayerStyle(PMaterialStyleStroke left, PMaterialStyleStroke right) { this->strokePair.first = left; - this->strokePair.second = right ? right : std::dynamic_pointer_cast( - std::shared_ptr(std::move(left->clone())) + this->strokePair.second = right ? right : std::static_pointer_cast( + std::shared_ptr(std::move(left->clone())) ); } StrokeElementLayerStyle::StrokeElementLayerStyle(const StrokeElementLayerStyle& other) { - strokePair.first = std::dynamic_pointer_cast( - std::shared_ptr(std::move(other.strokePair.first->clone())) + strokePair.first = std::static_pointer_cast( + std::shared_ptr(std::move(other.strokePair.first->clone())) ); - strokePair.second = std::dynamic_pointer_cast( - std::shared_ptr(std::move(other.strokePair.second->clone())) + strokePair.second = std::static_pointer_cast( + std::shared_ptr(std::move(other.strokePair.second->clone())) ); enableEachSideIndependent = other.enableEachSideIndependent; } QJsonObject StrokeElementLayerStyle::toJson() const { - // todo: 修改打开逻辑 QJsonObject json; - json["type"] = getTypeName(); + json["type"] = typeName(); json["enableEachSideIndependent"] = enableEachSideIndependent; json["left"] = EncodeUtil::toBase64(strokePair.first->encoded()); json["right"] = EncodeUtil::toBase64(strokePair.second->encoded()); @@ -143,28 +255,24 @@ std::unique_ptr StrokeElementLayerStyle::clone() const std::vector FillElementLayerStyle::toBaseStyles() const { + // TODO: implement return std::vector(); } -QString FillElementLayerStyle::getStyleName() const -{ - return QStringLiteral("填充"); -} - QWidget* FillElementLayerStyle::getInputWidget() { // TODO - QLineEdit* name = new QLineEdit; + auto* name = new QLineEdit; name->setText(QStringLiteral("填充")); return name; } QWidget* FillElementLayerStyle::getListDisplayWidget() const { - QWidget* w = new QWidget; - QLabel* name = new QLabel(w); + auto* w = new QWidget; + auto* name = new QLabel(w); name->setText(QStringLiteral("填充")); - QHBoxLayout* layout = new QHBoxLayout(w); + auto* layout = new QHBoxLayout(w); layout->setMargin(0); layout->addWidget(name); return w; @@ -192,20 +300,20 @@ std::unique_ptr FillElementLayerStyle::clone() const std::unique_ptr LayerStyle::fromJson(const QJsonObject& json) { QString type = json["type"].toString(); - if (type == StrokeElementLayerStyle::getTypeName()) + if (type == StrokeElementLayerStyle::typeName()) { auto ptr = std::make_unique( - std::dynamic_pointer_cast( - std::shared_ptr(std::move(Renderer::MaterialStyle::decoded(EncodeUtil::fromBase64(json["left"].toString())))) + std::static_pointer_cast( + std::shared_ptr(std::move(MaterialStyle::decoded(EncodeUtil::fromBase64(json["left"].toString())))) ), - std::dynamic_pointer_cast( - std::shared_ptr(std::move(Renderer::MaterialStyle::decoded(EncodeUtil::fromBase64(json["right"].toString())))) + std::static_pointer_cast( + std::shared_ptr(std::move(MaterialStyle::decoded(EncodeUtil::fromBase64(json["right"].toString())))) ) ); ptr->enableEachSideIndependent = json["enableEachSideIndependent"].toBool(); return ptr; } - else if (type == FillElementLayerStyle::getTypeName()) + else if (type == FillElementLayerStyle::typeName()) { return std::make_unique(); } diff --git a/ArchitectureColoredPainting/src/Editor/LayerStyle.h b/ArchitectureColoredPainting/src/Editor/LayerStyle.h index 636201d..a310b6e 100644 --- a/ArchitectureColoredPainting/src/Editor/LayerStyle.h +++ b/ArchitectureColoredPainting/src/Editor/LayerStyle.h @@ -1,11 +1,11 @@ #pragma once -#include #include #include -#include -#include +#include +#include #include #include +#include #include "../Renderer/Painting/ElementStyle.h" #include "../Renderer/Painting/MaterialStyleStroke.h" #include "../Renderer/Painting/MaterialStyleFill.h" @@ -13,64 +13,90 @@ using Renderer::MaterialStyle; using Renderer::MaterialStyleStroke; -#define STYLE_TYPENAME(name) static QString getTypeName() { return name; } +#define STYLE_NAME(display_name, type_name) \ + static QString displayName() { return QStringLiteral(display_name); } \ + QString getDisplayName() const override { return QStringLiteral(display_name); } \ + static QString typeName() { return type_name; } +#define radialStroke(stroke) std::static_pointer_cast(stroke->materialStroke) -/** - * 在进行Style的添加时,首先创建空对象,然后直接调用getInputWidget()方法 - * 在进行Style的修改时,直接调用getInputWidget()方法 - * - * 对于LayerStyle的实现类,应该同时实现ElementStyle,并将相同种类的(如描边或填充)的style整合成一个类, - * 对于相同的类,一个图层应该只拥有一个 - */ class LayerStyle : public Renderer::ElementStyle { public: - const static std::vector()>>> types; static std::unique_ptr fromJson(const QJsonObject& json); - virtual QString getStyleName() const = 0; + virtual QString getDisplayName() const = 0; virtual QWidget* getInputWidget() = 0; virtual QWidget* getListDisplayWidget() const = 0; - virtual ~LayerStyle() {}; + virtual ~LayerStyle() = default; virtual QJsonObject toJson() const = 0; virtual std::unique_ptr clone() const = 0; }; +class LayerStyleContainer : public Renderer::ElementStyle +{ + using DisplayNameWithSupplier = std::map()>>; +private: + DisplayNameWithSupplier unusedStyles; + DisplayNameWithSupplier usedStyles; + std::map> styles; + size_t hash; +public: + static LayerStyleContainer fromJson(const QJsonArray& jsonArray); + + LayerStyleContainer(); + std::vector toBaseStyles() const override; + QJsonArray toJson() const; + + bool empty() const; + bool full() const; + std::map>::iterator begin(); + std::map>::iterator end(); + + QStringList unusedStyleNames() const; + std::unique_ptr makeUnusedStyle(const QString& styleName) const; + bool useStyle(const std::shared_ptr& style); + bool dropStyle(const QString& styleName); + size_t getHash() const; + + /** + * 需要在每次更改后手动调用 + */ + void computeNewHash(); +}; + class StrokeElementLayerStyle : public LayerStyle { using PMaterialStyleStroke = std::shared_ptr; -private: - std::pair strokePair; public: - STYLE_TYPENAME("stroke") + STYLE_NAME("描边","stroke") - StrokeElementLayerStyle() = default; + StrokeElementLayerStyle(); StrokeElementLayerStyle(PMaterialStyleStroke left, PMaterialStyleStroke right = nullptr); StrokeElementLayerStyle(const StrokeElementLayerStyle& other); - ~StrokeElementLayerStyle() = default; + ~StrokeElementLayerStyle() override = default; std::vector toBaseStyles() const override; - QString getStyleName() const override; QWidget* getInputWidget() override; QWidget* getListDisplayWidget() const override; QJsonObject toJson() const override; std::unique_ptr clone() const override; + std::pair strokePair; bool enableEachSideIndependent = false; }; class FillElementLayerStyle : public LayerStyle { public: - STYLE_TYPENAME("fill") + STYLE_NAME("填充","fill") + std::vector toBaseStyles() const override; - QString getStyleName() const override; QWidget* getInputWidget() override; QWidget* getListDisplayWidget() const override; FillElementLayerStyle() = default; FillElementLayerStyle(const FillElementLayerStyle& other); - ~FillElementLayerStyle() = default; + ~FillElementLayerStyle() override = default; std::vector> materialStyles; QJsonObject toJson() const override; std::unique_ptr clone() const override; diff --git a/ArchitectureColoredPainting/src/Editor/LayerWrapper.cpp b/ArchitectureColoredPainting/src/Editor/LayerWrapper.cpp index febc24a..9281248 100644 --- a/ArchitectureColoredPainting/src/Editor/LayerWrapper.cpp +++ b/ArchitectureColoredPainting/src/Editor/LayerWrapper.cpp @@ -80,10 +80,7 @@ LeafLayerWrapper::LeafLayerWrapper(QJsonObject json, ElementManager *elementMana int elementIndex = json.value("element").toInt(); wrappedElement = elementManager->getElementById(elementIndex); QJsonArray stylesArray = json.value("styles").toArray(); - for (const auto& style : stylesArray) - { - styles.push_back(LayerStyle::fromJson(style.toObject())); - } + styles = LayerStyleContainer::fromJson(stylesArray); } void LayerWrapper::SimpleProperty::apply(PixelPath&cache) @@ -135,7 +132,7 @@ void LeafLayerWrapper::refresh(LayerWrapper* layer) cache.clear(); if (wrappedElement != nullptr) { - cache.addPath(wrappedElement->getPaintObject(&(this->styles))); + cache.addPath(wrappedElement->getPaintObject(this->styles)); } LayerWrapper::refresh(); } @@ -245,10 +242,7 @@ QJsonObject LeafLayerWrapper::toJson() const QJsonObject json = LayerWrapper::toJson(); json.insert("element", wrappedElement->index); json.insert("is-folder", false); - QJsonArray stylesJson; - for (auto& style : styles) - stylesJson.push_back(style->toJson()); - json.insert("styles", stylesJson); + json.insert("styles", styles.toJson()); return json; } diff --git a/ArchitectureColoredPainting/src/Editor/LayerWrapper.h b/ArchitectureColoredPainting/src/Editor/LayerWrapper.h index 9a76c3b..dd87c4f 100644 --- a/ArchitectureColoredPainting/src/Editor/LayerWrapper.h +++ b/ArchitectureColoredPainting/src/Editor/LayerWrapper.h @@ -98,8 +98,7 @@ class LeafLayerWrapper : public LayerWrapper { public: GraphicElement *wrappedElement; - //const vector styles; - vector> styles; + LayerStyleContainer styles; public: ~LeafLayerWrapper() = default; diff --git a/ArchitectureColoredPainting/src/Editor/RightBar/InfoDisplayWidget.cpp b/ArchitectureColoredPainting/src/Editor/RightBar/InfoDisplayWidget.cpp index d41d374..6e84bd7 100644 --- a/ArchitectureColoredPainting/src/Editor/RightBar/InfoDisplayWidget.cpp +++ b/ArchitectureColoredPainting/src/Editor/RightBar/InfoDisplayWidget.cpp @@ -5,7 +5,6 @@ #include #include #include -#include #include #include @@ -81,39 +80,40 @@ void InfoDisplayWidget::generateLayerForm() layout->addRow("scale-X:", scaleX); layout->addRow("scale-Y:", scaleY); layout->setRowWrapPolicy(QFormLayout::DontWrapRows); - - LeafLayerWrapper* leafP = dynamic_cast(this->displayLayer); - if (leafP) { - QListWidget* styleList = new QListWidget(this); - QListWidgetItem* header = new QListWidgetItem; - QWidget* headerWidget = new QWidget(styleList); - QHBoxLayout* headerLayout = new QHBoxLayout; + if (auto* leafP = dynamic_cast(this->displayLayer); leafP) { + auto* styleList = new QListWidget(this); - QLabel* headerLabel = new QLabel(headerWidget); + auto* header = new QListWidgetItem; + auto* headerWidget = new QWidget(styleList); + auto* headerLayout = new QHBoxLayout; + + auto* headerLabel = new QLabel(headerWidget); headerLabel->setText("鏍峰紡鍒楄〃"); headerLabel->setSizePolicy(QSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding)); //QtMaterialRaisedButton* addStyleButton = new QtMaterialRaisedButton("+", headerWidget); - QPushButton* addStyleButton = new QPushButton("+", headerWidget); + auto* addStyleButton = new QPushButton("+", headerWidget); addStyleButton->setFixedSize(QSize(20, 20)); - if (leafP->styles.size() >= LayerStyle::types.size()) + if (leafP->styles.full()) { addStyleButton->setDisabled(true); } else { - connect(addStyleButton, &QPushButton::clicked, [&, leafP]() { - LayerStyleDialog* dialog = new LayerStyleDialog(nullptr, nullptr, &(leafP->styles)); - dialog->exec(); - if (dialog->layerStyle) - { - leafP->styles.push_back(dialog->layerStyle); - emit requireRefreshPreview(); - emit requireSelfRefresh(); - emit requireRefreshElementWidget(); - } - dialog->deleteLater(); + connect(addStyleButton, &QPushButton::clicked, [&, leafP] { + auto* dialog = new LayerStyleDialog(leafP->styles); + dialog->exec(); + if (dialog->layerStyle) + { + leafP->styles.useStyle(dialog->layerStyle); + leafP->styles.computeNewHash(); + + emit requireRefreshPreview(); + emit requireSelfRefresh(); + emit requireRefreshElementWidget(); + } + dialog->deleteLater(); }); } @@ -179,32 +179,35 @@ void InfoDisplayWidget::generateLayerForm() { leafP->styles.push_back(std::shared_ptr(new StrokeElementLayerStyle())); }*/ - std::vector>* styles = &(leafP->styles); - for (auto styleIterator = styles->begin(); styleIterator != styles->end(); styleIterator++) + auto* styles = &leafP->styles; + for (auto styleIterator = styles->begin(); styleIterator != styles->end(); ++styleIterator) { - QListWidgetItem* item = new QListWidgetItem; - QWidget* w = new QWidget; + auto* item = new QListWidgetItem; + auto* w = new QWidget(this); item->setSizeHint(QSize(50, 40)); - QHBoxLayout* layout = new QHBoxLayout; + auto* layout = new QHBoxLayout(w); layout->setAlignment(Qt::AlignmentFlag::AlignRight); //QtMaterialFlatButton* detailButton = new QtMaterialFlatButton(w); //QtMaterialFlatButton* removeButton = new QtMaterialFlatButton(w); - QPushButton* detailButton = new QPushButton(w); - QPushButton* removeButton = new QPushButton(w); + auto* detailButton = new QPushButton(w); + auto* removeButton = new QPushButton(w); detailButton->setText("..."); detailButton->setFixedSize(QSize(20, 20)); removeButton->setText("脳"); removeButton->setFixedSize(QSize(20, 20)); connect(detailButton, &QPushButton::clicked, this, - [this, styleIterator]() + [this, styles, styleIterator] { - LayerStyleDialog* dialog = new LayerStyleDialog(nullptr, *styleIterator); + auto* dialog = + new LayerStyleDialog(*styles, styleIterator->second); dialog->exec(); if (dialog->layerStyle) { - (*styleIterator) = dialog->layerStyle; + styleIterator->second = dialog->layerStyle; + styles->computeNewHash(); + emit requireRefreshPreview(); emit requireSelfRefresh(); emit requireRefreshElementWidget(); @@ -213,15 +216,17 @@ void InfoDisplayWidget::generateLayerForm() }); connect(removeButton, &QPushButton::clicked, this, - [this, styleIterator, styles]() + [this, styleIterator, styles] { - styles->erase(styleIterator); + styles->dropStyle(styleIterator->first); + styles->computeNewHash(); + emit requireRefreshPreview(); emit requireSelfRefresh(); emit requireRefreshElementWidget(); }); - QWidget* styleDisplayWidget = (*styleIterator)->getListDisplayWidget(); + QWidget* styleDisplayWidget = styleIterator->second->getListDisplayWidget(); styleDisplayWidget->setParent(w); styleDisplayWidget->setSizePolicy(QSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding));