diff --git a/APP_VERSION b/APP_VERSION
index ee90284c..60d413dc 100644
--- a/APP_VERSION
+++ b/APP_VERSION
@@ -1 +1 @@
-1.0.4
+2.0.0-ALPHA
diff --git a/resources.qrc b/resources.qrc
index 47e5d964..641551d3 100644
--- a/resources.qrc
+++ b/resources.qrc
@@ -5,7 +5,6 @@
resources/NotoSans-Bold.ttf
resources/NotoSans-Italic.ttf
resources/NotoSans-Regular.ttf
- resources/trophy.svg
resources/styles/app.qss
translations/st_en.qm
translations/st_es.qm
diff --git a/resources/styles/app.qss b/resources/styles/app.qss
index 138c84a1..0470999b 100644
--- a/resources/styles/app.qss
+++ b/resources/styles/app.qss
@@ -9,6 +9,38 @@ QWidget#centralwidget {
color: #E0E0E0;
}
+QWidget#homeContent {
+ background: transparent;
+}
+
+QLabel#homeEyebrow {
+ color: #15B9C2;
+ font-size: 12px;
+ font-weight: 700;
+ letter-spacing: 0.08em;
+ text-transform: uppercase;
+}
+
+QLabel#homeTitle {
+ color: #F4F7F8;
+ font-size: 30px;
+ font-weight: 700;
+}
+
+QLabel#homeSubtitle {
+ color: #9AA5A8;
+ font-size: 15px;
+ line-height: 1.5;
+}
+
+QLabel#difficultyTitle {
+ color: #C9D0D2;
+ font-size: 12px;
+ font-weight: 700;
+ letter-spacing: 0.08em;
+ text-transform: uppercase;
+}
+
QMenu#menuAcercaDe::item {
padding: 6px 24px;
}
@@ -23,56 +55,84 @@ QMenu#menuAcercaDe::icon {
}
QLabel#labelScore {
- font-weight: bold;
+ font-weight: 700;
font-size: 15px;
- color: white;
+ color: #F3F5F6;
+}
+
+QLabel#badgeNivel {
+ min-width: 34px;
+ min-height: 24px;
+ padding: 0 10px;
+ border-radius: 12px;
+ background-color: rgba(17, 179, 188, 0.18);
+ color: #BDECEF;
+ border: none;
+ qproperty-alignment: 'AlignCenter';
+}
+
+QProgressBar#progressBarNivel {
+ background-color: #2A2E30;
+ border: none;
+ border-radius: 4px;
+}
+
+QProgressBar#progressBarNivel::chunk {
+ background-color: #11B3BC;
+ border-radius: 4px;
}
QPushButton#pushButton,
QPushButton#pushButton_2 {
- background-color: #00ADB5;
+ background-color: #262B2D;
color: #FFFFFF;
- border: none;
- padding: 12px 24px;
+ border: 1px solid #353A3D;
+ padding: 0 18px;
border-radius: 10px;
font-size: 16px;
- font-weight: bold;
+ font-weight: 700;
+ text-align: left;
}
QPushButton#pushButton:hover,
QPushButton#pushButton_2:hover {
- background-color: #00CED1;
+ background-color: #2D3436;
+ border: 1px solid #4A5255;
}
QPushButton#pushButton:pressed,
QPushButton#pushButton_2:pressed {
- background-color: #007F86;
+ background-color: #222729;
}
QPushButton#tutorial {
- background-color: #2F2F2F;
- color: #CCCCCC;
- border: 1px solid #444444;
- padding: 8px 16px;
- border-radius: 4px;
+ background-color: rgba(255, 255, 255, 0.03);
+ color: #CDD5D7;
+ border: 1px solid rgba(255, 255, 255, 0.08);
+ padding: 0 14px;
+ border-radius: 8px;
font-size: 14px;
+ font-weight: 600;
+ text-align: left;
}
QPushButton#tutorial:hover {
- background-color: #3A3A3A;
+ background-color: rgba(255, 255, 255, 0.06);
color: #FFFFFF;
+ border: 1px solid rgba(255, 255, 255, 0.14);
}
QPushButton#tutorial:pressed {
- background-color: #262626;
+ background-color: rgba(255, 255, 255, 0.09);
}
QRadioButton#lv1Button,
QRadioButton#lv2Button,
QRadioButton#lv3Button {
- color: #DDDDDD;
- font-size: 16px;
- spacing: 6px;
+ color: #D9E0E2;
+ font-size: 15px;
+ font-weight: 600;
+ spacing: 8px;
}
QRadioButton#lv1Button::indicator,
@@ -100,26 +160,73 @@ QRadioButton#lv3Button::indicator:checked + QLabel {
QPushButton#idiom {
background: transparent;
- color: #CCCCCC;
- border: 1px solid #00ADB5;
- border-radius: 4px;
- padding: 6px 14px;
+ color: #AEB7BA;
+ border: 1px solid #3A4245;
+ border-radius: 8px;
+ padding: 6px 12px;
font-size: 12px;
}
QPushButton#idiom:hover {
- background-color: rgba(255, 255, 255, 0.05);
+ background-color: rgba(255, 255, 255, 0.04);
color: #FFFFFF;
+ border: 1px solid #4A5457;
}
QPushButton#idiom:pressed {
background-color: rgba(255, 255, 255, 0.10);
}
+QWidget#LLTutorWindow,
+QWidget#SLRTutorWindow {
+ background-color: #1F1F1F;
+}
+
+QWidget#LLTutorWindow QPushButton#backButton,
+QWidget#SLRTutorWindow QPushButton#backButton {
+ background: transparent;
+ color: #C5CED0;
+ border: 1px solid #353D40;
+ border-radius: 8px;
+ padding: 6px 12px;
+ font-size: 13px;
+ font-weight: 600;
+}
+
+QWidget#LLTutorWindow QPushButton#backButton:hover,
+QWidget#SLRTutorWindow QPushButton#backButton:hover {
+ background-color: rgba(255, 255, 255, 0.04);
+ color: #FFFFFF;
+ border: 1px solid #475155;
+}
+
+QWidget#LLTutorWindow QPushButton#backButton:pressed,
+QWidget#SLRTutorWindow QPushButton#backButton:pressed {
+ background-color: rgba(255, 255, 255, 0.08);
+}
+
+QWidget#LLTutorWindow QLabel#tick,
+QWidget#SLRTutorWindow QLabel#tick {
+ color: #42C78B;
+}
+
+QWidget#LLTutorWindow QLabel#cross,
+QWidget#SLRTutorWindow QLabel#cross {
+ color: #E46B6B;
+}
+
+QWidget#LLTutorWindow QLabel#cntRight,
+QWidget#LLTutorWindow QLabel#cntWrong,
+QWidget#SLRTutorWindow QLabel#cntRight,
+QWidget#SLRTutorWindow QLabel#cntWrong {
+ color: #F1F4F5;
+ font-weight: 600;
+}
+
QListWidget#listWidget {
- border: 1px solid #3A3A3A;
- border-radius: 6px;
- background-color: transparent;
+ border: 1px solid #303638;
+ border-radius: 12px;
+ background-color: #212526;
}
QListWidget#listWidget::viewport {
@@ -155,10 +262,10 @@ QListWidget#listWidget QScrollBar::sub-page:vertical {
}
QAbstractScrollArea#gr {
- background-color: #232936;
- border: 1px solid #3A3A3A;
- padding: 12px;
- border-radius: 6px;
+ background-color: #20252B;
+ border: 1px solid #30363A;
+ padding: 14px;
+ border-radius: 12px;
}
QAbstractScrollArea#gr QWidget {
@@ -166,19 +273,25 @@ QAbstractScrollArea#gr QWidget {
}
QFrame#grammarView {
- background-color: #232936;
+ background-color: #20252B;
}
QTextEdit#textEdit {
- background-color: #1E1E1E;
+ background-color: #212526;
color: #FFFFFF;
- border: 1px solid #3A3A3A;
- border-radius: 6px;
- padding: 8px;
+ border: 1px solid #303638;
+ border-radius: 12px;
+ padding: 12px;
selection-background-color: #44475A;
selection-color: #FFFFFF;
}
+QTextEdit#textEdit QWidget,
+QTextEdit#textEdit QAbstractScrollArea,
+QTextEdit#textEdit QAbstractScrollArea::viewport {
+ background-color: #212526;
+}
+
QTextEdit#textEdit QScrollBar:vertical {
background: #1E1E1E;
width: 10px;
@@ -208,45 +321,46 @@ QTextEdit#textEdit QScrollBar::sub-page:vertical {
}
QTextEdit#userResponse {
- background-color: #2E2E2E;
- color: #E0E0E0;
- border: 1px solid #444444;
- border-radius: 6px;
- padding: 6px 10px;
- font-size: 16px;
+ background-color: #252A2C;
+ color: #E7ECEE;
+ border: 1px solid #383F42;
+ border-radius: 12px;
+ padding: 10px 14px;
+ font-size: 15px;
}
QTextEdit#userResponse:focus {
- border-bottom: 2px solid #00ADB5;
+ border: 1px solid #11B3BC;
+ background-color: #282E30;
}
QTextEdit#userResponse:disabled {
- background-color: #3A3A3A;
+ background-color: #313638;
color: #777777;
- border: 1px solid #555555;
+ border: 1px solid #444A4D;
}
-QPushButton#confirmButton {
- background-color: rgba(0, 173, 181, 0.85);
+QToolButton#confirmButton {
+ background-color: #11B3BC;
border: none;
- border-radius: 20px;
- min-width: 40px;
- min-height: 40px;
- max-width: 40px;
- max-height: 40px;
+ border-radius: 16px;
+ min-width: 48px;
+ min-height: 48px;
+ max-width: 48px;
+ max-height: 48px;
padding: 0px;
- icon-size: 24px 24px;
+ icon-size: 22px 22px;
}
-QPushButton#confirmButton:hover {
- background-color: #00C8D6;
+QToolButton#confirmButton:hover {
+ background-color: #1AC4CD;
}
-QPushButton#confirmButton:pressed {
- background-color: #009AA3;
+QToolButton#confirmButton:pressed {
+ background-color: #0A9098;
}
-QPushButton#confirmButton:disabled {
+QToolButton#confirmButton:disabled {
background-color: #888888;
color: #DDDDDD;
}
@@ -363,6 +477,42 @@ QMessageBox QPushButton[role="danger"]:pressed {
background-color: #C12E2A;
}
+QDialog#infoDialog {
+ background-color: #1F1F1F;
+ color: #E8ECEE;
+}
+
+QLabel#infoDialogEyebrow {
+ color: #11B3BC;
+ font-size: 12px;
+ font-weight: 700;
+ letter-spacing: 0.08em;
+}
+
+QLabel#infoDialogTitle {
+ color: #F5F7F8;
+ font-size: 24px;
+ font-weight: 700;
+}
+
+QLabel#infoDialogSubtitle {
+ color: #9AA5A8;
+ font-size: 14px;
+}
+
+QTextBrowser#infoDialogContent {
+ background-color: #212526;
+ color: #E8ECEE;
+ border: 1px solid #303638;
+ border-radius: 12px;
+ padding: 14px 16px;
+ selection-background-color: #35515A;
+}
+
+QTextBrowser#infoDialogContent a {
+ color: #36C5CC;
+}
+
QWizard[wizardTheme="slr"] * {
background-color: #2B2B2B;
color: #E0E0E0;
diff --git a/src/appversion.h b/src/appversion.h
index f9ed797b..7280c1d1 100644
--- a/src/appversion.h
+++ b/src/appversion.h
@@ -5,11 +5,11 @@
namespace SyntaxTutor::Version {
inline QString current() {
- return QStringLiteral("1.0.4");
+ return QStringLiteral("2.0.0-ALPHA");
}
inline const char* raw() {
- return "1.0.4";
+ return "2.0.0-ALPHA";
}
} // namespace SyntaxTutor::Version
#endif // APPVERSION_H
diff --git a/src/gui/lltabledialog.cpp b/src/gui/lltabledialog.cpp
index c6fad3df..5f7b128c 100644
--- a/src/gui/lltabledialog.cpp
+++ b/src/gui/lltabledialog.cpp
@@ -17,6 +17,7 @@
*/
#include "lltabledialog.h"
+#include
#include
#include
@@ -96,7 +97,18 @@ LLTableDialog::LLTableDialog(const QStringList& rowHeaders,
resize(width, height);
connect(submitButton, &QPushButton::clicked, this,
- [this]() { emit submitted(getTableData()); });
+ [this]() {
+ commitPendingEdit();
+ emit submitted(getTableData());
+ });
+}
+
+void LLTableDialog::commitPendingEdit() {
+ if (QWidget* editor = QApplication::focusWidget();
+ editor != nullptr && table->isAncestorOf(editor)) {
+ submitButton->setFocus(Qt::OtherFocusReason);
+ QApplication::processEvents();
+ }
}
QVector> LLTableDialog::getTableData() const {
diff --git a/src/gui/lltabledialog.h b/src/gui/lltabledialog.h
index 73be372f..8efd7e60 100644
--- a/src/gui/lltabledialog.h
+++ b/src/gui/lltabledialog.h
@@ -83,6 +83,8 @@ class LLTableDialog : public QDialog {
void submitted(const QVector>& data);
private:
+ void commitPendingEdit();
+
QTableWidget* table; ///< The widget representing the LL(1) parsing table.
QPushButton* submitButton; ///< Button to submit the completed table.
};
diff --git a/src/gui/lltutorwindow.cpp b/src/gui/lltutorwindow.cpp
index ecf1a31e..69f3fdc5 100644
--- a/src/gui/lltutorwindow.cpp
+++ b/src/gui/lltutorwindow.cpp
@@ -43,6 +43,44 @@ QString NormalizeProductionCell(const QString& cell) {
return normalized;
}
+QStringList ParseProductionCell(Grammar& grammar, const QString& cell) {
+ const QString trimmed = cell.trimmed();
+ if (trimmed.isEmpty()) {
+ return {};
+ }
+
+ const QStringList spacedTokens =
+ trimmed.split(kCellWhitespace, Qt::SkipEmptyParts);
+ if (!spacedTokens.isEmpty()) {
+ bool allKnown = true;
+ for (const QString& token : spacedTokens) {
+ if (!grammar.st_.In(token.toStdString())) {
+ allKnown = false;
+ break;
+ }
+ }
+
+ if (allKnown) {
+ return spacedTokens;
+ }
+ }
+
+ const QString normalized = NormalizeProductionCell(trimmed);
+ if (normalized.isEmpty()) {
+ return {};
+ }
+
+ QStringList production;
+ for (const std::string& symbol : grammar.Split(normalized.toStdString())) {
+ production.append(QString::fromStdString(symbol));
+ }
+ if (!production.isEmpty()) {
+ return production;
+ }
+
+ return {normalized};
+}
+
ParsedSymbols ParseSymbolList(const QString& input) {
ParsedSymbols parsed;
const QString text = input.trimmed();
@@ -78,29 +116,28 @@ LLTutorWindow::LLTutorWindow(const Grammar& grammar, TutorialManager* tm,
// ====== UI Setup ==========================================
ui->setupUi(this);
- ui->backButton->setText(tr("Back"));
+ ui->backButton->setText(tr("Atras"));
- // -- Confirm Button Icon & Shadow
+ // -- Confirm Button Icon
ui->confirmButton->setIcon(QIcon(":/resources/send.svg"));
- auto* shadow = new QGraphicsDropShadowEffect;
- shadow->setBlurRadius(10);
- shadow->setOffset(0);
- shadow->setColor(QColor::fromRgb(0, 200, 214));
- ui->confirmButton->setGraphicsEffect(shadow);
// -- User Response Box
ui->userResponse->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
+ ui->userResponse->setFixedHeight(48);
ui->userResponse->setPlaceholderText(tr("Introduce aquí tu respuesta."));
+ ui->confirmButton->setFixedSize(48, 48);
// -- Chat Font
ui->listWidget->setVerticalScrollMode(QAbstractItemView::ScrollPerPixel);
ui->listWidget->verticalScrollBar()->setSingleStep(10);
+ ui->listWidget->viewport()->installEventFilter(this);
// ====== Grammar Display & Formatting ======================
formattedGrammar = FormatGrammar(this->grammar);
grammarView = new GrammarView(ui->gr);
grammarView->setRows(buildGrammarRows(this->grammar));
ui->gr->setWidget(grammarView);
+ ui->gr->setFixedWidth(grammarView->sizeHint().width() + 32);
ui->gr->setAlignment(Qt::AlignLeft | Qt::AlignVCenter);
sortedNonTerminals =
@@ -146,10 +183,10 @@ void LLTutorWindow::requestExit(bool applyResults) {
bool LLTutorWindow::confirmExitToHome() {
QMessageBox msg(this);
- msg.setWindowTitle(tr("Leave LL(1) exercise"));
+ msg.setWindowTitle(tr("Salir del ejercicio LL(1)"));
msg.setTextFormat(Qt::RichText);
- msg.setText(tr("Do you want to go back to the home page? This will discard "
- "your current progress."));
+ msg.setText(tr("Quieres volver al menu principal? Se perdera el progreso "
+ "actual."));
msg.setStandardButtons(QMessageBox::Yes | QMessageBox::No);
msg.setDefaultButton(QMessageBox::No);
@@ -157,7 +194,7 @@ bool LLTutorWindow::confirmExitToHome() {
QAbstractButton* noBtn = msg.button(QMessageBox::No);
if (yesBtn) {
- yesBtn->setText(tr("Yes"));
+ yesBtn->setText(tr("Si"));
yesBtn->setCursor(Qt::PointingHandCursor);
yesBtn->setIcon(QIcon());
yesBtn->setProperty("role", "primary");
@@ -192,7 +229,6 @@ void LLTutorWindow::exportConversationToPdf(const QString& filePath) {
html += R"(