Main Page | Namespace List | Class Hierarchy | Alphabetical List | Class List | Directories | File List | Namespace Members | Class Members | File Members | Related Pages

qimpenhelp.cpp

Go to the documentation of this file.
00001 /**********************************************************************
00002 ** Copyright (C) 2000-2002 Trolltech AS.  All rights reserved.
00003 **
00004 ** This file is part of the Qtopia Environment.
00005 **
00006 ** This file may be distributed and/or modified under the terms of the
00007 ** GNU General Public License version 2 as published by the Free Software
00008 ** Foundation and appearing in the file LICENSE.GPL included in the
00009 ** packaging of this file.
00010 **
00011 ** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
00012 ** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
00013 **
00014 ** See http://www.trolltech.com/gpl/ for GPL licensing information.
00015 **
00016 ** Contact info@trolltech.com if any conditions of this licensing are
00017 ** not clear to you.
00018 **
00019 **********************************************************************/
00020 
00021 #include "qimpenwidget.h"
00022 #include "qimpencombining.h"
00023 #include "qimpenmatch.h"
00024 #include "qimpenhelp.h"
00025 
00026 #include <qpe/qpeapplication.h>
00027 #include <qpe/global.h>
00028 #include <qpe/config.h>
00029 #include <qpe/stringutil.h>
00030 
00031 #include <qtextview.h>
00032 #include <qlabel.h>
00033 #include <qlistbox.h>
00034 #include <qcombobox.h>
00035 #include <qpushbutton.h>
00036 #include <qlayout.h>
00037 #include <qtimer.h>
00038 #include <qtextstream.h>
00039 
00040 /* XPM */
00041 static const char * const left_xpm[] = {
00042 "16 16 2 1",
00043 "       c None",
00044 ".      c #000000",
00045 "                ",
00046 "                ",
00047 "                ",
00048 "        .       ",
00049 "       ..       ",
00050 "      ...       ",
00051 "     ....       ",
00052 "    .....       ",
00053 "   ......       ",
00054 "    .....       ",
00055 "     ....       ",
00056 "      ...       ",
00057 "       ..       ",
00058 "        .       ",
00059 "                ",
00060 "                "};
00061 
00062 
00063 /* XPM */
00064 static const char * const right_xpm[] = {
00065 "16 16 2 1",
00066 "       c None",
00067 ".      c #000000",
00068 "                ",
00069 "                ",
00070 "                ",
00071 "     .          ",
00072 "     ..         ",
00073 "     ...        ",
00074 "     ....       ",
00075 "     .....      ",
00076 "     ......     ",
00077 "     .....      ",
00078 "     ....       ",
00079 "     ...        ",
00080 "     ..         ",
00081 "     .          ",
00082 "                ",
00083 "                "};
00084 
00085 class CharListItem : public QListBoxText
00086 {
00087 public:
00088     CharListItem( const QString &text, uint c )
00089         : QListBoxText( text )
00090     {
00091         _code = c;
00092     }
00093 
00094     uint code() const { return _code; }
00095 
00096 protected:
00097     uint _code;
00098 };
00099 
00100 HandwritingHelp::HandwritingHelp( QIMPenProfile *p, QWidget *parent, const char *name, WFlags f )
00101     : QTabWidget( parent, name, f )
00102 {
00103     setCaption( tr("Handwriting Help") );
00104     QTextView *help = new QTextView( this );
00105     help->setFrameStyle( QFrame::NoFrame );
00106     help->setText(
00107         tr( "<ul><li>When you start to use the handwriting recogniser "
00108             "write slowly, accurately and firmly."
00109             "<li>Use the guide lines when drawing your characters."
00110             "<li>When drawing a character with multiple strokes, each "
00111             "successive stroke must be drawn before the grayed strokes are erased."
00112             "<li>Practice your handwriting using the handwriting trainer."
00113             "<li>When adding your own character templates make sure they "
00114             "are sufficiently different from other characters' templates."
00115             "</ul>") );
00116 
00117     addTab( help, tr("Tips") );
00118 
00119     HandwritingTrainer *trainer = new HandwritingTrainer( p, this );
00120     addTab( trainer, tr("Trainer") );
00121 }
00122 
00123 void HandwritingHelp::showEvent( QShowEvent * )
00124 {
00125     Global::hideInputMethod();
00126 }
00127 
00128 void HandwritingHelp::hideEvent( QHideEvent * )
00129 {
00130     Global::showInputMethod();
00131 }
00132 
00133 //---------------------------------------------------------------------------
00134 
00135 HandwritingTrainer::HandwritingTrainer( QIMPenProfile *p, QWidget *parent, const char *name )
00136     : QWidget( parent, name ), profile(p)
00137 {
00138     QGridLayout *gl = new QGridLayout( this, 4, 2, 0, 4 );
00139     gl->setColStretch( 1, 1 );
00140     gl->setRowStretch(3, 1);
00141 
00142     charSetCombo = new QComboBox( this );
00143     gl->addMultiCellWidget( charSetCombo, 0, 0, 0, 1 );
00144     connect( charSetCombo, SIGNAL(activated(int)), SLOT(selectCharSet(int)));
00145     QIMPenCharSetIterator it( profile->charSets() );
00146     for ( ; it.current(); ++it ) {
00147         if ( ! it.current()->hidden() )
00148             charSetCombo->insertItem( it.current()->description() );
00149     }
00150 
00151     charList = new QListBox( this );
00152     charList->setHScrollBarMode( QListBox::AlwaysOff );
00153     charList->setFixedWidth(80);
00154     connect( charList, SIGNAL(highlighted(int)), this, SLOT(selectChar(int)) );
00155     gl->addWidget(charList, 1, 0);
00156 
00157     result = new QLabel( this );
00158     result->setAlignment(AlignLeft | AlignVCenter | WordBreak);
00159     result->setText(
00160         tr( "Select a reference character from the list.  Practice writing in "
00161             "the area on the right."));
00162     gl->addMultiCellWidget(result, 1, 2, 1, 1);
00163 
00164     matcher = new QIMPenMatch( this );
00165     matcher->setCharSet( currentSet );
00166     connect( matcher, SIGNAL(noMatch()), this, SLOT(noMatch()) );
00167     connect( matcher, SIGNAL(matchedCharacters(const QIMPenCharMatchList&)),
00168              this, SLOT(matched(const QIMPenCharMatchList&)) );
00169 
00170     QHBoxLayout *hb = new QHBoxLayout();
00171     gl->addLayout( hb, 2, 0 );
00172     prevBtn = new QPushButton( this );
00173     prevBtn->setPixmap( QPixmap( (const char **)left_xpm ) );
00174     connect( prevBtn, SIGNAL(clicked()), SLOT(prevChar()));
00175     hb->addWidget( prevBtn );
00176 
00177     nextBtn = new QPushButton( this );
00178     nextBtn->setPixmap( QPixmap( (const char **)right_xpm ) );
00179     connect( nextBtn, SIGNAL(clicked()), SLOT(nextChar()));
00180     hb->addWidget( nextBtn );
00181 
00182     refPw = new QIMPenWidget( this );
00183     refPw->setReadOnly( TRUE );
00184     gl->addWidget( refPw, 3, 0 );
00185 
00186     pracPw = new QIMPenWidget( this );
00187     connect( matcher, SIGNAL(removeStroke()), pracPw, SLOT(removeStroke()) );
00188     connect( pracPw, SIGNAL(beginStroke()),
00189              this, SLOT(beginStroke()) );
00190     connect( pracPw, SIGNAL(stroke(QIMPenStroke*)),
00191              this, SLOT(strokeEntered(QIMPenStroke*)) );
00192     connect( pracPw, SIGNAL(beginStroke()),
00193              matcher, SLOT(beginStroke()) );
00194     connect( pracPw, SIGNAL(stroke(QIMPenStroke*)),
00195              matcher, SLOT(strokeEntered(QIMPenStroke*)) );
00196     gl->addWidget( pracPw, 3, 1 );
00197 
00198     redrawTimer = new QTimer( this );
00199     connect( redrawTimer, SIGNAL(timeout()), this, SLOT(redrawChar()) );
00200     redrawTimer->start( 5000 );
00201 
00202     currentSet = 0;
00203     charSetCombo->setCurrentItem( 1 );
00204     selectCharSet( 1 );
00205 }
00206 
00207 HandwritingTrainer::~HandwritingTrainer()
00208 {
00209 }
00210 
00211 void HandwritingTrainer::showEvent( QShowEvent * )
00212 {
00213     redrawChar();
00214     redrawTimer->start( 5000 );
00215 }
00216 
00217 void HandwritingTrainer::setCurrentChar( QIMPenChar *c )
00218 {
00219     currentChar = c;
00220     refPw->showCharacter( currentChar );
00221     pracPw->clear();
00222     if ( currentChar ) {
00223         prevBtn->setEnabled( findPrev() != 0 );
00224         nextBtn->setEnabled( findNext() != 0 );
00225     }
00226     redrawTimer->start( 5000 );
00227 }
00228 
00229 void HandwritingTrainer::selectChar( int i )
00230 {
00231     static int last_char = 0;
00232 
00233     if (last_char != i) {
00234         result->setText("");
00235     }
00236 
00237     currentChar = 0;
00238     currentCode = ((CharListItem *)charList->item(i))->code();
00239     QIMPenCharIterator it(currentSet->characters() );
00240     for ( ; it.current(); ++it ) {
00241         if ( it.current()->character() == currentCode &&
00242                 !it.current()->testFlag( QIMPenChar::Deleted ) ) {
00243             setCurrentChar( it.current() );
00244             break;
00245         }
00246     }
00247     if ( !it.current() )
00248         setCurrentChar( 0 );
00249 }
00250 
00251 void HandwritingTrainer::selectCharSet( int i )
00252 {
00253     if ( currentSet ) {
00254         refPw->removeCharSet( 0 );
00255         pracPw->removeCharSet( 0 );
00256         result->setText("");
00257     }
00258     currentSet = profile->charSets().at( i );
00259     fillCharList();
00260     refPw->insertCharSet( currentSet );
00261     pracPw->insertCharSet( currentSet );
00262     matcher->setCharSet( currentSet );
00263     if ( charList->count() ) {
00264         charList->setSelected( 0, TRUE );
00265         selectChar(0);
00266     }
00267 }
00268 
00269 void HandwritingTrainer::noMatch()
00270 {
00271     result->setText( tr("No match") );
00272 }
00273 
00274 void HandwritingTrainer::matched( const QIMPenCharMatchList &ml )
00275 {
00276     int maxErr = 20000 + (*ml.begin()).penChar->strokeLength(0) * 1000;
00277     int baseErr = (*ml.begin()).penChar->strokeLength(0) * 250;
00278     unsigned int numStrokes = (*ml.begin()).penChar->strokeCount();
00279     QIMPenCharMatchList::ConstIterator it;
00280     /*
00281     for ( it = ml.begin(); it != ml.end(); ++it ) {
00282         if ( (*it).penChar->strokeCount() == numStrokes ) {
00283             if ( (*it).error > maxErr )
00284                 maxErr = (*it).error;
00285         }
00286     }
00287     */
00288     int i;
00289     QString res;
00290     QTextStream ts(&res, IO_WriteOnly);
00291     ts << "<qt>" << tr("Matched: ");
00292     for ( i = 0, it = ml.begin(); it != ml.end() && i < 4; ++it, i++ ) {
00293         if ( (*it).penChar->strokeCount() == numStrokes ) {
00294             int rate = 100 - ( ((*it).error - baseErr) * 100 ) / maxErr;
00295             if ( it != ml.begin() ) {
00296                 if ( rate < -10 )
00297                     continue;
00298                 ts << "<br>";
00299                 ts << tr("Similar to: ");
00300             }
00301             ts << "<big>";
00302             if ( (*it).penChar->character() == currentChar->character() )
00303                 ts << "<b>";
00304             ts << Qtopia::escapeString((*it).penChar->name());
00305             ts << " (" << rateString(rate) << ")";
00306             if ( (*it).penChar->character() == currentChar->character() )
00307                 ts << "</b>";
00308             ts << "</big>";
00309         }
00310     }
00311     ts << "</qt>";
00312     result->setText( res );
00313 }
00314 
00315 QString HandwritingTrainer::rateString( int rate ) const
00316 {
00317     if ( rate < 1 )
00318         rate = 1;
00319     if ( rate > 100 )
00320         rate = 100;
00321     return tr("%1%").arg(rate);
00322 }
00323 
00324 void HandwritingTrainer::prevChar()
00325 {
00326     QIMPenChar *pc = findPrev();
00327     if ( pc )
00328         setCurrentChar( pc );
00329 }
00330 
00331 void HandwritingTrainer::nextChar()
00332 {
00333     QIMPenChar *pc = findNext();
00334     if ( pc )
00335         setCurrentChar( pc );
00336 }
00337 
00338 void HandwritingTrainer::redrawChar()
00339 {
00340     if ( currentChar )
00341         refPw->showCharacter( currentChar );
00342 }
00343 
00344 void HandwritingTrainer::beginStroke()
00345 {
00346     redrawTimer->start( 5000 );
00347 }
00348 
00349 void HandwritingTrainer::strokeEntered( QIMPenStroke * )
00350 {
00351     pracPw->greyStroke();
00352 }
00353 
00354 QIMPenChar *HandwritingTrainer::findPrev()
00355 {
00356     if ( !currentChar )
00357         return 0;
00358     QIMPenCharIterator it( currentSet->characters() );
00359     bool found = FALSE;
00360     for ( it.toLast(); it.current(); --it ) {
00361         if ( !found && it.current() == currentChar )
00362             found = TRUE;
00363         else if ( found && it.current()->character() == currentCode &&
00364                 !it.current()->testFlag( QIMPenChar::Deleted ) ) {
00365             return it.current();
00366         }
00367     }
00368 
00369     return 0;
00370 }
00371 
00372 QIMPenChar *HandwritingTrainer::findNext()
00373 {
00374     if ( !currentChar )
00375         return 0;
00376     QIMPenCharIterator it( currentSet->characters() );
00377     bool found = FALSE;
00378     for ( ; it.current(); ++it ) {
00379         if ( !found && it.current() == currentChar )
00380             found = TRUE;
00381         else if ( found && it.current()->character() == currentCode &&
00382                 !it.current()->testFlag( QIMPenChar::Deleted ) ) {
00383             return it.current();
00384         }
00385     }
00386 
00387     return 0;
00388 }
00389 
00390 void HandwritingTrainer::fillCharList()
00391 {
00392     charList->clear();
00393     QIMPenCharIterator it( currentSet->characters() );
00394     CharListItem *li = 0;
00395     for ( ; it.current(); ++it ) {
00396         uint ch = it.current()->character();
00397         QString n = it.current()->name();
00398         if ( !n.isEmpty() )
00399             li = new CharListItem( n, ch );
00400         if ( li ) {
00401             CharListItem *i = (CharListItem *)charList->findItem( li->text() );
00402             if ( !i || i->code() != ch ) {
00403                 charList->insertItem( li );
00404             } else {
00405                 delete li;
00406                 li = 0;
00407             }
00408         }
00409     }
00410     currentChar = 0;
00411 }
00412 

Generated on Sat Nov 5 16:16:01 2005 for OPIE by  doxygen 1.4.2