mirror of
https://git.wownero.com/wowlet/wowlet.git
synced 2024-08-15 01:03:14 +00:00
Initial code for supporting an alternative QtQuick based UI for OpenVR
This commit is contained in:
parent
e918955210
commit
96034902d1
19 changed files with 1034 additions and 46 deletions
|
@ -49,12 +49,10 @@ if(OPENVR)
|
||||||
"vr/utils/*.cpp"
|
"vr/utils/*.cpp"
|
||||||
)
|
)
|
||||||
list(APPEND SOURCE_FILES ${SOURCE_FILES_QML})
|
list(APPEND SOURCE_FILES ${SOURCE_FILES_QML})
|
||||||
|
|
||||||
if(MINGW)
|
|
||||||
set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -Wno-deprecated-declarations") # @TODO: removeme
|
|
||||||
endif()
|
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -Wno-deprecated-declarations") # @TODO: removeme
|
||||||
|
|
||||||
add_subdirectory(libwalletqt)
|
add_subdirectory(libwalletqt)
|
||||||
add_subdirectory(model)
|
add_subdirectory(model)
|
||||||
add_subdirectory(utils)
|
add_subdirectory(utils)
|
||||||
|
|
|
@ -107,6 +107,8 @@ AppContext::AppContext(QCommandLineParser *cmdargs) {
|
||||||
// Tor & socks proxy
|
// Tor & socks proxy
|
||||||
this->ws = new WSClient(this, m_wsUrl);
|
this->ws = new WSClient(this, m_wsUrl);
|
||||||
connect(this->ws, &WSClient::WSMessage, this, &AppContext::onWSMessage);
|
connect(this->ws, &WSClient::WSMessage, this, &AppContext::onWSMessage);
|
||||||
|
connect(this->ws, &WSClient::connectionEstablished, this, &AppContext::wsConnected);
|
||||||
|
connect(this->ws, &WSClient::closed, this, &AppContext::wsDisconnected);
|
||||||
|
|
||||||
// Store the wallet every 2 minutes
|
// Store the wallet every 2 minutes
|
||||||
m_storeTimer.start(2 * 60 * 1000);
|
m_storeTimer.start(2 * 60 * 1000);
|
||||||
|
@ -330,6 +332,8 @@ void AppContext::onWalletOpened(Wallet *wallet) {
|
||||||
this->refreshed = false;
|
this->refreshed = false;
|
||||||
this->currentWallet = wallet;
|
this->currentWallet = wallet;
|
||||||
this->walletPath = this->currentWallet->path() + ".keys";
|
this->walletPath = this->currentWallet->path() + ".keys";
|
||||||
|
QFileInfo fileInfo(this->currentWallet->path());
|
||||||
|
this->walletName = fileInfo.fileName();
|
||||||
this->walletViewOnly = this->currentWallet->viewOnly();
|
this->walletViewOnly = this->currentWallet->viewOnly();
|
||||||
config()->set(Config::walletPath, this->walletPath);
|
config()->set(Config::walletPath, this->walletPath);
|
||||||
|
|
||||||
|
@ -536,6 +540,12 @@ void AppContext::createConfigDirectory(const QString &dir) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void AppContext::createWalletWithoutSpecifyingSeed(const QString &name, const QString &password) {
|
||||||
|
WowletSeed seed = WowletSeed(this->restoreHeights[this->networkType], this->coinName, this->seedLanguage);
|
||||||
|
auto path = QDir(this->defaultWalletDir).filePath(name);
|
||||||
|
this->createWallet(seed, path, password);
|
||||||
|
}
|
||||||
|
|
||||||
void AppContext::createWallet(WowletSeed seed, const QString &path, const QString &password) {
|
void AppContext::createWallet(WowletSeed seed, const QString &path, const QString &password) {
|
||||||
if(Utils::fileExists(path)) {
|
if(Utils::fileExists(path)) {
|
||||||
auto err = QString("Failed to write wallet to path: \"%1\"; file already exists.").arg(path);
|
auto err = QString("Failed to write wallet to path: \"%1\"; file already exists.").arg(path);
|
||||||
|
@ -605,6 +615,9 @@ void AppContext::createWalletFinish(const QString &password) {
|
||||||
this->currentWallet->store();
|
this->currentWallet->store();
|
||||||
this->walletPassword = password;
|
this->walletPassword = password;
|
||||||
emit walletCreated(this->currentWallet);
|
emit walletCreated(this->currentWallet);
|
||||||
|
|
||||||
|
// emit signal on behalf of walletManager, open wallet
|
||||||
|
this->walletManager->walletOpened(this->currentWallet);
|
||||||
}
|
}
|
||||||
|
|
||||||
void AppContext::initRestoreHeights() {
|
void AppContext::initRestoreHeights() {
|
||||||
|
@ -835,7 +848,13 @@ void AppContext::updateBalance() {
|
||||||
AppContext::balance = balance_u / globals::cdiv;
|
AppContext::balance = balance_u / globals::cdiv;
|
||||||
double spendable = this->currentWallet->unlockedBalance();
|
double spendable = this->currentWallet->unlockedBalance();
|
||||||
|
|
||||||
|
// formatted
|
||||||
|
QString fmt_str = QString("Balance: %1 WOW").arg(Utils::balanceFormat(spendable));
|
||||||
|
if (balance > spendable)
|
||||||
|
fmt_str += QString(" (+%1 WOW unconfirmed)").arg(Utils::balanceFormat(balance - spendable));
|
||||||
|
|
||||||
emit balanceUpdated(balance_u, spendable);
|
emit balanceUpdated(balance_u, spendable);
|
||||||
|
emit balanceUpdatedFormatted(fmt_str);
|
||||||
}
|
}
|
||||||
|
|
||||||
void AppContext::syncStatusUpdated(quint64 height, quint64 target) {
|
void AppContext::syncStatusUpdated(quint64 height, quint64 target) {
|
||||||
|
|
|
@ -60,9 +60,12 @@ public:
|
||||||
|
|
||||||
QString walletPath;
|
QString walletPath;
|
||||||
QString walletPassword = "";
|
QString walletPassword = "";
|
||||||
|
QString walletName;
|
||||||
bool walletViewOnly = false;
|
bool walletViewOnly = false;
|
||||||
NetworkType::Type networkType;
|
NetworkType::Type networkType;
|
||||||
|
|
||||||
|
Q_PROPERTY(QString walletName MEMBER walletName);
|
||||||
|
|
||||||
QString applicationPath;
|
QString applicationPath;
|
||||||
|
|
||||||
static void createConfigDirectory(const QString &dir) ;
|
static void createConfigDirectory(const QString &dir) ;
|
||||||
|
@ -89,24 +92,20 @@ public:
|
||||||
static QMap<QString, QString> txCache;
|
static QMap<QString, QString> txCache;
|
||||||
static TxFiatHistory *txFiatHistory;
|
static TxFiatHistory *txFiatHistory;
|
||||||
|
|
||||||
QList<WalletKeysFiles> listWallets() {
|
|
||||||
// return listing of wallet .keys items
|
|
||||||
m_walletKeysFilesModel->refresh();
|
|
||||||
return m_walletKeysFilesModel->listWallets();
|
|
||||||
}
|
|
||||||
|
|
||||||
// libwalletqt
|
// libwalletqt
|
||||||
bool refreshed = false;
|
bool refreshed = false;
|
||||||
|
|
||||||
WalletManager *walletManager;
|
WalletManager *walletManager;
|
||||||
Wallet *currentWallet = nullptr;
|
Wallet *currentWallet = nullptr;
|
||||||
void createWallet(WowletSeed seed, const QString &path, const QString &password);
|
void createWallet(WowletSeed seed, const QString &path, const QString &password);
|
||||||
|
Q_INVOKABLE void createWalletWithoutSpecifyingSeed(const QString &name, const QString &password);
|
||||||
void createWalletViewOnly(const QString &path, const QString &password, const QString &address, const QString &viewkey, const QString &spendkey, quint64 restoreHeight);
|
void createWalletViewOnly(const QString &path, const QString &password, const QString &address, const QString &viewkey, const QString &spendkey, quint64 restoreHeight);
|
||||||
void createWalletFinish(const QString &password);
|
void createWalletFinish(const QString &password);
|
||||||
void syncStatusUpdated(quint64 height, quint64 target);
|
void syncStatusUpdated(quint64 height, quint64 target);
|
||||||
void updateBalance();
|
void updateBalance();
|
||||||
void initTor();
|
Q_INVOKABLE void initTor();
|
||||||
|
Q_INVOKABLE void initWS();
|
||||||
void initRestoreHeights();
|
void initRestoreHeights();
|
||||||
void initWS();
|
|
||||||
void donateBeg();
|
void donateBeg();
|
||||||
void refreshModels();
|
void refreshModels();
|
||||||
void setWindowTitle(bool mining = false);
|
void setWindowTitle(bool mining = false);
|
||||||
|
@ -115,8 +114,21 @@ public:
|
||||||
void closeWallet(bool emitClosedSignal = true, bool storeWallet = false);
|
void closeWallet(bool emitClosedSignal = true, bool storeWallet = false);
|
||||||
void storeWallet();
|
void storeWallet();
|
||||||
|
|
||||||
|
Q_INVOKABLE QVariantList listWallets() {
|
||||||
|
m_walletKeysFilesModel->refresh();
|
||||||
|
|
||||||
|
QVariantList list;
|
||||||
|
for(const WalletKeysFiles &wallet: m_walletKeysFilesModel->listWallets())
|
||||||
|
list << wallet.toVariant();
|
||||||
|
return list;
|
||||||
|
}
|
||||||
|
|
||||||
|
Q_INVOKABLE QString displayAmount(quint64 amount) {
|
||||||
|
return Utils::balanceFormat(amount);
|
||||||
|
}
|
||||||
|
|
||||||
public slots:
|
public slots:
|
||||||
void onOpenWallet(const QString& path, const QString &password);
|
Q_INVOKABLE void onOpenWallet(const QString& path, const QString &password);
|
||||||
void onCreateTransaction(QString address, quint64 amount, const QString description, bool all);
|
void onCreateTransaction(QString address, quint64 amount, const QString description, bool all);
|
||||||
void onCreateTransactionMultiDest(const QVector<QString> &addresses, const QVector<quint64> &amounts, const QString &description);
|
void onCreateTransactionMultiDest(const QVector<QString> &addresses, const QVector<quint64> &amounts, const QString &description);
|
||||||
void onCancelTransaction(PendingTransaction *tx, const QVector<QString> &address);
|
void onCancelTransaction(PendingTransaction *tx, const QVector<QString> &address);
|
||||||
|
@ -151,6 +163,7 @@ signals:
|
||||||
void walletClosed();
|
void walletClosed();
|
||||||
|
|
||||||
void balanceUpdated(quint64 balance, quint64 spendable);
|
void balanceUpdated(quint64 balance, quint64 spendable);
|
||||||
|
void balanceUpdatedFormatted(QString fmt);
|
||||||
void blockchainSync(int height, int target);
|
void blockchainSync(int height, int target);
|
||||||
void refreshSync(int height, int target);
|
void refreshSync(int height, int target);
|
||||||
void synchronized();
|
void synchronized();
|
||||||
|
@ -165,6 +178,8 @@ signals:
|
||||||
void createTransactionError(QString message);
|
void createTransactionError(QString message);
|
||||||
void createTransactionCancelled(const QVector<QString> &address, double amount);
|
void createTransactionCancelled(const QVector<QString> &address, double amount);
|
||||||
void createTransactionSuccess(PendingTransaction *tx, const QVector<QString> &address);
|
void createTransactionSuccess(PendingTransaction *tx, const QVector<QString> &address);
|
||||||
|
void wsConnected();
|
||||||
|
void wsDisconnected();
|
||||||
void redditUpdated(QList<QSharedPointer<RedditPost>> &posts);
|
void redditUpdated(QList<QSharedPointer<RedditPost>> &posts);
|
||||||
void nodesUpdated(QList<QSharedPointer<WowletNode>> &nodes);
|
void nodesUpdated(QList<QSharedPointer<WowletNode>> &nodes);
|
||||||
void ccsUpdated(QList<QSharedPointer<CCSEntry>> &entries);
|
void ccsUpdated(QList<QSharedPointer<CCSEntry>> &entries);
|
||||||
|
|
|
@ -36,8 +36,10 @@ public:
|
||||||
LogLevel_Min = Monero::WalletManagerFactory::LogLevel_Min,
|
LogLevel_Min = Monero::WalletManagerFactory::LogLevel_Min,
|
||||||
LogLevel_Max = Monero::WalletManagerFactory::LogLevel_Max,
|
LogLevel_Max = Monero::WalletManagerFactory::LogLevel_Max,
|
||||||
};
|
};
|
||||||
|
explicit WalletManager(QObject *parent = nullptr);
|
||||||
static WalletManager * instance();
|
static WalletManager * instance();
|
||||||
|
~WalletManager();
|
||||||
|
|
||||||
// wizard: createWallet path;
|
// wizard: createWallet path;
|
||||||
Q_INVOKABLE Wallet * createWallet(const QString &path, const QString &password,
|
Q_INVOKABLE Wallet * createWallet(const QString &path, const QString &password,
|
||||||
const QString &language, NetworkType::Type nettype = NetworkType::MAINNET, quint64 kdfRounds = 1);
|
const QString &language, NetworkType::Type nettype = NetworkType::MAINNET, quint64 kdfRounds = 1);
|
||||||
|
@ -187,9 +189,6 @@ public slots:
|
||||||
private:
|
private:
|
||||||
friend class WalletPassphraseListenerImpl;
|
friend class WalletPassphraseListenerImpl;
|
||||||
|
|
||||||
explicit WalletManager(QObject *parent = 0);
|
|
||||||
~WalletManager();
|
|
||||||
|
|
||||||
bool isMining() const;
|
bool isMining() const;
|
||||||
|
|
||||||
static WalletManager * m_instance;
|
static WalletManager * m_instance;
|
||||||
|
|
|
@ -114,12 +114,15 @@ if (AttachConsole(ATTACH_PARENT_PROCESS)) {
|
||||||
|
|
||||||
qRegisterMetaType<QVector<QString>>();
|
qRegisterMetaType<QVector<QString>>();
|
||||||
|
|
||||||
|
#ifdef QML
|
||||||
|
qputenv("QML_DISABLE_DISK_CACHE", "1");
|
||||||
|
#endif
|
||||||
|
|
||||||
if(openVREnabled) {
|
if(openVREnabled) {
|
||||||
#ifdef HAS_OPENVR
|
#ifdef HAS_OPENVR
|
||||||
QApplication vr_app(argc, argv);
|
QApplication vr_app(argc, argv);
|
||||||
auto *ctx = new AppContext(&parser);
|
auto *ctx = new AppContext(&parser);
|
||||||
auto *vr = new wowletVR::WowletVR(ctx, &parser, &vr_app);
|
auto *vr = new wowletvr::WowletVR(ctx, &parser, &vr_app);
|
||||||
qDebug() << "Context: " << qgetenv("QMLSCENE_DEVICE");
|
|
||||||
if(vr->errors.length() > 0)
|
if(vr->errors.length() > 0)
|
||||||
return 1;
|
return 1;
|
||||||
|
|
||||||
|
|
|
@ -574,8 +574,6 @@ void MainWindow::onWalletOpenedError(const QString &err) {
|
||||||
|
|
||||||
void MainWindow::onWalletCreated(Wallet *wallet) {
|
void MainWindow::onWalletCreated(Wallet *wallet) {
|
||||||
qDebug() << Q_FUNC_INFO;
|
qDebug() << Q_FUNC_INFO;
|
||||||
// emit signal on behalf of walletManager
|
|
||||||
m_ctx->walletManager->walletOpened(wallet);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void MainWindow::onWalletOpened(Wallet *wallet) {
|
void MainWindow::onWalletOpened(Wallet *wallet) {
|
||||||
|
|
|
@ -51,7 +51,7 @@ int TransactionHistoryModel::columnCount(const QModelIndex &parent) const {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
return Column::COUNT;
|
return TransactionInfoRole::COUNT;
|
||||||
}
|
}
|
||||||
|
|
||||||
QVariant TransactionHistoryModel::data(const QModelIndex &index, int role) const {
|
QVariant TransactionHistoryModel::data(const QModelIndex &index, int role) const {
|
||||||
|
@ -70,14 +70,14 @@ QVariant TransactionHistoryModel::data(const QModelIndex &index, int role) const
|
||||||
}
|
}
|
||||||
else if (role == Qt::TextAlignmentRole) {
|
else if (role == Qt::TextAlignmentRole) {
|
||||||
switch (index.column()) {
|
switch (index.column()) {
|
||||||
case Column::Amount:
|
case TransactionInfoRole::Amount:
|
||||||
case Column::FiatAmount:
|
case TransactionInfoRole::FiatAmount:
|
||||||
result = Qt::AlignRight;
|
result = Qt::AlignRight;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (role == Qt::DecorationRole) {
|
else if (role == Qt::DecorationRole) {
|
||||||
switch (index.column()) {
|
switch (index.column()) {
|
||||||
case Column::Date:
|
case TransactionInfoRole::Date:
|
||||||
{
|
{
|
||||||
if (tInfo.isFailed())
|
if (tInfo.isFailed())
|
||||||
result = QVariant(m_warning);
|
result = QVariant(m_warning);
|
||||||
|
@ -100,7 +100,7 @@ QVariant TransactionHistoryModel::data(const QModelIndex &index, int role) const
|
||||||
}
|
}
|
||||||
else if (role == Qt::ToolTipRole) {
|
else if (role == Qt::ToolTipRole) {
|
||||||
switch(index.column()) {
|
switch(index.column()) {
|
||||||
case Column::Date:
|
case TransactionInfoRole::Date:
|
||||||
{
|
{
|
||||||
if (tInfo.isFailed())
|
if (tInfo.isFailed())
|
||||||
result = "Transaction failed";
|
result = "Transaction failed";
|
||||||
|
@ -113,8 +113,8 @@ QVariant TransactionHistoryModel::data(const QModelIndex &index, int role) const
|
||||||
}
|
}
|
||||||
else if (role == Qt::ForegroundRole) {
|
else if (role == Qt::ForegroundRole) {
|
||||||
switch(index.column()) {
|
switch(index.column()) {
|
||||||
case Column::FiatAmount:
|
case TransactionInfoRole::FiatAmount:
|
||||||
case Column::Amount:
|
case TransactionInfoRole::Amount:
|
||||||
{
|
{
|
||||||
if (tInfo.direction() == TransactionInfo::Direction_Out) {
|
if (tInfo.direction() == TransactionInfo::Direction_Out) {
|
||||||
result = QVariant(QColor("#BC1E1E"));
|
result = QVariant(QColor("#BC1E1E"));
|
||||||
|
@ -134,9 +134,19 @@ QVariant TransactionHistoryModel::parseTransactionInfo(const TransactionInfo &tI
|
||||||
{
|
{
|
||||||
switch (column)
|
switch (column)
|
||||||
{
|
{
|
||||||
case Column::Date:
|
case TransactionInfoRole::TransactionFailedRole:
|
||||||
|
return tInfo.isFailed();
|
||||||
|
case TransactionInfoRole::TransactionPendingRole:
|
||||||
|
return tInfo.isPending();
|
||||||
|
case TransactionInfoRole::TransactionConfirmationsRole:
|
||||||
|
return tInfo.confirmations();
|
||||||
|
case TransactionInfoRole::TransactionConfirmationsRequiredRole:
|
||||||
|
return tInfo.confirmationsRequired();
|
||||||
|
case TransactionInfoRole::Date:
|
||||||
return tInfo.timestamp().toString("yyyy-MM-dd HH:mm");
|
return tInfo.timestamp().toString("yyyy-MM-dd HH:mm");
|
||||||
case Column::Description: {
|
case TransactionInfoRole::TransactionIsOutRole:
|
||||||
|
return tInfo.direction() == TransactionInfo::Direction_Out;
|
||||||
|
case TransactionInfoRole::Description: {
|
||||||
// if this tx is still in the pool, then we wont get the
|
// if this tx is still in the pool, then we wont get the
|
||||||
// description. We've cached it inside `AppContext::txDescriptionCache`
|
// description. We've cached it inside `AppContext::txDescriptionCache`
|
||||||
// for the time being.
|
// for the time being.
|
||||||
|
@ -147,15 +157,15 @@ QVariant TransactionHistoryModel::parseTransactionInfo(const TransactionInfo &tI
|
||||||
}
|
}
|
||||||
return tInfo.description();
|
return tInfo.description();
|
||||||
}
|
}
|
||||||
case Column::Amount:
|
case TransactionInfoRole::Amount:
|
||||||
{
|
{
|
||||||
QString amount = QString::number(tInfo.balanceDelta() / globals::cdiv, 'f', 4);
|
QString amount = QString::number(tInfo.balanceDelta() / globals::cdiv, 'f', 4);
|
||||||
amount = (tInfo.direction() == TransactionInfo::Direction_Out) ? "-" + amount : "+" + amount;
|
amount = (tInfo.direction() == TransactionInfo::Direction_Out) ? "-" + amount : "+" + amount;
|
||||||
return amount;
|
return amount;
|
||||||
}
|
}
|
||||||
case Column::TxID:
|
case TransactionInfoRole::TxID:
|
||||||
return tInfo.hash();
|
return tInfo.hash();
|
||||||
case Column::FiatAmount:
|
case TransactionInfoRole::FiatAmount:
|
||||||
{
|
{
|
||||||
double usd_price = AppContext::txFiatHistory->get(tInfo.timestamp().toString("yyyyMMdd"));
|
double usd_price = AppContext::txFiatHistory->get(tInfo.timestamp().toString("yyyyMMdd"));
|
||||||
if (usd_price == 0.0)
|
if (usd_price == 0.0)
|
||||||
|
@ -183,15 +193,15 @@ QVariant TransactionHistoryModel::headerData(int section, Qt::Orientation orient
|
||||||
}
|
}
|
||||||
if (orientation == Qt::Horizontal) {
|
if (orientation == Qt::Horizontal) {
|
||||||
switch(section) {
|
switch(section) {
|
||||||
case Column::Date:
|
case TransactionInfoRole::Date:
|
||||||
return QString("Date");
|
return QString("Date");
|
||||||
case Column::Description:
|
case TransactionInfoRole::Description:
|
||||||
return QString("Description");
|
return QString("Description");
|
||||||
case Column::Amount:
|
case TransactionInfoRole::Amount:
|
||||||
return QString("Amount");
|
return QString("Amount");
|
||||||
case Column::TxID:
|
case TransactionInfoRole::TxID:
|
||||||
return QString("Txid");
|
return QString("Txid");
|
||||||
case Column::FiatAmount:
|
case TransactionInfoRole::FiatAmount:
|
||||||
return QString("Fiat");
|
return QString("Fiat");
|
||||||
default:
|
default:
|
||||||
return QVariant();
|
return QVariant();
|
||||||
|
@ -205,7 +215,7 @@ bool TransactionHistoryModel::setData(const QModelIndex &index, const QVariant &
|
||||||
QString hash;
|
QString hash;
|
||||||
|
|
||||||
switch (index.column()) {
|
switch (index.column()) {
|
||||||
case Column::Description:
|
case TransactionInfoRole::Description:
|
||||||
{
|
{
|
||||||
m_transactionHistory->transaction(index.row(), [this, &hash, &value](const TransactionInfo &tInfo){
|
m_transactionHistory->transaction(index.row(), [this, &hash, &value](const TransactionInfo &tInfo){
|
||||||
hash = tInfo.hash();
|
hash = tInfo.hash();
|
||||||
|
|
|
@ -21,15 +21,21 @@ class TransactionHistoryModel : public QAbstractTableModel
|
||||||
Q_PROPERTY(TransactionHistory * transactionHistory READ transactionHistory WRITE setTransactionHistory NOTIFY transactionHistoryChanged)
|
Q_PROPERTY(TransactionHistory * transactionHistory READ transactionHistory WRITE setTransactionHistory NOTIFY transactionHistoryChanged)
|
||||||
|
|
||||||
public:
|
public:
|
||||||
enum Column
|
enum TransactionInfoRole
|
||||||
{
|
{
|
||||||
Date = 0,
|
Date = 0,
|
||||||
Description,
|
Description,
|
||||||
Amount,
|
Amount,
|
||||||
TxID,
|
TxID,
|
||||||
FiatAmount,
|
FiatAmount,
|
||||||
|
TransactionIsOutRole,
|
||||||
|
TransactionFailedRole,
|
||||||
|
TransactionPendingRole,
|
||||||
|
TransactionConfirmationsRole,
|
||||||
|
TransactionConfirmationsRequiredRole,
|
||||||
COUNT
|
COUNT
|
||||||
};
|
};
|
||||||
|
Q_ENUM(TransactionInfoRole)
|
||||||
|
|
||||||
explicit TransactionHistoryModel(QObject * parent = nullptr);
|
explicit TransactionHistoryModel(QObject * parent = nullptr);
|
||||||
void setTransactionHistory(TransactionHistory * th);
|
void setTransactionHistory(TransactionHistory * th);
|
||||||
|
|
|
@ -13,6 +13,7 @@
|
||||||
using namespace std::chrono;
|
using namespace std::chrono;
|
||||||
|
|
||||||
|
|
||||||
|
WalletKeysFiles::WalletKeysFiles() = default; // to please Q_DECLARE_METATYPE
|
||||||
WalletKeysFiles::WalletKeysFiles(const QFileInfo &info, int networkType, QString address) :
|
WalletKeysFiles::WalletKeysFiles(const QFileInfo &info, int networkType, QString address) :
|
||||||
m_fileName(info.fileName()),
|
m_fileName(info.fileName()),
|
||||||
m_modified(info.lastModified().toSecsSinceEpoch()),
|
m_modified(info.lastModified().toSecsSinceEpoch()),
|
||||||
|
@ -47,6 +48,10 @@ int WalletKeysFiles::networkType() const {
|
||||||
return m_networkType;
|
return m_networkType;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QVariant WalletKeysFiles::toVariant() const {
|
||||||
|
return QVariant::fromValue<WalletKeysFiles>(*this);
|
||||||
|
}
|
||||||
|
|
||||||
QJsonObject WalletKeysFiles::toJsonObject() const {
|
QJsonObject WalletKeysFiles::toJsonObject() const {
|
||||||
auto item = QJsonObject();
|
auto item = QJsonObject();
|
||||||
item["fileName"] = m_fileName;
|
item["fileName"] = m_fileName;
|
||||||
|
|
|
@ -10,7 +10,9 @@
|
||||||
|
|
||||||
class WalletKeysFiles
|
class WalletKeysFiles
|
||||||
{
|
{
|
||||||
|
Q_GADGET
|
||||||
public:
|
public:
|
||||||
|
WalletKeysFiles();
|
||||||
WalletKeysFiles(const QFileInfo &info, int networkType, QString address);
|
WalletKeysFiles(const QFileInfo &info, int networkType, QString address);
|
||||||
|
|
||||||
QString fileName() const;
|
QString fileName() const;
|
||||||
|
@ -20,6 +22,13 @@ public:
|
||||||
QString address() const;
|
QString address() const;
|
||||||
|
|
||||||
QJsonObject toJsonObject() const;
|
QJsonObject toJsonObject() const;
|
||||||
|
QVariant toVariant() const;
|
||||||
|
|
||||||
|
Q_PROPERTY(qint64 modified READ modified)
|
||||||
|
Q_PROPERTY(QString fileName READ fileName)
|
||||||
|
Q_PROPERTY(QString path READ path)
|
||||||
|
Q_PROPERTY(QString address READ address)
|
||||||
|
Q_PROPERTY(int networkType READ networkType)
|
||||||
|
|
||||||
private:
|
private:
|
||||||
QString m_fileName;
|
QString m_fileName;
|
||||||
|
@ -28,6 +37,8 @@ private:
|
||||||
int m_networkType;
|
int m_networkType;
|
||||||
QString m_address;
|
QString m_address;
|
||||||
};
|
};
|
||||||
|
Q_DECLARE_METATYPE(WalletKeysFiles)
|
||||||
|
|
||||||
|
|
||||||
class WalletKeysFilesModel : public QAbstractTableModel
|
class WalletKeysFilesModel : public QAbstractTableModel
|
||||||
{
|
{
|
||||||
|
|
|
@ -80,8 +80,8 @@ void WSServer::onNewConnection() {
|
||||||
|
|
||||||
// blast wallet listing on connect
|
// blast wallet listing on connect
|
||||||
QJsonArray arr;
|
QJsonArray arr;
|
||||||
for(const WalletKeysFiles &wallet: m_ctx->listWallets())
|
for(const QVariant &wallet: m_ctx->listWallets())
|
||||||
arr << wallet.toJsonObject();
|
arr << wallet.value<WalletKeysFiles>().toJsonObject();
|
||||||
auto welcomeWalletMessage = WSServer::createWSMessage("walletList", arr);
|
auto welcomeWalletMessage = WSServer::createWSMessage("walletList", arr);
|
||||||
pSocket->sendBinaryMessage(welcomeWalletMessage);
|
pSocket->sendBinaryMessage(welcomeWalletMessage);
|
||||||
|
|
||||||
|
@ -336,9 +336,6 @@ void WSServer::onWalletCreatedError(const QString &err) {
|
||||||
void WSServer::onWalletCreated(Wallet *wallet) {
|
void WSServer::onWalletCreated(Wallet *wallet) {
|
||||||
auto obj = wallet->toJsonObject();
|
auto obj = wallet->toJsonObject();
|
||||||
sendAll("walletCreated", obj);
|
sendAll("walletCreated", obj);
|
||||||
|
|
||||||
// emit signal on behalf of walletManager
|
|
||||||
m_ctx->walletManager->walletOpened(wallet);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void WSServer::onSynchronized() {
|
void WSServer::onSynchronized() {
|
||||||
|
@ -350,7 +347,7 @@ void WSServer::onWalletOpenPasswordRequired(bool invalidPassword, const QString
|
||||||
QJsonObject obj;
|
QJsonObject obj;
|
||||||
obj["invalidPassword"] = invalidPassword;
|
obj["invalidPassword"] = invalidPassword;
|
||||||
obj["path"] = path;
|
obj["path"] = path;
|
||||||
sendAll("synchronized", obj);
|
sendAll("walletOpenPasswordRequired", obj);
|
||||||
}
|
}
|
||||||
|
|
||||||
void WSServer::onConnectionStatusChanged(int status) {
|
void WSServer::onConnectionStatusChanged(int status) {
|
||||||
|
|
107
src/vr/main.cpp
Normal file
107
src/vr/main.cpp
Normal file
|
@ -0,0 +1,107 @@
|
||||||
|
// SPDX-License-Identifier: BSD-3-Clause
|
||||||
|
// Copyright (c) 2020-2021, The Monero Project.
|
||||||
|
|
||||||
|
#include <iostream>
|
||||||
|
#include <QResource>
|
||||||
|
#include <QApplication>
|
||||||
|
#include <QCoreApplication>
|
||||||
|
#include <QQmlComponent>
|
||||||
|
#include <QtCore>
|
||||||
|
#include <QtGui>
|
||||||
|
#include <QQmlApplicationEngine>
|
||||||
|
#include <QtQml>
|
||||||
|
#include <QQuickView>
|
||||||
|
#include <QQuickItem>
|
||||||
|
|
||||||
|
#include "openvr.h"
|
||||||
|
#include "vr/openvr_init.h"
|
||||||
|
#include "vr/main.h"
|
||||||
|
|
||||||
|
#include "libwalletqt/TransactionInfo.h"
|
||||||
|
#include "libwalletqt/TransactionHistory.h"
|
||||||
|
#include "model/TransactionHistoryModel.h"
|
||||||
|
#include "model/TransactionHistoryProxyModel.h"
|
||||||
|
#include "libwalletqt/WalletManager.h"
|
||||||
|
|
||||||
|
#include "utils/keysfiles.h"
|
||||||
|
|
||||||
|
namespace wowletvr {
|
||||||
|
|
||||||
|
void check_error(int line, vr::EVRInitError error) { if (error != 0) printf("%d: error %s\n", line, VR_GetVRInitErrorAsSymbol(error)); }
|
||||||
|
|
||||||
|
WowletVR::WowletVR(AppContext *ctx, QCommandLineParser *parser, QObject *parent) :
|
||||||
|
QObject(parent), ctx(ctx), m_parser(parser) {
|
||||||
|
desktopMode = m_parser->isSet("openvr-debug");
|
||||||
|
|
||||||
|
#ifdef Q_OS_WIN
|
||||||
|
if(desktopMode)
|
||||||
|
qputenv("QMLSCENE_DEVICE", "softwarecontext");
|
||||||
|
#endif
|
||||||
|
|
||||||
|
qDebug() << "QMLSCENE_DEVICE: " << qgetenv("QMLSCENE_DEVICE");
|
||||||
|
|
||||||
|
m_engine.rootContext()->setContextProperty("homePath", QDir::homePath());
|
||||||
|
m_engine.rootContext()->setContextProperty("applicationDirectory", QApplication::applicationDirPath());
|
||||||
|
m_engine.rootContext()->setContextProperty("idealThreadCount", QThread::idealThreadCount());
|
||||||
|
m_engine.rootContext()->setContextProperty("qtRuntimeVersion", qVersion());
|
||||||
|
m_engine.rootContext()->setContextProperty("ctx", ctx);
|
||||||
|
|
||||||
|
// qmlRegisterType<clipboardAdapter>("moneroComponents.Clipboard", 1, 0, "Clipboard");
|
||||||
|
qRegisterMetaType<NetworkType::Type>();
|
||||||
|
qmlRegisterType<NetworkType>("wowlet.NetworkType", 1, 0, "NetworkType");
|
||||||
|
|
||||||
|
qmlRegisterUncreatableType<WalletKeysFiles>("wowlet.WalletKeysFiles", 1, 0, "WalletKeysFiles", "lol");
|
||||||
|
qmlRegisterUncreatableType<Wallet>("wowlet.Wallet", 1, 0, "Wallet", "Wallet can't be instantiated directly");
|
||||||
|
qmlRegisterType<WalletManager>("wowlet.WalletManager", 1, 0, "WalletManager");
|
||||||
|
|
||||||
|
qmlRegisterUncreatableType<TransactionHistoryProxyModel>("wowlet.TransactionHistoryProxyModel", 1, 0, "TransactionHistoryProxyModel", "TransactionHistoryProxyModel can't be instantiated directly");
|
||||||
|
qmlRegisterUncreatableType<TransactionHistoryModel>("wowlet.TransactionHistoryModel", 1, 0, "TransactionHistoryModel", "TransactionHistoryModel can't be instantiated directly");
|
||||||
|
qmlRegisterUncreatableType<TransactionInfo>("wowlet.TransactionInfo", 1, 0, "TransactionInfo", "TransactionHistory can't be instantiated directly");
|
||||||
|
qmlRegisterUncreatableType<TransactionHistory>("wowlet.TransactionHistory", 1, 0, "TransactionHistory", "TransactionHistory can't be instantiated directly");
|
||||||
|
|
||||||
|
qRegisterMetaType<PendingTransaction::Priority>();
|
||||||
|
qRegisterMetaType<TransactionInfo::Direction>();
|
||||||
|
qRegisterMetaType<TransactionHistoryModel::TransactionInfoRole>();
|
||||||
|
|
||||||
|
// @TODO: custom DPI / AA
|
||||||
|
// QCoreApplication::setAttribute( Qt::AA_UseDesktopOpenGL );
|
||||||
|
// QCoreApplication::setAttribute( Qt::AA_Use96Dpi );
|
||||||
|
|
||||||
|
auto widgetUrl = QUrl(QStringLiteral("qrc:///main"));
|
||||||
|
m_component = new QQmlComponent(&m_engine, widgetUrl);
|
||||||
|
|
||||||
|
this->errors = m_component->errors();
|
||||||
|
for (auto &e : this->errors)
|
||||||
|
qCritical() << "QML Error: " << e.toString().toStdString().c_str();
|
||||||
|
|
||||||
|
if(!desktopMode) {
|
||||||
|
openvr_init::initializeOpenVR(openvr_init::OpenVrInitializationType::Overlay);
|
||||||
|
m_controller = new wowletvr::OverlayController(desktopMode, m_engine);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void WowletVR::render() {
|
||||||
|
auto quickObj = m_component->create();
|
||||||
|
QQuickItem *quickObjItem = qobject_cast<QQuickItem*>(quickObj);
|
||||||
|
|
||||||
|
auto displayName = application_strings::applicationDisplayName;
|
||||||
|
auto appKey = application_strings::applicationKey;
|
||||||
|
|
||||||
|
if(desktopMode) {
|
||||||
|
auto m_pWindow = new QQuickWindow();
|
||||||
|
qobject_cast<QQuickItem *>(quickObj)->setParentItem(m_pWindow->contentItem());
|
||||||
|
m_pWindow->setGeometry(0, 0,
|
||||||
|
static_cast<int>(qobject_cast<QQuickItem *>(quickObj)->width()),
|
||||||
|
static_cast<int>(qobject_cast<QQuickItem *>(quickObj)->height()));
|
||||||
|
m_pWindow->show();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
m_controller->SetWidget(quickObjItem, displayName, appKey);
|
||||||
|
}
|
||||||
|
|
||||||
|
WowletVR::~WowletVR() {
|
||||||
|
int weoignwieog = 1;
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
38
src/vr/main.h
Normal file
38
src/vr/main.h
Normal file
|
@ -0,0 +1,38 @@
|
||||||
|
// SPDX-License-Identifier: BSD-3-Clause
|
||||||
|
// Copyright (c) 2020-2021, The Monero Project.
|
||||||
|
|
||||||
|
#ifndef WOWLET_MAIN_H
|
||||||
|
#define WOWLET_MAIN_H
|
||||||
|
|
||||||
|
#include <QtCore>
|
||||||
|
#include <QQmlError>
|
||||||
|
#include <QQmlApplicationEngine>
|
||||||
|
#include <QtQml>
|
||||||
|
|
||||||
|
#include "overlaycontroller.h"
|
||||||
|
#include "appcontext.h"
|
||||||
|
|
||||||
|
namespace wowletvr {
|
||||||
|
|
||||||
|
class WowletVR : public QObject {
|
||||||
|
Q_OBJECT
|
||||||
|
public:
|
||||||
|
explicit WowletVR(AppContext *ctx, QCommandLineParser *cmdargs, QObject *parent = nullptr);
|
||||||
|
~WowletVR() override;
|
||||||
|
|
||||||
|
void render();
|
||||||
|
|
||||||
|
QList<QQmlError> errors;
|
||||||
|
|
||||||
|
private:
|
||||||
|
AppContext *ctx;
|
||||||
|
QCommandLineParser *m_parser;
|
||||||
|
QQmlEngine m_engine;
|
||||||
|
QQmlComponent *m_component;
|
||||||
|
bool desktopMode = false;
|
||||||
|
wowletvr::OverlayController *m_controller;
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif //WOWLET_MAIN_H
|
74
src/vr/openvr_init.cpp
Executable file
74
src/vr/openvr_init.cpp
Executable file
|
@ -0,0 +1,74 @@
|
||||||
|
// SPDX-License-Identifier: BSD-3-Clause
|
||||||
|
// Copyright (c) 2020-2021, The Monero Project.
|
||||||
|
// Copyright (c) OpenVR Advanced Settings
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
#include <openvr.h>
|
||||||
|
#include <QDebug>
|
||||||
|
#include <QMessageBox>
|
||||||
|
#include "openvr_init.h"
|
||||||
|
|
||||||
|
namespace openvr_init
|
||||||
|
{
|
||||||
|
bool initializeProperly(const OpenVrInitializationType initType) {
|
||||||
|
auto initializationType = vr::EVRApplicationType::VRApplication_Other;
|
||||||
|
if (initType == OpenVrInitializationType::Overlay) {
|
||||||
|
initializationType = vr::EVRApplicationType::VRApplication_Overlay;
|
||||||
|
} else if (initType == OpenVrInitializationType::Utility) {
|
||||||
|
initializationType = vr::EVRApplicationType::VRApplication_Utility;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto initError = vr::VRInitError_None;
|
||||||
|
vr::VR_Init(&initError, initializationType);
|
||||||
|
if (initError != vr::VRInitError_None) {
|
||||||
|
if (initError == vr::VRInitError_Init_HmdNotFound || initError == vr::VRInitError_Init_HmdNotFoundPresenceFailed) {
|
||||||
|
QMessageBox::critical(nullptr, "Wowlet VR", "Could not find HMD!");
|
||||||
|
}
|
||||||
|
qCritical() << "Failed to initialize OpenVR: " << std::string(vr::VR_GetVRInitErrorAsEnglishDescription(initError)).c_str();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
qInfo() << "OpenVR initialized successfully.";
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool initializeOpenVR(const OpenVrInitializationType initType)
|
||||||
|
{
|
||||||
|
bool res = initializeProperly(initType);
|
||||||
|
if(!res)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// Check whether OpenVR is too outdated
|
||||||
|
if (!vr::VR_IsInterfaceVersionValid(vr::IVRSystem_Version)) {
|
||||||
|
return reportVersionError(vr::IVRSystem_Version);
|
||||||
|
} else if (!vr::VR_IsInterfaceVersionValid(vr::IVRSettings_Version)) {
|
||||||
|
return reportVersionError(vr::IVRSettings_Version);
|
||||||
|
} else if (!vr::VR_IsInterfaceVersionValid(vr::IVROverlay_Version)) {
|
||||||
|
return reportVersionError(vr::IVROverlay_Version);
|
||||||
|
} else if (!vr::VR_IsInterfaceVersionValid(vr::IVRApplications_Version)) {
|
||||||
|
return reportVersionError(vr::IVRApplications_Version);
|
||||||
|
} else if (!vr::VR_IsInterfaceVersionValid(vr::IVRChaperone_Version)) {
|
||||||
|
return reportVersionError(vr::IVRChaperone_Version);
|
||||||
|
} else if (!vr::VR_IsInterfaceVersionValid(vr::IVRChaperoneSetup_Version)) {
|
||||||
|
return reportVersionError(vr::IVRChaperoneSetup_Version);
|
||||||
|
} else if (!vr::VR_IsInterfaceVersionValid(vr::IVRCompositor_Version)) {
|
||||||
|
return reportVersionError(vr::IVRCompositor_Version);
|
||||||
|
} else if (!vr::VR_IsInterfaceVersionValid(vr::IVRNotifications_Version)) {
|
||||||
|
return reportVersionError(vr::IVRNotifications_Version);
|
||||||
|
} else if (!vr::VR_IsInterfaceVersionValid(vr::IVRInput_Version)) {
|
||||||
|
return reportVersionError(vr::IVRInput_Version);
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool reportVersionError(const char* const interfaceAndVersion) {
|
||||||
|
// The function call and error message was the same for all version checks.
|
||||||
|
// Specific error messages are unlikely to be necessary since both the type
|
||||||
|
// and version are in the string and will be output.
|
||||||
|
auto msg = "OpenVR version is too outdated. Please update OpenVR: " + QString(interfaceAndVersion);
|
||||||
|
QMessageBox::critical(nullptr, "Wowlet VR", msg);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace openvr_init
|
16
src/vr/openvr_init.h
Executable file
16
src/vr/openvr_init.h
Executable file
|
@ -0,0 +1,16 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
namespace openvr_init
|
||||||
|
{
|
||||||
|
|
||||||
|
enum class OpenVrInitializationType
|
||||||
|
{
|
||||||
|
Overlay,
|
||||||
|
Utility,
|
||||||
|
};
|
||||||
|
|
||||||
|
bool initializeProperly(OpenVrInitializationType initType);
|
||||||
|
bool initializeOpenVR(OpenVrInitializationType initType );
|
||||||
|
bool reportVersionError(const char* interfaceAndVersion);
|
||||||
|
|
||||||
|
} // namespace openvr_init
|
484
src/vr/overlaycontroller.cpp
Executable file
484
src/vr/overlaycontroller.cpp
Executable file
|
@ -0,0 +1,484 @@
|
||||||
|
// SPDX-License-Identifier: BSD-3-Clause
|
||||||
|
// Copyright (c) 2020-2021, The Monero Project.
|
||||||
|
// Copyright (c) OpenVR Advanced Settings
|
||||||
|
|
||||||
|
#include <QOpenGLFramebufferObjectFormat>
|
||||||
|
#include <QOpenGLPaintDevice>
|
||||||
|
#include <QPainter>
|
||||||
|
#include <QQuickView>
|
||||||
|
#include <QApplication>
|
||||||
|
#include <QQmlEngine>
|
||||||
|
#include <QQmlContext>
|
||||||
|
#include <QtWidgets/QWidget>
|
||||||
|
#include <QMouseEvent>
|
||||||
|
#include <QtWidgets/QGraphicsSceneMouseEvent>
|
||||||
|
#include <QtWidgets/QApplication>
|
||||||
|
#include <QtWidgets/QGraphicsEllipseItem>
|
||||||
|
#include <QOpenGLExtraFunctions>
|
||||||
|
#include <QCursor>
|
||||||
|
#include <QProcess>
|
||||||
|
#include <QMessageBox>
|
||||||
|
#include <iostream>
|
||||||
|
#include <cmath>
|
||||||
|
|
||||||
|
#include "overlaycontroller.h"
|
||||||
|
#include <openvr.h>
|
||||||
|
|
||||||
|
// application namespace
|
||||||
|
namespace wowletvr
|
||||||
|
{
|
||||||
|
|
||||||
|
OverlayController::OverlayController(bool desktopMode, QQmlEngine& qmlEngine) :
|
||||||
|
QObject(),
|
||||||
|
m_desktopMode(desktopMode)
|
||||||
|
{
|
||||||
|
// Arbitrarily chosen Max Length of Directory path, should be sufficient for
|
||||||
|
// Any set-up
|
||||||
|
const uint32_t maxLength = 16192;
|
||||||
|
uint32_t requiredLength;
|
||||||
|
|
||||||
|
char tempRuntimePath[maxLength];
|
||||||
|
bool pathIsGood = vr::VR_GetRuntimePath( tempRuntimePath, maxLength, &requiredLength );
|
||||||
|
|
||||||
|
// Throw Error If over 16k characters in path string
|
||||||
|
if ( !pathIsGood )
|
||||||
|
{
|
||||||
|
qCritical() << "Error Finding VR Runtime Path, Attempting Recovery: ";
|
||||||
|
uint32_t maxLengthRe = requiredLength;
|
||||||
|
qInfo() << "Open VR reporting Required path length of: "
|
||||||
|
<< maxLengthRe;
|
||||||
|
}
|
||||||
|
|
||||||
|
m_runtimePathUrl = QUrl::fromLocalFile( tempRuntimePath );
|
||||||
|
qInfo() << "VR Runtime Path: " << m_runtimePathUrl.toLocalFile();
|
||||||
|
|
||||||
|
QSurfaceFormat format;
|
||||||
|
// Qt's QOpenGLPaintDevice is not compatible with OpenGL versions >= 3.0
|
||||||
|
// NVIDIA does not care, but unfortunately AMD does
|
||||||
|
// Are subtle changes to the semantics of OpenGL functions actually covered
|
||||||
|
// by the compatibility profile, and this is an AMD bug?
|
||||||
|
format.setVersion( 2, 1 );
|
||||||
|
// format.setProfile( QSurfaceFormat::CompatibilityProfile );
|
||||||
|
format.setDepthBufferSize( 16 );
|
||||||
|
format.setStencilBufferSize( 8 );
|
||||||
|
format.setSamples( 16 );
|
||||||
|
|
||||||
|
m_openGLContext.setFormat( format );
|
||||||
|
if ( !m_openGLContext.create() ) {
|
||||||
|
throw std::runtime_error( "Could not create OpenGL context" );
|
||||||
|
}
|
||||||
|
|
||||||
|
// create an offscreen surface to attach the context and FBO to
|
||||||
|
m_offscreenSurface.setFormat( m_openGLContext.format() );
|
||||||
|
m_offscreenSurface.create();
|
||||||
|
m_openGLContext.makeCurrent( &m_offscreenSurface );
|
||||||
|
|
||||||
|
if (!vr::VROverlay()){
|
||||||
|
QMessageBox::critical(nullptr, "Wowlet VR Overlay", "Is OpenVR running?");
|
||||||
|
throw std::runtime_error( std::string( "No Overlay interface" ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set qml context
|
||||||
|
qmlEngine.rootContext()->setContextProperty("applicationVersion", "1337");
|
||||||
|
qmlEngine.rootContext()->setContextProperty("vrRuntimePath", getVRRuntimePathUrl());
|
||||||
|
|
||||||
|
// Pretty disgusting trick to allow qmlRegisterSingletonType to continue
|
||||||
|
// working with the lambdas that were already there. The callback function
|
||||||
|
// in qmlRegisterSingletonType won't work with any lambdas that capture the
|
||||||
|
// environment. The alternative to making a static pointer to this was
|
||||||
|
// rewriting all QML to not be singletons, which should probably be done
|
||||||
|
// whenever possible.
|
||||||
|
static OverlayController* const objectAddress = this;
|
||||||
|
constexpr auto qmlSingletonImportName = "ovrwow.wowletvr";
|
||||||
|
qmlRegisterSingletonType<OverlayController>(
|
||||||
|
qmlSingletonImportName,
|
||||||
|
1,
|
||||||
|
0,
|
||||||
|
"OverlayController",
|
||||||
|
[]( QQmlEngine*, QJSEngine* ) {
|
||||||
|
QObject* obj = objectAddress;
|
||||||
|
QQmlEngine::setObjectOwnership( obj, QQmlEngine::CppOwnership );
|
||||||
|
return obj;
|
||||||
|
});
|
||||||
|
|
||||||
|
qInfo() << "OPENSSL VERSION: " << QSslSocket::sslLibraryBuildVersionString();
|
||||||
|
}
|
||||||
|
|
||||||
|
OverlayController::~OverlayController() {
|
||||||
|
Shutdown();
|
||||||
|
}
|
||||||
|
|
||||||
|
void OverlayController::exitApp() {
|
||||||
|
Shutdown();
|
||||||
|
QApplication::exit();
|
||||||
|
|
||||||
|
qInfo() << "All systems exited.";
|
||||||
|
exit( EXIT_SUCCESS );
|
||||||
|
// Does not fallthrough
|
||||||
|
}
|
||||||
|
|
||||||
|
void OverlayController::Shutdown() {
|
||||||
|
if (m_pRenderTimer)
|
||||||
|
{
|
||||||
|
disconnect( &m_renderControl,
|
||||||
|
SIGNAL( renderRequested() ),
|
||||||
|
this,
|
||||||
|
SLOT( OnRenderRequest() ) );
|
||||||
|
disconnect( &m_renderControl,
|
||||||
|
SIGNAL( sceneChanged() ),
|
||||||
|
this,
|
||||||
|
SLOT( OnRenderRequest() ) );
|
||||||
|
disconnect( m_pRenderTimer.get(),
|
||||||
|
SIGNAL( timeout() ),
|
||||||
|
this,
|
||||||
|
SLOT( renderOverlay() ) );
|
||||||
|
m_pRenderTimer->stop();
|
||||||
|
m_pRenderTimer.reset();
|
||||||
|
}
|
||||||
|
m_pFbo.reset();
|
||||||
|
}
|
||||||
|
|
||||||
|
void OverlayController::SetWidget( QQuickItem* quickItem,
|
||||||
|
const std::string& name,
|
||||||
|
const std::string& key )
|
||||||
|
{
|
||||||
|
if ( !m_desktopMode )
|
||||||
|
{
|
||||||
|
vr::VROverlayError overlayError
|
||||||
|
= vr::VROverlay()->CreateDashboardOverlay(
|
||||||
|
key.c_str(),
|
||||||
|
name.c_str(),
|
||||||
|
&m_ulOverlayHandle,
|
||||||
|
&m_ulOverlayThumbnailHandle );
|
||||||
|
if ( overlayError != vr::VROverlayError_None )
|
||||||
|
{
|
||||||
|
if ( overlayError == vr::VROverlayError_KeyInUse )
|
||||||
|
{
|
||||||
|
QMessageBox::critical( nullptr,
|
||||||
|
"Wowlet VR Overlay",
|
||||||
|
"Another instance is already running." );
|
||||||
|
}
|
||||||
|
throw std::runtime_error( std::string(
|
||||||
|
"Failed to create Overlay: "
|
||||||
|
+ std::string( vr::VROverlay()->GetOverlayErrorNameFromEnum(
|
||||||
|
overlayError ) ) ) );
|
||||||
|
}
|
||||||
|
vr::VROverlay()->SetOverlayWidthInMeters( m_ulOverlayHandle, 2.5f );
|
||||||
|
vr::VROverlay()->SetOverlayInputMethod(
|
||||||
|
m_ulOverlayHandle, vr::VROverlayInputMethod_Mouse );
|
||||||
|
vr::VROverlay()->SetOverlayFlag(
|
||||||
|
m_ulOverlayHandle,
|
||||||
|
vr::VROverlayFlags_SendVRSmoothScrollEvents,
|
||||||
|
true );
|
||||||
|
|
||||||
|
constexpr auto thumbiconFilename = "img/icons/thumbicon.png";
|
||||||
|
const auto thumbIconPath = paths::binaryDirectoryFindFile( thumbiconFilename );
|
||||||
|
if ( !thumbIconPath.empty() ) {
|
||||||
|
vr::VROverlay()->SetOverlayFromFile( m_ulOverlayThumbnailHandle, thumbIconPath.c_str() );
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
qCritical() << "Could not find thumbnail icon \"" << thumbiconFilename << "\"";
|
||||||
|
}
|
||||||
|
|
||||||
|
// Too many render calls in too short time overwhelm Qt and an
|
||||||
|
// assertion gets thrown. Therefore we use an timer to delay render
|
||||||
|
// calls
|
||||||
|
m_pRenderTimer.reset(new QTimer());
|
||||||
|
m_pRenderTimer->setSingleShot( false );
|
||||||
|
m_pRenderTimer->setInterval( 5 );
|
||||||
|
connect( m_pRenderTimer.get(),
|
||||||
|
SIGNAL( timeout() ),
|
||||||
|
this,
|
||||||
|
SLOT( renderOverlay() ) );
|
||||||
|
|
||||||
|
QOpenGLFramebufferObjectFormat fboFormat;
|
||||||
|
fboFormat.setAttachment(
|
||||||
|
QOpenGLFramebufferObject::CombinedDepthStencil );
|
||||||
|
fboFormat.setTextureTarget( GL_TEXTURE_2D );
|
||||||
|
m_pFbo.reset( new QOpenGLFramebufferObject(
|
||||||
|
static_cast<int>( quickItem->width() ),
|
||||||
|
static_cast<int>( quickItem->height() ),
|
||||||
|
fboFormat ) );
|
||||||
|
|
||||||
|
m_window.setRenderTarget( m_pFbo.get() );
|
||||||
|
quickItem->setParentItem( m_window.contentItem() );
|
||||||
|
m_window.setGeometry( 0,
|
||||||
|
0,
|
||||||
|
static_cast<int>( quickItem->width() ),
|
||||||
|
static_cast<int>( quickItem->height() ) );
|
||||||
|
m_renderControl.initialize( &m_openGLContext );
|
||||||
|
|
||||||
|
vr::HmdVector2_t vecWindowSize
|
||||||
|
= { static_cast<float>( quickItem->width() ),
|
||||||
|
static_cast<float>( quickItem->height() ) };
|
||||||
|
vr::VROverlay()->SetOverlayMouseScale( m_ulOverlayHandle,
|
||||||
|
&vecWindowSize );
|
||||||
|
|
||||||
|
connect( &m_renderControl,
|
||||||
|
SIGNAL( renderRequested() ),
|
||||||
|
this,
|
||||||
|
SLOT( OnRenderRequest() ) );
|
||||||
|
connect( &m_renderControl,
|
||||||
|
SIGNAL( sceneChanged() ),
|
||||||
|
this,
|
||||||
|
SLOT( OnRenderRequest() ) );
|
||||||
|
|
||||||
|
m_pRenderTimer->start();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void OverlayController::OnRenderRequest() {
|
||||||
|
if ( m_pRenderTimer && !m_pRenderTimer->isActive() )
|
||||||
|
{
|
||||||
|
m_pRenderTimer->start();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void OverlayController::renderOverlay() {
|
||||||
|
if ( !m_desktopMode )
|
||||||
|
{
|
||||||
|
// skip rendering if the overlay isn't visible
|
||||||
|
if ( !vr::VROverlay()
|
||||||
|
|| ( !vr::VROverlay()->IsOverlayVisible( m_ulOverlayHandle )
|
||||||
|
&& !vr::VROverlay()->IsOverlayVisible(
|
||||||
|
m_ulOverlayThumbnailHandle ) ) )
|
||||||
|
return;
|
||||||
|
m_renderControl.polishItems();
|
||||||
|
m_renderControl.sync();
|
||||||
|
m_renderControl.render();
|
||||||
|
|
||||||
|
GLuint unTexture = m_pFbo->texture();
|
||||||
|
if ( unTexture != 0 )
|
||||||
|
{
|
||||||
|
#if defined _WIN64 || defined _LP64
|
||||||
|
// To avoid any compiler warning because of cast to a larger
|
||||||
|
// pointer type (warning C4312 on VC)
|
||||||
|
vr::Texture_t texture = { reinterpret_cast<void*>(
|
||||||
|
static_cast<uint64_t>( unTexture ) ),
|
||||||
|
vr::TextureType_OpenGL,
|
||||||
|
vr::ColorSpace_Auto };
|
||||||
|
#else
|
||||||
|
vr::Texture_t texture = { reinterpret_cast<void*>( unTexture ),
|
||||||
|
vr::TextureType_OpenGL,
|
||||||
|
vr::ColorSpace_Auto };
|
||||||
|
#endif
|
||||||
|
vr::VROverlay()->SetOverlayTexture( m_ulOverlayHandle, &texture );
|
||||||
|
}
|
||||||
|
m_openGLContext.functions()->glFlush(); // We need to flush otherwise
|
||||||
|
// the texture may be empty.*/
|
||||||
|
|
||||||
|
if(m_customTickRateCounter % k_nonVsyncTickRate == 0) {
|
||||||
|
mainEventLoop();
|
||||||
|
m_customTickRateCounter = 0;
|
||||||
|
} else {
|
||||||
|
m_customTickRateCounter += 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool OverlayController::pollNextEvent( vr::VROverlayHandle_t ulOverlayHandle,
|
||||||
|
vr::VREvent_t* pEvent ) {
|
||||||
|
if ( isDesktopMode() )
|
||||||
|
{
|
||||||
|
return vr::VRSystem()->PollNextEvent( pEvent, sizeof( vr::VREvent_t ) );
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return vr::VROverlay()->PollNextOverlayEvent(
|
||||||
|
ulOverlayHandle, pEvent, sizeof( vr::VREvent_t ) );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
QPoint OverlayController::getMousePositionForEvent( vr::VREvent_Mouse_t mouse ) {
|
||||||
|
float y = mouse.y;
|
||||||
|
#ifdef __linux__
|
||||||
|
float h = static_cast<float>( m_window.height() );
|
||||||
|
y = h - y;
|
||||||
|
#endif
|
||||||
|
return QPoint( static_cast<int>( mouse.x ), static_cast<int>( y ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
void OverlayController::mainEventLoop() {
|
||||||
|
if ( !vr::VRSystem() )
|
||||||
|
return;
|
||||||
|
|
||||||
|
vr::VREvent_t vrEvent;
|
||||||
|
|
||||||
|
while ( pollNextEvent( m_ulOverlayHandle, &vrEvent ) ) {
|
||||||
|
switch ( vrEvent.eventType )
|
||||||
|
{
|
||||||
|
case vr::VREvent_MouseMove:
|
||||||
|
{
|
||||||
|
QPoint ptNewMouse = getMousePositionForEvent( vrEvent.data.mouse );
|
||||||
|
if ( ptNewMouse != m_ptLastMouse )
|
||||||
|
{
|
||||||
|
QMouseEvent mouseEvent( QEvent::MouseMove,
|
||||||
|
ptNewMouse,
|
||||||
|
m_window.mapToGlobal( ptNewMouse ),
|
||||||
|
Qt::NoButton,
|
||||||
|
m_lastMouseButtons,
|
||||||
|
nullptr );
|
||||||
|
m_ptLastMouse = ptNewMouse;
|
||||||
|
QCoreApplication::sendEvent( &m_window, &mouseEvent );
|
||||||
|
OnRenderRequest();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case vr::VREvent_MouseButtonDown:
|
||||||
|
{
|
||||||
|
QPoint ptNewMouse = getMousePositionForEvent( vrEvent.data.mouse );
|
||||||
|
Qt::MouseButton button
|
||||||
|
= vrEvent.data.mouse.button == vr::VRMouseButton_Right
|
||||||
|
? Qt::RightButton
|
||||||
|
: Qt::LeftButton;
|
||||||
|
m_lastMouseButtons |= button;
|
||||||
|
QMouseEvent mouseEvent( QEvent::MouseButtonPress,
|
||||||
|
ptNewMouse,
|
||||||
|
m_window.mapToGlobal( ptNewMouse ),
|
||||||
|
button,
|
||||||
|
m_lastMouseButtons,
|
||||||
|
nullptr );
|
||||||
|
QCoreApplication::sendEvent( &m_window, &mouseEvent );
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case vr::VREvent_MouseButtonUp:
|
||||||
|
{
|
||||||
|
QPoint ptNewMouse = getMousePositionForEvent( vrEvent.data.mouse );
|
||||||
|
Qt::MouseButton button
|
||||||
|
= vrEvent.data.mouse.button == vr::VRMouseButton_Right
|
||||||
|
? Qt::RightButton
|
||||||
|
: Qt::LeftButton;
|
||||||
|
m_lastMouseButtons &= ~button;
|
||||||
|
QMouseEvent mouseEvent( QEvent::MouseButtonRelease,
|
||||||
|
ptNewMouse,
|
||||||
|
m_window.mapToGlobal( ptNewMouse ),
|
||||||
|
button,
|
||||||
|
m_lastMouseButtons,
|
||||||
|
nullptr );
|
||||||
|
QCoreApplication::sendEvent( &m_window, &mouseEvent );
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case vr::VREvent_ScrollSmooth:
|
||||||
|
{
|
||||||
|
// Wheel speed is defined as 1/8 of a degree
|
||||||
|
QWheelEvent wheelEvent(
|
||||||
|
m_ptLastMouse,
|
||||||
|
m_window.mapToGlobal( m_ptLastMouse ),
|
||||||
|
QPoint(),
|
||||||
|
QPoint( static_cast<int>( vrEvent.data.scroll.xdelta
|
||||||
|
* ( 360.0f * 8.0f ) ),
|
||||||
|
static_cast<int>( vrEvent.data.scroll.ydelta
|
||||||
|
* ( 360.0f * 8.0f ) ) ),
|
||||||
|
0,
|
||||||
|
Qt::Vertical,
|
||||||
|
m_lastMouseButtons,
|
||||||
|
nullptr );
|
||||||
|
QCoreApplication::sendEvent( &m_window, &wheelEvent );
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case vr::VREvent_OverlayShown:
|
||||||
|
{
|
||||||
|
m_window.update();
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case vr::VREvent_Quit:
|
||||||
|
{
|
||||||
|
qInfo() << "Received quit request.";
|
||||||
|
vr::VRSystem()->AcknowledgeQuit_Exiting(); // Let us buy some
|
||||||
|
// time just in case
|
||||||
|
|
||||||
|
exitApp();
|
||||||
|
// Won't fallthrough, but also exitApp() wont, but QT won't
|
||||||
|
// acknowledge
|
||||||
|
exit( EXIT_SUCCESS );
|
||||||
|
}
|
||||||
|
|
||||||
|
case vr::VREvent_DashboardActivated:
|
||||||
|
{
|
||||||
|
qDebug() << "Dashboard activated";
|
||||||
|
m_dashboardVisible = true;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case vr::VREvent_DashboardDeactivated:
|
||||||
|
{
|
||||||
|
qDebug() << "Dashboard deactivated";
|
||||||
|
m_dashboardVisible = false;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case vr::VREvent_KeyboardDone:
|
||||||
|
{
|
||||||
|
char keyboardBuffer[1024];
|
||||||
|
vr::VROverlay()->GetKeyboardText( keyboardBuffer, 1024 );
|
||||||
|
emit keyBoardInputSignal( QString( keyboardBuffer ),
|
||||||
|
static_cast<unsigned long>(
|
||||||
|
vrEvent.data.keyboard.uUserValue ) );
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( m_ulOverlayThumbnailHandle != vr::k_ulOverlayHandleInvalid ) {
|
||||||
|
while ( vr::VROverlay()->PollNextOverlayEvent(
|
||||||
|
m_ulOverlayThumbnailHandle, &vrEvent, sizeof( vrEvent ) ) )
|
||||||
|
{
|
||||||
|
switch ( vrEvent.eventType )
|
||||||
|
{
|
||||||
|
case vr::VREvent_OverlayShown:
|
||||||
|
{
|
||||||
|
m_window.update();
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void OverlayController::showKeyboard(QString existingText, unsigned long userValue)
|
||||||
|
{
|
||||||
|
vr::VROverlay()->ShowKeyboardForOverlay(
|
||||||
|
m_ulOverlayHandle,
|
||||||
|
vr::k_EGamepadTextInputModeNormal,
|
||||||
|
vr::k_EGamepadTextInputLineModeSingleLine,
|
||||||
|
0,
|
||||||
|
"Advanced Settings Overlay",
|
||||||
|
1024,
|
||||||
|
existingText.toStdString().c_str(),
|
||||||
|
userValue);
|
||||||
|
setKeyboardPos();
|
||||||
|
}
|
||||||
|
|
||||||
|
void OverlayController::setKeyboardPos()
|
||||||
|
{
|
||||||
|
vr::HmdVector2_t emptyvec;
|
||||||
|
emptyvec.v[0] = 0;
|
||||||
|
emptyvec.v[1] = 0;
|
||||||
|
vr::HmdRect2_t empty;
|
||||||
|
empty.vTopLeft = emptyvec;
|
||||||
|
empty.vBottomRight = emptyvec;
|
||||||
|
vr::VROverlay()->SetKeyboardPositionForOverlay( m_ulOverlayHandle, empty );
|
||||||
|
}
|
||||||
|
|
||||||
|
QUrl OverlayController::getVRRuntimePathUrl() {
|
||||||
|
return m_runtimePathUrl;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool OverlayController::soundDisabled() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
const vr::VROverlayHandle_t& OverlayController::overlayHandle() {
|
||||||
|
return m_ulOverlayHandle;
|
||||||
|
}
|
||||||
|
|
||||||
|
const vr::VROverlayHandle_t& OverlayController::overlayThumbnailHandle() {
|
||||||
|
return m_ulOverlayThumbnailHandle;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace wowletvr
|
134
src/vr/overlaycontroller.h
Executable file
134
src/vr/overlaycontroller.h
Executable file
|
@ -0,0 +1,134 @@
|
||||||
|
// SPDX-License-Identifier: BSD-3-Clause
|
||||||
|
// Copyright (c) 2020-2021, The Monero Project.
|
||||||
|
// Copyright (c) OpenVR Advanced Settings
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <openvr.h>
|
||||||
|
#include <QtCore/QtCore>
|
||||||
|
// because of incompatibilities with QtOpenGL and GLEW we need to cherry pick includes
|
||||||
|
#include <QVector2D>
|
||||||
|
#include <QMatrix4x4>
|
||||||
|
#include <QVector>
|
||||||
|
#include <QVector2D>
|
||||||
|
#include <QVector3D>
|
||||||
|
#include <QObject>
|
||||||
|
#include <QQmlEngine>
|
||||||
|
#include <QtGui/QOpenGLContext>
|
||||||
|
#include <QtWidgets/QGraphicsScene>
|
||||||
|
#include <QOffscreenSurface>
|
||||||
|
#include <QOpenGLFramebufferObject>
|
||||||
|
#include <QQuickWindow>
|
||||||
|
#include <QQuickItem>
|
||||||
|
#include <QQuickRenderControl>
|
||||||
|
#include <QNetworkAccessManager>
|
||||||
|
#include <QNetworkReply>
|
||||||
|
#include <QNetworkRequest>
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
|
#include "openvr_init.h"
|
||||||
|
#include "vr/utils/paths.h"
|
||||||
|
#include "appcontext.h"
|
||||||
|
|
||||||
|
namespace application_strings
|
||||||
|
{
|
||||||
|
constexpr auto applicationOrganizationName = "Wownero";
|
||||||
|
constexpr auto applicationName = "Wowlet VR";
|
||||||
|
constexpr const char* applicationKey = "steam.overlay.1001337";
|
||||||
|
constexpr const char* applicationDisplayName = "Wowlet VR";
|
||||||
|
|
||||||
|
constexpr const char* applicationVersionString = "1337";
|
||||||
|
|
||||||
|
} // namespace application_strings
|
||||||
|
|
||||||
|
constexpr int k_nonVsyncTickRate = 20;
|
||||||
|
|
||||||
|
// application namespace
|
||||||
|
namespace wowletvr
|
||||||
|
{
|
||||||
|
|
||||||
|
class OverlayController : public QObject
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
public:
|
||||||
|
OverlayController(bool desktopMode, QQmlEngine& qmlEngine);
|
||||||
|
virtual ~OverlayController();
|
||||||
|
|
||||||
|
void Shutdown();
|
||||||
|
|
||||||
|
Q_INVOKABLE void exitApp();
|
||||||
|
|
||||||
|
bool isDashboardVisible()
|
||||||
|
{
|
||||||
|
return m_dashboardVisible;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SetWidget( QQuickItem* quickItem,
|
||||||
|
const std::string& name,
|
||||||
|
const std::string& key = "" );
|
||||||
|
|
||||||
|
bool isDesktopMode()
|
||||||
|
{
|
||||||
|
return m_desktopMode;
|
||||||
|
}
|
||||||
|
|
||||||
|
Q_INVOKABLE QUrl getVRRuntimePathUrl();
|
||||||
|
Q_INVOKABLE bool soundDisabled();
|
||||||
|
|
||||||
|
const vr::VROverlayHandle_t& overlayHandle();
|
||||||
|
const vr::VROverlayHandle_t& overlayThumbnailHandle();
|
||||||
|
|
||||||
|
bool pollNextEvent(vr::VROverlayHandle_t ulOverlayHandle, vr::VREvent_t* pEvent );
|
||||||
|
void mainEventLoop();
|
||||||
|
|
||||||
|
private:
|
||||||
|
vr::VROverlayHandle_t m_ulOverlayHandle = vr::k_ulOverlayHandleInvalid;
|
||||||
|
vr::VROverlayHandle_t m_ulOverlayThumbnailHandle
|
||||||
|
= vr::k_ulOverlayHandleInvalid;
|
||||||
|
|
||||||
|
QQuickRenderControl m_renderControl;
|
||||||
|
QQuickWindow m_window{ &m_renderControl };
|
||||||
|
std::unique_ptr<QOpenGLFramebufferObject> m_pFbo;
|
||||||
|
QOpenGLContext m_openGLContext;
|
||||||
|
QOffscreenSurface m_offscreenSurface;
|
||||||
|
|
||||||
|
std::unique_ptr<QTimer> m_pRenderTimer;
|
||||||
|
bool m_dashboardVisible = false;
|
||||||
|
|
||||||
|
QPoint m_ptLastMouse;
|
||||||
|
Qt::MouseButtons m_lastMouseButtons = nullptr;
|
||||||
|
|
||||||
|
bool m_desktopMode;
|
||||||
|
|
||||||
|
QUrl m_runtimePathUrl;
|
||||||
|
|
||||||
|
uint64_t m_customTickRateCounter = 0;
|
||||||
|
uint64_t m_currentFrame = 0;
|
||||||
|
uint64_t m_lastFrame = 0;
|
||||||
|
|
||||||
|
QNetworkAccessManager* netManager = new QNetworkAccessManager( this );
|
||||||
|
QJsonDocument m_remoteVersionJsonDocument = QJsonDocument();
|
||||||
|
QJsonObject m_remoteVersionJsonObject;
|
||||||
|
|
||||||
|
private:
|
||||||
|
QPoint getMousePositionForEvent( vr::VREvent_Mouse_t mouse );
|
||||||
|
|
||||||
|
bool m_exclusiveState = false;
|
||||||
|
bool m_keyPressOneState = false;
|
||||||
|
bool m_keyPressTwoState = false;
|
||||||
|
|
||||||
|
AppContext *m_ctx;
|
||||||
|
|
||||||
|
public slots:
|
||||||
|
void renderOverlay();
|
||||||
|
void OnRenderRequest();
|
||||||
|
|
||||||
|
void showKeyboard( QString existingText, unsigned long userValue = 0 );
|
||||||
|
void setKeyboardPos();
|
||||||
|
|
||||||
|
signals:
|
||||||
|
void keyBoardInputSignal( QString input, unsigned long userValue = 0 );
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace wowletvr
|
58
src/vr/utils/paths.cpp
Executable file
58
src/vr/utils/paths.cpp
Executable file
|
@ -0,0 +1,58 @@
|
||||||
|
#include "paths.h"
|
||||||
|
#include <QStandardPaths>
|
||||||
|
#include <QCoreApplication>
|
||||||
|
#include <QString>
|
||||||
|
#include <QFileInfo>
|
||||||
|
#include <QDir>
|
||||||
|
|
||||||
|
namespace paths
|
||||||
|
{
|
||||||
|
string binaryDirectory()
|
||||||
|
{
|
||||||
|
const auto path = QCoreApplication::applicationDirPath();
|
||||||
|
if ( path == "" ) {
|
||||||
|
qCritical() << "Could not find binary directory.";
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
return path.toStdString() + "/../"; // @ TODO: removeme
|
||||||
|
}
|
||||||
|
|
||||||
|
string binaryDirectoryFindFile( const string& fileName ) {
|
||||||
|
const auto path = binaryDirectory();
|
||||||
|
if (path.empty()) {
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto filePath = QDir( QString::fromStdString( path ) + '/'
|
||||||
|
+ QString::fromStdString( fileName ) );
|
||||||
|
QFileInfo file( filePath.path() );
|
||||||
|
if (!file.exists())
|
||||||
|
{
|
||||||
|
qCritical() << "Could not find file '" << fileName.c_str()
|
||||||
|
<< "' in binary directory.";
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
return QDir::toNativeSeparators( file.filePath() ).toStdString();
|
||||||
|
}
|
||||||
|
|
||||||
|
string settingsDirectory() {
|
||||||
|
const auto path = QStandardPaths::writableLocation( QStandardPaths::AppDataLocation );
|
||||||
|
if (path == "") {
|
||||||
|
qCritical() << "Could not find settings directory.";
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
return path.toStdString();
|
||||||
|
}
|
||||||
|
|
||||||
|
string verifyIconFilePath( const string& filename ) {
|
||||||
|
const string notifIconPath = paths::binaryDirectoryFindFile( filename );
|
||||||
|
if (notifIconPath.empty()) {
|
||||||
|
qCritical() << "Could not find icon " << filename.c_str() << "\"";
|
||||||
|
}
|
||||||
|
|
||||||
|
return notifIconPath;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace paths
|
16
src/vr/utils/paths.h
Executable file
16
src/vr/utils/paths.h
Executable file
|
@ -0,0 +1,16 @@
|
||||||
|
#pragma once
|
||||||
|
#include <QDebug>
|
||||||
|
#include <string>
|
||||||
|
#include <optional>
|
||||||
|
#include <experimental/optional>
|
||||||
|
|
||||||
|
namespace paths
|
||||||
|
{
|
||||||
|
using std::string;
|
||||||
|
|
||||||
|
string binaryDirectory();
|
||||||
|
string binaryDirectoryFindFile( const string& fileName );
|
||||||
|
string settingsDirectory();
|
||||||
|
string verifyIconFilePath( const string& filename );
|
||||||
|
|
||||||
|
} // namespace paths
|
Loading…
Reference in a new issue