diff --git a/src/include/api.h b/src/include/api.h index 1b4851c..53c6608 100644 --- a/src/include/api.h +++ b/src/include/api.h @@ -8,7 +8,7 @@ Result transpile(std::string fileContent); std::string escapeText(std::string text); -std::string wrapText(std::string text, size_t width); +std::string wrapLine(std::string text, size_t width); extern std::chrono::high_resolution_clock::time_point start; diff --git a/src/qtapp/mdemList.cpp b/src/qtapp/mdemList.cpp index a17a1f1..96a7cec 100644 --- a/src/qtapp/mdemList.cpp +++ b/src/qtapp/mdemList.cpp @@ -73,7 +73,7 @@ #include "parser.h" #include "qscilexer.h" -// Memorybase. +// Atmiņas bāze. QString currentPath = ""; std::string currentMdem = ""; QFileSystemModel *model; @@ -81,7 +81,7 @@ QTreeView *mdemList; std::map buffers; MdemBuffer *currentMdemBuffer; -// Mdem list. +// Atmiņas kaartīšu saraksts. std::vector mdems = std::vector(); QVBoxLayout *hMdemScroll; QSpacerItem *mdemSpacer; @@ -89,17 +89,20 @@ ErrorView *errorView; Pagination *pagination; int perPage; -// Editor +// Redaktors. QsciScintilla *editor; QMainWindow *editorWindow; Mdem *editMdem; -// Top labels. -QLabel *membaseLabel; -QLabel *mdemLabel; -QLabel *lastPracticeLabel; -QMainWindow *trainWindow; +// Augšēja informācija. +QLabel *membaseLabel; +QLabel *mdemLabel; +QLabel *lastPracticeLabel; +QMainWindow *trainWindow; +/* + * Atmiņas kartītei parāda visus slēptos elementus. + * */ void showBacklabels(Mdem *mdem) { for (size_t i = 0; i < mdem->backLabels.size(); ++i) { if (i < mdem->labelCount) { @@ -114,14 +117,19 @@ void showBacklabels(Mdem *mdem) { } } +/* + * Izveido jautājuma kartīšu pirmkodu ar norādītu trenešanas laiku. + * Papildus konfigurācijai var norādīt platumu pirms jaunas rindas un laika zonu. + */ std::string outputMdem( std::vector questions, time_t time = 0, - const int wrap_width = 80, + const int wrapWidth = 80, const int timezoneOffset = 0 ) { std::stringstream ss; + // Ja ir saistīts laiks, ja tāds ir. if (time > 0) { std::tm* tm = std::localtime(&time); char buffer[100]; @@ -130,18 +138,25 @@ std::string outputMdem( ss << time << std::endl; } + // Detranspilē katru jautājumu. for (auto question: questions) { + + // Pārtraukums. ss << std::endl; std::string cooldownPart; if (question->cooldown != 0) { cooldownPart = std::format(" [{:.2f}]", question->cooldown); } - ss << wrapText( + + // Jautājuma teksts. + ss << wrapLine( std::format("-{}{} >\n", cooldownPart, " " + escapeText(question->questionText)), - wrap_width + wrapWidth ); + + // Detranspilē atbilstoši veidam. if (MultiElementQuestion* mw = dynamic_cast(question)) { for (auto choice: mw->choices) { char opener; @@ -155,30 +170,32 @@ std::string outputMdem( orderModifier = "^"; } ss << - wrapText( + wrapLine( std::format( "\t{}{} {}\n", opener, orderModifier, escapeText(choice.answer) ) - , wrap_width); + , wrapWidth); } + } else if (GroupQuestion* gq = dynamic_cast(question)) { + for (auto group: gq->groups) { - ss << wrapText( + ss << wrapLine( std::format( "\t- {}:\n", escapeText(group.name) ) - , wrap_width); + , wrapWidth); for (auto element: group.elements) { - ss << wrapText( + ss << wrapLine( std::format( "\t\t- {}\n", escapeText(element) ) - , wrap_width); + , wrapWidth); } } } @@ -186,14 +203,21 @@ std::string outputMdem( return ss.str(); } +/* + * Izveido lappušu objektus atbilstoši jautājumu skaitam vienā lapā. + * */ void makePages() { pagination->pages.clear(); auto len = currentMdemBuffer->questions.size(); perPage = settings->value(SETTING_PER_PAGE).toInt(); auto pageAmount = len / perPage; + + // Papildus lapa, ja objektu skaits nedalās tieši un paliek papildus kartītes. if (len % perPage != 0) { pageAmount += 1; } + + // Veido lappuses objektus. for (size_t i = 0; i < pageAmount; i++) { size_t startingIndex = perPage * i ; size_t amount = perPage; @@ -204,9 +228,20 @@ void makePages() { Page{startingIndex, startingIndex + amount} ); } + + // Ja tiek noņemts pēdējais lappuses elements, pārliek lappusi uz iepriekšējo. + if (pagination->pages.size() > 1 && pagination->currentPage >= pagination->pages.size()) { + --pagination->currentPage; + } } +/* + * Uzstāda atmiņas kartīti ar jebkura veida jautājuma. + * Uzstāda jautājuma tekstu un pievieno/uzstāda atbildes elementus. + * */ void setupMdem(Mdem *mdem, Question *question) { + + // Priekšas teksts. std::stringstream ss; if (question->cooldown > 0) { ss << std::format("[{:.2f}] ", question->cooldown); @@ -215,10 +250,15 @@ void setupMdem(Mdem *mdem, Question *question) { mdem->wFrontText.setText( QString::fromStdString(ss.str()) ); + if (MultiElementQuestion* mw = dynamic_cast(question)) { auto choices = mw->choices; + + // Pievieno vairākus elementus atbilstoši veidam. for (size_t k = 0; k < choices.size(); ++k) { auto answer = choices[k].answer; + + // Sagatavo elementu. switch (mw->type) { case MultiElementType::Order: answer = std::format("{}. {}", k + 1, answer); @@ -233,7 +273,9 @@ void setupMdem(Mdem *mdem, Question *question) { case MultiElementType::Regular: answer = std::format("- {}", answer); break; - } + } + + // Pievieno elementu. if (k < mdem->backLabels.size()) { mdem->backLabels[k]->setText(QString::fromStdString(answer)); } else { @@ -243,10 +285,13 @@ void setupMdem(Mdem *mdem, Question *question) { mdem->wBack.layout()->addWidget(label); } } + mdem->labelCount = choices.size(); } else if (GroupQuestion* mw = dynamic_cast(question)) { auto groups = mw->groups; std::vector elements; + + // Sagatovo grupas un elementus. for (size_t k = 0; k < groups.size(); ++k) { auto answer = groups[k].name; elements.push_back(std::format("- {}:", answer)); @@ -254,6 +299,8 @@ void setupMdem(Mdem *mdem, Question *question) { elements.push_back(std::format(" - {}", groups[k].elements[l])); } } + + // Pievieno grupas un elementus. for (size_t k = 0; k < elements.size(); ++k) { if (k < mdem->backLabels.size()) { mdem->backLabels[k]->setText(QString::fromStdString(elements[k])); @@ -264,12 +311,16 @@ void setupMdem(Mdem *mdem, Question *question) { mdem->wBack.layout()->addWidget(label); } } + mdem->labelCount = elements.size(); } } void switchPage(int pageIdx); +/* + * Iegūst faila nosaukumu no faila ceļa. + */ std::string getFilename(std::string path) { static const std::regex lastPathElementExp = std::regex("(.+\\/)*(.+)"); std::smatch matches; @@ -277,6 +328,9 @@ std::string getFilename(std::string path) { return matches[2].str(); } +/* + * Atjauno atmiņas kartīšu faila augšējo informāciju. + * */ void updateMdemInfo(std::string filename, bool isChanged) { currentMdemBuffer->isModified = isChanged; if (filename.length() > 0) { @@ -301,14 +355,16 @@ void updateMdemInfo(std::string filename, bool isChanged) { } } +/* + * Izveido atmiņas kartīti un visus tās elementus. + * */ Mdem* makeMdem() { auto mdem = new Mdem; mdem->wMdem.setLayout(&mdem->vMdem); - + + // Priekša. QString id = QString("mdem_%1").arg(1); mdem->wMdem.setObjectName(id); - - // Front mdem->wFront.setMinimumHeight(70); mdem->wFront.setLayout(&mdem->hFront); mdem->wFront.setProperty("first", "true"); @@ -324,7 +380,7 @@ Mdem* makeMdem() { "}" ).arg(id, MDEM_BACKGROUND)); - // Add Front Content + // Saturs. mdem->wFrontText.setWordWrap(true); mdem->wFrontText.setSizePolicy( QSizePolicy::Expanding, @@ -332,6 +388,7 @@ Mdem* makeMdem() { ); mdem->hFront.addWidget(&mdem->wFrontText); + // Rediģēšanas poga. mdem->editButton.setText("Rediģēt"); QObject::connect( &mdem->editButton, @@ -355,6 +412,7 @@ Mdem* makeMdem() { ); mdem->hFront.addWidget(&mdem->editButton); + // Dzēšanas poga. mdem->deleteButton.setText("Dzēst"); QObject::connect( &mdem->deleteButton, @@ -380,15 +438,12 @@ Mdem* makeMdem() { } ); mdem->hFront.addWidget(&mdem->deleteButton); - - mdem->toggleVisibility.setText("Parādīt"); - mdem->hFront.addWidget(&mdem->toggleVisibility); - // Back + // Aizmugura. mdem->wBack.setLayout(&mdem->hBack); mdem->vMdem.addWidget(&mdem->wBack); - // Add Back Content + // Aizmuguras saturs. for (size_t i = 0; i < 20; ++i) { // @Improve: back label pooling QLabel *elBackText = new QLabel(); @@ -404,7 +459,9 @@ Mdem* makeMdem() { mdem->wBack.hide(); mdem->wMdem.hide(); - // Connect button to toggle view + // Atbildes parādīšanas poga. + mdem->toggleVisibility.setText("Parādīt"); + mdem->hFront.addWidget(&mdem->toggleVisibility); QObject::connect(&mdem->toggleVisibility, &QToolButton::clicked, [mdem]() { if (mdem->wBack.isVisible()) { mdem->wBack.hide(); @@ -418,17 +475,22 @@ Mdem* makeMdem() { return mdem; } +/* + * Izveido rādāmās kartītes (argumentam nedrīkst pārniegt maksimāli iespējamo daudzumu lapā). + * */ +void createMdems(std::vector& questions) { -void CreateMdems(std::vector& questions) { hMdemScroll->removeItem(mdemSpacer); + // Paslēp visas atmiņas kartītes. for (Mdem *mdem : mdems) { if (mdem->wMdem.isVisible()) { mdem->wMdem.hide(); } } - perPage = settings->value(SETTING_PER_PAGE).toInt(); + // Pievieno atmiņas kartītes, ja nepieciešamais daudzums pārsniedz esošo. + perPage = settings->value(SETTING_PER_PAGE).toInt(); if (perPage > mdems.size()) { for (size_t i = mdems.size(); i < perPage; i++) { if (i >= mdems.size()) { @@ -439,6 +501,7 @@ void CreateMdems(std::vector& questions) { } } + // Parāda nepieciešamās atmiņas kartītes. for (size_t i = 0; i < questions.size(); ++i) { mdems[i]->question = questions[i]; setupMdem(mdems[i], questions[i]); @@ -450,6 +513,9 @@ void CreateMdems(std::vector& questions) { hMdemScroll->addItem(mdemSpacer); } +/* + * Atjauno sarakstu un tā informāciju. + */ void update(bool isChanged) { if (pagination->currentPage > -1) { switchPage(pagination->currentPage); @@ -460,9 +526,10 @@ void update(bool isChanged) { } void switchPage(int pageIdx) { + pagination->currentPage = pageIdx; - // Hide all pagination buttons + // Paslēp visas lappušu pogas. for (auto& button : pagination->paginationButtons) { button->hide(); } @@ -472,7 +539,7 @@ void switchPage(int pageIdx) { snprintf(buffer, sizeof(buffer), "Lappuse: %d", pageIdx + 1); pagination->paginationLabel.setText(buffer); - // Adjust mdem amount, hide widgets in mdems + // Paslēp atbilžu elementus. for (auto& mdem : mdems) { if (mdem->wBack.isVisible()) { mdem->wBack.hide(); @@ -480,7 +547,7 @@ void switchPage(int pageIdx) { } } - // Update pagination buttons + // Atjauno lappušu pogas. for (int k = -DISTANCE; k <= DISTANCE; ++k) { if (pageIdx + k >= 0 && pageIdx + k < pagination->pages.size()) { auto button = pagination->paginationButtons[l]; @@ -496,50 +563,51 @@ void switchPage(int pageIdx) { } } - // Handle first and last buttons + // Pirmās un pēdējās pogas redzamība. if (pageIdx > 0 && pagination->pages.size() > 1) { pagination->firstButton.show(); } else { pagination->firstButton.hide(); } - if (pageIdx < pagination->pages.size() - 1 && pagination->pages.size() > 1) { pagination->lastButton.show(); } else { pagination->lastButton.hide(); } - // Handle next and previous buttons - if (!pagination->pages.empty() && pagination->currentPage < pagination->pages.size() - 1) { - pagination->nextButton.show(); - } else { - pagination->nextButton.hide(); - } - + // Iepriekšējās pogas redzamība. if (!pagination->pages.empty() && pagination->currentPage >= 1) { pagination->prevButton.show(); } else { pagination->prevButton.hide(); } + // Nākamās pogas redzamība. + if (!pagination->pages.empty() && pagination->currentPage < pagination->pages.size() - 1) { + pagination->nextButton.show(); + } else { + pagination->nextButton.hide(); + } + Page page; + // Samazina lappuses numuru, ja pēdējai lappusei nepietiek atmiņas kartīšu. if (pagination->pages.size() <= 0) { + // Nav lapu -> veidojam tukšu lapu. page = Page(); } else if (pageIdx < pagination->pages.size()){ - page = pagination->pages[pageIdx]; + // Pieprasītā lapa eksistē -> atgriežam to. + page = pagination->pages[pageIdx]; } else { - if (pageIdx - 1 < pagination->pages.size()) { - page = pagination->pages[pageIdx -1]; - } else { - page = pagination->pages[0]; - } + // Pieprasītā lapa eksistē -> atgriežam iepriekšējo. + page = pagination->pages[pageIdx - 1]; } + // Izveido lappusi. std::vector pageSlice( currentMdemBuffer->questions.begin() + page.start, currentMdemBuffer->questions.begin() + page.end ); - CreateMdems(pageSlice); + createMdems(pageSlice); } void reloadMdem(std::string path) { @@ -586,7 +654,7 @@ void reloadMdem(std::string path) { auto file = std::ifstream(path); std::string content; - // Reset the mdem list. + // Atiestata atmiņas kartīšu sarakstu. for (auto mdem: mdems) { mdem->wMdem.hide(); } @@ -631,7 +699,7 @@ void reloadMdem(std::string path) { delete question; } - // Show errors. + // Parāda kļūdu. hMdemScroll->removeItem(mdemSpacer); errorView->label.setText( QString::fromStdString( @@ -680,7 +748,7 @@ void pickDirectory(QString directory) { currentPath = directory; - // Update tree view. + // Atjauno failu sarakstu. if (directory.length() <= 0) { membaseLabel->setText(directory); return; @@ -688,7 +756,7 @@ void pickDirectory(QString directory) { mdemList->setRootIndex(model->setRootPath(directory)); std::smatch matches; - // Update label. + // Atjauno teksta elementu. membaseLabel->setText(QString::fromStdString( std::format( "Atmiņas bāze: {}", @@ -794,17 +862,20 @@ void saveMdem() { } } +/* + * Inicializē visus atmiņas kartīšu saraksta elementus un izvēlni. + */ QMainWindow *initMdemListWindow() { QMainWindow* window = new QMainWindow; pagination = new Pagination; auto *toolbar = new Toolbar(); - // Setup the related windows. + // Saistīti logi. auto *settingsWindow = initSettings(); trainWindow = initTrainWindow(); QMainWindow *guideWindow = new QMainWindow; - { // Guide window. + { // Apmācības logs. auto guideWidget = new QWidget; auto *layout = new QVBoxLayout; auto *textBrowser = new QTextBrowser; @@ -818,13 +889,13 @@ QMainWindow *initMdemListWindow() { QAction *actionOpen; QAction *openSettings; QAction *actionHelp; - { // Menu bar. + { // Izvēlne. QMenuBar *menuBar = new QMenuBar; QFileDialog *fileDialog = new QFileDialog; QMenu *menu = new QMenu("Fails"); menu->setStyleSheet("font-size: 15px;"); - actionOpen = menu->addAction("Atvērt atmņas bāzi (Ctrl+O)"); + actionOpen = menu->addAction("Atvērt atmiņas bāzi (Ctrl+O)"); QObject::connect( actionOpen, &QAction::triggered, @@ -862,7 +933,7 @@ QMainWindow *initMdemListWindow() { window->setMenuBar(menuBar); } - { // Editor. + { // Redaktors. editorWindow = new QMainWindow; editorWindow->setWindowTitle("Jautājumu redaktors"); @@ -905,26 +976,26 @@ QMainWindow *initMdemListWindow() { } auto *wTop = new QWidget(); - { // Top. + { // Augša. - // Main top layout. + // Pamata augšējais izklājums. QHBoxLayout *hlTop = new QHBoxLayout(); wTop->setLayout(hlTop); - // Labels - auto *wLabels = new QWidget(); + // Teksta elementi. + auto *wLabels = new QWidget(); auto *vlLeftTop = new QVBoxLayout(); wLabels->setLayout(vlLeftTop); wLabels->setMinimumSize(0, 40); + // Atmiņas bāzes teksta elements. QString labelStyle = "font-size: 20px; font-weight: 400;"; - // Memorybase label. - membaseLabel = new QLabel(); + membaseLabel = new QLabel(); membaseLabel->setStyleSheet(labelStyle); vlLeftTop->addWidget(membaseLabel); - // Memorybase label. - mdemLabel = new QLabel(); + // Atmiņas kartīšu faila teksta elements. + mdemLabel = new QLabel(); mdemLabel->setStyleSheet(labelStyle); vlLeftTop->addWidget(mdemLabel); @@ -932,9 +1003,9 @@ QMainWindow *initMdemListWindow() { lastPracticeLabel->setStyleSheet(labelStyle); vlLeftTop->addWidget(lastPracticeLabel); - // Button layout. - auto buttons = new QWidget(); - auto vlButtons = new QVBoxLayout(); + // Pogu izklājums. + auto buttons = new QWidget(); + auto vlButtons = new QVBoxLayout(); buttons->setLayout(vlButtons); buttons->setStyleSheet("font-size: 15px;"); @@ -946,8 +1017,7 @@ QMainWindow *initMdemListWindow() { auto hlButtonsBottom = new QHBoxLayout(); buttonsBottom->setLayout(hlButtonsBottom); - // Define buttons. - + // Pogu definēšana. QObject::connect(&toolbar->btnAdd, &QToolButton::clicked, []() { editMdem = nullptr; editorWindow->show(); @@ -976,7 +1046,7 @@ QMainWindow *initMdemListWindow() { } ); - // Button content. + // Pogu saturs. toolbar->btnAdd.setText("Pievienot"); toolbar->btnSave.setText("Saglabāt"); toolbar->btnLoad.setText("Ielādēt"); @@ -987,7 +1057,7 @@ QMainWindow *initMdemListWindow() { toolbar->cbAlgorithm.addItem("Primārais", PRIMARY); toolbar->btnPractice.setText("Mācīties"); - // Add buttons. + // Pievieno pogas. hlButtonsTop->addWidget(&toolbar->btnAdd); hlButtonsTop->addWidget(&toolbar->btnSave); hlButtonsTop->addWidget(&toolbar->btnLoad); @@ -1008,8 +1078,8 @@ QMainWindow *initMdemListWindow() { hlTop->addWidget(buttons); } - QWidget *leftWidget = new QWidget(); - { // Left side. + QWidget *leftWidget = new QWidget(); + { // Kreisā puse. QVBoxLayout *leftLayout = new QVBoxLayout(); leftWidget->setLayout(leftLayout); @@ -1032,7 +1102,6 @@ QMainWindow *initMdemListWindow() { if (currentPath.size() > 0) { pickDirectory(currentPath); } - /*leftLayout->addWidget(leftTop);*/ QObject::connect( mdemList, @@ -1049,14 +1118,13 @@ QMainWindow *initMdemListWindow() { for (int col = 1; col < model->columnCount(); ++col) { mdemList->hideColumn(col); } - // TODO: name -> nosaukums in HEADER leftLayout->addWidget(mdemList); } auto wMain = new QWidget; auto *rightWidget = new QWidget(); auto *rightLayout = new QVBoxLayout(); - { // Main layout. + { // Pamata izklājums. auto vlMain = new QVBoxLayout; wMain->setLayout(vlMain); @@ -1072,7 +1140,7 @@ QMainWindow *initMdemListWindow() { vlMain->addWidget(hSplitter); } - { // Error. + { // Kļūda. errorView = new ErrorView; errorView->box.setObjectName("error-box"); errorView->box.setLayout(&errorView->layout); @@ -1089,7 +1157,7 @@ QMainWindow *initMdemListWindow() { errorView->label.setWordWrap(true); } - { // Mdems + { // Atmiņas kartītes. QScrollArea *mdemScroll = new QScrollArea(); QWidget *mdemContainer = new QWidget(); hMdemScroll = new QVBoxLayout(); @@ -1104,10 +1172,9 @@ QMainWindow *initMdemListWindow() { QSizePolicy::Minimum, QSizePolicy::Expanding ); - /*hMdemScroll->addItem(mdemSpacer);*/ } - { // Pagination + { // Lappušu pogas. auto wPagination = new QWidget(); auto hPagination = new QHBoxLayout(); @@ -1171,7 +1238,7 @@ QMainWindow *initMdemListWindow() { rightLayout->addWidget(wPagination); } - { // Setup shortcuts. + { // Uzstāda īsceļus. auto addShortcut = [window](QString key, std::function func) { QShortcut* shortcut = new QShortcut(QKeySequence(key), window); QObject::connect(shortcut, &QShortcut::activated, [func]() { diff --git a/src/qtapp/settings.cpp b/src/qtapp/settings.cpp index 1aa7193..d662208 100644 --- a/src/qtapp/settings.cpp +++ b/src/qtapp/settings.cpp @@ -63,19 +63,25 @@ QSettings *settings; +/* + * Inicializē uzstādījumu logu. + * */ QWidget *initSettings () { - QString configDir = QStandardPaths::writableLocation(QStandardPaths::AppConfigLocation); + + // Uzstādījumu fails - paņem standarta atrašanās vietu operētājsistēmā. + auto configDir = QStandardPaths::writableLocation(QStandardPaths::AppConfigLocation); QDir().mkpath(configDir); QString settingsFile = configDir + "/mdem.ini"; settings = new QSettings(settingsFile, QSettings::IniFormat); - auto* settingsWindow = new QWidget; + // Logs. + auto* settingsWindow = new QWidget; settingsWindow->setWindowTitle("Iestatījumi"); + // Augšējais izklājums. auto top = new QWidget; auto hlTop = new QVBoxLayout; top->setLayout(hlTop); - auto settingsLabel = new QLabel; settingsLabel->setText("Iestatījumi"); settingsLabel->setStyleSheet( @@ -83,62 +89,67 @@ QWidget *initSettings () { ); hlTop->addWidget(settingsLabel); + // Forma. auto wForm = new QWidget; auto formLayout = new QFormLayout; - wForm->setLayout(formLayout); auto mbaseInput = new QLineEdit; auto browseButton = new QPushButton("Izvēlēties"); auto pathLayout = new QHBoxLayout; + wForm->setLayout(formLayout); pathLayout->addWidget(mbaseInput); pathLayout->addWidget(browseButton); wForm->setStyleSheet("font-size: 15px;"); - formLayout->addRow("Noklusējuma memorybase:", pathLayout); - QObject::connect(browseButton, &QPushButton::clicked, [mbaseInput]() { - QString dir = QFileDialog::getExistingDirectory( - nullptr, - "Izvēlēties noklusēto direktoriju", - mbaseInput->text() - ); - if (!dir.isEmpty()) { - mbaseInput->setText(dir); - } - }); - + // Lauki. auto perPage = new QSpinBox; - perPage->setRange(5, 50); - formLayout->addRow("Mdems per page [5-50]:", perPage); - auto characterWrap = new QSpinBox; - characterWrap->setRange(30, 150); - formLayout->addRow("Rindas pārnešanas platums jautājumu teksta ģenerēšanā [30-150]:", characterWrap); - auto* timezone = new QSpinBox; - timezone->setRange(-12, 12); - formLayout->addRow("Laika zona (e.g. +2 as 2):", timezone); - auto* notRemembered = new QDoubleSpinBox; - notRemembered->setRange(0, 100); - formLayout->addRow("Neatcerējos:", notRemembered); - auto* hard = new QDoubleSpinBox; - hard->setRange(0, 100); - formLayout->addRow("Grūti:", hard); - auto* medium = new QDoubleSpinBox; - medium->setRange(0, 100); - formLayout->addRow("Vidēji:", medium); - auto* easy = new QDoubleSpinBox; - easy->setRange(0, 100); - formLayout->addRow("Viegli:", easy); - auto* debug = new QCheckBox; - formLayout->addRow("Atkļūdošana:", debug); - auto* showTimes = new QCheckBox; - formLayout->addRow("Rādīt laikus komandrindā:", showTimes); + { // Uzstāda uzstādījumu laukus. + formLayout->addRow("Noklusējuma atmiņas bāze:", pathLayout); + QObject::connect(browseButton, &QPushButton::clicked, [mbaseInput]() { + QString dir = QFileDialog::getExistingDirectory( + nullptr, + "Izvēlēties noklusēto direktoriju", + mbaseInput->text() + ); + if (!dir.isEmpty()) { + mbaseInput->setText(dir); + } + }); + perPage->setRange(5, 50); + formLayout->addRow("Mdems per page [5-50]:", perPage); + + characterWrap->setRange(30, 150); + formLayout->addRow("Rindas pārnešanas platums jautājumu teksta ģenerēšanā [30-150]:", characterWrap); + + timezone->setRange(-12, 12); + formLayout->addRow("Laika zona (e.g. +2 as 2):", timezone); + + notRemembered->setRange(0, 100); + formLayout->addRow("Neatcerējos:", notRemembered); + + hard->setRange(0, 100); + formLayout->addRow("Grūti:", hard); + + medium->setRange(0, 100); + formLayout->addRow("Vidēji:", medium); + + easy->setRange(0, 100); + formLayout->addRow("Viegli:", easy); + + formLayout->addRow("Atkļūdošana:", debug); + + formLayout->addRow("Rādīt laikus komandrindā:", showTimes); + } + + // Uzstādījumu pogas. auto wButtons = new QWidget; auto btnLayout = new QHBoxLayout; wButtons->setLayout(btnLayout); @@ -149,7 +160,7 @@ QWidget *initSettings () { btnLayout->addWidget(btnLoad); wButtons->setStyleSheet("font-size: 15px;"); - // @Improve: validate setting values + // Uzstāda lauku vērtības no uzstādījumu vērtībām. auto setSettingInputs = [ perPage, mbaseInput, @@ -174,6 +185,7 @@ QWidget *initSettings () { showTimes->setChecked(settings->value(SETTING_SHOW_TIMES).toBool() == true); }; + // Parāda izmaiņas indikatoru. auto updateSettingsLabel = [settingsLabel](bool isChanged) { if (isChanged) { settingsLabel->setText("Iestatījumi *"); @@ -182,6 +194,7 @@ QWidget *initSettings () { } }; + // Pievieno klausītāju atbilstoši izmantotam lauku tipam. auto attachChangeListener = [settingsLabel, updateSettingsLabel](QObject *input, QString key) { if (QLineEdit *lineInput = qobject_cast(input)) { QObject::connect( @@ -224,6 +237,7 @@ QWidget *initSettings () { } }; + // Izmaiņas laukos parāda indikatoros. attachChangeListener(perPage, SETTING_PER_PAGE); attachChangeListener(mbaseInput, SETTING_MEMORYBASE); attachChangeListener(characterWrap, SETTING_CHARACTER_WRAP); @@ -235,6 +249,7 @@ QWidget *initSettings () { attachChangeListener(debug, SETTING_DEBUG); attachChangeListener(showTimes, SETTING_SHOW_TIMES); + // Atjauno uzstādījumus no lauku vērtībām. auto saveSettings = [ perPage, mbaseInput, @@ -260,7 +275,6 @@ QWidget *initSettings () { settings->setValue(SETTING_SHOW_TIMES, showTimes->isChecked()); updateSettingsLabel(false); }; - auto loadSettings = [setSettingInputs, updateSettingsLabel]() { settings->sync(); setSettingInputs(); @@ -274,6 +288,17 @@ QWidget *initSettings () { saveSettings(); } ); + auto shortcutSave = new QShortcut( + QKeySequence("Ctrl+S"), + settingsWindow + ); + QObject::connect( + shortcutSave, + &QShortcut::activated, + [saveSettings]() { + saveSettings(); + } + ); QObject::connect( btnLoad, &QPushButton::clicked, @@ -283,11 +308,7 @@ QWidget *initSettings () { ); loadSettings(); - QShortcut* shortcutSave = new QShortcut(QKeySequence("Ctrl+S"), settingsWindow); - QObject::connect(shortcutSave, &QShortcut::activated, [saveSettings]() { - saveSettings(); - }); - + // Lai pogas ir lejā. auto spacer = new QSpacerItem( 50, 50, @@ -295,6 +316,7 @@ QWidget *initSettings () { QSizePolicy::Expanding ); + // Pievieno elementus. mainLayout->addWidget(top); mainLayout->addWidget(wForm); mainLayout->addItem(spacer); diff --git a/src/qtapp/trainWindow.cpp b/src/qtapp/trainWindow.cpp index 55da0e0..a2e9537 100644 --- a/src/qtapp/trainWindow.cpp +++ b/src/qtapp/trainWindow.cpp @@ -71,15 +71,23 @@ const QString buttonStyle = "font-size: 15px;" "}"; +/* + * Pielāgots sarakta elements, kam var uzstādīt sarkanu, zaļu vai neitrālu (pelēku) krāsu. + * */ class CustomItemDelegate : public QStyledItemDelegate { -public: - CustomItemDelegate(QObject *parent = nullptr) : QStyledItemDelegate(parent) {} - // Override the paint method to apply custom styling - void paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const override { +public: + CustomItemDelegate(QObject *parent = nullptr) + : QStyledItemDelegate(parent) {} + + void paint( + QPainter *painter, + const QStyleOptionViewItem &option, + const QModelIndex &index + ) const override { painter->save(); Qt::GlobalColor color; - auto colorIdx = index.data(Qt::UserRole + 1).toInt() ; + auto colorIdx = index.data(Qt::UserRole + 1).toInt(); switch (colorIdx) { case NEUTRAL: { color = Qt::lightGray; @@ -100,6 +108,9 @@ public: } }; +/* + * Saraksta skats, kas tiek izmantots vairāku elementu jautājumā. + */ class MultiChoiceListView : public QListView { Q_OBJECT @@ -114,6 +125,9 @@ public: } }; +/* + * Saraksta skats, kas tiek izmantots secības jautājumā. + */ class OrderListView : public QListView { Q_OBJECT @@ -133,6 +147,8 @@ protected: QModelIndex sourceIndex = currentIndex(); QModelIndex targetIndex = indexAt(event->pos()); + // Secības jautājumā, drag & drop var mainīt tikai secību -, + // novedot ar jautājumu uz otru jautājumu, tos pamaina vietām. if (sourceIndex.isValid() && targetIndex.isValid()) { QStandardItemModel *model = qobject_cast(this->model()); if (model) { @@ -148,6 +164,9 @@ protected: } }; +/* + * Saraksta skats, kas tiek izmantots grupēšanas jautājumā. + */ class MoveListView : public QListView { Q_OBJECT @@ -170,7 +189,9 @@ protected: void dragMoveEvent(QDragMoveEvent *event) override { event->acceptProposedAction(); } - + + // Ja elements pārvilkts uz šo sarakstu, + // tas tiks atvienots no sākotnējā skata un pievienots beigām. void dropEvent(QDropEvent *event) override { QListView *source = qobject_cast(event->source()); QStandardItemModel *sourceModel = qobject_cast(source->model()); @@ -185,6 +206,7 @@ protected: } }; +// Nepieciešams, lai klases strādātu. #include "trainWindow.moc" struct GroupView { @@ -196,19 +218,17 @@ struct GroupView { MoveListView itemList; }; -#define ITEM_POOL_CHUNK 200 - -// Main components -QWidget *trainWidget; -QVBoxLayout *vTrainWidget; +// Pamata komponentes +QWidget *trainWidget; +QVBoxLayout *vTrainWidget; CustomItemDelegate *itemDelegate; -// Question +// Jautājums. QWidget *questionBox; QVBoxLayout *vQuestionBox; QLabel *lQuestionText; -// Bottom buttons +// Apakšējās pogas. QVBoxLayout *vButtonBox; QWidget *actionButtons; QHBoxLayout *hButtons; @@ -218,18 +238,18 @@ QToolButton *btnShowAnswer; QSpacerItem *rightSpacer; QToolButton *btnNext; -// Answer question -QLabel *answerText; +// Atbildes jautājums. +QLabel *answerText; -// Multi-choice question +// Izvēles jautājums. QStandardItemModel *multiChoiceModel; QListView *multiChoiceList; -// Order question +// Secības jautājums. OrderListView *orderList; QStandardItemModel *orderModel; -// Group question +// Grupas jautājums. QStandardItemModel *groupItemModel; QListView *groupItemList; QWidget *wGroupQuestion; @@ -237,22 +257,28 @@ QVBoxLayout *vGroups; QSpacerItem *groupSpacer; std::vector groupModels; -// Questions & State +// Jautājumi un stāvokļa dati. MdemBuffer *practiceBuffer; - int32_t currentQuestionIndex = -1; std::vector groupViews; PracticeAlgorithm practiceAlgoritm; time_t lastTrainedAt; - -std::default_random_engine rng; std::vector itemPool; +std::default_random_engine rng; +// Intervālu izvēles pogas. QToolButton *btnNotRemembered; QToolButton *btnHard; QToolButton *btnMedium; QToolButton *btnEasy; +#define ITEM_POOL_CHUNK 200 +// Elementi no sarakstiem tiek +// pārizmantoti un pievienoti pēc pieprasījuma. + +/* + * Aizņemas elementu no pārizmantota saraksta, papildinot sarakstu, ja nepieciešams. + */ QStandardItem* acquireItem() { if (itemPool.size() <= 0) { for (size_t i = 0; i < ITEM_POOL_CHUNK; ++i) { @@ -264,11 +290,17 @@ QStandardItem* acquireItem() { return item; } +/* + * Atgriež elementu pārizmantotā sarakstā. + */ void releaseItem(QStandardItem** item) { itemPool.push_back(*item); (*item) = nullptr; } +/** + * Atgriež visus pārizmantotos elementus no saraksta modeļa. + */ auto releaseAllInModel(QStandardItemModel *model) { auto itemCount = model->rowCount(); for (size_t i = 0; i < itemCount; ++i) { @@ -278,6 +310,9 @@ auto releaseAllInModel(QStandardItemModel *model) { } }; +/** + * Atgriež visus pārizmantotos elementus no katra modeļa. + */ void releaseAllItems() { releaseAllInModel(multiChoiceModel); releaseAllInModel(groupItemModel); @@ -287,6 +322,10 @@ void releaseAllItems() { } } +/** + * Paslēp visus jautājumu specifiskus + * un pogu elementus, izņemot pogu Nākamais. + */ void hideQuestionElements() { lQuestionText->hide(); answerText->hide(); @@ -302,6 +341,9 @@ void hideQuestionElements() { btnShowAnswer->hide(); } +/* + * Parāda intervāla atbildes pogas. + */ void showFeedBackButtons() { btnNotRemembered->show(); btnHard->show(); @@ -309,11 +351,18 @@ void showFeedBackButtons() { btnEasy->show(); } +/* + * Uzstāda atbildes jautājumu mācīšanās procesā. + */ void setupAnswerQuestion(MultiElementQuestion *question) { + + // Jautājuma teksts. lQuestionText->setText( QString::fromStdString(question->questionText) ); lQuestionText->show(); + + // Formē atbildes elementu. auto ss = std::stringstream(); for (auto answerEl: question->choices) { ss << std::format("- {}", answerEl.answer) << std::endl; @@ -325,35 +374,39 @@ void setupAnswerQuestion(MultiElementQuestion *question) { answerText->hide(); } - auto checkAnswerClicked = []() { - answerText->show(); - btnCheck->hide(); - if (practiceAlgoritm == SPACED) { - showFeedBackButtons(); - } - }; - // Rāda tikai atbildes parādīšanas opciju. QObject::connect( btnShowAnswer, &QToolButton::clicked, - [checkAnswerClicked](bool checked) { - checkAnswerClicked(); + [](bool checked) { + answerText->show(); + // btnCheck->hide(); + if (practiceAlgoritm == SPACED) { + showFeedBackButtons(); + } btnShowAnswer->hide(); } ); btnShowAnswer->show(); } +/* + * Uzstāda secības jautājumu mācīšanās procesā. + */ void setupOrderQuestion(MultiElementQuestion *question) { + + // Jautājuma teksts. lQuestionText->setText( QString::fromStdString(question->questionText) ); lQuestionText->show(); + + // Secības jautājumam ir nepieciešami jautājumi nejaušā secībā. orderModel->clear(); auto shuffledAnswers = question->choices; std::shuffle(shuffledAnswers.begin(), shuffledAnswers.end(), rng); + // Pievieno secības elementus. auto addChoice = [](QStandardItem *item, std::string text) { item->setData(QVariant(), Qt::CheckStateRole); item->setCheckable(false); @@ -365,12 +418,15 @@ void setupOrderQuestion(MultiElementQuestion *question) { addChoice(item, answerEl.answer); item->setData(NEUTRAL, Qt::UserRole + 1); } - orderList->show(); + + // Pārbaudes poga. QObject::connect( btnCheck, &QToolButton::clicked, [question](bool checked) { + + // Salīdzina atbildes pēc atbildes satura. for (size_t i = 0; i < orderModel->rowCount(); ++i) { auto item = orderModel->item(i, 0); auto text = item->text(); @@ -390,12 +446,14 @@ void setupOrderQuestion(MultiElementQuestion *question) { } } ); - btnCheck->show(); + // Pareizās atbildes poga. + btnCheck->show(); QObject::connect( btnShowAnswer, &QToolButton::clicked, [question](bool checked) { + // Salīdzina atbildes pēc atbildes satura. for (size_t i = 0; i < question->choices.size(); ++i) { auto item = orderModel->item(i, 0); auto choice = question->choices[i]; @@ -408,12 +466,18 @@ void setupOrderQuestion(MultiElementQuestion *question) { ); } +/* + * Uzstāda vairāku elementu jautājumu mācīšanās procesā. + */ void setupMultiChoiceQuestion(MultiElementQuestion *question) { + + // Jautājuma teksts. lQuestionText->setText( QString::fromStdString(question->questionText) ); lQuestionText->show(); + // Pievieno izvēles elementus. multiChoiceModel->clear(); for (auto answerEl: question->choices) { auto *item = acquireItem(); @@ -425,11 +489,14 @@ void setupMultiChoiceQuestion(MultiElementQuestion *question) { } multiChoiceList->show(); + // Rāda tikai pārbaudes opciju, jo izvēles jautājumam + // atbildi var saprast jau pēc pārbaudes. QObject::connect( btnCheck, &QToolButton::clicked, [question](bool checked) { for (size_t i = 0; i < multiChoiceModel->rowCount(); ++i) { + // Elementu secība nav mainīta -> skatās pareizumu pēc pozīcijas. auto item = multiChoiceModel->item(i, 0); auto isCorrect = question->choices[i].isCorrect == (item->checkState() == Qt::Checked); if (isCorrect) { @@ -437,6 +504,8 @@ void setupMultiChoiceQuestion(MultiElementQuestion *question) { } else { item->setData(INCORRECT, Qt::UserRole + 1); } + + // Jāatjauno saraksts, lai atjaunotos elementu krāsa. multiChoiceList->update(); } btnCheck->hide(); @@ -448,15 +517,22 @@ void setupMultiChoiceQuestion(MultiElementQuestion *question) { btnCheck->show(); } +/* + * Uzstāda grupēšanas jautājumu mācīšanās procesā. + */ void setupGroupQuestion(GroupQuestion *question) { + + // Noņem tieši sākumā, lai pēc tam to pieliktu. vGroups->removeItem(groupSpacer); + // Jautājuma teksts. lQuestionText->setText( QString::fromStdString(question->questionText) ); lQuestionText->show(); - wGroupQuestion->show(); + // Ieliek nesagrupētos elementus. + wGroupQuestion->show(); for (auto group: question->groups) { for (auto itemText: group.elements) { auto *qItem = acquireItem(); @@ -469,51 +545,64 @@ void setupGroupQuestion(GroupQuestion *question) { } groupItemList->update(); - auto makeGroup = []() { - auto groupView = new GroupView; - vGroups->addWidget(&groupView->label); - vGroups->addWidget(&groupView->itemList); - groupView->itemList.setModel(&groupView->itemModel); - groupView->itemList.setMaximumHeight(100); - groupView->itemList.setItemDelegate(itemDelegate); - groupView->widget.setLayout(&groupView->vWidget); - groupView->widget.layout()->addWidget(&groupView->label); - groupView->widget.layout()->addWidget(&groupView->itemList); - return groupView; - }; - - for (int k = 0; k < groupViews.size(); k++) { - groupViews[k]->widget.hide(); - } - for (size_t i = 0; i < question->groups.size(); i++) { - GroupView *groupView; - if (i < groupViews.size()) { - groupView = groupViews[i]; - } else { - groupView = makeGroup(); - groupViews.push_back(groupView); + { // Uzstāda grupu sarakstus, kur lietotājs pārliek elementus; + + // Paslēp visas grupas. + for (int k = 0; k < groupViews.size(); k++) { + groupViews[k]->widget.hide(); } - groupView->label.setText( - QString::fromStdString( - question->groups[i].name - ) - ); - vGroups->addWidget(&groupView->widget); - groupView->widget.show(); - } - vGroups->addItem(groupSpacer); + // Izveido grupas sarakstus, ja nepietiek jau esošo. + auto makeGroup = []() { + auto groupView = new GroupView; + vGroups->addWidget(&groupView->label); + vGroups->addWidget(&groupView->itemList); + groupView->itemList.setModel(&groupView->itemModel); + groupView->itemList.setMaximumHeight(100); + groupView->itemList.setItemDelegate(itemDelegate); + groupView->widget.setLayout(&groupView->vWidget); + groupView->widget.layout()->addWidget(&groupView->label); + groupView->widget.layout()->addWidget(&groupView->itemList); + return groupView; + }; + for (size_t i = 0; i < question->groups.size(); i++) { + GroupView *groupView; + if (i < groupViews.size()) { + groupView = groupViews[i]; + } else { + groupView = makeGroup(); + groupViews.push_back(groupView); + } + groupView->label.setText( + QString::fromStdString( + question->groups[i].name + ) + ); + vGroups->addWidget(&groupView->widget); + groupView->widget.show(); + } + vGroups->addItem(groupSpacer); + } + + // Pārbaudes poga. QObject::connect( btnCheck, &QToolButton::clicked, [question](bool checked) { + + // Katrs nesagrupēts -> nepareizs. for (size_t i = 0; i < groupItemModel->rowCount(); ++i) { auto item = groupItemModel->item(i, 0); item->setData(INCORRECT, Qt::UserRole + 1); } + + // Pārbauda elementus katrai grupai. for (size_t i = 0; i < question->groups.size(); i++) { auto groupView = groupViews[i]; auto group = question->groups[i]; + + // Ja pārnestā saraksta grupā elements ir atrasts atbilstošā grupā, + // tas ir pareizs, citādi - nepareizs. for (int j = 0; j < groupView->itemModel.rowCount(); ++j) { auto item = groupView->itemModel.item(j, 0); auto itemText = item->text().toStdString(); @@ -542,15 +631,20 @@ void setupGroupQuestion(GroupQuestion *question) { ); btnCheck->show(); + // Atbildes parādīšanas poga. QObject::connect( btnShowAnswer, &QToolButton::clicked, [question](bool checked) { + + // Vienkāršuma pēc atgriežam visus elementus. releaseAllInModel(groupItemModel); for (size_t i = 0; i < question->groups.size(); i++) { auto groupView = groupViews[i]; auto group = question->groups[i]; releaseAllInModel(&groupView->itemModel); + + // Pievienojam elementus atbilstošiem sarakstam. for (int j = 0; j < group.elements.size(); ++j) { auto *qItem = acquireItem(); auto groupElement = group.elements[j]; @@ -561,8 +655,8 @@ void setupGroupQuestion(GroupQuestion *question) { groupView->itemModel.appendRow(qItem); } } - btnShowAnswer->hide(); + if (practiceAlgoritm == SPACED) { showFeedBackButtons(); } @@ -570,11 +664,18 @@ void setupGroupQuestion(GroupQuestion *question) { ); } +/* + * Uzstāda jebkura veida jautājumu mācīšanās procesā. + */ void setupQuestion(Question *question) { + + // Atiestata jautājuma skatu jautājuma uzstādīšanai. hideQuestionElements(); releaseAllItems(); QObject::disconnect(btnShowAnswer, 0, 0, 0); QObject::disconnect(btnCheck, 0, 0, 0); + + // Izsauc atbilstošu f-ju jautājuma tipam. if (auto *q = dynamic_cast(question)) { switch (q->type) { case MultiElementType::Order: @@ -587,14 +688,15 @@ void setupQuestion(Question *question) { setupAnswerQuestion(q); break; } - } else if ( - auto *q = dynamic_cast(question) - ) { + } else if (auto *q = dynamic_cast(question)) { setupGroupQuestion(q); } } -void updatePaginationVisibility() { +/* + * Parāda/paslēp nākamā jautājuma pogu. + * */ +void updateNextButtonPrimary() { if (currentQuestionIndex == practiceBuffer->questions.size() - 1) { btnNext->hide(); } else { @@ -602,12 +704,18 @@ void updatePaginationVisibility() { } } +/* + * Nejaušs indekss vektorā. + * */ template int randomIndex(std::vector *vec) { srand(time(NULL)); return rand() % vec->size(); } +/* + * Iegūst UNIX epoch laiku. + * */ time_t getTime() { auto now = std::chrono::system_clock::now(); return std::chrono::duration_cast( @@ -615,85 +723,105 @@ time_t getTime() { ).count(); } +/* + * Uzstāda nākamo jautajumu atbilstoši algoritmam. + */ void setupNextQuestion() { if (practiceBuffer->questions.size() <= 0) { return; } switch (practiceAlgoritm) { case PRIMARY: { - currentQuestionIndex++; - if (currentQuestionIndex < practiceBuffer->questions.size()) { - setupQuestion(practiceBuffer->questions[currentQuestionIndex]); - } - updatePaginationVisibility(); + // Uzstāda nākamo pēc indeksa. + currentQuestionIndex++; + if (currentQuestionIndex < practiceBuffer->questions.size()) { + setupQuestion(practiceBuffer->questions[currentQuestionIndex]); + } + updateNextButtonPrimary(); } break; case RANDOM: { - 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 < practiceBuffer->questions.size(); ++k) { - if (practiceBuffer->questions[k] == questionCandidates[i]) { - currentQuestionIndex = k; - break; - } + + // Iegūst kandidātus - visi jautājumi, izņemot tagadējo. + auto questionCandidates = practiceBuffer->questions; + if (currentQuestionIndex > -1) { + questionCandidates.erase(questionCandidates.begin() + currentQuestionIndex); + } + + // Iegūst nejaušo jautājumu. + if (questionCandidates.size() > 0) { + auto i = randomIndex(&questionCandidates); + setupQuestion(questionCandidates[i]); + for (int k = 0; k < practiceBuffer->questions.size(); ++k) { + if (practiceBuffer->questions[k] == questionCandidates[i]) { + currentQuestionIndex = k; + break; } } + } } break; case SPACED: { - auto questionCandidates = std::vector(); - time_t time = getTime(); - auto lastTrainedAt = practiceBuffer->trainedAt; - practiceBuffer->trainedAt = time; - for (size_t 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(practiceBuffer->questions[i]); - } - auto newCooldown = cooldownEndsAt - time; - if (newCooldown < 0) { - newCooldown = 0; - } - practiceBuffer->questions[i]->cooldown = (double)newCooldown / 3600; + + // Iegūst kandidātus - jautājumi (izņemot tagadējo), kam ir pagājis pārtraukums, vai kam tā nav. + // Noteikšanas laikā atjauno pārtraukuma skaitli, balstoties uz tagadējo laiku. + auto questionCandidates = std::vector(); + time_t time = getTime(); + auto lastTrainedAt = practiceBuffer->trainedAt; + practiceBuffer->trainedAt = time; + for (size_t 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(practiceBuffer->questions[i]); } - if (questionCandidates.size() > 0) { - auto i = randomIndex(&questionCandidates); - setupQuestion( - questionCandidates[randomIndex(&questionCandidates)] - ); - for (int k = 0; k < practiceBuffer->questions.size(); ++k) { - if (practiceBuffer->questions[k] == questionCandidates[i]) { - currentQuestionIndex = k; - break; - } + auto newCooldown = cooldownEndsAt - time; + if (newCooldown < 0) { + newCooldown = 0; + } + practiceBuffer->questions[i]->cooldown = (double)newCooldown / 3600; + } + + // Ja kandidāti eksistē, izvēlas nejaušo. + if (questionCandidates.size() > 0) { + auto i = randomIndex(&questionCandidates); + setupQuestion( + questionCandidates[randomIndex(&questionCandidates)] + ); + for (int k = 0; k < practiceBuffer->questions.size(); ++k) { + if (practiceBuffer->questions[k] == questionCandidates[i]) { + currentQuestionIndex = k; + break; } } - update(true); + } + + // Ir jāatjauno atmiņas kartīšu skats, + // jo ir potenciāli izmainīti pārtraukumi. + update(true); } break; } } +/* + * Iesāk mācīšanos ar padotiem jautājumiem un algoritmu. + * */ void initiatePractice( MdemBuffer *mdemBuffer, PracticeAlgorithm algorithm ) { practiceAlgoritm = algorithm; practiceBuffer = mdemBuffer; - if (practiceBuffer->questions.size() <= 0) { return; } - currentQuestionIndex = -1; hideQuestionElements(); - updatePaginationVisibility(); + updateNextButtonPrimary(); setupNextQuestion(); } +/* + * Uzstāda tagadējā jautājuma pārtraukumu. + */ void setCooldownHours(double cooldown) { time_t time = getTime(); practiceBuffer->trainedAt = time; @@ -702,22 +830,30 @@ void setCooldownHours(double cooldown) { update(true); } +/* + * Inicializē mācīšanās logu. + * */ QMainWindow *initTrainWindow() { + + // Inicializē RNG nejaušiem jautājumiem. unsigned seed = std::chrono::system_clock::now().time_since_epoch().count(); rng = std::default_random_engine(seed); auto trainWindow = new QMainWindow(); - trainWidget = new QWidget(); - vTrainWidget = new QVBoxLayout(); - - trainWidget->setLayout(vTrainWidget); - trainWindow->setCentralWidget(trainWidget); - trainWidget->setLayout(vTrainWidget); - vTrainWidget->setAlignment(Qt::AlignCenter); - trainWidget->setObjectName("answer-question-widget"); + { // Mācīšanās komponente. + trainWidget = new QWidget(); + vTrainWidget = new QVBoxLayout(); + trainWidget->setLayout(vTrainWidget); + trainWindow->setCentralWidget(trainWidget); + trainWidget->setLayout(vTrainWidget); + vTrainWidget->setAlignment(Qt::AlignCenter); + trainWidget->setObjectName("answer-question-widget"); + } + // Pārizmantots elementu delegāts. itemDelegate = new CustomItemDelegate(multiChoiceList); + // Pievieno īsceļu ar doto f-ju. auto addShortcut = [trainWindow](QString key, std::function func) { QShortcut* shortcut = new QShortcut(QKeySequence(key), trainWindow); QObject::connect(shortcut, &QShortcut::activated, [func]() { @@ -725,42 +861,55 @@ QMainWindow *initTrainWindow() { }); }; - { // Top button menu. + { // Augšējā pogu izvēlne. + + // Izklājums. auto hTopButtons = new QHBoxLayout(); auto topButtons = new QWidget(); topButtons->setStyleSheet(buttonStyle); topButtons->setLayout(hTopButtons); - auto topLeftSpacer = new QSpacerItem(50, 50, QSizePolicy::Expanding, QSizePolicy::Minimum); + // Starplika, lai poga parādās labā pusē. + auto topLeftSpacer = new QSpacerItem( + 50, + 50, + QSizePolicy::Expanding, + QSizePolicy::Minimum + ); + hTopButtons->addItem(topLeftSpacer); + + // Saglabāšanas poga. auto btnSaveProgress = new QToolButton(); btnSaveProgress->setText("Saglabāt progresu"); - - hTopButtons->addItem(topLeftSpacer); - hTopButtons->addWidget(btnSaveProgress); - vTrainWidget->addWidget(topButtons); - QObject::connect(btnSaveProgress, &QToolButton::clicked, []() { saveMdem(); }); + addShortcut( + "Ctrl+S", + []() { + saveMdem(); + } + ); + hTopButtons->addWidget(btnSaveProgress); - QShortcut* shortcutSaveProgress = new QShortcut(QKeySequence("Ctrl+S"), trainWindow); - QObject::connect(shortcutSaveProgress, &QShortcut::activated, []() { - saveMdem(); - }); + vTrainWidget->addWidget(topButtons); } - { // Make the question box. - questionBox = new QWidget(); + { // Jautājuma box. + questionBox = new QWidget(); questionBox->setStyleSheet( "font-size: 15px;" ); - vQuestionBox = new QVBoxLayout(); + vQuestionBox = new QVBoxLayout(); questionBox->setLayout(vQuestionBox); - questionBox->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Expanding); + questionBox->setSizePolicy( + QSizePolicy::Minimum, + QSizePolicy::Expanding + ); vQuestionBox->setAlignment(Qt::AlignCenter); } - { // Make question text. + { // Jautājuma teksts. lQuestionText = new QLabel(); lQuestionText->setWordWrap(true); lQuestionText->setStyleSheet(QString( @@ -773,7 +922,7 @@ QMainWindow *initTrainWindow() { lQuestionText->hide(); } - { // Make multi-choice list. + { // Izvēles saraksts. multiChoiceModel = new QStandardItemModel(); multiChoiceList = new MultiChoiceListView(); multiChoiceList->setModel(multiChoiceModel); @@ -783,7 +932,7 @@ QMainWindow *initTrainWindow() { multiChoiceList->setItemDelegate(itemDelegate); } - { // Make answer text. + { // Atbildes teksts. answerText = new QLabel(); answerText->setWordWrap(true); answerText->setStyleSheet(QString( @@ -796,33 +945,63 @@ QMainWindow *initTrainWindow() { answerText->hide(); } - { // Make order list. + { // Secības jautājums. orderModel = new QStandardItemModel(); orderList = new OrderListView(); orderList->setModel(orderModel); orderList->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Minimum); orderList->setItemDelegate(itemDelegate); - - // Connect to handle the drop event properly - QObject::connect( - orderModel, - &QStandardItemModel::rowsMoved, - [](const QModelIndex &, int sourceRow, int, const QModelIndex &, int destinationRow) { - if (sourceRow != destinationRow - 1) { - auto *movedItem = orderModel->takeItem(sourceRow); - orderModel->insertRow(destinationRow > sourceRow ? destinationRow - 1 : destinationRow, movedItem); - } - } - ); - questionBox->layout()->addWidget(orderList); orderList->hide(); } - { // Make buttons menu. There are left middle and right buttons. + { // Grupēšanas jautājums. + + // Izklājums. + wGroupQuestion = new QWidget(); + wGroupQuestion->setStyleSheet( + "border:none;" + ); + auto hGroupQuestion = new QHBoxLayout(); + groupSpacer = new QSpacerItem( + 50, 50, + QSizePolicy::Minimum, + QSizePolicy::Expanding + ); + wGroupQuestion->setLayout(hGroupQuestion); + wGroupQuestion->setStyleSheet("padding: 0; margin: 0;"); + wGroupQuestion->hide(); + + // Kreisais saraksts. + auto itemScroll = new QScrollArea(); + auto vItems = new QVBoxLayout(); + itemScroll->setLayout(vItems); + groupItemModel = new QStandardItemModel(); + groupItemList = new MoveListView(); + groupItemList->setItemDelegate(itemDelegate); + groupItemList->setModel(groupItemModel); + vItems->addWidget(groupItemList); + hGroupQuestion->addWidget(itemScroll); + + // Labais saraksts. + auto groupScroll = new QScrollArea(); + auto wGroupContainer = new QWidget(); + vGroups = new QVBoxLayout(); + groupScroll->setWidget(wGroupContainer); + groupScroll->setWidgetResizable(true); + wGroupContainer->setLayout(vGroups); + hGroupQuestion->addWidget(groupScroll); + + questionBox->layout()->addWidget(wGroupQuestion); + } + + { // Lejas pogu izvēlne - ir centra un labās puses pogas. + + // Pamata elementi. vButtonBox = new QVBoxLayout(); actionButtons = new QWidget(); hButtons = new QHBoxLayout(); + leftSpacer = new QSpacerItem( 50, 50, @@ -830,7 +1009,8 @@ QMainWindow *initTrainWindow() { QSizePolicy::Minimum ); - btnCheck = new QToolButton(); + // Intervālu pogām uzstāda pārtraukumu no uzstādījumiem vai noklusējuma + // vērtību, ja nav norādīts. btnNotRemembered = new QToolButton(); QObject::connect(btnNotRemembered, &QToolButton::clicked, []() { QString key = SETTING_NOT_REMEMBERED; @@ -849,7 +1029,7 @@ QMainWindow *initTrainWindow() { setCooldownHours(12); } }); - btnMedium = new QToolButton(); + btnMedium = new QToolButton(); QObject::connect(btnMedium, &QToolButton::clicked, []() { QString key = SETTING_MEDIUM; if (settings->contains(key)) { @@ -858,7 +1038,7 @@ QMainWindow *initTrainWindow() { setCooldownHours(24); } }); - btnEasy = new QToolButton(); + btnEasy = new QToolButton(); QObject::connect(btnEasy, &QToolButton::clicked, []() { QString key = SETTING_EASY; if (settings->contains(key)) { @@ -867,6 +1047,8 @@ QMainWindow *initTrainWindow() { setCooldownHours(48); } }); + + // Intervālu pogu teksti un īsceļi. btnNotRemembered->setText("Neatcerējos (Z)"); addShortcut("Z", []() { if (btnNotRemembered->isVisible()) { @@ -892,21 +1074,44 @@ QMainWindow *initTrainWindow() { } }); + // Kontroles pogas. btnCheck = new QToolButton(); - QShortcut* shortcutCheck = new QShortcut(QKeySequence("Return"), trainWindow); - QObject::connect(shortcutCheck, &QShortcut::activated, []() { - btnCheck->click(); - }); - btnShowAnswer = new QToolButton(); - QShortcut* shortcutShowAnswer = new QShortcut(QKeySequence("Return"), trainWindow); - QObject::connect(shortcutShowAnswer, &QShortcut::activated, []() { - btnShowAnswer->click(); + btnCheck->setText("Pārbaudīt atbildi"); + btnShowAnswer->setText("Parādīt atbildi"); + addShortcut( + "Return", + []() { + if (btnCheck->isVisible()) { + btnCheck->click(); + } + if (btnShowAnswer->isVisible()) { + btnShowAnswer->click(); + } + } + ); + btnCheck->hide(); + btnShowAnswer->hide(); + + // Nākamāis poga. + rightSpacer = new QSpacerItem( + 50, + 50, + QSizePolicy::Expanding, + QSizePolicy::Minimum + ); + btnNext = new QToolButton(); + btnNext->setText("Nākamais"); + QObject::connect(btnNext, &QToolButton::clicked, []() { + setupNextQuestion(); + }); + addShortcut("l", []() { + if (btnNext->isVisible()) { + btnNext->click(); + } }); - rightSpacer = new QSpacerItem(50, 50, QSizePolicy::Expanding, QSizePolicy::Minimum); - btnNext = new QToolButton(); - + // Pievieno pogas. hButtons->addItem(leftSpacer); hButtons->addWidget(btnCheck); hButtons->addWidget(btnShowAnswer); @@ -914,71 +1119,16 @@ QMainWindow *initTrainWindow() { hButtons->addWidget(btnHard); hButtons->addWidget(btnMedium); hButtons->addWidget(btnEasy); - hButtons->addItem(rightSpacer); hButtons->addWidget(btnNext); vButtonBox->addWidget(actionButtons); actionButtons->setLayout(hButtons); - btnCheck->setText("Pārbaudīt atbildi"); - btnShowAnswer->setText("Parādīt atbildi"); - btnCheck->hide(); - btnShowAnswer->hide(); - - btnNext->setText("Nākamais"); - QObject::connect(btnNext, &QToolButton::clicked, []() { - setupNextQuestion(); - }); questionBox->setObjectName("question-box"); actionButtons->setStyleSheet(buttonStyle); } - { // Make group question view. - wGroupQuestion = new QWidget(); - wGroupQuestion->setStyleSheet( - "border:none;" - ); - auto hGroupQuestion = new QHBoxLayout(); - groupSpacer = new QSpacerItem( - 50, 50, - QSizePolicy::Minimum, - QSizePolicy::Expanding - ); - wGroupQuestion->setLayout(hGroupQuestion); - - - // Items on the left. - auto itemScroll = new QScrollArea(); - auto vItems = new QVBoxLayout(); - itemScroll->setLayout(vItems); - groupItemModel = new QStandardItemModel(); - groupItemList = new MoveListView(); - groupItemList->setItemDelegate(itemDelegate); - groupItemList->setModel(groupItemModel); - vItems->addWidget(groupItemList); - hGroupQuestion->addWidget(itemScroll); - - // Items on the right. - auto groupScroll = new QScrollArea(); - auto wGroupContainer = new QWidget(); - vGroups = new QVBoxLayout(); - groupScroll->setWidget(wGroupContainer); - groupScroll->setWidgetResizable(true); - wGroupContainer->setLayout(vGroups); - hGroupQuestion->addWidget(groupScroll); - - - wGroupQuestion->setStyleSheet("padding: 0; margin: 0;"); - wGroupQuestion->hide(); - questionBox->layout()->addWidget(wGroupQuestion); - } - - addShortcut("l", []() { - if (btnNext->isVisible()) { - btnNext->click(); - } - }); - + // Pievieno uzstādīto. vTrainWidget->addWidget(questionBox); vTrainWidget->addWidget(actionButtons); return trainWindow; diff --git a/src/transpiler/api.cpp b/src/transpiler/api.cpp index 8d26ee5..47b0ac8 100644 --- a/src/transpiler/api.cpp +++ b/src/transpiler/api.cpp @@ -16,11 +16,17 @@ bool showTimes = false; std::chrono::high_resolution_clock::time_point start; std::chrono::high_resolution_clock::time_point end; -std::string wrapText(std::string text, size_t width) { +/* + * Pārveido teksta rindu tā, lai teksts nepārsniegtu doto + * platumu. Pievieno nākamās rindās atstarpi ar platumu kurā sākas pirmās rindas + * teksts. + * */ +std::string wrapLine(std::string text, size_t width) { std::string result; size_t currentLineLength = 0; size_t wordStart = 0; - + + // Nosaka, cik tālu no rindas sākuma atrodas teksts pirmā rindā. size_t preservedSpaceCount = 0; for (size_t i = 0; i < text.length(); ++i) { if (text[i] == '\t') { @@ -37,13 +43,15 @@ std::string wrapText(std::string text, size_t width) { for (size_t i = wordStart; i < text.length(); ++i) { if (text[i] == ' ' || i == text.length() - 1) { - size_t wordEnd = (i == text.length() - 1) ? i + 1 : i; // Handle the last word - size_t wordLength = wordEnd - wordStart; - if (currentLineLength + wordLength > width) { - result += '\n'; - result.append(preservedSpaceCount / TABWIDTH, '\t'); - result.append(preservedSpaceCount % TABWIDTH, ' '); - currentLineLength = preservedSpaceCount; + // Ja vārds pārsniedz norādīto platumu, pievieno + // jaunās rindas simbolu un turpina no iepriekš noteiktā attāluma. + size_t wordEnd = (i == text.length() - 1) ? i + 1 : i; + size_t wordLength = wordEnd - wordStart; + if (currentLineLength + wordLength > width) { + result += '\n'; + result.append(preservedSpaceCount / TABWIDTH, '\t'); + result.append(preservedSpaceCount % TABWIDTH, ' '); + currentLineLength = preservedSpaceCount; } result += text.substr(wordStart, wordLength) + ' '; currentLineLength += wordLength + 1; @@ -53,6 +61,9 @@ std::string wrapText(std::string text, size_t width) { return result; } +/* + * Tekstā katram rezervētam tekstvienību simbolam pievieno '\' pirms simbola. + */ std::string escapeText(std::string text) { std::stringstream ss; for (auto c: text) { @@ -89,6 +100,10 @@ std::string escapeText(std::string text) { return ss.str(); } +/* + * Transpilē tekstu jautājumos un metadatos. + * Veic leksisko analīzi un parsēšanu. + * */ Result transpile(std::string fileContent) { start = std::chrono::high_resolution_clock::now(); end = std::chrono::high_resolution_clock::now(); @@ -125,7 +140,9 @@ Result transpile(std::string fileContent) { return {questions}; } - +/* + * Parāda nomērīta laika sekundes un milisekundes. + */ std::string showTime(std::string label) { auto duration = std::chrono::duration_cast(end - start); double_t seconds = (double_t) duration.count() / 1000000;