diff --git a/dust3d.pro b/dust3d.pro index 5a853cd4..ae42fd28 100644 --- a/dust3d.pro +++ b/dust3d.pro @@ -31,6 +31,9 @@ HEADERS += src/turnaroundloader.h SOURCES += src/skeletonwidget.cpp HEADERS += src/skeletonwidget.h +SOURCES += src/combineeditwidget.cpp +HEADERS += src/combineeditwidget.h + SOURCES += src/theme.cpp HEADERS += src/theme.h diff --git a/src/combineeditwidget.cpp b/src/combineeditwidget.cpp new file mode 100644 index 00000000..9b5e29fb --- /dev/null +++ b/src/combineeditwidget.cpp @@ -0,0 +1,26 @@ +#include +#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(); +} + + diff --git a/src/combineeditwidget.h b/src/combineeditwidget.h new file mode 100644 index 00000000..80af8403 --- /dev/null +++ b/src/combineeditwidget.h @@ -0,0 +1,20 @@ +#ifndef COMBINE_EDIT_WIDGET_H +#define COMBINE_EDIT_WIDGET_H +#include +#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 diff --git a/src/main.cpp b/src/main.cpp index c6464253..bcd16e34 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -13,14 +13,14 @@ int main(int argc, char ** argv) qApp->setStyle(QStyleFactory::create("Fusion")); QPalette darkPalette; 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::AlternateBase, QColor(53,53,53)); darkPalette.setColor(QPalette::ToolTipBase, Qt::white); darkPalette.setColor(QPalette::ToolTipText, Qt::white); darkPalette.setColor(QPalette::Text, Qt::white); 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::Link, QColor(42, 130, 218)); darkPalette.setColor(QPalette::Highlight, QColor(42, 130, 218)); diff --git a/src/mainwindow.cpp b/src/mainwindow.cpp index 993171a8..b2c25a78 100644 --- a/src/mainwindow.cpp +++ b/src/mainwindow.cpp @@ -7,15 +7,18 @@ #include #include #include +#include #include #include "mainwindow.h" #include "skeletonwidget.h" +#include "combineeditwidget.h" #include "theme.h" MainWindow::MainWindow() { m_partsPageButton = new QPushButton("Parts"); m_combinePageButton = new QPushButton("Combine"); + m_motionPageButton = new QPushButton("Motion"); QWidget *hrWidget = new QWidget; hrWidget->setFixedHeight(2); @@ -26,14 +29,15 @@ MainWindow::MainWindow() QButtonGroup *pageButtonGroup = new QButtonGroup; pageButtonGroup->addButton(m_partsPageButton); pageButtonGroup->addButton(m_combinePageButton); + pageButtonGroup->addButton(m_motionPageButton); m_partsPageButton->setCheckable(true); m_combinePageButton->setCheckable(true); + m_motionPageButton->setCheckable(true); pageButtonGroup->setExclusive(true); - m_partsPageButton->setChecked(true); - updatePageButtons(); + m_combinePageButton->setChecked(true); QHBoxLayout *topButtonsLayout = new QHBoxLayout; topButtonsLayout->setContentsMargins(0, 0, 0, 0); @@ -41,6 +45,7 @@ MainWindow::MainWindow() topButtonsLayout->addStretch(); topButtonsLayout->addWidget(m_partsPageButton); topButtonsLayout->addWidget(m_combinePageButton); + topButtonsLayout->addWidget(m_motionPageButton); topButtonsLayout->addStretch(); QVBoxLayout *topLayout = new QVBoxLayout; @@ -49,11 +54,92 @@ MainWindow::MainWindow() topLayout->addLayout(topButtonsLayout); 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); + 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; mainLayout->addLayout(topLayout); - mainLayout->addWidget(skeletonWidget); + mainLayout->addWidget(stackedWidget); QWidget *centralWidget = new QWidget; centralWidget->setLayout(mainLayout); @@ -63,16 +149,63 @@ MainWindow::MainWindow() bool connectResult = false; + connectResult = connect(changeTurnaroundButton, SIGNAL(clicked()), skeletonWidget, SLOT(changeTurnaround())); + assert(connectResult); + connectResult = connect(m_partsPageButton, SIGNAL(clicked()), this, SLOT(updatePageButtons())); assert(connectResult); connectResult = connect(m_combinePageButton, SIGNAL(clicked()), this, SLOT(updatePageButtons())); 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() { + 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_combinePageButton->setStyleSheet(m_combinePageButton->isChecked() ? Theme::tabButtonSelectedStylesheet : Theme::tabButtonStylesheet); + m_motionPageButton->setStyleSheet(m_motionPageButton->isChecked() ? Theme::tabButtonSelectedStylesheet : Theme::tabButtonStylesheet); } diff --git a/src/mainwindow.h b/src/mainwindow.h index ef0637d0..b845588f 100644 --- a/src/mainwindow.h +++ b/src/mainwindow.h @@ -4,6 +4,8 @@ #include #include #include +#include +#include "skeletonwidget.h" class MainWindow : public QMainWindow { @@ -12,9 +14,15 @@ public: MainWindow(); public slots: void updatePageButtons(); + void saveParts(); + void loadParts(); private: QPushButton *m_partsPageButton; QPushButton *m_combinePageButton; + QPushButton *m_motionPageButton; + QStackedWidget *m_stackedWidget; + QString m_savePartsAs; + SkeletonWidget *m_skeletonWidget; }; #endif diff --git a/src/skeletoneditgraphicsview.cpp b/src/skeletoneditgraphicsview.cpp index afeb50b2..e9dac1d5 100644 --- a/src/skeletoneditgraphicsview.cpp +++ b/src/skeletoneditgraphicsview.cpp @@ -1,5 +1,9 @@ #include +#include +#include #include +#include +#include #include "skeletoneditgraphicsview.h" #include "skeletoneditnodeitem.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> pendingNodes; + std::vector> pendingEdges; + std::map 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 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 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 *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 *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 *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::iterator it; + QList list = scene()->items(); + std::map nodeIdMap; + int nextNodeId = 1; + for (it = list.begin(); it != list.end(); ++it) { + if ((*it)->data(0).toString() == "node") { + SkeletonEditNodeItem *nodeItem = static_cast(*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(*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(*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(); +} + diff --git a/src/skeletoneditgraphicsview.h b/src/skeletoneditgraphicsview.h index 97466bf0..ffd90e95 100644 --- a/src/skeletoneditgraphicsview.h +++ b/src/skeletoneditgraphicsview.h @@ -17,6 +17,8 @@ public slots: public: SkeletonEditGraphicsView(QWidget *parent = 0); void updateBackgroundImage(const QImage &image); + void saveToXml(const QString &filename); + void loadFromXml(const QString &filename); protected: void mouseMoveEvent(QMouseEvent *event); void wheelEvent(QWheelEvent *event); diff --git a/src/skeletoneditwidget.cpp b/src/skeletoneditwidget.cpp index 15b12af5..4f9195ed 100644 --- a/src/skeletoneditwidget.cpp +++ b/src/skeletoneditwidget.cpp @@ -6,7 +6,7 @@ // Modifed from http://doc.qt.io/qt-5/qtwidgets-graphicsview-chip-view-cpp.html -SkeletonEditWidget::SkeletonEditWidget(QFrame *parent) : +SkeletonEditWidget::SkeletonEditWidget(QWidget *parent) : QFrame(parent) { m_graphicsView = new SkeletonEditGraphicsView(this); diff --git a/src/skeletoneditwidget.h b/src/skeletoneditwidget.h index 9625688a..8038c4f1 100644 --- a/src/skeletoneditwidget.h +++ b/src/skeletoneditwidget.h @@ -14,7 +14,7 @@ class SkeletonEditWidget : public QFrame signals: void sizeChanged(); public: - SkeletonEditWidget(QFrame *parent = 0); + SkeletonEditWidget(QWidget *parent = 0); SkeletonEditGraphicsView *graphicsView(); protected: void resizeEvent(QResizeEvent *event); diff --git a/src/skeletonwidget.cpp b/src/skeletonwidget.cpp index ea566a98..b398719f 100644 --- a/src/skeletonwidget.cpp +++ b/src/skeletonwidget.cpp @@ -92,6 +92,11 @@ SkeletonWidget::SkeletonWidget(QWidget *parent) : //assert(connectResult); } +SkeletonEditGraphicsView *SkeletonWidget::graphicsView() +{ + return m_skeletonEditWidget->graphicsView(); +} + void SkeletonWidget::showModelingWidgetAtCorner() { if (!m_modelingWidget->isVisible()) { diff --git a/src/skeletonwidget.h b/src/skeletonwidget.h index d2290327..3e04d17d 100644 --- a/src/skeletonwidget.h +++ b/src/skeletonwidget.h @@ -8,12 +8,14 @@ #include "skeletoneditwidget.h" #include "skeletontomesh.h" #include "turnaroundloader.h" +#include "skeletoneditgraphicsview.h" class SkeletonWidget : public QWidget { Q_OBJECT public: SkeletonWidget(QWidget *parent=0); + SkeletonEditGraphicsView *graphicsView(); public slots: void skeletonChanged(); void meshReady();