mirror of
https://github.com/jorenchik/mdemory.git
synced 2026-03-22 00:26:21 +00:00
flashcard training widget drafts
This commit is contained in:
8
src/cpp/include/trainWindow.h
Normal file
8
src/cpp/include/trainWindow.h
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
|
||||||
|
#include <QMainWindow>
|
||||||
|
|
||||||
|
extern QMainWindow *trainWindow;
|
||||||
|
|
||||||
|
void initTrainWindow();
|
||||||
Binary file not shown.
@@ -15,6 +15,7 @@ find_package(Qt5 COMPONENTS Widgets REQUIRED)
|
|||||||
add_executable(
|
add_executable(
|
||||||
MdemoryApp
|
MdemoryApp
|
||||||
main.cpp
|
main.cpp
|
||||||
|
trainWindow.cpp
|
||||||
)
|
)
|
||||||
|
|
||||||
target_link_libraries(MdemoryApp Qt5::Widgets api)
|
target_link_libraries(MdemoryApp Qt5::Widgets api)
|
||||||
|
|||||||
@@ -5,7 +5,11 @@
|
|||||||
#include <qabstractbutton.h>
|
#include <qabstractbutton.h>
|
||||||
#include <qlabel.h>
|
#include <qlabel.h>
|
||||||
#include <qlayoutitem.h>
|
#include <qlayoutitem.h>
|
||||||
|
#include <qmainwindow.h>
|
||||||
#include <qobjectdefs.h>
|
#include <qobjectdefs.h>
|
||||||
|
#include <qtoolbutton.h>
|
||||||
|
#include <qwindow.h>
|
||||||
|
#include <qwindowdefs.h>
|
||||||
#include <regex>
|
#include <regex>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
@@ -27,10 +31,12 @@
|
|||||||
#include <QRegularExpression>
|
#include <QRegularExpression>
|
||||||
#include <QStringList>
|
#include <QStringList>
|
||||||
#include <QListView>
|
#include <QListView>
|
||||||
|
#include <QWindow>
|
||||||
#include <qabstractitemmodel.h>
|
#include <qabstractitemmodel.h>
|
||||||
|
|
||||||
#include "api.h"
|
#include "api.h"
|
||||||
#include "parser.h"
|
#include "parser.h"
|
||||||
|
#include "trainWindow.h"
|
||||||
|
|
||||||
struct Page {
|
struct Page {
|
||||||
int start;
|
int start;
|
||||||
@@ -131,6 +137,7 @@ public:
|
|||||||
|
|
||||||
|
|
||||||
QString workingPath = "/home/jorenchik/Code/mdemory/memorybase";
|
QString workingPath = "/home/jorenchik/Code/mdemory/memorybase";
|
||||||
|
std::string currentPath = "";
|
||||||
QList<Mdem*> mdems = QList<Mdem*>();
|
QList<Mdem*> mdems = QList<Mdem*>();
|
||||||
std::vector<Question*> questions = std::vector<Question*>();
|
std::vector<Question*> questions = std::vector<Question*>();
|
||||||
QLabel *deckListLabel;
|
QLabel *deckListLabel;
|
||||||
@@ -140,13 +147,17 @@ QSpacerItem *mdemSpacer;
|
|||||||
const int PER_PAGE = 8;
|
const int PER_PAGE = 8;
|
||||||
int currentPage = -1;
|
int currentPage = -1;
|
||||||
std::vector<Page> pages;
|
std::vector<Page> pages;
|
||||||
|
QList<QToolButton*> paginationButtons;
|
||||||
QToolButton* prevButton;
|
QToolButton* prevButton;
|
||||||
QToolButton* firstButton;
|
QToolButton* firstButton;
|
||||||
QToolButton* lastButton;
|
QToolButton* lastButton;
|
||||||
QToolButton* nextButton;
|
QToolButton* nextButton;
|
||||||
QList<QToolButton*> paginationButtons;
|
|
||||||
QLabel* paginationLabel;
|
QLabel* paginationLabel;
|
||||||
|
|
||||||
|
QToolButton *load;
|
||||||
|
QToolButton *practice;
|
||||||
|
|
||||||
|
|
||||||
const std::regex doubleSpaceExp(
|
const std::regex doubleSpaceExp(
|
||||||
" ",
|
" ",
|
||||||
std::regex_constants::ECMAScript | std::regex_constants::icase
|
std::regex_constants::ECMAScript | std::regex_constants::icase
|
||||||
@@ -313,6 +324,35 @@ void SwitchPage(int pageIdx) {
|
|||||||
CreateMdems(pageSlice);
|
CreateMdems(pageSlice);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void loadMdem() {
|
||||||
|
auto file = std::ifstream(currentPath);
|
||||||
|
std::string content;
|
||||||
|
if (file) {
|
||||||
|
std::stringstream buffer;
|
||||||
|
buffer << file.rdbuf();
|
||||||
|
content = buffer.str();
|
||||||
|
auto parseRes = Transpile(content, true);
|
||||||
|
for (auto question: questions) {
|
||||||
|
delete question;
|
||||||
|
}
|
||||||
|
questions.clear();
|
||||||
|
if (parseRes.error == "") {
|
||||||
|
questions = parseRes.value;
|
||||||
|
makePages();
|
||||||
|
SwitchPage(0);
|
||||||
|
} else {
|
||||||
|
std::cout << "Compilation error." << std::endl;
|
||||||
|
for (auto mdem: mdems) {
|
||||||
|
if (mdem->wMdem->isVisible()) {
|
||||||
|
mdem->wMdem->hide();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
std::cout << std::format("Could not open the file: {}", currentPath) << std::endl;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
int main(int argc, char *argv[]) {
|
int main(int argc, char *argv[]) {
|
||||||
QApplication app(argc, argv);
|
QApplication app(argc, argv);
|
||||||
QMainWindow window;
|
QMainWindow window;
|
||||||
@@ -331,30 +371,16 @@ int main(int argc, char *argv[]) {
|
|||||||
leftWidget->setLayout(leftLayout);
|
leftWidget->setLayout(leftLayout);
|
||||||
leftLayout->addWidget(mdemLabel);
|
leftLayout->addWidget(mdemLabel);
|
||||||
model->setRootPath(workingPath);
|
model->setRootPath(workingPath);
|
||||||
|
// Hide all columns except the first one
|
||||||
mdemList->setModel(model);
|
mdemList->setModel(model);
|
||||||
|
|
||||||
QObject::connect(
|
QObject::connect(
|
||||||
mdemList,
|
mdemList,
|
||||||
&QTreeView::doubleClicked,
|
&QTreeView::doubleClicked,
|
||||||
[model](const QModelIndex &index) {
|
[model](const QModelIndex &index) {
|
||||||
auto fileInfo = model->fileInfo(index);
|
auto fileInfo = model->fileInfo(index);
|
||||||
auto path = fileInfo.filePath().toStdString();
|
currentPath = fileInfo.filePath().toStdString();
|
||||||
auto file = std::ifstream(path);
|
loadMdem();
|
||||||
std::string content;
|
|
||||||
if (file) {
|
|
||||||
std::stringstream buffer;
|
|
||||||
buffer << file.rdbuf();
|
|
||||||
content = buffer.str();
|
|
||||||
auto parseRes = Transpile(content, true);
|
|
||||||
for (auto question: questions) {
|
|
||||||
delete question;
|
|
||||||
}
|
|
||||||
questions.clear();
|
|
||||||
questions = parseRes.value;
|
|
||||||
makePages();
|
|
||||||
SwitchPage(0);
|
|
||||||
} else {
|
|
||||||
std::cout << std::format("Could not open the file: {}", path) << std::endl;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -362,8 +388,13 @@ int main(int argc, char *argv[]) {
|
|||||||
"/home/jorenchik/Code/mdemory/memorybase"
|
"/home/jorenchik/Code/mdemory/memorybase"
|
||||||
);
|
);
|
||||||
mdemList->setRootIndex(rootIndex);
|
mdemList->setRootIndex(rootIndex);
|
||||||
|
for (int col = 1; col < model->columnCount(); ++col) {
|
||||||
|
mdemList->hideColumn(col);
|
||||||
|
}
|
||||||
|
model->setHeaderData(0, Qt::Horizontal, QObject::tr("Custom Name"));
|
||||||
leftLayout->addWidget(mdemList);
|
leftLayout->addWidget(mdemList);
|
||||||
|
|
||||||
|
|
||||||
// DeckList
|
// DeckList
|
||||||
QLabel *deckLabel = new QLabel("Decks");
|
QLabel *deckLabel = new QLabel("Decks");
|
||||||
QListView *deckList = new QListView();
|
QListView *deckList = new QListView();
|
||||||
@@ -384,18 +415,16 @@ int main(int argc, char *argv[]) {
|
|||||||
hTop->addWidget(deckListLabel);
|
hTop->addWidget(deckListLabel);
|
||||||
hTop->addStretch(1);
|
hTop->addStretch(1);
|
||||||
|
|
||||||
QToolButton *refresh = new QToolButton();
|
load = new QToolButton();
|
||||||
QToolButton *practice = new QToolButton();
|
practice = new QToolButton();
|
||||||
QToolButton *shuffle = new QToolButton();
|
|
||||||
|
|
||||||
hTop->addWidget(refresh);
|
hTop->addWidget(load);
|
||||||
hTop->addWidget(shuffle);
|
|
||||||
hTop->addWidget(practice);
|
hTop->addWidget(practice);
|
||||||
|
|
||||||
// Buttons
|
// Buttons
|
||||||
refresh->setText("Refresh");
|
load->setText("Load");
|
||||||
shuffle->setText("Shuffle");
|
|
||||||
practice->setText("Practice");
|
practice->setText("Practice");
|
||||||
|
QObject::connect(load, &QToolButton::clicked, &loadMdem);
|
||||||
|
|
||||||
// Mdems
|
// Mdems
|
||||||
QScrollArea *mdemScroll = new QScrollArea();
|
QScrollArea *mdemScroll = new QScrollArea();
|
||||||
@@ -477,7 +506,17 @@ int main(int argc, char *argv[]) {
|
|||||||
hPagination->addWidget(paginationLabel);
|
hPagination->addWidget(paginationLabel);
|
||||||
rightLayout->addWidget(pagination);
|
rightLayout->addWidget(pagination);
|
||||||
|
|
||||||
|
initTrainWindow();
|
||||||
|
QObject::connect(
|
||||||
|
practice,
|
||||||
|
&QToolButton::clicked,
|
||||||
|
[](bool checked) {
|
||||||
|
trainWindow->show();
|
||||||
|
trainWindow->resize(600, 300);
|
||||||
|
});
|
||||||
|
|
||||||
window.setCentralWidget(hSplitter);
|
window.setCentralWidget(hSplitter);
|
||||||
window.show();
|
window.show();
|
||||||
|
|
||||||
return app.exec();
|
return app.exec();
|
||||||
}
|
}
|
||||||
|
|||||||
237
src/cpp/qtapp/trainWindow.cpp
Normal file
237
src/cpp/qtapp/trainWindow.cpp
Normal file
@@ -0,0 +1,237 @@
|
|||||||
|
#include <QMainWindow>
|
||||||
|
#include <QWidget>
|
||||||
|
#include <QToolButton>
|
||||||
|
#include <qboxlayout.h>
|
||||||
|
#include <qlabel.h>
|
||||||
|
#include <qlistview.h>
|
||||||
|
#include <qnamespace.h>
|
||||||
|
#include <qstandarditemmodel.h>
|
||||||
|
#include <qstringlistmodel.h>
|
||||||
|
#include <qtoolbutton.h>
|
||||||
|
#include <Qt>
|
||||||
|
#include <qwidget.h>
|
||||||
|
#include <QStandardItemModel>
|
||||||
|
#include <QDropEvent>
|
||||||
|
|
||||||
|
#include "trainWindow.h"
|
||||||
|
|
||||||
|
QWidget *wMaster;
|
||||||
|
QVBoxLayout *hMaster;
|
||||||
|
|
||||||
|
QWidget *questionBox;
|
||||||
|
QVBoxLayout *vQuestionBox;
|
||||||
|
QLabel *lQuestionText;
|
||||||
|
QLabel *answerText;
|
||||||
|
|
||||||
|
QVBoxLayout *vButtonBox;
|
||||||
|
QWidget *actionButtons;
|
||||||
|
QHBoxLayout *hButtons;
|
||||||
|
QToolButton *btnPrev;
|
||||||
|
QToolButton *btnShowAnswer;
|
||||||
|
QToolButton *btnNext;
|
||||||
|
|
||||||
|
QMainWindow *trainWindow;
|
||||||
|
QWidget *trainWidget;
|
||||||
|
QVBoxLayout *vTrainWidget;
|
||||||
|
|
||||||
|
class CustomListView : public QListView
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
public:
|
||||||
|
explicit CustomListView(QWidget *parent = nullptr) : QListView(parent) {}
|
||||||
|
|
||||||
|
protected:
|
||||||
|
void dropEvent(QDropEvent *event) override
|
||||||
|
{
|
||||||
|
QModelIndex sourceIndex = currentIndex();
|
||||||
|
QModelIndex targetIndex = indexAt(event->pos());
|
||||||
|
|
||||||
|
if (sourceIndex.isValid() && targetIndex.isValid()) {
|
||||||
|
QStandardItemModel *model = qobject_cast<QStandardItemModel *>(this->model());
|
||||||
|
if (model) {
|
||||||
|
QVariant sourceData = model->data(sourceIndex);
|
||||||
|
QVariant targetData = model->data(targetIndex);
|
||||||
|
model->setData(sourceIndex, targetData);
|
||||||
|
model->setData(targetIndex, sourceData);
|
||||||
|
event->ignore();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
event->ignore();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
#include "trainWindow.moc"
|
||||||
|
|
||||||
|
void initTrainWindow() {
|
||||||
|
// # Types of question
|
||||||
|
//
|
||||||
|
// - AnswerQuestion:
|
||||||
|
// One answer (could be on multiple lines).
|
||||||
|
// - ChoiceQuestion:
|
||||||
|
// One or many correct answers that are showed to user.
|
||||||
|
// - OrderQuestion:
|
||||||
|
// Many items that should be ordered in a list.
|
||||||
|
// - MatchQuestion:
|
||||||
|
// Match some items to other items.
|
||||||
|
|
||||||
|
trainWindow = new QMainWindow();
|
||||||
|
trainWidget = new QWidget();
|
||||||
|
vTrainWidget = new QVBoxLayout();
|
||||||
|
|
||||||
|
/*wMaster = new QWidget();*/
|
||||||
|
/*hMaster = new QVBoxLayout();*/
|
||||||
|
trainWidget->setLayout(vTrainWidget);
|
||||||
|
trainWindow->setCentralWidget(trainWidget);
|
||||||
|
trainWidget->setLayout(vTrainWidget);
|
||||||
|
vTrainWidget->setAlignment(Qt::AlignCenter);
|
||||||
|
trainWidget->setObjectName("answer-question-widget");
|
||||||
|
|
||||||
|
{ // Make the question box.
|
||||||
|
vQuestionBox = new QVBoxLayout();
|
||||||
|
questionBox = new QWidget();
|
||||||
|
questionBox->setLayout(vQuestionBox);
|
||||||
|
questionBox->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Expanding);
|
||||||
|
vQuestionBox->setAlignment(Qt::AlignCenter);
|
||||||
|
}
|
||||||
|
|
||||||
|
{ // Make question text.
|
||||||
|
lQuestionText = new QLabel();
|
||||||
|
lQuestionText->setText("What is the capital of Latvia?");
|
||||||
|
lQuestionText->setWordWrap(true);
|
||||||
|
lQuestionText->setStyleSheet(QString(
|
||||||
|
"QLabel {"
|
||||||
|
"font-size: 20px;"
|
||||||
|
"}"
|
||||||
|
));
|
||||||
|
lQuestionText->setTextInteractionFlags(Qt::TextSelectableByMouse);
|
||||||
|
vQuestionBox->addWidget(lQuestionText);
|
||||||
|
}
|
||||||
|
|
||||||
|
{ // Make answer text.
|
||||||
|
answerText = new QLabel();
|
||||||
|
answerText->setText("- Riga\n- Second line");
|
||||||
|
answerText->setWordWrap(true);
|
||||||
|
answerText->hide();
|
||||||
|
answerText->setStyleSheet(QString(
|
||||||
|
"QLabel {"
|
||||||
|
"font-size: 15px;"
|
||||||
|
"}"
|
||||||
|
));
|
||||||
|
answerText->setTextInteractionFlags(Qt::TextSelectableByMouse);
|
||||||
|
vQuestionBox->addWidget(answerText);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
auto listStyle =
|
||||||
|
"QListView {"
|
||||||
|
" background-color: white;"
|
||||||
|
" border: 1px solid black;"
|
||||||
|
"}"
|
||||||
|
"QListView::item::first {"
|
||||||
|
" padding: 5px 0 0 0;"
|
||||||
|
"}"
|
||||||
|
"QListView::item {"
|
||||||
|
" color: blue;"
|
||||||
|
" padding: 5px;"
|
||||||
|
" border: 1px solid gray;"
|
||||||
|
" background-color: white;"
|
||||||
|
"}"
|
||||||
|
"QListView::item:selected {"
|
||||||
|
"}"
|
||||||
|
"QListView::item:hover {"
|
||||||
|
" background-color: lightyellow;"
|
||||||
|
"}";
|
||||||
|
|
||||||
|
{ // Make multi-choice list.
|
||||||
|
auto *multiChoiceModel = new QStandardItemModel();
|
||||||
|
QListView *listView = new QListView();
|
||||||
|
listView->setModel(multiChoiceModel);
|
||||||
|
|
||||||
|
auto *firstItem = new QStandardItem();
|
||||||
|
firstItem->setText("Item 1");
|
||||||
|
firstItem->setCheckable(true);
|
||||||
|
auto *secondItem = new QStandardItem();
|
||||||
|
secondItem->setText("Item 2");
|
||||||
|
secondItem->setCheckable(true);
|
||||||
|
multiChoiceModel->setItem(0, firstItem);
|
||||||
|
multiChoiceModel->setItem(1, secondItem);
|
||||||
|
|
||||||
|
listView->setStyleSheet(listStyle);
|
||||||
|
|
||||||
|
questionBox->layout()->addWidget(listView);
|
||||||
|
listView->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Minimum);
|
||||||
|
listView->setEditTriggers(QAbstractItemView::NoEditTriggers);
|
||||||
|
}
|
||||||
|
|
||||||
|
{ // Make order list.
|
||||||
|
auto *orderModel = new QStandardItemModel();
|
||||||
|
QListView *orderList = new CustomListView();
|
||||||
|
orderList->setModel(orderModel);
|
||||||
|
|
||||||
|
auto *firstItem = new QStandardItem();
|
||||||
|
firstItem->setText("Item 1");
|
||||||
|
auto *secondItem = new QStandardItem();
|
||||||
|
secondItem->setText("Item 2");
|
||||||
|
auto *thirdItem = new QStandardItem();
|
||||||
|
thirdItem->setText("Item 3");
|
||||||
|
orderModel->setItem(0, firstItem);
|
||||||
|
orderModel->setItem(1, secondItem);
|
||||||
|
orderModel->setItem(2, thirdItem);
|
||||||
|
|
||||||
|
|
||||||
|
questionBox->layout()->addWidget(orderList);
|
||||||
|
orderList->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Minimum);
|
||||||
|
orderList->setEditTriggers(QAbstractItemView::NoEditTriggers);
|
||||||
|
orderList->setDragDropMode(QAbstractItemView::InternalMove);
|
||||||
|
orderList->setFocusPolicy(Qt::NoFocus);
|
||||||
|
|
||||||
|
orderList->setStyleSheet(listStyle);
|
||||||
|
|
||||||
|
// Connect to handle the drop event properly
|
||||||
|
QObject::connect(
|
||||||
|
orderModel,
|
||||||
|
&QStandardItemModel::rowsMoved,
|
||||||
|
[orderModel](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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
{ // Make buttons menu. There are left middle and right buttons.
|
||||||
|
vButtonBox = new QVBoxLayout();
|
||||||
|
actionButtons = new QWidget();
|
||||||
|
hButtons = new QHBoxLayout();
|
||||||
|
btnPrev = new QToolButton();
|
||||||
|
btnShowAnswer = new QToolButton();
|
||||||
|
btnNext = new QToolButton();
|
||||||
|
|
||||||
|
hButtons->addWidget(btnPrev);
|
||||||
|
hButtons->addWidget(btnShowAnswer);
|
||||||
|
hButtons->addWidget(btnNext);
|
||||||
|
vButtonBox->addWidget(actionButtons);
|
||||||
|
actionButtons->setLayout(hButtons);
|
||||||
|
btnPrev->setText("Previous");
|
||||||
|
btnShowAnswer->setText("Show answer");
|
||||||
|
btnNext->setText("Next");
|
||||||
|
QObject::connect(btnShowAnswer, &QToolButton::clicked, [](bool checked) {
|
||||||
|
answerText->show();
|
||||||
|
btnShowAnswer->hide();
|
||||||
|
});
|
||||||
|
actionButtons->setStyleSheet(QString(
|
||||||
|
"QToolButton {"
|
||||||
|
"padding: 4px 5px;"
|
||||||
|
"font-size: 15px;"
|
||||||
|
"}"
|
||||||
|
));
|
||||||
|
questionBox->setObjectName("question-box");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
vTrainWidget->addWidget(questionBox);
|
||||||
|
vTrainWidget->addWidget(actionButtons);
|
||||||
|
vTrainWidget->addWidget(wMaster);
|
||||||
|
}
|
||||||
Binary file not shown.
Reference in New Issue
Block a user