Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions SyntaxTutor.pro
Original file line number Diff line number Diff line change
Expand Up @@ -31,8 +31,10 @@ SOURCES += \
src/backend/lr0_item.cpp \
src/backend/slr1_parser.cpp \
src/backend/symbol_table.cpp \
src/widgets/automatonview.cpp \
src/widgets/customtextedit.cpp \
src/widgets/grammarview.cpp \
src/gui/automatonviewerdialog.cpp \
src/gui/examreportdialog.cpp \
src/gui/grammareditordialog.cpp \
src/gui/lltabledialog.cpp \
Expand All @@ -54,8 +56,10 @@ HEADERS += \
src/backend/slr1_parser.hpp \
src/backend/state.hpp \
src/backend/symbol_table.hpp \
src/widgets/automatonview.h \
src/widgets/customtextedit.h \
src/widgets/grammarview.h \
src/gui/automatonviewerdialog.h \
src/gui/examreportdialog.h \
src/gui/examsession.h \
src/gui/grammareditordialog.h \
Expand Down
62 changes: 62 additions & 0 deletions resources/styles/app.qss
Original file line number Diff line number Diff line change
Expand Up @@ -846,3 +846,65 @@ QDialog[examReport="true"] QPushButton#examReportCloseButton:hover {
color: #FFFFFF;
border: 1px solid rgba(255, 255, 255, 0.12);
}

QPushButton#automatonButton {
background-color: rgba(17, 179, 188, 0.12);
color: #11B3BC;
border: 1px solid rgba(17, 179, 188, 0.35);
border-radius: 8px;
padding: 8px 14px;
font-size: 12px;
font-weight: 600;
}

QPushButton#automatonButton:hover {
background-color: rgba(17, 179, 188, 0.2);
color: #36C5CC;
}

QPushButton#automatonButton:pressed {
background-color: rgba(17, 179, 188, 0.28);
}

QPushButton#automatonButton:disabled {
background-color: #2A2E30;
color: #6F7A7E;
border: 1px solid #353D40;
}

QGraphicsView#slrAutomatonView {
background-color: #212526;
border: 1px solid #303638;
border-radius: 12px;
}

QDialog[automatonViewer="true"] {
background-color: #1F1F1F;
}

QDialog[automatonViewer="true"] QLabel#automatonViewerHint {
color: #6F7A7E;
font-size: 12px;
}

QDialog[automatonViewer="true"] QPushButton#automatonViewerToolButton {
background-color: #2B3133;
color: #E8ECEE;
border: 1px solid rgba(255, 255, 255, 0.1);
border-radius: 8px;
padding: 6px 12px;
font-size: 13px;
font-weight: 600;
min-width: 28px;
}

QDialog[automatonViewer="true"] QPushButton#automatonViewerToolButton:hover {
background-color: #343B3D;
border: 1px solid rgba(17, 179, 188, 0.4);
color: #36C5CC;
}

QDialog[automatonViewer="true"] QPushButton#automatonViewerToolButton:pressed {
background-color: #11B3BC;
color: #07343A;
}
91 changes: 91 additions & 0 deletions src/gui/automatonviewerdialog.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
/*
* SyntaxTutor - Interactive Tutorial About Syntax Analyzers
* Copyright (C) 2025 Jose R. (jose-rzm)
*
* This program is free software: you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/

#include "automatonviewerdialog.h"
#include "automatonview.h"

#include <QHBoxLayout>
#include <QLabel>
#include <QPushButton>
#include <QVBoxLayout>

AutomatonViewerDialog::AutomatonViewerDialog(AutomatonView* view,
QWidget* parent)
: QDialog(parent), view_(view) {
setObjectName("automatonViewerDialog");
setProperty("automatonViewer", true);
setWindowTitle(tr("Autómata LR(0)"));
setModal(false);
resize(820, 620);
setMinimumSize(520, 420);

auto* rootLayout = new QVBoxLayout(this);
rootLayout->setContentsMargins(16, 14, 16, 16);
rootLayout->setSpacing(12);

auto* toolbar = new QHBoxLayout();
toolbar->setSpacing(8);

auto* hint = new QLabel(
tr("Ctrl + rueda para acercar, arrastra para desplazar"), this);
hint->setObjectName("automatonViewerHint");
toolbar->addWidget(hint);
toolbar->addStretch(1);

auto makeToolButton = [this](const QString& text, const QString& tip) {
auto* button = new QPushButton(text, this);
button->setObjectName("automatonViewerToolButton");
button->setToolTip(tip);
button->setCursor(Qt::PointingHandCursor);
button->setAutoDefault(false);
button->setDefault(false);
return button;
};

auto* zoomOutButton = makeToolButton(QStringLiteral("−"), tr("Alejar"));
auto* zoomInButton = makeToolButton(QStringLiteral("+"), tr("Acercar"));
auto* fitButton = makeToolButton(tr("Ajustar"), tr("Ajustar a la vista"));
auto* centerButton =
makeToolButton(tr("Centrar estado"), tr("Centrar el estado actual"));

toolbar->addWidget(zoomOutButton);
toolbar->addWidget(zoomInButton);
toolbar->addWidget(fitButton);
toolbar->addWidget(centerButton);
rootLayout->addLayout(toolbar);

view_->setParent(this);
rootLayout->addWidget(view_, 1);
view_->show();

connect(zoomOutButton, &QPushButton::clicked, view_,
&AutomatonView::zoomOut);
connect(zoomInButton, &QPushButton::clicked, view_, &AutomatonView::zoomIn);
connect(fitButton, &QPushButton::clicked, view_, &AutomatonView::fitToView);
connect(centerButton, &QPushButton::clicked, view_,
&AutomatonView::centerOnCurrentState);
}

AutomatonViewerDialog::~AutomatonViewerDialog() {
// The view is owned by the tutor, not by this dialog. Detach it so it
// survives the dialog and can be embedded again next time.
if (view_ != nullptr && view_->parent() == this) {
view_->hide();
view_->setParent(nullptr);
}
}
57 changes: 57 additions & 0 deletions src/gui/automatonviewerdialog.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
/*
* SyntaxTutor - Interactive Tutorial About Syntax Analyzers
* Copyright (C) 2025 Jose R. (jose-rzm)
*
* This program is free software: you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/

#ifndef AUTOMATONVIEWERDIALOG_H
#define AUTOMATONVIEWERDIALOG_H

#include <QDialog>
#include <QPointer>

class AutomatonView;

/**
* @class AutomatonViewerDialog
* @brief Non-modal floating window that hosts the LR(0) automaton view.
*
* The dialog is a thin shell: it embeds an externally-owned AutomatonView
* (so its progressive reveal state is preserved across open/close cycles)
* and adds a toolbar with zoom in/out, fit-to-view and center-current
* actions. It never owns the view: on destruction it reparents the view out
* so the tutor can keep reusing it. Being non-modal, the student can keep it
* open while continuing the exercise.
*/
class AutomatonViewerDialog : public QDialog {
Q_OBJECT
public:
/**
* @brief Builds the viewer around an existing automaton view.
*
* @param view The automaton view to embed; ownership is not taken.
* @param parent Parent widget.
*/
explicit AutomatonViewerDialog(AutomatonView* view,
QWidget* parent = nullptr);
~AutomatonViewerDialog() override;

private:
// QPointer so the dialog never dereferences the borrowed view if it is
// destroyed first (e.g. by the tutor during teardown).
QPointer<AutomatonView> view_;
};

#endif // AUTOMATONVIEWERDIALOG_H
Loading
Loading