Compare commits

..

11 Commits

Author SHA1 Message Date
yang.yongquan fbfc5f2759 更新至main 2023-03-20 20:06:17 +08:00
ArgonarioD bf71d17b5d [editor/style] 适配了新的StrokeEndType | #18
* [stroke] 适配了新添加的StrokeEndType::kClosed
 * [stroke] 对接了Renderer方面提供的新接口
2023-03-20 19:58:02 +08:00
ArgonarioD 4b2776d429 [editor/style] 优化了Stroke的添加交互 | #17 2023-03-20 19:03:15 +08:00
karlis 831541ff36 Merge branch 'main' of http://101.34.228.45:3000/BigC/ArchitectureColoredPainting 2023-03-20 18:04:01 +08:00
karlis 6a1c64a426 添加Ctrl+左键快捷缩放,C+S+左键等比缩放 2023-03-20 18:03:54 +08:00
wuyize ae641bb87c 增加了StrokeEndType::kClosed 2023-03-20 17:52:57 +08:00
karlis f25f2d2a81 实现高亮选中Layer 2023-03-20 17:35:33 +08:00
karlis 8a34f57251 实现显示/隐藏图层功能 | #16 2023-03-20 15:52:27 +08:00
karlis f06fbbaef6 FIX: 暂时修复修改图层属性导致的crash 2023-03-20 14:44:36 +08:00
ArgonarioD 855dd2e075 [editor] 修复了一些会导致warning的问题 | #15
* 添加了ColorHelper
 * LayerStyleDialog重复setLayer导致的warning
 * QColorDialog::getColor时由于Qt的bug未正确设置大小导致的warning
2023-03-20 02:48:52 +08:00
wuyize b6e79ee6de 实现通过json文件构造Painting 2023-03-20 00:26:50 +08:00
38 changed files with 511 additions and 391 deletions

View File

@ -202,6 +202,7 @@
<QtMoc Include="src\Editor\EditorWidgetComponent\ColorPicker.h" /> <QtMoc Include="src\Editor\EditorWidgetComponent\ColorPicker.h" />
<QtMoc Include="src\Editor\RightBar\EditorSettingWidget.h" /> <QtMoc Include="src\Editor\RightBar\EditorSettingWidget.h" />
<QtMoc Include="src\Editor\EditorWidgetComponent\FillStyleWidget.h" /> <QtMoc Include="src\Editor\EditorWidgetComponent\FillStyleWidget.h" />
<ClInclude Include="src\ColorHelper.hpp" />
<ClInclude Include="src\Editor\LayerWrapper.h" /> <ClInclude Include="src\Editor\LayerWrapper.h" />
<ClInclude Include="src\Editor\util\EncodeUtil.hpp" /> <ClInclude Include="src\Editor\util\EncodeUtil.hpp" />
<ClInclude Include="src\Editor\util\JsonUtil.hpp" /> <ClInclude Include="src\Editor\util\JsonUtil.hpp" />

View File

@ -519,6 +519,9 @@
<ClInclude Include="src\Editor\LayerWrapper.h"> <ClInclude Include="src\Editor\LayerWrapper.h">
<Filter>Header Files\Editor\Layer</Filter> <Filter>Header Files\Editor\Layer</Filter>
</ClInclude> </ClInclude>
<ClInclude Include="src\ColorHelper.hpp">
<Filter>Header Files</Filter>
</ClInclude>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<QtRcc Include="res\MainWindow.qrc"> <QtRcc Include="res\MainWindow.qrc">

View File

@ -180,6 +180,12 @@
<property name="accessibleName"> <property name="accessibleName">
<string/> <string/>
</property> </property>
<property name="iconSize">
<size>
<width>10</width>
<height>10</height>
</size>
</property>
<column> <column>
<property name="text"> <property name="text">
<string>图层名</string> <string>图层名</string>
@ -190,6 +196,11 @@
<string>关联图元</string> <string>关联图元</string>
</property> </property>
</column> </column>
<column>
<property name="text">
<string>可见</string>
</property>
</column>
</widget> </widget>
</item> </item>
</layout> </layout>

View File

@ -1093,6 +1093,7 @@ void main()
bool onVeryBegin = false; bool onVeryBegin = false;
bool onVeryEnd = false; bool onVeryEnd = false;
vec2 tangentEndLast; vec2 tangentEndLast;
vec2 tangentFirstBegin;
uint lastHitIndex = 0; uint lastHitIndex = 0;
bool lastHitElement = false; bool lastHitElement = false;
hitElement = false; hitElement = false;
@ -1108,7 +1109,19 @@ void main()
pBegin = path[++pathIndex]; pBegin = path[++pathIndex];
p3Last = pBegin; p3Last = pBegin;
p2Last = pBegin; p2Last = pBegin;
onVeryBegin = true; if(endType == 4)
{
//onVeryBegin = false;
vec2 lastP1 = path[pathSize-3];
vec2 lastP2 = path[pathSize-2];
vec2 lastP3 = path[pathSize-1];
if (lastP3 != lastP2)
tangentEndLast = normalize(lastP3 - lastP2);
else
tangentEndLast = normalize(lastP3 - lastP1);
}
else
onVeryBegin = true;
continue; continue;
} }
mat4x2 p = mat4x2(p3Last, pTemp, path[++pathIndex], path[++pathIndex]); mat4x2 p = mat4x2(p3Last, pTemp, path[++pathIndex], path[++pathIndex]);
@ -1119,7 +1132,13 @@ void main()
vec2 pTemp = path[pathIndex + 1]; vec2 pTemp = path[pathIndex + 1];
if (isinf(pTemp.x)) if (isinf(pTemp.x))
{ {
onVeryEnd = true; if(endType == 4)
{
//onVeryEnd = false;
tangentBeginNext = tangentFirstBegin;
}
else
onVeryEnd = true;
} }
else else
{ {
@ -1180,6 +1199,8 @@ void main()
} }
} }
tangentEndLast = tangentEnd; tangentEndLast = tangentEnd;
if(pathIndex == 0)
tangentFirstBegin = tangentBegin;
} }
p3Last = p[3]; p3Last = p[3];
p2Last = p[2]; p2Last = p[2];

View File

@ -0,0 +1,49 @@
#pragma once
#include <lib/qtmaterialstyle.h>
#include <lib/qtmaterialtheme.h>
#include <QColorDialog>
class ColorHelper
{
QtMaterialTheme theme;
QColor primary1;
public:
void setPrimary1(const QColor& color)
{
theme.setColor("primary1", color);
primary1 = color;
}
[[nodiscard]] QColor getPrimary1() const
{
return primary1;
}
ColorHelper()
{
setPrimary1(QColor::fromRgb(0, 90, 158));
QtMaterialStyle::instance().setTheme(&theme);
}
static ColorHelper& instance()
{
static ColorHelper instance;
return instance;
}
static QColor execColorDialog(
const QColor& initial = instance().getPrimary1(),
QWidget* parent = nullptr,
const QString& title = ""
) {
auto dialog = QColorDialog(initial, parent);
if (!title.isEmpty())
{
dialog.setWindowTitle(title);
}
dialog.adjustSize();
dialog.exec();
return dialog.selectedColor();
}
};

View File

