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(QT NAMES Qt6 Qt5 REQUIRED COMPONENTS Widgets)
|
||||
find_package(Qt${QT_VERSION_MAJOR} REQUIRED COMPONENTS Widgets)
|
||||
find_package(QT NAMES Qt6 Qt5 REQUIRED COMPONENTS Widgets Multimedia)
|
||||
find_package(Qt${QT_VERSION_MAJOR} REQUIRED COMPONENTS Widgets Multimedia)
|
||||
|
||||
set(PROJECT_SOURCES
|
||||
siview/chunkmodel.cpp
|
||||
|
@ -19,11 +19,18 @@ set(PROJECT_SOURCES
|
|||
siview/siview.cpp
|
||||
siview/siview.h
|
||||
|
||||
viewer/bitmappanel.cpp
|
||||
viewer/bitmappanel.h
|
||||
viewer/wavpanel.cpp
|
||||
viewer/wavpanel.h
|
||||
|
||||
main.cpp
|
||||
mainwindow.cpp
|
||||
mainwindow.h
|
||||
#objectmodel.cpp
|
||||
#objectmodel.h
|
||||
model.cpp
|
||||
model.h
|
||||
objectmodel.cpp
|
||||
objectmodel.h
|
||||
panel.cpp
|
||||
panel.h
|
||||
vector3edit.cpp
|
||||
|
@ -43,7 +50,7 @@ else()
|
|||
)
|
||||
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")
|
||||
|
||||
set_target_properties(si-edit PROPERTIES
|
||||
|
|
|
@ -6,7 +6,6 @@
|
|||
#include <QMessageBox>
|
||||
#include <QSplitter>
|
||||
|
||||
#include "interleaf.h"
|
||||
#include "siview/siview.h"
|
||||
|
||||
using namespace si;
|
||||
|
@ -20,18 +19,45 @@ MainWindow::MainWindow(QWidget *parent) :
|
|||
this->setCentralWidget(splitter);
|
||||
|
||||
tree_ = new QTreeView();
|
||||
//tree_->setModel(&chunk_model_);
|
||||
tree_->setModel(&model_);
|
||||
tree_->setContextMenuPolicy(Qt::CustomContextMenu);
|
||||
connect(tree_->selectionModel(), &QItemSelectionModel::currentRowChanged, this, &MainWindow::SelectionChanged);
|
||||
connect(tree_, &QTreeView::customContextMenuRequested, this, &MainWindow::ShowContextMenu);
|
||||
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();
|
||||
splitter->addWidget(config_stack_);
|
||||
config_layout->addWidget(config_stack_);
|
||||
|
||||
panel_blank_ = new Panel();
|
||||
config_stack_->addWidget(panel_blank_);
|
||||
|
||||
panel_wav_ = new WavPanel();
|
||||
config_stack_->addWidget(panel_wav_);
|
||||
|
||||
panel_bmp_ = new BitmapPanel();
|
||||
config_stack_->addWidget(panel_bmp_);
|
||||
|
||||
InitializeMenuBar();
|
||||
|
||||
splitter->setSizes({99999, 99999});
|
||||
|
@ -43,8 +69,9 @@ void MainWindow::OpenFilename(const QString &s)
|
|||
if (si.Read(s.toStdString())) {
|
||||
SIViewDialog d(SIViewDialog::Import, &si, this);
|
||||
if (d.exec() == QDialog::Accepted) {
|
||||
Interleaf interleaf;
|
||||
interleaf.Parse(&si);
|
||||
model_.SetCore(nullptr);
|
||||
interleaf_.Parse(&si);
|
||||
model_.SetCore(&interleaf_);
|
||||
}
|
||||
} else {
|
||||
QMessageBox::critical(this, QString(), tr("Failed to load Interleaf file."));
|
||||
|
@ -76,7 +103,7 @@ void MainWindow::InitializeMenuBar()
|
|||
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());
|
||||
current->SetData(nullptr);
|
||||
|
@ -84,6 +111,28 @@ void MainWindow::SetPanel(Panel *panel, si::Chunk *chunk)
|
|||
config_stack_->setCurrentWidget(panel);
|
||||
panel->SetData(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()
|
||||
|
@ -97,10 +146,17 @@ void MainWindow::OpenFile()
|
|||
void MainWindow::SelectionChanged(const QModelIndex &index)
|
||||
{
|
||||
Panel *p = panel_blank_;
|
||||
Chunk *c = static_cast<Chunk*>(index.internalPointer());
|
||||
Object *c = dynamic_cast<Object*>(static_cast<Core*>(index.internalPointer()));
|
||||
|
||||
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_) {
|
||||
|
@ -126,21 +182,13 @@ void MainWindow::ExtractSelectedItems()
|
|||
}
|
||||
|
||||
for (const QModelIndex &i : selected) {
|
||||
if (Chunk *chunk = static_cast<Chunk*>(i.internalPointer())) {
|
||||
QString filename(chunk->data("FileName"));
|
||||
if (filename.isEmpty()) {
|
||||
filename = QString(chunk->data("Name"));
|
||||
filename.append(QStringLiteral(".bin"));
|
||||
if (Object *obj = dynamic_cast<Object*>(static_cast<Core*>(i.internalPointer()))) {
|
||||
ExtractObject(obj);
|
||||
}
|
||||
}
|
||||
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);
|
||||
if (!s.isEmpty()) {
|
||||
//chunk->Export()
|
||||
}
|
||||
}
|
||||
}
|
||||
void MainWindow::ExtractClicked()
|
||||
{
|
||||
ExtractObject(last_set_data_);
|
||||
}
|
||||
|
|
|
@ -1,12 +1,17 @@
|
|||
#ifndef MAINWINDOW_H
|
||||
#define MAINWINDOW_H
|
||||
|
||||
#include <chunk.h>
|
||||
#include <interleaf.h>
|
||||
#include <object.h>
|
||||
#include <QGroupBox>
|
||||
#include <QMainWindow>
|
||||
#include <QStackedWidget>
|
||||
#include <QTreeView>
|
||||
|
||||
#include "objectmodel.h"
|
||||
#include "panel.h"
|
||||
#include "viewer/bitmappanel.h"
|
||||
#include "viewer/wavpanel.h"
|
||||
|
||||
class MainWindow : public QMainWindow
|
||||
{
|
||||
|
@ -23,15 +28,24 @@ private:
|
|||
|
||||
void InitializeMenuBar();
|
||||
|
||||
void SetPanel(Panel *panel, si::Chunk *chunk);
|
||||
void SetPanel(Panel *panel, si::Object *chunk);
|
||||
|
||||
void ExtractObject(si::Object *obj);
|
||||
|
||||
QStackedWidget *config_stack_;
|
||||
|
||||
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:
|
||||
void OpenFile();
|
||||
|
@ -44,6 +58,8 @@ private slots:
|
|||
|
||||
void ExtractSelectedItems();
|
||||
|
||||
void ExtractClicked();
|
||||
|
||||
};
|
||||
|
||||
#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 <chunk.h>
|
||||
#include <object.h>
|
||||
|
||||
#define super QAbstractItemModel
|
||||
#define super Model
|
||||
|
||||
using namespace si;
|
||||
|
||||
|
@ -16,49 +16,23 @@ int ObjectModel::columnCount(const QModelIndex &parent) const
|
|||
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
|
||||
{
|
||||
uint32_t offset;
|
||||
Chunk *c = GetItem(index.row(), &offset);
|
||||
Core *c = GetCoreFromIndex(index);
|
||||
|
||||
switch (role) {
|
||||
case Qt::DisplayRole:
|
||||
|
||||
switch (index.column()) {
|
||||
case kColIndex:
|
||||
return index.row();
|
||||
case kColOffset:
|
||||
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"));
|
||||
if (Object *o = dynamic_cast<Object*>(c)) {
|
||||
return QString::number(o->id());
|
||||
}
|
||||
//return index.row();
|
||||
break;
|
||||
case kColName:
|
||||
if (Object *o = dynamic_cast<Object*>(c)) {
|
||||
return QString::fromStdString(o->name());
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
@ -75,8 +49,6 @@ QVariant ObjectModel::headerData(int section, Qt::Orientation orientation, int r
|
|||
switch (section) {
|
||||
case kColIndex:
|
||||
return tr("Index");
|
||||
case kColOffset:
|
||||
return tr("Offset");
|
||||
case kColName:
|
||||
return tr("Name");
|
||||
}
|
||||
|
|
|
@ -1,9 +1,11 @@
|
|||
#ifndef OBJECTMODEL_H
|
||||
#define OBJECTMODEL_H
|
||||
|
||||
#include <QAbstractItemModel>
|
||||
#include <interleaf.h>
|
||||
|
||||
class ObjectModel : public QAbstractItemModel
|
||||
#include "model.h"
|
||||
|
||||
class ObjectModel : public Model
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
|
@ -17,9 +19,6 @@ public:
|
|||
explicit ObjectModel(QObject *parent = nullptr);
|
||||
|
||||
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 headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const override;
|
||||
|
||||
|
|
|
@ -10,6 +10,7 @@ class Panel : public QWidget
|
|||
public:
|
||||
explicit Panel(QWidget *parent = nullptr);
|
||||
|
||||
void *GetData() const { return data_; }
|
||||
void SetData(void *data);
|
||||
|
||||
signals:
|
||||
|
|
|
@ -2,13 +2,12 @@
|
|||
|
||||
#include <iostream>
|
||||
|
||||
#define super QAbstractItemModel
|
||||
#define super Model
|
||||
|
||||
using namespace si;
|
||||
|
||||
ChunkModel::ChunkModel(QObject *parent) :
|
||||
super{parent},
|
||||
chunk_(nullptr)
|
||||
super{parent}
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -17,50 +16,9 @@ int ChunkModel::columnCount(const QModelIndex &parent) const
|
|||
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
|
||||
{
|
||||
Chunk *c = GetChunkFromIndex(index);
|
||||
Chunk *c = static_cast<Chunk*>(GetCoreFromIndex(index));
|
||||
if (!c) {
|
||||
return QVariant();
|
||||
}
|
||||
|
@ -108,19 +66,3 @@ QVariant ChunkModel::headerData(int section, Qt::Orientation orientation, int ro
|
|||
|
||||
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
|
||||
|
||||
#include <chunk.h>
|
||||
#include <QAbstractItemModel>
|
||||
|
||||
class ChunkModel : public QAbstractItemModel
|
||||
#include "model.h"
|
||||
|
||||
class ChunkModel : public Model
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
|
@ -21,22 +22,9 @@ public:
|
|||
explicit ChunkModel(QObject *parent = nullptr);
|
||||
|
||||
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 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
|
||||
|
|
|
@ -71,6 +71,17 @@ MxChPanel::MxChPanel(QWidget *parent) :
|
|||
data_sz_edit_->setMaximum(INT_MAX);
|
||||
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();
|
||||
}
|
||||
|
||||
|
@ -99,6 +110,10 @@ void MxChPanel::OnClosingData(void *data)
|
|||
chunk->data("Object") = u32(obj_edit_->value());
|
||||
chunk->data("Time") = u32(ms_offset_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)
|
||||
|
@ -116,3 +131,15 @@ void MxChPanel::FlagCheckBoxClicked(bool e)
|
|||
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 <QLineEdit>
|
||||
#include <QPushButton>
|
||||
#include <QSpinBox>
|
||||
#include <QTextEdit>
|
||||
|
||||
|
@ -23,12 +24,16 @@ private:
|
|||
QSpinBox *obj_edit_;
|
||||
QSpinBox *ms_offset_edit_;
|
||||
QSpinBox *data_sz_edit_;
|
||||
QTextEdit *data_edit_;
|
||||
QPushButton *show_data_btn_;
|
||||
|
||||
QVector<QCheckBox*> flag_checkboxes_;
|
||||
|
||||
private slots:
|
||||
void FlagCheckBoxClicked(bool e);
|
||||
|
||||
void ShowDataField();
|
||||
|
||||
};
|
||||
|
||||
#endif // MXCHPANEL_H
|
||||
|
|
|
@ -20,7 +20,7 @@ SIViewDialog::SIViewDialog(Mode mode, Chunk *riff, QWidget *parent) :
|
|||
layout->addWidget(splitter);
|
||||
|
||||
auto tree = new QTreeView();
|
||||
chunk_model_.SetChunk(riff);
|
||||
chunk_model_.SetCore(riff);
|
||||
tree->setModel(&chunk_model_);
|
||||
tree->setContextMenuPolicy(Qt::CustomContextMenu);
|
||||
connect(tree->selectionModel(), &QItemSelectionModel::currentRowChanged, this, &SIViewDialog::SelectionChanged);
|
||||
|
@ -53,6 +53,7 @@ SIViewDialog::SIViewDialog(Mode mode, Chunk *riff, QWidget *parent) :
|
|||
btn_layout->addStretch();
|
||||
|
||||
auto accept_btn = new QPushButton(mode == Import ? tr("De-Weave") : tr("Weave"));
|
||||
accept_btn->setDefault(true);
|
||||
connect(accept_btn, &QPushButton::clicked, this, &SIViewDialog::accept);
|
||||
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