|
|
|
@ -3,6 +3,9 @@
|
|
|
|
|
#include "../ColorHelper.hpp"
|
|
|
|
|
#include <qtmaterialraisedbutton.h>
|
|
|
|
|
#include <limits>
|
|
|
|
|
#include <array>
|
|
|
|
|
#include <ranges>
|
|
|
|
|
#include <utility>
|
|
|
|
|
|
|
|
|
|
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<MaterialStyleStroke>& stroke)
|
|
|
|
|
{
|
|
|
|
|
return stroke->endType == Renderer::StrokeEndType::kClosed;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
StrokeStyleWidget::StrokeStyleWidget(
|
|
|
|
|
std::shared_ptr<MaterialStyleStroke> stroke,
|
|
|
|
|
const std::shared_ptr<MaterialStyleStroke>& 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<Renderer::StrokeRadialGradient>(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<int>(this->stroke->endType));
|
|
|
|
|
connect(endTypeBox, QOverload<int>::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<int>(this->stroke->endType));
|
|
|
|
|
connect(endTypeBox, QOverload<int>::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<Renderer::StrokeRadialGradient> materialStroke)
|
|
|
|
|
void StrokeStyleWidget::initTable(const std::shared_ptr<Renderer::StrokeRadialGradient>& 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_ptr<Renderer::StrokeRadialGradient
|
|
|
|
|
<< QStringLiteral("粗糙度")
|
|
|
|
|
<< QStringLiteral("其他操作");
|
|
|
|
|
strokeTable->setHorizontalHeaderLabels(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:
|
|
|
|
|