@ -1,5 +1,6 @@
#include "ColorPicker.h" #include "ColorPicker.h"
#include <QColorDialog> #include <QColorDialog>
#include <QDebug>
QString getStyleSheet(const QColor& color) QString getStyleSheet(const QColor& color)
{ {
@ -26,9 +27,8 @@ QColor ColorPicker::getColor() const
void ColorPicker::onClicked() void ColorPicker::onClicked()
{ {
QColorDialog dialog(this->color, this); //const QColor newColor = QColorDialog::getColor(this->color, this);
dialog.exec(); const QColor newColor = ColorHelper::execColorDialog(this->color, this);
QColor newColor = dialog.selectedColor();
if (newColor.isValid() && this->color != newColor) if (newColor.isValid() && this->color != newColor)
{ {
this->color = newColor; this->color = newColor;

View File

@ -1,4 +1,5 @@
#pragma once #pragma once
#include "../ColorHelper.hpp"
#include <QPushButton> #include <QPushButton>
class ColorPicker : public QPushButton class ColorPicker : public QPushButton
{ {
@ -6,7 +7,7 @@ class ColorPicker : public QPushButton
private: private:
QColor color; QColor color;
public: public:
ColorPicker(const QColor& color = QColor::fromRgb(0, 0, 0), QWidget* parent = nullptr); ColorPicker(const QColor& color = ColorHelper::instance().getPrimary1(), QWidget* parent = nullptr);
QColor getColor() const; QColor getColor() const;
public slots: public slots:
void onClicked(); void onClicked();

View File

@ -4,7 +4,7 @@
#include <QLabel> #include <QLabel>
#include <qtmaterialtextfield.h> #include <qtmaterialtextfield.h>
FillStyleWidget::FillStyleWidget(std::shared_ptr<Renderer::MaterialStyleFill> fill, QWidget* parent) FillStyleWidget::FillStyleWidget(std::shared_ptr<MaterialStyleFill> fill, QWidget* parent)
: QWidget(parent), fill(fill) : QWidget(parent), fill(fill)
{ {
auto* layout = new QGridLayout(this); auto* layout = new QGridLayout(this);

View File

@ -1,16 +1,15 @@
#include "LayerStyleDialog.h" #include "LayerStyleDialog.h"
#include <QComboBox> #include <QComboBox>
#include <QDialogButtonBox> #include <QDialogButtonBox>
#include <QHBoxLayout>
#include <QGridLayout> #include <QGridLayout>
LayerStyleDialog::LayerStyleDialog( LayerStyleDialog::LayerStyleDialog(
LayerStyleContainer& styles, LayerStyleContainer& styles,
std::shared_ptr<LayerStyle> existedStyle, const std::shared_ptr<LayerStyle>& existedStyle,
QWidget* parent QWidget* parent
) : QDialog(parent), styles(&styles) ) : QDialog(parent), styles(&styles)
{ {
auto* dialogLayout = new QVBoxLayout(this); dialogLayout = new QGridLayout;
dialogLayout->setAlignment(Qt::AlignmentFlag::AlignHCenter); dialogLayout->setAlignment(Qt::AlignmentFlag::AlignHCenter);
this->setLayout(dialogLayout); this->setLayout(dialogLayout);
@ -18,11 +17,9 @@ LayerStyleDialog::LayerStyleDialog(
{ {
this->modifyingStyle = existedStyle->clone(); this->modifyingStyle = existedStyle->clone();
this->styleContainer = nullptr;
this->styleWidget = modifyingStyle->getInputWidget(); this->styleWidget = modifyingStyle->getInputWidget();
this->styleWidget->setParent(this); this->styleWidget->setParent(this);
dialogLayout->addWidget(styleWidget); dialogLayout->addWidget(styleWidget, 1, 0);
// do something
} }
else else
{ {
@ -34,13 +31,12 @@ LayerStyleDialog::LayerStyleDialog(
typeSelector->addItems(unusedStyleNames); typeSelector->addItems(unusedStyleNames);
this->modifyingStyle = std::move(styles.makeUnusedStyle(unusedStyleNames[0])); this->modifyingStyle = std::move(styles.makeUnusedStyle(unusedStyleNames[0]));
dialogLayout->addWidget(typeSelector); dialogLayout->addWidget(typeSelector, 0, 0);
this->styleContainer = new QGridLayout(this);
dialogLayout->addLayout(styleContainer);
this->styleWidget = this->modifyingStyle->getInputWidget(); this->styleWidget = this->modifyingStyle->getInputWidget();
this->styleWidget->setParent(this); this->styleWidget->setParent(this);
this->styleContainer->addWidget(styleWidget); this->dialogLayout->addWidget(styleWidget, 1, 0);
connect(typeSelector, &QComboBox::currentTextChanged, connect(typeSelector, &QComboBox::currentTextChanged,
this, &LayerStyleDialog::onStyleTypeSelectorChanged); this, &LayerStyleDialog::onStyleTypeSelectorChanged);
} }
@ -48,7 +44,8 @@ LayerStyleDialog::LayerStyleDialog(
auto* buttonBox = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel, this); auto* buttonBox = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel, this);
connect(buttonBox, &QDialogButtonBox::accepted, this, &LayerStyleDialog::accept); connect(buttonBox, &QDialogButtonBox::accepted, this, &LayerStyleDialog::accept);
connect(buttonBox, &QDialogButtonBox::rejected, this, &LayerStyleDialog::reject); connect(buttonBox, &QDialogButtonBox::rejected, this, &LayerStyleDialog::reject);
dialogLayout->addWidget(buttonBox); dialogLayout->addWidget(buttonBox, 2, 0);
this->adjustSize();
} }
void LayerStyleDialog::accept() void LayerStyleDialog::accept()
@ -61,14 +58,14 @@ void LayerStyleDialog::onStyleTypeSelectorChanged(const QString& current)
{ {
if (this->styleWidget) if (this->styleWidget)
{ {
this->styleContainer->removeWidget(this->styleWidget); this->dialogLayout->removeWidget(this->styleWidget);
this->styleWidget->setParent(nullptr); this->styleWidget->setParent(nullptr);
delete styleWidget; delete styleWidget;
} }
this->modifyingStyle = std::move(styles->makeUnusedStyle(current)); this->modifyingStyle = std::move(styles->makeUnusedStyle(current));
this->styleWidget = this->modifyingStyle->getInputWidget(); this->styleWidget = this->modifyingStyle->getInputWidget();
this->styleWidget->setParent(this); this->styleWidget->setParent(this);
this->styleContainer->addWidget(styleWidget, 0, 0, 1, 1); this->dialogLayout->addWidget(styleWidget, 1, 0);
this->styleWidget->adjustSize(); this->styleWidget->adjustSize();
this->adjustSize(); this->adjustSize();
} }

View File

@ -8,13 +8,13 @@ class LayerStyleDialog : public QDialog
Q_OBJECT Q_OBJECT
private: private:
QWidget* styleWidget; QWidget* styleWidget;
QGridLayout* styleContainer; QGridLayout* dialogLayout;
LayerStyleContainer* styles; LayerStyleContainer* styles;
std::unique_ptr<LayerStyle> modifyingStyle; std::unique_ptr<LayerStyle> modifyingStyle;
public: public:
LayerStyleDialog( LayerStyleDialog(
LayerStyleContainer& styles, LayerStyleContainer& styles,
std::shared_ptr<LayerStyle> existedStyle = nullptr, const std::shared_ptr<LayerStyle>& existedStyle = nullptr,
QWidget* parent = nullptr QWidget* parent = nullptr
); );
std::shared_ptr<LayerStyle> layerStyle; std::shared_ptr<LayerStyle> layerStyle;

View File

@ -1,8 +1,11 @@
#include "StrokeStyleWidget.h" #include "StrokeStyleWidget.h"
#include "ColorPicker.h" #include "ColorPicker.h"
#include "../ColorHelper.hpp"
#include <qtmaterialraisedbutton.h> #include <qtmaterialraisedbutton.h>
#include <limits> #include <limits>
#include <lib/qtmaterialstyle.h> #include <array>
#include <ranges>
#include <utility>
constexpr int COLUMN_WIDTH = 0; constexpr int COLUMN_WIDTH = 0;
constexpr int COLUMN_COLOR = 1; constexpr int COLUMN_COLOR = 1;
@ -10,11 +13,27 @@ constexpr int COLUMN_METALLIC = 2;
constexpr int COLUMN_ROUGHNESS = 3; constexpr int COLUMN_ROUGHNESS = 3;
constexpr int COLUMN_OPERATIONS = 4; 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( StrokeStyleWidget::StrokeStyleWidget(
std::shared_ptr<MaterialStyleStroke> stroke, const std::shared_ptr<MaterialStyleStroke>& stroke,
QWidget* parent QWidget* parent
) : QWidget(parent), stroke(stroke) ) : QWidget(parent), stroke(stroke)
{ {
auto& materialMap = radialStroke(stroke)->materialMap;
if (materialMap.empty())
{
materialMap[1.f] = newMaterial();
}
auto* viewLayout = new QVBoxLayout(this); auto* viewLayout = new QVBoxLayout(this);
this->setLayout(viewLayout); this->setLayout(viewLayout);
@ -25,13 +44,20 @@ StrokeStyleWidget::StrokeStyleWidget(
strokeProperties->setLayout(strokePropertiesLayout); strokeProperties->setLayout(strokePropertiesLayout);
strokePropertiesLayout->addWidget(enableGradual); strokePropertiesLayout->addWidget(enableGradual);
strokePropertiesLayout->addWidget(endTypeBox); if (!isClosedStroke(stroke))
{
strokePropertiesLayout->addWidget(endTypeBox);
}
viewLayout->addWidget(strokeProperties); viewLayout->addWidget(strokeProperties);
viewLayout->addWidget(widthField); viewLayout->addWidget(widthField);
initTable(std::dynamic_pointer_cast<Renderer::StrokeRadialGradient>(stroke->materialStroke)); initTable(radialStroke(stroke));
viewLayout->addWidget(strokeTable); viewLayout->addWidget(strokeTable);
initAddButton();
viewLayout->addWidget(addButton);
this->adjustSize(); this->adjustSize();
} }
@ -44,30 +70,23 @@ void StrokeStyleWidget::initStrokeSettings()
radialStroke(this->stroke)->gradual = checked; radialStroke(this->stroke)->gradual = checked;
}); });
#define endTypeBoxLabel(start, end) QStringLiteral(start##" -> "##end) if (!isClosedStroke(stroke))
this->endTypeBox = new QComboBox(this); {
endTypeBox->addItem(endTypeBoxLabel("圆头", "圆头")); // kRound this->endTypeBox = new QComboBox(this);
endTypeBox->addItem(endTypeBoxLabel("平头", "圆头")); // kFlatRound for (const auto& displayName : MaterialStyleStroke::strokeEndTypeNames | std::views::keys)
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)
{ {
case 0: endTypeBox->addItem(displayName);
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->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); this->widthField = new QtMaterialTextField(this);
widthField->setLabel(QStringLiteral("本侧描边宽度")); widthField->setLabel(QStringLiteral("本侧描边宽度"));
@ -83,13 +102,12 @@ void StrokeStyleWidget::initStrokeSettings()
}); });
} }
// TODO: 新增时参数校验 void StrokeStyleWidget::initTable(const std::shared_ptr<Renderer::StrokeRadialGradient>& materialStroke)
void StrokeStyleWidget::initTable(std::shared_ptr<Renderer::StrokeRadialGradient> materialStroke)
{ {
this->strokeTable = new QTableWidget(this); this->strokeTable = new QTableWidget(this);
strokeTable->setSizeAdjustPolicy(QAbstractScrollArea::AdjustToContentsOnFirstShow); strokeTable->setSizeAdjustPolicy(QAbstractScrollArea::AdjustToContentsOnFirstShow);
strokeTable->setColumnCount(5); strokeTable->setColumnCount(5);
strokeTable->setRowCount(materialStroke->materialMap.size() + 1); strokeTable->setRowCount(materialStroke->materialMap.size());
QStringList headers; QStringList headers;
headers << QStringLiteral("离心距离占比") headers << QStringLiteral("离心距离占比")
<< QStringLiteral("颜色") << QStringLiteral("颜色")
@ -97,44 +115,45 @@ void StrokeStyleWidget::initTable(std::shared_ptr<Renderer::StrokeRadialGradient
<< QStringLiteral("粗糙度") << QStringLiteral("粗糙度")
<< QStringLiteral("其他操作"); << QStringLiteral("其他操作");
strokeTable->setHorizontalHeaderLabels(headers); strokeTable->setHorizontalHeaderLabels(headers);
strokeTable->setMinimumHeight(strokeTable->rowHeight(0) * 5);
strokeTable->setMinimumWidth(strokeTable->sizeHint().width());
int row = 0; 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++; row++;
} }
// 新增按钮 connect(strokeTable, &QTableWidget::currentItemChanged, this, &StrokeStyleWidget::onCurrentItemChanged);
QtMaterialRaisedButton* addButton = new QtMaterialRaisedButton("+", strokeTable); connect(strokeTable, &QTableWidget::cellChanged, this, &StrokeStyleWidget::onCellChanged);
addButton->setBackgroundColor(QtMaterialStyle::instance().themeColor("primary1")); }
strokeTable->setSpan(row, 0, 1, 5);
strokeTable->setCellWidget(row, 0, addButton); void StrokeStyleWidget::initAddButton()
strokeTable->setMinimumHeight(strokeTable->rowHeight(row) * 5); {
strokeTable->setMinimumWidth(strokeTable->sizeHint().width()); this->addButton = new QtMaterialRaisedButton("+", strokeTable);
addButton->setFixedHeight(strokeTable->rowHeight(row)); addButton->setFixedHeight(this->strokeTable->rowHeight(0));
connect(addButton, &QtMaterialRaisedButton::clicked, [this]() { addButton->setBackgroundColor(ColorHelper::instance().getPrimary1());
connect(addButton, &QtMaterialRaisedButton::clicked, [this] {
handlingRowInsert = true; handlingRowInsert = true;
auto materialMap = &(radialStroke(this->stroke)->materialMap); auto& materialMap = radialStroke(this->stroke)->materialMap;
float newWidth = 0; float newWidth;
if (materialMap->size() == 0) if (materialMap.empty())
{ {
newWidth = 0.1; newWidth = 1.f;
} }
else else
{ {
auto lastPair = materialMap->rbegin(); const auto firstPair = materialMap.begin();
newWidth = lastPair->first + 0.01; newWidth = firstPair->first / 2;
} }
Renderer::Material newMaterial(QColor::fromRgb(0, 0, 0)); const Renderer::Material newMaterial(ColorHelper::instance().getPrimary1());
(*materialMap)[newWidth] = newMaterial; materialMap[newWidth] = newMaterial;
int newRow = this->strokeTable->rowCount() - 1; const int newRow = this->strokeTable->rowCount();
this->strokeTable->insertRow(newRow); this->strokeTable->insertRow(newRow);
setTableRow(newRow, newWidth, (*materialMap)[newWidth]); setTableRow(newRow, newWidth, materialMap[newWidth]);
this->strokeTable->update(); this->strokeTable->update();
handlingRowInsert = false; 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) void StrokeStyleWidget::setTableRow(int row, float width, Renderer::Material& material)
@ -143,14 +162,14 @@ void StrokeStyleWidget::setTableRow(int row, float width, Renderer::Material& ma
widthItem->setData(Qt::EditRole, width); widthItem->setData(Qt::EditRole, width);
strokeTable->setItem(row, COLUMN_WIDTH, widthItem); strokeTable->setItem(row, COLUMN_WIDTH, widthItem);
QColor* colorPtr = &(material.color); QColor* colorPtr = &material.color;
auto* colorItem = new QTableWidgetItem; auto* colorItem = new QTableWidgetItem;
colorItem->setData(Qt::DisplayRole, *colorPtr); colorItem->setData(Qt::DisplayRole, *colorPtr);
strokeTable->setItem(row, COLUMN_COLOR, colorItem); strokeTable->setItem(row, COLUMN_COLOR, colorItem);
auto* colorPicker = new ColorPicker(*colorPtr, strokeTable); auto* colorPicker = new ColorPicker(*colorPtr, strokeTable);
strokeTable->setCellWidget(row, COLUMN_COLOR, colorPicker); strokeTable->setCellWidget(row, COLUMN_COLOR, colorPicker);
connect(colorPicker, &ColorPicker::colorChanged, [this, colorPtr](QColor color) { connect(colorPicker, &ColorPicker::colorChanged, [this, colorPtr](QColor color) {
*colorPtr = color; *colorPtr = std::move(color);
this->strokeTable->update(); this->strokeTable->update();
}); });
@ -163,10 +182,10 @@ void StrokeStyleWidget::setTableRow(int row, float width, Renderer::Material& ma
strokeTable->setItem(row, COLUMN_ROUGHNESS, roughnessItem); strokeTable->setItem(row, COLUMN_ROUGHNESS, roughnessItem);
auto* removeButton = new QtMaterialRaisedButton("-", strokeTable); auto* removeButton = new QtMaterialRaisedButton("-", strokeTable);
removeButton->setBackgroundColor(QtMaterialStyle::instance().themeColor("primary1")); removeButton->setBackgroundColor(ColorHelper::instance().getPrimary1());
removeButton->setFixedSize(20, 20); removeButton->setFixedSize(20, 20);
strokeTable->setCellWidget(row, COLUMN_OPERATIONS, removeButton); 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()); radialStroke(this->stroke)->materialMap.erase(this->strokeTable->item(row, COLUMN_WIDTH)->text().toFloat());
this->strokeTable->removeRow(row); 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) void StrokeStyleWidget::onCurrentItemChanged(QTableWidgetItem* current, QTableWidgetItem* previous)
{ {
if (!current) return; if (!current) return;
int column = current->column(); const int column = current->column();
if (column != COLUMN_COLOR && column != COLUMN_OPERATIONS) if (column != COLUMN_COLOR && column != COLUMN_OPERATIONS)
{ {
this->currentItemValue = current->data(Qt::EditRole); this->currentItemValue = current->data(Qt::EditRole);
@ -185,23 +204,27 @@ void StrokeStyleWidget::onCurrentItemChanged(QTableWidgetItem* current, QTableWi
void StrokeStyleWidget::onCellChanged(int row, int column) void StrokeStyleWidget::onCellChanged(int row, int column)
{ {
if (handlingRowInsert) return; if (handlingRowInsert) return;
auto changedItem = strokeTable->item(row, column); const auto changedItem = strokeTable->item(row, column);
auto changedItemValue = changedItem->text().toFloat(); const auto changedItemValue = changedItem->text().toFloat();
if (changedItemValue < 0 || 1 < changedItemValue) if (changedItemValue < 0 || 1 < changedItemValue)
{ {
changedItem->setData(Qt::EditRole, this->currentItemValue.toFloat()); changedItem->setData(Qt::EditRole, this->currentItemValue.toFloat());
return; 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) switch (column)
{ {
case COLUMN_WIDTH: case COLUMN_WIDTH:
{ {
float oldWidth = this->currentItemValue.toFloat(); float oldWidth = this->currentItemValue.toFloat();
auto node = radialStroke(stroke)->materialMap.extract(oldWidth); auto node = radialStroke(stroke)->materialMap.extract(oldWidth);
if (node.empty())
{
break;
}
node.key() = changedWidth; node.key() = changedWidth;
radialStroke(stroke)->materialMap.insert(std::move(node)); radialStroke(stroke)->materialMap.insert(std::move(node));
strokeTable->sortItems(COLUMN_WIDTH); strokeTable->sortItems(COLUMN_WIDTH, Qt::DescendingOrder);
break; break;
} }
case COLUMN_METALLIC: case COLUMN_METALLIC:

View File

@ -6,6 +6,7 @@
#include <QComboBox> #include <QComboBox>
#include <qtmaterialtextfield.h> #include <qtmaterialtextfield.h>
#include <qtmaterialcheckbox.h> #include <qtmaterialcheckbox.h>
#include <qtmaterialraisedbutton.h>
class StrokeStyleWidget : public QWidget class StrokeStyleWidget : public QWidget
{ {
Q_OBJECT Q_OBJECT
@ -16,15 +17,17 @@ private:
QComboBox* endTypeBox; QComboBox* endTypeBox;
QtMaterialTextField* widthField; QtMaterialTextField* widthField;
QTableWidget* strokeTable; QTableWidget* strokeTable;
QtMaterialRaisedButton* addButton;
bool handlingRowInsert = false; bool handlingRowInsert = false;
void initStrokeSettings(); void initStrokeSettings();
void initTable(std::shared_ptr<Renderer::StrokeRadialGradient> materialStroke); void initTable(const std::shared_ptr<Renderer::StrokeRadialGradient>& materialStroke);
void initAddButton();
void setTableRow(int row, float width, Renderer::Material& material); void setTableRow(int row, float width, Renderer::Material& material);
public: public:
StrokeStyleWidget(std::shared_ptr<Renderer::MaterialStyleStroke> stroke, QWidget* parent = nullptr); StrokeStyleWidget(const std::shared_ptr<MaterialStyleStroke>& stroke, QWidget* parent = nullptr);
std::shared_ptr<Renderer::MaterialStyleStroke> stroke; std::shared_ptr<MaterialStyleStroke> stroke;
protected slots: protected slots:
void onCurrentItemChanged(QTableWidgetItem* current, QTableWidgetItem* previous); void onCurrentItemChanged(QTableWidgetItem* current, QTableWidgetItem* previous);

View File

@ -25,6 +25,7 @@ EditorWidgetItem::EditorWidgetItem(QString filePath,QWidget *parent) : QWidget(p
treeWidget->refresh(); treeWidget->refresh();
previewWindow->refresh(); previewWindow->refresh();
}; };
connect(previewWindow, &PreviewWindow::triggerCentralRefresh, centralRefresh);
connect(layerInfoDisplayWidget, &InfoDisplayWidget::triggerCentralRefresh, centralRefresh); connect(layerInfoDisplayWidget, &InfoDisplayWidget::triggerCentralRefresh, centralRefresh);
connect(elementInfoDisplayWidget, &ElementPoolWidget::triggerCentralRefresh, centralRefresh); connect(elementInfoDisplayWidget, &ElementPoolWidget::triggerCentralRefresh, centralRefresh);
connect(treeWidget, &LayerTreeWidget::triggerCentralRefresh, centralRefresh); connect(treeWidget, &LayerTreeWidget::triggerCentralRefresh, centralRefresh);
@ -33,15 +34,15 @@ EditorWidgetItem::EditorWidgetItem(QString filePath,QWidget *parent) : QWidget(p
connect(previewWindow, &PreviewWindow::refreshElementPreviewByIndex, elementInfoDisplayWidget, &ElementPoolWidget::refreshPictureByIndex); connect(previewWindow, &PreviewWindow::refreshElementPreviewByIndex, elementInfoDisplayWidget, &ElementPoolWidget::refreshPictureByIndex);
connect(previewWindow, &PreviewWindow::layerInfoChanged, layerInfoDisplayWidget, &InfoDisplayWidget::triggerSelfRefresh); connect(previewWindow, &PreviewWindow::layerInfoChanged, layerInfoDisplayWidget, &InfoDisplayWidget::triggerSelfRefresh);
connect(treeWidget, &LayerTreeWidget::displayLayerChange, previewWindow, &PreviewWindow::currentLayerChanged); connect(treeWidget, &LayerTreeWidget::displayLayerChange, previewWindow, &PreviewWindow::currentLayerChanged);
connect(treeWidget, &LayerTreeWidget::requireRefreshElementWidget, elementInfoDisplayWidget, &ElementPoolWidget::refresh); //connect(treeWidget, &LayerTreeWidget::requireRefreshElementWidget, elementInfoDisplayWidget, &ElementPoolWidget::refresh);
connect(layerInfoDisplayWidget, &InfoDisplayWidget::requireRefreshElementWidget, elementInfoDisplayWidget, &ElementPoolWidget::refresh); // connect(layerInfoDisplayWidget, &InfoDisplayWidget::requireRefreshElementWidget, elementInfoDisplayWidget, &ElementPoolWidget::refresh);
connect(treeWidget, &LayerTreeWidget::displayLayerChange, this, &EditorWidgetItem::onLayerChange); connect(treeWidget, &LayerTreeWidget::displayLayerChange, this, &EditorWidgetItem::onLayerChange);
connect(layerInfoDisplayWidget, &InfoDisplayWidget::requireRefreshPreview, this, // connect(layerInfoDisplayWidget, &InfoDisplayWidget::requireRefreshPreview, this,
&EditorWidgetItem::triggerRefreshPreview); // &EditorWidgetItem::triggerRefreshPreview);
connect(treeWidget, &LayerTreeWidget::requireRefreshPreview, this, // connect(treeWidget, &LayerTreeWidget::requireRefreshPreview, this,
&EditorWidgetItem::triggerRefreshPreview); // &EditorWidgetItem::triggerRefreshPreview);
connect(layerInfoDisplayWidget, &InfoDisplayWidget::requireSelfRefresh, layerInfoDisplayWidget, &InfoDisplayWidget::triggerSelfRefresh); //connect(layerInfoDisplayWidget, &InfoDisplayWidget::requireSelfRefresh, layerInfoDisplayWidget, &InfoDisplayWidget::triggerSelfRefresh);
connect(elementInfoDisplayWidget, &ElementPoolWidget::refreshLayerTree, treeWidget, &LayerTreeWidget::refresh); // connect(elementInfoDisplayWidget, &ElementPoolWidget::refreshLayerTree, treeWidget, &LayerTreeWidget::refresh);
// &EditorWidget::triggerRefreshPreview); // &EditorWidget::triggerRefreshPreview);
// test // test
QFile settingFile; QFile settingFile;
@ -73,9 +74,10 @@ EditorWidgetItem::EditorWidgetItem(QString filePath,QWidget *parent) : QWidget(p
this->projectName = source.value("project-name").toString(); this->projectName = source.value("project-name").toString();
qDebug() << this->backgroundColor; qDebug() << this->backgroundColor;
qDebug() << this->projectName; qDebug() << this->projectName;
QTimer::singleShot(300, this, [this]() { QTimer::singleShot(300, this, [this, centralRefresh]() {
handleBackgroundColorChange(this->backgroundColor); handleBackgroundColorChange(this->backgroundColor);
handleProjectNameChange(this->projectName); handleProjectNameChange(this->projectName);
centralRefresh();
}); });
} }

View File

@ -127,7 +127,7 @@ bool SimpleElement::isClosed() const
void GroupElement::paint(QPainter* painter, QTransform transform, const LayerStyleContainer& styles) void GroupElement::paint(QPainter* painter, QTransform transform, const LayerStyleContainer& styles)
{ {
sourceLayer->paint(painter, transform); sourceLayer->paint(painter, transform, true);
} }
bool GroupElement::isClosed() const bool GroupElement::isClosed() const

View File

@ -13,8 +13,21 @@ LayerWrapper *LayerManager::getRoot() const
} }
void LayerManager::paint(QPainter *painter, QSize size,LayerWrapper* selecetedLayer) const void LayerManager::paint(QPainter *painter, QSize size,LayerWrapper* selecetedLayer) const
{ {
painter->save();
root->getCache(); root->getCache();
root->paint(painter); root->paint(painter);
painter->restore();
painter->save();
// painter->setBrush(QBrush(Qt::white));
//painter->setCompositionMode(QPainter::CompositionMode_Difference);
if (selecetedLayer != nullptr)
{
painter->setPen(QPen(Qt::gray, 2, Qt::DashLine));
selecetedLayer->paintVisualBounding(painter);
//painter->setPen(QPen(Qt::gray, 2, Qt::DashDotLine));
//selecetedLayer->paintVisualBounding(painter);
}
painter->restore();
} }
bool LayerManager::singleSelectedCheck() const bool LayerManager::singleSelectedCheck() const
{ {

View File

@ -2,6 +2,7 @@
#include "./EditorWidgetComponent/StrokeStyleWidget.h" #include "./EditorWidgetComponent/StrokeStyleWidget.h"
#include "./EditorWidgetComponent/FillStyleWidget.h" #include "./EditorWidgetComponent/FillStyleWidget.h"
#include "./util/EncodeUtil.hpp" #include "./util/EncodeUtil.hpp"
#include "../ColorHelper.hpp"
#include <qtmaterialcheckbox.h> #include <qtmaterialcheckbox.h>
#include <QHBoxLayout> #include <QHBoxLayout>
#include <QPushButton> #include <QPushButton>
@ -206,11 +207,11 @@ bool LayerStyleContainer::dropStyle(const QString& styleName)
float LayerStyleContainer::boundingBoxAffectValue() const { float LayerStyleContainer::boundingBoxAffectValue() const {
float maxLineWidth = 0; float maxLineWidth = 0;
const auto strokeStyle = styles.at(StrokeElementLayerStyle::displayName()); const auto strokeStyle = styles.find(StrokeElementLayerStyle::displayName());
if (strokeStyle != nullptr) if (strokeStyle != styles.end())
{ {
if (const auto strokeElementLayerStyle = if (const auto strokeElementLayerStyle =
std::dynamic_pointer_cast<StrokeElementLayerStyle>(strokeStyle); std::dynamic_pointer_cast<StrokeElementLayerStyle>(strokeStyle->second);
strokeElementLayerStyle != nullptr) strokeElementLayerStyle != nullptr)
{ {
const auto& leftStyleStroke = strokeElementLayerStyle->strokePair.first; const auto& leftStyleStroke = strokeElementLayerStyle->strokePair.first;
@ -247,18 +248,18 @@ std::unique_ptr<StrokeElementLayerStyle> StrokeElementLayerStyle::fromJson(const
return ptr; return ptr;
} }
StrokeElementLayerStyle::StrokeElementLayerStyle() StrokeElementLayerStyle::StrokeElementLayerStyle(bool isClosed)
{ {
const auto materialMap = std::map<float, Renderer::Material>(); const auto materialMap = std::map<float, Renderer::Material>();
this->strokePair.first = std::make_shared<MaterialStyleStroke>( this->strokePair.first = std::make_shared<MaterialStyleStroke>(
7, 7,
Renderer::StrokeType::kLeftSide, Renderer::StrokeEndType::kFlat, Renderer::StrokeType::kLeftSide, isClosed ? Renderer::StrokeEndType::kClosed : Renderer::StrokeEndType::kFlat,
std::make_shared<Renderer::StrokeRadialGradient>(materialMap, false) std::make_shared<Renderer::StrokeRadialGradient>(materialMap, false)
); );
this->strokePair.second = std::make_shared<MaterialStyleStroke>( this->strokePair.second = std::make_shared<MaterialStyleStroke>(
7, 7,
Renderer::StrokeType::kRightSide, Renderer::StrokeEndType::kFlat, Renderer::StrokeType::kRightSide, isClosed ? Renderer::StrokeEndType::kClosed : Renderer::StrokeEndType::kFlat,
std::make_shared<Renderer::StrokeRadialGradient>(materialMap, false) std::make_shared<Renderer::StrokeRadialGradient>(materialMap, false)
); );
@ -536,7 +537,7 @@ FillElementLayerStyle::FillElementLayerStyle(const PMaterialStyleFill& fillMater
if (!fillMaterialStyle) if (!fillMaterialStyle)
{ {
this->fillMaterialStyle = std::make_shared<MaterialStyleFill>( this->fillMaterialStyle = std::make_shared<MaterialStyleFill>(
std::make_shared<Renderer::FillPlain>(Renderer::Material(QColor::fromRgb(0, 0, 0))) std::make_shared<Renderer::FillPlain>(ColorHelper::instance().getPrimary1())
); );
} }
} }

View File

@ -46,7 +46,7 @@ public:
STYLE_NAME("Ãè±ß", "stroke") STYLE_NAME("Ãè±ß", "stroke")
static std::unique_ptr<StrokeElementLayerStyle> fromJson(const QJsonObject& json); static std::unique_ptr<StrokeElementLayerStyle> fromJson(const QJsonObject& json);
StrokeElementLayerStyle(); StrokeElementLayerStyle(bool isClosed);
StrokeElementLayerStyle(const PMaterialStyleStroke& left, const PMaterialStyleStroke& right = nullptr); StrokeElementLayerStyle(const PMaterialStyleStroke& left, const PMaterialStyleStroke& right = nullptr);
StrokeElementLayerStyle(const StrokeElementLayerStyle& other); StrokeElementLayerStyle(const StrokeElementLayerStyle& other);
~StrokeElementLayerStyle() override = default; ~StrokeElementLayerStyle() override = default;
@ -88,17 +88,23 @@ public:
class LayerStyleContainer : public Renderer::ElementStyle class LayerStyleContainer : public Renderer::ElementStyle
{ {
using DisplayNameWithSupplier = std::map<QString, std::function<std::unique_ptr<LayerStyle>()>>; using DisplayNameWithSupplier = std::map<QString, std::function<std::unique_ptr<LayerStyle>()>>;
private:
inline const static DisplayNameWithSupplier commonStyles = { { private:
inline const static DisplayNameWithSupplier commonStyles = { };
inline const static DisplayNameWithSupplier closedOnlyStyles = {
{
FillElementLayerStyle::displayName(),
[] { return std::make_unique<FillElementLayerStyle>(); }
},
{
StrokeElementLayerStyle::displayName(),
[] { return std::make_unique<StrokeElementLayerStyle>(true); }
}
};
inline const static DisplayNameWithSupplier unclosedOnlyStyles = { {
StrokeElementLayerStyle::displayName(), StrokeElementLayerStyle::displayName(),
[] { return std::make_unique<StrokeElementLayerStyle>(); } [] { return std::make_unique<StrokeElementLayerStyle>(false); }
} }; } };
inline const static DisplayNameWithSupplier closedOnlyStyles = { {
FillElementLayerStyle::displayName(),
[] { return std::make_unique<FillElementLayerStyle>(); }
} };
inline const static DisplayNameWithSupplier unclosedOnlyStyles = { };
DisplayNameWithSupplier unusedStyles; DisplayNameWithSupplier unusedStyles;
DisplayNameWithSupplier usedStyles; DisplayNameWithSupplier usedStyles;

View File

@ -47,6 +47,7 @@ LayerWrapper::LayerWrapper(QJsonObject json, FolderLayerWrapper*parent, ElementM
transformJson.value("scale").toObject().value("y").toDouble()}; transformJson.value("scale").toObject().value("y").toDouble()};
property.rotation = {transformJson.value("rotation").toDouble()}; property.rotation = {transformJson.value("rotation").toDouble()};
selected = false; selected = false;
hidden = false;
} }
FolderLayerWrapper::FolderLayerWrapper(QJsonObject json, ElementManager *elementManager, FolderLayerWrapper*parent) FolderLayerWrapper::FolderLayerWrapper(QJsonObject json, ElementManager *elementManager, FolderLayerWrapper*parent)
@ -199,6 +200,7 @@ void FolderLayerWrapper::delSelf() {
QTreeWidgetItem* LayerWrapper::getQTreeItem() QTreeWidgetItem* LayerWrapper::getQTreeItem()
{ {
this->qTreeWidgetItem->setData(0, Qt::UserRole, QVariant::fromValue(this)); this->qTreeWidgetItem->setData(0, Qt::UserRole, QVariant::fromValue(this));
this->qTreeWidgetItem->setCheckState(0, Qt::Checked);
return this->qTreeWidgetItem; return this->qTreeWidgetItem;
} }
@ -280,31 +282,34 @@ int FolderLayerWrapper::getReferencedBy()const
return -1; return -1;
} }
void LayerWrapper::paint(QPainter* painter, QTransform transform, bool ignoreSelected) void LayerWrapper::paint(QPainter* painter, QTransform transform, bool force)
{ {
if (!ignoreSelected && this->selected) // if (this->selected)
{ // {
painter->save(); // painter->save();
painter->setTransform(transform, ignoreSelected); //painter->setPen(QPen(Qt::red, 2));
painter->setPen(QPen(Qt::gray, 2)); //painter->setTransform(transform);
painter->setPen(Qt::DashLine); //painter->drawRect(this->cache.getBoundingRect());
painter->drawRect(cache.getBoundingRect()); //painter->restore();
painter->restore(); // }
}
} }
void FolderLayerWrapper::paint(QPainter* painter, QTransform transform, bool ignoreSelected) void FolderLayerWrapper::paint(QPainter* painter, QTransform transform, bool force)
{ {
LayerWrapper::paint(painter, transform, ignoreSelected); if (hidden && !force)
return;
LayerWrapper::paint(painter, transform, force);
transform = property.transform * transform; transform = property.transform * transform;
//qDebug() << transform; //qDebug() << transform;
for (auto& child : children) for (auto& child : children)
child->paint(painter, transform, ignoreSelected); child->paint(painter, transform, force);
} }
void LeafLayerWrapper::paint(QPainter* painter, QTransform transform, bool ignoreSelected) void LeafLayerWrapper::paint(QPainter* painter, QTransform transform, bool force)
{ {
LayerWrapper::paint(painter, transform, ignoreSelected); if (hidden && !force)
return;
LayerWrapper::paint(painter, transform, force);
transform = property.transform * transform; transform = property.transform * transform;
//qDebug() << transform; //qDebug() << transform;
if (wrappedElement != nullptr) if (wrappedElement != nullptr)
@ -347,11 +352,12 @@ void FolderLayerWrapper::collectDownReachable(std::set<LayerWrapper*>& reachable
void LayerWrapper::refreshTreeItem() void LayerWrapper::refreshTreeItem()
{ {
hidden = qTreeWidgetItem->checkState(0) == Qt::Unchecked;
} }
void LeafLayerWrapper::refreshTreeItem() void LeafLayerWrapper::refreshTreeItem()
{ {
LayerWrapper::refreshTreeItem();
if (typeid(*wrappedElement) == typeid(GroupElement)) if (typeid(*wrappedElement) == typeid(GroupElement))
{ {
this->qTreeWidgetItem->setText(0, "@ " + this->property.name); this->qTreeWidgetItem->setText(0, "@ " + this->property.name);
@ -366,6 +372,7 @@ void LeafLayerWrapper::refreshTreeItem()
void FolderLayerWrapper::refreshTreeItem() void FolderLayerWrapper::refreshTreeItem()
{ {
LayerWrapper::refreshTreeItem();
for (auto& child : this->children) { for (auto& child : this->children) {
child->refreshTreeItem(); child->refreshTreeItem();
} }
@ -429,3 +436,20 @@ bool LayerWrapper::canApplyStyles() const
{ {
return typeid(*this) == typeid(LeafLayerWrapper) && !referencingGroupElement(); return typeid(*this) == typeid(LeafLayerWrapper) && !referencingGroupElement();
} }
void LayerWrapper::paintVisualBounding(QPainter* painter) const
{
if (hidden)
return;
QTransform transform;
auto layer = this->parent;
while (layer != nullptr)
{
transform = transform * layer->property.transform;
layer = layer->parent;
}
painter->save();
painter->setTransform(transform);
painter->drawRect(cache.getBoundingRect());
painter->restore();
}

View File

@ -37,6 +37,7 @@ class LayerWrapper
public: public:
QTreeWidgetItem* qTreeWidgetItem; QTreeWidgetItem* qTreeWidgetItem;
bool selected; bool selected;
bool hidden;
struct SimpleProperty struct SimpleProperty
{ {
QString name = ""; QString name = "";
@ -58,7 +59,7 @@ class LayerWrapper
FolderLayerWrapper*getParent() const; // invoke by manager, then invoke parent's applyStyles FolderLayerWrapper*getParent() const; // invoke by manager, then invoke parent's applyStyles
LayerWrapper(QJsonObject json, FolderLayerWrapper*parent, ElementManager* elementManager=nullptr); LayerWrapper(QJsonObject json, FolderLayerWrapper*parent, ElementManager* elementManager=nullptr);
LayerWrapper() = default; LayerWrapper() = default;
virtual void paint(QPainter* painter, QTransform transform=QTransform(), bool ignoreSelected = false); virtual void paint(QPainter* painter, QTransform transform=QTransform(), bool force = false);
// TODO : export Function // TODO : export Function
// virtual LayerWrapper *addChild() = 0; // Leaf Child Only // virtual LayerWrapper *addChild() = 0; // Leaf Child Only
// virtual LayerWrapper *addParent() = 0; // Folder Parent Only // virtual LayerWrapper *addParent() = 0; // Folder Parent Only
@ -74,6 +75,7 @@ class LayerWrapper
virtual size_t referencedCount(bool excludeSelf = false) const; virtual size_t referencedCount(bool excludeSelf = false) const;
virtual bool deleteable(bool excludeSubTree = false) const; virtual bool deleteable(bool excludeSubTree = false) const;
virtual bool referencingGroupElement() const; virtual bool referencingGroupElement() const;
virtual void paintVisualBounding(QPainter* painter) const;
bool canApplyStyles() const; bool canApplyStyles() const;
}; };
@ -97,7 +99,7 @@ class FolderLayerWrapper : public LayerWrapper
QTreeWidgetItem* getQTreeItem() override; QTreeWidgetItem* getQTreeItem() override;
QJsonObject toJson() const override; QJsonObject toJson() const override;
int getReferencedBy()const; int getReferencedBy()const;
void paint(QPainter* painter, QTransform transform = QTransform(), bool ignoreSelected = false) override; void paint(QPainter* painter, QTransform transform = QTransform(), bool force = false) override;
void collectDownReachable(std::set<LayerWrapper*>& reachable) override; void collectDownReachable(std::set<LayerWrapper*>& reachable) override;
void refreshTreeItem() override; void refreshTreeItem() override;
size_t referencedCount(bool excludeSelf = false) const override; size_t referencedCount(bool excludeSelf = false) const override;
@ -115,7 +117,7 @@ class LeafLayerWrapper : public LayerWrapper
void refresh(LayerWrapper* layer = nullptr) override; void refresh(LayerWrapper* layer = nullptr) override;
LeafLayerWrapper(QJsonObject json, ElementManager *elementManager, FolderLayerWrapper*parent); LeafLayerWrapper(QJsonObject json, ElementManager *elementManager, FolderLayerWrapper*parent);
QJsonObject toJson() const override; QJsonObject toJson() const override;
void paint(QPainter* painter, QTransform transform = QTransform(), bool ignoreSelected = false) override; void paint(QPainter* painter, QTransform transform = QTransform(), bool force = false) override;
void collectDownReachable(std::set<LayerWrapper*>& reachable) override; void collectDownReachable(std::set<LayerWrapper*>& reachable) override;
QTreeWidgetItem* getQTreeItem() override; QTreeWidgetItem* getQTreeItem() override;
void refreshTreeItem() override; void refreshTreeItem() override;

View File

@ -78,7 +78,8 @@ PixelPath PixelPath::trans(QTransform& mat)const
painter.setTransform(mat); painter.setTransform(mat);
painter.drawPixmap(0, 0, pixmap); painter.drawPixmap(0, 0, pixmap);
result.painterPath.addPath(this->painterPath); result.painterPath.addPath(this->painterPath);
result.boundingRect = mat.mapRect(boundingRect); result.painterPath = mat.map(result.painterPath);
result.boundingRect = result.painterPath.boundingRect();
return result; return result;
} }

View File

@ -1,4 +1,5 @@
#include "PreviewWindow.h" #include "PreviewWindow.h"
#include <QApplication>
PreviewWindow::PreviewWindow(QWidget *parent) : QOpenGLWidget(parent) PreviewWindow::PreviewWindow(QWidget *parent) : QOpenGLWidget(parent)
{ {
@ -84,7 +85,17 @@ void PreviewWindow::mouseMoveEvent(QMouseEvent* event)
int dx = event->x() - m_lastPos.x(); int dx = event->x() - m_lastPos.x();
int dy = event->y() - m_lastPos.y(); int dy = event->y() - m_lastPos.y();
if (currentLayer != nullptr) { if (currentLayer != nullptr) {
if (event->buttons() & Qt::LeftButton) { if (QApplication::keyboardModifiers() == Qt::ControlModifier && (event->buttons() & Qt::LeftButton))
{
currentLayer->property.scale.setX(std::max(0.0, currentLayer->property.scale.x() + dx / 50.0));
currentLayer->property.scale.setY(std::max(0.0, currentLayer->property.scale.y() + dy / 50.0));
}
else if (QApplication::keyboardModifiers() == (Qt::ControlModifier | Qt::ShiftModifier) && (event->buttons() & Qt::LeftButton))
{
currentLayer->property.scale.setX(std::max(0.0, currentLayer->property.scale.x() * (1.0 + dx / 50.0)));
currentLayer->property.scale.setY(std::max(0.0, currentLayer->property.scale.y() * (1.0 + dx / 50.0)));
}
else if (event->buttons() & Qt::LeftButton) {
// 如果按下的是左键,那么平移图形 // 如果按下的是左键,那么平移图形
currentLayer->property.offset.setX(currentLayer->property.offset.x() + dx); currentLayer->property.offset.setX(currentLayer->property.offset.x() + dx);
currentLayer->property.offset.setY(currentLayer->property.offset.y() + dy); currentLayer->property.offset.setY(currentLayer->property.offset.y() + dy);
@ -100,19 +111,18 @@ void PreviewWindow::mouseMoveEvent(QMouseEvent* event)
auto index = -1; auto index = -1;
if (typeid(*layer) == typeid(FolderLayerWrapper)) if (typeid(*layer) == typeid(FolderLayerWrapper))
index = dynamic_cast<FolderLayerWrapper*>(layer)->getReferencedBy(); index = dynamic_cast<FolderLayerWrapper*>(layer)->getReferencedBy();
if (index != -1)
emit refreshElementPreviewByIndex(index);
layer = layer->getParent(); layer = layer->getParent();
} }
} }
// 更新上一次的位置 // 更新上一次的位置
emit triggerCentralRefresh();
m_lastPos = event->pos(); m_lastPos = event->pos();
this->repaint(); this->repaint();
} }
void PreviewWindow::mouseReleaseEvent(QMouseEvent* event) void PreviewWindow::mouseReleaseEvent(QMouseEvent* event)
{ {
emit layerInfoChanged(); //emit layerInfoChanged();
} }
void PreviewWindow::setBackgroundColor(QColor color) void PreviewWindow::setBackgroundColor(QColor color)

View File

@ -46,4 +46,5 @@ class PreviewWindow : public QOpenGLWidget, protected QOpenGLFunctions
void layerInfoChanged(); void layerInfoChanged();
void refreshElementPreview(GraphicElement*); void refreshElementPreview(GraphicElement*);
void refreshElementPreviewByIndex(int); void refreshElementPreviewByIndex(int);
void triggerCentralRefresh();
}; };

View File

@ -1,6 +1,6 @@
#include "EditorSettingWidget.h" #include "EditorSettingWidget.h"
#include "../ColorHelper.hpp"
#include <QPushButton> #include <QPushButton>
#include <QColorDialog>
#include <QInputDialog> #include <QInputDialog>
EditorSettingWidget::EditorSettingWidget(QWidget* parent) EditorSettingWidget::EditorSettingWidget(QWidget* parent)
@ -8,7 +8,7 @@ EditorSettingWidget::EditorSettingWidget(QWidget* parent)
{ {
ui.setupUi(this); ui.setupUi(this);
connect(ui.backgroundColorButton, &QPushButton::clicked, this, [this]() { connect(ui.backgroundColorButton, &QPushButton::clicked, this, [this]() {
QColor color = QColorDialog::getColor(Qt::white, this, QString::fromLocal8Bit("Ñ¡Ôñ±³¾°ÑÕÉ«")); QColor color = ColorHelper::execColorDialog(Qt::white, this, QString::fromLocal8Bit("Ñ¡Ôñ±³¾°ÑÕÉ«"));
if (color.isValid()) if (color.isValid())
{ {
emit backgroundColorChanged(color); emit backgroundColorChanged(color);

View File

@ -21,12 +21,11 @@ void InfoDisplayWidget::generateLayerForm()
{ {
while (this->layout()->count() > 0 && (item = this->layout()->takeAt(0)) != nullptr) while (this->layout()->count() > 0 && (item = this->layout()->takeAt(0)) != nullptr)
{ {
delete item->widget(); item->widget()->deleteLater();
delete item; delete item;
} }
delete this->layout(); delete this->layout();
} }
QFormLayout *layout = new QFormLayout(); QFormLayout *layout = new QFormLayout();
layout->setRowWrapPolicy(QFormLayout::WrapAllRows); layout->setRowWrapPolicy(QFormLayout::WrapAllRows);
if (this->displayLayer == nullptr) if (this->displayLayer == nullptr)

View File

@ -2,6 +2,7 @@
#include <QInputDialog> #include <QInputDialog>
#include <QMenu> #include <QMenu>
#include "./EditorWidgetComponent/LayerCreateWidget.h" #include "./EditorWidgetComponent/LayerCreateWidget.h"
#include <QTimer>
LayerTreeWidget::LayerTreeWidget(QWidget *parent) LayerTreeWidget::LayerTreeWidget(QWidget *parent)
{ {
@ -26,6 +27,10 @@ LayerTreeWidget::LayerTreeWidget(QWidget *parent)
} }
emit triggerCentralRefresh(); emit triggerCentralRefresh();
}); });
connect(this, &QTreeWidget::itemChanged, this, [=]() {
emit triggerCentralRefresh();
});
// connect(this, &QTreeWidget::itemDoubleClicked, this, &LayerTreeWidget::onItemDoubleClicked); // connect(this, &QTreeWidget::itemDoubleClicked, this, &LayerTreeWidget::onItemDoubleClicked);
} }

View File

@ -5,7 +5,7 @@
#include <queue> #include <queue>
using Renderer::Painting; using Renderer::Painting;
using Renderer::Element; using Renderer::BaseElement;
using Renderer::ElementTransform; using Renderer::ElementTransform;
using Renderer::BaseElement; using Renderer::BaseElement;
using glm::bvec2; using glm::bvec2;
@ -18,231 +18,119 @@ using std::queue;
const double PaintingUtil::pi = acos(-1); const double PaintingUtil::pi = acos(-1);
struct LayerNode { struct LayerNode {
LayerWrapper* nowLayer; LayerWrapper* nowLayer;
QTransform transfrom; QTransform transfrom;
}; };
QJsonObject PaintingUtil::readJsonFile(QString jsonFilePath) { QJsonObject PaintingUtil::readJsonFile(QString jsonFilePath) {
QFile jsonFile(jsonFilePath); QFile jsonFile(jsonFilePath);
jsonFile.open(QFile::ReadOnly); qDebug() << jsonFilePath;
QByteArray fileContent = jsonFile.readAll().trimmed(); jsonFile.open(QFile::ReadOnly);
jsonFile.close(); QByteArray fileContent = jsonFile.readAll().trimmed();
QJsonParseError jError; jsonFile.close();
QJsonDocument jsonDoc(QJsonDocument::fromJson(fileContent, &jError)); QJsonParseError jError;
return jsonDoc.object(); QJsonDocument jsonDoc(QJsonDocument::fromJson(fileContent, &jError));
return jsonDoc.object();
} }
Painting PaintingUtil::transfromToPainting(QString jsonFilePath) { Painting PaintingUtil::transfromToPainting(QString jsonFilePath) {
Painting painting; Painting painting;
glm::bvec2 flip(0, 0); glm::bvec2 flip(0, 0);
QJsonObject jsonObj = readJsonFile(jsonFilePath); QJsonObject jsonObj = readJsonFile(jsonFilePath);
qDebug() << jsonObj; qDebug() << jsonObj;
shared_ptr<ElementManager> elementManager = make_shared<ElementManager>(jsonObj, Renderer::ElementRenderer::instance()); shared_ptr<ElementManager> elementManager = make_shared<ElementManager>(jsonObj, Renderer::ElementRenderer::instance());
shared_ptr<LayerManager> layerManager = make_shared<LayerManager>(jsonObj, elementManager.get()); shared_ptr<LayerManager> layerManager = make_shared<LayerManager>(jsonObj, elementManager.get());
//qDebug() << elementManager->toJson(); //qDebug() << elementManager->toJson();
//qDebug() << layerManager->toJson(); //qDebug() << layerManager->toJson();
//qDebug() << ((SimpleElement*)((LeafLayerWrapper*)((FolderLayerWrapper*)((FolderLayerWrapper*)layerManager->getRoot())->children[0].get())->children[0].get())->wrappedElement)->painterPath; //qDebug() << ((SimpleElement*)((LeafLayerWrapper*)((FolderLayerWrapper*)((FolderLayerWrapper*)layerManager->getRoot())->children[0].get())->children[0].get())->wrappedElement)->painterPath;
//qDebug() << ((LeafLayerWrapper*)((FolderLayerWrapper*)((FolderLayerWrapper*)layerManager->getRoot())->children[0].get())->children[0].get())->getCache().painterPath; //qDebug() << ((LeafLayerWrapper*)((FolderLayerWrapper*)((FolderLayerWrapper*)layerManager->getRoot())->children[0].get())->children[0].get())->getCache().painterPath;
queue<LayerNode> layerQueue; //qDebug() << elementManager->toJson();
LayerWrapper* root = layerManager->getRoot(); //qDebug() << layerManager->toJson();
root->getCache(); //qDebug() << ((SimpleElement*)((LeafLayerWrapper*)((FolderLayerWrapper*)((FolderLayerWrapper*)layerManager->getRoot())->children[0].get())->children[0].get())->wrappedElement)->painterPath;
double maxLineWidth = getMaxLineWidth(root); //qDebug() << ((LeafLayerWrapper*)((FolderLayerWrapper*)((FolderLayerWrapper*)layerManager->getRoot())->children[0].get())->children[0].get())->getCache().painterPath;
layerQueue.push({ root, root->property.transform }); queue<LayerNode> layerQueue;
while (!layerQueue.empty()) { LayerWrapper* root = layerManager->getRoot();
auto layerNode = layerQueue.front(); root->getCache();
layerQueue.pop(); //double maxLineWidth = getMaxLineWidth(root);
FolderLayerWrapper* nowLayer = handleLayerWrapper(layerNode.nowLayer, maxLineWidth, layerNode.transfrom, painting); layerQueue.push({ root, root->property.transform });
if (nowLayer != nullptr) { while (!layerQueue.empty()) {
for (auto sonLayer : nowLayer->children) { auto layerNode = layerQueue.front();
layerQueue.push({ sonLayer.get(), layerNode.transfrom}); layerQueue.pop();
} FolderLayerWrapper* nowLayer = handleLayerWrapper(layerNode.nowLayer, layerNode.transfrom, painting);
} if (nowLayer != nullptr) {
} for (auto sonLayer : nowLayer->children) {
layerQueue.push({ sonLayer.get(), layerNode.transfrom });
}
}
}
return painting; return painting;
} }
FolderLayerWrapper* PaintingUtil::handleLayerWrapper(LayerWrapper* nowLayer, double& maxLineWidth, QTransform& transform, Painting& painting) { FolderLayerWrapper* PaintingUtil::handleLayerWrapper(LayerWrapper* nowLayer, QTransform& transform, Painting& painting) {
LeafLayerWrapper* leafLayer = dynamic_cast<LeafLayerWrapper*>(nowLayer); LeafLayerWrapper* leafLayer = dynamic_cast<LeafLayerWrapper*>(nowLayer);
transform = nowLayer->property.transform * transform; transform = nowLayer->property.transform * transform;
if (leafLayer != nullptr) { if (leafLayer != nullptr) {
GroupElement* wrapperElement = dynamic_cast<GroupElement*>(leafLayer->wrappedElement); GroupElement* wrapperElement = dynamic_cast<GroupElement*>(leafLayer->wrappedElement);
if (wrapperElement != nullptr) { if (wrapperElement != nullptr) {
transform = wrapperElement->sourceLayer->property.transform * transform; transform = wrapperElement->sourceLayer->property.transform * transform;
return wrapperElement->sourceLayer; return wrapperElement->sourceLayer;
} }
PixelPath pixelPath = nowLayer->getCache(); PixelPath pixelPath = nowLayer->getCache();
QPainterPath painterPath = pixelPath.getPainterPath(); QPainterPath painterPath = pixelPath.getPainterPath();
QRectF bound = painterPath.boundingRect(); QRectF bound = painterPath.boundingRect();
//qDebug() << leafLayer<<"------" << painterPath; //qDebug() << leafLayer<<"------" << painterPath;
//qDebug() << transform; // transform to -1£¬ 1
//Element element; QTransform trans;
//ElementTransform elementTrans; double maxLen = std::max(bound.width(), bound.height());
//element.ratio = bound.width() / bound.height(); qDebug() << maxLen << bound;
// transform to initial painterPath trans.scale(1 / maxLen, 1 / maxLen);
// transfrom to -1£¬ 1 trans.translate(-bound.center().x(), -bound.center().y());
QTransform trans;
trans.translate(-centerX, -centerY)
.scale(1 / nowLayer->property.scale.x(), 1 / nowLayer->property.scale.y())
.rotate(-nowLayer->property.rotation)
.translate(centerX, centerY)
.translate(-nowLayer->property.offset.x(), -nowLayer->property.offset.y());
QPainterPath painterPath = trans.map(pixelPath.getPainterPath());
// transfrom to -1£¬ 1
QTransform trans;
double maxLen = std::max(bound.width(), bound.height()) + maxLineWidth * 2;
qDebug() << maxLen << bound;
trans.scale(1 / maxLen, 1 / maxLen);
trans.translate(-bound.center().x(), -bound.center().y());
qDebug() << trans.map(painterPath); painterPath = trans.map(painterPath);
shared_ptr<vector<vector<Renderer::Point> >> contour = std::make_shared<vector<vector<Renderer::Point> >>(PainterPathUtil::transformToLines(trans.map(painterPath))); shared_ptr<vector<vector<Renderer::Point> >> contour = std::make_shared<vector<vector<Renderer::Point> >>(PainterPathUtil::transformToLines(painterPath));
QSize screenSize = QSize(1024, 1024); QSize screenSize = QSize(1024, 1024);
//element.style = std::make_shared<Renderer::ElementStyleStrokeDemo>(0.06);
ElementTransform elementTransform;
transform = trans.inverted() * transform * QTransform::fromScale(2. / screenSize.width(), 2. / screenSize.height()) * QTransform::fromTranslate(-1, -1) * QTransform::fromScale(1, -1);
painterPath = transform.map(painterPath); auto baseStyles = leafLayer->styles.toBaseStyles();
qDebug() << painterPath; Renderer::BaseElement element;
bound = painterPath.boundingRect(); element.contour = contour;
for (auto& baseStyle : baseStyles) {
double lineWidth = 0;
if (baseStyle.material->type() == Renderer::MaterialStyleType::kStroke) {
auto material = std::static_pointer_cast<MaterialStyleStroke>(baseStyle.material);
material->halfWidth /= maxLen;
lineWidth = material->halfWidth;
qDebug() << material->halfWidth;
}
QPainterPathStroker stroker;
stroker.setWidth(lineWidth);
stroker.setCapStyle(Qt::RoundCap);
QPainterPath strokePath = stroker.createStroke(painterPath);
auto rect = transform.map(strokePath).boundingRect();
elementTransform.bound = glm::vec4(rect.x(), rect.y(), rect.x() + rect.width(), rect.y() + rect.height());
qDebug() << elementTransform.bound.x << elementTransform.bound.y << elementTransform.bound.z << elementTransform.bound.z;
transform = transform.inverted();
elementTransform.transform = glm::mat3x2(
transform.m11(), transform.m12(), transform.m21(),
transform.m22(), transform.m31(), transform.m32()
);
//qDebug() << transform;
elementTransform.zIndex = 0;
ElementTransform elementTransform; element.style = baseStyle.material;
transform = transform * trans; painting.addElement(element, elementTransform);
//elementTransform.bound = glm::vec4(-1, -1, 1, 1); }
elementTransform.bound = glm::vec4(
2 * (bound.x() - maxLineWidth) / screenSize.width() - 1,
2 * (bound.y() - maxLineWidth) / screenSize.height() - 1,
2 * (bound.x() + bound.width() + maxLineWidth) / screenSize.width() - 1,
2 * (bound.y() + bound.height() + maxLineWidth) / screenSize.height() - 1
);
qDebug() << elementTransform.bound.x << elementTransform.bound.y << elementTransform.bound.z << elementTransform.bound.z;
transform = transform.inverted();
elementTransform.transform = glm::mat3x2(
transform.m11(), transform.m12(), transform.m21(),
transform.m22(), transform.m31(), transform.m32()
);
qDebug() << transform;
elementTransform.zIndex = 0;
auto baseStyles = leafLayer->styles.toBaseStyles(); return nullptr;
BaseElement element; element.contour = contour; }
for (auto baseStyle : baseStyles) {
if (baseStyle.material->type() == Renderer::MaterialStyleType::kStroke) {
auto material = dynamic_cast<MaterialStyleStroke*>(baseStyle.material.get());
material->halfWidth = material->halfWidth / maxLen;
qDebug() << material->halfWidth;
}
element.style = baseStyle.material;
painting.addElement(element, elementTransform);
}
//qDebug() << bound; FolderLayerWrapper* folderLayer = dynamic_cast<FolderLayerWrapper*>(nowLayer);
return folderLayer;
// TODO ¸ÄÓþØÕó
/* elementTrans.center = glm::vec2(
(2 * bound.center().x() - screenSize.width()) / screenSize.width(),
(2 * bound.center().y() - screenSize.height()) / screenSize.height()
);
qDebug() << elementTrans.center.x << elementTrans.center.y;
decomposeTransform(transform, elementTrans.rotation, elementTrans.scale);
elementTrans.scale = glm::vec2(
bound.width() * 2 / screenSize.width(),
bound.height() * 2 / screenSize.height()
);
elementTrans.flip = glm::bvec2(
nowLayer->property.flipHorizontally,
nowLayer->property.flipVertically
);
qDebug() << elementTrans.scale.x << elementTrans.scale.y;
painting.addElement(element, elementTrans);*/
return nullptr;
}
FolderLayerWrapper* folderLayer = dynamic_cast<FolderLayerWrapper*>(nowLayer);
return folderLayer;
}
void PaintingUtil::decomposeTransform(QTransform trans, float& angle, glm::vec2& scale) {
//qDebug() << trans;
trans.setMatrix(
trans.m11(), trans.m12(), trans.m13(),
trans.m21(), trans.m22(), trans.m23(),
0, 0, 1);
//qDebug() << trans.dx() << trans.dy();
int count = 0;
double norm = 0, n = 0;
QTransform R = trans, Rit, Rnext;
do {
++count;
Rit = R.transposed().inverted();
Rnext.setMatrix(
(R.m11() + Rit.m11()) / 2,
(R.m12() + Rit.m12()) / 2,
(R.m13() + Rit.m13()) / 2,
(R.m21() + Rit.m21()) / 2,
(R.m22() + Rit.m22()) / 2,
(R.m23() + Rit.m23()) / 2,
(R.m31() + Rit.m31()) / 2,
(R.m32() + Rit.m32()) / 2,
(R.m33() + Rit.m33()) / 2
);
norm = 0;
norm = max(norm,
fabs(R.m11() - Rnext.m11())
+ fabs(R.m12() - Rnext.m12())
+ fabs(R.m13() - Rnext.m13()));
norm = max(norm,
fabs(R.m21() - Rnext.m21())
+ fabs(R.m22() - Rnext.m22())
+ fabs(R.m23() - Rnext.m23()));
norm = max(norm,
fabs(R.m31() - Rnext.m31())
+ fabs(R.m32() - Rnext.m32())
+ fabs(R.m33() - Rnext.m33()));
R = Rnext;
} while (count < 100 && norm > 0.0001);
double cosValue = max(-1.0, min(R.m11(), 1.0));
double sinValue = max(-1.0, min(R.m12(), 1.0));
angle = acos(cosValue) * 180 / pi;
if (sinValue < 0) {
angle = 360 - angle;
}
qDebug() << angle;
//R = R.inverted() * trans;
//scale = glm::vec2(R.m11(), R.m22());
//qDebug() << scale.x << scale.y;
return;
}
double PaintingUtil::getMaxLineWidth(LayerWrapper* root) {
double maxWidth = 0;
queue<LayerWrapper* > layerQueue;
layerQueue.push(root);
while (!layerQueue.empty()) {
auto layer = layerQueue.front();
layerQueue.pop();
FolderLayerWrapper* nextLayer = nullptr;
LeafLayerWrapper* leafLayer = dynamic_cast<LeafLayerWrapper*>(layer);
if (leafLayer != nullptr) {
GroupElement* wrapperElement = dynamic_cast<GroupElement*>(leafLayer->wrappedElement);
if (wrapperElement != nullptr) {
nextLayer = wrapperElement->sourceLayer;
}
else {
maxWidth = std::max(maxWidth, (double)leafLayer->styles.boundingBoxAffectValue());
}
}
else {
nextLayer = dynamic_cast<FolderLayerWrapper*>(layer);
}
if (nextLayer != nullptr) {
for (auto sonLayer : nextLayer->children) {
layerQueue.push(sonLayer.get());
}
}
}
return maxWidth;
} }

View File

@ -7,11 +7,9 @@ class PaintingUtil
private: private:
static const double pi; static const double pi;
static QJsonObject readJsonFile(QString jsonFilePath); static QJsonObject readJsonFile(QString jsonFilePath);
static FolderLayerWrapper* handleLayerWrapper(LayerWrapper* nowLayer, double& maxLineWidth, QTransform& transform, Renderer::Painting& painting); static FolderLayerWrapper* handleLayerWrapper(LayerWrapper* nowLayer, QTransform& transform, Renderer::Painting& painting);
static double getMaxLineWidth(LayerWrapper* root); //static double getMaxLineWidth(LayerWrapper* root);
public: public:
static Renderer::Painting transfromToPainting(QString jsonFilePath); static Renderer::Painting transfromToPainting(QString jsonFilePath);
static void decomposeTransform(QTransform trans, float& angle, glm::vec2& scale);
}; };

View File

@ -22,3 +22,8 @@ void ::FluentMenu::paintEvent(QPaintEvent* event)
} }
QMenu::paintEvent(event); QMenu::paintEvent(event);
} }
QAction* FluentMenu::exec(const QPoint& pos, QAction* at)
{
return QMenu::exec(parentWidget()->mapToGlobal(parentWidget()->mapFromGlobal(pos) + QPoint(-shadowRadius, -shadowRadius)), at);
}

View File

@ -7,6 +7,7 @@ class FluentMenu : public QMenu
public: public:
explicit FluentMenu(QWidget* parent = nullptr); explicit FluentMenu(QWidget* parent = nullptr);
void paintEvent(QPaintEvent* event) override; void paintEvent(QPaintEvent* event) override;
QAction* exec(const QPoint& pos, QAction* at = nullptr);
int shadowRadius = 16; int shadowRadius = 16;
int borderRadius = 6; int borderRadius = 6;
int itemBorderRadius = 4; int itemBorderRadius = 4;

View File

@ -244,8 +244,9 @@ GLuint Renderer::Model::loadPainting(std::string path)
return iter->second; return iter->second;
Painting painting; Painting painting;
path = "../test.json";
if (auto file = QFileInfo(QString(path.c_str())); file.isFile()) if (auto file = QFileInfo(QString(path.c_str())); file.isFile())
painting = PaintingUtil::transfromToPainting(file.path()); painting = PaintingUtil::transfromToPainting(file.filePath());
else else
{ {
qDebug() << path.c_str() << "Not Found, Using Default Painting"; qDebug() << path.c_str() << "Not Found, Using Default Painting";

View File

@ -20,8 +20,7 @@ QVector4D BvhTree::Union(QVector4D a, QVector4D b) {
QVector4D BvhTree::merge(BvhPtr lp, BvhPtr rp) { QVector4D BvhTree::merge(BvhPtr lp, BvhPtr rp) {
QVector4D a = lp->bound, b = rp->bound; QVector4D a = lp->bound, b = rp->bound;
/* /*if (lp->isLeaf) {
if (lp->isLeaf) {
a = BvhTreeData::boundWithRotation(a, lp->getRightSon()); a = BvhTreeData::boundWithRotation(a, lp->getRightSon());
} }
if (rp->isLeaf) { if (rp->isLeaf) {

View File

@ -1,5 +1,6 @@
#include "MaterialStyleStroke.h" #include "MaterialStyleStroke.h"
#include <QDebug> #include <QDebug>
#include <array>
using namespace Renderer; using namespace Renderer;
@ -117,4 +118,10 @@ float Renderer::MaterialStyleStroke::getHalfWidth() const
return halfWidth; return halfWidth;
} }
#define endTypeBoxLabel(start, end) QStringLiteral(start##" -> "##end)
const std::array<std::pair<QString, StrokeEndType>, 4> Renderer::MaterialStyleStroke::strokeEndTypeNames = {
std::pair{endTypeBoxLabel("Բͷ", "Բͷ"), StrokeEndType::kRound},
std::pair{endTypeBoxLabel("ƽͷ", "Բͷ"), StrokeEndType::kFlatRound},
std::pair{endTypeBoxLabel("Բͷ", "ƽͷ"), StrokeEndType::kRoundFlat},
std::pair{endTypeBoxLabel("ƽͷ", "ƽͷ"), StrokeEndType::kFlat}
};

View File

@ -43,7 +43,7 @@ namespace Renderer
}; };
enum class StrokeType { kBothSides = 2, kLeftSide = 1, kRightSide = 0 }; enum class StrokeType { kBothSides = 2, kLeftSide = 1, kRightSide = 0 };
enum class StrokeEndType { kRound = 0b00, kFlat = 0b11, kRoundFlat = 0b10, kFlatRound = 0b01 }; enum class StrokeEndType { kRound = 0b00, kFlat = 0b11, kRoundFlat = 0b10, kFlatRound = 0b01, kClosed = 0b100/*用于封闭图形*/ };
class MaterialStyleStroke : public MaterialStyle class MaterialStyleStroke : public MaterialStyle
{ {
@ -59,5 +59,6 @@ namespace Renderer
StrokeType strokeType; StrokeType strokeType;
StrokeEndType endType; StrokeEndType endType;
std::shared_ptr<MaterialStroke> materialStroke; std::shared_ptr<MaterialStroke> materialStroke;
static const std::array<std::pair<QString, StrokeEndType>, 4> strokeEndTypeNames;
}; };
} }

View File

@ -29,7 +29,7 @@ Renderer::RendererWidget::RendererWidget(QWidget* parent)
ui.openButton->setChecked(false); ui.openButton->setChecked(false);
}); });
QObject::connect(ui.openButton, &QPushButton::clicked, [&, menu]() { QObject::connect(ui.openButton, &QPushButton::clicked, [&, menu]() {
menu->exec(ui.openButton->mapToGlobal(QPoint(-menu->shadowRadius, ui.openButton->height() - menu->shadowRadius))); menu->exec(ui.openButton->mapToGlobal(QPoint(0, ui.openButton->height())));
}); });
QObject::connect(ui.horizontalSlider, &QSlider::valueChanged, QObject::connect(ui.horizontalSlider, &QSlider::valueChanged,

View File

@ -1,11 +1,11 @@
#include "MainWindow.h" #include "MainWindow.h"
#include "ColorHelper.hpp"
#include <QGuiApplication> #include <QGuiApplication>
#include <QtWidgets/QApplication> #include <QtWidgets/QApplication>
#include <FramelessHelper/Core/private/framelessconfig_p.h> #include <FramelessHelper/Core/private/framelessconfig_p.h>
#include <iostream> #include <iostream>
#include <format> #include <format>
#include "consoleapi2.h" #include "consoleapi2.h"
#include <lib/qtmaterialstyle.h>
extern "C" extern "C"
{ {
@ -51,9 +51,7 @@ int main(int argc, char* argv[])
QApplication::setHighDpiScaleFactorRoundingPolicy(Qt::HighDpiScaleFactorRoundingPolicy::PassThrough); QApplication::setHighDpiScaleFactorRoundingPolicy(Qt::HighDpiScaleFactorRoundingPolicy::PassThrough);
QApplication a(argc, argv); QApplication a(argc, argv);
Q_INIT_RESOURCE(resources); Q_INIT_RESOURCE(resources);
QtMaterialTheme theme; ColorHelper::instance();
theme.setColor("primary1", QColor(0, 90, 158));
QtMaterialStyle::instance().setTheme(&theme);
//FramelessHelper::Core::setApplicationOSThemeAware(); //FramelessHelper::Core::setApplicationOSThemeAware();
FramelessConfig::instance()->set(Global::Option::ForceNonNativeBackgroundBlur); FramelessConfig::instance()->set(Global::Option::ForceNonNativeBackgroundBlur);
//FramelessConfig::instance()->set(Global::Option::EnableBlurBehindWindow); //FramelessConfig::instance()->set(Global::Option::EnableBlurBehindWindow);

View File

@ -42,17 +42,38 @@ namespace UnitTest
{ {
virtual std::vector<Renderer::BaseStyle> toBaseStyles() const override virtual std::vector<Renderer::BaseStyle> toBaseStyles() const override
{ {
return { BaseStyle(std::make_shared<TransformStyle>(), return { BaseStyle(std::make_shared<TransformStyle>(),
std::make_shared<MaterialStyleFill>( std::make_shared<MaterialStyleFill>(std::make_shared<FillPlain>(Material(QColor(255,255,0))))) };
std::make_shared<FillPlain>(Material(QColor(255,255,0))))) }; }
} style;
TestGLWidget w(style, path);
w.show();
a.exec();
}
TEST_METHOD(TestFillPlainAndStrokeRadialGradient)
{
QApplication a(argc, argv);
class Style : public Renderer::ElementStyle
{
virtual std::vector<Renderer::BaseStyle> toBaseStyles() const override
{
std::map<float, Material> materialMap = {
{0.20, Material{QColor(255,255,255)}},
{0.60, Material{QColor(165,176,207)}},
{1.00, Material{QColor(58,64,151)}}
};
return { BaseStyle(std::make_shared<TransformStyle>(),
std::make_shared<MaterialStyleFill>(
std::make_shared<FillPlain>(Material(QColor(255,255,0))))),
BaseStyle(std::make_shared<TransformStyle>(),
std::make_shared<MaterialStyleStroke>(10, StrokeType::kBothSides, StrokeEndType::kRound,
std::make_shared<StrokeRadialGradient>(materialMap, false))) };
} }
} style; } style;
TestGLWidget w(style, path); TestGLWidget w(style, path);
w.show(); w.show();
a.exec(); a.exec();
} }
}; };
TEST_CLASS(ElementRendererStokeTypeTest) TEST_CLASS(ElementRendererStokeTypeTest)

View File

@ -122,20 +122,6 @@ namespace UnitTest
}; };
TEST_CLASS(PaintingUtilTest) TEST_CLASS(PaintingUtilTest)
{ {
TEST_METHOD(TransfromTest)
{
qInstallMessageHandler(messageHandler);
QPainterPath path;
path.addRect(0, 0, 20, 20);
QTransform trans;
qDebug() << path.boundingRect();
//qDebug() << trans;
//qDebug() << acos(-0.707107);
glm::vec2 scale;
float rotate;
PaintingUtil::decomposeTransform(trans, rotate, scale);
qDebug() << rotate;
qDebug() << scale.x << scale.y;
}
}; };
} }

View File

@ -24,7 +24,7 @@
} }
], ],
"height": 1080, "height": 1080,
"project-name": "", "project-name": "ÑùÀý1",
"root-layer": { "root-layer": {
"children": [ "children": [
{ {
@ -36,7 +36,7 @@
"styles": [ "styles": [
{ {
"enableEachSideIndependent": false, "enableEachSideIndependent": false,
"left": "AACgQAEAIZwAf///AAAA/w==", "left": "AAAAQAEAIZwAf///qqr//w==",
"right": "AADgQAAACJw=", "right": "AADgQAAACJw=",
"type": "stroke" "type": "stroke"
} }
@ -52,6 +52,30 @@
"y": 1 "y": 1
} }
} }
},
{
"element": 0,
"is-folder": false,
"name": "Leaf2",
"styles": [
{
"enableEachSideIndependent": true,
"left": "AAAAQAEAIZwAf////1UA/w==",
"right": "AADgQAAACJw=",
"type": "stroke"
}
],
"transform": {
"offset": {
"x": 150,
"y": 0
},
"rotation": 0,
"scale": {
"x": 1.5,
"y": 1.5
}
}
} }
], ],
"is-folder": true, "is-folder": true,
@ -68,6 +92,24 @@
"y": 1 "y": 1
} }
} }
},
{
"element": 1,
"is-folder": false,
"name": "ReferencingGroupLayer",
"styles": [
],
"transform": {
"offset": {
"x": 100,
"y": 0
},
"rotation": 45,
"scale": {
"x": 1,
"y": 1
}
}
} }
], ],
"is-folder": true, "is-folder": true,