2018-03-11 03:18:24 +00:00
|
|
|
#include <QVBoxLayout>
|
|
|
|
#include <QPushButton>
|
|
|
|
#include <QButtonGroup>
|
|
|
|
#include <QGridLayout>
|
|
|
|
#include <QToolBar>
|
2018-03-11 16:02:15 +00:00
|
|
|
#include <QThread>
|
2018-03-13 06:39:36 +00:00
|
|
|
#include <QFileDialog>
|
2018-03-14 02:55:59 +00:00
|
|
|
#include <QApplication>
|
|
|
|
#include <QDesktopWidget>
|
2018-03-14 15:22:00 +00:00
|
|
|
#include <QStackedWidget>
|
2018-03-15 15:40:30 +00:00
|
|
|
#include <QXmlStreamReader>
|
|
|
|
#include <QBuffer>
|
2018-03-19 07:58:51 +00:00
|
|
|
#include <QFormLayout>
|
|
|
|
#include <QComboBox>
|
2018-03-26 12:41:46 +00:00
|
|
|
#include <QMenu>
|
|
|
|
#include <QMenuBar>
|
2018-03-11 16:02:15 +00:00
|
|
|
#include <assert.h>
|
|
|
|
#include "mainwindow.h"
|
2018-03-14 06:43:16 +00:00
|
|
|
#include "skeletonwidget.h"
|
|
|
|
#include "theme.h"
|
2018-03-15 15:40:30 +00:00
|
|
|
#include "ds3file.h"
|
2018-03-26 12:41:46 +00:00
|
|
|
#include "skeletonxml.h"
|
2018-03-10 06:57:14 +00:00
|
|
|
|
2018-03-14 06:43:16 +00:00
|
|
|
MainWindow::MainWindow()
|
2018-03-10 06:57:14 +00:00
|
|
|
{
|
2018-03-15 15:40:30 +00:00
|
|
|
m_modelPageButton = new QPushButton("Model");
|
|
|
|
m_sharePageButton = new QPushButton("Share");
|
2018-03-11 03:18:24 +00:00
|
|
|
|
2018-03-14 06:43:16 +00:00
|
|
|
QWidget *hrWidget = new QWidget;
|
2018-03-26 12:41:46 +00:00
|
|
|
hrWidget->setFixedHeight(1);
|
2018-03-14 06:43:16 +00:00
|
|
|
hrWidget->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed);
|
|
|
|
hrWidget->setStyleSheet(QString("background-color: #fc6621;"));
|
|
|
|
hrWidget->setContentsMargins(0, 0, 0, 0);
|
2018-03-11 03:18:24 +00:00
|
|
|
|
2018-03-14 06:43:16 +00:00
|
|
|
QButtonGroup *pageButtonGroup = new QButtonGroup;
|
2018-03-15 15:40:30 +00:00
|
|
|
pageButtonGroup->addButton(m_modelPageButton);
|
|
|
|
pageButtonGroup->addButton(m_sharePageButton);
|
2018-03-11 03:18:24 +00:00
|
|
|
|
2018-03-15 15:40:30 +00:00
|
|
|
m_modelPageButton->setCheckable(true);
|
|
|
|
m_sharePageButton->setCheckable(true);
|
2018-03-11 03:18:24 +00:00
|
|
|
|
2018-03-14 06:43:16 +00:00
|
|
|
pageButtonGroup->setExclusive(true);
|
2018-03-11 03:18:24 +00:00
|
|
|
|
2018-03-15 15:40:30 +00:00
|
|
|
m_modelPageButton->setChecked(true);
|
2018-03-11 03:18:24 +00:00
|
|
|
|
2018-03-14 06:43:16 +00:00
|
|
|
QHBoxLayout *topButtonsLayout = new QHBoxLayout;
|
|
|
|
topButtonsLayout->setContentsMargins(0, 0, 0, 0);
|
2018-03-26 12:41:46 +00:00
|
|
|
topButtonsLayout->setSpacing(20);
|
2018-03-15 15:40:30 +00:00
|
|
|
topButtonsLayout->addWidget(m_modelPageButton);
|
|
|
|
topButtonsLayout->addWidget(m_sharePageButton);
|
2018-03-14 06:43:16 +00:00
|
|
|
topButtonsLayout->addStretch();
|
2018-03-11 03:18:24 +00:00
|
|
|
|
2018-03-14 06:43:16 +00:00
|
|
|
QVBoxLayout *topLayout = new QVBoxLayout;
|
|
|
|
topLayout->setContentsMargins(0, 0, 0, 0);
|
|
|
|
topLayout->setSpacing(0);
|
|
|
|
topLayout->addLayout(topButtonsLayout);
|
|
|
|
topLayout->addWidget(hrWidget);
|
2018-03-11 16:02:15 +00:00
|
|
|
|
2018-03-19 07:58:51 +00:00
|
|
|
m_edgePropertyWidget = new QWidget;
|
|
|
|
QFormLayout *formLayout = new QFormLayout;
|
|
|
|
QComboBox *edgeTypeBox = new QComboBox;
|
|
|
|
edgeTypeBox->addItem("Spine", "Spine");
|
|
|
|
edgeTypeBox->addItem("Attach", "Attach");
|
|
|
|
formLayout->addRow(tr("Edge Type:"), edgeTypeBox);
|
|
|
|
m_edgePropertyWidget->setLayout(formLayout);
|
|
|
|
|
2018-03-15 15:40:30 +00:00
|
|
|
QVBoxLayout *modelRightLayout = new QVBoxLayout;
|
2018-03-14 15:22:00 +00:00
|
|
|
|
2018-03-20 03:31:05 +00:00
|
|
|
modelRightLayout->addSpacing(10);
|
2018-03-14 15:22:00 +00:00
|
|
|
|
|
|
|
QPushButton *changeTurnaroundButton = new QPushButton(" Change Turnaround ");
|
2018-03-15 15:40:30 +00:00
|
|
|
modelRightLayout->addWidget(changeTurnaroundButton);
|
2018-03-14 15:22:00 +00:00
|
|
|
|
2018-03-20 07:56:49 +00:00
|
|
|
QPushButton *exportModelButton = new QPushButton(" Export ");
|
|
|
|
modelRightLayout->addWidget(exportModelButton);
|
2018-03-14 15:22:00 +00:00
|
|
|
|
2018-03-15 15:40:30 +00:00
|
|
|
QPushButton *newModelButton = new QPushButton(" New ");
|
|
|
|
modelRightLayout->addWidget(newModelButton);
|
2018-03-14 15:22:00 +00:00
|
|
|
|
2018-03-15 15:40:30 +00:00
|
|
|
QPushButton *loadModelButton = new QPushButton(" Load ");
|
|
|
|
modelRightLayout->addWidget(loadModelButton);
|
2018-03-14 15:22:00 +00:00
|
|
|
|
2018-03-15 15:40:30 +00:00
|
|
|
QPushButton *saveModelButton = new QPushButton(" Save ");
|
|
|
|
modelRightLayout->addWidget(saveModelButton);
|
2018-03-14 15:22:00 +00:00
|
|
|
|
2018-03-15 15:40:30 +00:00
|
|
|
QPushButton *saveModelAsButton = new QPushButton(" Save as ");
|
|
|
|
modelRightLayout->addWidget(saveModelAsButton);
|
|
|
|
saveModelAsButton->hide();
|
2018-03-14 15:22:00 +00:00
|
|
|
|
2018-03-19 07:58:51 +00:00
|
|
|
modelRightLayout->addSpacing(20);
|
|
|
|
|
|
|
|
modelRightLayout->addWidget(m_edgePropertyWidget);
|
|
|
|
|
2018-03-15 15:40:30 +00:00
|
|
|
modelRightLayout->addStretch();
|
2018-03-14 15:22:00 +00:00
|
|
|
|
2018-03-14 06:43:16 +00:00
|
|
|
SkeletonWidget *skeletonWidget = new SkeletonWidget(this);
|
2018-03-14 15:22:00 +00:00
|
|
|
m_skeletonWidget = skeletonWidget;
|
|
|
|
|
2018-03-15 15:40:30 +00:00
|
|
|
QHBoxLayout *modelPageLayout = new QHBoxLayout;
|
|
|
|
modelPageLayout->addWidget(skeletonWidget);
|
2018-03-26 12:41:46 +00:00
|
|
|
//modelPageLayout->addLayout(modelRightLayout);
|
2018-03-14 15:22:00 +00:00
|
|
|
|
2018-03-15 15:40:30 +00:00
|
|
|
QWidget *modelPageWidget = new QWidget;
|
|
|
|
modelPageWidget->setLayout(modelPageLayout);
|
2018-03-14 15:22:00 +00:00
|
|
|
|
2018-03-15 15:40:30 +00:00
|
|
|
QWidget *sharePageWidget = new QWidget;
|
2018-03-14 15:22:00 +00:00
|
|
|
|
|
|
|
QStackedWidget *stackedWidget = new QStackedWidget;
|
2018-03-15 15:40:30 +00:00
|
|
|
stackedWidget->addWidget(modelPageWidget);
|
|
|
|
stackedWidget->addWidget(sharePageWidget);
|
2018-03-26 12:41:46 +00:00
|
|
|
stackedWidget->setContentsMargins(0, 0, 0, 0);
|
2018-03-14 15:22:00 +00:00
|
|
|
|
|
|
|
m_stackedWidget = stackedWidget;
|
2018-03-11 03:18:24 +00:00
|
|
|
|
|
|
|
QVBoxLayout *mainLayout = new QVBoxLayout;
|
2018-03-26 12:41:46 +00:00
|
|
|
//mainLayout->addLayout(topLayout);
|
2018-03-14 15:22:00 +00:00
|
|
|
mainLayout->addWidget(stackedWidget);
|
2018-03-26 12:41:46 +00:00
|
|
|
mainLayout->setContentsMargins(0, 0, 0, 0);
|
2018-03-11 03:18:24 +00:00
|
|
|
|
|
|
|
QWidget *centralWidget = new QWidget;
|
|
|
|
centralWidget->setLayout(mainLayout);
|
|
|
|
|
|
|
|
setCentralWidget(centralWidget);
|
|
|
|
setWindowTitle(tr("Dust 3D"));
|
2018-03-11 16:02:15 +00:00
|
|
|
|
2018-03-26 12:41:46 +00:00
|
|
|
QAction *newAct = new QAction(tr("&New"), this);
|
|
|
|
newAct->setShortcuts(QKeySequence::New);
|
|
|
|
newAct->setStatusTip(tr("Create a new file"));
|
|
|
|
connect(newAct, &QAction::triggered, this, &MainWindow::newFile);
|
|
|
|
|
|
|
|
QAction *openAct = new QAction(tr("&Open..."), this);
|
|
|
|
openAct->setShortcuts(QKeySequence::Open);
|
|
|
|
openAct->setStatusTip(tr("Open an existing file"));
|
|
|
|
connect(openAct, &QAction::triggered, this, &MainWindow::open);
|
|
|
|
|
|
|
|
QAction *saveAct = new QAction(tr("&Save"), this);
|
|
|
|
saveAct->setShortcuts(QKeySequence::Save);
|
|
|
|
saveAct->setStatusTip(tr("Save the document to disk"));
|
|
|
|
connect(saveAct, &QAction::triggered, this, &MainWindow::save);
|
|
|
|
|
|
|
|
QAction *exitAct = new QAction(tr("E&xit"), this);
|
|
|
|
exitAct->setShortcuts(QKeySequence::Quit);
|
|
|
|
exitAct->setStatusTip(tr("Exit the application"));
|
|
|
|
connect(exitAct, &QAction::triggered, this, &QWidget::close);
|
|
|
|
|
|
|
|
QAction *undoAct = new QAction(tr("&Undo"), this);
|
|
|
|
undoAct->setShortcuts(QKeySequence::Undo);
|
|
|
|
undoAct->setStatusTip(tr("Undo the last operation"));
|
|
|
|
connect(undoAct, &QAction::triggered, this, &MainWindow::undo);
|
|
|
|
|
|
|
|
QAction *redoAct = new QAction(tr("&Redo"), this);
|
|
|
|
redoAct->setShortcuts(QKeySequence::Redo);
|
|
|
|
redoAct->setStatusTip(tr("Redo the last operation"));
|
|
|
|
connect(redoAct, &QAction::triggered, this, &MainWindow::redo);
|
|
|
|
|
|
|
|
QAction *cutAct = new QAction(tr("Cu&t"), this);
|
|
|
|
cutAct->setShortcuts(QKeySequence::Cut);
|
|
|
|
cutAct->setStatusTip(tr("Cut the current selection's contents to the "
|
|
|
|
"clipboard"));
|
|
|
|
connect(cutAct, &QAction::triggered, this, &MainWindow::cut);
|
|
|
|
|
|
|
|
QAction *copyAct = new QAction(tr("&Copy"), this);
|
|
|
|
copyAct->setShortcuts(QKeySequence::Copy);
|
|
|
|
copyAct->setStatusTip(tr("Copy the current selection's contents to the "
|
|
|
|
"clipboard"));
|
|
|
|
connect(copyAct, &QAction::triggered, this, &MainWindow::copy);
|
|
|
|
|
|
|
|
QAction *pasteAct = new QAction(tr("&Paste"), this);
|
|
|
|
pasteAct->setShortcuts(QKeySequence::Paste);
|
|
|
|
pasteAct->setStatusTip(tr("Paste the clipboard's contents into the current "
|
|
|
|
"selection"));
|
|
|
|
connect(pasteAct, &QAction::triggered, this, &MainWindow::paste);
|
|
|
|
|
|
|
|
QAction *changeTurnaroundAct = new QAction(tr("&Change Turnaround..."), this);
|
|
|
|
connect(changeTurnaroundAct, &QAction::triggered, skeletonWidget, &SkeletonWidget::changeTurnaround);
|
|
|
|
|
|
|
|
QMenu *fileMenu = menuBar()->addMenu(tr("&File"));
|
|
|
|
fileMenu->addAction(newAct);
|
|
|
|
fileMenu->addAction(openAct);
|
|
|
|
fileMenu->addAction(saveAct);
|
|
|
|
fileMenu->addSeparator();
|
|
|
|
fileMenu->addAction(exitAct);
|
|
|
|
|
|
|
|
QMenu *editMenu = menuBar()->addMenu(tr("&Edit"));
|
|
|
|
editMenu->addAction(undoAct);
|
|
|
|
editMenu->addAction(redoAct);
|
|
|
|
editMenu->addSeparator();
|
|
|
|
editMenu->addAction(cutAct);
|
|
|
|
editMenu->addAction(copyAct);
|
|
|
|
editMenu->addAction(pasteAct);
|
|
|
|
editMenu->addSeparator();
|
|
|
|
editMenu->addAction(changeTurnaroundAct);
|
|
|
|
|
2018-03-14 06:43:16 +00:00
|
|
|
bool connectResult = false;
|
2018-03-11 16:02:15 +00:00
|
|
|
|
2018-03-14 15:22:00 +00:00
|
|
|
connectResult = connect(changeTurnaroundButton, SIGNAL(clicked()), skeletonWidget, SLOT(changeTurnaround()));
|
|
|
|
assert(connectResult);
|
|
|
|
|
2018-03-15 15:40:30 +00:00
|
|
|
connectResult = connect(m_modelPageButton, SIGNAL(clicked()), this, SLOT(updatePageButtons()));
|
2018-03-11 16:02:15 +00:00
|
|
|
assert(connectResult);
|
2018-03-14 15:22:00 +00:00
|
|
|
|
2018-03-15 15:40:30 +00:00
|
|
|
connectResult = connect(m_sharePageButton, SIGNAL(clicked()), this, SLOT(updatePageButtons()));
|
2018-03-14 15:22:00 +00:00
|
|
|
assert(connectResult);
|
|
|
|
|
2018-03-20 07:56:49 +00:00
|
|
|
connectResult = connect(exportModelButton, SIGNAL(clicked()), this, SLOT(exportModel()));
|
|
|
|
assert(connectResult);
|
|
|
|
|
2018-03-15 15:40:30 +00:00
|
|
|
connectResult = connect(saveModelButton, SIGNAL(clicked()), this, SLOT(saveModel()));
|
2018-03-14 15:22:00 +00:00
|
|
|
assert(connectResult);
|
|
|
|
|
2018-03-15 15:40:30 +00:00
|
|
|
connectResult = connect(loadModelButton, SIGNAL(clicked()), this, SLOT(loadModel()));
|
2018-03-14 15:22:00 +00:00
|
|
|
assert(connectResult);
|
|
|
|
|
|
|
|
updatePageButtons();
|
|
|
|
}
|
|
|
|
|
2018-03-26 12:41:46 +00:00
|
|
|
void MainWindow::newFile()
|
|
|
|
{
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
void MainWindow::open()
|
|
|
|
{
|
|
|
|
loadModel();
|
|
|
|
}
|
|
|
|
|
|
|
|
void MainWindow::save()
|
|
|
|
{
|
|
|
|
saveModel();
|
|
|
|
}
|
|
|
|
|
|
|
|
void MainWindow::undo()
|
|
|
|
{
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
void MainWindow::redo()
|
|
|
|
{
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
void MainWindow::cut()
|
|
|
|
{
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
void MainWindow::copy()
|
|
|
|
{
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
void MainWindow::paste()
|
|
|
|
{
|
|
|
|
|
|
|
|
}
|
|
|
|
|
2018-03-20 07:56:49 +00:00
|
|
|
void MainWindow::exportModel()
|
|
|
|
{
|
|
|
|
QString exportTo = QFileDialog::getSaveFileName(this,
|
|
|
|
tr("Export Model"), ".",
|
|
|
|
tr("Wavefront OBJ File (*.obj)"));
|
|
|
|
if (exportTo.isEmpty()) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
m_skeletonWidget->modelWidget()->exportMeshAsObj(exportTo);
|
|
|
|
}
|
|
|
|
|
2018-03-15 15:40:30 +00:00
|
|
|
void MainWindow::loadModel()
|
2018-03-14 15:22:00 +00:00
|
|
|
{
|
|
|
|
QString filename = QFileDialog::getOpenFileName(this,
|
2018-03-15 15:40:30 +00:00
|
|
|
tr("Load Model"), ".",
|
|
|
|
tr("Dust 3D Project (*.ds3)"));
|
2018-03-14 15:22:00 +00:00
|
|
|
if (filename.isEmpty())
|
|
|
|
return;
|
2018-03-15 15:40:30 +00:00
|
|
|
Ds3FileReader ds3Reader(filename);
|
|
|
|
for (int i = 0; i < ds3Reader.items().size(); ++i) {
|
|
|
|
Ds3ReaderItem item = ds3Reader.items().at(i);
|
|
|
|
if (item.type == "model") {
|
|
|
|
QByteArray data;
|
|
|
|
ds3Reader.loadItem(item.name, &data);
|
|
|
|
QXmlStreamReader xmlReader(data);
|
2018-03-26 12:41:46 +00:00
|
|
|
SkeletonSnapshot snapshot;
|
|
|
|
loadSkeletonFromXmlStream(&snapshot, xmlReader);
|
|
|
|
m_skeletonWidget->graphicsView()->loadFromSnapshot(&snapshot);
|
2018-03-15 15:40:30 +00:00
|
|
|
} else if (item.type == "asset") {
|
|
|
|
if (item.name == "canvas.png") {
|
|
|
|
QByteArray data;
|
|
|
|
ds3Reader.loadItem(item.name, &data);
|
|
|
|
QImage image = QImage::fromData(data, "PNG");
|
|
|
|
m_skeletonWidget->graphicsView()->updateBackgroundImage(image);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2018-03-18 08:46:53 +00:00
|
|
|
m_skeletonWidget->graphicsView()->turnOffAddNodeMode();
|
2018-03-14 15:22:00 +00:00
|
|
|
}
|
|
|
|
|
2018-03-15 15:40:30 +00:00
|
|
|
void MainWindow::saveModel()
|
2018-03-14 15:22:00 +00:00
|
|
|
{
|
2018-03-15 15:40:30 +00:00
|
|
|
if (m_saveModelAs.isEmpty()) {
|
|
|
|
m_saveModelAs = QFileDialog::getSaveFileName(this,
|
|
|
|
tr("Save Model"), ".",
|
|
|
|
tr("Dust 3D Project (*.ds3)"));
|
|
|
|
if (m_saveModelAs.isEmpty()) {
|
2018-03-14 15:22:00 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
2018-03-15 15:40:30 +00:00
|
|
|
|
|
|
|
Ds3FileWriter ds3Writer;
|
|
|
|
|
|
|
|
QByteArray modelXml;
|
|
|
|
QXmlStreamWriter stream(&modelXml);
|
2018-03-26 12:41:46 +00:00
|
|
|
SkeletonSnapshot snapshot;
|
|
|
|
m_skeletonWidget->graphicsView()->saveToSnapshot(&snapshot);
|
|
|
|
saveSkeletonToXmlStream(&snapshot, &stream);
|
2018-03-15 15:40:30 +00:00
|
|
|
if (modelXml.size() > 0)
|
|
|
|
ds3Writer.add("model1.xml", "model", &modelXml);
|
|
|
|
|
|
|
|
QByteArray imageByteArray;
|
|
|
|
QBuffer pngBuffer(&imageByteArray);
|
|
|
|
pngBuffer.open(QIODevice::WriteOnly);
|
|
|
|
m_skeletonWidget->graphicsView()->backgroundImage().save(&pngBuffer, "PNG");
|
|
|
|
if (imageByteArray.size() > 0)
|
|
|
|
ds3Writer.add("canvas.png", "asset", &imageByteArray);
|
|
|
|
|
|
|
|
ds3Writer.save(m_saveModelAs);
|
2018-03-10 06:57:14 +00:00
|
|
|
}
|
|
|
|
|
2018-03-14 06:43:16 +00:00
|
|
|
void MainWindow::updatePageButtons()
|
2018-03-11 16:02:15 +00:00
|
|
|
{
|
2018-03-15 15:40:30 +00:00
|
|
|
if (m_modelPageButton->isChecked()) {
|
2018-03-14 15:22:00 +00:00
|
|
|
m_stackedWidget->setCurrentIndex(0);
|
|
|
|
}
|
2018-03-15 15:40:30 +00:00
|
|
|
if (m_sharePageButton->isChecked()) {
|
2018-03-14 15:22:00 +00:00
|
|
|
m_stackedWidget->setCurrentIndex(1);
|
|
|
|
}
|
2018-03-15 15:40:30 +00:00
|
|
|
m_modelPageButton->setStyleSheet(m_modelPageButton->isChecked() ? Theme::tabButtonSelectedStylesheet : Theme::tabButtonStylesheet);
|
|
|
|
m_sharePageButton->setStyleSheet(m_sharePageButton->isChecked() ? Theme::tabButtonSelectedStylesheet : Theme::tabButtonStylesheet);
|
2018-03-11 16:02:15 +00:00
|
|
|
}
|
|
|
|
|