diff --git a/ArchitectureColoredPainting/src/Editor/LayerStyle.cpp b/ArchitectureColoredPainting/src/Editor/LayerStyle.cpp index 582d01d..aabc5de 100644 --- a/ArchitectureColoredPainting/src/Editor/LayerStyle.cpp +++ b/ArchitectureColoredPainting/src/Editor/LayerStyle.cpp @@ -92,9 +92,9 @@ void LayerStyleContainer::computeNewHash() } } -LayerStyleContainer LayerStyleContainer::fromJson(bool isClosedElement, const QJsonArray& jsonArray) +LayerStyleContainer LayerStyleContainer::fromJson(ElementType elementType, const QJsonArray& jsonArray) { - LayerStyleContainer container(isClosedElement); + LayerStyleContainer container(elementType); for (const auto& style : jsonArray) { container.useStyle(LayerStyle::fromJson(style.toObject())); @@ -102,20 +102,20 @@ LayerStyleContainer LayerStyleContainer::fromJson(bool isClosedElement, const QJ return container; } -LayerStyleContainer::LayerStyleContainer(bool isClosedElement) : hash(0) +LayerStyleContainer::LayerStyleContainer(ElementType elementType) : hash(0) { for (const auto& style : commonStyles) { unusedStyles.insert(style); } - if (isClosedElement) + if (elementType & LayerStyleContainer::TYPE_CLOSED) { for (const auto& style : closedOnlyStyles) { unusedStyles.insert(style); } } - else + if (elementType & LayerStyleContainer::TYPE_UNCLOSED) { for (const auto& style : unclosedOnlyStyles) { @@ -182,12 +182,28 @@ std::map>::iterator LayerStyleContainer::en return styles.end(); } -bool LayerStyleContainer::useStyle(const std::shared_ptr& style) +std::map>::const_iterator LayerStyleContainer::cbegin() const { - auto styleNode = unusedStyles.extract(style->getDisplayName()); + return styles.cbegin(); +} + +std::map>::const_iterator LayerStyleContainer::cend() const +{ + return styles.cend(); +} + +bool LayerStyleContainer::useStyle(const std::shared_ptr& style, bool forceOverride) +{ + const auto styleDisplayName = style->getDisplayName(); + auto styleNode = unusedStyles.extract(styleDisplayName); if (styleNode.empty()) { - return false; + if (!forceOverride || !styles.contains(styleDisplayName)) + { + return false; + } + styles[styleDisplayName] = style; + return true; } styles[styleNode.key()] = style; usedStyles.insert(std::move(styleNode)); @@ -259,6 +275,18 @@ bool LayerStyleContainer::operator==(const LayerStyleContainer& other) const return std::ranges::equal(styles | std::views::values, other.styles | std::views::values); } +LayerStyleContainer LayerStyleContainer::operator<<(const LayerStyleContainer& other) const +{ + LayerStyleContainer result = other; + for (const auto& style : std::ranges::subrange(this->cbegin(), this->cend()) + | std::views::values) + { + result.useStyle(style); + } + result.computeNewHash(); + return result; +} + std::unique_ptr StrokeElementLayerStyle::fromJson(const QJsonObject& json) { auto ptr = std::make_unique( diff --git a/ArchitectureColoredPainting/src/Editor/LayerStyle.h b/ArchitectureColoredPainting/src/Editor/LayerStyle.h index d497194..f60cfd4 100644 --- a/ArchitectureColoredPainting/src/Editor/LayerStyle.h +++ b/ArchitectureColoredPainting/src/Editor/LayerStyle.h @@ -116,27 +116,35 @@ private: std::map> styles; size_t hash; public: - static LayerStyleContainer fromJson(bool isClosedElement, const QJsonArray& jsonArray); + using ElementType = unsigned short; + constexpr static ElementType TYPE_ALL = 0xffff; + constexpr static ElementType TYPE_CLOSED = 0b01; + constexpr static ElementType TYPE_UNCLOSED = 0b10; - LayerStyleContainer(bool isClosedElement); - std::vector toBaseStyles() const override; - QJsonArray toJson() const; + static LayerStyleContainer fromJson(ElementType elementType, const QJsonArray& jsonArray); - bool empty() const; - bool full() const; - std::map>::iterator begin(); - std::map>::iterator end(); + LayerStyleContainer(ElementType elementType); + [[nodiscard]] std::vector toBaseStyles() const override; + [[nodiscard]] QJsonArray toJson() const; - QStringList unusedStyleNames() const; - std::unique_ptr makeUnusedStyle(const QString& styleName) const; - bool useStyle(const std::shared_ptr& style); + [[nodiscard]] bool empty() const; + [[nodiscard]] bool full() const; + [[nodiscard]] std::map>::iterator begin(); + [[nodiscard]] std::map>::iterator end(); + [[nodiscard]] std::map>::const_iterator cbegin() const; + [[nodiscard]] std::map>::const_iterator cend() const; + + [[nodiscard]] QStringList unusedStyleNames() const; + [[nodiscard]] std::unique_ptr makeUnusedStyle(const QString& styleName) const; + bool useStyle(const std::shared_ptr& style, bool forceOverride = false); bool overrideStyle(const std::shared_ptr& style); bool dropStyle(const QString& styleName); - std::shared_ptr getStyle(const QString& styleName) const; - float boundingBoxAffectValue() const; - size_t getHash() const; + [[nodiscard]] std::shared_ptr getStyle(const QString& styleName) const; + [[nodiscard]] float boundingBoxAffectValue() const; + [[nodiscard]] size_t getHash() const; - bool operator==(const LayerStyleContainer& other) const; + [[nodiscard]] bool operator==(const LayerStyleContainer& other) const; + [[nodiscard]] LayerStyleContainer operator<<(const LayerStyleContainer& other) const; /** * 需要在每次更改后手动调用 diff --git a/ArchitectureColoredPainting/src/Editor/LayerWrapper.cpp b/ArchitectureColoredPainting/src/Editor/LayerWrapper.cpp index 6beb194..fae4f30 100644 --- a/ArchitectureColoredPainting/src/Editor/LayerWrapper.cpp +++ b/ArchitectureColoredPainting/src/Editor/LayerWrapper.cpp @@ -79,7 +79,9 @@ FolderLayerWrapper::FolderLayerWrapper(QJsonObject json, ElementManager *element LeafLayerWrapper::LeafLayerWrapper(QJsonObject json, ElementManager* elementManager, FolderLayerWrapper* parent) : LayerWrapper(json, parent, elementManager), wrappedElement(elementManager->getElementById(json.value("element").toInt())), - styles(LayerStyleContainer::fromJson(wrappedElement->isClosed(), json.value("styles").toArray())) + styles(LayerStyleContainer::fromJson( + wrappedElement->isClosed() ? LayerStyleContainer::TYPE_CLOSED : LayerStyleContainer::TYPE_UNCLOSED, + json.value("styles").toArray())) { qDebug() << json.value("name").toString() << " " << this; if(wrappedElement != nullptr) diff --git a/ArchitectureColoredPainting/src/Editor/RightBar/InfoDisplayWidget.cpp b/ArchitectureColoredPainting/src/Editor/RightBar/InfoDisplayWidget.cpp index 96950ae..c4e4256 100644 --- a/ArchitectureColoredPainting/src/Editor/RightBar/InfoDisplayWidget.cpp +++ b/ArchitectureColoredPainting/src/Editor/RightBar/InfoDisplayWidget.cpp @@ -21,37 +21,37 @@ InfoDisplayWidget::InfoDisplayWidget(QWidget* parent) :QWidget(parent) ui.rotation->setLabel(("鏃嬭浆瑙掑害")); ui.scaleX->setLabel(("姘村钩缂╂斁")); ui.scaleY->setLabel(("鍨傜洿缂╂斁")); - ui.rotation->setValidator(new QDoubleValidator(-10000, 10000, 6, this)); + ui.rotation->setValidator(new QIntValidator(-360, 360, this)); ui.styleList->setDisabled(true); - connect(ui.rotation, &QLineEdit::textChanged, [=](QString content) { + connect(ui.rotation, &QLineEdit::textChanged, [=](const QString& content) { if (fabs(content.toDouble() - this->displayLayer->property.rotation) < 1e-6) return; - this->displayLayer->property.rotation = content.toDouble(); + this->displayLayer->property.setRotation(content.toDouble()); emit triggerCentralRefresh(); }); ui.offsetX->setValidator(new QDoubleValidator(-10000, 10000, 2, this)); - connect(ui.offsetX, &QLineEdit::textChanged, [=](QString content) { + connect(ui.offsetX, &QLineEdit::textChanged, [=](const QString& content) { if (fabs(content.toDouble() - this->displayLayer->property.offset.x()) < 1e-6) return; this->displayLayer->property.offset = { content.toDouble(), this->displayLayer->property.offset.y() }; emit triggerCentralRefresh(); }); ui.offsetY->setValidator(new QDoubleValidator(-10000, 10000, 2, this)); - connect(ui.offsetY, &QLineEdit::textChanged, [=](QString content) { + connect(ui.offsetY, &QLineEdit::textChanged, [=](const QString& content) { if (fabs(content.toDouble() - this->displayLayer->property.offset.y()) < 1e-6) return; this->displayLayer->property.offset = { this->displayLayer->property.offset.x(), content.toDouble() }; emit triggerCentralRefresh(); }); ui.scaleX->setValidator(new QDoubleValidator(0, 10000, 6, this)); - connect(ui.scaleX, &QLineEdit::textChanged, [=](QString content) { + connect(ui.scaleX, &QLineEdit::textChanged, [=](const QString& content) { if (fabs(content.toDouble() - this->displayLayer->property.scale.x()) < 1e-6) return; this->displayLayer->property.scale = { content.toDouble(), this->displayLayer->property.scale.y() }; emit triggerCentralRefresh(); }); ui.scaleY->setValidator(new QDoubleValidator(0, 10000, 6, this)); - connect(ui.scaleY, &QLineEdit::textChanged, [=](QString content) { + connect(ui.scaleY, &QLineEdit::textChanged, [=](const QString& content) { if (fabs(content.toDouble() - this->displayLayer->property.scale.y()) < 1e-6) return; this->displayLayer->property.scale = { this->displayLayer->property.scale.x(), content.toDouble() }; diff --git a/UnitTest/LayerStyleTest.cpp b/UnitTest/LayerStyleTest.cpp new file mode 100644 index 0000000..3bc7622 --- /dev/null +++ b/UnitTest/LayerStyleTest.cpp @@ -0,0 +1,49 @@ +#include "CppUnitTest.h" +#include "Editor/LayerStyle.h" +#include +#include + +using namespace Microsoft::VisualStudio::CppUnitTestFramework; + +namespace UnitTest +{ + TEST_CLASS(LayerStyleContainerTest) + { + private: + char* argv[1]; + int argc; + LayerStyleContainer containerParent, containerChild; + public: + LayerStyleContainerTest() : + argv{ const_cast("") }, argc(1), + containerParent(LayerStyleContainer::TYPE_ALL), + containerChild(LayerStyleContainer::TYPE_UNCLOSED) + { + QApplication app(argc, argv); + Assert::IsTrue(containerParent.empty()); + Assert::IsTrue(containerChild.empty()); + + auto fillStyle = containerParent.makeUnusedStyle(FillElementLayerStyle::displayName()); + Assert::IsTrue(containerParent.useStyle(std::shared_ptr(std::move(fillStyle)))); + Assert::IsFalse(containerParent.empty()); + Assert::IsFalse(containerParent.full()); + + auto strokeStyle = containerParent.makeUnusedStyle(StrokeElementLayerStyle::displayName()); + containerParent.useStyle(std::shared_ptr(std::move(strokeStyle))); + + auto childStrokeStyle = containerChild.makeUnusedStyle(StrokeElementLayerStyle::displayName()); + containerChild.useStyle(std::shared_ptr(std::move(childStrokeStyle))); + Assert::IsTrue(containerChild.full()); + + containerParent.computeNewHash(); + containerChild.computeNewHash(); + } + + TEST_METHOD(ContainerCoverTest) + { + const auto newContainer = containerParent << containerChild; + Assert::IsTrue(newContainer.full()); + Assert::AreEqual(newContainer.getHash(), containerChild.getHash()); + } + }; +} \ No newline at end of file diff --git a/UnitTest/UnitTest.vcxproj b/UnitTest/UnitTest.vcxproj index 3c5c76d..ee2464b 100644 --- a/UnitTest/UnitTest.vcxproj +++ b/UnitTest/UnitTest.vcxproj @@ -111,6 +111,7 @@ input %(Filename).moc + input %(Filename).moc diff --git a/UnitTest/UnitTest.vcxproj.filters b/UnitTest/UnitTest.vcxproj.filters index 2265b74..df5ed3f 100644 --- a/UnitTest/UnitTest.vcxproj.filters +++ b/UnitTest/UnitTest.vcxproj.filters @@ -51,5 +51,8 @@ Source Files + + Source Files + \ No newline at end of file