Initial commit for new Console widget
ADD
src/console.cpp
+#include "console.h"
+
+#include "ripessettings.h"
+
+#include <QScrollBar>
+
+namespace Ripes {
+
+Console::Console(QWidget* parent) : QPlainTextEdit(parent) {
+ QFont font = QFont("Inconsolata", 12);
+ setFont(font);
+ document()->setMaximumBlockCount(100);
+
+ auto paletteChangeFunctor = [=] {
+ QPalette p = palette();
+ p.setColor(QPalette::Base, RipesSettings::value(RIPES_SETTING_CONSOLEBG).value<QColor>());
+ p.setColor(QPalette::Text, RipesSettings::value(RIPES_SETTING_CONSOLEFONT).value<QColor>());
+ setPalette(p);
+ };
+
+ connect(RipesSettings::getObserver(RIPES_SETTING_CONSOLEBG), &SettingObserver::modified, paletteChangeFunctor);
+ connect(RipesSettings::getObserver(RIPES_SETTING_CONSOLEFONT), &SettingObserver::modified, paletteChangeFunctor);
+ paletteChangeFunctor();
+
+ connect(RipesSettings::getObserver(RIPES_SETTING_CONSOLEECHO), &SettingObserver::modified,
+ [=](const QVariant& value) { m_localEchoEnabled = value.toBool(); });
+}
+
+void Console::putData(const QByteArray& data) {
+ insertPlainText(data);
+
+ QScrollBar* bar = verticalScrollBar();
+ bar->setValue(bar->maximum());
+}
+
+void Console::keyPressEvent(QKeyEvent* e) {
+ switch (e->key()) {
+ case Qt::Key_Backspace:
+ case Qt::Key_Left:
+ case Qt::Key_Right:
+ case Qt::Key_Up:
+ case Qt::Key_Down:
+ break;
+ default:
+ if (m_localEchoEnabled)
+ QPlainTextEdit::keyPressEvent(e);
+ emit sendData(e->text().toLocal8Bit());
+ }
+}
+
+} // namespace Ripes

ADD
src/console.h
+#pragma once
+
+#include <QPlainTextEdit>
+
+namespace Ripes {
+
+class Console : public QPlainTextEdit {
+ Q_OBJECT
+
+signals:
+ void sendData(const QByteArray& data);
+
+public:
+ Console(QWidget* parent = nullptr);
+
+ void putData(const QByteArray& data);
+
+protected:
+ void keyPressEvent(QKeyEvent* e) override;
+
+private:
+ bool m_localEchoEnabled = false;
+};
+
+} // namespace Ripes

MODIFY
src/processortab.ui
src/processortab.ui
</property>
<layout class="QGridLayout" name="gridLayout_6">
<item row="0" column="0">
- <widget class="QPlainTextEdit" name="console">
+ <widget class="Console" name="console">
<property name="sizePolicy">
<sizepolicy hsizetype="MinimumExpanding" vsizetype="MinimumExpanding">
<horstretch>0</horstretch>
<header>VSRTL/graphics/vsrtl_widget.h</header>
<container>1</container>
</customwidget>
+ <customwidget>
+ <class>Console</class>
+ <extends>QPlainTextEdit</extends>
+ <header>console.h</header>
+ </customwidget>
</customwidgets>
<resources/>
<connections/>

