mirror of
https://github.com/isledecomp/SIEdit.git
synced 2024-11-27 01:25:45 -05:00
app: implement deweaving and preview
This commit is contained in:
parent
4465f26c38
commit
cb53beb445
17 changed files with 509 additions and 152 deletions
|
@ -1,7 +1,7 @@
|
||||||
find_package(Qt5)
|
find_package(Qt5)
|
||||||
|
|
||||||
find_package(QT NAMES Qt6 Qt5 REQUIRED COMPONENTS Widgets)
|
find_package(QT NAMES Qt6 Qt5 REQUIRED COMPONENTS Widgets Multimedia)
|
||||||
find_package(Qt${QT_VERSION_MAJOR} REQUIRED COMPONENTS Widgets)
|
find_package(Qt${QT_VERSION_MAJOR} REQUIRED COMPONENTS Widgets Multimedia)
|
||||||
|
|
||||||
set(PROJECT_SOURCES
|
set(PROJECT_SOURCES
|
||||||
siview/chunkmodel.cpp
|
siview/chunkmodel.cpp
|
||||||
|
@ -19,11 +19,18 @@ set(PROJECT_SOURCES
|
||||||
siview/siview.cpp
|
siview/siview.cpp
|
||||||
siview/siview.h
|
siview/siview.h
|
||||||
|
|
||||||
|
viewer/bitmappanel.cpp
|
||||||
|
viewer/bitmappanel.h
|
||||||
|
viewer/wavpanel.cpp
|
||||||
|
viewer/wavpanel.h
|
||||||
|
|
||||||
main.cpp
|
main.cpp
|
||||||
mainwindow.cpp
|
mainwindow.cpp
|
||||||
mainwindow.h
|
mainwindow.h
|
||||||
#objectmodel.cpp
|
model.cpp
|
||||||
#objectmodel.h
|
model.h
|
||||||
|
objectmodel.cpp
|
||||||
|
objectmodel.h
|
||||||
panel.cpp
|
panel.cpp
|
||||||
panel.h
|
panel.h
|
||||||
vector3edit.cpp
|
vector3edit.cpp
|
||||||
|
@ -43,7 +50,7 @@ else()
|
||||||
)
|
)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
target_link_libraries(si-edit PRIVATE Qt${QT_VERSION_MAJOR}::Widgets libweaver)
|
target_link_libraries(si-edit PRIVATE Qt${QT_VERSION_MAJOR}::Widgets Qt${QT_VERSION_MAJOR}::Multimedia libweaver)
|
||||||
target_include_directories(si-edit PRIVATE "${CMAKE_SOURCE_DIR}/lib")
|
target_include_directories(si-edit PRIVATE "${CMAKE_SOURCE_DIR}/lib")
|
||||||
|
|
||||||
set_target_properties(si-edit PROPERTIES
|
set_target_properties(si-edit PROPERTIES
|
||||||
|
|
|
@ -6,7 +6,6 @@
|
||||||
#include <QMessageBox>
|
#include <QMessageBox>
|
||||||
#include <QSplitter>
|
#include <QSplitter>
|
||||||
|
|
||||||
#include "interleaf.h"
|
|
||||||
#include "siview/siview.h"
|
#include "siview/siview.h"
|
||||||
|
|
||||||
using namespace si;
|
using namespace si;
|
||||||
|
@ -20,18 +19,45 @@ MainWindow::MainWindow(QWidget *parent) :
|
||||||
this->setCentralWidget(splitter);
|
this->setCentralWidget(splitter);
|
||||||
|
|
||||||
tree_ = new QTreeView();
|
tree_ = new QTreeView();
|
||||||
//tree_->setModel(&chunk_model_);
|
tree_->setModel(&model_);
|
||||||
tree_->setContextMenuPolicy(Qt::CustomContextMenu);
|
tree_->setContextMenuPolicy(Qt::CustomContextMenu);
|
||||||
connect(tree_->selectionModel(), &QItemSelectionModel::currentRowChanged, this, &MainWindow::SelectionChanged);
|
connect(tree_->selectionModel(), &QItemSelectionModel::currentRowChanged, this, &MainWindow::SelectionChanged);
|
||||||
connect(tree_, &QTreeView::customContextMenuRequested, this, &MainWindow::ShowContextMenu);
|
connect(tree_, &QTreeView::customContextMenuRequested, this, &MainWindow::ShowContextMenu);
|
||||||
splitter->addWidget(tree_);
|
splitter->addWidget(tree_);
|
||||||
|
|
||||||
|
auto config_area = new QWidget();
|
||||||
|
splitter->addWidget(config_area);
|
||||||
|
|
||||||
|
auto config_layout = new QVBoxLayout(config_area);
|
||||||
|
|
||||||
|
action_grp_ = new QGroupBox();
|
||||||
|
config_layout->addWidget(action_grp_);
|
||||||
|
|
||||||
|
auto action_layout = new QHBoxLayout(action_grp_);
|
||||||
|
|
||||||
|
action_layout->addStretch();
|
||||||
|
|
||||||
|
auto extract_btn = new QPushButton(tr("Extract"));
|
||||||
|
action_layout->addWidget(extract_btn);
|
||||||
|
connect(extract_btn, &QPushButton::clicked, this, &MainWindow::ExtractClicked);
|
||||||
|
|
||||||
|
auto replace_btn = new QPushButton(tr("Replace"));
|
||||||
|
action_layout->addWidget(replace_btn);
|
||||||
|
|
||||||
|
action_layout->addStretch();
|
||||||
|
|
||||||
config_stack_ = new QStackedWidget();
|
config_stack_ = new QStackedWidget();
|
||||||
splitter->addWidget(config_stack_);
|
config_layout->addWidget(config_stack_);
|
||||||
|
|
||||||
panel_blank_ = new Panel();
|
panel_blank_ = new Panel();
|
||||||
config_stack_->addWidget(panel_blank_);
|
config_stack_->addWidget(panel_blank_);
|
||||||
|
|
||||||
|
panel_wav_ = new WavPanel();
|
||||||
|
config_stack_->addWidget(panel_wav_);
|
||||||
|
|
||||||
|
panel_bmp_ = new BitmapPanel();
|
||||||
|
config_stack_->addWidget(panel_bmp_);
|
||||||
|
|
||||||
InitializeMenuBar();
|
InitializeMenuBar();
|
||||||
|
|
||||||
splitter->setSizes({99999, 99999});
|
splitter->setSizes({99999, 99999});
|
||||||
|
@ -43,8 +69,9 @@ void MainWindow::OpenFilename(const QString &s)
|
||||||
if (si.Read(s.toStdString())) {
|
if (si.Read(s.toStdString())) {
|
||||||
SIViewDialog d(SIViewDialog::Import, &si, this);
|
SIViewDialog d(SIViewDialog::Import, &si, this);
|
||||||
if (d.exec() == QDialog::Accepted) {
|
if (d.exec() == QDialog::Accepted) {
|
||||||
Interleaf interleaf;
|
model_.SetCore(nullptr);
|
||||||
interleaf.Parse(&si);
|
interleaf_.Parse(&si);
|
||||||
|
model_.SetCore(&interleaf_);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
QMessageBox::critical(this, QString(), tr("Failed to load Interleaf file."));
|
QMessageBox::critical(this, QString(), tr("Failed to load Interleaf file."));
|
||||||
|
@ -76,7 +103,7 @@ void MainWindow::InitializeMenuBar()
|
||||||
setMenuBar(menubar);
|
setMenuBar(menubar);
|
||||||
}
|
}
|
||||||
|
|
||||||
void MainWindow::SetPanel(Panel *panel, si::Chunk *chunk)
|
void MainWindow::SetPanel(Panel *panel, si::Object *chunk)
|
||||||
{
|
{
|
||||||
auto current = static_cast<Panel*>(config_stack_->currentWidget());
|
auto current = static_cast<Panel*>(config_stack_->currentWidget());
|
||||||
current->SetData(nullptr);
|
current->SetData(nullptr);
|
||||||
|
@ -84,6 +111,28 @@ void MainWindow::SetPanel(Panel *panel, si::Chunk *chunk)
|
||||||
config_stack_->setCurrentWidget(panel);
|
config_stack_->setCurrentWidget(panel);
|
||||||
panel->SetData(chunk);
|
panel->SetData(chunk);
|
||||||
last_set_data_ = chunk;
|
last_set_data_ = chunk;
|
||||||
|
|
||||||
|
action_grp_->setEnabled(chunk);
|
||||||
|
}
|
||||||
|
|
||||||
|
void MainWindow::ExtractObject(si::Object *obj)
|
||||||
|
{
|
||||||
|
QString filename = QString::fromStdString(obj->filename());
|
||||||
|
if (filename.isEmpty()) {
|
||||||
|
filename = QString::fromStdString(obj->name());
|
||||||
|
filename.append(QStringLiteral(".bin"));
|
||||||
|
}
|
||||||
|
|
||||||
|
QString s = QFileDialog::getSaveFileName(this, tr("Export Object"), filename);
|
||||||
|
if (!s.isEmpty()) {
|
||||||
|
QFile f(s);
|
||||||
|
if (f.open(QFile::WriteOnly)) {
|
||||||
|
f.write(obj->data().data(), obj->data().size());
|
||||||
|
f.close();
|
||||||
|
} else {
|
||||||
|
QMessageBox::critical(this, QString(), tr("Failed to write to file \"%1\".").arg(s));
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void MainWindow::OpenFile()
|
void MainWindow::OpenFile()
|
||||||
|
@ -97,10 +146,17 @@ void MainWindow::OpenFile()
|
||||||
void MainWindow::SelectionChanged(const QModelIndex &index)
|
void MainWindow::SelectionChanged(const QModelIndex &index)
|
||||||
{
|
{
|
||||||
Panel *p = panel_blank_;
|
Panel *p = panel_blank_;
|
||||||
Chunk *c = static_cast<Chunk*>(index.internalPointer());
|
Object *c = dynamic_cast<Object*>(static_cast<Core*>(index.internalPointer()));
|
||||||
|
|
||||||
if (c) {
|
if (c) {
|
||||||
// HECK
|
switch (c->filetype()) {
|
||||||
|
case MxOb::WAV:
|
||||||
|
p = panel_wav_;
|
||||||
|
break;
|
||||||
|
case MxOb::STL:
|
||||||
|
p = panel_bmp_;
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (p != config_stack_->currentWidget() || c != last_set_data_) {
|
if (p != config_stack_->currentWidget() || c != last_set_data_) {
|
||||||
|
@ -126,21 +182,13 @@ void MainWindow::ExtractSelectedItems()
|
||||||
}
|
}
|
||||||
|
|
||||||
for (const QModelIndex &i : selected) {
|
for (const QModelIndex &i : selected) {
|
||||||
if (Chunk *chunk = static_cast<Chunk*>(i.internalPointer())) {
|
if (Object *obj = dynamic_cast<Object*>(static_cast<Core*>(i.internalPointer()))) {
|
||||||
QString filename(chunk->data("FileName"));
|
ExtractObject(obj);
|
||||||
if (filename.isEmpty()) {
|
}
|
||||||
filename = QString(chunk->data("Name"));
|
|
||||||
filename.append(QStringLiteral(".bin"));
|
|
||||||
}
|
}
|
||||||
if (filename.isEmpty()) {
|
|
||||||
filename = QStringLiteral("%1_%2.bin").arg(QString::fromLatin1((const char *) &chunk->id(), sizeof(uint32_t)),
|
|
||||||
QString::number(chunk->offset(), 16));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
QString s = QFileDialog::getSaveFileName(this, tr("Export Object"), filename);
|
void MainWindow::ExtractClicked()
|
||||||
if (!s.isEmpty()) {
|
{
|
||||||
//chunk->Export()
|
ExtractObject(last_set_data_);
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,12 +1,17 @@
|
||||||
#ifndef MAINWINDOW_H
|
#ifndef MAINWINDOW_H
|
||||||
#define MAINWINDOW_H
|
#define MAINWINDOW_H
|
||||||
|
|
||||||
#include <chunk.h>
|
#include <interleaf.h>
|
||||||
|
#include <object.h>
|
||||||
|
#include <QGroupBox>
|
||||||
#include <QMainWindow>
|
#include <QMainWindow>
|
||||||
#include <QStackedWidget>
|
#include <QStackedWidget>
|
||||||
#include <QTreeView>
|
#include <QTreeView>
|
||||||
|
|
||||||
|
#include "objectmodel.h"
|
||||||
#include "panel.h"
|
#include "panel.h"
|
||||||
|
#include "viewer/bitmappanel.h"
|
||||||
|
#include "viewer/wavpanel.h"
|
||||||
|
|
||||||
class MainWindow : public QMainWindow
|
class MainWindow : public QMainWindow
|
||||||
{
|
{
|
||||||
|
@ -23,15 +28,24 @@ private:
|
||||||
|
|
||||||
void InitializeMenuBar();
|
void InitializeMenuBar();
|
||||||
|
|
||||||
void SetPanel(Panel *panel, si::Chunk *chunk);
|
void SetPanel(Panel *panel, si::Object *chunk);
|
||||||
|
|
||||||
|
void ExtractObject(si::Object *obj);
|
||||||
|
|
||||||
QStackedWidget *config_stack_;
|
QStackedWidget *config_stack_;
|
||||||
|
|
||||||
QTreeView *tree_;
|
QTreeView *tree_;
|
||||||
|
|
||||||
Panel *panel_blank_;
|
QGroupBox *action_grp_;
|
||||||
|
|
||||||
si::Chunk *last_set_data_;
|
Panel *panel_blank_;
|
||||||
|
WavPanel *panel_wav_;
|
||||||
|
BitmapPanel *panel_bmp_;
|
||||||
|
|
||||||
|
ObjectModel model_;
|
||||||
|
si::Interleaf interleaf_;
|
||||||
|
|
||||||
|
si::Object *last_set_data_;
|
||||||
|
|
||||||
private slots:
|
private slots:
|
||||||
void OpenFile();
|
void OpenFile();
|
||||||
|
@ -44,6 +58,8 @@ private slots:
|
||||||
|
|
||||||
void ExtractSelectedItems();
|
void ExtractSelectedItems();
|
||||||
|
|
||||||
|
void ExtractClicked();
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // MAINWINDOW_H
|
#endif // MAINWINDOW_H
|
||||||
|
|
67
app/model.cpp
Normal file
67
app/model.cpp
Normal file
|
@ -0,0 +1,67 @@
|
||||||
|
#include "model.h"
|
||||||
|
|
||||||
|
#define super QAbstractItemModel
|
||||||
|
|
||||||
|
Model::Model(QObject *parent) :
|
||||||
|
super(parent),
|
||||||
|
core_(nullptr)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void Model::SetCore(si::Core *c)
|
||||||
|
{
|
||||||
|
beginResetModel();
|
||||||
|
core_ = c;
|
||||||
|
endResetModel();
|
||||||
|
}
|
||||||
|
|
||||||
|
si::Core *Model::GetCoreFromIndex(const QModelIndex &index) const
|
||||||
|
{
|
||||||
|
if (!index.isValid()) {
|
||||||
|
return core_;
|
||||||
|
} else {
|
||||||
|
return static_cast<si::Core*>(index.internalPointer());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
QModelIndex Model::index(int row, int column, const QModelIndex &parent) const
|
||||||
|
{
|
||||||
|
si::Core *c = GetCoreFromIndex(parent);
|
||||||
|
if (!c) {
|
||||||
|
return QModelIndex();
|
||||||
|
}
|
||||||
|
|
||||||
|
return createIndex(row, column, c->GetChildAt(row));
|
||||||
|
}
|
||||||
|
|
||||||
|
QModelIndex Model::parent(const QModelIndex &index) const
|
||||||
|
{
|
||||||
|
si::Core *child = GetCoreFromIndex(index);
|
||||||
|
if (!child) {
|
||||||
|
return QModelIndex();
|
||||||
|
}
|
||||||
|
|
||||||
|
si::Core *parent = child->GetParent();
|
||||||
|
if (!parent) {
|
||||||
|
return QModelIndex();
|
||||||
|
}
|
||||||
|
|
||||||
|
si::Core *grandparent = parent->GetParent();
|
||||||
|
if (!grandparent) {
|
||||||
|
return QModelIndex();
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t row = grandparent->IndexOfChild(parent);
|
||||||
|
return createIndex(int(row), 0, parent);
|
||||||
|
}
|
||||||
|
|
||||||
|
int Model::rowCount(const QModelIndex &parent) const
|
||||||
|
{
|
||||||
|
si::Core *c = GetCoreFromIndex(parent);
|
||||||
|
if (!c) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return int(c->GetChildCount());
|
||||||
|
}
|
27
app/model.h
Normal file
27
app/model.h
Normal file
|
@ -0,0 +1,27 @@
|
||||||
|
#ifndef MODEL_H
|
||||||
|
#define MODEL_H
|
||||||
|
|
||||||
|
#include <core.h>
|
||||||
|
#include <QAbstractItemModel>
|
||||||
|
|
||||||
|
class Model : public QAbstractItemModel
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
explicit Model(QObject *parent = nullptr);
|
||||||
|
|
||||||
|
si::Core *GetCore() const { return core_; }
|
||||||
|
void SetCore(si::Core *c);
|
||||||
|
|
||||||
|
virtual QModelIndex index(int row, int column, const QModelIndex &parent = QModelIndex()) const override;
|
||||||
|
virtual QModelIndex parent(const QModelIndex &index) const override;
|
||||||
|
virtual int rowCount(const QModelIndex &parent = QModelIndex()) const override;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
si::Core *GetCoreFromIndex(const QModelIndex &index) const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
si::Core *core_;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // MODEL_H
|
|
@ -1,8 +1,8 @@
|
||||||
#include "objectmodel.h"
|
#include "objectmodel.h"
|
||||||
|
|
||||||
#include <chunk.h>
|
#include <object.h>
|
||||||
|
|
||||||
#define super QAbstractItemModel
|
#define super Model
|
||||||
|
|
||||||
using namespace si;
|
using namespace si;
|
||||||
|
|
||||||
|
@ -16,49 +16,23 @@ int ObjectModel::columnCount(const QModelIndex &parent) const
|
||||||
return kColCount;
|
return kColCount;
|
||||||
}
|
}
|
||||||
|
|
||||||
QModelIndex ObjectModel::index(int row, int column, const QModelIndex &parent) const
|
|
||||||
{
|
|
||||||
return createIndex(row, column, GetItem(row));
|
|
||||||
}
|
|
||||||
|
|
||||||
QModelIndex ObjectModel::parent(const QModelIndex &index) const
|
|
||||||
{
|
|
||||||
return QModelIndex();
|
|
||||||
}
|
|
||||||
|
|
||||||
int ObjectModel::rowCount(const QModelIndex &parent) const
|
|
||||||
{
|
|
||||||
if (parent.isValid()) {
|
|
||||||
return 0;
|
|
||||||
} else {
|
|
||||||
Chunk *mxof = GetMxOf();
|
|
||||||
if (!mxof) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
return int(mxof->data("Offsets").size() / sizeof(uint32_t));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
QVariant ObjectModel::data(const QModelIndex &index, int role) const
|
QVariant ObjectModel::data(const QModelIndex &index, int role) const
|
||||||
{
|
{
|
||||||
uint32_t offset;
|
Core *c = GetCoreFromIndex(index);
|
||||||
Chunk *c = GetItem(index.row(), &offset);
|
|
||||||
|
|
||||||
switch (role) {
|
switch (role) {
|
||||||
case Qt::DisplayRole:
|
case Qt::DisplayRole:
|
||||||
|
|
||||||
switch (index.column()) {
|
switch (index.column()) {
|
||||||
case kColIndex:
|
case kColIndex:
|
||||||
return index.row();
|
if (Object *o = dynamic_cast<Object*>(c)) {
|
||||||
case kColOffset:
|
return QString::number(o->id());
|
||||||
return QStringLiteral("0x%1").arg(QString::number(offset, 16).toUpper());
|
|
||||||
case kColName:
|
|
||||||
if (c) {
|
|
||||||
Chunk *mxob = c->FindChildWithType(Chunk::TYPE_MxOb);
|
|
||||||
if (mxob) {
|
|
||||||
return QString(mxob->data("Name"));
|
|
||||||
}
|
}
|
||||||
|
//return index.row();
|
||||||
|
break;
|
||||||
|
case kColName:
|
||||||
|
if (Object *o = dynamic_cast<Object*>(c)) {
|
||||||
|
return QString::fromStdString(o->name());
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -75,8 +49,6 @@ QVariant ObjectModel::headerData(int section, Qt::Orientation orientation, int r
|
||||||
switch (section) {
|
switch (section) {
|
||||||
case kColIndex:
|
case kColIndex:
|
||||||
return tr("Index");
|
return tr("Index");
|
||||||
case kColOffset:
|
|
||||||
return tr("Offset");
|
|
||||||
case kColName:
|
case kColName:
|
||||||
return tr("Name");
|
return tr("Name");
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,9 +1,11 @@
|
||||||
#ifndef OBJECTMODEL_H
|
#ifndef OBJECTMODEL_H
|
||||||
#define OBJECTMODEL_H
|
#define OBJECTMODEL_H
|
||||||
|
|
||||||
#include <QAbstractItemModel>
|
#include <interleaf.h>
|
||||||
|
|
||||||
class ObjectModel : public QAbstractItemModel
|
#include "model.h"
|
||||||
|
|
||||||
|
class ObjectModel : public Model
|
||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
public:
|
public:
|
||||||
|
@ -17,9 +19,6 @@ public:
|
||||||
explicit ObjectModel(QObject *parent = nullptr);
|
explicit ObjectModel(QObject *parent = nullptr);
|
||||||
|
|
||||||
virtual int columnCount(const QModelIndex &parent = QModelIndex()) const override;
|
virtual int columnCount(const QModelIndex &parent = QModelIndex()) const override;
|
||||||
virtual QModelIndex index(int row, int column, const QModelIndex &parent = QModelIndex()) const override;
|
|
||||||
virtual QModelIndex parent(const QModelIndex &index) const override;
|
|
||||||
virtual int rowCount(const QModelIndex &parent = QModelIndex()) const override;
|
|
||||||
virtual QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override;
|
virtual QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override;
|
||||||
virtual QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const override;
|
virtual QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const override;
|
||||||
|
|
||||||
|
|
|
@ -10,6 +10,7 @@ class Panel : public QWidget
|
||||||
public:
|
public:
|
||||||
explicit Panel(QWidget *parent = nullptr);
|
explicit Panel(QWidget *parent = nullptr);
|
||||||
|
|
||||||
|
void *GetData() const { return data_; }
|
||||||
void SetData(void *data);
|
void SetData(void *data);
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
|
|
|
@ -2,13 +2,12 @@
|
||||||
|
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
|
|
||||||
#define super QAbstractItemModel
|
#define super Model
|
||||||
|
|
||||||
using namespace si;
|
using namespace si;
|
||||||
|
|
||||||
ChunkModel::ChunkModel(QObject *parent) :
|
ChunkModel::ChunkModel(QObject *parent) :
|
||||||
super{parent},
|
super{parent}
|
||||||
chunk_(nullptr)
|
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -17,50 +16,9 @@ int ChunkModel::columnCount(const QModelIndex &parent) const
|
||||||
return kColCount;
|
return kColCount;
|
||||||
}
|
}
|
||||||
|
|
||||||
QModelIndex ChunkModel::index(int row, int column, const QModelIndex &parent) const
|
|
||||||
{
|
|
||||||
Chunk *c = GetChunkFromIndex(parent);
|
|
||||||
if (!c) {
|
|
||||||
return QModelIndex();
|
|
||||||
}
|
|
||||||
|
|
||||||
return createIndex(row, column, c->GetChildAt(row));
|
|
||||||
}
|
|
||||||
|
|
||||||
QModelIndex ChunkModel::parent(const QModelIndex &index) const
|
|
||||||
{
|
|
||||||
Chunk *child = GetChunkFromIndex(index);
|
|
||||||
if (!child) {
|
|
||||||
return QModelIndex();
|
|
||||||
}
|
|
||||||
|
|
||||||
Core *parent = child->GetParent();
|
|
||||||
if (!parent) {
|
|
||||||
return QModelIndex();
|
|
||||||
}
|
|
||||||
|
|
||||||
Core *grandparent = parent->GetParent();
|
|
||||||
if (!grandparent) {
|
|
||||||
return QModelIndex();
|
|
||||||
}
|
|
||||||
|
|
||||||
size_t row = grandparent->IndexOfChild(parent);
|
|
||||||
return createIndex(int(row), 0, parent);
|
|
||||||
}
|
|
||||||
|
|
||||||
int ChunkModel::rowCount(const QModelIndex &parent) const
|
|
||||||
{
|
|
||||||
Chunk *c = GetChunkFromIndex(parent);
|
|
||||||
if (!c) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
return int(c->GetChildCount());
|
|
||||||
}
|
|
||||||
|
|
||||||
QVariant ChunkModel::data(const QModelIndex &index, int role) const
|
QVariant ChunkModel::data(const QModelIndex &index, int role) const
|
||||||
{
|
{
|
||||||
Chunk *c = GetChunkFromIndex(index);
|
Chunk *c = static_cast<Chunk*>(GetCoreFromIndex(index));
|
||||||
if (!c) {
|
if (!c) {
|
||||||
return QVariant();
|
return QVariant();
|
||||||
}
|
}
|
||||||
|
@ -108,19 +66,3 @@ QVariant ChunkModel::headerData(int section, Qt::Orientation orientation, int ro
|
||||||
|
|
||||||
return super::headerData(section, orientation, role);
|
return super::headerData(section, orientation, role);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ChunkModel::SetChunk(si::Chunk *c)
|
|
||||||
{
|
|
||||||
beginResetModel();
|
|
||||||
chunk_ = c;
|
|
||||||
endResetModel();
|
|
||||||
}
|
|
||||||
|
|
||||||
si::Chunk *ChunkModel::GetChunkFromIndex(const QModelIndex &index) const
|
|
||||||
{
|
|
||||||
if (!index.isValid()) {
|
|
||||||
return chunk_;
|
|
||||||
} else {
|
|
||||||
return static_cast<Chunk*>(index.internalPointer());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
@ -2,9 +2,10 @@
|
||||||
#define CHUNKMODEL_H
|
#define CHUNKMODEL_H
|
||||||
|
|
||||||
#include <chunk.h>
|
#include <chunk.h>
|
||||||
#include <QAbstractItemModel>
|
|
||||||
|
|
||||||
class ChunkModel : public QAbstractItemModel
|
#include "model.h"
|
||||||
|
|
||||||
|
class ChunkModel : public Model
|
||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
public:
|
public:
|
||||||
|
@ -21,22 +22,9 @@ public:
|
||||||
explicit ChunkModel(QObject *parent = nullptr);
|
explicit ChunkModel(QObject *parent = nullptr);
|
||||||
|
|
||||||
virtual int columnCount(const QModelIndex &parent = QModelIndex()) const override;
|
virtual int columnCount(const QModelIndex &parent = QModelIndex()) const override;
|
||||||
virtual QModelIndex index(int row, int column, const QModelIndex &parent = QModelIndex()) const override;
|
|
||||||
virtual QModelIndex parent(const QModelIndex &index) const override;
|
|
||||||
virtual int rowCount(const QModelIndex &parent = QModelIndex()) const override;
|
|
||||||
virtual QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override;
|
virtual QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override;
|
||||||
virtual QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const override;
|
virtual QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const override;
|
||||||
|
|
||||||
void SetChunk(si::Chunk *c);
|
|
||||||
|
|
||||||
protected:
|
|
||||||
si::Chunk *GetChunkFromIndex(const QModelIndex &index) const;
|
|
||||||
|
|
||||||
si::Chunk *root() const { return chunk_; }
|
|
||||||
|
|
||||||
private:
|
|
||||||
si::Chunk *chunk_;
|
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // CHUNKMODEL_H
|
#endif // CHUNKMODEL_H
|
||||||
|
|
|
@ -71,6 +71,17 @@ MxChPanel::MxChPanel(QWidget *parent) :
|
||||||
data_sz_edit_->setMaximum(INT_MAX);
|
data_sz_edit_->setMaximum(INT_MAX);
|
||||||
layout()->addWidget(data_sz_edit_, row, 1);
|
layout()->addWidget(data_sz_edit_, row, 1);
|
||||||
|
|
||||||
|
row++;
|
||||||
|
|
||||||
|
show_data_btn_ = new QPushButton(tr("Show Data"));
|
||||||
|
connect(show_data_btn_, &QPushButton::clicked, this, &MxChPanel::ShowDataField);
|
||||||
|
layout()->addWidget(show_data_btn_, row, 0, 1, 2);
|
||||||
|
|
||||||
|
data_edit_ = new QTextEdit();
|
||||||
|
data_edit_->setFont(QFontDatabase::systemFont(QFontDatabase::FixedFont));
|
||||||
|
layout()->addWidget(data_edit_, row, 0, 1, 2);
|
||||||
|
data_edit_->hide();
|
||||||
|
|
||||||
FinishLayout();
|
FinishLayout();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -99,6 +110,10 @@ void MxChPanel::OnClosingData(void *data)
|
||||||
chunk->data("Object") = u32(obj_edit_->value());
|
chunk->data("Object") = u32(obj_edit_->value());
|
||||||
chunk->data("Time") = u32(ms_offset_edit_->value());
|
chunk->data("Time") = u32(ms_offset_edit_->value());
|
||||||
chunk->data("DataSize") = u32(data_sz_edit_->value());*/
|
chunk->data("DataSize") = u32(data_sz_edit_->value());*/
|
||||||
|
|
||||||
|
show_data_btn_->show();
|
||||||
|
data_edit_->clear();
|
||||||
|
data_edit_->hide();
|
||||||
}
|
}
|
||||||
|
|
||||||
void MxChPanel::FlagCheckBoxClicked(bool e)
|
void MxChPanel::FlagCheckBoxClicked(bool e)
|
||||||
|
@ -116,3 +131,15 @@ void MxChPanel::FlagCheckBoxClicked(bool e)
|
||||||
flag_edit_->setText(QString::number(current, 16));
|
flag_edit_->setText(QString::number(current, 16));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void MxChPanel::ShowDataField()
|
||||||
|
{
|
||||||
|
show_data_btn_->hide();
|
||||||
|
data_edit_->show();
|
||||||
|
|
||||||
|
Chunk *chunk = static_cast<Chunk*>(GetData());
|
||||||
|
|
||||||
|
const Data &data = chunk->data("Data");
|
||||||
|
QByteArray ba(data.data(), int(data.size()));
|
||||||
|
data_edit_->setPlainText(ba.toHex());
|
||||||
|
}
|
||||||
|
|
|
@ -3,6 +3,7 @@
|
||||||
|
|
||||||
#include <QCheckBox>
|
#include <QCheckBox>
|
||||||
#include <QLineEdit>
|
#include <QLineEdit>
|
||||||
|
#include <QPushButton>
|
||||||
#include <QSpinBox>
|
#include <QSpinBox>
|
||||||
#include <QTextEdit>
|
#include <QTextEdit>
|
||||||
|
|
||||||
|
@ -23,12 +24,16 @@ private:
|
||||||
QSpinBox *obj_edit_;
|
QSpinBox *obj_edit_;
|
||||||
QSpinBox *ms_offset_edit_;
|
QSpinBox *ms_offset_edit_;
|
||||||
QSpinBox *data_sz_edit_;
|
QSpinBox *data_sz_edit_;
|
||||||
|
QTextEdit *data_edit_;
|
||||||
|
QPushButton *show_data_btn_;
|
||||||
|
|
||||||
QVector<QCheckBox*> flag_checkboxes_;
|
QVector<QCheckBox*> flag_checkboxes_;
|
||||||
|
|
||||||
private slots:
|
private slots:
|
||||||
void FlagCheckBoxClicked(bool e);
|
void FlagCheckBoxClicked(bool e);
|
||||||
|
|
||||||
|
void ShowDataField();
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // MXCHPANEL_H
|
#endif // MXCHPANEL_H
|
||||||
|
|
|
@ -20,7 +20,7 @@ SIViewDialog::SIViewDialog(Mode mode, Chunk *riff, QWidget *parent) :
|
||||||
layout->addWidget(splitter);
|
layout->addWidget(splitter);
|
||||||
|
|
||||||
auto tree = new QTreeView();
|
auto tree = new QTreeView();
|
||||||
chunk_model_.SetChunk(riff);
|
chunk_model_.SetCore(riff);
|
||||||
tree->setModel(&chunk_model_);
|
tree->setModel(&chunk_model_);
|
||||||
tree->setContextMenuPolicy(Qt::CustomContextMenu);
|
tree->setContextMenuPolicy(Qt::CustomContextMenu);
|
||||||
connect(tree->selectionModel(), &QItemSelectionModel::currentRowChanged, this, &SIViewDialog::SelectionChanged);
|
connect(tree->selectionModel(), &QItemSelectionModel::currentRowChanged, this, &SIViewDialog::SelectionChanged);
|
||||||
|
@ -53,6 +53,7 @@ SIViewDialog::SIViewDialog(Mode mode, Chunk *riff, QWidget *parent) :
|
||||||
btn_layout->addStretch();
|
btn_layout->addStretch();
|
||||||
|
|
||||||
auto accept_btn = new QPushButton(mode == Import ? tr("De-Weave") : tr("Weave"));
|
auto accept_btn = new QPushButton(mode == Import ? tr("De-Weave") : tr("Weave"));
|
||||||
|
accept_btn->setDefault(true);
|
||||||
connect(accept_btn, &QPushButton::clicked, this, &SIViewDialog::accept);
|
connect(accept_btn, &QPushButton::clicked, this, &SIViewDialog::accept);
|
||||||
btn_layout->addWidget(accept_btn);
|
btn_layout->addWidget(accept_btn);
|
||||||
|
|
||||||
|
|
39
app/viewer/bitmappanel.cpp
Normal file
39
app/viewer/bitmappanel.cpp
Normal file
|
@ -0,0 +1,39 @@
|
||||||
|
#include "bitmappanel.h"
|
||||||
|
|
||||||
|
#include <object.h>
|
||||||
|
#include <QBuffer>
|
||||||
|
#include <QGroupBox>
|
||||||
|
|
||||||
|
BitmapPanel::BitmapPanel(QWidget *parent)
|
||||||
|
{
|
||||||
|
int row = 0;
|
||||||
|
|
||||||
|
auto preview_grp = new QGroupBox(tr("Bitmap"));
|
||||||
|
layout()->addWidget(preview_grp, row, 0, 1, 2);
|
||||||
|
|
||||||
|
auto preview_layout = new QVBoxLayout(preview_grp);
|
||||||
|
|
||||||
|
img_lbl_ = new QLabel();
|
||||||
|
img_lbl_->setAlignment(Qt::AlignHCenter);
|
||||||
|
preview_layout->addWidget(img_lbl_);
|
||||||
|
|
||||||
|
desc_lbl_ = new QLabel();
|
||||||
|
desc_lbl_->setAlignment(Qt::AlignHCenter);
|
||||||
|
preview_layout->addWidget(desc_lbl_);
|
||||||
|
|
||||||
|
FinishLayout();
|
||||||
|
}
|
||||||
|
|
||||||
|
void BitmapPanel::OnOpeningData(void *data)
|
||||||
|
{
|
||||||
|
si::Object *o = static_cast<si::Object*>(data);
|
||||||
|
|
||||||
|
QByteArray b(o->data().data(), o->data().size());
|
||||||
|
QBuffer buf(&b);
|
||||||
|
QImage img;
|
||||||
|
img.load(&buf, "BMP");
|
||||||
|
|
||||||
|
img_lbl_->setPixmap(QPixmap::fromImage(img));
|
||||||
|
|
||||||
|
desc_lbl_->setText(tr("%1x%2").arg(QString::number(img.width()), QString::number(img.height())));
|
||||||
|
}
|
24
app/viewer/bitmappanel.h
Normal file
24
app/viewer/bitmappanel.h
Normal file
|
@ -0,0 +1,24 @@
|
||||||
|
#ifndef BITMAPPANEL_H
|
||||||
|
#define BITMAPPANEL_H
|
||||||
|
|
||||||
|
#include <panel.h>
|
||||||
|
#include <QLabel>
|
||||||
|
|
||||||
|
class BitmapPanel : public Panel
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
public:
|
||||||
|
BitmapPanel(QWidget *parent = nullptr);
|
||||||
|
|
||||||
|
protected:
|
||||||
|
virtual void OnOpeningData(void *data) override;
|
||||||
|
//virtual void OnClosingData(void *data) override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
QLabel *img_lbl_;
|
||||||
|
|
||||||
|
QLabel *desc_lbl_;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // BITMAPPANEL_H
|
146
app/viewer/wavpanel.cpp
Normal file
146
app/viewer/wavpanel.cpp
Normal file
|
@ -0,0 +1,146 @@
|
||||||
|
#include "wavpanel.h"
|
||||||
|
|
||||||
|
#include <iostream>
|
||||||
|
#include <object.h>
|
||||||
|
#include <QGroupBox>
|
||||||
|
#include <QHBoxLayout>
|
||||||
|
|
||||||
|
WavPanel::WavPanel(QWidget *parent) :
|
||||||
|
Panel(parent),
|
||||||
|
audio_out_(nullptr)
|
||||||
|
{
|
||||||
|
int row = 0;
|
||||||
|
|
||||||
|
auto wav_group = new QGroupBox(tr("Playback"));
|
||||||
|
layout()->addWidget(wav_group, row, 0, 1, 2);
|
||||||
|
|
||||||
|
auto wav_layout = new QHBoxLayout(wav_group);
|
||||||
|
|
||||||
|
playhead_slider_ = new QSlider(Qt::Horizontal);
|
||||||
|
playhead_slider_->setMinimum(0);
|
||||||
|
connect(playhead_slider_, &QSlider::valueChanged, this, &WavPanel::SliderMoved);
|
||||||
|
wav_layout->addWidget(playhead_slider_);
|
||||||
|
|
||||||
|
play_btn_ = new QPushButton(tr("Play"));
|
||||||
|
play_btn_->setCheckable(true);
|
||||||
|
connect(play_btn_, &QPushButton::clicked, this, &WavPanel::Play);
|
||||||
|
wav_layout->addWidget(play_btn_);
|
||||||
|
|
||||||
|
FinishLayout();
|
||||||
|
|
||||||
|
buffer_.setBuffer(&array_);
|
||||||
|
|
||||||
|
playback_timer_ = new QTimer(this);
|
||||||
|
playback_timer_->setInterval(100);
|
||||||
|
connect(playback_timer_, &QTimer::timeout, this, &WavPanel::TimerUpdate);
|
||||||
|
}
|
||||||
|
|
||||||
|
void WavPanel::OnOpeningData(void *data)
|
||||||
|
{
|
||||||
|
si::Object *o = static_cast<si::Object*>(data);
|
||||||
|
|
||||||
|
// Find fmt and data
|
||||||
|
auto dat = o->data().data();
|
||||||
|
for (size_t i=0; i<o->data().size(); i++) {
|
||||||
|
if (!memcmp(dat+i, "fmt ", 4)) {
|
||||||
|
header_ = *(si::WAVFormatHeader *)(dat+i+8);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (size_t i=0; i<o->data().size(); i++) {
|
||||||
|
if (!memcmp(dat+i, "data", 4)) {
|
||||||
|
uint32_t sz = *(uint32_t*)(dat+i+4);
|
||||||
|
playhead_slider_->setMaximum(sz/GetSampleSize());
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void WavPanel::OnClosingData(void *data)
|
||||||
|
{
|
||||||
|
Play(false);
|
||||||
|
playhead_slider_->setValue(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
int WavPanel::GetSampleSize() const
|
||||||
|
{
|
||||||
|
return (header_.BitsPerSample/8) * header_.Channels;
|
||||||
|
}
|
||||||
|
|
||||||
|
void WavPanel::Play(bool e)
|
||||||
|
{
|
||||||
|
if (audio_out_) {
|
||||||
|
audio_out_->stop();
|
||||||
|
//audio_out_->deleteLater();
|
||||||
|
delete audio_out_;
|
||||||
|
audio_out_ = nullptr;
|
||||||
|
}
|
||||||
|
buffer_.close();
|
||||||
|
playback_timer_->stop();
|
||||||
|
|
||||||
|
if (e) {
|
||||||
|
const si::bytearray &lib = static_cast<si::Object*>(GetData())->data();
|
||||||
|
array_ = QByteArray(lib.data(), lib.size());
|
||||||
|
buffer_.open(QBuffer::ReadOnly);
|
||||||
|
|
||||||
|
size_t start = 0;
|
||||||
|
si::WAVFormatHeader header;
|
||||||
|
|
||||||
|
// Find fmt and data
|
||||||
|
auto dat = lib.data();
|
||||||
|
for (size_t i=0; i<lib.size(); i++) {
|
||||||
|
if (!memcmp(dat+i, "fmt ", 4)) {
|
||||||
|
header = *(si::WAVFormatHeader *)(dat+i+8);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (size_t i=0; i<lib.size(); i++) {
|
||||||
|
if (!memcmp(dat+i, "data", 4)) {
|
||||||
|
start = i + 8;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
buffer_start_ = start;
|
||||||
|
|
||||||
|
if (playhead_slider_->value() < playhead_slider_->maximum()) {
|
||||||
|
start += playhead_slider_->value() * GetSampleSize();
|
||||||
|
}
|
||||||
|
|
||||||
|
buffer_.seek(start);
|
||||||
|
|
||||||
|
QAudioFormat audio_fmt;
|
||||||
|
audio_fmt.setSampleRate(header.SampleRate);
|
||||||
|
audio_fmt.setChannelCount(header.Channels);
|
||||||
|
audio_fmt.setSampleSize(header.BitsPerSample);
|
||||||
|
audio_fmt.setByteOrder(QAudioFormat::LittleEndian);
|
||||||
|
audio_fmt.setCodec(QStringLiteral("audio/pcm"));
|
||||||
|
audio_fmt.setSampleType(QAudioFormat::SignedInt);
|
||||||
|
|
||||||
|
audio_out_ = new QAudioOutput(audio_fmt, this);
|
||||||
|
connect(audio_out_, &QAudioOutput::stateChanged, this, &WavPanel::OutputChanged);
|
||||||
|
audio_out_->start(&buffer_);
|
||||||
|
|
||||||
|
playback_timer_->start();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void WavPanel::TimerUpdate()
|
||||||
|
{
|
||||||
|
playhead_slider_->setValue((buffer_.pos() - buffer_start_) / GetSampleSize());
|
||||||
|
}
|
||||||
|
|
||||||
|
void WavPanel::OutputChanged(QAudio::State state)
|
||||||
|
{
|
||||||
|
if (state != QAudio::ActiveState) {
|
||||||
|
Play(false);
|
||||||
|
play_btn_->setChecked(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void WavPanel::SliderMoved(int i)
|
||||||
|
{
|
||||||
|
if (buffer_.isOpen()) {
|
||||||
|
buffer_.seek(buffer_start_ + i * GetSampleSize());
|
||||||
|
}
|
||||||
|
}
|
48
app/viewer/wavpanel.h
Normal file
48
app/viewer/wavpanel.h
Normal file
|
@ -0,0 +1,48 @@
|
||||||
|
#ifndef WAVPANEL_H
|
||||||
|
#define WAVPANEL_H
|
||||||
|
|
||||||
|
#include <sitypes.h>
|
||||||
|
#include <QAudioOutput>
|
||||||
|
#include <QBuffer>
|
||||||
|
#include <QByteArray>
|
||||||
|
#include <QPushButton>
|
||||||
|
#include <QSlider>
|
||||||
|
#include <QTimer>
|
||||||
|
|
||||||
|
#include "panel.h"
|
||||||
|
|
||||||
|
class WavPanel : public Panel
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
public:
|
||||||
|
WavPanel(QWidget *parent = nullptr);
|
||||||
|
|
||||||
|
protected:
|
||||||
|
virtual void OnOpeningData(void *data) override;
|
||||||
|
virtual void OnClosingData(void *data) override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
int GetSampleSize() const;
|
||||||
|
|
||||||
|
QSlider *playhead_slider_;
|
||||||
|
QPushButton *play_btn_;
|
||||||
|
|
||||||
|
QAudioOutput *audio_out_;
|
||||||
|
QBuffer buffer_;
|
||||||
|
QByteArray array_;
|
||||||
|
size_t buffer_start_;
|
||||||
|
QTimer *playback_timer_;
|
||||||
|
si::WAVFormatHeader header_;
|
||||||
|
|
||||||
|
private slots:
|
||||||
|
void Play(bool e);
|
||||||
|
|
||||||
|
void TimerUpdate();
|
||||||
|
|
||||||
|
void OutputChanged(QAudio::State state);
|
||||||
|
|
||||||
|
void SliderMoved(int i);
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // WAVPANEL_H
|
Loading…
Reference in a new issue