From 9a205f9b02899d6ffefcf505fcf79ab890dfa465 Mon Sep 17 00:00:00 2001 From: Goombert Date: Sun, 6 Sep 2020 14:36:15 -0400 Subject: [PATCH 1/5] add git dock widget to main window --- MainWindow.cpp | 1 + MainWindow.ui | 151 ++++++++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 151 insertions(+), 1 deletion(-) diff --git a/MainWindow.cpp b/MainWindow.cpp index fd57d8749..7ef1484ff 100644 --- a/MainWindow.cpp +++ b/MainWindow.cpp @@ -126,6 +126,7 @@ MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent), _ui(new Ui::MainW setCorner(Qt::BottomRightCorner, Qt::RightDockWidgetArea); _ui->setupUi(this); + this->tabifyDockWidget(_ui->outputDockWidget, _ui->gitDockWidget); QToolBar *outputTB = new QToolBar(this); outputTB->setIconSize(QSize(24, 24)); diff --git a/MainWindow.ui b/MainWindow.ui index b8926488a..8d618ad76 100644 --- a/MainWindow.ui +++ b/MainWindow.ui @@ -100,7 +100,7 @@ 0 0 1200 - 31 + 21 @@ -497,6 +497,155 @@ + + + Git + + + 8 + + + + + 4 + + + 4 + + + 4 + + + 4 + + + 4 + + + + + + + + obj_playerchanged + + + + :/actions/edit.png:/actions/edit.png + + + + + spr_deleted + + + + :/actions/delete.png:/actions/delete.png + + + + + spr_added + + + + :/actions/add.png:/actions/add.png + + + + + + + + 24 + + + + + + + + + true + + + + 1 + + + + + [Working Copy] + + + + :/actions/tag.png:/actions/tag.png + + + + + Automatic Commit + + + + + Automatic Commit + + + + Adds the player + + + + + + First commit + + + + + + + + + + ... + + + + :/actions/add.png:/actions/add.png + + + + + + + ... + + + + :/actions/find.png:/actions/find.png + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + + From 82918931bd16e9aed2d043f289f218920c868aea Mon Sep 17 00:00:00 2001 From: Greg Williamson Date: Sun, 6 Sep 2020 16:07:25 -0400 Subject: [PATCH 2/5] wip merge rubber's ui --- Components/EGMManager.cpp | 214 ++++++++++++++++++++++++++++++++++++++ Components/EGMManager.h | 60 +++++++++++ MainWindow.cpp | 87 ++++++---------- MainWindow.h | 47 ++++----- RadialGM.pro | 5 +- 5 files changed, 327 insertions(+), 86 deletions(-) create mode 100644 Components/EGMManager.cpp create mode 100644 Components/EGMManager.h diff --git a/Components/EGMManager.cpp b/Components/EGMManager.cpp new file mode 100644 index 000000000..d586393e7 --- /dev/null +++ b/Components/EGMManager.cpp @@ -0,0 +1,214 @@ +#include "EGMManager.h" +#include "gmk.h" +#include "gmx.h" +#include "yyp.h" + +#include +#include +#include +#include +#include + +EGMManager::EGMManager() : _egm(nullptr), _repo(nullptr) { + qDebug() << "Intializing git library"; + git_libgit2_init(); +} + +EGMManager::~EGMManager() { + git_tree_free(_git_tree); + git_signature_free(_git_sig); + git_repository_free(_repo); + git_libgit2_shutdown(); +} + +buffers::Project* EGMManager::NewProject() { + _project = std::make_unique(); + QTemporaryDir dir; + dir.setAutoRemove(false); + _rootPath = dir.path(); + InitRepo(); + return _project.get(); +} + +buffers::Project* EGMManager::LoadProject(const QString& fPath) { + QFileInfo fileInfo(fPath); + const QString suffix = fileInfo.suffix(); + + if (suffix == "egm") { + _project = _egm.LoadEGM(fPath.toStdString()); + } else if (suffix == "gm81" || suffix == "gmk" || suffix == "gm6" || suffix == "gmd") { + _project = gmk::LoadGMK(fPath.toStdString(), GetEventData()); + } else if (suffix == "gmx") { + _project = gmx::LoadGMX(fPath.toStdString(), GetEventData()); + } else if (suffix == "yyp") { + _project = yyp::LoadYYP(fPath.toStdString(), GetEventData()); + } + + return _project.get(); +} + +buffers::Game* EGMManager::GetGame() { return _project->mutable_game(); } + +bool EGMManager::LoadEventData(const QString& fPath) { + QFile f(fPath); + if (f.exists()) { + _event_data = std::make_unique(ParseEventFile(fPath.toStdString())); + } else { + qDebug() << "Error: Failed to load events file. Loading internal events.ey."; + QFile internal_events(":/events.ey"); + internal_events.open(QIODevice::ReadOnly | QFile::Text); + std::stringstream ss; + ss << internal_events.readAll().toStdString(); + _event_data = std::make_unique(ParseEventFile(ss)); + } + + _egm = egm::EGM(_event_data.get()); + + return _event_data->events().size() > 0; +} + +EventData* EGMManager::GetEventData() { return _event_data.get(); } + +git_commit* EGMManager::GitLookUp(const git_oid* id) { + git_commit* commit = nullptr; + int error = git_commit_lookup(&commit, _repo, id); + if (error != 0) GitError(); + return commit; +} + +bool EGMManager::InitRepo() { + qDebug() << "Intializing git repository at: " << _rootPath; + git_repository_init_options opts = GIT_REPOSITORY_INIT_OPTIONS_INIT; + opts.description = "ENIGMA Game"; + int error = git_repository_init_ext(&_repo, _rootPath.toStdString().c_str(), &opts); + if (error != 0) { + GitError(); + return false; + } + + error = git_signature_default(&_git_sig, _repo); + if (error != 0) { + GitError(); + return false; + } + + error = git_repository_index(&_git_index, _repo); + if (error != 0) { + GitError(); + return false; + } + error = git_index_write_tree(&_git_tree_id, _git_index); + if (error != 0) { + GitError(); + return false; + } + error = git_tree_lookup(&_git_tree, _repo, &_git_tree_id); + if (error != 0) { + GitError(); + return false; + } + error = git_commit_create_v(&_git_commit_id, _repo, "HEAD", _git_sig, _git_sig, NULL, "Initial commit", _git_tree, 0); + if (error != 0) { + GitError(); + return false; + } + + return CreateBranch("RadialGM") && Checkout("RadialGM"); +} + +bool EGMManager::CreateBranch(const QString& branchName) { + qDebug() << "Creating git branch: " << branchName; + git_commit* c = GitLookUp(&_git_commit_id); + git_reference* ref = nullptr; + int error = git_branch_create(&ref, _repo, branchName.toStdString().c_str(), c, 0); + git_reference_free(ref); + if (error != 0) { + GitError(); + return false; + } + return true; +} + +bool EGMManager::Checkout(const QString& ref) { + qDebug() << "Checking out git reference: " << ref; + int error = git_repository_set_head(_repo, ref.toStdString().c_str()); + if (error != 0) { + GitError(); + return false; + } + return true; +} + +/*bool EGMManager::CheckoutFile(const QString& ref, const QString& file) { +}*/ + +bool EGMManager::AddFile(const QString& file) { + qDebug() << "Adding file to EGM: " << file; + int error = git_index_add_bypath(_git_index, file.toStdString().c_str()); + if (error != 0) { + GitError(); + return false; + } + return true; +} + +bool EGMManager::MoveFile(const QString& file, const QString& newPath) { return false; } + +bool EGMManager::RemoveFile(const QString& file) { + qDebug() << "Removing file from EGM: " << file; + int error = git_index_remove_bypath(_git_index, file.toStdString().c_str()); + if (error != 0) { + GitError(); + return false; + } + return true; +} + +bool EGMManager::RemoveDir(const QString& dir) { + qDebug() << "Removing directory from EGM: " << dir; + int error = git_index_remove_directory(_git_index, dir.toStdString().c_str(), 0); + if (error != 0) { + GitError(); + return false; + } + return true; +} + +bool EGMManager::CommitChanges(const QString& message) { + qDebug() << "Commiting changes"; + int error = git_commit_create_v(&_git_commit_id, _repo, "HEAD", _git_sig, _git_sig, NULL, + message.toStdString().c_str(), _git_tree, 0); + if (error != 0) { + GitError(); + return false; + } + return true; +} + +/*bool EGMManager::AddRemote(const QString& url) { + +} + +bool EGMManager::ChangeRemote(unsigned index, const QString& url) { + +} + +bool EGMManager::RemoveRemote(unsigned index) { + +} + +const QStringList& EGMManager::GetRemotes() const { + +} + +bool EGMManager::PushChanges() { + +}*/ + +bool EGMManager::Save(const QString& fPath) {} + +void EGMManager::GitError() { + const git_error* e = git_error_last(); + QErrorMessage errorDialog; + errorDialog.showMessage(QString("Git Error: ") + e->klass + "\n" + e->message); +} diff --git a/Components/EGMManager.h b/Components/EGMManager.h new file mode 100644 index 000000000..ff84094da --- /dev/null +++ b/Components/EGMManager.h @@ -0,0 +1,60 @@ +#ifndef EGMMANAGER_H +#define EGMMANAGER_H + +#include "event_reader/event_parser.h" +#include "egm.h" + +#include +#include +#include + +#include + +class EGMManager : public QObject { + Q_OBJECT +public: + EGMManager(); + ~EGMManager(); + buffers::Project* NewProject(); + buffers::Project* LoadProject(const QString& fPath); + buffers::Game *GetGame(); + bool LoadEventData(const QString& fPath); + EventData* GetEventData(); + bool InitRepo(); + git_commit* GitLookUp(const git_oid* id); + bool CreateBranch(const QString& branchName); + bool Checkout(const QString& ref); + //bool CheckoutFile(const QString& ref, const QString& file); + bool AddFile(const QString& file); + bool MoveFile(const QString& file, const QString& newPath); + bool RemoveFile(const QString& file); + bool RemoveDir(const QString& dir); + bool CommitChanges(const QString& message); + /*bool AddRemote(const QString& url); + bool ChangeRemote(unsigned index, const QString& url); + bool RemoveRemote(unsigned index); + const QStringList& GetRemotes() const; + bool PushChanges();*/ + +signals: + QStringList FilesEditedExternally(); + QStringList ConflictedFilesDetected(); + +public slots: + void GitError(); + bool Save(const QString& fPath); + +protected: + std::unique_ptr _project; + egm::EGM _egm; + QStringList _remoteURLs; + std::unique_ptr _event_data; + QString _rootPath; + git_repository* _repo; + git_signature* _git_sig; + git_index* _git_index; + git_oid _git_tree_id, _git_commit_id; + git_tree* _git_tree; +}; + +#endif // EGMMANAGER_H diff --git a/MainWindow.cpp b/MainWindow.cpp index 7ef1484ff..e44f0c8b8 100644 --- a/MainWindow.cpp +++ b/MainWindow.cpp @@ -25,26 +25,22 @@ #include "Plugins/ServerPlugin.h" #endif -#include "gmk.h" -#include "gmx.h" -#include "yyp.h" - #include +#include #include #include -#include -#include #undef GetMessage -QList MainWindow::EnigmaSearchPaths = {QDir::currentPath(), "./enigma-dev", "../enigma-dev", "../RadialGM/Submodules/enigma-dev"}; +QList MainWindow::EnigmaSearchPaths = {QDir::currentPath(), "./enigma-dev", "../enigma-dev", + "../RadialGM/Submodules/enigma-dev"}; QFileInfo MainWindow::EnigmaRoot = MainWindow::getEnigmaRoot(); QList MainWindow::systemCache; MainWindow *MainWindow::_instance = nullptr; +EGMManager MainWindow::egmManager; QScopedPointer MainWindow::resourceMap; QScopedPointer MainWindow::treeModel; -std::unique_ptr MainWindow::_event_data; static QTextEdit *diagnosticTextEdit = nullptr; static QAction *toggleDiagnosticsAction = nullptr; @@ -94,27 +90,15 @@ QFileInfo MainWindow::getEnigmaRoot() { auto entryList = dir.entryInfoList(QStringList({"ENIGMAsystem"}), filters, QDir::SortFlag::NoSort); if (!entryList.empty()) { EnigmaRoot = entryList.first(); - break; + break; } } return EnigmaRoot; } -MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent), _ui(new Ui::MainWindow), egm(nullptr) { - - if (!EnigmaRoot.filePath().isEmpty()) { - _event_data = std::make_unique(ParseEventFile((EnigmaRoot.absolutePath() + "/events.ey").toStdString())); - } else { - qDebug() << "Error: Failed to locate ENIGMA sources. Loading internal events.ey.\n" << "Search Paths:\n" << MainWindow::EnigmaSearchPaths; - QFile internal_events(":/events.ey"); - internal_events.open(QIODevice::ReadOnly | QFile::Text); - std::stringstream ss; - ss << internal_events.readAll().toStdString(); - _event_data = std::make_unique(ParseEventFile(ss)); - } - - egm = egm::EGM(_event_data.get()); +MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent), _ui(new Ui::MainWindow) { + egmManager.LoadEventData(EnigmaRoot.absolutePath() + "/events.ey"); ArtManager::Init(); @@ -189,7 +173,10 @@ MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent), _ui(new Ui::MainW openNewProject(); } -MainWindow::~MainWindow() { diagnosticTextEdit = nullptr; delete _ui; } +MainWindow::~MainWindow() { + diagnosticTextEdit = nullptr; + delete _ui; +} void MainWindow::setCurrentConfig(const buffers::resources::Settings &settings) { emit _instance->CurrentConfigChanged(settings); @@ -294,9 +281,9 @@ void MainWindow::updateWindowMenu() { numberString = numberString.insert(numberString.length() - 1, '&'); QString text = tr("%1 %2").arg(numberString).arg(windowTitle); - QAction *action = _ui->menuWindow->addAction( - mdiSubWindow->windowIcon(), text, mdiSubWindow, - [this, mdiSubWindow]() { _ui->mdiArea->setActiveSubWindow(mdiSubWindow); }); + QAction *action = + _ui->menuWindow->addAction(mdiSubWindow->windowIcon(), text, mdiSubWindow, + [this, mdiSubWindow]() { _ui->mdiArea->setActiveSubWindow(mdiSubWindow); }); windowActions.append(action); action->setCheckable(true); action->setChecked(mdiSubWindow == _ui->mdiArea->activeSubWindow()); @@ -304,19 +291,7 @@ void MainWindow::updateWindowMenu() { } void MainWindow::openFile(QString fName) { - QFileInfo fileInfo(fName); - const QString suffix = fileInfo.suffix(); - - std::unique_ptr loadedProject = nullptr; - if (suffix == "egm") { - loadedProject = egm.LoadEGM(fName.toStdString()); - } else if (suffix == "gm81" || suffix == "gmk" || suffix == "gm6" || suffix == "gmd") { - loadedProject = gmk::LoadGMK(fName.toStdString(), _event_data.get()); - } else if (suffix == "gmx") { - loadedProject = gmx::LoadGMX(fName.toStdString(), _event_data.get()); - } else if (suffix == "yyp") { - loadedProject = yyp::LoadYYP(fName.toStdString(), _event_data.get()); - } + buffers::Project* loadedProject = egmManager.LoadProject(fName); if (!loadedProject) { QMessageBox::warning(this, tr("Failed To Open Project"), tr("There was a problem loading the project: ") + fName, @@ -324,14 +299,14 @@ void MainWindow::openFile(QString fName) { return; } - MainWindow::setWindowTitle(fileInfo.fileName() + " - ENIGMA"); + MainWindow::setWindowTitle(fName + " - ENIGMA"); _recentFiles->prependFile(fName); - openProject(std::move(loadedProject)); + openProject(loadedProject); } void MainWindow::openNewProject() { MainWindow::setWindowTitle(tr(" - ENIGMA")); - auto newProject = std::unique_ptr(new buffers::Project()); + auto newProject = egmManager.NewProject(); auto *root = newProject->mutable_game()->mutable_root(); QList defaultGroups = {tr("Sprites"), tr("Sounds"), tr("Backgrounds"), tr("Paths"), tr("Scripts"), tr("Shaders"), tr("Fonts"), tr("Timelines"), @@ -341,17 +316,15 @@ void MainWindow::openNewProject() { groupNode->set_folder(true); groupNode->set_name(groupName.toStdString()); } - openProject(std::move(newProject)); + openProject(newProject); } -void MainWindow::openProject(std::unique_ptr openedProject) { +void MainWindow::openProject(buffers::Project* openedProject) { this->_ui->mdiArea->closeAllSubWindows(); ArtManager::clearCache(); - _project = std::move(openedProject); - - resourceMap.reset(new ResourceModelMap(_project->mutable_game()->mutable_root(), nullptr)); - treeModel.reset(new TreeModel(_project->mutable_game()->mutable_root(), resourceMap.get(), nullptr)); + resourceMap.reset(new ResourceModelMap(openedProject->mutable_game()->mutable_root(), nullptr)); + treeModel.reset(new TreeModel(openedProject->mutable_game()->mutable_root(), resourceMap.get(), nullptr)); _ui->treeView->setModel(treeModel.get()); treeModel->connect(treeModel.get(), &TreeModel::ResourceRenamed, resourceMap.get(), @@ -405,7 +378,9 @@ void MainWindow::on_actionCloseOthers_triggered() { } } -void MainWindow::on_actionToggleTabbedView_triggered() { this->setTabbedMode(_ui->actionToggleTabbedView->isChecked()); } +void MainWindow::on_actionToggleTabbedView_triggered() { + this->setTabbedMode(_ui->actionToggleTabbedView->isChecked()); +} void MainWindow::on_actionNext_triggered() { _ui->mdiArea->activateNextSubWindow(); } @@ -435,8 +410,7 @@ void MainWindow::on_actionExploreENIGMA_triggered() { QDesktopServices::openUrl( void MainWindow::on_actionAbout_triggered() { QMessageBox aboutBox(QMessageBox::Information, tr("About"), - tr("ENIGMA is a free, open-source, and cross-platform game engine."), - QMessageBox::Ok, this); + tr("ENIGMA is a free, open-source, and cross-platform game engine."), QMessageBox::Ok, this); QAbstractButton *aboutQtButton = aboutBox.addButton(tr("About Qt"), QMessageBox::HelpRole); aboutBox.exec(); @@ -577,12 +551,9 @@ void MainWindow::on_actionDelete_triggered() { selectedNames += (node == *selectedNodes.begin() ? "" : ", ") + QString::fromStdString(node->name()); } - QMessageBox mb( - QMessageBox::Icon::Question, - tr("Delete Resources"), - tr("Do you want to delete the selected resources from the project?"), - QMessageBox::Yes | QMessageBox::No, this - ); + QMessageBox mb(QMessageBox::Icon::Question, tr("Delete Resources"), + tr("Do you want to delete the selected resources from the project?"), + QMessageBox::Yes | QMessageBox::No, this); mb.setDetailedText(selectedNames); int ret = mb.exec(); if (ret != QMessageBox::Yes) return; diff --git a/MainWindow.h b/MainWindow.h index 1c7353206..a372a4db8 100644 --- a/MainWindow.h +++ b/MainWindow.h @@ -6,19 +6,18 @@ #include "Models/TreeModel.h" class MainWindow; +#include "Components/EGMManager.h" #include "Components/RecentFiles.h" #include "project.pb.h" #include "server.pb.h" -#include "event_reader/event_parser.h" -#include "egm.h" +#include #include #include #include #include #include -#include namespace Ui { class MainWindow; @@ -27,6 +26,21 @@ class MainWindow; class MainWindow : public QMainWindow { Q_OBJECT + private: + void closeEvent(QCloseEvent *event) override; + + static MainWindow *_instance; + static EGMManager egmManager; + QHash _subWindows; + Ui::MainWindow *_ui; + QPointer _recentFiles; + + void openSubWindow(buffers::TreeNode *item); + void readSettings(); + void writeSettings(); + void setTabbedMode(bool enabled); + static QFileInfo getEnigmaRoot(); + public: static QScopedPointer resourceMap; static QScopedPointer treeModel; @@ -34,12 +48,12 @@ class MainWindow : public QMainWindow { explicit MainWindow(QWidget *parent); ~MainWindow(); - void openProject(std::unique_ptr openedProject); - buffers::Game *Game() const { return this->_project->mutable_game(); } + void openProject(buffers::Project* openedProject); + buffers::Game *Game() const { return egmManager.GetGame(); } + static EventData *GetEventData() { return egmManager.GetEventData(); } static QList EnigmaSearchPaths; static QFileInfo EnigmaRoot; - static EventData* GetEventData() { return _event_data.get(); } signals: void CurrentConfigChanged(const buffers::resources::Settings &settings); @@ -101,27 +115,6 @@ class MainWindow : public QMainWindow { void on_treeView_doubleClicked(const QModelIndex &index); void on_treeView_customContextMenuRequested(const QPoint &pos); - - private: - void closeEvent(QCloseEvent *event) override; - - static MainWindow *_instance; - - QHash _subWindows; - - Ui::MainWindow *_ui; - - std::unique_ptr _project; - QPointer _recentFiles; - - static std::unique_ptr _event_data; - egm::EGM egm; - - void openSubWindow(buffers::TreeNode *item); - void readSettings(); - void writeSettings(); - void setTabbedMode(bool enabled); - static QFileInfo getEnigmaRoot(); }; #endif // MAINWINDOW_H diff --git a/RadialGM.pro b/RadialGM.pro index c20f30c0c..4e08e70c2 100644 --- a/RadialGM.pro +++ b/RadialGM.pro @@ -65,9 +65,11 @@ LIBS += -L$$PWD/Submodules/enigma-dev/CommandLine/libEGM/ \ -L$$PWD/Submodules/enigma-dev/ \ -lProtocols \ -lpugixml \ - -lgrpc++ + -lgrpc++ \ + -lgit2 SOURCES += \ + Components/EGMManager.cpp \ Dialogs/EventArgumentsDialog.cpp \ Dialogs/TimelineChangeMoment.cpp \ Editors/IncludeEditor.cpp \ @@ -117,6 +119,7 @@ SOURCES += \ Models/TreeSortFilterProxyModel.cpp HEADERS += \ + Components/EGMManager.h \ Dialogs/EventArgumentsDialog.h \ Dialogs/TimelineChangeMoment.h \ Editors/IncludeEditor.h \ From c96b46c2b37a7d0191db8a6a0077b5293fe350ca Mon Sep 17 00:00:00 2001 From: Greg Williamson Date: Tue, 10 Nov 2020 10:04:43 -0500 Subject: [PATCH 3/5] add line for josh --- CMakeLists.txt | 14 +++ Components/EGMManager.cpp | 4 +- Components/GitTreeItem.cpp | 18 ++++ Components/GitTreeItem.h | 18 ++++ Components/GitTreeStyledDelegate.cpp | 20 ++++ Components/GitTreeStyledDelegate.h | 15 +++ MainWindow.cpp | 8 ++ MainWindow.ui | 152 +++++++++++---------------- Models/GitHistoryModel.cpp | 60 +++++++++++ Models/GitHistoryModel.h | 22 ++++ RadialGM.pro | 6 ++ 11 files changed, 244 insertions(+), 93 deletions(-) create mode 100644 Components/GitTreeItem.cpp create mode 100644 Components/GitTreeItem.h create mode 100644 Components/GitTreeStyledDelegate.cpp create mode 100644 Components/GitTreeStyledDelegate.h create mode 100644 Models/GitHistoryModel.cpp create mode 100644 Models/GitHistoryModel.h diff --git a/CMakeLists.txt b/CMakeLists.txt index f6791e816..a83a0d07a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -59,6 +59,9 @@ set(RGM_SOURCES Components/Utility.cpp Components/QMenuView.cpp Components/RecentFiles.cpp + Components/GitTreeItem.cpp + Components/GitTreeStyledDelegate.cpp + Components/EGMManager.cpp Models/TreeSortFilterProxyModel.cpp Models/MessageModel.cpp Models/RepeatedImageModel.cpp @@ -72,6 +75,7 @@ set(RGM_SOURCES Models/EventsListModel.cpp Models/EventTypesListModel.cpp Models/EventTypesListSortFilterProxyModel.cpp + Models/GitHistoryModel.cpp Editors/ObjectEditor.cpp Editors/PathEditor.cpp Editors/CodeEditor.cpp @@ -112,6 +116,9 @@ set(RGM_HEADERS Components/ArtManager.h Components/QMenuView_p.h Components/Utility.h + Components/GitTreeItem.h + Components/GitTreeStyledDelegate.h + Components/EGMManager.h Models/TreeModel.h Models/RepeatedStringModel.h Models/ResourceModelMap.h @@ -126,6 +133,7 @@ set(RGM_HEADERS Models/EventsListModel.h Models/EventTypesListModel.h Models/EventTypesListSortFilterProxyModel.h + Models/GitHistoryModel.cpp Editors/FontEditor.h Editors/PathEditor.h Editors/SpriteEditor.h @@ -276,6 +284,12 @@ find_package(Freetype REQUIRED) include_directories(${FREETYPE_INCLUDE_DIRS}) target_link_libraries(${EXE} PRIVATE ${FREETYPE_LIBRARIES}) +# Find libgit2 +find_path(GIT2_INCLUDE_PATH NAMES git2.h) +include_directories(${GIT2_INCLUDE_PATH}) +find_library(GIT2_LIBRARIES git2) +target_link_libraries(${EXE} PRIVATE ${GIT2_LIBRARIES}) + # Find JPEG find_library(LIB_JPEG NAMES jpeg) target_link_libraries(${EXE} PRIVATE ${LIB_JPEG}) diff --git a/Components/EGMManager.cpp b/Components/EGMManager.cpp index d586393e7..d516ba863 100644 --- a/Components/EGMManager.cpp +++ b/Components/EGMManager.cpp @@ -205,7 +205,9 @@ bool EGMManager::PushChanges() { }*/ -bool EGMManager::Save(const QString& fPath) {} +bool EGMManager::Save(const QString& fPath) { + return false; +} void EGMManager::GitError() { const git_error* e = git_error_last(); diff --git a/Components/GitTreeItem.cpp b/Components/GitTreeItem.cpp new file mode 100644 index 000000000..e98e5d3d4 --- /dev/null +++ b/Components/GitTreeItem.cpp @@ -0,0 +1,18 @@ +#include "GitTreeItem.h" +#include + +GitTreeItem::GitTreeItem() {} + +constexpr int scale = 8; + +void GitTreeItem::paint(QPainter *painter, const QRect &rect, const QPalette &palette, EditMode mode) const { + painter->save(); + painter->setBrush(QBrush(Qt::black)); + painter->drawEllipse(rect.left() + (rect.width() - scale)/2, rect.top() + (rect.height() - scale)/2, scale, scale); + painter->drawLine(rect.left() + (rect.width())/2, rect.top(), rect.left() + (rect.width())/2, rect.bottom()); + painter->restore(); +} + +QSize GitTreeItem::sizeHint() const { + return QSize(scale, scale); +} diff --git a/Components/GitTreeItem.h b/Components/GitTreeItem.h new file mode 100644 index 000000000..e580bf4d9 --- /dev/null +++ b/Components/GitTreeItem.h @@ -0,0 +1,18 @@ +#ifndef GITTREEITEM_H +#define GITTREEITEM_H + +#include +#include + +class GitTreeItem +{ +public: + enum class EditMode { ReadOnly }; + GitTreeItem(); + void paint(QPainter *painter, const QRect &rect, const QPalette &palette, EditMode mode) const; + QSize sizeHint() const; +}; + +Q_DECLARE_METATYPE(GitTreeItem) + +#endif // GITTREEITEM_H diff --git a/Components/GitTreeStyledDelegate.cpp b/Components/GitTreeStyledDelegate.cpp new file mode 100644 index 000000000..bcf941fac --- /dev/null +++ b/Components/GitTreeStyledDelegate.cpp @@ -0,0 +1,20 @@ +#include "GitTreeStyledDelegate.h" +#include "GitTreeItem.h" + +#include + +GitTreeStyledDelegate::GitTreeStyledDelegate(QObject* parent) : QStyledItemDelegate(parent) {} + +void GitTreeStyledDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const { + if (index.data().canConvert()) { + GitTreeItem i = qvariant_cast(index.data()); + i.paint(painter, option.rect, option.palette, GitTreeItem::EditMode::ReadOnly); + } else QStyledItemDelegate::paint(painter, option, index); +} + +QSize GitTreeStyledDelegate::sizeHint(const QStyleOptionViewItem &option, const QModelIndex &index) const { + if (index.data().canConvert()) { + GitTreeItem i = qvariant_cast(index.data()); + return i.sizeHint(); + } else return QStyledItemDelegate::sizeHint(option, index); +} diff --git a/Components/GitTreeStyledDelegate.h b/Components/GitTreeStyledDelegate.h new file mode 100644 index 000000000..a5209d1ff --- /dev/null +++ b/Components/GitTreeStyledDelegate.h @@ -0,0 +1,15 @@ +#ifndef GITTREESTYLEDDELEGATE_H +#define GITTREESTYLEDDELEGATE_H + +#include + +class GitTreeStyledDelegate : public QStyledItemDelegate +{ + Q_OBJECT +public: + GitTreeStyledDelegate(QObject* parent = nullptr); + void paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const override; + QSize sizeHint(const QStyleOptionViewItem &option, const QModelIndex &index) const override; +}; + +#endif // GITTREESTYLEDDELEGATE_H diff --git a/MainWindow.cpp b/MainWindow.cpp index e44f0c8b8..ccc37f9ee 100644 --- a/MainWindow.cpp +++ b/MainWindow.cpp @@ -18,6 +18,9 @@ #include "Components/ArtManager.h" #include "Components/Logger.h" +#include "Components/GitTreeStyledDelegate.h" + +#include "Models/GitHistoryModel.h" #include "Plugins/RGMPlugin.h" @@ -170,6 +173,11 @@ MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent), _ui(new Ui::MainW connect(_ui->actionCreateExecutable, &QAction::triggered, pluginServer, &RGMPlugin::CreateExecutable); #endif + GitHistoryModel* ghm = new GitHistoryModel(this); + _ui->gitLogView->setModel(ghm); + _ui->gitLogView->setItemDelegate(new GitTreeStyledDelegate); + _ui->gitLogView->horizontalHeader()->setSectionResizeMode(QHeaderView::Stretch); + openNewProject(); } diff --git a/MainWindow.ui b/MainWindow.ui index 8d618ad76..185f656f9 100644 --- a/MainWindow.ui +++ b/MainWindow.ui @@ -100,7 +100,7 @@ 0 0 1200 - 21 + 18 @@ -505,103 +505,71 @@ 8 - - - 4 - - - 4 - - - 4 - - - 4 - - - 4 - + - - - - - - obj_playerchanged - - - - :/actions/edit.png:/actions/edit.png - - + + + Qt::Horizontal + + + - - spr_deleted - - - - :/actions/delete.png:/actions/delete.png - + + + + obj_playerchanged + + + + :/actions/edit.png:/actions/edit.png + + + + + spr_deleted + + + + :/actions/delete.png:/actions/delete.png + + + + + spr_added + + + + :/actions/add.png:/actions/add.png + + + - - spr_added - - - - :/actions/add.png:/actions/add.png - + + + 24 + + - - - - - - 24 - - - - - - - - - true - - - - 1 - - - - - [Working Copy] - - - - :/actions/tag.png:/actions/tag.png - - - - - Automatic Commit - - - - - Automatic Commit - - - - Adds the player - - - - - - First commit + + + + + + 1 + 0 + - + + true + + + false + + + false + + diff --git a/Models/GitHistoryModel.cpp b/Models/GitHistoryModel.cpp new file mode 100644 index 000000000..94e569470 --- /dev/null +++ b/Models/GitHistoryModel.cpp @@ -0,0 +1,60 @@ +#include "GitHistoryModel.h" +#include "Components/GitTreeItem.h" + +GitHistoryModel::GitHistoryModel(QObject* parent) : QAbstractTableModel(parent) { + int error; + git_repository *repo = NULL; + + error = git_repository_open_ext(&repo, "/home/greg/enigma-dev/", 0, NULL); + + git_revwalk *walker; + error = git_revwalk_new(&walker, repo); + error = git_revwalk_push_range(walker, "HEAD~20..HEAD"); + git_revwalk_sorting(walker, GIT_SORT_NONE); + + git_oid oid; + while (!git_revwalk_next(&oid, walker)) { + git_commit* commit = nullptr; + git_commit_lookup(&commit, repo, &oid); + _commits.append(commit); + } +} + +int GitHistoryModel::rowCount(const QModelIndex &parent) const { + if (parent.isValid()) return 0; + return _commits.count(); +} + +int GitHistoryModel::columnCount(const QModelIndex &parent) const { + if (parent.isValid()) return 0; + return 5; +} + +QVariant GitHistoryModel::headerData(int section, Qt::Orientation orientation, int role) const { + if (role != Qt::DisplayRole || orientation != Qt::Orientation::Horizontal) return QVariant(); + + switch(section) { + case 0: return tr("Tree"); + case 1: return tr("ID"); + case 2: return tr("Description"); + case 3: return tr("Author"); + case 4: return tr("Email"); + } + + return QVariant(); +} + +QVariant GitHistoryModel::data(const QModelIndex &index, int role) const { + if (role != Qt::DisplayRole) return QVariant(); + git_commit* commit = _commits[index.row()]; + + switch(index.column()) { + case 0: return QVariant::fromValue(GitTreeItem()); + case 1: return git_oid_tostr_s(git_commit_id(commit)); + case 2: return git_commit_summary(commit); + case 3: return git_commit_author(commit)->name; + case 4: return git_commit_author(commit)->email; + } + + return QVariant(); +} diff --git a/Models/GitHistoryModel.h b/Models/GitHistoryModel.h new file mode 100644 index 000000000..36b6f2a25 --- /dev/null +++ b/Models/GitHistoryModel.h @@ -0,0 +1,22 @@ +#ifndef GITHISTORYMODEL_H +#define GITHISTORYMODEL_H + +#include +#include + +#include + +class GitHistoryModel : public QAbstractTableModel +{ +public: + GitHistoryModel(QObject *parent); + virtual int rowCount(const QModelIndex &parent = QModelIndex()) const override; + virtual int columnCount(const QModelIndex &parent = QModelIndex()) const override; + virtual QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override; + virtual QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const override; + +protected: + QVector _commits; +}; + +#endif // GITHISTORYMODEL_H diff --git a/RadialGM.pro b/RadialGM.pro index 4e08e70c2..95cd5d926 100644 --- a/RadialGM.pro +++ b/RadialGM.pro @@ -70,6 +70,8 @@ LIBS += -L$$PWD/Submodules/enigma-dev/CommandLine/libEGM/ \ SOURCES += \ Components/EGMManager.cpp \ + Components/GitTreeItem.cpp \ + Components/GitTreeStyledDelegate.cpp \ Dialogs/EventArgumentsDialog.cpp \ Dialogs/TimelineChangeMoment.cpp \ Editors/IncludeEditor.cpp \ @@ -78,6 +80,7 @@ SOURCES += \ Models/EventTypesListModel.cpp \ Models/EventTypesListSortFilterProxyModel.cpp \ Models/EventsListModel.cpp \ + Models/GitHistoryModel.cpp \ Models/MessageModel.cpp \ Models/RepeatedImageModel.cpp \ Models/RepeatedMessageModel.cpp \ @@ -120,6 +123,8 @@ SOURCES += \ HEADERS += \ Components/EGMManager.h \ + Components/GitTreeItem.h \ + Components/GitTreeStyledDelegate.h \ Dialogs/EventArgumentsDialog.h \ Dialogs/TimelineChangeMoment.h \ Editors/IncludeEditor.h \ @@ -139,6 +144,7 @@ HEADERS += \ Models/EventTypesListModel.h \ Models/EventTypesListSortFilterProxyModel.h \ Models/EventsListModel.h \ + Models/GitHistoryModel.h \ Models/MessageModel.h \ Models/RepeatedImageModel.h \ Models/RepeatedMessageModel.h \ From 6928e52248f12fa4578e2798725c75fb329c7a9b Mon Sep 17 00:00:00 2001 From: Greg Williamson Date: Tue, 10 Nov 2020 13:05:23 -0500 Subject: [PATCH 4/5] update sub --- Submodules/enigma-dev | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Submodules/enigma-dev b/Submodules/enigma-dev index f82929201..560ad579a 160000 --- a/Submodules/enigma-dev +++ b/Submodules/enigma-dev @@ -1 +1 @@ -Subproject commit f829292014cc870cf05a7484b26496612742279d +Subproject commit 560ad579a8dcb9ab23f5a521274d518fef574cd6 From c5d80a1ea8a69e7dd304ce5eb90dbab75d96051d Mon Sep 17 00:00:00 2001 From: Greg Williamson Date: Mon, 16 Nov 2020 09:44:08 -0500 Subject: [PATCH 5/5] wip --- Components/EGMManager.cpp | 12 ++++++ Components/EGMManager.h | 5 +++ Editors/BaseEditor.cpp | 4 ++ MainWindow.cpp | 6 +++ MainWindow.h | 1 + MainWindow.ui | 30 +------------- Models/ResourceChangesModel.cpp | 70 +++++++++++++++++++++++++++++++++ Models/ResourceChangesModel.h | 30 ++++++++++++++ Models/ResourceModelMap.cpp | 7 ++++ RadialGM.pro | 2 + Submodules/enigma-dev | 2 +- 11 files changed, 139 insertions(+), 30 deletions(-) create mode 100644 Models/ResourceChangesModel.cpp create mode 100644 Models/ResourceChangesModel.h diff --git a/Components/EGMManager.cpp b/Components/EGMManager.cpp index d516ba863..1521fe3e1 100644 --- a/Components/EGMManager.cpp +++ b/Components/EGMManager.cpp @@ -22,6 +22,8 @@ EGMManager::~EGMManager() { } buffers::Project* EGMManager::NewProject() { + _resChangeModel.ClearChanges(); + _project = std::make_unique(); QTemporaryDir dir; dir.setAutoRemove(false); @@ -31,6 +33,8 @@ buffers::Project* EGMManager::NewProject() { } buffers::Project* EGMManager::LoadProject(const QString& fPath) { + _resChangeModel.ClearChanges(); + QFileInfo fileInfo(fPath); const QString suffix = fileInfo.suffix(); @@ -49,6 +53,14 @@ buffers::Project* EGMManager::LoadProject(const QString& fPath) { buffers::Game* EGMManager::GetGame() { return _project->mutable_game(); } +ResourceChangesModel& EGMManager::GetResourceChangesModel() { + return _resChangeModel; +} + +void EGMManager::ResourceChanged(const QString &res, ResChange change) { + _resChangeModel.ResourceChanged(res, change); +} + bool EGMManager::LoadEventData(const QString& fPath) { QFile f(fPath); if (f.exists()) { diff --git a/Components/EGMManager.h b/Components/EGMManager.h index ff84094da..310d71f3c 100644 --- a/Components/EGMManager.h +++ b/Components/EGMManager.h @@ -1,6 +1,8 @@ #ifndef EGMMANAGER_H #define EGMMANAGER_H +#include "Models/ResourceChangesModel.h" + #include "event_reader/event_parser.h" #include "egm.h" @@ -18,6 +20,8 @@ class EGMManager : public QObject { buffers::Project* NewProject(); buffers::Project* LoadProject(const QString& fPath); buffers::Game *GetGame(); + ResourceChangesModel& GetResourceChangesModel(); + void ResourceChanged(const QString &res, ResChange change); bool LoadEventData(const QString& fPath); EventData* GetEventData(); bool InitRepo(); @@ -47,6 +51,7 @@ public slots: protected: std::unique_ptr _project; egm::EGM _egm; + ResourceChangesModel _resChangeModel; QStringList _remoteURLs; std::unique_ptr _event_data; QString _rootPath; diff --git a/Editors/BaseEditor.cpp b/Editors/BaseEditor.cpp index 28d9180a6..a6f62b616 100644 --- a/Editors/BaseEditor.cpp +++ b/Editors/BaseEditor.cpp @@ -1,5 +1,6 @@ #include "BaseEditor.h" #include "Models/MessageModel.h" +#include "MainWindow.h" #include #include @@ -27,6 +28,8 @@ void BaseEditor::closeEvent(QCloseEvent* event) { return; } else if (reply == QMessageBox::No) { _nodeMapper->clearMapping(); + buffers::TreeNode* n = static_cast(_nodeMapper->GetModel()->GetBuffer()); + MainWindow::ResourceChanged(QString::fromStdString(n->name()), ResChange::Reverted); if (!_resMapper->RestoreBackup()) { // This should never happen but here incase someone decides to incorrectly null the backup qDebug() << "Failed to revert editor changes"; @@ -49,6 +52,7 @@ void BaseEditor::dataChanged(const QModelIndex& topLeft, const QModelIndex& /*bo emit ResourceRenamed(n->type_case(), oldValue.toString(), QString::fromStdString(n->name())); } _resMapper->SetDirty(true); + MainWindow::ResourceChanged(QString::fromStdString(n->name()), ResChange::Modified); } void BaseEditor::RebindSubModels() { diff --git a/MainWindow.cpp b/MainWindow.cpp index ccc37f9ee..2b8bee994 100644 --- a/MainWindow.cpp +++ b/MainWindow.cpp @@ -178,6 +178,8 @@ MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent), _ui(new Ui::MainW _ui->gitLogView->setItemDelegate(new GitTreeStyledDelegate); _ui->gitLogView->horizontalHeader()->setSectionResizeMode(QHeaderView::Stretch); + _ui->changesListView->setModel(&egmManager.GetResourceChangesModel()); + openNewProject(); } @@ -589,3 +591,7 @@ void MainWindow::on_actionSortByName_triggered() { void MainWindow::on_treeView_customContextMenuRequested(const QPoint &pos) { _ui->menuEdit->exec(_ui->treeView->mapToGlobal(pos)); } + +void MainWindow::ResourceChanged(const QString &res, ResChange change) { + egmManager.ResourceChanged(res, change); +} diff --git a/MainWindow.h b/MainWindow.h index a372a4db8..7227a276e 100644 --- a/MainWindow.h +++ b/MainWindow.h @@ -51,6 +51,7 @@ class MainWindow : public QMainWindow { void openProject(buffers::Project* openedProject); buffers::Game *Game() const { return egmManager.GetGame(); } static EventData *GetEventData() { return egmManager.GetEventData(); } + static void ResourceChanged(const QString &res, ResChange change); static QList EnigmaSearchPaths; static QFileInfo EnigmaRoot; diff --git a/MainWindow.ui b/MainWindow.ui index 185f656f9..9f84f5a46 100644 --- a/MainWindow.ui +++ b/MainWindow.ui @@ -514,35 +514,7 @@ - - - - obj_playerchanged - - - - :/actions/edit.png:/actions/edit.png - - - - - spr_deleted - - - - :/actions/delete.png:/actions/delete.png - - - - - spr_added - - - - :/actions/add.png:/actions/add.png - - - + diff --git a/Models/ResourceChangesModel.cpp b/Models/ResourceChangesModel.cpp new file mode 100644 index 000000000..848466735 --- /dev/null +++ b/Models/ResourceChangesModel.cpp @@ -0,0 +1,70 @@ +#include "ResourceChangesModel.h" + +#include + +ResourceChangesModel::ResourceChangesModel(QObject *parent) : QAbstractListModel(parent) {} + +void ResourceChangesModel::ResourceChanged(const QString &res, ResChange change) { + beginResetModel(); + + if (change == ResChange::Reverted) _changes.remove(res); + + if (_changes.contains(res)) { + // Add then remove shouldn't be on list + if (_changes[res] == ResChange::Added && change == ResChange::Removed) { + _changes.remove(res); + return; + } + // modified shouldnt overwrite added + if (_changes[res] == ResChange::Added && change == ResChange::Modified) return; + // modified shouldnt overwrite renamed + if (_changes[res] == ResChange::Renamed && change == ResChange::Modified) return; + } + + // TODO: if renamed before commited change the added name + if (_changes[res] == ResChange::Added && change == ResChange::Renamed) { + } + + _changes[res] = change; + + endResetModel(); +} + +void ResourceChangesModel::ClearChanges() { + beginResetModel(); + _changes.clear(); + endResetModel(); +} + +int ResourceChangesModel::rowCount(const QModelIndex &parent) const { + if (parent.isValid()) + return 0; + else + return _changes.size(); +} + +QVariant ResourceChangesModel::data(const QModelIndex &index, int role) const { + if (!index.isValid()) return QVariant(); + + QList keys = _changes.keys(); + + if (role == Qt::DecorationRole) { + switch (_changes[keys[index.row()]]) { + case ResChange::Added: return QIcon(":/actions/add.png"); + case ResChange::Modified: return QIcon(":/actions/edit.png"); + case ResChange::Renamed: return QIcon(":/actions/edit.png"); + case ResChange::Removed: return QIcon(":/actions/delete.png"); + case ResChange::Reverted: return QVariant(); + } + } else if (role == Qt::DisplayRole) { + switch (_changes[keys[index.row()]]) { + case ResChange::Added: return keys[index.row()] + " " + tr("Added"); + case ResChange::Modified: return keys[index.row()] + " " + tr("Modified"); + case ResChange::Renamed: return keys[index.row()] + " " + tr("Renamed"); + case ResChange::Removed: return keys[index.row()] + " " + tr("Removed"); + case ResChange::Reverted: return QVariant(); + } + } + + return QVariant(); +} diff --git a/Models/ResourceChangesModel.h b/Models/ResourceChangesModel.h new file mode 100644 index 000000000..c65a12d03 --- /dev/null +++ b/Models/ResourceChangesModel.h @@ -0,0 +1,30 @@ +#ifndef RESOURCECHANGESMODEL_H +#define RESOURCECHANGESMODEL_H + +#include +#include +#include + +enum class ResChange : int { + Added, + Modified, + Renamed, + Removed, + Reverted +}; + +class ResourceChangesModel : public QAbstractListModel +{ + Q_OBJECT +public: + ResourceChangesModel(QObject* parent = nullptr); + virtual int rowCount(const QModelIndex &parent = QModelIndex()) const override; + virtual QVariant data(const QModelIndex &index, int role) const override; + void ResourceChanged(const QString &res, ResChange change); + void ClearChanges(); + +protected: + QMap _changes; +}; + +#endif // RESOURCECHANGESMODEL_H diff --git a/Models/ResourceModelMap.cpp b/Models/ResourceModelMap.cpp index 191f9aadf..3285df7da 100644 --- a/Models/ResourceModelMap.cpp +++ b/Models/ResourceModelMap.cpp @@ -26,12 +26,17 @@ void ResourceModelMap::AddResource(buffers::TreeNode* child) { if (model != nullptr) { connect(model, &ProtoModel::DataChanged, [this]() { emit DataChanged(); }); } + + if (!child->has_folder()) + MainWindow::ResourceChanged(QString::fromStdString(child->name()), ResChange::Added); } void ResourceModelMap::RemoveResource(TypeCase type, const QString& name) { if (!_resources.contains(type)) return; if (!_resources[type].contains(name)) return; + MainWindow::ResourceChanged(name, ResChange::Removed); + // Delete all instances of this object type if (type == TypeCase::kObject) { for (auto room : _resources[TypeCase::kRoom]) { @@ -125,6 +130,8 @@ MessageModel* ResourceModelMap::GetResourceByName(int type, const std::string& n } void ResourceModelMap::ResourceRenamed(TypeCase type, const QString& oldName, const QString& newName) { + MainWindow::ResourceChanged(oldName, ResChange::Renamed); + if (oldName == newName || !_resources[type].contains(oldName)) return; _resources[type][newName] = _resources[type][oldName]; diff --git a/RadialGM.pro b/RadialGM.pro index 95cd5d926..53148631d 100644 --- a/RadialGM.pro +++ b/RadialGM.pro @@ -85,6 +85,7 @@ SOURCES += \ Models/RepeatedImageModel.cpp \ Models/RepeatedMessageModel.cpp \ Models/RepeatedStringModel.cpp \ + Models/ResourceChangesModel.cpp \ Widgets/AssetScrollAreaBackground.cpp \ Widgets/PathView.cpp \ Widgets/SpriteSubimageListView.cpp \ @@ -150,6 +151,7 @@ HEADERS += \ Models/RepeatedMessageModel.h \ Models/RepeatedModel.h \ Models/RepeatedStringModel.h \ + Models/ResourceChangesModel.h \ Widgets/AssetScrollArea.h \ Widgets/AssetScrollAreaBackground.h \ Widgets/BackgroundView.h \ diff --git a/Submodules/enigma-dev b/Submodules/enigma-dev index 560ad579a..148a56c4e 160000 --- a/Submodules/enigma-dev +++ b/Submodules/enigma-dev @@ -1 +1 @@ -Subproject commit 560ad579a8dcb9ab23f5a521274d518fef574cd6 +Subproject commit 148a56c4e6cc5b0c35df251b99b846558f13b03b