File indexing completed on 2024-04-14 03:49:10

0001 /*
0002     SPDX-FileCopyrightText: 2009 Daniel Laidig <d.laidig@gmx.de>
0003     SPDX-License-Identifier: GPL-2.0-or-later
0004 */
0005 
0006 #include "guifrontend.h"
0007 
0008 #include <QTimer>
0009 
0010 #include <KColorScheme>
0011 #include <KLocalizedString>
0012 #include <QDebug>
0013 
0014 #include "ui_practice_mainwindow.h"
0015 
0016 #include "comparisonmodewidget.h"
0017 #include "conjugationmodewidget.h"
0018 #include "flashcardmodewidget.h"
0019 #include "mixedlettersmodewidget.h"
0020 #include "multiplechoicemodewidget.h"
0021 #include "settings/kgametheme/kgametheme.h"
0022 #include "themedbackgroundrenderer.h"
0023 #include "writtenpracticewidget.h"
0024 
0025 using namespace Practice;
0026 
0027 GuiFrontend::GuiFrontend(QWidget *parent)
0028     : AbstractFrontend(parent)
0029     , m_widget(new ImageWidget())
0030     , m_ui(new Ui::PracticeMainWindow())
0031     , m_resultState(AbstractFrontend::AnswerWrong)
0032     , m_feedbackState(AbstractFrontend::AnswerWrong)
0033     , m_themedBackgroundRenderer(new ThemedBackgroundRenderer(this, QStringLiteral("practicethemecache.bin")))
0034 {
0035     m_widget->setScalingEnabled(false, false);
0036     m_widget->setKeepAspectRatio(Qt::IgnoreAspectRatio);
0037     m_widget->setFadingEnabled(false);
0038 
0039     m_ui->setupUi(m_widget);
0040     m_ui->centralPracticeWidget->setLayout(new QHBoxLayout());
0041 
0042     connect(Prefs::self(), &Prefs::configChanged, this, &GuiFrontend::setTheme);
0043     setTheme();
0044 
0045     connect(m_themedBackgroundRenderer, &ThemedBackgroundRenderer::backgroundChanged, this, &GuiFrontend::backgroundChanged);
0046     connect(m_widget, &ImageWidget::sizeChanged, this, &GuiFrontend::updateBackground);
0047 
0048     connect(m_ui->continueButton, &QPushButton::clicked, this, &GuiFrontend::continueAction);
0049     connect(m_ui->answerLaterButton, &QPushButton::clicked, this, &GuiFrontend::skipAction);
0050     connect(m_ui->hintButton, &QPushButton::clicked, this, &GuiFrontend::hintAction);
0051     connect(m_ui->statusToggle, &Practice::StatusToggle::toggle, this, &GuiFrontend::toggleResultState);
0052     connect(m_ui->countAsCorrectButton, &QPushButton::clicked, this, &GuiFrontend::countAsCorrectButtonClicked);
0053     connect(m_ui->countAsWrongButton, &QPushButton::clicked, this, &GuiFrontend::countAsWrongButtonClicked);
0054 
0055     m_ui->centralPracticeWidget->installEventFilter(this);
0056     m_ui->imageWidget->installEventFilter(this);
0057     m_ui->rightContainer->installEventFilter(this);
0058 
0059     QTimer::singleShot(0, this, &GuiFrontend::updateBackground);
0060 }
0061 
0062 GuiFrontend::~GuiFrontend()
0063 {
0064     delete m_widget;
0065     delete m_ui;
0066 }
0067 
0068 QVariant GuiFrontend::userInput()
0069 {
0070     return m_modeWidget->userInput();
0071 }
0072 
0073 QWidget *GuiFrontend::widget()
0074 {
0075     return m_widget;
0076 }
0077 
0078 void GuiFrontend::setMode(Mode mode)
0079 {
0080     qDebug() << "setCentralWidget" << mode;
0081     AbstractModeWidget *newWidget = nullptr;
0082     switch (mode) {
0083     case Written:
0084         if (/*m_modeWidget->metaObject()->className() == QLatin1String("WrittenPracticeWidget")*/ false) {
0085             qDebug() << "Written practice widget is already the central widget";
0086             break;
0087         }
0088         newWidget = new WrittenPracticeWidget(this, m_widget);
0089         break;
0090     case MultipleChoice:
0091         newWidget = new MultiplechoiceModeWidget(this, m_widget);
0092         break;
0093     case FlashCard:
0094         newWidget = new FlashCardModeWidget(this, m_widget);
0095         break;
0096     case MixedLetters:
0097         newWidget = new MixedLettersModeWidget(this, m_widget);
0098         break;
0099     case Conjugation:
0100         newWidget = new ConjugationModeWidget(this, m_widget);
0101         break;
0102     case Comparison:
0103         newWidget = new ComparisonModeWidget(this, m_widget);
0104         break;
0105     case ExampleSentence:
0106         newWidget = new WrittenPracticeWidget(this, m_widget, true);
0107         break;
0108     default:
0109         Q_ASSERT("Practice Mode Invalid" == nullptr);
0110     }
0111     if (newWidget) {
0112         m_ui->centralPracticeWidget->layout()->addWidget(newWidget);
0113         delete m_modeWidget;
0114         m_modeWidget = newWidget;
0115         connect(m_modeWidget, SIGNAL(continueAction()), m_ui->continueButton, SLOT(animateClick()));
0116     }
0117     m_ui->buttonStack->setCurrentIndex(0);
0118     updateFontColors();
0119 }
0120 
0121 void GuiFrontend::setLessonName(const QString &lessonName)
0122 {
0123     m_ui->lessonLabel->setText(i18nc("Display of the current unit during practice", "Unit: %1", lessonName));
0124 }
0125 
0126 void GuiFrontend::showGrade(int preGrade, int grade)
0127 {
0128     if (preGrade == 0 && grade == 0) {
0129         m_ui->gradeLabel->setText(i18n("New word"));
0130     } else {
0131         m_ui->gradeLabel->setText(i18nc("Display of the current confidence level during practice, 1st param is either initial or long term",
0132                                         "%1, confidence %2",
0133                                         grade == 0 ? i18n("initial") : i18n("long term"),
0134                                         QString::number(grade == 0 ? preGrade : grade)));
0135     }
0136 }
0137 
0138 void GuiFrontend::showQuestion()
0139 {
0140     m_ui->answerLaterButton->setEnabled(true);
0141     m_ui->hintButton->setEnabled(Prefs::showHints());
0142     QTimer::singleShot(0, m_ui->continueButton, SLOT(setFocus()));
0143     m_modeWidget->showQuestion();
0144     setImage(m_questionImage);
0145 }
0146 
0147 void GuiFrontend::showSolution()
0148 {
0149     m_ui->continueButton->setFocus();
0150     m_modeWidget->showSolution();
0151     m_ui->answerLaterButton->setEnabled(false);
0152     m_ui->hintButton->setEnabled(false);
0153     setImage(m_solutionImage);
0154 }
0155 void GuiFrontend::setSynonym(const QString &entry)
0156 {
0157     m_modeWidget->setSynonym(entry);
0158 }
0159 
0160 void GuiFrontend::showSynonym()
0161 {
0162     m_modeWidget->showSynonym();
0163 }
0164 
0165 void GuiFrontend::setBoxes(grade_t currentBox, grade_t newBoxIfCorrect, grade_t newBoxIfWrong)
0166 {
0167     m_ui->boxesWidget->setBoxes(currentBox, 0);
0168     m_currentBox = currentBox;
0169     m_newBoxIfCorrect = newBoxIfCorrect;
0170     m_newBoxIfWrong = newBoxIfWrong;
0171 }
0172 
0173 void GuiFrontend::backgroundChanged(const QPixmap &pixmap)
0174 {
0175     m_widget->setPixmap(pixmap);
0176 }
0177 
0178 void GuiFrontend::showSetResultButtons(bool show)
0179 {
0180     m_ui->buttonStack->setCurrentIndex(int(show));
0181     if (show) {
0182         m_ui->countAsCorrectButton->setFocus();
0183     }
0184 }
0185 
0186 bool GuiFrontend::eventFilter(QObject *object, QEvent *event)
0187 {
0188     if (event->type() == QEvent::Resize)
0189         updateBackground();
0190     return AbstractFrontend::eventFilter(object, event);
0191 }
0192 
0193 void GuiFrontend::setFinishedWordsTotalWords(int finished, int total)
0194 {
0195     int finishedPercentage = 1.0 * finished / total * 100;
0196     // update progress bar
0197     m_ui->totalProgress->setMaximum(total);
0198     m_ui->totalProgress->setValue(finished);
0199     m_ui->totalProgress->setToolTip(i18np("You answered correctly %2 of a total of %1 word.\nYou are %3% done.",
0200                                           "You answered correctly %2 of a total of %1 words.\nYou are %3% done.",
0201                                           total,
0202                                           finished,
0203                                           finishedPercentage));
0204 }
0205 
0206 QFont GuiFrontend::knownLangFont() const
0207 {
0208     return m_knownLangFont;
0209 }
0210 
0211 QFont GuiFrontend::learningLangFont() const
0212 {
0213     return m_learningLangFont;
0214 }
0215 
0216 void GuiFrontend::setKnownLangFont(const QFont &font)
0217 {
0218     m_knownLangFont = font;
0219 }
0220 
0221 void GuiFrontend::setLearningLangFont(const QFont &font)
0222 {
0223     m_learningLangFont = font;
0224 }
0225 
0226 void GuiFrontend::setHint(const QVariant &hint)
0227 {
0228     m_modeWidget->setHint(hint);
0229 }
0230 
0231 void GuiFrontend::setQuestion(const QVariant &question)
0232 {
0233     m_modeWidget->setQuestion(question);
0234 }
0235 
0236 void GuiFrontend::setQuestionPronunciation(const QString &pronunciationText)
0237 {
0238     m_modeWidget->setQuestionPronunciation(pronunciationText);
0239 }
0240 
0241 void GuiFrontend::setQuestionSound(const QUrl &soundUrl)
0242 {
0243     m_modeWidget->setQuestionSound(soundUrl);
0244 }
0245 
0246 void GuiFrontend::setSolution(const QVariant &solution)
0247 {
0248     m_modeWidget->setSolution(solution);
0249 }
0250 
0251 void GuiFrontend::setQuestionImage(const QUrl &image)
0252 {
0253     m_questionImage = image;
0254 }
0255 
0256 void GuiFrontend::setSolutionImage(const QUrl &image)
0257 {
0258     m_solutionImage = image;
0259 }
0260 
0261 void GuiFrontend::setQuestionFont(const QFont &font)
0262 {
0263     m_modeWidget->setQuestionFont(font);
0264 }
0265 
0266 void GuiFrontend::setSolutionFont(const QFont &font)
0267 {
0268     m_modeWidget->setSolutionFont(font);
0269 }
0270 
0271 void GuiFrontend::setImage(const QUrl &image)
0272 {
0273     if (m_lastImage == image) {
0274         return;
0275     }
0276     QPixmap pixmap(image.path());
0277     if (pixmap.isNull()) {
0278         m_ui->imageWidget->setPixmap(m_themedBackgroundRenderer->getPixmapForId(QStringLiteral("image-placeholder"), QSize(150, 150)));
0279     } else {
0280         m_ui->imageWidget->setPixmap(pixmap);
0281     }
0282     m_lastImage = image;
0283 }
0284 
0285 void GuiFrontend::setSolutionPronunciation(const QString &pronunciationText)
0286 {
0287     m_modeWidget->setSolutionPronunciation(pronunciationText);
0288 }
0289 
0290 void GuiFrontend::setSolutionSound(const QUrl &soundUrl)
0291 {
0292     m_modeWidget->setSolutionSound(soundUrl);
0293 }
0294 
0295 void GuiFrontend::setFeedback(const QVariant &feedback)
0296 {
0297     m_modeWidget->setFeedback(feedback);
0298 }
0299 
0300 void GuiFrontend::setFeedbackState(ResultState feedbackState)
0301 {
0302     m_feedbackState = feedbackState;
0303     m_modeWidget->setFeedbackState(feedbackState);
0304 }
0305 
0306 void GuiFrontend::setResultState(ResultState resultState)
0307 {
0308     // TODO: temporary text labels instead of graphics
0309     //    m_ui->statusImageLabel->setFont(QFont("", 80, QFont::Bold));
0310     m_ui->statusToggle->setResultState(resultState);
0311     switch (resultState) {
0312     case AbstractFrontend::QuestionState:
0313     case AbstractFrontend::AnswerSynonym:
0314         //        m_ui->statusImageLabel->setText("?");
0315         //        m_ui->toggleButton->setEnabled(false);
0316         //        m_ui->toggleButton->setText(QString(0x2717)+QChar(0x2192)+QChar(0x2713));
0317         m_ui->boxesWidget->setBoxes(m_currentBox);
0318         break;
0319     case AbstractFrontend::AnswerCorrect:
0320         //        m_ui->statusImageLabel->setText(QChar(0x2713));
0321         //        m_ui->toggleButton->setEnabled(true);
0322         //        m_ui->toggleButton->setText(QString(0x2713)+QChar(0x2192)+QChar(0x2717));
0323         m_ui->boxesWidget->setBoxes(m_newBoxIfCorrect, m_currentBox);
0324         break;
0325 
0326         //        m_ui->statusImageLabel->setText("?");
0327         //        m_ui->toggleButton->setEnabled(true);
0328         //        m_ui->toggleButton->setText(QString(0x2713)+QChar(0x2192)+QChar(0x2717));
0329         //        m_ui->boxesWidget->setBoxes(m_currentBox);
0330         //        break;
0331     case AbstractFrontend::AnswerWrong:
0332         //        m_ui->statusImageLabel->setText(QChar(0x2717));
0333         //        m_ui->toggleButton->setEnabled(true);
0334         //        m_ui->toggleButton->setText(QString(0x2717)+QChar(0x2192)+QChar(0x2713));
0335         m_ui->boxesWidget->setBoxes(m_newBoxIfWrong, m_currentBox);
0336         break;
0337     }
0338 
0339     m_resultState = resultState;
0340     m_modeWidget->setResultState(resultState);
0341 }
0342 
0343 AbstractFrontend::ResultState GuiFrontend::resultState()
0344 {
0345     return m_resultState;
0346 }
0347 
0348 void GuiFrontend::countAsCorrectButtonClicked()
0349 {
0350     m_resultState = AnswerCorrect;
0351     Q_EMIT continueAction();
0352 }
0353 
0354 void GuiFrontend::countAsWrongButtonClicked()
0355 {
0356     m_resultState = AnswerWrong;
0357     Q_EMIT continueAction();
0358 }
0359 
0360 void GuiFrontend::toggleResultState()
0361 {
0362     if (resultState() == AnswerWrong) {
0363         setResultState(AnswerCorrect);
0364     } else {
0365         setResultState(AnswerWrong);
0366     }
0367 }
0368 
0369 void GuiFrontend::updateBackground()
0370 {
0371     m_themedBackgroundRenderer->clearRects();
0372     m_themedBackgroundRenderer->addRect(QStringLiteral("background"), QRect(QPoint(), m_widget->size()));
0373     m_themedBackgroundRenderer->addRect(QStringLiteral("image"), m_ui->imageWidget->frameGeometry());
0374     m_themedBackgroundRenderer->addRect(QStringLiteral("central"), m_ui->centralPracticeWidget->frameGeometry());
0375     m_themedBackgroundRenderer->addRect(QStringLiteral("buttons"), m_ui->rightContainer->frameGeometry());
0376     QPixmap pixmap = m_themedBackgroundRenderer->getScaledBackground();
0377     if (!pixmap.isNull()) {
0378         m_widget->setPixmap(pixmap);
0379     }
0380     m_themedBackgroundRenderer->updateBackground();
0381 }
0382 
0383 void GuiFrontend::updateFontColors()
0384 {
0385     QPalette p(QApplication::palette());
0386     QColor c = m_themedBackgroundRenderer->fontColor(QStringLiteral("Outer"), p.color(QPalette::Active, QPalette::WindowText));
0387     p.setColor(QPalette::WindowText, c);
0388     m_ui->lessonLabel->setPalette(p);
0389     m_ui->gradeLabel->setPalette(p);
0390 
0391     if (m_modeWidget) {
0392         p = QApplication::palette();
0393         c = m_themedBackgroundRenderer->fontColor(QStringLiteral("Central"), p.color(QPalette::Active, QPalette::WindowText));
0394         p.setColor(QPalette::Active, QPalette::WindowText, c);
0395         p.setColor(QPalette::Inactive, QPalette::WindowText, c);
0396         m_modeWidget->setPalette(p);
0397 
0398         KColorScheme scheme(QPalette::Active);
0399         QPalette correctPalette = QApplication::palette();
0400         c = m_themedBackgroundRenderer->fontColor(QStringLiteral("Correct"), scheme.foreground(KColorScheme::PositiveText).color());
0401         correctPalette.setColor(QPalette::WindowText, c);
0402         correctPalette.setColor(QPalette::Text, scheme.foreground(KColorScheme::PositiveText).color());
0403         QPalette wrongPalette = QApplication::palette();
0404         c = m_themedBackgroundRenderer->fontColor(QStringLiteral("Wrong"), scheme.foreground(KColorScheme::NegativeText).color());
0405         wrongPalette.setColor(QPalette::WindowText, c);
0406         wrongPalette.setColor(QPalette::Text, scheme.foreground(KColorScheme::NegativeText).color());
0407 
0408         m_modeWidget->setResultPalettes(correctPalette, wrongPalette);
0409     }
0410 }
0411 
0412 void GuiFrontend::setTheme()
0413 {
0414     m_themedBackgroundRenderer->setTheme(Prefs::theme());
0415     updateFontColors();
0416     updateBackground();
0417     m_widget->setContentsMargins(m_themedBackgroundRenderer->contentMargins());
0418     m_ui->boxesWidget->setRenderer(m_themedBackgroundRenderer);
0419     m_ui->statusToggle->setRenderer(m_themedBackgroundRenderer);
0420 }
0421 
0422 #include "moc_guifrontend.cpp"