diff --git a/ArchitectureColoredPainting/ArchitectureColoredPainting.vcxproj b/ArchitectureColoredPainting/ArchitectureColoredPainting.vcxproj
index a0e5563..91c9f62 100644
--- a/ArchitectureColoredPainting/ArchitectureColoredPainting.vcxproj
+++ b/ArchitectureColoredPainting/ArchitectureColoredPainting.vcxproj
@@ -153,7 +153,7 @@
-
+
@@ -189,7 +189,7 @@
-
+
@@ -197,6 +197,7 @@
+
diff --git a/ArchitectureColoredPainting/ArchitectureColoredPainting.vcxproj.filters b/ArchitectureColoredPainting/ArchitectureColoredPainting.vcxproj.filters
index e019bc3..71f1e04 100644
--- a/ArchitectureColoredPainting/ArchitectureColoredPainting.vcxproj.filters
+++ b/ArchitectureColoredPainting/ArchitectureColoredPainting.vcxproj.filters
@@ -216,7 +216,7 @@
Source Files\Editor\Style
-
+
Source Files\Editor\Style
@@ -254,7 +254,7 @@
Header Files
-
+
Header Files\Editor\Style
@@ -477,6 +477,9 @@
Header Files\Editor\Style
+
+ Header Files\Editor\util
+
diff --git a/ArchitectureColoredPainting/src/Editor/EditorWidgetComponent/StrokeStyleWidget.cpp b/ArchitectureColoredPainting/src/Editor/EditorWidgetComponent/StrokeStyleWidget.cpp
new file mode 100644
index 0000000..00283ca
--- /dev/null
+++ b/ArchitectureColoredPainting/src/Editor/EditorWidgetComponent/StrokeStyleWidget.cpp
@@ -0,0 +1,216 @@
+#include "StrokeStyleWidget.h"
+#include "ColorPicker.h"
+#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;
+constexpr int COLUMN_ROUGHNESS = 3;
+constexpr int COLUMN_OPERATIONS = 4;
+
+// FIXME: Material的控件有显示bug
+StrokeStyleWidget::StrokeStyleWidget(
+ std::shared_ptr stroke,
+ QWidget* parent
+) : QWidget(parent), stroke(stroke)
+{
+ QVBoxLayout* viewLayout = new QVBoxLayout(this);
+ this->setLayout(viewLayout);
+
+ initStrokeSettings();
+ QWidget* strokeProperties = new QWidget(this);
+ QHBoxLayout* strokePropertiesLayout = new QHBoxLayout(strokeProperties);
+ strokePropertiesLayout->setMargin(0);
+
+ strokeProperties->setLayout(strokePropertiesLayout);
+ strokePropertiesLayout->addWidget(enableGradual);
+ strokePropertiesLayout->addWidget(endTypeBox);
+
+ viewLayout->addWidget(strokeProperties);
+ viewLayout->addWidget(widthField);
+
+ initTable(std::dynamic_pointer_cast(stroke->materialStroke));
+ viewLayout->addWidget(strokeTable);
+ this->adjustSize();
+}
+
+void StrokeStyleWidget::initStrokeSettings()
+{
+ this->enableGradual = new QtMaterialCheckBox(this);
+ enableGradual->setText(QStringLiteral("启用渐变"));
+ enableGradual->setChecked(radialStroke(stroke)->gradual);
+ connect(enableGradual, &QtMaterialCheckBox::toggled, [this](bool checked) {
+ radialStroke(this->stroke)->gradual = checked;
+ });
+
+#define endTypeBoxLabel(start, end) QStringLiteral(start##" -> "##end)
+ this->endTypeBox = new QComboBox(this);
+ endTypeBox->addItem(endTypeBoxLabel("圆头", "圆头")); // kRound
+ endTypeBox->addItem(endTypeBoxLabel("平头", "圆头")); // kFlatRound
+ endTypeBox->addItem(endTypeBoxLabel("圆头", "平头")); // kRoundFlat
+ endTypeBox->addItem(endTypeBoxLabel("平头", "平头")); // kFlat
+ endTypeBox->setCurrentIndex(static_cast(this->stroke->endType));
+ connect(endTypeBox, QOverload::of(&QComboBox::currentIndexChanged), [this](int index) {
+ switch (index)
+ {
+ case 0:
+ this->stroke->endType = Renderer::StrokeEndType::kRound;
+ break;
+ case 1:
+ this->stroke->endType = Renderer::StrokeEndType::kFlatRound;
+ break;
+ case 2:
+ this->stroke->endType = Renderer::StrokeEndType::kRoundFlat;
+ break;
+ case 3:
+ this->stroke->endType = Renderer::StrokeEndType::kFlat;
+ break;
+ }
+ });
+
+ 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);
+ widthValidator->setNotation(QDoubleValidator::StandardNotation);
+ widthField->setValidator(widthValidator);
+ connect(widthField, &QtMaterialTextField::textChanged, [this](const QString& changed) {
+ if (this->widthField->hasAcceptableInput())
+ {
+ this->stroke->halfWidth = changed.toFloat();
+ }
+ });
+}
+
+// TODO: 新增时参数校验
+void StrokeStyleWidget::initTable(std::shared_ptr materialStroke)
+{
+ this->strokeTable = new QTableWidget(this);
+ strokeTable->setSizeAdjustPolicy(QAbstractScrollArea::AdjustToContentsOnFirstShow);
+ strokeTable->setColumnCount(5);
+ strokeTable->setRowCount(materialStroke->materialMap.size() + 1);
+ QStringList headers;
+ headers << QStringLiteral("离心距离占比")
+ << QStringLiteral("颜色")
+ << QStringLiteral("金属度")
+ << QStringLiteral("粗糙度")
+ << QStringLiteral("其他操作");
+ strokeTable->setHorizontalHeaderLabels(headers);
+ int row = 0;
+ // 内容
+ for (auto & strokePair : materialStroke->materialMap)
+ {
+ setTableRow(row, strokePair.first, strokePair.second);
+ row++;
+ }
+ // 新增按钮
+ QtMaterialRaisedButton* addButton = new QtMaterialRaisedButton("+", strokeTable);
+ strokeTable->setSpan(row, 0, 1, 5);
+ strokeTable->setCellWidget(row, 0, addButton);
+ connect(addButton, &QtMaterialRaisedButton::clicked, [this]() {
+ handlingRowInsert = true;
+ auto materialMap = &(radialStroke(this->stroke)->materialMap);
+ float newWidth = 0;
+ if (materialMap->size() == 0)
+ {
+ newWidth = 0.1;
+ }
+ else
+ {
+ auto lastPair = materialMap->rbegin();
+ newWidth = lastPair->first + 0.01;
+ }
+ Renderer::Material newMaterial = { QColor::fromRgb(0,0,0), 0.f, .8f };
+ (*materialMap)[newWidth] = newMaterial;
+ int newRow = this->strokeTable->rowCount() - 1;
+ this->strokeTable->insertRow(newRow);
+ setTableRow(newRow, newWidth, (*materialMap)[newWidth]);
+ this->strokeTable->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;
+ widthItem->setData(Qt::EditRole, width);
+ strokeTable->setItem(row, COLUMN_WIDTH, widthItem);
+
+ QColor* colorPtr = &(material.color);
+ QTableWidgetItem* colorItem = new QTableWidgetItem;
+ colorItem->setData(Qt::DisplayRole, *colorPtr);
+ strokeTable->setItem(row, COLUMN_COLOR, colorItem);
+ ColorPicker* 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;
+ metallicItem->setData(Qt::EditRole, material.metallic);
+ strokeTable->setItem(row, COLUMN_METALLIC, metallicItem);
+
+ QTableWidgetItem* roughnessItem = new QTableWidgetItem;
+ roughnessItem->setData(Qt::EditRole, material.roughness);
+ strokeTable->setItem(row, COLUMN_ROUGHNESS, roughnessItem);
+
+ QtMaterialRaisedButton* removeButton = new QtMaterialRaisedButton("-", strokeTable);
+ removeButton->setFixedSize(20, 20);
+ strokeTable->setCellWidget(row, COLUMN_OPERATIONS, removeButton);
+ connect(removeButton, &QtMaterialRaisedButton::clicked, [this, row]() {
+ if (this->strokeTable->rowCount() <= 1) return;
+ radialStroke(this->stroke)->materialMap.erase(this->strokeTable->item(row, COLUMN_WIDTH)->text().toFloat());
+ this->strokeTable->removeRow(row);
+ });
+}
+
+void StrokeStyleWidget::onCurrentItemChanged(QTableWidgetItem* current, QTableWidgetItem* previous)
+{
+ if (!current) return;
+ int column = current->column();
+ if (column != COLUMN_COLOR && column != COLUMN_OPERATIONS)
+ {
+ this->currentItemValue = current->data(Qt::EditRole);
+ }
+}
+
+void StrokeStyleWidget::onCellChanged(int row, int column)
+{
+ if (handlingRowInsert) return;
+ auto changedItem = strokeTable->item(row, column);
+ auto changedItemValue = changedItem->text().toFloat();
+ if (changedItemValue < 0 || 1 < changedItemValue)
+ {
+ changedItem->setData(Qt::EditRole, this->currentItemValue.toFloat());
+ return;
+ }
+ auto changedWidth = strokeTable->item(row, COLUMN_WIDTH)->data(Qt::EditRole).toFloat();
+ switch (column)
+ {
+ case COLUMN_WIDTH:
+ {
+ float oldWidth = this->currentItemValue.toFloat();
+ auto node = radialStroke(stroke)->materialMap.extract(oldWidth);
+ node.key() = changedWidth;
+ radialStroke(stroke)->materialMap.insert(std::move(node));
+ strokeTable->sortItems(COLUMN_WIDTH);
+ break;
+ }
+ case COLUMN_METALLIC:
+ {
+ radialStroke(stroke)->materialMap[changedWidth].metallic = changedItemValue;
+ break;
+ }
+ case COLUMN_ROUGHNESS:
+ {
+ radialStroke(stroke)->materialMap[changedWidth].roughness = changedItemValue;
+ break;
+ }
+ }
+}
\ No newline at end of file
diff --git a/ArchitectureColoredPainting/src/Editor/EditorWidgetComponent/StrokeStyleWidget.h b/ArchitectureColoredPainting/src/Editor/EditorWidgetComponent/StrokeStyleWidget.h
new file mode 100644
index 0000000..6d5dbdd
--- /dev/null
+++ b/ArchitectureColoredPainting/src/Editor/EditorWidgetComponent/StrokeStyleWidget.h
@@ -0,0 +1,33 @@
+#pragma once
+#include "LayerStyle.h"
+#include "../Renderer/Painting/MaterialStyleStroke.h"
+#include
+#include
+#include
+#include
+#include
+class StrokeStyleWidget : public QWidget
+{
+ Q_OBJECT
+private:
+ QVariant currentItemValue;
+
+ QtMaterialCheckBox* enableGradual;
+ QComboBox* endTypeBox;
+ QtMaterialTextField* widthField;
+ QTableWidget* strokeTable;
+ bool handlingRowInsert = false;
+
+ void initStrokeSettings();
+ void initTable(std::shared_ptr materialStroke);
+ void setTableRow(int row, float width, Renderer::Material& material);
+
+public:
+ StrokeStyleWidget(std::shared_ptr stroke, QWidget* parent = nullptr);
+ std::shared_ptr stroke;
+
+protected slots:
+ void onCurrentItemChanged(QTableWidgetItem* current, QTableWidgetItem* previous);
+ void onCellChanged(int row, int column);
+};
+
diff --git a/ArchitectureColoredPainting/src/Editor/LayerStyle.cpp b/ArchitectureColoredPainting/src/Editor/LayerStyle.cpp
index e44e855..9b65355 100644
--- a/ArchitectureColoredPainting/src/Editor/LayerStyle.cpp
+++ b/ArchitectureColoredPainting/src/Editor/LayerStyle.cpp
@@ -1,5 +1,6 @@
#include "LayerStyle.h"
-#include "./EditorWidgetComponent/StrokeStyleListView.h"
+#include "./EditorWidgetComponent/StrokeStyleWidget.h"
+#include "./util/JsonUtil.hpp"
#include
#include
#include
@@ -50,8 +51,7 @@ QWidget* StrokeElementLayerStyle::getInputWidget()
if (this->strokePair.first == nullptr)
{
auto materialMap = std::map();
- materialMap[0.3] = Renderer::Material{ QColor(0,255,255), 0.f, .8f };
- materialMap[1.0] = Renderer::Material{ QColor(80,25,255), 0.f, .8f };
+ materialMap[1.0] = Renderer::Material{ QColor(0, 0, 0), 0.f, .8f };
this->strokePair.first = std::shared_ptr(new Renderer::MaterialStyleStroke(
15,
Renderer::StrokeType::kLeftSide, Renderer::StrokeEndType::kFlat,
@@ -63,8 +63,7 @@ QWidget* StrokeElementLayerStyle::getInputWidget()
if (this->strokePair.second == nullptr)
{
auto materialMap = std::map();
- materialMap[0.3] = Renderer::Material{ QColor(0,255,255), 0.f, .8f };
- materialMap[1.0] = Renderer::Material{ QColor(80,25,255), 0.f, .8f };
+ materialMap[1.0] = Renderer::Material{ QColor(0, 0, 0), 0.f, .8f };
this->strokePair.second = std::shared_ptr(new Renderer::MaterialStyleStroke(
15,
Renderer::StrokeType::kRightSide, Renderer::StrokeEndType::kFlat,
@@ -79,9 +78,7 @@ QWidget* StrokeElementLayerStyle::getInputWidget()
QVBoxLayout* layout = new QVBoxLayout(w);
layout->setMargin(0);
- StrokeStyleListView* leftStrokeView = new StrokeStyleListView(
- std::dynamic_pointer_cast(this->strokePair.first->materialStroke), w
- );
+ StrokeStyleWidget* leftStrokeView = new StrokeStyleWidget(this->strokePair.first, w);
layout->addWidget(leftStrokeView);
QtMaterialCheckBox* checkEachSideIndependent = new QtMaterialCheckBox(w);
@@ -89,9 +86,7 @@ QWidget* StrokeElementLayerStyle::getInputWidget()
checkEachSideIndependent->setChecked(enableEachSideIndependent);
layout->addWidget(checkEachSideIndependent);
- StrokeStyleListView* rightStrokeView = new StrokeStyleListView(
- std::dynamic_pointer_cast(this->strokePair.second->materialStroke), w
- );
+ StrokeStyleWidget* rightStrokeView = new StrokeStyleWidget(this->strokePair.second, w);
layout->addWidget(rightStrokeView);
rightStrokeView->setDisabled(!this->enableEachSideIndependent);
@@ -124,6 +119,16 @@ StrokeElementLayerStyle::StrokeElementLayerStyle(const StrokeElementLayerStyle&
enableEachSideIndependent = other.enableEachSideIndependent;
}
+QJsonObject StrokeElementLayerStyle::toJson() const
+{
+ QJsonObject json;
+ json.insert("type", "stroke");
+ json.insert("enableEachSideIndependent", enableEachSideIndependent);
+ json.insert("left", JsonUtil::toQJsonArray(strokePair.first->encoded()));
+ json.insert("right", JsonUtil::toQJsonArray(strokePair.second->encoded()));
+ return json;
+}
+
std::unique_ptr StrokeElementLayerStyle::clone() const
{
return std::make_unique(StrokeElementLayerStyle(*this));
@@ -167,7 +172,17 @@ FillElementLayerStyle::FillElementLayerStyle(const FillElementLayerStyle& other)
}
}
+QJsonObject FillElementLayerStyle::toJson() const
+{
+ return QJsonObject();
+}
+
std::unique_ptr FillElementLayerStyle::clone() const
{
return std::make_unique(FillElementLayerStyle(*this));
}
+
+std::unique_ptr LayerStyle::fromJson(const QJsonObject& json)
+{
+ return std::unique_ptr();
+}
diff --git a/ArchitectureColoredPainting/src/Editor/LayerStyle.h b/ArchitectureColoredPainting/src/Editor/LayerStyle.h
index 7d5fb25..6717299 100644
--- a/ArchitectureColoredPainting/src/Editor/LayerStyle.h
+++ b/ArchitectureColoredPainting/src/Editor/LayerStyle.h
@@ -5,6 +5,7 @@
#include
#include
#include
+#include
#include "../Renderer/Painting/ElementStyle.h"
#include "../Renderer/Painting/MaterialStyleStroke.h"
#include "../Renderer/Painting/MaterialStyleFill.h"
@@ -23,10 +24,13 @@ 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 QWidget* getInputWidget() = 0;
virtual QWidget* getListDisplayWidget() const = 0;
virtual ~LayerStyle() {};
+ virtual QJsonObject toJson() const = 0;
virtual std::unique_ptr clone() const = 0;
};
@@ -43,6 +47,7 @@ public:
StrokeElementLayerStyle() = default;
StrokeElementLayerStyle(const StrokeElementLayerStyle& other);
~StrokeElementLayerStyle() = default;
+ QJsonObject toJson() const override;
std::unique_ptr clone() const override;
bool enableEachSideIndependent = false;
@@ -59,5 +64,6 @@ public:
FillElementLayerStyle(const FillElementLayerStyle& other);
~FillElementLayerStyle() = default;
std::vector> materialStyles;
+ QJsonObject toJson() const override;
std::unique_ptr clone() const override;
};
\ No newline at end of file
diff --git a/ArchitectureColoredPainting/src/Editor/LayerWrapper.cpp b/ArchitectureColoredPainting/src/Editor/LayerWrapper.cpp
index 4c73d5d..0e9b8f4 100644
--- a/ArchitectureColoredPainting/src/Editor/LayerWrapper.cpp
+++ b/ArchitectureColoredPainting/src/Editor/LayerWrapper.cpp
@@ -240,6 +240,10 @@ 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);
return json;
}
diff --git a/ArchitectureColoredPainting/src/Editor/LayerWrapper.h b/ArchitectureColoredPainting/src/Editor/LayerWrapper.h
index 7df5d13..f753dcb 100644
--- a/ArchitectureColoredPainting/src/Editor/LayerWrapper.h
+++ b/ArchitectureColoredPainting/src/Editor/LayerWrapper.h
@@ -6,6 +6,7 @@
#include
#include
#include
+#include
#include
#include
#include
diff --git a/ArchitectureColoredPainting/src/Editor/util/JsonUtil.hpp b/ArchitectureColoredPainting/src/Editor/util/JsonUtil.hpp
new file mode 100644
index 0000000..e393f38
--- /dev/null
+++ b/ArchitectureColoredPainting/src/Editor/util/JsonUtil.hpp
@@ -0,0 +1,14 @@
+#pragma once
+#include
+
+namespace JsonUtil
+{
+#include
+ template
+ QJsonArray toQJsonArray(const std::vector& vec)
+ {
+ QJsonArray array;
+ std::copy(vec.begin(), vec.end(), std::back_inserter(array));
+ return array;
+ }
+}