[editor] 为LayerStyleContainer重载了<<运算符 | #30

dev-wuyize
ArgonarioD 2023-03-23 01:44:28 +08:00
parent ba4be72918
commit 2f9b988dac
7 changed files with 122 additions and 31 deletions

View File

@ -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) for (const auto& style : jsonArray)
{ {
container.useStyle(LayerStyle::fromJson(style.toObject())); container.useStyle(LayerStyle::fromJson(style.toObject()));
@ -102,20 +102,20 @@ LayerStyleContainer LayerStyleContainer::fromJson(bool isClosedElement, const QJ
return container; return container;
} }
LayerStyleContainer::LayerStyleContainer(bool isClosedElement) : hash(0) LayerStyleContainer::LayerStyleContainer(ElementType elementType) : hash(0)
{ {
for (const auto& style : commonStyles) for (const auto& style : commonStyles)
{ {
unusedStyles.insert(style); unusedStyles.insert(style);
} }
if (isClosedElement) if (elementType & LayerStyleContainer::TYPE_CLOSED)
{ {
for (const auto& style : closedOnlyStyles) for (const auto& style : closedOnlyStyles)
{ {
unusedStyles.insert(style); unusedStyles.insert(style);
} }
} }
else if (elementType & LayerStyleContainer::TYPE_UNCLOSED)
{ {
for (const auto& style : unclosedOnlyStyles) for (const auto& style : unclosedOnlyStyles)
{ {
@ -182,13 +182,29 @@ std::map<QString, std::shared_ptr<LayerStyle>>::iterator LayerStyleContainer::en
return styles.end(); return styles.end();
} }
bool LayerStyleContainer::useStyle(const std::shared_ptr<LayerStyle>& style) std::map<QString, std::shared_ptr<LayerStyle>>::const_iterator LayerStyleContainer::cbegin() const
{ {
auto styleNode = unusedStyles.extract(style->getDisplayName()); return styles.cbegin();
}
std::map<QString, std::shared_ptr<LayerStyle>>::const_iterator LayerStyleContainer::cend() const
{
return styles.cend();
}
bool LayerStyleContainer::useStyle(const std::shared_ptr<LayerStyle>& style, bool forceOverride)
{
const auto styleDisplayName = style->getDisplayName();
auto styleNode = unusedStyles.extract(styleDisplayName);
if (styleNode.empty()) if (styleNode.empty())
{
if (!forceOverride || !styles.contains(styleDisplayName))
{ {
return false; return false;
} }
styles[styleDisplayName] = style;
return true;
}
styles[styleNode.key()] = style; styles[styleNode.key()] = style;
usedStyles.insert(std::move(styleNode)); usedStyles.insert(std::move(styleNode));
return true; return true;
@ -259,6 +275,18 @@ bool LayerStyleContainer::operator==(const LayerStyleContainer& other) const
return std::ranges::equal(styles | std::views::values, other.styles | std::views::values); 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> StrokeElementLayerStyle::fromJson(const QJsonObject& json) std::unique_ptr<StrokeElementLayerStyle> StrokeElementLayerStyle::fromJson(const QJsonObject& json)
{ {
auto ptr = std::make_unique<StrokeElementLayerStyle>( auto ptr = std::make_unique<StrokeElementLayerStyle>(

View File

@ -116,27 +116,35 @@ private:
std::map<QString, std::shared_ptr<LayerStyle>> styles; std::map<QString, std::shared_ptr<LayerStyle>> styles;
size_t hash; size_t hash;
public: 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); static LayerStyleContainer fromJson(ElementType elementType, const QJsonArray& jsonArray);
std::vector<Renderer::BaseStyle> toBaseStyles() const override;
QJsonArray toJson() const;
bool empty() const; LayerStyleContainer(ElementType elementType);
bool full() const; [[nodiscard]] std::vector<Renderer::BaseStyle> toBaseStyles() const override;
std::map<QString, std::shared_ptr<LayerStyle>>::iterator begin(); [[nodiscard]] QJsonArray toJson() const;
std::map<QString, std::shared_ptr<LayerStyle>>::iterator end();
QStringList unusedStyleNames() const; [[nodiscard]] bool empty() const;
std::unique_ptr<LayerStyle> makeUnusedStyle(const QString& styleName) const; [[nodiscard]] bool full() const;
bool useStyle(const std::shared_ptr<LayerStyle>& style); [[nodiscard]] std::map<QString, std::shared_ptr<LayerStyle>>::iterator begin();
[[nodiscard]] std::map<QString, std::shared_ptr<LayerStyle>>::iterator end();
[[nodiscard]] std::map<QString, std::shared_ptr<LayerStyle>>::const_iterator cbegin() const;
[[nodiscard]] std::map<QString, std::shared_ptr<LayerStyle>>::const_iterator cend() const;
[[nodiscard]] QStringList unusedStyleNames() const;
[[nodiscard]] std::unique_ptr<LayerStyle> makeUnusedStyle(const QString& styleName) const;
bool useStyle(const std::shared_ptr<LayerStyle>& style, bool forceOverride = false);
bool overrideStyle(const std::shared_ptr<LayerStyle>& style); bool overrideStyle(const std::shared_ptr<LayerStyle>& style);
bool dropStyle(const QString& styleName); bool dropStyle(const QString& styleName);
std::shared_ptr<LayerStyle> getStyle(const QString& styleName) const; [[nodiscard]] std::shared_ptr<LayerStyle> getStyle(const QString& styleName) const;
float boundingBoxAffectValue() const; [[nodiscard]] float boundingBoxAffectValue() const;
size_t getHash() 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;
/** /**
* *

View File

@ -79,7 +79,9 @@ FolderLayerWrapper::FolderLayerWrapper(QJsonObject json, ElementManager *element
LeafLayerWrapper::LeafLayerWrapper(QJsonObject json, ElementManager* elementManager, FolderLayerWrapper* parent) LeafLayerWrapper::LeafLayerWrapper(QJsonObject json, ElementManager* elementManager, FolderLayerWrapper* parent)
: LayerWrapper(json, parent, elementManager), : LayerWrapper(json, parent, elementManager),
wrappedElement(elementManager->getElementById(json.value("element").toInt())), 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; qDebug() << json.value("name").toString() << " " << this;
if(wrappedElement != nullptr) if(wrappedElement != nullptr)

View File

@ -21,37 +21,37 @@ InfoDisplayWidget::InfoDisplayWidget(QWidget* parent) :QWidget(parent)
ui.rotation->setLabel(("旋转角度")); ui.rotation->setLabel(("旋转角度"));
ui.scaleX->setLabel(("水平缩放")); ui.scaleX->setLabel(("水平缩放"));
ui.scaleY->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); 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) if (fabs(content.toDouble() - this->displayLayer->property.rotation) < 1e-6)
return; return;
this->displayLayer->property.rotation = content.toDouble(); this->displayLayer->property.setRotation(content.toDouble());
emit triggerCentralRefresh(); emit triggerCentralRefresh();
}); });
ui.offsetX->setValidator(new QDoubleValidator(-10000, 10000, 2, this)); 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) if (fabs(content.toDouble() - this->displayLayer->property.offset.x()) < 1e-6)
return; return;
this->displayLayer->property.offset = { content.toDouble(), this->displayLayer->property.offset.y() }; this->displayLayer->property.offset = { content.toDouble(), this->displayLayer->property.offset.y() };
emit triggerCentralRefresh(); emit triggerCentralRefresh();
}); });
ui.offsetY->setValidator(new QDoubleValidator(-10000, 10000, 2, this)); 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) if (fabs(content.toDouble() - this->displayLayer->property.offset.y()) < 1e-6)
return; return;
this->displayLayer->property.offset = { this->displayLayer->property.offset.x(), content.toDouble() }; this->displayLayer->property.offset = { this->displayLayer->property.offset.x(), content.toDouble() };
emit triggerCentralRefresh(); emit triggerCentralRefresh();
}); });
ui.scaleX->setValidator(new QDoubleValidator(0, 10000, 6, this)); 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) if (fabs(content.toDouble() - this->displayLayer->property.scale.x()) < 1e-6)
return; return;
this->displayLayer->property.scale = { content.toDouble(), this->displayLayer->property.scale.y() }; this->displayLayer->property.scale = { content.toDouble(), this->displayLayer->property.scale.y() };
emit triggerCentralRefresh(); emit triggerCentralRefresh();
}); });
ui.scaleY->setValidator(new QDoubleValidator(0, 10000, 6, this)); 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) if (fabs(content.toDouble() - this->displayLayer->property.scale.y()) < 1e-6)
return; return;
this->displayLayer->property.scale = { this->displayLayer->property.scale.x(), content.toDouble() }; this->displayLayer->property.scale = { this->displayLayer->property.scale.x(), content.toDouble() };

View File

@ -0,0 +1,49 @@
#include "CppUnitTest.h"
#include "Editor/LayerStyle.h"
#include <QGuiApplication>
#include <QtWidgets/QApplication>
using namespace Microsoft::VisualStudio::CppUnitTestFramework;
namespace UnitTest
{
TEST_CLASS(LayerStyleContainerTest)
{
private:
char* argv[1];
int argc;
LayerStyleContainer containerParent, containerChild;
public:
LayerStyleContainerTest() :
argv{ const_cast<char*>("") }, 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());
}
};
}

View File

@ -111,6 +111,7 @@
<DynamicSource Condition="'$(Configuration)|$(Platform)'=='Release|x64'">input</DynamicSource> <DynamicSource Condition="'$(Configuration)|$(Platform)'=='Release|x64'">input</DynamicSource>
<QtMocFileName Condition="'$(Configuration)|$(Platform)'=='Release|x64'">%(Filename).moc</QtMocFileName> <QtMocFileName Condition="'$(Configuration)|$(Platform)'=='Release|x64'">%(Filename).moc</QtMocFileName>
</ClCompile> </ClCompile>
<ClCompile Include="LayerStyleTest.cpp" />
<ClCompile Include="PaintingTest.cpp"> <ClCompile Include="PaintingTest.cpp">
<DynamicSource Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">input</DynamicSource> <DynamicSource Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">input</DynamicSource>
<QtMocFileName Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">%(Filename).moc</QtMocFileName> <QtMocFileName Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">%(Filename).moc</QtMocFileName>

View File

@ -51,5 +51,8 @@
<ClCompile Include="StyleTest.cpp"> <ClCompile Include="StyleTest.cpp">
<Filter>Source Files</Filter> <Filter>Source Files</Filter>
</ClCompile> </ClCompile>
<ClCompile Include="LayerStyleTest.cpp">
<Filter>Source Files</Filter>
</ClCompile>
</ItemGroup> </ItemGroup>
</Project> </Project>