From b9a81b64846f75f263b46842c9b1fbfffd9e72fc Mon Sep 17 00:00:00 2001 From: jorenchik Date: Sun, 20 Oct 2024 13:58:56 +0300 Subject: [PATCH] multiple improvements: multi-line buffering, editing interface --- src/include/main.h | 16 ++- src/qtapp/main.cpp | 265 ++++++++++++++++++++------------------ src/qtapp/trainWindow.cpp | 91 ++++++++----- src/transpiler/parser.cpp | 3 +- 4 files changed, 219 insertions(+), 156 deletions(-) diff --git a/src/include/main.h b/src/include/main.h index 0c5582a..a065515 100644 --- a/src/include/main.h +++ b/src/include/main.h @@ -1,16 +1,28 @@ #pragma once #include +#include #include "parser.h" void update(bool isChanged = false); + void saveMdem(); struct MdemBuffer { - std::vector questions = std::vector(); - time_t trainedAt = 0; + std::vector questions = std::vector(); + time_t trainedAt = 0; + bool error = false; + bool isModified = false; }; void updateMdemInfo(std::string filename = "", bool isChanged = true); +extern QSettings *settings; + +#define SETTING_TIMEZONE "timezone" +#define SETTING_CHARACTER_WRAP "characterWrap" +#define SETTING_NOT_REMEMBERED "notRemembered" +#define SETTING_HARD "hard" +#define SETTING_MEDIUM "medium" +#define SETTING_EASY "easy" diff --git a/src/qtapp/main.cpp b/src/qtapp/main.cpp index 33a1b3d..f721efd 100644 --- a/src/qtapp/main.cpp +++ b/src/qtapp/main.cpp @@ -3,6 +3,7 @@ #include #include #include +#include #include #include #include @@ -24,7 +25,6 @@ #include #include - #include #include #include @@ -53,6 +53,7 @@ #include #include #include +#include #include #include #include @@ -69,7 +70,6 @@ #define DISTANCE 2 #define PER_PAGE 8 #define MDEM_BACKGROUND "#F7F7F7" -#define WRAP_WIDTH 50 struct Mdem { QWidget wMdem; @@ -107,16 +107,14 @@ QFileSystemModel *model; QTreeView *mdemList; QLabel *membaseLabel; -// @Improvement: make it into a hashmap with different buffers; -MdemBuffer *mdemBuffer; -bool isBufferModified = false; +std::map buffers; +MdemBuffer *currentMdemBuffer; // Mdem scroll list. -QList mdems = QList(); -QVBoxLayout *hMdemScroll; -QSpacerItem *mdemSpacer; -std::vector errorPool; -std::vector errorViews; +QList mdems = QList(); +QVBoxLayout *hMdemScroll; +QSpacerItem *mdemSpacer; +ErrorView* errorView; // Editor Mdem* editMdem; @@ -162,8 +160,13 @@ void showBacklabels(Mdem *mdem) { std::string outputMdem(std::vector questions, time_t time = 0) { std::stringstream ss; + int wrap_width = 80; + if (settings->contains(SETTING_CHARACTER_WRAP)) { + wrap_width = settings->value(SETTING_CHARACTER_WRAP).toInt(); + } + if (time > 0) { - auto timezoneOffset = settings->value("timezone").toInt(); + auto timezoneOffset = settings->value(SETTING_TIMEZONE).toInt(); /*time = time + 3600 * timezoneOffset;*/ std::tm* tm = std::localtime(&time); char buffer[100]; @@ -182,7 +185,7 @@ std::string outputMdem(std::vector questions, time_t time = 0) { std::format("-{}{} >\n", cooldownPart, " " + escapeText(question->QuestionText)), - WRAP_WIDTH + wrap_width ); if (MultiElementQuestion* mw = dynamic_cast(question)) { for (auto choice: mw->Choices) { @@ -204,7 +207,7 @@ std::string outputMdem(std::vector questions, time_t time = 0) { orderModifier, escapeText(choice.Answer) ) - , WRAP_WIDTH); + , wrap_width); } } else if (GroupQuestion* gq = dynamic_cast(question)) { for (auto group: gq->Groups) { @@ -213,14 +216,14 @@ std::string outputMdem(std::vector questions, time_t time = 0) { "\t- {}:\n", escapeText(group.name) ) - , WRAP_WIDTH); + , wrap_width); for (auto element: group.elements) { ss << wrapText( std::format( "\t\t- {}\n", escapeText(element) ) - , WRAP_WIDTH); + , wrap_width); } } } @@ -230,7 +233,7 @@ std::string outputMdem(std::vector questions, time_t time = 0) { void makePages() { pages.clear(); - auto len = mdemBuffer->questions.size(); + auto len = currentMdemBuffer->questions.size(); auto pageAmount = len / PER_PAGE; if (len % PER_PAGE != 0) { pageAmount += 1; @@ -238,8 +241,8 @@ void makePages() { for (int i = 0; i < pageAmount; i++) { auto startingIndex = PER_PAGE * i ; auto amount = PER_PAGE; - if (i == mdemBuffer->questions.size() / PER_PAGE) { - amount = mdemBuffer->questions.size() % PER_PAGE; + if (i == currentMdemBuffer->questions.size() / PER_PAGE) { + amount = currentMdemBuffer->questions.size() % PER_PAGE; } pages.push_back(Page{startingIndex, startingIndex + amount}); } @@ -316,15 +319,15 @@ std::string getFilename(std::string path) { } void updateMdemInfo(std::string filename, bool isChanged) { - isBufferModified = isBufferModified; + currentMdemBuffer->isModified = isChanged; if (filename.length() > 0) { std::stringstream ss; ss << std::format("mdem: {}", filename); if (isChanged) { ss << "*"; } - if (mdemBuffer->trainedAt > 0) { - std::tm* tm = std::localtime(&mdemBuffer->trainedAt); + if (currentMdemBuffer->trainedAt > 0) { + std::tm* tm = std::localtime(¤tMdemBuffer->trainedAt); char buffer[100]; std::strftime(buffer, sizeof(buffer), "%d.%m.%Y %H:%M", tm); ss << std::endl << "Last practiced: " << std::string(buffer); @@ -388,9 +391,9 @@ Mdem* makeMdem() { [mdem](bool checked) { if (mdem->question) { Question* deleted = nullptr; - for (int i = 0; i < mdemBuffer->questions.size(); ++i) { - if (mdemBuffer->questions[i] == mdem->question) { - mdemBuffer->questions.erase(mdemBuffer->questions.begin() + i); + for (int i = 0; i < currentMdemBuffer->questions.size(); ++i) { + if (currentMdemBuffer->questions[i] == mdem->question) { + currentMdemBuffer->questions.erase(currentMdemBuffer->questions.begin() + i); delete mdem->question; mdem->question = nullptr; updateMdemInfo(getFilename(currentMdem), true); @@ -417,7 +420,7 @@ Mdem* makeMdem() { // Add Back Content for (int i = 0; i < 20; ++i) { - // @Fix: back label pooling + // @Improve: back label pooling QLabel *elBackText = new QLabel(); mdem->hBack.addWidget(elBackText); mdem->backLabels.append(elBackText); @@ -547,7 +550,6 @@ void SwitchPage(int pageIdx) { prevButton->hide(); } - // Handle page slice Page page; if (pages.size() <= 0) { page = Page(); @@ -562,67 +564,64 @@ void SwitchPage(int pageIdx) { } std::vector pageSlice( - mdemBuffer->questions.begin() + page.start, - mdemBuffer->questions.begin() + page.end + currentMdemBuffer->questions.begin() + page.start, + currentMdemBuffer->questions.begin() + page.end ); CreateMdems(pageSlice); } - -ErrorView *makeErrorView() { - auto errorView = new ErrorView; - errorView->box.setObjectName("error-box"); - errorView->box.setLayout(&errorView->layout); - errorView->box.setMinimumHeight(30); - errorView->box.setStyleSheet( - QString( - "QWidget#error-box {" - "border: 1px solid red;" - "background: %2;" - "}" - ).arg(MDEM_BACKGROUND) - ); - errorView->layout.addWidget(&errorView->label); - errorView->label.setWordWrap(true); - return errorView; -}; - -ErrorView* acquireError() { - if (errorPool.size() <= 0) { - for (int i = 0; i < ERROR_POOL_CHUNK; ++i) { - auto errorView = makeErrorView(); - errorPool.push_back(errorView); - hMdemScroll->addWidget(&errorView->box); - errorView->box.hide(); +void reloadMdem(std::string path) { + if (path == "") { + return; + } + + auto toRemove = std::vector(); + for (auto it = buffers.begin(); it != buffers.end(); ++it) { + auto pair = *it; + if (currentMdem.compare(path) != 0 && + (!pair.second->isModified || pair.second->error)) { + toRemove.push_back(pair.first); } } - auto item = errorPool.back(); - errorPool.pop_back(); - errorViews.push_back(item); - std::cout << std::format("Acquired, current pool size: {}\n", errorPool.size()); - return item; -} + for (auto key: toRemove) { + buffers.erase(key); + } -void releaseError(ErrorView** item) { - errorPool.push_back(*item); - (*item) = nullptr; - std::cout << std::format("Released, current pool size: {}\n", errorPool.size()); -} + MdemBuffer *buffer; + auto filename = getFilename(path); + if (currentMdem.compare(path) == 0) { + buffer = currentMdemBuffer; + currentMdem = path; + if (buffers.contains(path)) { + buffers.erase(path); + } + } else if (!buffers.contains(path)) { + buffer = new MdemBuffer; + buffers[path] = buffer; + currentMdemBuffer = buffer; + currentMdem = path; + } else { + buffer = buffers[path]; + currentMdemBuffer = buffer; + makePages(); + SwitchPage(0); + updateMdemInfo(getFilename(filename), buffer->isModified); + currentMdem = path; + errorView->box.hide(); + return; + } -void reloadMdem() { - auto file = std::ifstream(currentMdem); + auto file = std::ifstream(path); std::string content; // Reset the mdem list. for (auto mdem: mdems) { mdem->wMdem.hide(); } - for (auto question: mdemBuffer->questions) { + for (auto question: currentMdemBuffer->questions) { delete question; } - mdemBuffer->questions.clear(); - - auto filename = getFilename(currentMdem); + currentMdemBuffer->questions.clear(); if (file) { std::stringstream buffer; @@ -630,28 +629,20 @@ void reloadMdem() { content = buffer.str(); auto res = transpile(content, true); - while (errorViews.size() > 0) { - auto errorView = errorViews.back(); - errorViews.pop_back(); - errorView->box.hide(); - releaseError(&errorView); - } - + currentMdemBuffer->error = res.error.length() > 0; if (res.error == "") { if (res.value.lastTrainedAt == 0) { - mdemBuffer->trainedAt = 0; + currentMdemBuffer->trainedAt = 0; } else { auto timezoneOffset = settings->value("timezone").toInt(); - mdemBuffer->trainedAt = res.value.lastTrainedAt - 3600 * timezoneOffset; + currentMdemBuffer->trainedAt = res.value.lastTrainedAt - 3600 * timezoneOffset; } - std::cout << std::format("Last trained at: {}", mdemBuffer->trainedAt) << std::endl; + std::cout << std::format("Last trained at: {}", currentMdemBuffer->trainedAt) << std::endl; - mdemBuffer->questions = res.value.questions; - makePages(); - SwitchPage(0); - updateMdemInfo(filename, false); + currentMdemBuffer->questions = res.value.questions; + errorView->box.hide(); } else { - mdemBuffer->trainedAt = 0; + currentMdemBuffer->trainedAt = 0; std::cout << std::format("Compilation error: {}", res.error) << std::endl; for (auto question: res.value.questions) { @@ -660,7 +651,6 @@ void reloadMdem() { // Show errors. hMdemScroll->removeItem(mdemSpacer); - auto errorView = acquireError(); errorView->label.setText( QString::fromStdString( std::format( @@ -673,9 +663,13 @@ void reloadMdem() { ) ); errorView->box.show(); + hMdemScroll->addWidget(&errorView->box); hMdemScroll->addItem(mdemSpacer); } + makePages(); + SwitchPage(0); + updateMdemInfo(filename, false); } else { std::cout << std::format("Could not open the file: {}", currentPath) << std::endl; } @@ -703,14 +697,13 @@ void pickDirectory(QString directory) { ) )); - currentMdem = ""; - reloadMdem(); + reloadMdem(""); } void setupEditorSave() { auto res = transpile(editor->text().toStdString(), true); if (res.error.length() > 0) { - mdemBuffer->trainedAt = 0; + currentMdemBuffer->trainedAt = 0; for (auto question: res.value.questions) { delete question; } @@ -730,11 +723,11 @@ void setupEditorSave() { } else if (res.value.questions.size() == 1) { auto oldQuestion = editMdem->question; editMdem->question = res.value.questions[0]; - for (int i = 0; i < mdemBuffer->questions.size(); ++i) { - if (mdemBuffer->questions[i] == oldQuestion) { - mdemBuffer->questions.erase(mdemBuffer->questions.begin() + i); + for (int i = 0; i < currentMdemBuffer->questions.size(); ++i) { + if (currentMdemBuffer->questions[i] == oldQuestion) { + currentMdemBuffer->questions.erase(currentMdemBuffer->questions.begin() + i); delete oldQuestion; - mdemBuffer->questions.insert(mdemBuffer->questions.begin() + i, res.value.questions[0]); + currentMdemBuffer->questions.insert(currentMdemBuffer->questions.begin() + i, res.value.questions[0]); break; } } @@ -757,8 +750,8 @@ void setupEditorSave() { "There are no questions in your input." ); } else { - mdemBuffer->questions.insert( - mdemBuffer->questions.begin(), + currentMdemBuffer->questions.insert( + currentMdemBuffer->questions.begin(), res.value.questions.begin(), res.value.questions.end() ); @@ -774,12 +767,12 @@ void setupEditorSave() { void saveMdem() { auto filename = getFilename(currentMdem); std::ofstream out(currentMdem); - out << outputMdem(mdemBuffer->questions, mdemBuffer->trainedAt); + out << outputMdem(currentMdemBuffer->questions, currentMdemBuffer->trainedAt); updateMdemInfo(getFilename(currentMdem), false); } int main(int argc, char *argv[]) { - mdemBuffer = new MdemBuffer; + QApplication app(argc, argv); QMainWindow window; @@ -825,50 +818,60 @@ int main(int argc, char *argv[]) { auto formLayout = new QFormLayout; auto characterWrap = new QSpinBox; - characterWrap->setRange(50, 150); - formLayout->addRow("Character wrap in code gen:", characterWrap); + characterWrap->setRange(30, 150); + formLayout->addRow("Character wrap in code gen [30-150]:", characterWrap); auto* timezone = new QSpinBox; timezone->setRange(-12, 12); formLayout->addRow("Timezone as number (e.g. +2 as 2):", timezone); - auto* notRemembered = new QSpinBox; + auto* notRemembered = new QDoubleSpinBox; notRemembered->setRange(0, 100); formLayout->addRow("Not remembered:", notRemembered); - auto* hard = new QSpinBox; + auto* hard = new QDoubleSpinBox; hard->setRange(0, 100); formLayout->addRow("Hard:", hard); - auto* medium = new QSpinBox; + auto* medium = new QDoubleSpinBox; medium->setRange(0, 100); formLayout->addRow("Medium:", medium); - auto* easy = new QSpinBox; + auto* easy = new QDoubleSpinBox; easy->setRange(0, 100); formLayout->addRow("Easy:", easy); auto* btnSaveSettings = new QPushButton("Save"); auto* mainLayout = new QVBoxLayout; - // TODO: make defaults and validate settings values - characterWrap->setValue(settings->value("characterWrap").toInt()); - timezone->setValue(settings->value("timezone").toInt()); - notRemembered->setValue(settings->value("notRemembered").toInt()); - hard->setValue(settings->value("hard").toInt()); - medium->setValue(settings->value("medium").toInt()); - easy->setValue(settings->value("easy").toInt()); + // @Improve: validate setting values + characterWrap->setValue(settings->value(SETTING_CHARACTER_WRAP).toInt()); + timezone->setValue(settings->value(SETTING_TIMEZONE).toInt()); + notRemembered->setValue(settings->value(SETTING_NOT_REMEMBERED).toDouble()); + hard->setValue(settings->value(SETTING_HARD).toDouble()); + medium->setValue(settings->value(SETTING_MEDIUM).toDouble()); + easy->setValue(settings->value(SETTING_EASY).toDouble()); + + auto saveSettings = [characterWrap, timezone, notRemembered, hard, medium, easy]() { + settings->setValue(SETTING_CHARACTER_WRAP, characterWrap->value()); + settings->setValue(SETTING_TIMEZONE, timezone->value()); + settings->setValue(SETTING_NOT_REMEMBERED, notRemembered->value()); + settings->setValue(SETTING_HARD, hard->value()); + settings->setValue(SETTING_MEDIUM, medium->value()); + settings->setValue(SETTING_EASY, easy->value()); + }; QObject::connect( btnSaveSettings, &QPushButton::clicked, - [characterWrap, timezone, notRemembered, hard, medium, easy]() { - settings->setValue("characterWrap", characterWrap->value()); - settings->setValue("timezone", timezone->value()); - settings->setValue("notRemembered", notRemembered->value()); - settings->setValue("hard", hard->value()); - settings->setValue("medium", medium->value()); - settings->setValue("easy", easy->value()); + [saveSettings]() { + saveSettings(); + } + ); + + QShortcut* shortcutSave = new QShortcut(QKeySequence("Ctrl+S"), settingsWindow); + QObject::connect(shortcutSave, &QShortcut::activated, [saveSettings]() { + saveSettings(); }); mainLayout->addLayout(formLayout); @@ -947,8 +950,7 @@ int main(int argc, char *argv[]) { &QTreeView::doubleClicked, [](const QModelIndex &index) { auto fileInfo = model->fileInfo(index); - currentMdem = fileInfo.filePath().toStdString(); - reloadMdem(); + reloadMdem(fileInfo.filePath().toStdString()); } ); @@ -1020,7 +1022,9 @@ int main(int argc, char *argv[]) { editorWindow->show(); editor->setText(""); }); - QObject::connect(load, &QToolButton::clicked, &reloadMdem); + QObject::connect(load, &QToolButton::clicked, []() { + reloadMdem(currentMdem); + }); QObject::connect(btnSaveFile, &QToolButton::clicked, []() { saveMdem(); }); @@ -1031,13 +1035,30 @@ int main(int argc, char *argv[]) { trainWindow->show(); trainWindow->resize(600, 300); initiatePractice( - mdemBuffer, + currentMdemBuffer, static_cast(cbAlgorithm->currentData().toInt()) ); } ); } + { // Error. + errorView = new ErrorView; + errorView->box.setObjectName("error-box"); + errorView->box.setLayout(&errorView->layout); + errorView->box.setMinimumHeight(30); + errorView->box.setStyleSheet( + QString( + "QWidget#error-box {" + "border: 1px solid red;" + "background: %2;" + "}" + ).arg(MDEM_BACKGROUND) + ); + errorView->layout.addWidget(&errorView->label); + errorView->label.setWordWrap(true); + } + { // Mdems QScrollArea *mdemScroll = new QScrollArea(); QWidget *mdemContainer = new QWidget(); diff --git a/src/qtapp/trainWindow.cpp b/src/qtapp/trainWindow.cpp index 0a3d35e..40b5a75 100644 --- a/src/qtapp/trainWindow.cpp +++ b/src/qtapp/trainWindow.cpp @@ -231,7 +231,7 @@ QVBoxLayout *vGroups; std::vector groupModels; // Questions & State -MdemBuffer *currentBuffer; +MdemBuffer *practiceBuffer; int32_t currentQuestionIndex = -1; std::vector groupViews; @@ -318,15 +318,19 @@ void setupAnswerQuestion(MultiElementQuestion *question) { if (answerText->isVisible()) { answerText->hide(); } + + auto checkAnswerClicked = []() { + answerText->show(); + btnTriggerAnswer->hide(); + if (practiceAlgoritm == SPACED) { + showFeedBackButtons(); + } + }; QObject::connect( btnTriggerAnswer, &QToolButton::clicked, - [](bool checked) { - answerText->show(); - btnTriggerAnswer->hide(); - if (practiceAlgoritm == SPACED) { - showFeedBackButtons(); - } + [checkAnswerClicked](bool checked) { + checkAnswerClicked(); } ); btnTriggerAnswer->show(); @@ -533,7 +537,7 @@ void setupQuestion(Question *question) { } void updatePaginationVisibility() { - if (currentQuestionIndex == currentBuffer->questions.size() - 1) { + if (currentQuestionIndex == practiceBuffer->questions.size() - 1) { btnNext->hide(); } else { btnNext->show(); @@ -554,27 +558,27 @@ time_t getTime() { } void setupNextQuestion() { - if (currentBuffer->questions.size() <= 0) { + if (practiceBuffer->questions.size() <= 0) { return; } switch (practiceAlgoritm) { case PRIMARY: { currentQuestionIndex++; - if (currentQuestionIndex < currentBuffer->questions.size()) { - setupQuestion(currentBuffer->questions[currentQuestionIndex]); + if (currentQuestionIndex < practiceBuffer->questions.size()) { + setupQuestion(practiceBuffer->questions[currentQuestionIndex]); } updatePaginationVisibility(); } break; case RANDOM: { - auto questionCandidates = currentBuffer->questions; + auto questionCandidates = practiceBuffer->questions; if (currentQuestionIndex > -1) { questionCandidates.erase(questionCandidates.begin() + currentQuestionIndex); } if (questionCandidates.size() > 0) { auto i = randomIndex(&questionCandidates); setupQuestion(questionCandidates[i]); - for (int k = 0; k < currentBuffer->questions.size(); ++k) { - if (currentBuffer->questions[k] == questionCandidates[i]) { + for (int k = 0; k < practiceBuffer->questions.size(); ++k) { + if (practiceBuffer->questions[k] == questionCandidates[i]) { currentQuestionIndex = k; break; } @@ -584,27 +588,27 @@ void setupNextQuestion() { case SPACED: { auto questionCandidates = std::vector(); time_t time = getTime(); - auto lastTrainedAt = currentBuffer->trainedAt; - currentBuffer->trainedAt = time; - for (int i = 0; i < currentBuffer->questions.size(); ++i) { - auto cooldownSeconds = currentBuffer->questions[i]->Cooldown * 3600; + auto lastTrainedAt = practiceBuffer->trainedAt; + practiceBuffer->trainedAt = time; + for (int i = 0; i < practiceBuffer->questions.size(); ++i) { + auto cooldownSeconds = practiceBuffer->questions[i]->Cooldown * 3600; auto cooldownEndsAt = lastTrainedAt + cooldownSeconds; if (i != currentQuestionIndex && cooldownEndsAt <= time) { - questionCandidates.push_back(currentBuffer->questions[i]); + questionCandidates.push_back(practiceBuffer->questions[i]); } auto newCooldown = cooldownEndsAt - time; if (newCooldown < 0) { newCooldown = 0; } - currentBuffer->questions[i]->Cooldown = (double)newCooldown / 3600; + practiceBuffer->questions[i]->Cooldown = (double)newCooldown / 3600; } if (questionCandidates.size() > 0) { auto i = randomIndex(&questionCandidates); setupQuestion( questionCandidates[randomIndex(&questionCandidates)] ); - for (int k = 0; k < currentBuffer->questions.size(); ++k) { - if (currentBuffer->questions[k] == questionCandidates[i]) { + for (int k = 0; k < practiceBuffer->questions.size(); ++k) { + if (practiceBuffer->questions[k] == questionCandidates[i]) { currentQuestionIndex = k; break; } @@ -620,9 +624,9 @@ void initiatePractice( PracticeAlgorithm algorithm ) { practiceAlgoritm = algorithm; - currentBuffer = mdemBuffer; + practiceBuffer = mdemBuffer; - if (currentBuffer->questions.size() <= 0) { + if (practiceBuffer->questions.size() <= 0) { return; } @@ -632,10 +636,10 @@ void initiatePractice( setupNextQuestion(); } -void setCooldownHours(int cooldown) { +void setCooldownHours(double cooldown) { time_t time = getTime(); - currentBuffer->trainedAt = time; - auto question = currentBuffer->questions[currentQuestionIndex]; + practiceBuffer->trainedAt = time; + auto question = practiceBuffer->questions[currentQuestionIndex]; question->Cooldown = cooldown; update(true); } @@ -759,19 +763,39 @@ void initTrainWindow() { btnTriggerAnswer = new QToolButton(); btnNotRemembered = new QToolButton(); QObject::connect(btnNotRemembered, &QToolButton::clicked, []() { - setCooldownHours(0); + QString key = SETTING_NOT_REMEMBERED; + if (settings->contains(key)) { + setCooldownHours(settings->value(key).toDouble()); + } else { + setCooldownHours(0); + } }); btnHard = new QToolButton(); QObject::connect(btnHard, &QToolButton::clicked, []() { - setCooldownHours(12); + QString key = SETTING_HARD; + if (settings->contains(key)) { + setCooldownHours(settings->value(key).toDouble()); + } else { + setCooldownHours(12); + } }); btnMedium = new QToolButton(); QObject::connect(btnMedium, &QToolButton::clicked, []() { - setCooldownHours(48); + QString key = SETTING_MEDIUM; + if (settings->contains(key)) { + setCooldownHours(settings->value(key).toDouble()); + } else { + setCooldownHours(24); + } }); btnEasy = new QToolButton(); QObject::connect(btnEasy, &QToolButton::clicked, []() { - setCooldownHours(72); + QString key = SETTING_EASY; + if (settings->contains(key)) { + setCooldownHours(settings->value(key).toDouble()); + } else { + setCooldownHours(48); + } }); btnNotRemembered->setText("Not remembered"); btnHard->setText("Hard"); @@ -780,6 +804,11 @@ void initTrainWindow() { btnTriggerAnswer = new QToolButton(); + QShortcut* shortcutShowAnswer = new QShortcut(QKeySequence("Return"), trainWindow); + QObject::connect(shortcutShowAnswer, &QShortcut::activated, []() { + btnTriggerAnswer->click(); + }); + rightSpacer = new QSpacerItem(50, 50, QSizePolicy::Expanding, QSizePolicy::Minimum); btnNext = new QToolButton(); diff --git a/src/transpiler/parser.cpp b/src/transpiler/parser.cpp index 6a0d697..7985db3 100644 --- a/src/transpiler/parser.cpp +++ b/src/transpiler/parser.cpp @@ -152,7 +152,8 @@ time_t parseToUTCTime(const std::string datetime, std::string format) { return time; } - +// @Fix: Prevent duplicate group names and questions in ordered question (to +// simplify checking in practice). Result parseQuestions(const std::vector& tokens) { auto questions = std::vector(); time_t time = 0;