Add parts loader and saver

master
Jeremy Hu 2018-03-14 23:22:00 +08:00
parent 5dbff8b9e3
commit 130ffdae79
12 changed files with 365 additions and 7 deletions

View File

@ -31,6 +31,9 @@ HEADERS += src/turnaroundloader.h
SOURCES += src/skeletonwidget.cpp SOURCES += src/skeletonwidget.cpp
HEADERS += src/skeletonwidget.h HEADERS += src/skeletonwidget.h
SOURCES += src/combineeditwidget.cpp
HEADERS += src/combineeditwidget.h
SOURCES += src/theme.cpp SOURCES += src/theme.cpp
HEADERS += src/theme.h HEADERS += src/theme.h

26
src/combineeditwidget.cpp Normal file
View File

@ -0,0 +1,26 @@
#include <QGridLayout>
#include "combineeditwidget.h"
CombineEditWidget::CombineEditWidget(QWidget *parent) :
QFrame(parent)
{
m_modelingWidget = new ModelingWidget(this);
QGridLayout *mainLayout = new QGridLayout;
mainLayout->addWidget(m_modelingWidget, 0, 0, 1, 1);
setLayout(mainLayout);
}
ModelingWidget *CombineEditWidget::modelingWidget()
{
return m_modelingWidget;
}
void CombineEditWidget::resizeEvent(QResizeEvent *event)
{
QFrame::resizeEvent(event);
emit sizeChanged();
}

20
src/combineeditwidget.h Normal file
View File

@ -0,0 +1,20 @@
#ifndef COMBINE_EDIT_WIDGET_H
#define COMBINE_EDIT_WIDGET_H
#include <QFrame>
#include "modelingwidget.h"
class CombineEditWidget : public QFrame
{
Q_OBJECT
signals:
void sizeChanged();
public:
CombineEditWidget(QWidget *parent = 0);
ModelingWidget *modelingWidget();
protected:
void resizeEvent(QResizeEvent *event);
private:
ModelingWidget *m_modelingWidget;
};
#endif

View File

@ -13,14 +13,14 @@ int main(int argc, char ** argv)
qApp->setStyle(QStyleFactory::create("Fusion")); qApp->setStyle(QStyleFactory::create("Fusion"));
QPalette darkPalette; QPalette darkPalette;
darkPalette.setColor(QPalette::Window, QColor(53,53,53)); darkPalette.setColor(QPalette::Window, QColor(53,53,53));
darkPalette.setColor(QPalette::WindowText, Qt::white); darkPalette.setColor(QPalette::WindowText, QColor(239,239,239));
darkPalette.setColor(QPalette::Base, QColor(25,25,25)); darkPalette.setColor(QPalette::Base, QColor(25,25,25));
darkPalette.setColor(QPalette::AlternateBase, QColor(53,53,53)); darkPalette.setColor(QPalette::AlternateBase, QColor(53,53,53));
darkPalette.setColor(QPalette::ToolTipBase, Qt::white); darkPalette.setColor(QPalette::ToolTipBase, Qt::white);
darkPalette.setColor(QPalette::ToolTipText, Qt::white); darkPalette.setColor(QPalette::ToolTipText, Qt::white);
darkPalette.setColor(QPalette::Text, Qt::white); darkPalette.setColor(QPalette::Text, Qt::white);
darkPalette.setColor(QPalette::Button, QColor(53,53,53)); darkPalette.setColor(QPalette::Button, QColor(53,53,53));
darkPalette.setColor(QPalette::ButtonText, Qt::white); darkPalette.setColor(QPalette::ButtonText, QColor(239,239,239));
darkPalette.setColor(QPalette::BrightText, Qt::red); darkPalette.setColor(QPalette::BrightText, Qt::red);
darkPalette.setColor(QPalette::Link, QColor(42, 130, 218)); darkPalette.setColor(QPalette::Link, QColor(42, 130, 218));
darkPalette.setColor(QPalette::Highlight, QColor(42, 130, 218)); darkPalette.setColor(QPalette::Highlight, QColor(42, 130, 218));

View File

