diff --git a/ArchitectureColoredPainting/src/Editor/EditorWidgetComponent/StrokeStyleWidget.cpp b/ArchitectureColoredPainting/src/Editor/EditorWidgetComponent/StrokeStyleWidget.cpp index e9999bb..7422763 100644 --- a/ArchitectureColoredPainting/src/Editor/EditorWidgetComponent/StrokeStyleWidget.cpp +++ b/ArchitectureColoredPainting/src/Editor/EditorWidgetComponent/StrokeStyleWidget.cpp @@ -3,6 +3,9 @@ #include "../ColorHelper.hpp" #include #include +#include +#include +#include constexpr int COLUMN_WIDTH = 0; constexpr int COLUMN_COLOR = 1; @@ -10,11 +13,27 @@ constexpr int COLUMN_METALLIC = 2; constexpr int COLUMN_ROUGHNESS = 3; constexpr int COLUMN_OPERATIONS = 4; +inline Renderer::Material newMaterial() +{ + return {ColorHelper::instance().getPrimary1()}; +} + +inline bool isClosedStroke(const std::shared_ptr& stroke) +{ + return stroke->endType == Renderer::StrokeEndType::kClosed; +} + StrokeStyleWidget::StrokeStyleWidget( - std::shared_ptr stroke, + const std::shared_ptr& stroke, QWidget* parent ) : QWidget(parent), stroke(stroke) { + auto& materialMap = radialStroke(stroke)->materialMap; + if (materialMap.empty()) + { + materialMap[1.f] = newMaterial(); + } + auto* viewLayout = new QVBoxLayout(this); this->setLayout(viewLayout); @@ -25,13 +44,20 @@ StrokeStyleWidget::StrokeStyleWidget( strokeProperties->setLayout(strokePropertiesLayout); strokePropertiesLayout->addWidget(enableGradual); - strokePropertiesLayout->addWidget(endTypeBox); + if (!isClosedStroke(stroke)) + { + strokePropertiesLayout->addWidget(endTypeBox); + } viewLayout->addWidget(strokeProperties); viewLayout->addWidget(widthField); - initTable(std::dynamic_pointer_cast(stroke->materialStroke)); + initTable(radialStroke(stroke)); viewLayout->addWidget(strokeTable); + + initAddButton(); + viewLayout->addWidget(addButton); + this->adjustSize(); } @@ -44,30 +70,23 @@ void StrokeStyleWidget::initStrokeSettings() 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) + if (!isClosedStroke(stroke)) + { + this->endTypeBox = new QComboBox(this); + for (const auto& displayName : MaterialStyleStroke::strokeEndTypeNames | std::views::keys) { - 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; + endTypeBox->addItem(displayName); } - }); + endTypeBox->setCurrentIndex(static_cast(this->stroke->endType)); + connect(endTypeBox, QOverload::of(&QComboBox::currentIndexChanged), [this](int index) { + const auto& [displayName, endType] = MaterialStyleStroke::strokeEndTypeNames[index]; + this->stroke->endType = endType; + }); + } + else + { + this->endTypeBox = nullptr; + } this->widthField = new QtMaterialTextField(this); widthField->setLabel(QStringLiteral("±¾²àÃè±ß¿í¶È")); @@ -83,13 +102,12 @@ void StrokeStyleWidget::initStrokeSettings() }); } -// TODO: ÐÂÔöʱ²ÎÊýУÑé -void StrokeStyleWidget::initTable(std::shared_ptr materialStroke) +void StrokeStyleWidget::initTable(const std::shared_ptr& materialStroke) { this->strokeTable = new QTableWidget(this); strokeTable->setSizeAdjustPolicy(QAbstractScrollArea::AdjustToContentsOnFirstShow); strokeTable->setColumnCount(5); - strokeTable->setRowCount(materialStroke->materialMap.size() + 1); + strokeTable->setRowCount(materialStroke->materialMap.size()); QStringList headers; headers << QStringLiteral("ÀëÐľàÀëÕ¼±È") << QStringLiteral("ÑÕÉ«") @@ -97,44 +115,45 @@ void StrokeStyleWidget::initTable(std::shared_ptrsetHorizontalHeaderLabels(headers); + strokeTable->setMinimumHeight(strokeTable->rowHeight(0) * 5); + strokeTable->setMinimumWidth(strokeTable->sizeHint().width()); int row = 0; // ÄÚÈÝ - for (auto & strokePair : materialStroke->materialMap) + for (auto& [width, material] : std::views::reverse(materialStroke->materialMap)) { - setTableRow(row, strokePair.first, strokePair.second); + setTableRow(row, width, material); row++; } - // ÐÂÔö°´Å¥ - auto* addButton = new QtMaterialRaisedButton("+", strokeTable); + connect(strokeTable, &QTableWidget::currentItemChanged, this, &StrokeStyleWidget::onCurrentItemChanged); + connect(strokeTable, &QTableWidget::cellChanged, this, &StrokeStyleWidget::onCellChanged); +} + +void StrokeStyleWidget::initAddButton() +{ + this->addButton = new QtMaterialRaisedButton("+", strokeTable); + addButton->setFixedHeight(this->strokeTable->rowHeight(0)); addButton->setBackgroundColor(ColorHelper::instance().getPrimary1()); - 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]() { + connect(addButton, &QtMaterialRaisedButton::clicked, [this] { handlingRowInsert = true; - auto materialMap = &radialStroke(this->stroke)->materialMap; + auto& materialMap = radialStroke(this->stroke)->materialMap; float newWidth; - if (materialMap->empty()) + if (materialMap.empty()) { - newWidth = 0.1; + newWidth = 1.f; } else { - const auto lastPair = materialMap->rbegin(); - newWidth = lastPair->first + 0.01; + const auto firstPair = materialMap.begin(); + newWidth = firstPair->first / 2; } const Renderer::Material newMaterial(ColorHelper::instance().getPrimary1()); - (*materialMap)[newWidth] = newMaterial; - int newRow = this->strokeTable->rowCount() - 1; + materialMap[newWidth] = newMaterial; + const int newRow = this->strokeTable->rowCount(); this->strokeTable->insertRow(newRow); - setTableRow(newRow, newWidth, (*materialMap)[newWidth]); + 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) @@ -150,7 +169,7 @@ void StrokeStyleWidget::setTableRow(int row, float width, Renderer::Material& ma auto* colorPicker = new ColorPicker(*colorPtr, strokeTable); strokeTable->setCellWidget(row, COLUMN_COLOR, colorPicker); connect(colorPicker, &ColorPicker::colorChanged, [this, colorPtr](QColor color) { - *colorPtr = color; + *colorPtr = std::move(color); this->strokeTable->update(); }); @@ -166,7 +185,7 @@ void StrokeStyleWidget::setTableRow(int row, float width, Renderer::Material& ma removeButton->setBackgroundColor(ColorHelper::instance().getPrimary1()); removeButton->setFixedSize(20, 20); strokeTable->setCellWidget(row, COLUMN_OPERATIONS, removeButton); - connect(removeButton, &QtMaterialRaisedButton::clicked, [this, row]() { + connect(removeButton, &QtMaterialRaisedButton::clicked, [this, row] { radialStroke(this->stroke)->materialMap.erase(this->strokeTable->item(row, COLUMN_WIDTH)->text().toFloat()); this->strokeTable->removeRow(row); }); @@ -175,7 +194,7 @@ void StrokeStyleWidget::setTableRow(int row, float width, Renderer::Material& ma void StrokeStyleWidget::onCurrentItemChanged(QTableWidgetItem* current, QTableWidgetItem* previous) { if (!current) return; - int column = current->column(); + const int column = current->column(); if (column != COLUMN_COLOR && column != COLUMN_OPERATIONS) { this->currentItemValue = current->data(Qt::EditRole); @@ -185,23 +204,27 @@ void StrokeStyleWidget::onCurrentItemChanged(QTableWidgetItem* current, QTableWi void StrokeStyleWidget::onCellChanged(int row, int column) { if (handlingRowInsert) return; - auto changedItem = strokeTable->item(row, column); - auto changedItemValue = changedItem->text().toFloat(); + const auto changedItem = strokeTable->item(row, column); + const 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(); + const 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); + if (node.empty()) + { + break; + } node.key() = changedWidth; radialStroke(stroke)->materialMap.insert(std::move(node)); - strokeTable->sortItems(COLUMN_WIDTH); + strokeTable->sortItems(COLUMN_WIDTH, Qt::DescendingOrder); break; } case COLUMN_METALLIC: diff --git a/ArchitectureColoredPainting/src/Editor/EditorWidgetComponent/StrokeStyleWidget.h b/ArchitectureColoredPainting/src/Editor/EditorWidgetComponent/StrokeStyleWidget.h index 67af3ee..c4d1bfc 100644 --- a/ArchitectureColoredPainting/src/Editor/EditorWidgetComponent/StrokeStyleWidget.h +++ b/ArchitectureColoredPainting/src/Editor/EditorWidgetComponent/StrokeStyleWidget.h @@ -6,6 +6,7 @@ #include #include #include +#include class StrokeStyleWidget : public QWidget { Q_OBJECT @@ -16,14 +17,16 @@ private: QComboBox* endTypeBox; QtMaterialTextField* widthField; QTableWidget* strokeTable; + QtMaterialRaisedButton* addButton; bool handlingRowInsert = false; void initStrokeSettings(); - void initTable(std::shared_ptr materialStroke); + void initTable(const std::shared_ptr& materialStroke); + void initAddButton(); void setTableRow(int row, float width, Renderer::Material& material); public: - StrokeStyleWidget(std::shared_ptr stroke, QWidget* parent = nullptr); + StrokeStyleWidget(const std::shared_ptr& stroke, QWidget* parent = nullptr); std::shared_ptr stroke; protected slots: diff --git a/ArchitectureColoredPainting/src/Editor/LayerStyle.cpp b/ArchitectureColoredPainting/src/Editor/LayerStyle.cpp index 292d0ca..d8bbae3 100644 --- a/ArchitectureColoredPainting/src/Editor/LayerStyle.cpp +++ b/ArchitectureColoredPainting/src/Editor/LayerStyle.cpp @@ -78,7 +78,7 @@ QWidget* StrokeElementLayerStyle::getListDisplayWidget() const void LayerStyleContainer::computeNewHash() { hash = 0; - for (auto& f : styles + for (auto& f : styles | std::views::values | std::views::transform(&LayerStyle::toBaseStyles) | std::views::join @@ -248,18 +248,18 @@ std::unique_ptr StrokeElementLayerStyle::fromJson(const return ptr; } -StrokeElementLayerStyle::StrokeElementLayerStyle() +StrokeElementLayerStyle::StrokeElementLayerStyle(bool isClosed) { const auto materialMap = std::map(); this->strokePair.first = std::make_shared( 7, - Renderer::StrokeType::kLeftSide, Renderer::StrokeEndType::kFlat, + Renderer::StrokeType::kLeftSide, isClosed ? Renderer::StrokeEndType::kClosed : Renderer::StrokeEndType::kFlat, std::make_shared(materialMap, false) ); this->strokePair.second = std::make_shared( 7, - Renderer::StrokeType::kRightSide, Renderer::StrokeEndType::kFlat, + Renderer::StrokeType::kRightSide, isClosed ? Renderer::StrokeEndType::kClosed : Renderer::StrokeEndType::kFlat, std::make_shared(materialMap, false) ); diff --git a/ArchitectureColoredPainting/src/Editor/LayerStyle.h b/ArchitectureColoredPainting/src/Editor/LayerStyle.h index 9274732..3eba1ad 100644 --- a/ArchitectureColoredPainting/src/Editor/LayerStyle.h +++ b/ArchitectureColoredPainting/src/Editor/LayerStyle.h @@ -46,7 +46,7 @@ public: STYLE_NAME("Ãè±ß", "stroke") static std::unique_ptr fromJson(const QJsonObject& json); - StrokeElementLayerStyle(); + StrokeElementLayerStyle(bool isClosed); StrokeElementLayerStyle(const PMaterialStyleStroke& left, const PMaterialStyleStroke& right = nullptr); StrokeElementLayerStyle(const StrokeElementLayerStyle& other); ~StrokeElementLayerStyle() override = default; @@ -88,17 +88,23 @@ public: class LayerStyleContainer : public Renderer::ElementStyle { using DisplayNameWithSupplier = std::map()>>; -private: - inline const static DisplayNameWithSupplier commonStyles = { { +private: + inline const static DisplayNameWithSupplier commonStyles = { }; + inline const static DisplayNameWithSupplier closedOnlyStyles = { + { + FillElementLayerStyle::displayName(), + [] { return std::make_unique(); } + }, + { + StrokeElementLayerStyle::displayName(), + [] { return std::make_unique(true); } + } + }; + inline const static DisplayNameWithSupplier unclosedOnlyStyles = { { StrokeElementLayerStyle::displayName(), - [] { return std::make_unique(); } + [] { return std::make_unique(false); } } }; - inline const static DisplayNameWithSupplier closedOnlyStyles = { { - FillElementLayerStyle::displayName(), - [] { return std::make_unique(); } - } }; - inline const static DisplayNameWithSupplier unclosedOnlyStyles = { }; DisplayNameWithSupplier unusedStyles; DisplayNameWithSupplier usedStyles;