mirror of
https://github.com/baldurk/renderdoc.git
synced 2026-05-05 01:20:42 +00:00
Move common Qt utility functions & JSON I/O together in a single place
This commit is contained in:
@@ -24,6 +24,7 @@
|
||||
|
||||
#include "CaptureContext.h"
|
||||
#include <QApplication>
|
||||
#include <QDir>
|
||||
#include <QFileInfo>
|
||||
#include <QLabel>
|
||||
#include <QMenu>
|
||||
@@ -33,6 +34,7 @@
|
||||
#include <QStandardPaths>
|
||||
#include <QTimer>
|
||||
#include "Windows/MainWindow.h"
|
||||
#include "QRDUtils.h"
|
||||
|
||||
CaptureContext::CaptureContext(QString paramFilename, QString remoteHost, uint32_t remoteIdent,
|
||||
bool temp, PersistantConfig &cfg)
|
||||
@@ -377,135 +379,3 @@ void *CaptureContext::FillWindowingData(WId widget)
|
||||
|
||||
#endif
|
||||
}
|
||||
|
||||
void GUIInvoke::call(const std::function<void()> &f)
|
||||
{
|
||||
if(qApp->thread() == QThread::currentThread())
|
||||
{
|
||||
f();
|
||||
return;
|
||||
}
|
||||
|
||||
// TODO: could maybe do away with string compare here via caching
|
||||
// invoke->metaObject()->indexOfMethod("doInvoke"); ?
|
||||
|
||||
GUIInvoke *invoke = new GUIInvoke(f);
|
||||
invoke->moveToThread(qApp->thread());
|
||||
QMetaObject::invokeMethod(invoke, "doInvoke", Qt::QueuedConnection);
|
||||
}
|
||||
|
||||
void GUIInvoke::blockcall(const std::function<void()> &f)
|
||||
{
|
||||
if(qApp->thread() == QThread::currentThread())
|
||||
{
|
||||
f();
|
||||
return;
|
||||
}
|
||||
|
||||
// TODO: could maybe do away with string compare here via caching
|
||||
// invoke->metaObject()->indexOfMethod("doInvoke"); ?
|
||||
|
||||
GUIInvoke *invoke = new GUIInvoke(f);
|
||||
invoke->moveToThread(qApp->thread());
|
||||
QMetaObject::invokeMethod(invoke, "doInvoke", Qt::BlockingQueuedConnection);
|
||||
}
|
||||
|
||||
void RDDialog::show(QMenu *menu, QPoint pos)
|
||||
{
|
||||
menu->setWindowModality(Qt::ApplicationModal);
|
||||
menu->popup(pos);
|
||||
QEventLoop loop;
|
||||
while(menu->isVisible())
|
||||
{
|
||||
loop.processEvents(QEventLoop::WaitForMoreEvents);
|
||||
QCoreApplication::sendPostedEvents();
|
||||
}
|
||||
}
|
||||
|
||||
int RDDialog::show(QDialog *dialog)
|
||||
{
|
||||
dialog->setWindowModality(Qt::ApplicationModal);
|
||||
dialog->show();
|
||||
QEventLoop loop;
|
||||
while(dialog->isVisible())
|
||||
{
|
||||
loop.processEvents(QEventLoop::WaitForMoreEvents);
|
||||
QCoreApplication::sendPostedEvents();
|
||||
}
|
||||
|
||||
return dialog->result();
|
||||
}
|
||||
|
||||
QMessageBox::StandardButton RDDialog::messageBox(QMessageBox::Icon icon, QWidget *parent,
|
||||
const QString &title, const QString &text,
|
||||
QMessageBox::StandardButtons buttons,
|
||||
QMessageBox::StandardButton defaultButton)
|
||||
{
|
||||
QMessageBox mb(icon, title, text, buttons, parent);
|
||||
mb.setDefaultButton(defaultButton);
|
||||
show(&mb);
|
||||
return mb.standardButton(mb.clickedButton());
|
||||
}
|
||||
|
||||
QString RDDialog::getExistingDirectory(QWidget *parent, const QString &caption, const QString &dir,
|
||||
QFileDialog::Options options)
|
||||
{
|
||||
QFileDialog fd(parent, caption, dir, QString());
|
||||
fd.setAcceptMode(QFileDialog::AcceptOpen);
|
||||
fd.setFileMode(QFileDialog::DirectoryOnly);
|
||||
fd.setOptions(options);
|
||||
show(&fd);
|
||||
|
||||
if(fd.result() == QFileDialog::Accepted)
|
||||
{
|
||||
QStringList files = fd.selectedFiles();
|
||||
if(!files.isEmpty())
|
||||
return files[0];
|
||||
}
|
||||
|
||||
return QString();
|
||||
}
|
||||
|
||||
QString RDDialog::getOpenFileName(QWidget *parent, const QString &caption, const QString &dir,
|
||||
const QString &filter, QString *selectedFilter,
|
||||
QFileDialog::Options options)
|
||||
{
|
||||
QFileDialog fd(parent, caption, dir, filter);
|
||||
fd.setAcceptMode(QFileDialog::AcceptOpen);
|
||||
fd.setOptions(options);
|
||||
show(&fd);
|
||||
|
||||
if(fd.result() == QFileDialog::Accepted)
|
||||
{
|
||||
if(selectedFilter)
|
||||
*selectedFilter = fd.selectedNameFilter();
|
||||
|
||||
QStringList files = fd.selectedFiles();
|
||||
if(!files.isEmpty())
|
||||
return files[0];
|
||||
}
|
||||
|
||||
return QString();
|
||||
}
|
||||
|
||||
QString RDDialog::getSaveFileName(QWidget *parent, const QString &caption, const QString &dir,
|
||||
const QString &filter, QString *selectedFilter,
|
||||
QFileDialog::Options options)
|
||||
{
|
||||
QFileDialog fd(parent, caption, dir, filter);
|
||||
fd.setAcceptMode(QFileDialog::AcceptSave);
|
||||
fd.setOptions(options);
|
||||
show(&fd);
|
||||
|
||||
if(fd.result() == QFileDialog::Accepted)
|
||||
{
|
||||
if(selectedFilter)
|
||||
*selectedFilter = fd.selectedNameFilter();
|
||||
|
||||
QStringList files = fd.selectedFiles();
|
||||
if(!files.isEmpty())
|
||||
return files[0];
|
||||
}
|
||||
|
||||
return QString();
|
||||
}
|
||||
|
||||
@@ -25,7 +25,6 @@
|
||||
#pragma once
|
||||
|
||||
#include <QDebug>
|
||||
#include <QFileDialog>
|
||||
#include <QList>
|
||||
#include <QMap>
|
||||
#include <QMessageBox>
|
||||
@@ -194,163 +193,3 @@ private:
|
||||
QProgressDialog *m_Progress;
|
||||
MainWindow *m_MainWindow;
|
||||
};
|
||||
|
||||
// implementation of QOverload, to avoid depending on 5.7.
|
||||
// From: http://stackoverflow.com/a/16795664/4070143
|
||||
template <typename... Args>
|
||||
struct OverloadedSlot
|
||||
{
|
||||
template <typename C, typename R>
|
||||
static constexpr auto of(R (C::*pmf)(Args...)) -> decltype(pmf)
|
||||
{
|
||||
return pmf;
|
||||
}
|
||||
};
|
||||
|
||||
// Utility class for invoking a lambda on the GUI thread.
|
||||
// This is supported by QTimer::singleShot on Qt 5.4 but it's probably
|
||||
// wise not to require a higher version that necessary.
|
||||
#include <functional>
|
||||
|
||||
class GUIInvoke : public QObject
|
||||
{
|
||||
private:
|
||||
Q_OBJECT
|
||||
GUIInvoke(const std::function<void()> &f) : func(f) {}
|
||||
std::function<void()> func;
|
||||
|
||||
public:
|
||||
static void call(const std::function<void()> &f);
|
||||
static void blockcall(const std::function<void()> &f);
|
||||
|
||||
protected slots:
|
||||
void doInvoke()
|
||||
{
|
||||
func();
|
||||
deleteLater();
|
||||
}
|
||||
};
|
||||
|
||||
// Utility class for calling a lambda on a new thread.
|
||||
#include <QThread>
|
||||
|
||||
class LambdaThread : public QObject
|
||||
{
|
||||
private:
|
||||
Q_OBJECT
|
||||
|
||||
std::function<void()> m_func;
|
||||
QThread *m_Thread;
|
||||
QSemaphore completed;
|
||||
bool m_SelfDelete = false;
|
||||
|
||||
public slots:
|
||||
void process()
|
||||
{
|
||||
m_func();
|
||||
m_Thread->quit();
|
||||
m_Thread->deleteLater();
|
||||
m_Thread = NULL;
|
||||
if(m_SelfDelete)
|
||||
deleteLater();
|
||||
completed.acquire();
|
||||
}
|
||||
|
||||
void selfDelete(bool d) { m_SelfDelete = d; }
|
||||
public:
|
||||
explicit LambdaThread(std::function<void()> f)
|
||||
{
|
||||
completed.release();
|
||||
m_Thread = new QThread();
|
||||
m_func = f;
|
||||
moveToThread(m_Thread);
|
||||
QObject::connect(m_Thread, &QThread::started, this, &LambdaThread::process);
|
||||
}
|
||||
|
||||
void start(QThread::Priority prio = QThread::InheritPriority) { m_Thread->start(prio); }
|
||||
bool isRunning() { return completed.available(); }
|
||||
bool wait(unsigned long time = ULONG_MAX)
|
||||
{
|
||||
if(m_Thread)
|
||||
return m_Thread->wait(time);
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
class QMenu;
|
||||
|
||||
// helper for doing a manual blocking invoke of a dialog
|
||||
struct RDDialog
|
||||
{
|
||||
static void show(QMenu *menu, QPoint pos);
|
||||
static int show(QDialog *dialog);
|
||||
static QMessageBox::StandardButton messageBox(
|
||||
QMessageBox::Icon, QWidget *parent, const QString &title, const QString &text,
|
||||
QMessageBox::StandardButtons buttons = QMessageBox::Ok,
|
||||
QMessageBox::StandardButton defaultButton = QMessageBox::NoButton);
|
||||
|
||||
static QMessageBox::StandardButton information(
|
||||
QWidget *parent, const QString &title, const QString &text,
|
||||
QMessageBox::StandardButtons buttons = QMessageBox::Ok,
|
||||
QMessageBox::StandardButton defaultButton = QMessageBox::NoButton)
|
||||
{
|
||||
return messageBox(QMessageBox::Information, parent, title, text, buttons, defaultButton);
|
||||
}
|
||||
|
||||
static QMessageBox::StandardButton question(
|
||||
QWidget *parent, const QString &title, const QString &text,
|
||||
QMessageBox::StandardButtons buttons = QMessageBox::StandardButtons(QMessageBox::Yes |
|
||||
QMessageBox::No),
|
||||
QMessageBox::StandardButton defaultButton = QMessageBox::NoButton)
|
||||
{
|
||||
return messageBox(QMessageBox::Question, parent, title, text, buttons, defaultButton);
|
||||
}
|
||||
|
||||
static QMessageBox::StandardButton warning(
|
||||
QWidget *parent, const QString &title, const QString &text,
|
||||
QMessageBox::StandardButtons buttons = QMessageBox::Ok,
|
||||
QMessageBox::StandardButton defaultButton = QMessageBox::NoButton)
|
||||
{
|
||||
return messageBox(QMessageBox::Warning, parent, title, text, buttons, defaultButton);
|
||||
}
|
||||
|
||||
static QMessageBox::StandardButton critical(
|
||||
QWidget *parent, const QString &title, const QString &text,
|
||||
QMessageBox::StandardButtons buttons = QMessageBox::Ok,
|
||||
QMessageBox::StandardButton defaultButton = QMessageBox::NoButton)
|
||||
{
|
||||
return messageBox(QMessageBox::Critical, parent, title, text, buttons, defaultButton);
|
||||
}
|
||||
|
||||
static QString getExistingDirectory(QWidget *parent = NULL, const QString &caption = QString(),
|
||||
const QString &dir = QString(),
|
||||
QFileDialog::Options options = QFileDialog::ShowDirsOnly);
|
||||
|
||||
static QString getOpenFileName(QWidget *parent = NULL, const QString &caption = QString(),
|
||||
const QString &dir = QString(), const QString &filter = QString(),
|
||||
QString *selectedFilter = NULL,
|
||||
QFileDialog::Options options = QFileDialog::Options());
|
||||
|
||||
static QString getSaveFileName(QWidget *parent = NULL, const QString &caption = QString(),
|
||||
const QString &dir = QString(), const QString &filter = QString(),
|
||||
QString *selectedFilter = NULL,
|
||||
QFileDialog::Options options = QFileDialog::Options());
|
||||
};
|
||||
|
||||
// useful delegate for enforcing a given size
|
||||
#include <QItemDelegate>
|
||||
|
||||
class SizeDelegate : public QItemDelegate
|
||||
{
|
||||
private:
|
||||
Q_OBJECT
|
||||
|
||||
QSize m_Size;
|
||||
|
||||
public:
|
||||
SizeDelegate(QSize size) : m_Size(size) {}
|
||||
QSize sizeHint(const QStyleOptionViewItem &option, const QModelIndex &index) const
|
||||
{
|
||||
return m_Size;
|
||||
}
|
||||
};
|
||||
|
||||
@@ -25,9 +25,12 @@
|
||||
#include "PersistantConfig.h"
|
||||
#include <QDebug>
|
||||
#include <QDir>
|
||||
#include <QJsonDocument>
|
||||
#include "QRDUtils.h"
|
||||
#include "renderdoc_replay.h"
|
||||
|
||||
#define JSON_ID "rdocConfigData"
|
||||
#define JSON_VER 1
|
||||
|
||||
// helper templates to convert some more complex types to/from appropriate variants
|
||||
template <typename variantType, typename origType>
|
||||
variantType convertToVariant(const origType &val)
|
||||
@@ -93,29 +96,12 @@ bool PersistantConfig::Deserialize(QString filename)
|
||||
|
||||
if(f.open(QIODevice::ReadOnly | QIODevice::Text))
|
||||
{
|
||||
QByteArray json = f.readAll();
|
||||
QVariantMap values;
|
||||
|
||||
if(json.isEmpty())
|
||||
{
|
||||
qCritical() << "Read invalid empty JSON data from file " << f.errorString();
|
||||
bool success = LoadFromJSON(values, f, JSON_ID, JSON_VER);
|
||||
|
||||
if(!success)
|
||||
return false;
|
||||
}
|
||||
|
||||
QJsonDocument doc = QJsonDocument::fromJson(json);
|
||||
|
||||
if(doc.isEmpty() || doc.isNull())
|
||||
{
|
||||
qCritical() << "Failed to convert file to JSON document";
|
||||
return false;
|
||||
}
|
||||
|
||||
QVariantMap values = doc.toVariant().toMap();
|
||||
|
||||
if(values.isEmpty() || !values.contains("renderdocConfigData"))
|
||||
{
|
||||
qCritical() << "Converted config data is invalid or unrecognised";
|
||||
return false;
|
||||
}
|
||||
|
||||
applyValues(values);
|
||||
|
||||
@@ -131,32 +117,9 @@ bool PersistantConfig::Serialize(QString filename)
|
||||
{
|
||||
QVariantMap values = storeValues();
|
||||
|
||||
// marker that this is indeed a valid config to load from
|
||||
values["renderdocConfigData"] = 1;
|
||||
|
||||
QFile f(filename);
|
||||
if(f.open(QIODevice::WriteOnly | QIODevice::Truncate | QIODevice::Text))
|
||||
{
|
||||
QJsonDocument doc = QJsonDocument::fromVariant(values);
|
||||
|
||||
if(doc.isEmpty() || doc.isNull())
|
||||
{
|
||||
qCritical() << "Failed to convert config data to JSON document";
|
||||
return false;
|
||||
}
|
||||
|
||||
QByteArray jsontext = doc.toJson(QJsonDocument::Indented);
|
||||
|
||||
qint64 ret = f.write(jsontext);
|
||||
|
||||
if(ret != jsontext.size())
|
||||
{
|
||||
qCritical() << "Failed to write JSON data to file: " << ret << " " << f.errorString();
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
return SaveToJSON(values, f, JSON_ID, JSON_VER);
|
||||
|
||||
qWarning() << "Couldn't write to " << filename << " " << f.errorString();
|
||||
|
||||
|
||||
@@ -0,0 +1,221 @@
|
||||
/******************************************************************************
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2016 Baldur Karlsson
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
******************************************************************************/
|
||||
|
||||
#include "QRDUtils.h"
|
||||
#include <QGuiApplication>
|
||||
#include <QJsonDocument>
|
||||
#include <QMenu>
|
||||
|
||||
bool SaveToJSON(QVariantMap &data, QIODevice &f, const char *magicIdentifier, uint32_t magicVersion)
|
||||
{
|
||||
// marker that this data is valid
|
||||
data[magicIdentifier] = magicVersion;
|
||||
|
||||
QJsonDocument doc = QJsonDocument::fromVariant(data);
|
||||
|
||||
if(doc.isEmpty() || doc.isNull())
|
||||
{
|
||||
qCritical() << "Failed to convert data to JSON document";
|
||||
return false;
|
||||
}
|
||||
|
||||
QByteArray jsontext = doc.toJson(QJsonDocument::Indented);
|
||||
|
||||
qint64 ret = f.write(jsontext);
|
||||
|
||||
if(ret != jsontext.size())
|
||||
{
|
||||
qCritical() << "Failed to write JSON data: " << ret << " " << f.errorString();
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool LoadFromJSON(QVariantMap &data, QIODevice &f, const char *magicIdentifier, uint32_t magicVersion)
|
||||
{
|
||||
QByteArray json = f.readAll();
|
||||
|
||||
if(json.isEmpty())
|
||||
{
|
||||
qCritical() << "Read invalid empty JSON data from file " << f.errorString();
|
||||
return false;
|
||||
}
|
||||
|
||||
QJsonDocument doc = QJsonDocument::fromJson(json);
|
||||
|
||||
if(doc.isEmpty() || doc.isNull())
|
||||
{
|
||||
qCritical() << "Failed to convert file to JSON document";
|
||||
return false;
|
||||
}
|
||||
|
||||
data = doc.toVariant().toMap();
|
||||
|
||||
if(data.isEmpty() || !data.contains(magicIdentifier))
|
||||
{
|
||||
qCritical() << "Converted config data is invalid or unrecognised";
|
||||
return false;
|
||||
}
|
||||
|
||||
if(data[magicIdentifier].toUInt() != magicVersion)
|
||||
{
|
||||
qCritical() << "Converted config data is not the right version";
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void GUIInvoke::call(const std::function<void()> &f)
|
||||
{
|
||||
if(qApp->thread() == QThread::currentThread())
|
||||
{
|
||||
f();
|
||||
return;
|
||||
}
|
||||
|
||||
// TODO: could maybe do away with string compare here via caching
|
||||
// invoke->metaObject()->indexOfMethod("doInvoke"); ?
|
||||
|
||||
GUIInvoke *invoke = new GUIInvoke(f);
|
||||
invoke->moveToThread(qApp->thread());
|
||||
QMetaObject::invokeMethod(invoke, "doInvoke", Qt::QueuedConnection);
|
||||
}
|
||||
|
||||
void GUIInvoke::blockcall(const std::function<void()> &f)
|
||||
{
|
||||
if(qApp->thread() == QThread::currentThread())
|
||||
{
|
||||
f();
|
||||
return;
|
||||
}
|
||||
|
||||
// TODO: could maybe do away with string compare here via caching
|
||||
// invoke->metaObject()->indexOfMethod("doInvoke"); ?
|
||||
|
||||
GUIInvoke *invoke = new GUIInvoke(f);
|
||||
invoke->moveToThread(qApp->thread());
|
||||
QMetaObject::invokeMethod(invoke, "doInvoke", Qt::BlockingQueuedConnection);
|
||||
}
|
||||
|
||||
void RDDialog::show(QMenu *menu, QPoint pos)
|
||||
{
|
||||
menu->setWindowModality(Qt::ApplicationModal);
|
||||
menu->popup(pos);
|
||||
QEventLoop loop;
|
||||
while(menu->isVisible())
|
||||
{
|
||||
loop.processEvents(QEventLoop::WaitForMoreEvents);
|
||||
QCoreApplication::sendPostedEvents();
|
||||
}
|
||||
}
|
||||
|
||||
int RDDialog::show(QDialog *dialog)
|
||||
{
|
||||
dialog->setWindowModality(Qt::ApplicationModal);
|
||||
dialog->show();
|
||||
QEventLoop loop;
|
||||
while(dialog->isVisible())
|
||||
{
|
||||
loop.processEvents(QEventLoop::WaitForMoreEvents);
|
||||
QCoreApplication::sendPostedEvents();
|
||||
}
|
||||
|
||||
return dialog->result();
|
||||
}
|
||||
|
||||
QMessageBox::StandardButton RDDialog::messageBox(QMessageBox::Icon icon, QWidget *parent,
|
||||
const QString &title, const QString &text,
|
||||
QMessageBox::StandardButtons buttons,
|
||||
QMessageBox::StandardButton defaultButton)
|
||||
{
|
||||
QMessageBox mb(icon, title, text, buttons, parent);
|
||||
mb.setDefaultButton(defaultButton);
|
||||
show(&mb);
|
||||
return mb.standardButton(mb.clickedButton());
|
||||
}
|
||||
|
||||
QString RDDialog::getExistingDirectory(QWidget *parent, const QString &caption, const QString &dir,
|
||||
QFileDialog::Options options)
|
||||
{
|
||||
QFileDialog fd(parent, caption, dir, QString());
|
||||
fd.setAcceptMode(QFileDialog::AcceptOpen);
|
||||
fd.setFileMode(QFileDialog::DirectoryOnly);
|
||||
fd.setOptions(options);
|
||||
show(&fd);
|
||||
|
||||
if(fd.result() == QFileDialog::Accepted)
|
||||
{
|
||||
QStringList files = fd.selectedFiles();
|
||||
if(!files.isEmpty())
|
||||
return files[0];
|
||||
}
|
||||
|
||||
return QString();
|
||||
}
|
||||
|
||||
QString RDDialog::getOpenFileName(QWidget *parent, const QString &caption, const QString &dir,
|
||||
const QString &filter, QString *selectedFilter,
|
||||
QFileDialog::Options options)
|
||||
{
|
||||
QFileDialog fd(parent, caption, dir, filter);
|
||||
fd.setAcceptMode(QFileDialog::AcceptOpen);
|
||||
fd.setOptions(options);
|
||||
show(&fd);
|
||||
|
||||
if(fd.result() == QFileDialog::Accepted)
|
||||
{
|
||||
if(selectedFilter)
|
||||
*selectedFilter = fd.selectedNameFilter();
|
||||
|
||||
QStringList files = fd.selectedFiles();
|
||||
if(!files.isEmpty())
|
||||
return files[0];
|
||||
}
|
||||
|
||||
return QString();
|
||||
}
|
||||
|
||||
QString RDDialog::getSaveFileName(QWidget *parent, const QString &caption, const QString &dir,
|
||||
const QString &filter, QString *selectedFilter,
|
||||
QFileDialog::Options options)
|
||||
{
|
||||
QFileDialog fd(parent, caption, dir, filter);
|
||||
fd.setAcceptMode(QFileDialog::AcceptSave);
|
||||
fd.setOptions(options);
|
||||
show(&fd);
|
||||
|
||||
if(fd.result() == QFileDialog::Accepted)
|
||||
{
|
||||
if(selectedFilter)
|
||||
*selectedFilter = fd.selectedNameFilter();
|
||||
|
||||
QStringList files = fd.selectedFiles();
|
||||
if(!files.isEmpty())
|
||||
return files[0];
|
||||
}
|
||||
|
||||
return QString();
|
||||
}
|
||||
@@ -0,0 +1,194 @@
|
||||
/******************************************************************************
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2016 Baldur Karlsson
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
******************************************************************************/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <QDebug>
|
||||
#include <QFileDialog>
|
||||
#include <QMessageBox>
|
||||
#include <QSemaphore>
|
||||
|
||||
bool SaveToJSON(QVariantMap &data, QIODevice &f, const char *magicIdentifier, uint32_t magicVersion);
|
||||
bool LoadFromJSON(QVariantMap &data, QIODevice &f, const char *magicIdentifier,
|
||||
uint32_t magicVersion);
|
||||
|
||||
// implementation of QOverload, to avoid depending on 5.7.
|
||||
// From: http://stackoverflow.com/a/16795664/4070143
|
||||
template <typename... Args>
|
||||
struct OverloadedSlot
|
||||
{
|
||||
template <typename C, typename R>
|
||||
static constexpr auto of(R (C::*pmf)(Args...)) -> decltype(pmf)
|
||||
{
|
||||
return pmf;
|
||||
}
|
||||
};
|
||||
|
||||
// Utility class for invoking a lambda on the GUI thread.
|
||||
// This is supported by QTimer::singleShot on Qt 5.4 but it's probably
|
||||
// wise not to require a higher version that necessary.
|
||||
#include <functional>
|
||||
|
||||
class GUIInvoke : public QObject
|
||||
{
|
||||
private:
|
||||
Q_OBJECT
|
||||
GUIInvoke(const std::function<void()> &f) : func(f) {}
|
||||
std::function<void()> func;
|
||||
|
||||
public:
|
||||
static void call(const std::function<void()> &f);
|
||||
static void blockcall(const std::function<void()> &f);
|
||||
|
||||
protected slots:
|
||||
void doInvoke()
|
||||
{
|
||||
func();
|
||||
deleteLater();
|
||||
}
|
||||
};
|
||||
|
||||
// Utility class for calling a lambda on a new thread.
|
||||
#include <QThread>
|
||||
|
||||
class LambdaThread : public QObject
|
||||
{
|
||||
private:
|
||||
Q_OBJECT
|
||||
|
||||
std::function<void()> m_func;
|
||||
QThread *m_Thread;
|
||||
QSemaphore completed;
|
||||
bool m_SelfDelete = false;
|
||||
|
||||
public slots:
|
||||
void process()
|
||||
{
|
||||
m_func();
|
||||
m_Thread->quit();
|
||||
m_Thread->deleteLater();
|
||||
m_Thread = NULL;
|
||||
if(m_SelfDelete)
|
||||
deleteLater();
|
||||
completed.acquire();
|
||||
}
|
||||
|
||||
void selfDelete(bool d) { m_SelfDelete = d; }
|
||||
public:
|
||||
explicit LambdaThread(std::function<void()> f)
|
||||
{
|
||||
completed.release();
|
||||
m_Thread = new QThread();
|
||||
m_func = f;
|
||||
moveToThread(m_Thread);
|
||||
QObject::connect(m_Thread, &QThread::started, this, &LambdaThread::process);
|
||||
}
|
||||
|
||||
void start(QThread::Priority prio = QThread::InheritPriority) { m_Thread->start(prio); }
|
||||
bool isRunning() { return completed.available(); }
|
||||
bool wait(unsigned long time = ULONG_MAX)
|
||||
{
|
||||
if(m_Thread)
|
||||
return m_Thread->wait(time);
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
class QMenu;
|
||||
|
||||
// helper for doing a manual blocking invoke of a dialog
|
||||
struct RDDialog
|
||||
{
|
||||
static void show(QMenu *menu, QPoint pos);
|
||||
static int show(QDialog *dialog);
|
||||
static QMessageBox::StandardButton messageBox(
|
||||
QMessageBox::Icon, QWidget *parent, const QString &title, const QString &text,
|
||||
QMessageBox::StandardButtons buttons = QMessageBox::Ok,
|
||||
QMessageBox::StandardButton defaultButton = QMessageBox::NoButton);
|
||||
|
||||
static QMessageBox::StandardButton information(
|
||||
QWidget *parent, const QString &title, const QString &text,
|
||||
QMessageBox::StandardButtons buttons = QMessageBox::Ok,
|
||||
QMessageBox::StandardButton defaultButton = QMessageBox::NoButton)
|
||||
{
|
||||
return messageBox(QMessageBox::Information, parent, title, text, buttons, defaultButton);
|
||||
}
|
||||
|
||||
static QMessageBox::StandardButton question(
|
||||
QWidget *parent, const QString &title, const QString &text,
|
||||
QMessageBox::StandardButtons buttons = QMessageBox::StandardButtons(QMessageBox::Yes |
|
||||
QMessageBox::No),
|
||||
QMessageBox::StandardButton defaultButton = QMessageBox::NoButton)
|
||||
{
|
||||
return messageBox(QMessageBox::Question, parent, title, text, buttons, defaultButton);
|
||||
}
|
||||
|
||||
static QMessageBox::StandardButton warning(
|
||||
QWidget *parent, const QString &title, const QString &text,
|
||||
QMessageBox::StandardButtons buttons = QMessageBox::Ok,
|
||||
QMessageBox::StandardButton defaultButton = QMessageBox::NoButton)
|
||||
{
|
||||
return messageBox(QMessageBox::Warning, parent, title, text, buttons, defaultButton);
|
||||
}
|
||||
|
||||
static QMessageBox::StandardButton critical(
|
||||
QWidget *parent, const QString &title, const QString &text,
|
||||
QMessageBox::StandardButtons buttons = QMessageBox::Ok,
|
||||
QMessageBox::StandardButton defaultButton = QMessageBox::NoButton)
|
||||
{
|
||||
return messageBox(QMessageBox::Critical, parent, title, text, buttons, defaultButton);
|
||||
}
|
||||
|
||||
static QString getExistingDirectory(QWidget *parent = NULL, const QString &caption = QString(),
|
||||
const QString &dir = QString(),
|
||||
QFileDialog::Options options = QFileDialog::ShowDirsOnly);
|
||||
|
||||
static QString getOpenFileName(QWidget *parent = NULL, const QString &caption = QString(),
|
||||
const QString &dir = QString(), const QString &filter = QString(),
|
||||
QString *selectedFilter = NULL,
|
||||
QFileDialog::Options options = QFileDialog::Options());
|
||||
|
||||
static QString getSaveFileName(QWidget *parent = NULL, const QString &caption = QString(),
|
||||
const QString &dir = QString(), const QString &filter = QString(),
|
||||
QString *selectedFilter = NULL,
|
||||
QFileDialog::Options options = QFileDialog::Options());
|
||||
};
|
||||
|
||||
// useful delegate for enforcing a given size
|
||||
#include <QItemDelegate>
|
||||
|
||||
class SizeDelegate : public QItemDelegate
|
||||
{
|
||||
private:
|
||||
Q_OBJECT
|
||||
|
||||
QSize m_Size;
|
||||
|
||||
public:
|
||||
SizeDelegate(QSize size) : m_Size(size) {}
|
||||
QSize sizeHint(const QStyleOptionViewItem &option, const QModelIndex &index) const
|
||||
{
|
||||
return m_Size;
|
||||
}
|
||||
};
|
||||
@@ -25,6 +25,7 @@
|
||||
#include "RenderManager.h"
|
||||
#include <QMutexLocker>
|
||||
#include "CaptureContext.h"
|
||||
#include "QRDUtils.h"
|
||||
|
||||
RenderManager::RenderManager()
|
||||
{
|
||||
|
||||
@@ -28,6 +28,7 @@
|
||||
#include <QRegularExpression>
|
||||
#include <QRegularExpressionMatch>
|
||||
#include "Code/CaptureContext.h"
|
||||
#include "Code/QRDUtils.h"
|
||||
#include "Windows/MainWindow.h"
|
||||
|
||||
void sharedLogOutput(QtMsgType type, const QMessageLogContext &context, const QString &msg)
|
||||
|
||||
@@ -24,7 +24,9 @@
|
||||
|
||||
#include "TextureSaveDialog.h"
|
||||
#include <QColorDialog>
|
||||
#include <QFileInfo>
|
||||
#include "Code/CaptureContext.h"
|
||||
#include "Code/QRDUtils.h"
|
||||
#include "ui_TextureSaveDialog.h"
|
||||
|
||||
TextureSaveDialog::TextureSaveDialog(const FetchTexture &t, const TextureSave &s, QWidget *parent)
|
||||
|
||||
@@ -25,6 +25,7 @@
|
||||
#include "EventBrowser.h"
|
||||
#include <QTimer>
|
||||
#include "Code/CaptureContext.h"
|
||||
#include "Code/QRDUtils.h"
|
||||
#include "ui_EventBrowser.h"
|
||||
|
||||
enum
|
||||
|
||||
@@ -35,6 +35,7 @@ class EventBrowser;
|
||||
|
||||
class QTreeWidgetItem;
|
||||
class QTimer;
|
||||
class SizeDelegate;
|
||||
|
||||
class EventBrowser : public QFrame, public ILogViewerForm
|
||||
{
|
||||
|
||||
@@ -25,14 +25,17 @@
|
||||
#include "MainWindow.h"
|
||||
#include <QFileDialog>
|
||||
#include <QFileInfo>
|
||||
#include <QJsonDocument>
|
||||
#include <QProgressBar>
|
||||
#include "Code/CaptureContext.h"
|
||||
#include "Code/QRDUtils.h"
|
||||
#include "Windows/Dialogs/AboutDialog.h"
|
||||
#include "EventBrowser.h"
|
||||
#include "TextureViewer.h"
|
||||
#include "ui_MainWindow.h"
|
||||
|
||||
#define JSON_ID "rdocLayoutData"
|
||||
#define JSON_VER 1
|
||||
|
||||
MainWindow::MainWindow(CaptureContext *ctx) : QMainWindow(NULL), ui(new Ui::MainWindow), m_Ctx(ctx)
|
||||
{
|
||||
ui->setupUi(this);
|
||||
@@ -790,32 +793,9 @@ bool MainWindow::SaveLayout(int layout)
|
||||
|
||||
QVariantMap state = saveState();
|
||||
|
||||
// marker that this is indeed a valid state to load from
|
||||
state["renderdocLayoutData"] = 1;
|
||||
|
||||
QFile f(path);
|
||||
if(f.open(QIODevice::WriteOnly | QIODevice::Truncate | QIODevice::Text))
|
||||
{
|
||||
QJsonDocument doc = QJsonDocument::fromVariant(state);
|
||||
|
||||
if(doc.isEmpty() || doc.isNull())
|
||||
{
|
||||
qCritical() << "Failed to convert state data to JSON document";
|
||||
return false;
|
||||
}
|
||||
|
||||
QByteArray jsontext = doc.toJson(QJsonDocument::Indented);
|
||||
|
||||
qint64 ret = f.write(jsontext);
|
||||
|
||||
if(ret != jsontext.size())
|
||||
{
|
||||
qCritical() << "Failed to write JSON data to file: " << ret << " " << f.errorString();
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
return SaveToJSON(state, f, JSON_ID, JSON_VER);
|
||||
|
||||
qWarning() << "Couldn't write to " << path << " " << f.errorString();
|
||||
|
||||
@@ -829,29 +809,12 @@ bool MainWindow::LoadLayout(int layout)
|
||||
QFile f(path);
|
||||
if(f.open(QIODevice::ReadOnly | QIODevice::Text))
|
||||
{
|
||||
QByteArray json = f.readAll();
|
||||
QVariantMap state;
|
||||
|
||||
if(json.isEmpty())
|
||||
{
|
||||
qCritical() << "Read invalid empty JSON data from file " << f.errorString();
|
||||
bool success = LoadFromJSON(state, f, JSON_ID, JSON_VER);
|
||||
|
||||
if(!success)
|
||||
return false;
|
||||
}
|
||||
|
||||
QJsonDocument doc = QJsonDocument::fromJson(json);
|
||||
|
||||
if(doc.isEmpty() || doc.isNull())
|
||||
{
|
||||
qCritical() << "Failed to convert file to JSON document";
|
||||
return false;
|
||||
}
|
||||
|
||||
QVariantMap state = doc.toVariant().toMap();
|
||||
|
||||
if(state.isEmpty() || !state.contains("renderdocLayoutData"))
|
||||
{
|
||||
qCritical() << "Converted state data is invalid or unrecognised";
|
||||
return false;
|
||||
}
|
||||
|
||||
return restoreState(state);
|
||||
}
|
||||
|
||||
@@ -27,12 +27,14 @@
|
||||
#include <math.h>
|
||||
#include <QClipboard>
|
||||
#include <QColorDialog>
|
||||
#include <QItemDelegate>
|
||||
#include <QJsonDocument>
|
||||
#include <QMenu>
|
||||
#include <QPainter>
|
||||
#include <QStyledItemDelegate>
|
||||
#include "3rdparty/toolwindowmanager/ToolWindowManagerArea.h"
|
||||
#include "Code/CaptureContext.h"
|
||||
#include "Code/QRDUtils.h"
|
||||
#include "Dialogs/TextureSaveDialog.h"
|
||||
#include "Widgets/ResourcePreview.h"
|
||||
#include "Widgets/TextureGoto.h"
|
||||
|
||||
@@ -25,6 +25,7 @@
|
||||
#pragma once
|
||||
|
||||
#include <QFrame>
|
||||
#include <QMenu>
|
||||
#include <QMouseEvent>
|
||||
#include "Code/CaptureContext.h"
|
||||
|
||||
|
||||
@@ -95,7 +95,8 @@ SOURCES += 3rdparty/toolwindowmanager/ToolWindowManager.cpp \
|
||||
Widgets/ThumbnailStrip.cpp \
|
||||
Widgets/TextureGoto.cpp \
|
||||
Widgets/RangeHistogram.cpp \
|
||||
Windows/Dialogs/TextureSaveDialog.cpp
|
||||
Windows/Dialogs/TextureSaveDialog.cpp \
|
||||
Code/QRDUtils.cpp
|
||||
|
||||
HEADERS += 3rdparty/toolwindowmanager/ToolWindowManager.h \
|
||||
3rdparty/toolwindowmanager/ToolWindowManagerArea.h \
|
||||
@@ -118,7 +119,8 @@ HEADERS += 3rdparty/toolwindowmanager/ToolWindowManager.h \
|
||||
Widgets/ThumbnailStrip.h \
|
||||
Widgets/TextureGoto.h \
|
||||
Widgets/RangeHistogram.h \
|
||||
Windows/Dialogs/TextureSaveDialog.h
|
||||
Windows/Dialogs/TextureSaveDialog.h \
|
||||
Code/QRDUtils.h
|
||||
|
||||
FORMS += Windows/Dialogs/AboutDialog.ui \
|
||||
Windows/MainWindow.ui \
|
||||
|
||||
@@ -278,10 +278,12 @@
|
||||
<ItemGroup>
|
||||
<ClCompile Include="Code\CommonPipelineState.cpp" />
|
||||
<ClCompile Include="Code\PersistantConfig.cpp" />
|
||||
<ClCompile Include="Code\QRDUtils.cpp" />
|
||||
<ClCompile Include="generated\moc_AboutDialog.cpp" />
|
||||
<ClCompile Include="generated\moc_CaptureContext.cpp" />
|
||||
<ClCompile Include="generated\moc_CustomPaintWidget.cpp" />
|
||||
<ClCompile Include="generated\moc_EventBrowser.cpp" />
|
||||
<ClCompile Include="generated\moc_QRDUtils.cpp" />
|
||||
<ClCompile Include="generated\moc_RangeHistogram.cpp" />
|
||||
<ClCompile Include="generated\moc_RDDoubleSpinBox.cpp" />
|
||||
<ClCompile Include="generated\moc_RDLabel.cpp" />
|
||||
@@ -330,6 +332,7 @@
|
||||
<ItemGroup>
|
||||
<ClInclude Include="Code\CommonPipelineState.h" />
|
||||
<ClInclude Include="Code\PersistantConfig.h" />
|
||||
<ClInclude Include="Code\QRDUtils.h" />
|
||||
<ClInclude Include="generated\ui_AboutDialog.h" />
|
||||
<ClInclude Include="generated\ui_EventBrowser.h" />
|
||||
<ClInclude Include="generated\ui_MainWindow.h" />
|
||||
|
||||
@@ -169,6 +169,12 @@
|
||||
<ClCompile Include="generated\moc_TextureSaveDialog.cpp">
|
||||
<Filter>Generated Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="Code\QRDUtils.cpp">
|
||||
<Filter>Code</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="generated\moc_QRDUtils.cpp">
|
||||
<Filter>Generated Files</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="3rdparty\flowlayout\FlowLayout.h">
|
||||
@@ -246,6 +252,9 @@
|
||||
<ClInclude Include="generated\ui_TextureSaveDialog.h">
|
||||
<Filter>Generated Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="Code\QRDUtils.h">
|
||||
<Filter>Code</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="resources.qrc">
|
||||
|
||||
Reference in New Issue
Block a user