@ -7,15 +7,18 @@
#include <QFileDialog> #include <QFileDialog>
#include <QApplication> #include <QApplication>
#include <QDesktopWidget> #include <QDesktopWidget>
#include <QStackedWidget>
#include <assert.h> #include <assert.h>
#include "mainwindow.h" #include "mainwindow.h"
#include "skeletonwidget.h" #include "skeletonwidget.h"
#include "combineeditwidget.h"
#include "theme.h" #include "theme.h"
MainWindow::MainWindow() MainWindow::MainWindow()
{ {
m_partsPageButton = new QPushButton("Parts"); m_partsPageButton = new QPushButton("Parts");
m_combinePageButton = new QPushButton("Combine"); m_combinePageButton = new QPushButton("Combine");
m_motionPageButton = new QPushButton("Motion");
QWidget *hrWidget = new QWidget; QWidget *hrWidget = new QWidget;
hrWidget->setFixedHeight(2); hrWidget->setFixedHeight(2);
@ -26,14 +29,15 @@ MainWindow::MainWindow()
QButtonGroup *pageButtonGroup = new QButtonGroup; QButtonGroup *pageButtonGroup = new QButtonGroup;
pageButtonGroup->addButton(m_partsPageButton); pageButtonGroup->addButton(m_partsPageButton);
pageButtonGroup->addButton(m_combinePageButton); pageButtonGroup->addButton(m_combinePageButton);
pageButtonGroup->addButton(m_motionPageButton);
m_partsPageButton->setCheckable(true); m_partsPageButton->setCheckable(true);
m_combinePageButton->setCheckable(true); m_combinePageButton->setCheckable(true);
m_motionPageButton->setCheckable(true);
pageButtonGroup->setExclusive(true); pageButtonGroup->setExclusive(true);
m_partsPageButton->setChecked(true); m_combinePageButton->setChecked(true);
updatePageButtons();
QHBoxLayout *topButtonsLayout = new QHBoxLayout; QHBoxLayout *topButtonsLayout = new QHBoxLayout;
topButtonsLayout->setContentsMargins(0, 0, 0, 0); topButtonsLayout->setContentsMargins(0, 0, 0, 0);
@ -41,6 +45,7 @@ MainWindow::MainWindow()
topButtonsLayout->addStretch(); topButtonsLayout->addStretch();
topButtonsLayout->addWidget(m_partsPageButton); topButtonsLayout->addWidget(m_partsPageButton);
topButtonsLayout->addWidget(m_combinePageButton); topButtonsLayout->addWidget(m_combinePageButton);
topButtonsLayout->addWidget(m_motionPageButton);
topButtonsLayout->addStretch(); topButtonsLayout->addStretch();
QVBoxLayout *topLayout = new QVBoxLayout; QVBoxLayout *topLayout = new QVBoxLayout;
@ -49,11 +54,92 @@ MainWindow::MainWindow()
topLayout->addLayout(topButtonsLayout); topLayout->addLayout(topButtonsLayout);
topLayout->addWidget(hrWidget); topLayout->addWidget(hrWidget);
QVBoxLayout *partsRightLayout = new QVBoxLayout;
partsRightLayout->addSpacing(20);
QPushButton *changeTurnaroundButton = new QPushButton(" Change Turnaround ");
partsRightLayout->addWidget(changeTurnaroundButton);
QPushButton *exportPartsModelButton = new QPushButton(" Export Model(.obj) ");
partsRightLayout->addWidget(exportPartsModelButton);
QPushButton *newPartsButton = new QPushButton(" New Parts ");
partsRightLayout->addWidget(newPartsButton);
QPushButton *loadPartsButton = new QPushButton(" Load Parts ");
partsRightLayout->addWidget(loadPartsButton);
QPushButton *savePartsButton = new QPushButton(" Save Parts ");
partsRightLayout->addWidget(savePartsButton);
QPushButton *savePartsAsButton = new QPushButton(" Save Parts as ");
partsRightLayout->addWidget(savePartsAsButton);
savePartsAsButton->hide();
partsRightLayout->addStretch();
SkeletonWidget *skeletonWidget = new SkeletonWidget(this); SkeletonWidget *skeletonWidget = new SkeletonWidget(this);
m_skeletonWidget = skeletonWidget;
QHBoxLayout *partsPageLayout = new QHBoxLayout;
partsPageLayout->addWidget(skeletonWidget);
partsPageLayout->addLayout(partsRightLayout);
QWidget *partsPageWidget = new QWidget;
partsPageWidget->setLayout(partsPageLayout);
QVBoxLayout *combineRightLayout = new QVBoxLayout;
combineRightLayout->addSpacing(20);
QPushButton *importPartsToCombineButton = new QPushButton(" Import Parts ");
combineRightLayout->addWidget(importPartsToCombineButton);
QPushButton *exportCombineModelButton = new QPushButton(" Export Model(.obj) ");
combineRightLayout->addWidget(exportCombineModelButton);
QPushButton *newCombineButton = new QPushButton(" New Combine ");
combineRightLayout->addWidget(newCombineButton);
QPushButton *loadCombineButton = new QPushButton(" Load Combine ");
combineRightLayout->addWidget(loadCombineButton);
QPushButton *saveCombineButton = new QPushButton(" Save Combine ");
combineRightLayout->addWidget(saveCombineButton);
QPushButton *saveCombineAsButton = new QPushButton(" Save Combine as ");
combineRightLayout->addWidget(saveCombineAsButton);
saveCombineAsButton->hide();
combineRightLayout->addStretch();
combineRightLayout->setSizeConstraint(QLayout::SetMinimumSize);
CombineEditWidget *combineEditWidget = new CombineEditWidget();
QHBoxLayout *combinePageLayout = new QHBoxLayout;
combinePageLayout->addSpacing(10);
combinePageLayout->addWidget(combineEditWidget);
combinePageLayout->addStretch();
combinePageLayout->addLayout(combineRightLayout);
combinePageLayout->addSpacing(10);
QWidget *combinePageWidget = new QWidget;
combinePageWidget->setLayout(combinePageLayout);
QWidget *motionPageWidget = new QWidget;
QStackedWidget *stackedWidget = new QStackedWidget;
stackedWidget->addWidget(partsPageWidget);
stackedWidget->addWidget(combinePageWidget);
stackedWidget->addWidget(motionPageWidget);
m_stackedWidget = stackedWidget;
QVBoxLayout *mainLayout = new QVBoxLayout; QVBoxLayout *mainLayout = new QVBoxLayout;
mainLayout->addLayout(topLayout); mainLayout->addLayout(topLayout);
mainLayout->addWidget(skeletonWidget); mainLayout->addWidget(stackedWidget);
QWidget *centralWidget = new QWidget; QWidget *centralWidget = new QWidget;
centralWidget->setLayout(mainLayout); centralWidget->setLayout(mainLayout);
@ -63,16 +149,63 @@ MainWindow::MainWindow()
bool connectResult = false; bool connectResult = false;
connectResult = connect(changeTurnaroundButton, SIGNAL(clicked()), skeletonWidget, SLOT(changeTurnaround()));
assert(connectResult);
connectResult = connect(m_partsPageButton, SIGNAL(clicked()), this, SLOT(updatePageButtons())); connectResult = connect(m_partsPageButton, SIGNAL(clicked()), this, SLOT(updatePageButtons()));
assert(connectResult); assert(connectResult);
connectResult = connect(m_combinePageButton, SIGNAL(clicked()), this, SLOT(updatePageButtons())); connectResult = connect(m_combinePageButton, SIGNAL(clicked()), this, SLOT(updatePageButtons()));
assert(connectResult); assert(connectResult);
connectResult = connect(m_motionPageButton, SIGNAL(clicked()), this, SLOT(updatePageButtons()));
assert(connectResult);
connectResult = connect(savePartsButton, SIGNAL(clicked()), this, SLOT(saveParts()));
assert(connectResult);
connectResult = connect(loadPartsButton, SIGNAL(clicked()), this, SLOT(loadParts()));
assert(connectResult);
updatePageButtons();
}
void MainWindow::loadParts()
{
QString filename = QFileDialog::getOpenFileName(this,
tr("Load Parts"), ".",
tr("Xml files (*.xml)"));
if (filename.isEmpty())
return;
m_skeletonWidget->graphicsView()->loadFromXml(filename);
}
void MainWindow::saveParts()
{
if (m_savePartsAs.isEmpty()) {
m_savePartsAs = QFileDialog::getSaveFileName(this,
tr("Save Parts"), ".",
tr("Xml files (*.xml)"));
if (m_savePartsAs.isEmpty()) {
return;
}
}
m_skeletonWidget->graphicsView()->saveToXml(m_savePartsAs);
} }
void MainWindow::updatePageButtons() void MainWindow::updatePageButtons()
{ {
if (m_partsPageButton->isChecked()) {
m_stackedWidget->setCurrentIndex(0);
}
if (m_combinePageButton->isChecked()) {
m_stackedWidget->setCurrentIndex(1);
}
if (m_motionPageButton->isChecked()) {
m_stackedWidget->setCurrentIndex(2);
}
m_partsPageButton->setStyleSheet(m_partsPageButton->isChecked() ? Theme::tabButtonSelectedStylesheet : Theme::tabButtonStylesheet); m_partsPageButton->setStyleSheet(m_partsPageButton->isChecked() ? Theme::tabButtonSelectedStylesheet : Theme::tabButtonStylesheet);
m_combinePageButton->setStyleSheet(m_combinePageButton->isChecked() ? Theme::tabButtonSelectedStylesheet : Theme::tabButtonStylesheet); m_combinePageButton->setStyleSheet(m_combinePageButton->isChecked() ? Theme::tabButtonSelectedStylesheet : Theme::tabButtonStylesheet);
m_motionPageButton->setStyleSheet(m_motionPageButton->isChecked() ? Theme::tabButtonSelectedStylesheet : Theme::tabButtonStylesheet);
} }

