mirror of
https://github.com/jorenchik/mdemory.git
synced 2026-03-22 00:26:21 +00:00
basic training functionality - all question types
This commit is contained in:
@@ -1,29 +1,9 @@
|
|||||||
|
|
||||||
- What is the capital of Latvia? >
|
|
||||||
- Rīga
|
|
||||||
|
|
||||||
- [cap_est] What is the capital of Estonia? >
|
|
||||||
- Tallin
|
|
||||||
|
|
||||||
- What countries reside in Europe? >
|
|
||||||
+ Latvia
|
|
||||||
- Peru
|
|
||||||
+ Poland
|
|
||||||
- China
|
|
||||||
|
|
||||||
- Arrange these events in the order they occurred >
|
- Arrange these events in the order they occurred >
|
||||||
-^ The Fall of the Roman Empire (476 AD)
|
-^ The Fall of the Roman Empire
|
||||||
-^ The Renaissance (14th\-17th century)
|
-^ The Renaissance
|
||||||
-^ The Industrial Revolution (18th\-19th century)
|
-^ The Industrial Revolution
|
||||||
|
|
||||||
- [scient_method_order] Place the following steps of the scientific method in the correct order >
|
- [planet_characteristics] Match Planets to Their Characteristics >
|
||||||
- Ask a Question
|
|
||||||
- Form a Hypothesis
|
|
||||||
-^ Conduct an Experiment
|
|
||||||
- Analyze Data
|
|
||||||
|
|
||||||
|
|
||||||
- Match Planets to Their Characteristics >
|
|
||||||
- Earth:
|
- Earth:
|
||||||
- Contains Life
|
- Contains Life
|
||||||
- Mars:
|
- Mars:
|
||||||
@@ -40,3 +20,26 @@
|
|||||||
- Neptune:
|
- Neptune:
|
||||||
- Farthest from the Sun
|
- Farthest from the Sun
|
||||||
- Has Rings
|
- Has Rings
|
||||||
|
|
||||||
|
- What countries reside in Europe? >
|
||||||
|
+ Latvia
|
||||||
|
- Peru
|
||||||
|
+ Poland
|
||||||
|
- China
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
- What is the capital of Latvia? >
|
||||||
|
- Rīga
|
||||||
|
|
||||||
|
- [cap_est] What is the capital of Estonia? >
|
||||||
|
- Tallin
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
- [scient_method_order] Place the following steps of the scientific method in the correct order >
|
||||||
|
- Ask a Question
|
||||||
|
- Form a Hypothesis
|
||||||
|
-^ Conduct an Experiment
|
||||||
|
- Analyze Data
|
||||||
|
|
||||||
|
|||||||
@@ -353,7 +353,6 @@ void loadMdem() {
|
|||||||
questions = parseRes.value;
|
questions = parseRes.value;
|
||||||
makePages();
|
makePages();
|
||||||
SwitchPage(0);
|
SwitchPage(0);
|
||||||
setQuestions(questions);
|
|
||||||
std::smatch matches;
|
std::smatch matches;
|
||||||
auto filename = std::regex_search(currentPath, matches, lastPathElementExp);
|
auto filename = std::regex_search(currentPath, matches, lastPathElementExp);
|
||||||
deckListLabel->setText(
|
deckListLabel->setText(
|
||||||
@@ -555,7 +554,9 @@ int main(int argc, char *argv[]) {
|
|||||||
[](bool checked) {
|
[](bool checked) {
|
||||||
trainWindow->show();
|
trainWindow->show();
|
||||||
trainWindow->resize(600, 300);
|
trainWindow->resize(600, 300);
|
||||||
});
|
setQuestions(questions);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
window.setCentralWidget(hSplitter);
|
window.setCentralWidget(hSplitter);
|
||||||
window.show();
|
window.show();
|
||||||
|
|||||||
@@ -2,9 +2,15 @@
|
|||||||
#include <QWidget>
|
#include <QWidget>
|
||||||
#include <QToolButton>
|
#include <QToolButton>
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
|
#include <atomic>
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
#include <format>
|
#include <format>
|
||||||
|
#include <cstdlib>
|
||||||
|
#include <exception>
|
||||||
|
#include <format>
|
||||||
|
#include <qabstractitemview.h>
|
||||||
#include <qboxlayout.h>
|
#include <qboxlayout.h>
|
||||||
|
#include <qcoreevent.h>
|
||||||
#include <qlabel.h>
|
#include <qlabel.h>
|
||||||
#include <qlayoutitem.h>
|
#include <qlayoutitem.h>
|
||||||
#include <qlistview.h>
|
#include <qlistview.h>
|
||||||
@@ -20,10 +26,18 @@
|
|||||||
#include <QDropEvent>
|
#include <QDropEvent>
|
||||||
#include <QDrag>
|
#include <QDrag>
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
|
#include <QStyledItemDelegate>
|
||||||
|
#include <QPainter>
|
||||||
|
|
||||||
#include "trainWindow.h"
|
#include "trainWindow.h"
|
||||||
#include "parser.h"
|
#include "parser.h"
|
||||||
|
|
||||||
|
enum ElementState {
|
||||||
|
NEUTRAL = 0,
|
||||||
|
CORRECT,
|
||||||
|
INCORRECT
|
||||||
|
};
|
||||||
|
|
||||||
const auto listStyle =
|
const auto listStyle =
|
||||||
"QListView {"
|
"QListView {"
|
||||||
" background-color: white;"
|
" background-color: white;"
|
||||||
@@ -35,15 +49,48 @@ const auto listStyle =
|
|||||||
"QListView::item {"
|
"QListView::item {"
|
||||||
" color: black;"
|
" color: black;"
|
||||||
" padding: 5px;"
|
" padding: 5px;"
|
||||||
" border: 1px solid gray;"
|
" background-color: none;"
|
||||||
" background-color: white;"
|
|
||||||
"}"
|
"}"
|
||||||
"QListView::item:selected {"
|
"QListView::item:selected {"
|
||||||
|
" background-color: transparent;"
|
||||||
|
" padding-left: 0px;"
|
||||||
|
" margin-left: 0px;"
|
||||||
"}"
|
"}"
|
||||||
"QListView::item:hover {"
|
"QListView::item:hover {"
|
||||||
" background-color: lightyellow;"
|
" background-color: lightyellow;"
|
||||||
|
" padding-left: 0px;"
|
||||||
|
" margin-left: 0px;"
|
||||||
"}";
|
"}";
|
||||||
|
|
||||||
|
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 {
|
||||||
|
painter->save();
|
||||||
|
Qt::GlobalColor color;
|
||||||
|
auto colorIdx = index.data(Qt::UserRole + 1).toInt() ;
|
||||||
|
switch (colorIdx) {
|
||||||
|
case NEUTRAL:
|
||||||
|
color = Qt::lightGray;
|
||||||
|
break;
|
||||||
|
case INCORRECT:
|
||||||
|
color = Qt::red;
|
||||||
|
break;
|
||||||
|
case CORRECT:
|
||||||
|
color = Qt::green;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
painter->setOpacity(0.5);
|
||||||
|
if (color) {
|
||||||
|
painter->fillRect(option.rect, color);
|
||||||
|
}
|
||||||
|
painter->restore();
|
||||||
|
QStyledItemDelegate::paint(painter, option, index);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
class MultiChoiceListView : public QListView
|
class MultiChoiceListView : public QListView
|
||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
@@ -54,6 +101,7 @@ public:
|
|||||||
setAcceptDrops(true);
|
setAcceptDrops(true);
|
||||||
setEditTriggers(QAbstractItemView::NoEditTriggers);
|
setEditTriggers(QAbstractItemView::NoEditTriggers);
|
||||||
setFocusPolicy(Qt::NoFocus);
|
setFocusPolicy(Qt::NoFocus);
|
||||||
|
setSelectionMode(QAbstractItemView::NoSelection);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -65,9 +113,8 @@ public:
|
|||||||
explicit OrderListView(QWidget *parent = nullptr) : QListView(parent) {
|
explicit OrderListView(QWidget *parent = nullptr) : QListView(parent) {
|
||||||
setStyleSheet(listStyle);
|
setStyleSheet(listStyle);
|
||||||
setAcceptDrops(true);
|
setAcceptDrops(true);
|
||||||
setEditTriggers(QAbstractItemView::NoEditTriggers);
|
|
||||||
setFocusPolicy(Qt::NoFocus);
|
setFocusPolicy(Qt::NoFocus);
|
||||||
|
setEditTriggers(QAbstractItemView::NoEditTriggers);
|
||||||
setDragDropMode(QAbstractItemView::InternalMove);
|
setDragDropMode(QAbstractItemView::InternalMove);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -131,10 +178,21 @@ protected:
|
|||||||
|
|
||||||
#include "trainWindow.moc"
|
#include "trainWindow.moc"
|
||||||
|
|
||||||
|
struct GroupView {
|
||||||
|
QWidget widget;
|
||||||
|
QVBoxLayout vWidget;
|
||||||
|
QLabel label;
|
||||||
|
QScrollArea itemScroll;
|
||||||
|
QStandardItemModel itemModel;
|
||||||
|
MoveListView itemList;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
// Main components
|
// Main components
|
||||||
QMainWindow *trainWindow;
|
QMainWindow *trainWindow;
|
||||||
QWidget *trainWidget;
|
QWidget *trainWidget;
|
||||||
QVBoxLayout *vTrainWidget;
|
QVBoxLayout *vTrainWidget;
|
||||||
|
CustomItemDelegate *itemDelegate;
|
||||||
|
|
||||||
// Question
|
// Question
|
||||||
QWidget *questionBox;
|
QWidget *questionBox;
|
||||||
@@ -163,19 +221,312 @@ OrderListView *orderList;
|
|||||||
QStandardItemModel *orderModel;
|
QStandardItemModel *orderModel;
|
||||||
|
|
||||||
// Group question
|
// Group question
|
||||||
QStandardItemModel *itemModel;
|
QStandardItemModel *groupItemModel;
|
||||||
QListView *groupItemList;
|
QListView *groupItemList;
|
||||||
QWidget *wGroupQuestion;
|
QWidget *wGroupQuestion;
|
||||||
QVBoxLayout *vGroups;
|
QVBoxLayout *vGroups;
|
||||||
|
std::vector<QStandardItemModel*> groupModels;
|
||||||
|
|
||||||
|
// Questions & State
|
||||||
|
std::vector<Question*> trainQuestions = std::vector<Question*>();
|
||||||
|
int32_t currentQuestionIndex = -1;
|
||||||
|
std::vector<GroupView*> groupViews;
|
||||||
|
|
||||||
std::default_random_engine rng;
|
std::default_random_engine rng;
|
||||||
|
std::vector<QStandardItem*> itemPool;
|
||||||
|
|
||||||
QStandardItem *makeItem(std::string content, bool isCheckable) {
|
/*QStandardItem *makeItem(std::string content, bool isCheckable) {*/
|
||||||
auto *item = new QStandardItem();
|
/* auto *item = new QStandardItem(); */
|
||||||
item->setText(QString::fromStdString(content));
|
/* item->setText(QString::fromStdString(content));*/
|
||||||
item->setCheckable(isCheckable);
|
/* item->setCheckable(isCheckable);*/
|
||||||
|
/* return item;*/
|
||||||
|
/*};*/
|
||||||
|
|
||||||
|
#define ITEM_POOL_CHUNK 200
|
||||||
|
|
||||||
|
|
||||||
|
QStandardItem* acquireItem() {
|
||||||
|
if (itemPool.size() <= 0) {
|
||||||
|
for (int i = 0; i < ITEM_POOL_CHUNK; ++i) {
|
||||||
|
itemPool.push_back(new QStandardItem);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
auto item = itemPool.back();
|
||||||
|
itemPool.pop_back();
|
||||||
return item;
|
return item;
|
||||||
};
|
}
|
||||||
|
|
||||||
|
void releaseItem(QStandardItem** item) {
|
||||||
|
itemPool.push_back(*item);
|
||||||
|
(*item) = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
void releaseAllItems() {
|
||||||
|
std::cout <<
|
||||||
|
std::format("Starting release, currently in the pool: {}", itemPool.size()) <<
|
||||||
|
std::endl;
|
||||||
|
auto releaseAllInModel = [](QStandardItemModel *model) {
|
||||||
|
auto itemCount = model->rowCount();
|
||||||
|
for (int i = 0; i < itemCount; ++i) {
|
||||||
|
auto item = model->item(0);
|
||||||
|
model->takeRow(item->row());
|
||||||
|
releaseItem(&item);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
releaseAllInModel(multiChoiceModel);
|
||||||
|
releaseAllInModel(groupItemModel);
|
||||||
|
releaseAllInModel(orderModel);
|
||||||
|
for (auto groupView: groupViews) {
|
||||||
|
releaseAllInModel(&groupView->itemModel);
|
||||||
|
}
|
||||||
|
std::cout << std::format("All items released, currently in the pool: {}", itemPool.size()) << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
void hideQuestionElements() {
|
||||||
|
lQuestionText->hide();
|
||||||
|
answerText->hide();
|
||||||
|
orderList->hide();
|
||||||
|
multiChoiceList->hide();
|
||||||
|
wGroupQuestion->hide();
|
||||||
|
}
|
||||||
|
|
||||||
|
void setupAnswerQuestion(MultiElementQuestion *question) {
|
||||||
|
lQuestionText->setText(
|
||||||
|
QString::fromStdString(question->QuestionText)
|
||||||
|
);
|
||||||
|
lQuestionText->show();
|
||||||
|
auto ss = std::stringstream();
|
||||||
|
for (auto answerEl: question->Choices) {
|
||||||
|
ss << std::format("- {}", answerEl.Answer) << std::endl;
|
||||||
|
}
|
||||||
|
answerText->setText(
|
||||||
|
QString::fromStdString(ss.str())
|
||||||
|
);
|
||||||
|
if (answerText->isVisible()) {
|
||||||
|
answerText->hide();
|
||||||
|
}
|
||||||
|
QObject::connect(
|
||||||
|
btnTriggerAnswer,
|
||||||
|
&QToolButton::clicked,
|
||||||
|
[](bool checked) {
|
||||||
|
answerText->show();
|
||||||
|
btnTriggerAnswer->hide();
|
||||||
|
}
|
||||||
|
);
|
||||||
|
btnTriggerAnswer->show();
|
||||||
|
}
|
||||||
|
|
||||||
|
void setupOrderQuestion(MultiElementQuestion *question) {
|
||||||
|
lQuestionText->setText(
|
||||||
|
QString::fromStdString(question->QuestionText)
|
||||||
|
);
|
||||||
|
lQuestionText->show();
|
||||||
|
orderModel->clear();
|
||||||
|
auto shuffledAnswers = question->Choices;
|
||||||
|
std::shuffle(shuffledAnswers.begin(), shuffledAnswers.end(), rng);
|
||||||
|
for (auto answerEl: shuffledAnswers) {
|
||||||
|
auto *item = acquireItem();
|
||||||
|
item->setData(NEUTRAL, Qt::UserRole + 1);
|
||||||
|
item->setData(QVariant(), Qt::CheckStateRole);
|
||||||
|
item->setCheckable(false);
|
||||||
|
item->setText(QString::fromStdString(answerEl.Answer));
|
||||||
|
orderModel->appendRow(item);
|
||||||
|
}
|
||||||
|
orderList->show();
|
||||||
|
QObject::connect(
|
||||||
|
btnTriggerAnswer,
|
||||||
|
&QToolButton::clicked,
|
||||||
|
[question](bool checked) {
|
||||||
|
for (int i = 0; i < orderModel->rowCount(); ++i) {
|
||||||
|
auto item = orderModel->item(i, 0);
|
||||||
|
auto text = item->text();
|
||||||
|
auto isCorrect = question->Choices[i].Answer.compare(text.toStdString()) == 0;
|
||||||
|
if (isCorrect) {
|
||||||
|
item->setData(CORRECT, Qt::UserRole + 1);
|
||||||
|
} else {
|
||||||
|
item->setData(INCORRECT, Qt::UserRole + 1);
|
||||||
|
}
|
||||||
|
orderList->update();
|
||||||
|
}
|
||||||
|
btnTriggerAnswer->hide();
|
||||||
|
}
|
||||||
|
);
|
||||||
|
btnTriggerAnswer->show();
|
||||||
|
}
|
||||||
|
|
||||||
|
void setupMultiChoiceQuestion(MultiElementQuestion *question) {
|
||||||
|
lQuestionText->setText(
|
||||||
|
QString::fromStdString(question->QuestionText)
|
||||||
|
);
|
||||||
|
lQuestionText->show();
|
||||||
|
|
||||||
|
multiChoiceModel->clear();
|
||||||
|
for (auto answerEl: question->Choices) {
|
||||||
|
auto *item = acquireItem();
|
||||||
|
item->setText(QString::fromStdString(answerEl.Answer));
|
||||||
|
item->setData(NEUTRAL, Qt::UserRole + 1);
|
||||||
|
item->setCheckable(true);
|
||||||
|
item->setCheckState(Qt::CheckState::Unchecked);
|
||||||
|
multiChoiceModel->appendRow(item);
|
||||||
|
}
|
||||||
|
multiChoiceList->show();
|
||||||
|
|
||||||
|
QObject::connect(
|
||||||
|
btnTriggerAnswer,
|
||||||
|
&QToolButton::clicked,
|
||||||
|
[question](bool checked) {
|
||||||
|
for (int i = 0; i < multiChoiceModel->rowCount(); ++i) {
|
||||||
|
auto item = multiChoiceModel->item(i, 0);
|
||||||
|
auto isCorrect = question->Choices[i].IsCorrect == (item->checkState() == Qt::Checked);
|
||||||
|
if (isCorrect) {
|
||||||
|
item->setData(CORRECT, Qt::UserRole + 1);
|
||||||
|
} else {
|
||||||
|
item->setData(INCORRECT, Qt::UserRole + 1);
|
||||||
|
}
|
||||||
|
multiChoiceList->update();
|
||||||
|
}
|
||||||
|
btnTriggerAnswer->hide();
|
||||||
|
}
|
||||||
|
);
|
||||||
|
btnTriggerAnswer->show();
|
||||||
|
}
|
||||||
|
|
||||||
|
void setupGroupQuestion(GroupQuestion *question) {
|
||||||
|
auto groupSpacer = new QSpacerItem(
|
||||||
|
50, 50,
|
||||||
|
QSizePolicy::Minimum,
|
||||||
|
QSizePolicy::Expanding
|
||||||
|
);
|
||||||
|
|
||||||
|
lQuestionText->setText(
|
||||||
|
QString::fromStdString(question->QuestionText)
|
||||||
|
);
|
||||||
|
lQuestionText->show();
|
||||||
|
wGroupQuestion->show();
|
||||||
|
|
||||||
|
for (auto group: question->Groups) {
|
||||||
|
for (auto itemText: group.elements) {
|
||||||
|
auto *qItem = acquireItem();
|
||||||
|
qItem->setData(NEUTRAL, Qt::UserRole + 1);
|
||||||
|
qItem->setCheckable(false);
|
||||||
|
qItem->setData(QVariant(), Qt::CheckStateRole);
|
||||||
|
qItem->setText(QString::fromStdString(itemText));
|
||||||
|
groupItemModel->appendRow(qItem);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
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->itemScroll.setWidget(&groupView->itemScroll);*/
|
||||||
|
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 (int 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);
|
||||||
|
|
||||||
|
QObject::connect(
|
||||||
|
btnTriggerAnswer,
|
||||||
|
&QToolButton::clicked,
|
||||||
|
[question](bool checked) {
|
||||||
|
for (int i = 0; i < groupItemModel->rowCount(); ++i) {
|
||||||
|
auto item = groupItemModel->item(i, 0);
|
||||||
|
item->setData(INCORRECT, Qt::UserRole + 1);
|
||||||
|
}
|
||||||
|
for (int i = 0; i < groupViews.size(); i++) {
|
||||||
|
auto groupView = groupViews[i];
|
||||||
|
auto group = question->Groups[i];
|
||||||
|
for (int j = 0; j < groupView->itemModel.rowCount(); ++j) {
|
||||||
|
auto item = groupView->itemModel.item(j, 0);
|
||||||
|
auto itemText = item->text().toStdString();
|
||||||
|
bool found = false;
|
||||||
|
for (int k = 0; k < group.elements.size(); ++k) {
|
||||||
|
if (group.elements[k].compare(itemText) == 0) {
|
||||||
|
found = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (found) {
|
||||||
|
item->setData(CORRECT, Qt::UserRole + 1);
|
||||||
|
} else {
|
||||||
|
item->setData(INCORRECT, Qt::UserRole + 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
groupView->itemList.update();
|
||||||
|
}
|
||||||
|
btnTriggerAnswer->hide();
|
||||||
|
}
|
||||||
|
);
|
||||||
|
btnTriggerAnswer->show();
|
||||||
|
}
|
||||||
|
|
||||||
|
void setupQuestion(Question *question) {
|
||||||
|
hideQuestionElements();
|
||||||
|
releaseAllItems();
|
||||||
|
QObject::disconnect(btnTriggerAnswer, 0, 0, 0);
|
||||||
|
if (auto *question = dynamic_cast<MultiElementQuestion*>(trainQuestions[currentQuestionIndex])) {
|
||||||
|
switch (question->type) {
|
||||||
|
case MultiElementType::Order:
|
||||||
|
setupOrderQuestion(question);
|
||||||
|
break;
|
||||||
|
case MultiElementType::MultiChoice:
|
||||||
|
setupMultiChoiceQuestion(question);
|
||||||
|
break;
|
||||||
|
case MultiElementType::Regular:
|
||||||
|
setupAnswerQuestion(question);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
} else if (auto *question = dynamic_cast<GroupQuestion*>(trainQuestions[currentQuestionIndex])) {
|
||||||
|
setupGroupQuestion(question);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void updatePaginationVisibility() {
|
||||||
|
if (currentQuestionIndex == 0) {
|
||||||
|
btnPrev->hide();
|
||||||
|
} else {
|
||||||
|
btnPrev->show();
|
||||||
|
}
|
||||||
|
if (currentQuestionIndex == trainQuestions.size() - 1) {
|
||||||
|
btnNext->hide();
|
||||||
|
} else {
|
||||||
|
btnNext->show();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void setQuestions(std::vector<Question*> questions) {
|
||||||
|
trainQuestions = questions;
|
||||||
|
if (questions.size() <= 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
currentQuestionIndex = 0;
|
||||||
|
updatePaginationVisibility();
|
||||||
|
setupQuestion(trainQuestions[currentQuestionIndex]);
|
||||||
|
}
|
||||||
|
|
||||||
void initTrainWindow() {
|
void initTrainWindow() {
|
||||||
unsigned seed = std::chrono::system_clock::now().time_since_epoch().count();
|
unsigned seed = std::chrono::system_clock::now().time_since_epoch().count();
|
||||||
@@ -191,6 +542,8 @@ void initTrainWindow() {
|
|||||||
vTrainWidget->setAlignment(Qt::AlignCenter);
|
vTrainWidget->setAlignment(Qt::AlignCenter);
|
||||||
trainWidget->setObjectName("answer-question-widget");
|
trainWidget->setObjectName("answer-question-widget");
|
||||||
|
|
||||||
|
itemDelegate = new CustomItemDelegate(multiChoiceList);
|
||||||
|
|
||||||
{ // Make the question box.
|
{ // Make the question box.
|
||||||
questionBox = new QWidget();
|
questionBox = new QWidget();
|
||||||
vQuestionBox = new QVBoxLayout();
|
vQuestionBox = new QVBoxLayout();
|
||||||
@@ -220,6 +573,7 @@ void initTrainWindow() {
|
|||||||
multiChoiceList->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Minimum);
|
multiChoiceList->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Minimum);
|
||||||
questionBox->layout()->addWidget(multiChoiceList);
|
questionBox->layout()->addWidget(multiChoiceList);
|
||||||
multiChoiceList->hide();
|
multiChoiceList->hide();
|
||||||
|
multiChoiceList->setItemDelegate(itemDelegate);
|
||||||
}
|
}
|
||||||
|
|
||||||
{ // Make answer text.
|
{ // Make answer text.
|
||||||
@@ -241,6 +595,7 @@ void initTrainWindow() {
|
|||||||
orderList = new OrderListView();
|
orderList = new OrderListView();
|
||||||
orderList->setModel(orderModel);
|
orderList->setModel(orderModel);
|
||||||
orderList->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Minimum);
|
orderList->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Minimum);
|
||||||
|
orderList->setItemDelegate(itemDelegate);
|
||||||
|
|
||||||
// Connect to handle the drop event properly
|
// Connect to handle the drop event properly
|
||||||
QObject::connect(
|
QObject::connect(
|
||||||
@@ -276,9 +631,24 @@ void initTrainWindow() {
|
|||||||
vButtonBox->addWidget(actionButtons);
|
vButtonBox->addWidget(actionButtons);
|
||||||
actionButtons->setLayout(hButtons);
|
actionButtons->setLayout(hButtons);
|
||||||
btnPrev->setText("Previous");
|
btnPrev->setText("Previous");
|
||||||
btnTriggerAnswer->setText("Show answer");
|
QObject::connect(btnPrev, &QToolButton::clicked, []() {
|
||||||
btnNext->setText("Next");
|
currentQuestionIndex--;
|
||||||
|
if (currentQuestionIndex > -1) {
|
||||||
|
setupQuestion(trainQuestions[currentQuestionIndex]);
|
||||||
|
}
|
||||||
|
updatePaginationVisibility();
|
||||||
|
});
|
||||||
|
|
||||||
|
btnTriggerAnswer->setText("Show answer");
|
||||||
|
|
||||||
|
btnNext->setText("Next");
|
||||||
|
QObject::connect(btnNext, &QToolButton::clicked, []() {
|
||||||
|
currentQuestionIndex++;
|
||||||
|
if (currentQuestionIndex < trainQuestions.size()) {
|
||||||
|
setupQuestion(trainQuestions[currentQuestionIndex]);
|
||||||
|
}
|
||||||
|
updatePaginationVisibility();
|
||||||
|
});
|
||||||
questionBox->setObjectName("question-box");
|
questionBox->setObjectName("question-box");
|
||||||
actionButtons->setStyleSheet(QString(
|
actionButtons->setStyleSheet(QString(
|
||||||
"QToolButton {"
|
"QToolButton {"
|
||||||
@@ -301,9 +671,10 @@ void initTrainWindow() {
|
|||||||
auto itemScroll = new QScrollArea();
|
auto itemScroll = new QScrollArea();
|
||||||
auto vItems = new QVBoxLayout();
|
auto vItems = new QVBoxLayout();
|
||||||
itemScroll->setLayout(vItems);
|
itemScroll->setLayout(vItems);
|
||||||
itemModel = new QStandardItemModel();
|
groupItemModel = new QStandardItemModel();
|
||||||
groupItemList = new MoveListView();
|
groupItemList = new MoveListView();
|
||||||
groupItemList->setModel(itemModel);
|
groupItemList->setItemDelegate(itemDelegate);
|
||||||
|
groupItemList->setModel(groupItemModel);
|
||||||
vItems->addWidget(groupItemList);
|
vItems->addWidget(groupItemList);
|
||||||
hGroupQuestion->addWidget(itemScroll);
|
hGroupQuestion->addWidget(itemScroll);
|
||||||
|
|
||||||
@@ -316,6 +687,7 @@ void initTrainWindow() {
|
|||||||
wGroupContainer->setLayout(vGroups);
|
wGroupContainer->setLayout(vGroups);
|
||||||
hGroupQuestion->addWidget(groupScroll);
|
hGroupQuestion->addWidget(groupScroll);
|
||||||
|
|
||||||
|
|
||||||
wGroupQuestion->setStyleSheet("padding: 0; margin: 0;");
|
wGroupQuestion->setStyleSheet("padding: 0; margin: 0;");
|
||||||
wGroupQuestion->hide();
|
wGroupQuestion->hide();
|
||||||
questionBox->layout()->addWidget(wGroupQuestion);
|
questionBox->layout()->addWidget(wGroupQuestion);
|
||||||
@@ -325,165 +697,3 @@ void initTrainWindow() {
|
|||||||
vTrainWidget->addWidget(actionButtons);
|
vTrainWidget->addWidget(actionButtons);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<Question*> trainQuestions = std::vector<Question*>();
|
|
||||||
int32_t currentQuestionIndex = -1;
|
|
||||||
|
|
||||||
void hideQuestionElements() {
|
|
||||||
lQuestionText->hide();
|
|
||||||
answerText->hide();
|
|
||||||
orderList->hide();
|
|
||||||
multiChoiceList->hide();
|
|
||||||
wGroupQuestion->hide();
|
|
||||||
}
|
|
||||||
|
|
||||||
void setupAnswerQuestion(MultiElementQuestion *question) {
|
|
||||||
hideQuestionElements();
|
|
||||||
|
|
||||||
lQuestionText->setText(
|
|
||||||
QString::fromStdString(question->QuestionText)
|
|
||||||
);
|
|
||||||
lQuestionText->show();
|
|
||||||
auto ss = std::stringstream();
|
|
||||||
for (auto answerEl: question->Choices) {
|
|
||||||
ss << std::format("- {}", answerEl.Answer) << std::endl;
|
|
||||||
}
|
|
||||||
answerText->setText(
|
|
||||||
QString::fromStdString(ss.str())
|
|
||||||
);
|
|
||||||
if (answerText->isVisible()) {
|
|
||||||
answerText->hide();
|
|
||||||
}
|
|
||||||
auto showAnswer = [](bool checked) {
|
|
||||||
answerText->show();
|
|
||||||
btnTriggerAnswer->hide();
|
|
||||||
QObject::disconnect(btnTriggerAnswer, 0, 0, 0);
|
|
||||||
};
|
|
||||||
QObject::connect(
|
|
||||||
btnTriggerAnswer,
|
|
||||||
&QToolButton::clicked,
|
|
||||||
showAnswer
|
|
||||||
);
|
|
||||||
btnTriggerAnswer->show();
|
|
||||||
}
|
|
||||||
|
|
||||||
void setupOrderQuestion(MultiElementQuestion *question) {
|
|
||||||
hideQuestionElements();
|
|
||||||
|
|
||||||
lQuestionText->setText(
|
|
||||||
QString::fromStdString(question->QuestionText)
|
|
||||||
);
|
|
||||||
lQuestionText->show();
|
|
||||||
orderModel->clear();
|
|
||||||
auto shuffledAnswers = question->Choices;
|
|
||||||
std::shuffle(shuffledAnswers.begin(), shuffledAnswers.end(), rng);
|
|
||||||
for (auto answerEl: shuffledAnswers) {
|
|
||||||
orderModel->appendRow(makeItem(answerEl.Answer, false));
|
|
||||||
}
|
|
||||||
orderList->show();
|
|
||||||
auto showAnswer = [](bool checked) {
|
|
||||||
QObject::disconnect(btnTriggerAnswer, 0, 0, 0);
|
|
||||||
};
|
|
||||||
QObject::connect(
|
|
||||||
btnTriggerAnswer,
|
|
||||||
&QToolButton::clicked,
|
|
||||||
showAnswer
|
|
||||||
);
|
|
||||||
btnTriggerAnswer->show();
|
|
||||||
}
|
|
||||||
|
|
||||||
void setupMultiChoiceQuestion(MultiElementQuestion *question) {
|
|
||||||
hideQuestionElements();
|
|
||||||
|
|
||||||
lQuestionText->setText(
|
|
||||||
QString::fromStdString(question->QuestionText)
|
|
||||||
);
|
|
||||||
lQuestionText->show();
|
|
||||||
|
|
||||||
multiChoiceModel->clear();
|
|
||||||
for (auto answerEl: question->Choices) {
|
|
||||||
multiChoiceModel->appendRow(makeItem(answerEl.Answer, true));
|
|
||||||
}
|
|
||||||
multiChoiceList->show();
|
|
||||||
|
|
||||||
auto showAnswer = [](bool checked) {
|
|
||||||
QObject::disconnect(btnTriggerAnswer, 0, 0, 0);
|
|
||||||
};
|
|
||||||
QObject::connect(
|
|
||||||
btnTriggerAnswer,
|
|
||||||
&QToolButton::clicked,
|
|
||||||
showAnswer
|
|
||||||
);
|
|
||||||
btnTriggerAnswer->show();
|
|
||||||
}
|
|
||||||
|
|
||||||
void setupGroupQuestion(GroupQuestion *question) {
|
|
||||||
auto groupSpacer = new QSpacerItem(
|
|
||||||
50, 50,
|
|
||||||
QSizePolicy::Minimum,
|
|
||||||
QSizePolicy::Expanding
|
|
||||||
);
|
|
||||||
|
|
||||||
hideQuestionElements();
|
|
||||||
|
|
||||||
lQuestionText->setText(
|
|
||||||
QString::fromStdString(question->QuestionText)
|
|
||||||
);
|
|
||||||
lQuestionText->show();
|
|
||||||
wGroupQuestion->show();
|
|
||||||
|
|
||||||
for (auto group: question->Groups) {
|
|
||||||
for (auto item: group.elements) {
|
|
||||||
itemModel->appendRow(makeItem(item, false));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
auto makeAGroup = [](std::string groupName) {
|
|
||||||
auto groupLabel = new QLabel(QString::fromStdString(groupName));
|
|
||||||
auto scrollArea = new QScrollArea();
|
|
||||||
auto groupModel = new QStandardItemModel();
|
|
||||||
auto groupList = new MoveListView();
|
|
||||||
vGroups->addWidget(groupLabel);
|
|
||||||
vGroups->addWidget(groupList);
|
|
||||||
groupList->setModel(groupModel);
|
|
||||||
groupList->setMaximumHeight(100);
|
|
||||||
};
|
|
||||||
|
|
||||||
for (auto group: question->Groups) {
|
|
||||||
makeAGroup(group.name);
|
|
||||||
}
|
|
||||||
vGroups->addItem(groupSpacer);
|
|
||||||
|
|
||||||
auto showAnswer = [](bool checked) {
|
|
||||||
QObject::disconnect(btnTriggerAnswer, 0, 0, 0);
|
|
||||||
};
|
|
||||||
QObject::connect(
|
|
||||||
btnTriggerAnswer,
|
|
||||||
&QToolButton::clicked,
|
|
||||||
showAnswer
|
|
||||||
);
|
|
||||||
btnTriggerAnswer->show();
|
|
||||||
}
|
|
||||||
|
|
||||||
void setQuestions(std::vector<Question*> questions) {
|
|
||||||
trainQuestions = questions;
|
|
||||||
if (questions.size() <= 0) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// setupFirstQuestion
|
|
||||||
currentQuestionIndex = 0;
|
|
||||||
if (auto *question = dynamic_cast<MultiElementQuestion*>(trainQuestions[currentQuestionIndex])) {
|
|
||||||
switch (question->type) {
|
|
||||||
case MultiElementType::Order:
|
|
||||||
setupOrderQuestion(question);
|
|
||||||
break;
|
|
||||||
case MultiElementType::MultiChoice:
|
|
||||||
setupMultiChoiceQuestion(question);
|
|
||||||
break;
|
|
||||||
case MultiElementType::Regular:
|
|
||||||
setupAnswerQuestion(question);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
} else if (auto *question = dynamic_cast<GroupQuestion*>(trainQuestions[currentQuestionIndex])) {
|
|
||||||
setupGroupQuestion(question);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|||||||
19
tasks.md
19
tasks.md
@@ -1,3 +1,18 @@
|
|||||||
|
- [x] Augment the lexer for Order and match question;
|
||||||
|
- [x] Parse the questions accordingly;
|
||||||
|
- [x] Escape character;
|
||||||
|
- [ ] Implement order question checking;
|
||||||
|
- [ ] Implement multichoice question checking;
|
||||||
|
- [ ] Implement group question checking;
|
||||||
|
- [ ] Ensure no duplicates in questions where it matters.
|
||||||
|
We will need this for checking the answers;
|
||||||
|
- [ ]
|
||||||
|
- [ ]
|
||||||
|
- [ ]
|
||||||
|
- [ ]
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## 1-N Answer question
|
## 1-N Answer question
|
||||||
|
|
||||||
- kfoewf >
|
- kfoewf >
|
||||||
@@ -30,8 +45,4 @@
|
|||||||
- fewjpfe
|
- fewjpfe
|
||||||
- fioewf
|
- fioewf
|
||||||
|
|
||||||
- [ ] Augment the lexer for Order and match question;
|
|
||||||
- [ ] Parse the questions accordingly;
|
|
||||||
- [ ] Escape character;
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user