Skip to content

Commit

Permalink
GUI: Proper usage of status bar
Browse files Browse the repository at this point in the history
  • Loading branch information
fdde authored and DrMcCoy committed Dec 29, 2017
1 parent ccb2c68 commit 9d39493
Show file tree
Hide file tree
Showing 18 changed files with 617 additions and 345 deletions.
234 changes: 212 additions & 22 deletions src/gui/mainwindow.cpp
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
#include "verdigris/wobjectimpl.h"

#include <QFileDialog>
#include <QMessageBox>
#include <QStandardPaths>
#include <boost/scope_exit.hpp>

#include "verdigris/wobjectimpl.h"

#include "src/cline.h"
#include "src/aurora/util.h"
Expand All @@ -11,19 +12,21 @@
#include "src/common/writefile.h"
#include "src/gui/mainwindow.h"
#include "src/images/dumptga.h"
#include "src/sound/sound.h"
#include "src/sound/audiostream.h"

namespace GUI {

W_OBJECT_IMPL(MainWindow)

MainWindow::MainWindow(QWidget *parent, const char *version, const QSize &size, const Common::UString &path)
: QMainWindow(parent)
, _treeModel(nullptr)
{
_ui.setupUi(this);

// resize(size);

// preview
_panelPreviewEmpty = new PanelPreviewEmpty();
_panelPreviewImage = new PanelPreviewImage();
_panelPreviewSound = new PanelPreviewSound();
Expand All @@ -35,23 +38,23 @@ MainWindow::MainWindow(QWidget *parent, const char *version, const QSize &size,

// signals/slots
QObject::connect(_ui.actionOpenDirectory, &QAction::triggered, this, &MainWindow::slotOpenDir);
QObject::connect(_ui.actionOpenFile, &QAction::triggered, this, &MainWindow::slotOpenFile);
QObject::connect(_ui.actionClose, &QAction::triggered, this, &MainWindow::slotCloseDir);
QObject::connect(_ui.actionQuit, &QAction::triggered, this, &MainWindow::slotQuit);
QObject::connect(_resInfo, &ResourceInfoPanel::loadModel, this, &MainWindow::setTreeViewModel);
QObject::connect(_resInfo, &ResourceInfoPanel::logAppend, this, &MainWindow::slotLogAppend);
QObject::connect(_resInfo, &ResourceInfoPanel::closeDirClicked, this, &MainWindow::slotCloseDir);
QObject::connect(_resInfo, &ResourceInfoPanel::saveClicked, this, &MainWindow::saveItem);
QObject::connect(_resInfo, &ResourceInfoPanel::exportTGAClicked, this, &MainWindow::exportTGA);
QObject::connect(_resInfo, &ResourceInfoPanel::exportBMUMP3Clicked, this, &MainWindow::exportBMUMP3);
QObject::connect(_resInfo, &ResourceInfoPanel::exportWAVClicked, this, &MainWindow::exportWAV);
QObject::connect(_ui.actionAbout, &QAction::triggered, this, &MainWindow::slotAbout);

// status bar
_statusLabel = new QLabel(this);
_statusLabel->setText("None");
_statusLabel->setAlignment(Qt::AlignLeft);
_ui.statusBar->addWidget(_statusLabel, 1);
_ui.actionAbout->setShortcut(QKeySequence(tr("F1")));

// tree view
_ui.treeView->setHeaderHidden(true);
// status bar
_status = std::make_shared<StatusBar>(this->statusBar());
_status->setText("Idle...");

// open the path given in command line if any
if (path.empty()) {
Expand All @@ -65,26 +68,32 @@ MainWindow::MainWindow(QWidget *parent, const char *version, const QSize &size,
}
}

void MainWindow::slotLogAppend(const QString& text) {
MainWindow::~MainWindow() {
// delete _status;
}

void MainWindow::slotLogAppend(QString text) {
_ui.log->append(text);
}

void MainWindow::setTreeViewModel(const QString &path) {
void MainWindow::setTreeViewModel(QString path) {
if (_rootPath == path)
return;
_rootPath = path;

_statusLabel->setText("Loading...");
_statusLabel->repaint();
_status->push("Populating resource tree...");
BOOST_SCOPE_EXIT((&_status)) {
_status->pop();
} BOOST_SCOPE_EXIT_END

_treeModel.reset();
_ui.treeView->setModel(nullptr);

_treeModel = std::make_unique<ResourceTree>(path, _ui.treeView);
_treeModel = std::make_unique<ResourceTree>(_status, path, _ui.treeView);
_ui.treeView->setModel(_treeModel.get());
_ui.treeView->show();

_statusLabel->setText(tr("Root: %1").arg(path));
_ui.treeView->resizeColumnToContents(0);


QObject::connect(_ui.treeView->selectionModel(), &QItemSelectionModel::selectionChanged,
Expand All @@ -99,13 +108,18 @@ void MainWindow::setTreeViewModel(const QString &path) {

void MainWindow::slotOpenDir() {
QString dir = QFileDialog::getExistingDirectory(this,
tr("Open directory"),
QString(QStandardPaths::HomeLocation),
QFileDialog::ShowDirsOnly);
tr("Open directory"), QString(QStandardPaths::HomeLocation), QFileDialog::ShowDirsOnly);
if (!dir.isEmpty())
setTreeViewModel(dir);
}

void MainWindow::slotOpenFile() {
QString fileName = QFileDialog::getOpenFileName(this,
tr("Open Aurora game resource file"), QString(QStandardPaths::HomeLocation), tr("Aurora game resource (*.*)"));
if (!fileName.isEmpty())
setTreeViewModel(fileName);
}

void MainWindow::slotCloseDir() {
showPreviewPanel(_panelPreviewEmpty);

Expand All @@ -121,8 +135,6 @@ void MainWindow::slotCloseDir() {

_resInfo->clearLabels();

_statusLabel->setText("None");

_ui.actionClose->setEnabled(false);
}

Expand Down Expand Up @@ -184,6 +196,10 @@ void MainWindow::selection(const QItemSelection &selected, const QItemSelection
_panelPreviewSound->setItem(_currentItem);
}

QString constructStatus(const QString &action, const QString &name, const QString &destination) {
return action + " \"" + name + "\" to \"" + destination + "\"...";
}

void MainWindow::saveItem() {
if (!_currentItem)
return;
Expand All @@ -195,6 +211,11 @@ void MainWindow::saveItem() {
if (fileName.isEmpty())
return;

_status->push(constructStatus("Saving", _currentItem->getName(), fileName));
BOOST_SCOPE_EXIT((&_status)) {
_status->pop();
} BOOST_SCOPE_EXIT_END

try {
QScopedPointer<Common::SeekableReadStream> res(_currentItem->getResourceData());

Expand All @@ -221,6 +242,11 @@ void MainWindow::exportTGA() {
if (fileName.isEmpty())
return;

_status->push(constructStatus("Exporting", _currentItem->getName(), fileName));
BOOST_SCOPE_EXIT((&_status)) {
_status->pop();
} BOOST_SCOPE_EXIT_END

try {
QScopedPointer<Images::Decoder> image(_currentItem->getImage());

Expand All @@ -231,10 +257,174 @@ void MainWindow::exportTGA() {
}
}

/* EXPORT MP3 : UNTESTED! */
void MainWindow::exportBMUMP3Impl(Common::SeekableReadStream &bmu, Common::WriteStream &mp3) {
if ((bmu.size() <= 8) ||
(bmu.readUint32BE() != MKTAG('B', 'M', 'U', ' ')) ||
(bmu.readUint32BE() != MKTAG('V', '1', '.', '0')))
throw Common::Exception("Not a valid BMU file");

mp3.writeStream(bmu);
}

#define USTR(x) (Common::UString((x).toStdString()))

void MainWindow::exportBMUMP3() {
if (!_currentItem)
return;

assert(_currentItem->getFileType() == Aurora::kFileTypeBMU);

const QString title = "Save MP3 file";
const QString mask = "MP3 file (*.mp3)|*.mp3";
const QString def = TypeMan.setFileType(USTR(_currentItem->getName()), Aurora::kFileTypeMP3).toQString();

QString fileName = QFileDialog::getSaveFileName(this,
title, def,
mask);

if (fileName.isEmpty())
return;

_status->push(constructStatus("Exporting", _currentItem->getName(), fileName));
BOOST_SCOPE_EXIT((&_status)) {
_status->pop();
} BOOST_SCOPE_EXIT_END

try {
Common::ScopedPtr<Common::SeekableReadStream> res(_currentItem->getResourceData());

Common::WriteFile file(USTR(fileName));

exportBMUMP3Impl(*res, file);
file.flush();

} catch (Common::Exception &e) {
Common::printException(e, "WARNING: ");
return;
}

// return true;
}

uint64 getLength(Sound::AudioStream *sound) {
Sound::RewindableAudioStream *rewSound = dynamic_cast<Sound::RewindableAudioStream *>(sound);
if (!rewSound)
return Sound::RewindableAudioStream::kInvalidLength;

return rewSound->getLength();
}

struct SoundBuffer {
static const size_t kBufferSize = 4096;

int16 buffer[kBufferSize];
int samples;

SoundBuffer() : samples(0) {
}
};

void MainWindow::exportWAVImpl(Sound::AudioStream *sound, Common::WriteStream &wav) {
assert(sound);

const uint16 channels = sound->getChannels();
const uint32 rate = sound->getRate();

std::deque<SoundBuffer> buffers;

uint64 length = getLength(sound);
if (length != Sound::RewindableAudioStream::kInvalidLength)
buffers.resize((length / (SoundBuffer::kBufferSize / channels)) + 1);

uint32 samples = 0;
std::deque<SoundBuffer>::iterator buffer = buffers.begin();
while (!sound->endOfStream()) {
if (buffer == buffers.end()) {
buffers.push_back(SoundBuffer());
buffer = --buffers.end();
}

buffer->samples = sound->readBuffer(buffer->buffer, SoundBuffer::kBufferSize);

if (buffer->samples > 0)
samples += buffer->samples;

++buffer;
}

samples /= channels;

const uint32 dataSize = samples * channels * 2;
const uint32 byteRate = rate * channels * 2;
const uint16 blockAlign = channels * 2;

wav.writeUint32BE(MKTAG('R', 'I', 'F', 'F'));
wav.writeUint32LE(36 + dataSize);
wav.writeUint32BE(MKTAG('W', 'A', 'V', 'E'));

wav.writeUint32BE(MKTAG('f', 'm', 't', ' '));
wav.writeUint32LE(16);
wav.writeUint16LE(1);
wav.writeUint16LE(channels);
wav.writeUint32LE(rate);
wav.writeUint32LE(byteRate);
wav.writeUint16LE(blockAlign);
wav.writeUint16LE(16);

wav.writeUint32BE(MKTAG('d', 'a', 't', 'a'));
wav.writeUint32LE(dataSize);

for (std::deque<SoundBuffer>::const_iterator b = buffers.begin(); b != buffers.end(); ++b)
for (int i = 0; i < b->samples; i++)
wav.writeUint16LE(b->buffer[i]);
}

void MainWindow::exportWAV() {
if (!_currentItem)
return;

assert(_currentItem->getResourceType() == Aurora::kResourceSound);

const QString title = "Save PCM WAV file";
const QString mask = "WAV file (*.wav)|*.wav";
const QString def = TypeMan.setFileType(USTR(_currentItem->getName()), Aurora::kFileTypeWAV).toQString();

QString fileName = QFileDialog::getSaveFileName(this,
title, def,
mask);

if (fileName.isEmpty())
return;

_status->push(constructStatus("Exporting", _currentItem->getName(), fileName));
BOOST_SCOPE_EXIT((&_status)) {
_status->pop();
} BOOST_SCOPE_EXIT_END

try {
Common::ScopedPtr<Sound::AudioStream> sound(_currentItem->getAudioStream());

Common::WriteFile file(USTR(fileName));

exportWAVImpl(sound.get(), file);
file.flush();

} catch (Common::Exception &e) {
Common::printException(e, "WARNING: ");
return;
}

// return true;
}

void MainWindow::slotAbout() {
QString msg = createVersionText().toQString();

QMessageBox::about(this, "About", msg);
}

std::shared_ptr<StatusBar> MainWindow::getStatusBar() {
return _status;
}

} // namespace GUI

0 comments on commit 9d39493

Please sign in to comment.