From ab97615bea794cf974ef0df753ab7aeb90219cd2 Mon Sep 17 00:00:00 2001 From: huxingyi Date: Wed, 14 Nov 2018 21:21:45 +0800 Subject: [PATCH] Add "combineMode" configuration for component to replace the "inverse" attribute Currently, only support "Normal" and "Inversion" modes, "Normal" means normal mesh union, "Inversion" means mesh diff, it behaves like subtract itself from the previous mesh. --- dust3d.pro | 3 +++ src/combinemode.cpp | 6 ++++++ src/combinemode.h | 49 ++++++++++++++++++++++++++++++++++++++++++ src/document.cpp | 18 ++++++++++------ src/document.h | 7 +++--- src/documentwindow.cpp | 4 ++-- src/meshgenerator.cpp | 3 ++- src/parttreewidget.cpp | 41 ++++++++++++++++++++++++++++------- src/parttreewidget.h | 4 ++-- src/partwidget.cpp | 12 +++++------ src/partwidget.h | 4 ++-- src/theme.cpp | 4 ++-- src/theme.h | 2 +- 13 files changed, 123 insertions(+), 34 deletions(-) create mode 100644 src/combinemode.cpp create mode 100644 src/combinemode.h diff --git a/dust3d.pro b/dust3d.pro index 9d82921f..1a2cf6cc 100644 --- a/dust3d.pro +++ b/dust3d.pro @@ -291,6 +291,9 @@ HEADERS += src/skeletondocument.h SOURCES += src/posedocument.cpp HEADERS += src/posedocument.h +SOURCES += src/combinemode.cpp +HEADERS += src/combinemode.h + SOURCES += src/main.cpp HEADERS += src/version.h diff --git a/src/combinemode.cpp b/src/combinemode.cpp new file mode 100644 index 00000000..4087cdd5 --- /dev/null +++ b/src/combinemode.cpp @@ -0,0 +1,6 @@ +#include +#include "combinemode.h" + +IMPL_CombineModeToString +IMPL_CombineModeFromString +IMPL_CombineModeToDispName diff --git a/src/combinemode.h b/src/combinemode.h new file mode 100644 index 00000000..95ff2a52 --- /dev/null +++ b/src/combinemode.h @@ -0,0 +1,49 @@ +#ifndef DUST3D_COMBINE_MODE_H +#define DUST3D_COMBINE_MODE_H +#include + +enum class CombineMode +{ + Normal = 0, + Inversion, + Count +}; +CombineMode CombineModeFromString(const char *modeString); +#define IMPL_CombineModeFromString \ +CombineMode CombineModeFromString(const char *modeString) \ +{ \ + QString mode = modeString; \ + if (mode == "Normal") \ + return CombineMode::Normal; \ + if (mode == "Inversion") \ + return CombineMode::Inversion; \ + return CombineMode::Normal; \ +} +const char *CombineModeToString(CombineMode mode); +#define IMPL_CombineModeToString \ +const char *CombineModeToString(CombineMode mode) \ +{ \ + switch (mode) { \ + case CombineMode::Normal: \ + return "Normal"; \ + case CombineMode::Inversion: \ + return "Inversion"; \ + default: \ + return "Normal"; \ + } \ +} +QString CombineModeToDispName(CombineMode mode); +#define IMPL_CombineModeToDispName \ +QString CombineModeToDispName(CombineMode mode) \ +{ \ + switch (mode) { \ + case CombineMode::Normal: \ + return QObject::tr("Normal"); \ + case CombineMode::Inversion: \ + return QObject::tr("Inversion"); \ + default: \ + return QObject::tr("Normal"); \ + } \ +} + +#endif diff --git a/src/document.cpp b/src/document.cpp index e1175b4c..dd6402f8 100644 --- a/src/document.cpp +++ b/src/document.cpp @@ -903,7 +903,7 @@ void Document::toSnapshot(Snapshot *snapshot, const std::set &limitNodeId if (!componentIt.second.name.isEmpty()) component["name"] = componentIt.second.name; component["expanded"] = componentIt.second.expanded ? "true" : "false"; - component["inverse"] = componentIt.second.inverse ? "true" : "false"; + component["combineMode"] = CombineModeToString(componentIt.second.combineMode); component["dirty"] = componentIt.second.dirty ? "true" : "false"; if (componentIt.second.smoothAllAdjusted()) component["smoothAll"] = QString::number(componentIt.second.smoothAll); @@ -1178,7 +1178,11 @@ void Document::addFromSnapshot(const Snapshot &snapshot, bool fromPaste) oldNewIdMap[QUuid(componentKv.first)] = component.id; component.name = valueOfKeyInMapOrEmpty(componentKv.second, "name"); component.expanded = isTrueValueString(valueOfKeyInMapOrEmpty(componentKv.second, "expanded")); - component.inverse = isTrueValueString(valueOfKeyInMapOrEmpty(componentKv.second, "inverse")); + component.combineMode = CombineModeFromString(valueOfKeyInMapOrEmpty(componentKv.second, "combineMode").toUtf8().constData()); + if (component.combineMode == CombineMode::Normal) { + if (isTrueValueString(valueOfKeyInMapOrEmpty(componentKv.second, "inverse"))) + component.combineMode = CombineMode::Inversion; + } const auto &smoothAllIt = componentKv.second.find("smoothAll"); if (smoothAllIt != componentKv.second.end()) component.setSmoothAll(smoothAllIt->second.toFloat()); @@ -1192,7 +1196,7 @@ void Document::addFromSnapshot(const Snapshot &snapshot, bool fromPaste) //qDebug() << "Add part:" << partId << " from component:" << component.id; partMap[partId].componentId = component.id; if (inversePartIds.find(partId) != inversePartIds.end()) - component.inverse = true; + component.combineMode = CombineMode::Inversion; } componentMap[component.id] = component; newAddedComponentIds.insert(component.id); @@ -1609,18 +1613,18 @@ void Document::setPartVisibleState(QUuid partId, bool visible) emit optionsChanged(); } -void Document::setComponentInverseState(QUuid componentId, bool inverse) +void Document::setComponentCombineMode(QUuid componentId, CombineMode combineMode) { auto component = componentMap.find(componentId); if (component == componentMap.end()) { qDebug() << "Component not found:" << componentId; return; } - if (component->second.inverse == inverse) + if (component->second.combineMode == combineMode) return; - component->second.inverse = inverse; + component->second.combineMode = combineMode; component->second.dirty = true; - emit componentInverseStateChanged(componentId); + emit componentCombineModeChanged(componentId); emit skeletonChanged(); } diff --git a/src/document.h b/src/document.h index 18bebe03..85611898 100644 --- a/src/document.h +++ b/src/document.h @@ -24,6 +24,7 @@ #include "interpolationtype.h" #include "jointnodetree.h" #include "skeletondocument.h" +#include "combinemode.h" class MaterialPreviewsGenerator; class MotionsGenerator; @@ -55,7 +56,7 @@ public: QUuid linkToPartId; QUuid parentId; bool expanded = true; - bool inverse = false; + CombineMode combineMode = CombineMode::Normal; bool dirty = true; float smoothAll = 0.0; float smoothSeam = 0.0; @@ -401,7 +402,7 @@ signals: void partColorStateChanged(QUuid partId); void partWrapStateChanged(QUuid partId); void partMaterialIdChanged(QUuid partId); - void componentInverseStateChanged(QUuid partId); + void componentCombineModeChanged(QUuid componentId); void cleanup(); void originChanged(); void xlockStateChanged(); @@ -549,7 +550,7 @@ public slots: void setPartColorState(QUuid partId, bool hasColor, QColor color); void setPartWrapState(QUuid partId, bool wrapped); void setPartMaterialId(QUuid partId, QUuid materialId); - void setComponentInverseState(QUuid componentId, bool inverse); + void setComponentCombineMode(QUuid componentId, CombineMode combineMode); void moveComponentUp(QUuid componentId); void moveComponentDown(QUuid componentId); void moveComponentToTop(QUuid componentId); diff --git a/src/documentwindow.cpp b/src/documentwindow.cpp index 934dfb94..21074683 100644 --- a/src/documentwindow.cpp +++ b/src/documentwindow.cpp @@ -783,7 +783,7 @@ DocumentWindow::DocumentWindow() : connect(partTreeWidget, &PartTreeWidget::unlockAllComponents, m_document, &Document::unlockAllComponents); connect(partTreeWidget, &PartTreeWidget::setPartLockState, m_document, &Document::setPartLockState); connect(partTreeWidget, &PartTreeWidget::setPartVisibleState, m_document, &Document::setPartVisibleState); - connect(partTreeWidget, &PartTreeWidget::setComponentInverseState, m_document, &Document::setComponentInverseState); + connect(partTreeWidget, &PartTreeWidget::setComponentCombineMode, m_document, &Document::setComponentCombineMode); connect(partTreeWidget, &PartTreeWidget::hideDescendantComponents, m_document, &Document::hideDescendantComponents); connect(partTreeWidget, &PartTreeWidget::showDescendantComponents, m_document, &Document::showDescendantComponents); connect(partTreeWidget, &PartTreeWidget::lockDescendantComponents, m_document, &Document::lockDescendantComponents); @@ -796,7 +796,7 @@ DocumentWindow::DocumentWindow() : connect(m_document, &Document::componentRemoved, partTreeWidget, &PartTreeWidget::componentRemoved); connect(m_document, &Document::componentAdded, partTreeWidget, &PartTreeWidget::componentAdded); connect(m_document, &Document::componentExpandStateChanged, partTreeWidget, &PartTreeWidget::componentExpandStateChanged); - connect(m_document, &Document::componentInverseStateChanged, partTreeWidget, &PartTreeWidget::componentInverseStateChanged); + connect(m_document, &Document::componentCombineModeChanged, partTreeWidget, &PartTreeWidget::componentCombineModeChanged); connect(m_document, &Document::partPreviewChanged, partTreeWidget, &PartTreeWidget::partPreviewChanged); connect(m_document, &Document::partLockStateChanged, partTreeWidget, &PartTreeWidget::partLockStateChanged); connect(m_document, &Document::partVisibleStateChanged, partTreeWidget, &PartTreeWidget::partVisibleStateChanged); diff --git a/src/meshgenerator.cpp b/src/meshgenerator.cpp index f7824b4d..d7727e65 100644 --- a/src/meshgenerator.cpp +++ b/src/meshgenerator.cpp @@ -516,7 +516,8 @@ void *MeshGenerator::combineComponentMesh(QString componentId, bool *inverse) component = &findComponent->second; } - if (isTrueValueString(valueOfKeyInMapOrEmpty(*component, "inverse"))) + CombineMode combineMode = CombineModeFromString(valueOfKeyInMapOrEmpty(*component, "combineMode").toUtf8().constData()); + if (combineMode == CombineMode::Inversion) *inverse = true; if (m_dirtyComponentIds.find(componentId) == m_dirtyComponentIds.end()) { diff --git a/src/parttreewidget.cpp b/src/parttreewidget.cpp index 0d450e3f..daa1afc9 100644 --- a/src/parttreewidget.cpp +++ b/src/parttreewidget.cpp @@ -6,6 +6,7 @@ #include #include #include +#include #include "parttreewidget.h" #include "partwidget.h" #include "skeletongraphicswidget.h" @@ -119,8 +120,8 @@ void PartTreeWidget::updateComponentSelectState(QUuid componentId, bool selected auto item = m_partItemMap.find(component->linkToPartId); if (item != m_componentItemMap.end()) { PartWidget *widget = (PartWidget *)itemWidget(item->second, 0); - // Inverse state updating call should be called before check state updating call - widget->updateInverseState(component->inverse); + // Unnormal state updating call should be called before check state updating call + widget->updateUnnormalState(component->combineMode != CombineMode::Normal); widget->updateCheckedState(selected); } return; @@ -128,7 +129,7 @@ void PartTreeWidget::updateComponentSelectState(QUuid componentId, bool selected auto item = m_componentItemMap.find(componentId); if (item != m_componentItemMap.end()) { item->second->setFont(0, selected ? m_selectedFont : m_normalFont); - if (component->inverse) + if (component->combineMode != CombineMode::Normal) item->second->setForeground(0, selected ? QBrush(Theme::blue) : QBrush(Theme::blue)); else item->second->setForeground(0, selected ? QBrush(Theme::red) : QBrush(Theme::white)); @@ -259,7 +260,7 @@ void PartTreeWidget::showContextMenu(const QPoint &pos) } else { QLabel *previewLabel = new QLabel; previewLabel->setFixedHeight(Theme::partPreviewImageSize); - previewLabel->setStyleSheet("QLabel {color: " + (component && component->inverse ? Theme::blue.name() : Theme::red.name()) + "}"); + previewLabel->setStyleSheet("QLabel {color: " + (component && (component->combineMode != CombineMode::Normal) ? Theme::blue.name() : Theme::red.name()) + "}"); if (nullptr != component) { previewLabel->setText(component->name); } else if (!componentIds.empty()) { @@ -268,7 +269,31 @@ void PartTreeWidget::showContextMenu(const QPoint &pos) layout->addWidget(previewLabel); } QWidget *widget = new QWidget; - widget->setLayout(layout); + if (nullptr != component) { + QComboBox *combineModeSelectBox = new QComboBox; + for (size_t i = 0; i < (size_t)CombineMode::Count; ++i) { + CombineMode mode = (CombineMode)i; + combineModeSelectBox->addItem(CombineModeToDispName(mode)); + } + combineModeSelectBox->setCurrentIndex((int)component->combineMode); + + connect(combineModeSelectBox, static_cast(&QComboBox::currentIndexChanged), this, [=](int index) { + emit setComponentCombineMode(component->id, (CombineMode)index); + }); + + QHBoxLayout *combineModeLayout = new QHBoxLayout; + combineModeLayout->setAlignment(Qt::AlignCenter); + combineModeLayout->setContentsMargins(0, 0, 0, 0); + combineModeLayout->setSpacing(0); + combineModeLayout->addWidget(combineModeSelectBox); + + QVBoxLayout *newLayout = new QVBoxLayout; + newLayout->addLayout(layout); + newLayout->addLayout(combineModeLayout); + widget->setLayout(newLayout); + } else { + widget->setLayout(layout); + } forDisplayPartImage.setDefaultWidget(widget); if (!componentIds.empty()) { contextMenu.addAction(&forDisplayPartImage); @@ -283,8 +308,6 @@ void PartTreeWidget::showContextMenu(const QPoint &pos) lockAction.setIcon(Theme::awesome()->icon(fa::lock)); QAction unlockAction(tr("Unlock"), this); unlockAction.setIcon(Theme::awesome()->icon(fa::unlock)); - QAction invertAction(tr("Invert"), this); - QAction cancelInverseAction(tr("Cancel Inverse"), this); QAction selectAction(tr("Select"), this); if (nullptr != component && nullptr != part) { @@ -353,6 +376,7 @@ void PartTreeWidget::showContextMenu(const QPoint &pos) contextMenu.addAction(&unlockAction); } + /* if (component && !component->inverse) { connect(&invertAction, &QAction::triggered, [=]() { emit setComponentInverseState(component->id, true); @@ -366,6 +390,7 @@ void PartTreeWidget::showContextMenu(const QPoint &pos) }); contextMenu.addAction(&cancelInverseAction); } + */ contextMenu.addSeparator(); @@ -655,7 +680,7 @@ void PartTreeWidget::componentExpandStateChanged(QUuid componentId) componentItem->second->setExpanded(component->expanded); } -void PartTreeWidget::componentInverseStateChanged(QUuid componentId) +void PartTreeWidget::componentCombineModeChanged(QUuid componentId) { updateComponentAppearance(componentId); } diff --git a/src/parttreewidget.h b/src/parttreewidget.h index a03486a3..7471b97a 100644 --- a/src/parttreewidget.h +++ b/src/parttreewidget.h @@ -33,7 +33,7 @@ signals: void unlockAllComponents(); void setPartLockState(QUuid partId, bool locked); void setPartVisibleState(QUuid partId, bool visible); - void setComponentInverseState(QUuid componentId, bool inverse); + void setComponentCombineMode(QUuid componentId, CombineMode combineMode); void hideDescendantComponents(QUuid componentId); void showDescendantComponents(QUuid componentId); void lockDescendantComponents(QUuid componentId); @@ -49,7 +49,7 @@ public slots: void componentRemoved(QUuid componentId); void componentAdded(QUuid componentId); void componentExpandStateChanged(QUuid componentId); - void componentInverseStateChanged(QUuid componentId); + void componentCombineModeChanged(QUuid componentId); void partRemoved(QUuid partId); void partPreviewChanged(QUuid partid); void partLockStateChanged(QUuid partId); diff --git a/src/partwidget.cpp b/src/partwidget.cpp index 85bf5ce3..b6a3e9f7 100644 --- a/src/partwidget.cpp +++ b/src/partwidget.cpp @@ -15,7 +15,7 @@ PartWidget::PartWidget(const Document *document, QUuid partId) : m_document(document), m_partId(partId), - m_inverted(false) + m_unnormal(false) { QSizePolicy retainSizePolicy = sizePolicy(); retainSizePolicy.setRetainSizeWhenHidden(true); @@ -263,17 +263,17 @@ void PartWidget::updateAllButtons() void PartWidget::updateCheckedState(bool checked) { if (checked) - m_backgroundWidget->setStyleSheet("QWidget#background {border: 1px solid " + (m_inverted ? Theme::blue.name() : Theme::red.name()) + ";}"); + m_backgroundWidget->setStyleSheet("QWidget#background {border: 1px solid " + (m_unnormal ? Theme::blue.name() : Theme::red.name()) + ";}"); else m_backgroundWidget->setStyleSheet("QWidget#background {border: 1px solid transparent;}"); } -void PartWidget::updateInverseState(bool inverse) +void PartWidget::updateUnnormalState(bool unnormal) { - if (m_inverted == inverse) + if (m_unnormal == unnormal) return; - m_inverted = inverse; + m_unnormal = unnormal; updateAllButtons(); } @@ -439,7 +439,7 @@ void PartWidget::initButton(QPushButton *button) void PartWidget::updateButton(QPushButton *button, QChar icon, bool highlighted) { - Theme::updateAwesomeMiniButton(button, icon, highlighted, m_inverted); + Theme::updateAwesomeMiniButton(button, icon, highlighted, m_unnormal); } void PartWidget::updatePreview() diff --git a/src/partwidget.h b/src/partwidget.h index 15a4ef72..f6b63609 100644 --- a/src/partwidget.h +++ b/src/partwidget.h @@ -45,7 +45,7 @@ public: void updateColorButton(); void updateWrapButton(); void updateCheckedState(bool checked); - void updateInverseState(bool inverse); + void updateUnnormalState(bool unnormal); static QSize preferredSize(); ModelWidget *previewWidget(); protected: @@ -56,7 +56,7 @@ public slots: private: // need initialize const Document *m_document; QUuid m_partId; - bool m_inverted; + bool m_unnormal; private: ModelWidget *m_previewWidget; QPushButton *m_visibleButton; diff --git a/src/theme.cpp b/src/theme.cpp index 8742d9ec..9cd6d7b2 100644 --- a/src/theme.cpp +++ b/src/theme.cpp @@ -103,14 +103,14 @@ void Theme::initAwesomeMiniButton(QPushButton *button) button->setFocusPolicy(Qt::NoFocus); } -void Theme::updateAwesomeMiniButton(QPushButton *button, QChar icon, bool highlighted, bool inverted) +void Theme::updateAwesomeMiniButton(QPushButton *button, QChar icon, bool highlighted, bool unnormal) { button->setText(icon); QColor color; bool needDesaturation = true; if (highlighted) { - if (inverted) { + if (unnormal) { color = Theme::blue; needDesaturation = false; } else { diff --git a/src/theme.h b/src/theme.h index 4c68fe62..e0867f6c 100644 --- a/src/theme.h +++ b/src/theme.h @@ -47,7 +47,7 @@ public: static void initAwesomeLabel(QLabel *label); static void initAwesomeSmallButton(QPushButton *button); static void initAwesomeMiniButton(QPushButton *button); - static void updateAwesomeMiniButton(QPushButton *button, QChar icon, bool highlighted, bool inverted=false); + static void updateAwesomeMiniButton(QPushButton *button, QChar icon, bool highlighted, bool unnormal=false); static void initAwesomeToolButton(QPushButton *button); static void initAwesomeToolButtonWithoutFont(QPushButton *button); };