Skip to content

Commit

Permalink
GRPC & Compiler Related Features (#37)
Browse files Browse the repository at this point in the history
* Added `SettingsEditor` designer form class with the basic ENIGMA settings for compiling.
* Added 4 new icons to use in the script editor's autocompletion window. One of them is an f(x) icon for functions and the other three are colored right-facing arrows for constants/variables/globals. Resources will later just use their resource icons when we add that.
* Added a system cache to the main window for plugins to communicate available systems to the built in editors. This is primarily just used by the settings editor so it can populate the API combos using systems found by the GRPC plugin.
* Added a static instance accessor to the main window I'd like to later remove that is used to emit a config change signal from outside the main window itself. The reason is that signals require a QObject instance.
* Added a `CompileStatusChanged` signal to RGMPlugin interface so plugins can inform the main window when the compile status changes. This is how running the game disables the other buttons and forces the output dock widget visible.
* Added a static mutator to set the currently selected config which for now just fires a signal on the static instance that I want to remove. This is used temporarily for the settings editor to have a save button that actually tells the GRPC plugin to tell emake to update its API targets.
* Added the settings editor to the editor factory map so config resources can actually be opened.
* Replaced the change game settings action with a menu for config selection under the resources menu in the same place.
* Added a config selector to the main toolbar and gave it a split popup mode.
* Renamed the timeline actions in the menu to be a single word instead of two words. I never agreed with GameMaker making them two words, unlike every other resource group in the tree.
* Added mnemonics to the resource creation menu to facilitate keyboard navigation.
* Merged `ErrorRead` and `OutputRead` signals into a `LogOutput` signal on the main window. This is to support more granularity of logging which we can later allow the user to filter.
* Moved the initialization of the `TreeModel` icon map to its constructor to allow public access. This is so that later the icons can be used to represent resource keywords in the autocompletions.
* Added `future_deadline` helper to facilitate in calculating GRPC deadlines in the `ServerPlugin`.
* Added `tag`/`detag` helpers to the `ServerPlugin` to faciliate in tagging RPC states with async GRPC.
* Added `CallData` to manage the common state of async RPC calls in the `ServerPlugin`.
* Added `AsyncReadWorker` to drive the state machine of an async streaming read RPC in the `ServerPlugin`.
* Added `AsyncResponseReadWorker` to drive the state machine of a non-streaming async read RPC in the `ServerPlugin`.
* Changed all RPC stub implementations in `CompilerClient` to async using derivations of the above classes, helpers, and abstractions.
* Added `CompilerClient::ScheduleTask` to schedule an RPC to be started and processed asynchronously.
* Added `CompilerClient::UpdateLoop` for processing RPC calls asynchronously one at a time (for now). This is triggered regularly by a QTimer with an interval of 0 ms.
* Added a list of search paths for emake that looks for executable files in known locations. This means RGM can now find emake if it's directly next to it in the filesystem.
* Changed the `ServerPlugin` destructor to call `QProcess::close` instead of `QProcess::terminate` because the latter does not work for console programs that do not run an event loop on Windows.
* Added a static keyword API to `CodeWidget` that can be used to communicate keywords to QScintilla for syntax highlighting and autocompletion.
  • Loading branch information
RobertBColton authored Nov 1, 2018
1 parent f534deb commit 5ca0af8
Show file tree
Hide file tree
Showing 22 changed files with 1,915 additions and 137 deletions.
3 changes: 3 additions & 0 deletions CmakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ set(RGM_SOURCES
Editors/TimelineEditor.cpp
Editors/RoomEditor.cpp
Editors/SpriteEditor.cpp
Editors/SettingsEditor.cpp
Models/TreeModel.cpp
Models/SpriteModel.cpp
Models/ProtoModel.cpp
Expand Down Expand Up @@ -75,6 +76,7 @@ set(RGM_HEADERS
Editors/TimelineEditor.h
Editors/RoomEditor.h
Editors/SpriteEditor.h
Editors/SettingsEditor.h
Models/TreeModel.h
Models/ProtoModel.h
Models/ModelMapper.h
Expand Down Expand Up @@ -108,6 +110,7 @@ set(RGM_UI
Editors/TimelineEditor.ui
Editors/RoomEditor.ui
Editors/SpriteEditor.ui
Editors/SettingsEditor.ui
)

set(RGM_RC
Expand Down
3 changes: 2 additions & 1 deletion Editors/BaseEditor.h
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,8 @@ static const QHash<int, int> ResTypeFields = {{TypeCase::kSprite, TreeNode::kSpr
{TypeCase::kScript, TreeNode::kScriptFieldNumber},
{TypeCase::kTimeline, TreeNode::kTimelineFieldNumber},
{TypeCase::kObject, TreeNode::kObjectFieldNumber},
{TypeCase::kRoom, TreeNode::kRoomFieldNumber}};
{TypeCase::kRoom, TreeNode::kRoomFieldNumber},
{TypeCase::kSettings, TreeNode::kSettingsFieldNumber}};

class BaseEditor : public QWidget {
Q_OBJECT
Expand Down
106 changes: 106 additions & 0 deletions Editors/SettingsEditor.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
#include "SettingsEditor.h"
#include "MainWindow.h"
#include "ui_SettingsEditor.h"

#include "codegen/Settings.pb.h"

#include <QPushButton>

using namespace buffers::resources;

Q_DECLARE_METATYPE(buffers::SystemInfo);

static std::string get_combo_system_id(const QComboBox* combo) {
auto data = combo->currentData();
auto subsystem = data.value<buffers::SystemInfo>();
return subsystem.id();
}

SettingsEditor::SettingsEditor(ProtoModel* model, QWidget* parent)
: BaseEditor(model, parent), ui(new Ui::SettingsEditor) {
ui->setupUi(this);

QPushButton* saveButton = ui->buttonBox->button(QDialogButtonBox::Save);
saveButton->setIcon(QIcon(":/actions/accept.png"));
connect(saveButton, &QPushButton::clicked, [=]() {
Settings settings;
auto* api = settings.mutable_api();
api->set_target_audio(get_combo_system_id(ui->audioCombo));
api->set_target_collision(get_combo_system_id(ui->collisionCombo));
api->set_target_compiler(get_combo_system_id(ui->compilerCombo));
api->set_target_graphics(get_combo_system_id(ui->graphicsCombo));
api->set_target_network(get_combo_system_id(ui->networkCombo));
api->set_target_platform(get_combo_system_id(ui->platformCombo));
api->set_target_widgets(get_combo_system_id(ui->widgetsCombo));
api->add_extensions("Paths");

emit MainWindow::setCurrentConfig(settings);
});
QPushButton* discardButton = ui->buttonBox->button(QDialogButtonBox::Discard);
discardButton->setIcon(QIcon(":/actions/cancel.png"));

pageMap = {{"api", ui->apiPage}, {"extensions", ui->extensionsPage}, {"compiler", ui->compilerPage},
{"controls", ui->controlsPage}, {"graphics", ui->graphicsPage}, {"project info", ui->projectInfoPage},
{"version", ui->versionPage}};

const QMap<QString, QWidget*> systemUIMap = {
{QString("Audio"), ui->audioCombo}, {QString("Platform"), ui->platformCombo},
{QString("Graphics"), ui->graphicsCombo}, {QString("Widget"), ui->widgetsCombo},
{QString("Collision"), ui->collisionCombo}, {QString("Compilers"), ui->compilerCombo},
{QString("Network"), ui->networkCombo}, {QString("Extensions"), ui->extensionsList},
};
for (auto system : MainWindow::systemCache) {
const QString systemName = QString::fromStdString(system.name());
auto it = systemUIMap.find(systemName);
if (it == systemUIMap.end()) continue;
auto widget = it.value();
const QString className = widget->metaObject()->className();
QListWidget* listWidget = nullptr;
QComboBox* combo = nullptr;
if (className == "QListWidget") {
listWidget = static_cast<QListWidget*>(widget);
} else if (className == "QComboBox") {
combo = static_cast<QComboBox*>(widget);
connect(combo, static_cast<void (QComboBox::*)(int)>(&QComboBox::currentIndexChanged), [=]() {
auto data = combo->currentData();
auto subsystem = data.value<buffers::SystemInfo>();
const QString subsystemDesc = QString::fromStdString(subsystem.description());
const QString subsystemAuthor = QString::fromStdString(subsystem.author());
ui->authorName->setText(subsystemAuthor);
ui->systemDesc->setPlainText(subsystemDesc);
});
}
for (auto subsystem : system.subsystems()) {
const QString subsystemName = QString::fromStdString(subsystem.name());
const QString subsystemId = QString::fromStdString(subsystem.id());
const QString subsystemDesc = QString::fromStdString(subsystem.description());
if (combo) {
QVariant data;
data.setValue(subsystem);
combo->addItem(subsystemName, data);
} else if (listWidget) {
auto item = new QListWidgetItem(subsystemName, listWidget);
item->setFlags(item->flags() | Qt::ItemFlag::ItemIsUserCheckable);
item->setCheckState(Qt::Unchecked);
item->setToolTip(subsystemDesc);
item->setData(Qt::UserRole, subsystemId);
}
}
}
}

SettingsEditor::~SettingsEditor() { delete ui; }

void SettingsEditor::on_listWidget_currentItemChanged(QListWidgetItem* current, QListWidgetItem* /*previous*/) {
QWidget* widget = ui->emptyPage;
auto item = current;
if (item) {
const QString path = item->text().toLower();
auto it = pageMap.find(path);
if (it != pageMap.end()) {
widget = it.value();
}
}

ui->stackedWidget->setCurrentWidget(widget);
}
27 changes: 27 additions & 0 deletions Editors/SettingsEditor.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
#ifndef SETTINGSEDITOR_H
#define SETTINGSEDITOR_H

#include "BaseEditor.h"

#include <QListWidgetItem>

namespace Ui {
class SettingsEditor;
}

class SettingsEditor : public BaseEditor {
Q_OBJECT

public:
explicit SettingsEditor(ProtoModel* model, QWidget* parent);
~SettingsEditor();

private slots:
void on_listWidget_currentItemChanged(QListWidgetItem* current, QListWidgetItem* previous);

private:
Ui::SettingsEditor* ui;
QMap<QString, QWidget*> pageMap;
};

#endif // SETTINGSEDITOR_H
Loading

0 comments on commit 5ca0af8

Please sign in to comment.