View File

@ -4,6 +4,8 @@
#include <QString> #include <QString>
#include <QVBoxLayout> #include <QVBoxLayout>
#include <QPushButton> #include <QPushButton>
#include <QStackedWidget>
#include "skeletonwidget.h"
class MainWindow : public QMainWindow class MainWindow : public QMainWindow
{ {
@ -12,9 +14,15 @@ public:
MainWindow(); MainWindow();
public slots: public slots:
void updatePageButtons(); void updatePageButtons();
void saveParts();
void loadParts();
private: private:
QPushButton *m_partsPageButton; QPushButton *m_partsPageButton;
QPushButton *m_combinePageButton; QPushButton *m_combinePageButton;
QPushButton *m_motionPageButton;
QStackedWidget *m_stackedWidget;
QString m_savePartsAs;
SkeletonWidget *m_skeletonWidget;
}; };
#endif #endif

View File

@ -1,5 +1,9 @@
#include <QGraphicsPixmapItem> #include <QGraphicsPixmapItem>
#include <QXmlStreamWriter>
#include <QFile>
#include <cmath> #include <cmath>
#include <map>
#include <vector>
#include "skeletoneditgraphicsview.h" #include "skeletoneditgraphicsview.h"
#include "skeletoneditnodeitem.h" #include "skeletoneditnodeitem.h"
#include "skeletoneditedgeitem.h" #include "skeletoneditedgeitem.h"
@ -333,3 +337,158 @@ void SkeletonEditGraphicsView::adjustItems(QSizeF oldSceneSize, QSizeF newSceneS
} }
} }
} }
void SkeletonEditGraphicsView::loadFromXml(const QString &filename)
{
QFile file(filename);
if (!file.open(QFile::ReadOnly | QFile::Text)) {
return;
}
float radiusMul = 1.0;
float xMul = 1.0;
float yMul = radiusMul;
std::vector<std::map<QString, QString>> pendingNodes;
std::vector<std::map<QString, QString>> pendingEdges;
std::map<QString, SkeletonEditNodeItem *> addedNodeMapById;
QXmlStreamReader xml;
xml.setDevice(&file);
while (!xml.atEnd()) {
xml.readNext();
printf("tokenString:%s\n", xml.tokenString().toUtf8().constData());
if (xml.isStartElement()) {
printf("name:%s\n", xml.name().toUtf8().constData());
if (xml.name() == "canvas") {
QString canvasWidth = xml.attributes().value("width").toString();
QString canvasHeight = xml.attributes().value("height").toString();
float canvasHeightWidth = canvasWidth.toFloat();
float canvasHeightVal = canvasHeight.toFloat();
if (canvasHeightVal > 0)
radiusMul = (float)scene()->sceneRect().height() / canvasHeightVal;
if (canvasHeightWidth > 0)
xMul = (float)scene()->sceneRect().width() / canvasHeightWidth;
yMul = radiusMul;
} else if (xml.name() == "origin") {
if (pendingNodes.size() > 0) {
pendingNodes[pendingNodes.size() - 1]["x"] = QString("%1").arg(xml.attributes().value("x").toString().toFloat() * xMul);
pendingNodes[pendingNodes.size() - 1]["y"] = QString("%1").arg(xml.attributes().value("y").toString().toFloat() * yMul);
}
} else if (xml.name() == "node") {
QString nodeId = xml.attributes().value("id").toString();
QString nodeType = xml.attributes().value("type").toString();
QString nodePairId = xml.attributes().value("pair").toString();
QString nodeRadius = xml.attributes().value("radius").toString();
std::map<QString, QString> pendingNode;
pendingNode["id"] = nodeId;
pendingNode["type"] = nodeType;
pendingNode["pair"] = nodePairId;
pendingNode["radius"] = QString("%1").arg(nodeRadius.toFloat() * radiusMul);
pendingNode["x"] = "0";
pendingNode["y"] = "0";
pendingNodes.push_back(pendingNode);
} else if (xml.name() == "edge") {
QString edgeId = xml.attributes().value("id").toString();
QString edgeFromNodeId = xml.attributes().value("from").toString();
QString edgeToNodeId = xml.attributes().value("to").toString();
if (!edgeFromNodeId.isEmpty() && !edgeToNodeId.isEmpty()) {
std::map<QString, QString> pendingEdge;
pendingEdge["id"] = edgeId;
pendingEdge["from"] = edgeFromNodeId;
pendingEdge["to"] = edgeToNodeId;
pendingEdges.push_back(pendingEdge);
}
}
}
}
for (size_t i = 0; i < pendingNodes.size(); i++) {
std::map<QString, QString> *pendingNode = &pendingNodes[i];
float radius = (*pendingNode)["radius"].toFloat();
QRectF nodeRect((*pendingNode)["x"].toFloat() - radius, (*pendingNode)["y"].toFloat() - radius,
radius * 2, radius * 2);
addedNodeMapById[(*pendingNode)["id"]] = new SkeletonEditNodeItem(nodeRect);
}
for (size_t i = 0; i < pendingNodes.size(); i++) {
std::map<QString, QString> *pendingNode = &pendingNodes[i];
if ((*pendingNode)["type"] == "master") {
addedNodeMapById[(*pendingNode)["id"]]->setSlave(addedNodeMapById[(*pendingNode)["pair"]]);
} else if ((*pendingNode)["type"] == "slave") {
addedNodeMapById[(*pendingNode)["id"]]->setMaster(addedNodeMapById[(*pendingNode)["pair"]]);
}
scene()->addItem(addedNodeMapById[(*pendingNode)["id"]]);
}
for (size_t i = 0; i < pendingEdges.size(); i++) {
std::map<QString, QString> *pendingEdge = &pendingEdges[i];
SkeletonEditEdgeItem *newEdge = new SkeletonEditEdgeItem();
newEdge->setNodes(addedNodeMapById[(*pendingEdge)["from"]], addedNodeMapById[(*pendingEdge)["to"]]);
scene()->addItem(newEdge);
}
emit nodesChanged();
}
void SkeletonEditGraphicsView::saveToXml(const QString &filename)
{
QFile file(filename);
file.open(QIODevice::WriteOnly);
QXmlStreamWriter stream(&file);
stream.setAutoFormatting(true);
stream.writeStartDocument();
stream.writeStartElement("canvas");
stream.writeAttribute("width", QString("%1").arg(scene()->sceneRect().width()));
stream.writeAttribute("height", QString("%1").arg(scene()->sceneRect().height()));
QList<QGraphicsItem *>::iterator it;
QList<QGraphicsItem *> list = scene()->items();
std::map<SkeletonEditNodeItem *, int> nodeIdMap;
int nextNodeId = 1;
for (it = list.begin(); it != list.end(); ++it) {
if ((*it)->data(0).toString() == "node") {
SkeletonEditNodeItem *nodeItem = static_cast<SkeletonEditNodeItem *>(*it);
nodeIdMap[nodeItem] = nextNodeId;
nextNodeId++;
}
}
stream.writeStartElement("nodes");
for (it = list.begin(); it != list.end(); ++it) {
if ((*it)->data(0).toString() == "node") {
SkeletonEditNodeItem *nodeItem = static_cast<SkeletonEditNodeItem *>(*it);
stream.writeStartElement("node");
stream.writeAttribute("id", QString("node%1").arg(nodeIdMap[nodeItem]));
stream.writeAttribute("type", nodeItem->isMaster() ? "master" : "slave");
stream.writeAttribute("pair", QString("node%1").arg(nodeIdMap[nodeItem->pair()]));
stream.writeAttribute("radius", QString("%1").arg(nodeItem->radius()));
stream.writeStartElement("origin");
QPointF origin = nodeItem->origin();
stream.writeAttribute("x", QString("%1").arg(origin.x()));
stream.writeAttribute("y", QString("%1").arg(origin.y()));
stream.writeEndElement();
stream.writeEndElement();
}
}
stream.writeEndElement();
stream.writeStartElement("edges");
int nextEdgeId = 1;
for (it = list.begin(); it != list.end(); ++it) {
if ((*it)->data(0).toString() == "edge") {
SkeletonEditEdgeItem *edgeItem = static_cast<SkeletonEditEdgeItem *>(*it);
stream.writeStartElement("edge");
stream.writeAttribute("id", QString("edge%1").arg(nextEdgeId));
stream.writeAttribute("from", QString("node%1").arg(nodeIdMap[edgeItem->firstNode()]));
stream.writeAttribute("to", QString("node%1").arg(nodeIdMap[edgeItem->secondNode()]));
stream.writeEndElement();
nextEdgeId++;
}
}
stream.writeEndElement();
stream.writeEndElement();
stream.writeEndDocument();
}

