multiple improvements: multi-line buffering, editing interface

This commit is contained in:
jorenchik
2024-10-20 13:58:56 +03:00
parent 83e731e3de
commit b9a81b6484
4 changed files with 219 additions and 156 deletions

View File

@@ -1,16 +1,28 @@
#pragma once
#include <vector>
#include <QSettings>
#include "parser.h"
void update(bool isChanged = false);
void saveMdem();
struct MdemBuffer {
std::vector<Question*> questions = std::vector<Question*>();
time_t trainedAt = 0;
std::vector<Question*> questions = std::vector<Question*>();
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"

View File

@@ -3,6 +3,7 @@
#include <format>
#include <fstream>
#include <iostream>
#include <map>
#include <qabstractbutton.h>
#include <qboxlayout.h>
#include <qcombobox.h>
@@ -24,7 +25,6 @@
#include <Qsci/qsciscintilla.h>
#include <Qsci/qscilexercpp.h>
#include <QApplication>
#include <QMainWindow>
#include <QVBoxLayout>
@@ -53,6 +53,7 @@
#include <QLineEdit>
#include <QComboBox>
#include <QSpinBox>
#include <QDoubleSpinBox>
#include <QCheckBox>
#include <QPushButton>
#include <QStandardPaths>
@@ -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<std::string, MdemBuffer*> buffers;
MdemBuffer *currentMdemBuffer;
// Mdem scroll list.
QList<Mdem*> mdems = QList<Mdem*>();
QVBoxLayout *hMdemScroll;
QSpacerItem *mdemSpacer;
std::vector<ErrorView*> errorPool;
std::vector<ErrorView*> errorViews;
QList<Mdem*> mdems = QList<Mdem*>();
QVBoxLayout *hMdemScroll;
QSpacerItem *mdemSpacer;
ErrorView* errorView;
// Editor
Mdem* editMdem;
@@ -162,8 +160,13 @@ void showBacklabels(Mdem *mdem) {
std::string outputMdem(std::vector<Question*> 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<Question*> questions, time_t time = 0) {
std::format("-{}{} >\n",
cooldownPart,
" " + escapeText(question->QuestionText)),
WRAP_WIDTH
wrap_width
);
if (MultiElementQuestion* mw = dynamic_cast<MultiElementQuestion*>(question)) {
for (auto choice: mw->Choices) {
@@ -204,7 +207,7 @@ std::string outputMdem(std::vector<Question*> questions, time_t time = 0) {
orderModifier,
escapeText(choice.Answer)
)
, WRAP_WIDTH);
, wrap_width);
}
} else if (GroupQuestion* gq = dynamic_cast<GroupQuestion*>(question)) {
for (auto group: gq->Groups) {
@@ -213,14 +216,14 @@ std::string outputMdem(std::vector<Question*> 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<Question*> 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(&currentMdemBuffer->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<Question*> 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<std::string>();
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<PracticeAlgorithm>(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();

View File

@@ -231,7 +231,7 @@ QVBoxLayout *vGroups;
std::vector<QStandardItemModel*> groupModels;
// Questions & State
MdemBuffer *currentBuffer;
MdemBuffer *practiceBuffer;
int32_t currentQuestionIndex = -1;
std::vector<GroupView*> 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<Question*>();
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();

View File

@@ -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<ParseInfo> parseQuestions(const std::vector<Token>& tokens) {
auto questions = std::vector<Question*>();
time_t time = 0;