MODIFY
src/ripessettings.cpp
src/ripessettings.cpp
@@ -41,7 +41,7 @@ RipesSettings::RipesSettings() {
}
}
-const SettingObserver* RipesSettings::getObserver(const QString& key) {
+SettingObserver* RipesSettings::getObserver(const QString& key) {
return &get().m_observers.at(key);
}

MODIFY
src/ripessettings.h
src/ripessettings.h
#pragma once
+#include <QColor>
#include <QSettings>
namespace Ripes {
@@ -8,16 +9,25 @@ namespace Ripes {
#define RIPES_SETTING_REWINDSTACKSIZE ("simulator_rewindstacksize")
#define RIPES_SETTING_CCPATH ("compiler_path")
#define RIPES_SETTING_CCARGS ("compiler_args")
+#define RIPES_SETTING_CONSOLEECHO ("console_echo")
+#define RIPES_SETTING_CONSOLEBG ("console_bg_color")
+#define RIPES_SETTING_CONSOLEFONT ("console_font_color")
// Definitions of all default settings within Ripes
-const static std::map<QString, QVariant> s_defaultSettings = {{RIPES_SETTING_REWINDSTACKSIZE, 100},
+const static std::map<QString, QVariant> s_defaultSettings = {
+ {RIPES_SETTING_REWINDSTACKSIZE, 100},
{RIPES_SETTING_CCPATH, ""},
- {RIPES_SETTING_CCARGS, "-O0"}};
+ {RIPES_SETTING_CCARGS, "-O0"},
+ {RIPES_SETTING_CONSOLEECHO, "true"},
+ {RIPES_SETTING_CONSOLEBG, QColor(Qt::white)},
+ {RIPES_SETTING_CONSOLEFONT, QColor(Qt::black)},
+};
/**
* @brief The SettingObserver class
* A wrapper class around a single Ripes setting.
- * Provides a slot for setting the setting and a signal for broadcasting that the setting was modified.
+ * Provides a slot for setting the setting and a signal for broadcasting that the setting was modified. Useful for
+ * propagating settings changes to all over the codebase.
*/
class SettingObserver : public QObject {
Q_OBJECT
@@ -46,7 +56,7 @@ public:
* @brief getObserver
* returns the observer for the given setting key @p key
*/
- static const SettingObserver* getObserver(const QString& key);
+ static SettingObserver* getObserver(const QString& key);
private:
static RipesSettings& get() {

MODIFY
src/settingsdialog.cpp
src/settingsdialog.cpp
#include "ccmanager.h"
#include "ripessettings.h"
+#include <QCheckBox>
+#include <QColorDialog>
#include <QFileDialog>
#include <QGroupBox>
#include <QLabel>
@@ -28,23 +30,53 @@ std::pair<QWidget*, QGridLayout*> constructPage() {
return {pageWidget, itemLayout};
}
-template <typename T_Widget>
-std::pair<QLabel*, T_Widget*> createSettingsWidgets(const QString& settingName, const QString& labelText) {
+template <typename T_TriggerWidget, typename T_EditWidget = T_TriggerWidget>
+std::pair<QLabel*, T_TriggerWidget*> createSettingsWidgets(const QString& settingName, const QString& labelText) {
auto* label = new QLabel(labelText);
- T_Widget* widget = new T_Widget();
- const auto* settingObserver = RipesSettings::getObserver(settingName);
+ T_TriggerWidget* widget = new T_TriggerWidget();
- if constexpr (std::is_same<T_Widget, QSpinBox>()) {
+ auto* settingObserver = RipesSettings::getObserver(settingName);
+
+ if constexpr (std::is_same<T_EditWidget, QSpinBox>()) {
// Ensure that the current value can be represented in the spinbox. It is expected that the spinbox range will
// be specified after being created in this function.
widget->setRange(INT_MIN, INT_MAX);
widget->setValue(settingObserver->value().toUInt());
widget->connect(widget, QOverload<int>::of(&QSpinBox::valueChanged), settingObserver,
&SettingObserver::setValue);
- } else if constexpr (std::is_same<T_Widget, QLineEdit>()) {
+ } else if constexpr (std::is_same<T_EditWidget, QLineEdit>()) {
widget->connect(widget, &QLineEdit::textChanged, settingObserver, &SettingObserver::setValue);
widget->setText(settingObserver->value().toString());
+ } else if constexpr (std::is_same<T_EditWidget, QCheckBox>()) {
+ widget->connect(widget, &QCheckBox::toggled, settingObserver, &SettingObserver::setValue);
+ widget->setChecked(settingObserver->value().toBool());
+ } else if constexpr (std::is_same<T_EditWidget, QColorDialog>()) {
+ // Create a QPushButton which will trigger a QColorWidget when clicked. Changes in the color settings will
+ // trigger a change in the pushbutton color
+ auto colorSetterFunctor = [=] {
+ QPalette pal = widget->palette();
+ pal.setColor(QPalette::Button, settingObserver->value().value<QColor>());
+ widget->setAutoFillBackground(true);
+ widget->setPalette(pal);
+ };
+
+ // We want changes in the set color to propagate to the button, while in the dialog. But this connection must be
+ // deleted once the dialog is closed, to avoid a dangling connection between the settings object and the trigger
+ // widget.
+ auto conn = settingObserver->connect(settingObserver, &SettingObserver::modified, colorSetterFunctor);
+ widget->connect(widget, &QObject::destroyed, [=] { settingObserver->disconnect(conn); });
+
+ widget->connect(widget, &QPushButton::clicked, [=](bool) {
+ QColorDialog diag;
+ diag.setCurrentColor(settingObserver->value().value<QColor>());
+ if (diag.exec()) {
+ settingObserver->setValue(diag.selectedColor());
+ }
+ });
+
+ // Apply color of current setting
+ colorSetterFunctor();
}
return {label, widget};
@@ -59,6 +91,7 @@ SettingsDialog::SettingsDialog(QWidget* parent) : QDialog(parent), m_ui(new Ui::
// Create settings pages
addPage("Editor", createEditorPage());
addPage("Simulator", createSimulatorPage());
+ addPage("Environment", createEnvironmentPage());
m_ui->settingsList->setCurrentRow(0);
}
@@ -152,6 +185,35 @@ QWidget* SettingsDialog::createSimulatorPage() {
return pageWidget;
}
+QWidget* SettingsDialog::createEnvironmentPage() {
+ auto* consoleGroupBox = new QGroupBox("Console");
+ auto* consoleLayout = new QGridLayout();
+ consoleGroupBox->setLayout(consoleLayout);
+
+ auto [pageWidget, pageLayout] = constructPage();
+
+ // Setting: RIPES_SETTING_CONSOLEECHO
+ auto [echoLabel, echoCheckbox] = createSettingsWidgets<QCheckBox>(RIPES_SETTING_CONSOLEECHO, "Echo console input:");
+ consoleLayout->addWidget(echoLabel, 0, 0);
+ consoleLayout->addWidget(echoCheckbox, 0, 1);
+
+ // Setting: RIPES_SETTING_CONSOLEFONT
+ auto [fontColorLabel, fontColorButton] =
+ createSettingsWidgets<QPushButton, QColorDialog>(RIPES_SETTING_CONSOLEFONT, "Console font color:");
+ consoleLayout->addWidget(fontColorLabel, 1, 0);
+ consoleLayout->addWidget(fontColorButton, 1, 1);
+
+ // Setting: RIPES_SETTING_CONSOLEBG
+ auto [bgColorLabel, bgColorButton] =
+ createSettingsWidgets<QPushButton, QColorDialog>(RIPES_SETTING_CONSOLEBG, "Console background color:");
+ consoleLayout->addWidget(bgColorLabel, 2, 0);
+ consoleLayout->addWidget(bgColorButton, 2, 1);
+
+ pageLayout->addWidget(consoleGroupBox);
+
+ return pageWidget;
+}
+
void SettingsDialog::addPage(const QString& name, QWidget* page) {
const int index = m_ui->settingsPages->addWidget(page);
m_pageIndex[name] = index;

MODIFY
src/settingsdialog.h
src/settingsdialog.h
@@ -29,6 +29,7 @@ private:
QWidget* createEditorPage();
QWidget* createSimulatorPage();
+ QWidget* createEnvironmentPage();
Ui::SettingsDialog* m_ui;

Initial commit for new Console widget