View File

@ -17,6 +17,8 @@ public slots:
public: public:
SkeletonEditGraphicsView(QWidget *parent = 0); SkeletonEditGraphicsView(QWidget *parent = 0);
void updateBackgroundImage(const QImage &image); void updateBackgroundImage(const QImage &image);
void saveToXml(const QString &filename);
void loadFromXml(const QString &filename);
protected: protected:
void mouseMoveEvent(QMouseEvent *event); void mouseMoveEvent(QMouseEvent *event);
void wheelEvent(QWheelEvent *event); void wheelEvent(QWheelEvent *event);

View File

@ -6,7 +6,7 @@
// Modifed from http://doc.qt.io/qt-5/qtwidgets-graphicsview-chip-view-cpp.html // Modifed from http://doc.qt.io/qt-5/qtwidgets-graphicsview-chip-view-cpp.html
SkeletonEditWidget::SkeletonEditWidget(QFrame *parent) : SkeletonEditWidget::SkeletonEditWidget(QWidget *parent) :
QFrame(parent) QFrame(parent)
{ {
m_graphicsView = new SkeletonEditGraphicsView(this); m_graphicsView = new SkeletonEditGraphicsView(this);

View File

@ -14,7 +14,7 @@ class SkeletonEditWidget : public QFrame
signals: signals:
void sizeChanged(); void sizeChanged();
public: public:
SkeletonEditWidget(QFrame *parent = 0); SkeletonEditWidget(QWidget *parent = 0);
SkeletonEditGraphicsView *graphicsView(); SkeletonEditGraphicsView *graphicsView();
protected: protected:
void resizeEvent(QResizeEvent *event); void resizeEvent(QResizeEvent *event);

View File

@ -92,6 +92,11 @@ SkeletonWidget::SkeletonWidget(QWidget *parent) :
//assert(connectResult); //assert(connectResult);
} }
SkeletonEditGraphicsView *SkeletonWidget::graphicsView()
{
return m_skeletonEditWidget->graphicsView();
}
void SkeletonWidget::showModelingWidgetAtCorner() void SkeletonWidget::showModelingWidgetAtCorner()
{ {
if (!m_modelingWidget->isVisible()) { if (!m_modelingWidget->isVisible()) {

View File

@ -8,12 +8,14 @@
#include "skeletoneditwidget.h" #include "skeletoneditwidget.h"
#include "skeletontomesh.h" #include "skeletontomesh.h"
#include "turnaroundloader.h" #include "turnaroundloader.h"
#include "skeletoneditgraphicsview.h"
class SkeletonWidget : public QWidget class SkeletonWidget : public QWidget
{ {
Q_OBJECT Q_OBJECT
public: public:
SkeletonWidget(QWidget *parent=0); SkeletonWidget(QWidget *parent=0);
SkeletonEditGraphicsView *graphicsView();
public slots: public slots:
void skeletonChanged(); void skeletonChanged();
void meshReady(); void meshReady();