diff --git a/application/sources/bone_property_widget.cc b/application/sources/bone_property_widget.cc index c1eeaa24..bbd5f5e1 100644 --- a/application/sources/bone_property_widget.cc +++ b/application/sources/bone_property_widget.cc @@ -22,6 +22,38 @@ BonePropertyWidget::BonePropertyWidget(Document* document, QVBoxLayout* mainLayout = new QVBoxLayout; if (nullptr != m_bone) { + m_parentBoneComboBox = new QComboBox; + m_parentBoneComboBox->addItem(tr("None")); + + m_parentJointComboBox = new QComboBox; + m_parentJointComboBox->addItem(tr("1")); + m_parentJointComboBox->setVisible(false); + + QHBoxLayout* parentBoneAndJointLayout = new QHBoxLayout; + parentBoneAndJointLayout->addWidget(m_parentBoneComboBox); + parentBoneAndJointLayout->addWidget(m_parentJointComboBox); + + for (size_t i = 0; i < m_document->boneIdList.size(); ++i) { + const auto& boneId = m_document->boneIdList[i]; + if (boneId == m_boneId) + continue; + const Document::Bone* bone = m_document->findBone(boneId); + if (nullptr == bone) + continue; + m_parentBoneComboBox->addItem(QIcon(bone->previewPixmap), bone->name, QVariant(QString::fromStdString(boneId.toString()))); + if (m_bone->attachBoneId == boneId) + m_parentBoneComboBox->setCurrentIndex(m_parentBoneComboBox->count() - 1); + } + updateBoneJointComboBox(); + + connect(m_parentBoneComboBox, QOverload::of(&QComboBox::currentIndexChanged), this, &BonePropertyWidget::updateBoneJointComboBox); + connect(m_parentJointComboBox, QOverload::of(&QComboBox::currentIndexChanged), this, &BonePropertyWidget::synchronizeBoneAttachmentFromControls); + + QHBoxLayout* parentLayout = new QHBoxLayout; + parentLayout->addWidget(new QLabel(tr("Parent"))); + parentLayout->addLayout(parentBoneAndJointLayout); + parentLayout->addStretch(); + m_nameEdit = new QLineEdit; Theme::initLineEdit(m_nameEdit); m_nameEdit->setFixedWidth(Theme::partPreviewImageSize * 2.7); @@ -51,6 +83,7 @@ BonePropertyWidget::BonePropertyWidget(Document* document, jointsLayout->addStretch(); jointsLayout->addWidget(nodePicker); + mainLayout->addLayout(parentLayout); mainLayout->addLayout(renameLayout); mainLayout->addLayout(jointsLayout); } @@ -58,6 +91,7 @@ BonePropertyWidget::BonePropertyWidget(Document* document, mainLayout->setSizeConstraint(QLayout::SetFixedSize); connect(this, &BonePropertyWidget::renameBone, m_document, &Document::renameBone); + connect(this, &BonePropertyWidget::setBoneAttachment, m_document, &Document::setBoneAttachment); connect(this, &BonePropertyWidget::groupOperationAdded, m_document, &Document::saveSnapshot); setLayout(mainLayout); @@ -65,6 +99,35 @@ BonePropertyWidget::BonePropertyWidget(Document* document, setFixedSize(minimumSizeHint()); } +dust3d::Uuid BonePropertyWidget::editingParentBoneId() +{ + return dust3d::Uuid(m_parentBoneComboBox->currentData().toString().toStdString()); +} + +int BonePropertyWidget::editingParentJointIndex() +{ + return dust3d::String::toInt(m_parentJointComboBox->currentText().toStdString()) - 1; +} + +void BonePropertyWidget::synchronizeBoneAttachmentFromControls() +{ + if (nullptr == m_bone) + return; + + auto parentBoneId = editingParentBoneId(); + int parentJointIndex = editingParentJointIndex(); + + if (-1 == parentJointIndex) { + // The joint control is initializing, ignore + return; + } + + if (m_bone->attachBoneId == parentBoneId && parentJointIndex == m_bone->attachBoneJointIndex) + return; + + emit setBoneAttachment(m_boneId, parentBoneId, parentJointIndex); +} + void BonePropertyWidget::prepareBoneIds() { if (1 == m_boneIds.size()) { @@ -82,3 +145,29 @@ void BonePropertyWidget::nameEditChanged() emit renameBone(m_boneId, m_nameEdit->text()); emit groupOperationAdded(); } + +void BonePropertyWidget::updateBoneJointComboBox() +{ + if (nullptr == m_bone) + return; + + auto parentBoneId = editingParentBoneId(); + const Document::Bone* parentBone = m_document->findBone(parentBoneId); + if (nullptr == parentBone || parentBone->joints.size() < 2) { + if (1 == m_parentJointComboBox->count()) + return; + m_parentJointComboBox->clear(); + m_parentJointComboBox->addItem(tr("1")); + m_parentJointComboBox->setVisible(false); + synchronizeBoneAttachmentFromControls(); + return; + } + m_parentJointComboBox->clear(); + for (size_t i = 0; i < parentBone->joints.size(); ++i) { + m_parentJointComboBox->addItem(QString::number(i + 1)); + if (i == m_bone->attachBoneJointIndex) + m_parentJointComboBox->setCurrentIndex(m_parentJointComboBox->count() - 1); + } + m_parentJointComboBox->setVisible(true); + synchronizeBoneAttachmentFromControls(); +} diff --git a/application/sources/bone_property_widget.h b/application/sources/bone_property_widget.h index 57877697..35099b9c 100644 --- a/application/sources/bone_property_widget.h +++ b/application/sources/bone_property_widget.h @@ -7,6 +7,7 @@ #include class QLineEdit; +class QComboBox; class BonePropertyWidget : public QWidget { Q_OBJECT @@ -14,6 +15,7 @@ signals: void renameBone(const dust3d::Uuid& boneId, const QString& name); void groupOperationAdded(); void pickBoneJoints(const dust3d::Uuid& boneId, size_t joints); + void setBoneAttachment(const dust3d::Uuid& boneId, const dust3d::Uuid& toBoneId, int toBoneJointIndex); public: BonePropertyWidget(Document* document, @@ -21,6 +23,8 @@ public: QWidget* parent = nullptr); private slots: void nameEditChanged(); + void updateBoneJointComboBox(); + void synchronizeBoneAttachmentFromControls(); private: Document* m_document = nullptr; @@ -28,8 +32,12 @@ private: dust3d::Uuid m_boneId; const Document::Bone* m_bone = nullptr; QLineEdit* m_nameEdit = nullptr; + QComboBox* m_parentBoneComboBox = nullptr; + QComboBox* m_parentJointComboBox = nullptr; IntNumberWidget* m_jointsWidget = nullptr; void prepareBoneIds(); + dust3d::Uuid editingParentBoneId(); + int editingParentJointIndex(); }; #endif