diff --git a/application/sources/component_property_widget.cc b/application/sources/component_property_widget.cc index 5c8d72b4..901d114c 100644 --- a/application/sources/component_property_widget.cc +++ b/application/sources/component_property_widget.cc @@ -1,8 +1,11 @@ #include "component_property_widget.h" #include "document.h" #include "float_number_widget.h" +#include "image_forever.h" +#include "image_preview_widget.h" #include "theme.h" #include +#include #include #include #include @@ -188,29 +191,67 @@ ComponentPropertyWidget::ComponentPropertyWidget(Document* document, cutFaceGroupBox->setLayout(cutFaceLayout); } - QGroupBox* skinGroupBox = nullptr; + QGroupBox* colorImageGroupBox = nullptr; if (nullptr != m_part) { - QCheckBox* useImageBox = new QCheckBox(); - Theme::initCheckbox(useImageBox); - useImageBox->setText(tr("Use image")); - useImageBox->setChecked(m_part->rounded); + ImagePreviewWidget* colorImagePreviewWidget = new ImagePreviewWidget; + colorImagePreviewWidget->setFixedSize(Theme::partPreviewImageSize * 2, Theme::partPreviewImageSize * 2); + colorImagePreviewWidget->updateImage(m_part->colorImageId.isNull() ? QImage() : *ImageForever::get(m_part->colorImageId)); + connect(m_document, &Document::partColorImageChanged, this, [=]() { + auto part = m_document->findPart(m_partId); + if (nullptr == part) + return; + colorImagePreviewWidget->updateImage(part->colorImageId.isNull() ? QImage() : *ImageForever::get(part->colorImageId)); + }); + + QPushButton* colorImageEraser = new QPushButton(QChar(fa::eraser)); + Theme::initIconButton(colorImageEraser); + + connect(colorImageEraser, &QPushButton::clicked, [=]() { + emit setPartColorImage(m_partId, dust3d::Uuid()); + emit groupOperationAdded(); + }); + + QPushButton* colorImagePicker = new QPushButton(QChar(fa::image)); + Theme::initIconButton(colorImagePicker); + + connect(colorImagePicker, &QPushButton::clicked, [=]() { + QImage* image = pickImage(); + if (nullptr == image) + return; + auto imageId = ImageForever::add(image); + delete image; + emit setPartColorImage(m_partId, imageId); + emit groupOperationAdded(); + }); + + QHBoxLayout* colorImageToolsLayout = new QHBoxLayout; + colorImageToolsLayout->addWidget(colorImageEraser); + colorImageToolsLayout->addWidget(colorImagePicker); + colorImageToolsLayout->addStretch(); + + QVBoxLayout* colorImageLayout = new QVBoxLayout; + colorImageLayout->addWidget(colorImagePreviewWidget); + colorImageLayout->addLayout(colorImageToolsLayout); QHBoxLayout* skinLayout = new QHBoxLayout; + skinLayout->addLayout(colorImageLayout); skinLayout->addStretch(); - skinLayout->addWidget(useImageBox); - skinGroupBox = new QGroupBox(tr("Skin")); - skinGroupBox->setLayout(skinLayout); + colorImageGroupBox = new QGroupBox(tr("Color")); + colorImageGroupBox->setLayout(skinLayout); } + QHBoxLayout* skinLayout = new QHBoxLayout; + if (nullptr != colorImageGroupBox) + skinLayout->addWidget(colorImageGroupBox); + QVBoxLayout* mainLayout = new QVBoxLayout; mainLayout->addLayout(colorLayout); if (nullptr != deformGroupBox) mainLayout->addWidget(deformGroupBox); if (nullptr != cutFaceGroupBox) mainLayout->addWidget(cutFaceGroupBox); - if (nullptr != skinGroupBox) - mainLayout->addWidget(skinGroupBox); + mainLayout->addLayout(skinLayout); mainLayout->setSizeConstraint(QLayout::SetFixedSize); connect(this, &ComponentPropertyWidget::setPartColorState, m_document, &Document::setPartColorState); @@ -223,6 +264,7 @@ ComponentPropertyWidget::ComponentPropertyWidget(Document* document, connect(this, &ComponentPropertyWidget::setPartSubdivState, m_document, &Document::setPartSubdivState); connect(this, &ComponentPropertyWidget::setPartChamferState, m_document, &Document::setPartChamferState); connect(this, &ComponentPropertyWidget::setPartRoundState, m_document, &Document::setPartRoundState); + connect(this, &ComponentPropertyWidget::setPartColorImage, m_document, &Document::setPartColorImage); connect(this, &ComponentPropertyWidget::groupOperationAdded, m_document, &Document::saveSnapshot); setLayout(mainLayout); @@ -230,6 +272,19 @@ ComponentPropertyWidget::ComponentPropertyWidget(Document* document, setFixedSize(minimumSizeHint()); } +QImage* ComponentPropertyWidget::pickImage() +{ + QString fileName = QFileDialog::getOpenFileName(this, QString(), QString(), + tr("Image Files (*.png *.jpg *.bmp)")) + .trimmed(); + if (fileName.isEmpty()) + return nullptr; + QImage* image = new QImage(); + if (!image->load(fileName)) + return nullptr; + return image; +} + void ComponentPropertyWidget::preparePartIds() { std::unordered_set addedPartIdSet; diff --git a/application/sources/component_property_widget.h b/application/sources/component_property_widget.h index e226a0d9..e49fdaf4 100644 --- a/application/sources/component_property_widget.h +++ b/application/sources/component_property_widget.h @@ -20,6 +20,7 @@ signals: void setPartChamferState(const dust3d::Uuid& partId, bool chamfered); void setPartRoundState(const dust3d::Uuid& partId, bool rounded); void setPartCutRotation(const dust3d::Uuid& partId, float cutRotation); + void setPartColorImage(const dust3d::Uuid& partId, const dust3d::Uuid& imageId); void groupOperationAdded(); public: @@ -38,6 +39,7 @@ private: QColor m_color; QColor lastColor(); void preparePartIds(); + QImage* pickImage(); }; #endif diff --git a/application/sources/document.cc b/application/sources/document.cc index 7d38c4f9..d46f9089 100644 --- a/application/sources/document.cc +++ b/application/sources/document.cc @@ -1615,6 +1615,9 @@ void Document::toSnapshot(dust3d::Snapshot* snapshot, const std::setsecond); + } if (dust3d::String::isTrue(dust3d::String::valueOrEmpty(partKv.second, "inverse"))) inversePartIds.insert(part.id); const auto& colorIt = partKv.second.find("color"); diff --git a/application/sources/document_saver.cc b/application/sources/document_saver.cc index 07e41054..1a7aebba 100644 --- a/application/sources/document_saver.cc +++ b/application/sources/document_saver.cc @@ -32,6 +32,13 @@ void DocumentSaver::process() void DocumentSaver::collectUsedResourceIds(const dust3d::Snapshot* snapshot, std::set& imageIds) { + for (const auto& part : snapshot->parts) { + auto findImageIdString = part.second.find("colorImageId"); + if (findImageIdString == part.second.end()) + continue; + dust3d::Uuid imageId = dust3d::Uuid(findImageIdString->second); + imageIds.insert(imageId); + } for (const auto& material : snapshot->materials) { for (auto& layer : material.second) { for (auto& mapItem : layer.second) {