diff --git a/application/application.pro b/application/application.pro index 8ae07979..1ce13119 100644 --- a/application/application.pro +++ b/application/application.pro @@ -95,6 +95,8 @@ include(third_party/QtAwesome/QtAwesome/QtAwesome.pri) HEADERS += sources/about_widget.h SOURCES += sources/about_widget.cc +HEADERS += sources/bone_list_model.h +SOURCES += sources/bone_list_model.cc HEADERS += sources/ccd_ik_resolver.h SOURCES += sources/ccd_ik_resolver.cc HEADERS += sources/component_list_model.h diff --git a/application/sources/bone_list_model.cc b/application/sources/bone_list_model.cc new file mode 100644 index 00000000..0b243ce6 --- /dev/null +++ b/application/sources/bone_list_model.cc @@ -0,0 +1,103 @@ +#include "bone_list_model.h" +#include +#include + +BoneListModel::BoneListModel(const Document* document, QObject* parent) + : QAbstractListModel(parent) + , m_document(document) +{ + connect(m_document, &Document::bonePreviewPixmapChanged, [this](const dust3d::Uuid& boneId) { + auto findIndex = this->m_boneIdToIndexMap.find(boneId); + if (findIndex != this->m_boneIdToIndexMap.end()) { + emit this->dataChanged(findIndex->second, findIndex->second); + } + }); + connect(m_document, &Document::cleanup, this, &BoneListModel::reload); + connect(m_document, &Document::boneIdListChanged, this, &BoneListModel::reload); +} + +void BoneListModel::reload() +{ + beginResetModel(); + m_boneIdToIndexMap.clear(); + for (int i = 0; i < (int)m_document->boneIdList.size(); ++i) { + m_boneIdToIndexMap[m_document->boneIdList[i]] = createIndex(i, 0); + } + endResetModel(); + emit layoutChanged(); +} + +QModelIndex BoneListModel::boneIdToIndex(const dust3d::Uuid& boneId) const +{ + auto findIndex = m_boneIdToIndexMap.find(boneId); + if (findIndex == m_boneIdToIndexMap.end()) + return QModelIndex(); + return findIndex->second; +} + +int BoneListModel::rowCount(const QModelIndex& parent) const +{ + if (parent.isValid()) + return 0; + return (int)m_document->boneIdList.size(); +} + +int BoneListModel::columnCount(const QModelIndex& parent) const +{ + if (parent.isValid()) + return 0; + return 1; +} + +const Document::Bone* BoneListModel::modelIndexToBone(const QModelIndex& index) const +{ + if (index.row() >= (int)m_document->boneIdList.size()) { + dust3dDebug << "Bone list row is out of range, size:" << m_document->boneIdList.size() << "row:" << index.row(); + return nullptr; + } + const auto& boneId = m_document->boneIdList[index.row()]; + const Document::Bone* bone = m_document->findBone(boneId); + if (nullptr == bone) { + dust3dDebug << "Bone not found:" << boneId.toString(); + return nullptr; + } + return bone; +} + +const dust3d::Uuid BoneListModel::modelIndexToBoneId(const QModelIndex& index) const +{ + if (index.row() >= (int)m_document->boneIdList.size()) { + dust3dDebug << "Bone list row is out of range, size:" << m_document->boneIdList.size() << "row:" << index.row(); + return dust3d::Uuid(); + } + const auto& boneId = m_document->boneIdList[index.row()]; + return boneId; +} + +QVariant BoneListModel::data(const QModelIndex& index, int role) const +{ + switch (role) { + case Qt::ToolTipRole: { + const Document::Bone* bone = modelIndexToBone(index); + if (nullptr != bone) { + return bone->name; + } + } break; + case Qt::DecorationRole: { + const Document::Bone* bone = modelIndexToBone(index); + if (nullptr != bone) { + if (0 == bone->previewPixmap.width()) { + static QPixmap s_emptyPixmap; + if (0 == s_emptyPixmap.width()) { + QImage image((int)Theme::partPreviewImageSize, (int)Theme::partPreviewImageSize, QImage::Format_ARGB32); + image.fill(Qt::transparent); + s_emptyPixmap = QPixmap::fromImage(image); + } + return s_emptyPixmap; + } + return bone->previewPixmap; + } + } break; + } + return QVariant(); +} diff --git a/application/sources/bone_list_model.h b/application/sources/bone_list_model.h new file mode 100644 index 00000000..ec843fe9 --- /dev/null +++ b/application/sources/bone_list_model.h @@ -0,0 +1,28 @@ +#ifndef DUST3D_APPLICATION_BONE_LIST_MODEL_H_ +#define DUST3D_APPLICATION_BONE_LIST_MODEL_H_ + +#include "document.h" +#include +#include +#include + +class BoneListModel : public QAbstractListModel { + Q_OBJECT + +public: + BoneListModel(const Document* document, QObject* parent = nullptr); + int rowCount(const QModelIndex& parent = QModelIndex()) const; + int columnCount(const QModelIndex& parent = QModelIndex()) const; + QVariant data(const QModelIndex& index, int role) const; + const Document::Bone* modelIndexToBone(const QModelIndex& index) const; + QModelIndex boneIdToIndex(const dust3d::Uuid& boneId) const; + const dust3d::Uuid modelIndexToBoneId(const QModelIndex& index) const; +public slots: + void reload(); + +private: + const Document* m_document = nullptr; + std::unordered_map m_boneIdToIndexMap; +}; + +#endif diff --git a/application/sources/document.cc b/application/sources/document.cc index 32bd932d..2433f948 100644 --- a/application/sources/document.cc +++ b/application/sources/document.cc @@ -2855,6 +2855,7 @@ void Document::addBone(const dust3d::Uuid& boneId) boneMap.emplace(boneId, bone); boneIdList.push_back(boneId); emit boneAdded(boneId); + emit boneIdListChanged(); emit rigChanged(); } @@ -2893,6 +2894,7 @@ void Document::removeBone(const dust3d::Uuid& boneId) boneIdList.erase(std::remove(boneIdList.begin(), boneIdList.end(), boneId), boneIdList.end()); boneMap.erase(boneId); emit boneRemoved(boneId); + emit boneIdListChanged(); emit rigChanged(); } @@ -2920,3 +2922,11 @@ void Document::renameBone(const dust3d::Uuid& boneId, const QString& name) emit boneNameChanged(boneId); emit rigChanged(); } + +const Document::Bone* Document::findBone(const dust3d::Uuid& boneId) const +{ + auto boneIt = boneMap.find(boneId); + if (boneIt == boneMap.end()) + return nullptr; + return &boneIt->second; +} diff --git a/application/sources/document.h b/application/sources/document.h index fb68d9cf..6a1a49cd 100644 --- a/application/sources/document.h +++ b/application/sources/document.h @@ -564,6 +564,7 @@ public: dust3d::Uuid attachBoneId; int attachBoneJointIndex = 0; QString name; + QPixmap previewPixmap; Bone(const dust3d::Uuid& withId = dust3d::Uuid()); }; @@ -643,6 +644,8 @@ signals: void boneAttachmentChanged(const dust3d::Uuid& boneId); void boneNodesChanged(const dust3d::Uuid& boneId); void boneNameChanged(const dust3d::Uuid& boneId); + void bonePreviewPixmapChanged(const dust3d::Uuid& boneId); + void boneIdListChanged(); void rigChanged(); public: // need initialize @@ -769,6 +772,7 @@ public: void setComponentPreviewImage(const dust3d::Uuid& componentId, std::unique_ptr image); void resetDirtyFlags(); void markAllDirty(); + const Bone* findBone(const dust3d::Uuid& boneId) const; public slots: void undo();