File indexing completed on 2024-04-21 03:42:03

0001 /*
0002     SPDX-FileCopyrightText: 2001-2008 Anne-Marie Mahfouf <annma@kde.org>
0003 
0004     SPDX-License-Identifier: GPL-2.0-or-later
0005 */
0006 
0007 #include "klettresview.h"
0008 
0009 #include <QTimer>
0010 #include <QPainter>
0011 #include <QSvgRenderer>
0012 #include <QFile>
0013 #include <QPaintEvent>
0014 #include <QStandardPaths>
0015 
0016 #include <KLocalizedString>
0017 
0018 //Project headers
0019 #include "klettres.h"
0020 #include "prefs.h"
0021 #include "kltheme.h"
0022 #include "langutils.h"
0023 #include "klettres_debug.h"
0024 
0025 KLettresView::KLettresView(KLettres *parent)
0026         : QWidget(parent)
0027 {
0028     m_klettres = parent;
0029 
0030     //lineEdit for user input
0031     m_letterEdit = new QLineEdit( this );
0032     m_letterEdit->setToolTip(i18n("Type the letter or syllable that you just heard" ) );
0033     m_letterEdit->setFont(Prefs::font());
0034     m_letterEdit->setContextMenuPolicy(Qt::NoContextMenu);
0035     m_letterEdit->setAutoFillBackground(true);
0036 
0037     randomInt          = 0;
0038     m_renderer = new QSvgRenderer();
0039     setTheme(KLThemeFactory::instance()->buildTheme(0));
0040 }
0041 
0042 KLettresView::~KLettresView()
0043 {
0044     delete m_renderer;
0045     delete m_theme;
0046 }
0047 
0048 void KLettresView::chooseSound()
0049 {
0050     //get the next random sound
0051     m_random=m_klettres->soundFactory->randomList[randomInt%m_klettres->soundFactory->sounds];
0052     //The sound is played
0053     qCDebug(KLETTRES_LOG) << "m_random " << m_random;
0054     m_klettres->soundFactory->playSound(m_random);
0055     //store letter or syllable in m_currentLetter
0056     m_currentLetter = m_klettres->soundFactory->namesList[m_random];
0057     //Find the length of the syllable
0058     m_length=m_klettres->soundFactory->namesList[m_random].length();
0059     qCDebug(KLETTRES_LOG) << "syllable length " << m_length;
0060     int width;
0061     
0062     if (m_length<3) {
0063         width = 200;
0064     } else {
0065         width = 200+(20*(m_length-2));
0066     }
0067     
0068     m_letterEdit->setMinimumSize( QSize( width, 100 ) );
0069     m_letterEdit->setMaximumSize( QSize( width, 100 ) );
0070     update();
0071 }
0072 
0073 void KLettresView::setTheme(KLTheme *theme)
0074 {
0075     // we don't allow null themes
0076     if (!theme)
0077         return;
0078 
0079     QString svgpath = QStandardPaths::locate(QStandardPaths::GenericDataLocation,
0080                            QStringLiteral("klettres/pics/%1/%2").arg(theme->name(), theme->svgFileName()));
0081 
0082     // we don't allow themes with no svg installed
0083     if (!QFile::exists(svgpath)) {
0084         return;
0085     }
0086     delete m_theme;
0087     m_theme = theme;
0088 
0089     // stylesheet   
0090     int r1, g1, b1;
0091     m_theme->backgroundInputColor().getRgb(&r1, &g1, &b1);
0092     int r2, g2, b2;
0093     m_theme->letterInputColor().getRgb(&r2, &g2, &b2);
0094     m_letterEdit->setStyleSheet(QStringLiteral("border-style: solid; background-color: rgb(%1, %2, %3); color: rgb(%4, %5, %6) ; border-color: rgb(%4, %5, %6); border-bottom-right-radius:10; border-radius: 15px; border-width: 3px").arg(r1).arg(g1).arg(b1).arg(r2).arg(g2).arg(b2));
0095 
0096     m_renderer->load(svgpath);
0097     m_backgroundCache = QPixmap();
0098     update();
0099 }
0100 
0101 void KLettresView::paintEvent( QPaintEvent * e )
0102 {
0103     QPainter p(this);
0104     p.setRenderHint(QPainter::SmoothPixmapTransform);
0105     paintBackground(p, e->rect());
0106     paintLetter(p, e->rect());
0107     m_letterEdit->setFont(Prefs::font());
0108 }
0109 
0110 void KLettresView::paintBackground(QPainter &p, const QRect& rect)
0111 {
0112     // Draw the background
0113     if (m_backgroundCache.size() != size()) {
0114         m_backgroundCache = QPixmap(size());
0115         QPainter aux(&m_backgroundCache);
0116         m_renderer->render(&aux);
0117     }
0118     p.drawPixmap(rect.topLeft(), m_backgroundCache, rect);
0119 }
0120 
0121 void KLettresView::paintLetter(QPainter &p, const QRect& rect)
0122 {
0123     if (Prefs::level()%2==1) {
0124         QRect myRect = m_theme->wordRect(size());
0125         if (!myRect.intersects(rect)) {
0126             return;
0127         }
0128 
0129         const QString letterInLower = m_currentLetter.toLower();
0130         const QString prompt = (letterInLower == m_currentLetter) ? m_currentLetter
0131                                                                   : i18nc("%1 is uppercase letter, %2 is the same in lowercase", "%1 / %2", m_currentLetter, letterInLower);
0132         p.setPen( m_theme->letterColor());
0133         p.setFont(Prefs::font());
0134         p.drawText(myRect, prompt);
0135     }
0136     m_letterEdit->setGeometry( m_theme->inputRect(size()));  
0137     m_letterEdit->setFocus();
0138 }
0139 
0140 void KLettresView::game()
0141 {
0142     m_cursorPos = 1;
0143     //reset everything so when you change language or levels
0144     //it all restarts nicely
0145     QObject::disconnect(m_letterEdit, &QLineEdit::textChanged, this, &KLettresView::slotProcess);
0146     m_letterEdit->clear();
0147     m_letterEdit->setCursorPosition(0);
0148     m_letterEdit->setMaxLength( 1 );
0149     m_letterEdit->setFocus();
0150     m_upperLetter.clear();
0151     chooseSound();
0152     randomInt++;
0153     QObject::connect(m_letterEdit, &QLineEdit::textChanged, this, &KLettresView::slotProcess);
0154 }
0155 
0156 void KLettresView::slotProcess(const QString &inputLetter)
0157 {
0158     QString lang = Prefs::language();
0159     QObject::disconnect(m_letterEdit, &QLineEdit::textChanged, this, &KLettresView::slotProcess);
0160 
0161     //check if backspace
0162     if (inputLetter.length() != m_cursorPos) {
0163         m_cursorPos--;
0164         m_letterEdit->setMaxLength( m_cursorPos );
0165         QObject::connect(m_letterEdit, &QLineEdit::textChanged, this, &KLettresView::slotProcess);
0166         return;
0167     }
0168     QChar input_character = inputLetter.at(inputLetter.length()-1);
0169     QChar input_character_u; 
0170     qCDebug(KLETTRES_LOG) << "input_character " << input_character;
0171     
0172     if ((!LangUtils::isIndian(lang) && (input_character.isLetter())) || (LangUtils::isIndian(lang)))                               
0173     {
0174         if (input_character.unicode() == 0x00DF) { //everything in upper except the ß
0175             input_character_u = input_character.toLower();
0176         } else {
0177             input_character_u = input_character.toUpper();
0178         }
0179         m_upperLetter.append(input_character_u);
0180         m_letterEdit->selectAll();
0181         m_letterEdit->cut();
0182         m_letterEdit->setText(m_upperLetter);
0183         QTimer::singleShot(m_timer*100, this, &KLettresView::slotTimerDone);
0184     }  else {
0185         qCDebug(KLETTRES_LOG) << "cursor " << m_cursorPos;
0186         m_letterEdit->backspace();
0187         QObject::connect(m_letterEdit, &QLineEdit::textChanged, this, &KLettresView::slotProcess);
0188     }
0189     
0190 }
0191 
0192 void KLettresView::slotTimerDone()
0193 {
0194     QString match = m_currentLetter.left(m_cursorPos );
0195     qCDebug(KLETTRES_LOG) << "match " << match.toUpper();
0196     qCDebug(KLETTRES_LOG) << "m_upperLetter " << m_upperLetter;
0197     
0198     if (match == m_upperLetter) {
0199         if (m_cursorPos!=m_length) {//if text in lineEdit not equal to text on button
0200             //i.e if you still have to allow input
0201             m_letterEdit->setMaxLength( m_cursorPos +1 );
0202             m_letterEdit->setCursorPosition( m_cursorPos );
0203             m_letterEdit->setFocus();
0204             m_cursorPos ++;
0205             QObject::connect(m_letterEdit, &QLineEdit::textChanged, this, &KLettresView::slotProcess);
0206         } else {
0207             game();  //another syllable
0208         }
0209     } else { //if not, cut it
0210         qCDebug(KLETTRES_LOG) << "wrong letter ";
0211         m_letterEdit->backspace();  //delete the char to the left  and position curseur accordingly
0212         m_upperLetter.remove(m_upperLetter.size()-1, 1);
0213         m_letterEdit->setFocus();
0214         //play sound again
0215         m_klettres->soundFactory->playSound(m_random);
0216         QObject::connect(m_letterEdit, &QLineEdit::textChanged, this, &KLettresView::slotProcess);
0217     }
0218 }
0219 
0220 void KLettresView::slotPlayAgain()
0221 {
0222     //TODO wait for the previous sound to be payed before playing again as it won't play if the previous one was not finished
0223     m_klettres->soundFactory->playSound(m_random);
0224 }
0225 
0226 void KLettresView::keyReleaseEvent(QKeyEvent * e)
0227 {
0228        if (e->key() == Qt::Key_Backspace) {
0229             m_upperLetter.remove(m_cursorPos-1, 1);
0230        }
0231 }
0232 
0233 #include "moc_klettresview.cpp"