File indexing completed on 2024-04-21 07:28:02
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"