mirror of https://github.com/mgba-emu/mgba.git
Qt: Refactor the script buffer list into a model (#2566)
This commit is contained in:
parent
c1b1f72005
commit
1bda318531
|
@ -252,6 +252,7 @@ if(ENABLE_SCRIPTING)
|
||||||
list(APPEND SOURCE_FILES
|
list(APPEND SOURCE_FILES
|
||||||
ScriptingController.cpp
|
ScriptingController.cpp
|
||||||
ScriptingTextBuffer.cpp
|
ScriptingTextBuffer.cpp
|
||||||
|
ScriptingTextBufferModel.cpp
|
||||||
ScriptingView.cpp)
|
ScriptingView.cpp)
|
||||||
|
|
||||||
list(APPEND UI_FILES
|
list(APPEND UI_FILES
|
||||||
|
|
|
@ -7,6 +7,7 @@
|
||||||
|
|
||||||
#include "CoreController.h"
|
#include "CoreController.h"
|
||||||
#include "ScriptingTextBuffer.h"
|
#include "ScriptingTextBuffer.h"
|
||||||
|
#include "ScriptingTextBufferModel.h"
|
||||||
|
|
||||||
using namespace QGBA;
|
using namespace QGBA;
|
||||||
|
|
||||||
|
@ -33,6 +34,9 @@ ScriptingController::ScriptingController(QObject* parent)
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
m_bufferModel = new ScriptingTextBufferModel(this);
|
||||||
|
QObject::connect(m_bufferModel, &ScriptingTextBufferModel::textBufferCreated, this, &ScriptingController::textBufferCreated);
|
||||||
|
|
||||||
init();
|
init();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -87,10 +91,7 @@ void ScriptingController::clearController() {
|
||||||
|
|
||||||
void ScriptingController::reset() {
|
void ScriptingController::reset() {
|
||||||
CoreController::Interrupter interrupter(m_controller);
|
CoreController::Interrupter interrupter(m_controller);
|
||||||
for (ScriptingTextBuffer* buffer : m_buffers) {
|
m_bufferModel->reset();
|
||||||
delete buffer;
|
|
||||||
}
|
|
||||||
m_buffers.clear();
|
|
||||||
mScriptContextDetachCore(&m_scriptContext);
|
mScriptContextDetachCore(&m_scriptContext);
|
||||||
mScriptContextDeinit(&m_scriptContext);
|
mScriptContextDeinit(&m_scriptContext);
|
||||||
m_engines.clear();
|
m_engines.clear();
|
||||||
|
@ -106,21 +107,13 @@ void ScriptingController::runCode(const QString& code) {
|
||||||
load(vf, "*prompt");
|
load(vf, "*prompt");
|
||||||
}
|
}
|
||||||
|
|
||||||
mScriptTextBuffer* ScriptingController::createTextBuffer(void* context) {
|
|
||||||
ScriptingController* self = static_cast<ScriptingController*>(context);
|
|
||||||
ScriptingTextBuffer* buffer = new ScriptingTextBuffer(self);
|
|
||||||
self->m_buffers.append(buffer);
|
|
||||||
emit self->textBufferCreated(buffer);
|
|
||||||
return buffer->textBuffer();
|
|
||||||
}
|
|
||||||
|
|
||||||
void ScriptingController::init() {
|
void ScriptingController::init() {
|
||||||
mScriptContextInit(&m_scriptContext);
|
mScriptContextInit(&m_scriptContext);
|
||||||
mScriptContextAttachStdlib(&m_scriptContext);
|
mScriptContextAttachStdlib(&m_scriptContext);
|
||||||
mScriptContextRegisterEngines(&m_scriptContext);
|
mScriptContextRegisterEngines(&m_scriptContext);
|
||||||
|
|
||||||
mScriptContextAttachLogger(&m_scriptContext, &m_logger);
|
mScriptContextAttachLogger(&m_scriptContext, &m_logger);
|
||||||
mScriptContextSetTextBufferFactory(&m_scriptContext, &ScriptingController::createTextBuffer, this);
|
m_bufferModel->attachToContext(&m_scriptContext);
|
||||||
|
|
||||||
HashTableEnumerate(&m_scriptContext.engines, [](const char* key, void* engine, void* context) {
|
HashTableEnumerate(&m_scriptContext.engines, [](const char* key, void* engine, void* context) {
|
||||||
ScriptingController* self = static_cast<ScriptingController*>(context);
|
ScriptingController* self = static_cast<ScriptingController*>(context);
|
||||||
|
|
|
@ -15,10 +15,13 @@
|
||||||
|
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
|
||||||
|
class QTextDocument;
|
||||||
|
|
||||||
namespace QGBA {
|
namespace QGBA {
|
||||||
|
|
||||||
class CoreController;
|
class CoreController;
|
||||||
class ScriptingTextBuffer;
|
class ScriptingTextBuffer;
|
||||||
|
class ScriptingTextBufferModel;
|
||||||
|
|
||||||
class ScriptingController : public QObject {
|
class ScriptingController : public QObject {
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
@ -33,7 +36,7 @@ public:
|
||||||
bool load(VFileDevice& vf, const QString& name);
|
bool load(VFileDevice& vf, const QString& name);
|
||||||
|
|
||||||
mScriptContext* context() { return &m_scriptContext; }
|
mScriptContext* context() { return &m_scriptContext; }
|
||||||
QList<ScriptingTextBuffer*> textBuffers() { return m_buffers; }
|
ScriptingTextBufferModel* textBufferModel() const { return m_bufferModel; }
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
void log(const QString&);
|
void log(const QString&);
|
||||||
|
@ -59,7 +62,7 @@ private:
|
||||||
|
|
||||||
mScriptEngineContext* m_activeEngine = nullptr;
|
mScriptEngineContext* m_activeEngine = nullptr;
|
||||||
QHash<QString, mScriptEngineContext*> m_engines;
|
QHash<QString, mScriptEngineContext*> m_engines;
|
||||||
QList<ScriptingTextBuffer*> m_buffers;
|
ScriptingTextBufferModel* m_bufferModel;
|
||||||
|
|
||||||
std::shared_ptr<CoreController> m_controller;
|
std::shared_ptr<CoreController> m_controller;
|
||||||
};
|
};
|
||||||
|
|
|
@ -47,12 +47,12 @@ private:
|
||||||
static void deinit(struct mScriptTextBuffer*);
|
static void deinit(struct mScriptTextBuffer*);
|
||||||
|
|
||||||
static void setName(struct mScriptTextBuffer*, const char* name);
|
static void setName(struct mScriptTextBuffer*, const char* name);
|
||||||
|
|
||||||
static uint32_t getX(const struct mScriptTextBuffer*);
|
static uint32_t getX(const struct mScriptTextBuffer*);
|
||||||
static uint32_t getY(const struct mScriptTextBuffer*);
|
static uint32_t getY(const struct mScriptTextBuffer*);
|
||||||
static uint32_t cols(const struct mScriptTextBuffer*);
|
static uint32_t cols(const struct mScriptTextBuffer*);
|
||||||
static uint32_t rows(const struct mScriptTextBuffer*);
|
static uint32_t rows(const struct mScriptTextBuffer*);
|
||||||
|
|
||||||
static void print(struct mScriptTextBuffer*, const char* text);
|
static void print(struct mScriptTextBuffer*, const char* text);
|
||||||
static void clear(struct mScriptTextBuffer*);
|
static void clear(struct mScriptTextBuffer*);
|
||||||
static void setSize(struct mScriptTextBuffer*, uint32_t cols, uint32_t rows);
|
static void setSize(struct mScriptTextBuffer*, uint32_t cols, uint32_t rows);
|
||||||
|
|
|
@ -0,0 +1,73 @@
|
||||||
|
/* Copyright (c) 2013-2022 Jeffrey Pfau
|
||||||
|
*
|
||||||
|
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||||
|
#include "ScriptingTextBufferModel.h"
|
||||||
|
|
||||||
|
#include "ScriptingTextBuffer.h"
|
||||||
|
|
||||||
|
#include <QTextDocument>
|
||||||
|
|
||||||
|
using namespace QGBA;
|
||||||
|
|
||||||
|
ScriptingTextBufferModel::ScriptingTextBufferModel(QObject* parent)
|
||||||
|
: QAbstractListModel(parent)
|
||||||
|
{
|
||||||
|
// initializers only
|
||||||
|
}
|
||||||
|
|
||||||
|
void ScriptingTextBufferModel::attachToContext(mScriptContext* context)
|
||||||
|
{
|
||||||
|
mScriptContextSetTextBufferFactory(context, &ScriptingTextBufferModel::createTextBuffer, this);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ScriptingTextBufferModel::reset() {
|
||||||
|
beginResetModel();
|
||||||
|
QList<ScriptingTextBuffer*> toDelete = m_buffers;
|
||||||
|
m_buffers.clear();
|
||||||
|
endResetModel();
|
||||||
|
for (ScriptingTextBuffer* buffer : toDelete) {
|
||||||
|
delete buffer;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
mScriptTextBuffer* ScriptingTextBufferModel::createTextBuffer(void* context) {
|
||||||
|
ScriptingTextBufferModel* self = static_cast<ScriptingTextBufferModel*>(context);
|
||||||
|
self->beginInsertRows(QModelIndex(), self->m_buffers.size(), self->m_buffers.size() + 1);
|
||||||
|
ScriptingTextBuffer* buffer = new ScriptingTextBuffer(self);
|
||||||
|
QObject::connect(buffer, &ScriptingTextBuffer::bufferNameChanged, self, &ScriptingTextBufferModel::bufferNameChanged);
|
||||||
|
self->m_buffers.append(buffer);
|
||||||
|
emit self->textBufferCreated(buffer);
|
||||||
|
self->endInsertRows();
|
||||||
|
return buffer->textBuffer();
|
||||||
|
}
|
||||||
|
|
||||||
|
void ScriptingTextBufferModel::bufferNameChanged(const QString&) {
|
||||||
|
ScriptingTextBuffer* buffer = qobject_cast<ScriptingTextBuffer*>(sender());
|
||||||
|
int row = m_buffers.indexOf(buffer);
|
||||||
|
if (row < 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
QModelIndex idx = index(row, 0);
|
||||||
|
emit dataChanged(idx, idx, { Qt::DisplayRole });
|
||||||
|
}
|
||||||
|
|
||||||
|
int ScriptingTextBufferModel::rowCount(const QModelIndex& parent) const {
|
||||||
|
if (parent.isValid()) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
return m_buffers.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
QVariant ScriptingTextBufferModel::data(const QModelIndex& index, int role) const {
|
||||||
|
if (index.parent().isValid() || index.row() < 0 || index.row() >= m_buffers.size() || index.column() != 0) {
|
||||||
|
return QVariant();
|
||||||
|
}
|
||||||
|
if (role == Qt::DisplayRole) {
|
||||||
|
return m_buffers[index.row()]->document()->metaInformation(QTextDocument::DocumentTitle);
|
||||||
|
} else if (role == ScriptingTextBufferModel::DocumentRole) {
|
||||||
|
return QVariant::fromValue<QTextDocument*>(m_buffers[index.row()]->document());
|
||||||
|
}
|
||||||
|
return QVariant();
|
||||||
|
}
|
|
@ -0,0 +1,48 @@
|
||||||
|
/* Copyright (c) 2013-2022 Jeffrey Pfau
|
||||||
|
*
|
||||||
|
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <QAbstractListModel>
|
||||||
|
|
||||||
|
#include <mgba/script/context.h>
|
||||||
|
|
||||||
|
class mScriptTextBuffer;
|
||||||
|
|
||||||
|
namespace QGBA {
|
||||||
|
|
||||||
|
class ScriptingTextBuffer;
|
||||||
|
|
||||||
|
class ScriptingTextBufferModel : public QAbstractListModel {
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
public:
|
||||||
|
enum ItemDataRole {
|
||||||
|
DocumentRole = Qt::UserRole + 1,
|
||||||
|
};
|
||||||
|
|
||||||
|
ScriptingTextBufferModel(QObject* parent = nullptr);
|
||||||
|
|
||||||
|
void attachToContext(mScriptContext* context);
|
||||||
|
|
||||||
|
int rowCount(const QModelIndex& parent = QModelIndex()) const;
|
||||||
|
QVariant data(const QModelIndex& index, int role = Qt::DisplayRole) const;
|
||||||
|
|
||||||
|
signals:
|
||||||
|
void textBufferCreated(ScriptingTextBuffer*);
|
||||||
|
|
||||||
|
public slots:
|
||||||
|
void reset();
|
||||||
|
|
||||||
|
private slots:
|
||||||
|
void bufferNameChanged(const QString&);
|
||||||
|
|
||||||
|
private:
|
||||||
|
static mScriptTextBuffer* createTextBuffer(void* context);
|
||||||
|
|
||||||
|
QList<ScriptingTextBuffer*> m_buffers;
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
|
@ -9,6 +9,7 @@
|
||||||
#include "ConfigController.h"
|
#include "ConfigController.h"
|
||||||
#include "ScriptingController.h"
|
#include "ScriptingController.h"
|
||||||
#include "ScriptingTextBuffer.h"
|
#include "ScriptingTextBuffer.h"
|
||||||
|
#include "ScriptingTextBufferModel.h"
|
||||||
|
|
||||||
using namespace QGBA;
|
using namespace QGBA;
|
||||||
|
|
||||||
|
@ -19,26 +20,34 @@ ScriptingView::ScriptingView(ScriptingController* controller, ConfigController*
|
||||||
{
|
{
|
||||||
m_ui.setupUi(this);
|
m_ui.setupUi(this);
|
||||||
|
|
||||||
|
ScriptingTextBufferModel* bufferModel = controller->textBufferModel();
|
||||||
m_ui.prompt->setFont(GBAApp::app()->monospaceFont());
|
m_ui.prompt->setFont(GBAApp::app()->monospaceFont());
|
||||||
m_ui.log->setNewlineTerminated(true);
|
m_ui.log->setNewlineTerminated(true);
|
||||||
|
m_ui.buffers->setModel(bufferModel);
|
||||||
|
|
||||||
connect(m_ui.prompt, &QLineEdit::returnPressed, this, &ScriptingView::submitRepl);
|
connect(m_ui.prompt, &QLineEdit::returnPressed, this, &ScriptingView::submitRepl);
|
||||||
connect(m_ui.runButton, &QAbstractButton::clicked, this, &ScriptingView::submitRepl);
|
connect(m_ui.runButton, &QAbstractButton::clicked, this, &ScriptingView::submitRepl);
|
||||||
|
|
||||||
|
connect(bufferModel, &QAbstractItemModel::modelAboutToBeReset, this, &ScriptingView::controllerReset);
|
||||||
|
connect(bufferModel, &QAbstractItemModel::rowsInserted, this, [this, bufferModel](const QModelIndex&, int row, int) {
|
||||||
|
m_ui.buffers->setCurrentIndex(bufferModel->index(row, 0));
|
||||||
|
});
|
||||||
|
|
||||||
connect(m_controller, &ScriptingController::log, m_ui.log, &LogWidget::log);
|
connect(m_controller, &ScriptingController::log, m_ui.log, &LogWidget::log);
|
||||||
connect(m_controller, &ScriptingController::warn, m_ui.log, &LogWidget::warn);
|
connect(m_controller, &ScriptingController::warn, m_ui.log, &LogWidget::warn);
|
||||||
connect(m_controller, &ScriptingController::error, m_ui.log, &LogWidget::error);
|
connect(m_controller, &ScriptingController::error, m_ui.log, &LogWidget::error);
|
||||||
connect(m_controller, &ScriptingController::textBufferCreated, this, &ScriptingView::addTextBuffer);
|
|
||||||
|
|
||||||
connect(m_ui.buffers, &QListWidget::currentRowChanged, this, &ScriptingView::selectBuffer);
|
connect(m_ui.buffers->selectionModel(), &QItemSelectionModel::currentChanged, this, &ScriptingView::selectBuffer);
|
||||||
connect(m_ui.load, &QAction::triggered, this, &ScriptingView::load);
|
connect(m_ui.load, &QAction::triggered, this, &ScriptingView::load);
|
||||||
connect(m_ui.reset, &QAction::triggered, controller, &ScriptingController::reset);
|
connect(m_ui.reset, &QAction::triggered, controller, &ScriptingController::reset);
|
||||||
|
|
||||||
m_mruFiles = m_config->getMRU(ConfigController::MRU::Script);
|
m_mruFiles = m_config->getMRU(ConfigController::MRU::Script);
|
||||||
updateMRU();
|
updateMRU();
|
||||||
|
|
||||||
for (ScriptingTextBuffer* buffer : controller->textBuffers()) {
|
m_blankDocument = new QTextDocument(this);
|
||||||
addTextBuffer(buffer);
|
m_blankDocument->setDocumentLayout(new QPlainTextDocumentLayout(m_blankDocument));
|
||||||
}
|
|
||||||
|
m_ui.buffers->setCurrentIndex(bufferModel->index(0, 0));
|
||||||
}
|
}
|
||||||
|
|
||||||
void ScriptingView::submitRepl() {
|
void ScriptingView::submitRepl() {
|
||||||
|
@ -57,27 +66,16 @@ void ScriptingView::load() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void ScriptingView::addTextBuffer(ScriptingTextBuffer* buffer) {
|
void ScriptingView::controllerReset() {
|
||||||
QTextDocument* document = buffer->document();
|
selectBuffer(QModelIndex());
|
||||||
m_textBuffers.append(buffer);
|
|
||||||
QListWidgetItem* item = new QListWidgetItem(document->metaInformation(QTextDocument::DocumentTitle));
|
|
||||||
connect(buffer, &ScriptingTextBuffer::bufferNameChanged, this, [item](const QString& name) {
|
|
||||||
item->setText(name);
|
|
||||||
});
|
|
||||||
connect(buffer, &QObject::destroyed, this, [this, buffer, item]() {
|
|
||||||
m_textBuffers.removeAll(buffer);
|
|
||||||
delete item;
|
|
||||||
});
|
|
||||||
m_ui.buffers->addItem(item);
|
|
||||||
m_ui.buffers->setCurrentItem(item);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void ScriptingView::selectBuffer(int index) {
|
void ScriptingView::selectBuffer(const QModelIndex& current, const QModelIndex&) {
|
||||||
if (index < 0 || index >= m_textBuffers.size()) {
|
if (current.isValid()) {
|
||||||
// If the selected buffer is out of bounds, clear the document.
|
m_ui.buffer->setDocument(current.data(ScriptingTextBufferModel::DocumentRole).value<QTextDocument*>());
|
||||||
m_ui.buffer->setDocument(nullptr);
|
|
||||||
} else {
|
} else {
|
||||||
m_ui.buffer->setDocument(m_textBuffers[index]->document());
|
// If there is no selected buffer, use the blank document.
|
||||||
|
m_ui.buffer->setDocument(m_blankDocument);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -23,8 +23,8 @@ private slots:
|
||||||
void submitRepl();
|
void submitRepl();
|
||||||
void load();
|
void load();
|
||||||
|
|
||||||
void addTextBuffer(ScriptingTextBuffer*);
|
void controllerReset();
|
||||||
void selectBuffer(int);
|
void selectBuffer(const QModelIndex& current, const QModelIndex& = QModelIndex());
|
||||||
|
|
||||||
private:
|
private:
|
||||||
QString getFilters() const;
|
QString getFilters() const;
|
||||||
|
@ -36,8 +36,8 @@ private:
|
||||||
|
|
||||||
ConfigController* m_config;
|
ConfigController* m_config;
|
||||||
ScriptingController* m_controller;
|
ScriptingController* m_controller;
|
||||||
QList<ScriptingTextBuffer*> m_textBuffers;
|
|
||||||
QStringList m_mruFiles;
|
QStringList m_mruFiles;
|
||||||
|
QTextDocument* m_blankDocument;
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,7 +16,7 @@
|
||||||
<widget class="QWidget" name="centralwidget">
|
<widget class="QWidget" name="centralwidget">
|
||||||
<layout class="QGridLayout" name="gridLayout" columnstretch="0,1,0">
|
<layout class="QGridLayout" name="gridLayout" columnstretch="0,1,0">
|
||||||
<item row="0" column="0" rowspan="3">
|
<item row="0" column="0" rowspan="3">
|
||||||
<widget class="QListWidget" name="buffers">
|
<widget class="QListView" name="buffers">
|
||||||
<property name="sizePolicy">
|
<property name="sizePolicy">
|
||||||
<sizepolicy hsizetype="Preferred" vsizetype="Expanding">
|
<sizepolicy hsizetype="Preferred" vsizetype="Expanding">
|
||||||
<horstretch>0</horstretch>
|
<horstretch>0</horstretch>
|
||||||
|
|
Loading…
Reference in New Issue