summaryrefslogtreecommitdiff
Unidiff
Diffstat (more/less context) (ignore whitespace changes)
-rw-r--r--inputmethods/handwriting/qimpenchar.cpp9
-rw-r--r--inputmethods/handwriting/qimpeninput.cpp24
-rw-r--r--inputmethods/handwriting/qimpenmatch.cpp35
-rw-r--r--inputmethods/handwriting/qimpenstroke.cpp15
-rw-r--r--inputmethods/handwriting/qimpenwordpick.cpp2
5 files changed, 45 insertions, 40 deletions
diff --git a/inputmethods/handwriting/qimpenchar.cpp b/inputmethods/handwriting/qimpenchar.cpp
index 929f370..db5d135 100644
--- a/inputmethods/handwriting/qimpenchar.cpp
+++ b/inputmethods/handwriting/qimpenchar.cpp
@@ -1,92 +1,93 @@
1/********************************************************************** 1/**********************************************************************
2 ** Copyright (C) 2000 Trolltech AS. All rights reserved. 2 ** Copyright (C) 2000 Trolltech AS. All rights reserved.
3 ** 3 **
4 ** This file is part of Qtopia Environment. 4 ** This file is part of Qtopia Environment.
5 ** 5 **
6 ** This file may be distributed and/or modified under the terms of the 6 ** This file may be distributed and/or modified under the terms of the
7 ** GNU General Public License version 2 as published by the Free Software 7 ** GNU General Public License version 2 as published by the Free Software
8 ** Foundation and appearing in the file LICENSE.GPL included in the 8 ** Foundation and appearing in the file LICENSE.GPL included in the
9 ** packaging of this file. 9 ** packaging of this file.
10 ** 10 **
11 ** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE 11 ** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
12 ** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. 12 ** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
13 ** 13 **
14 ** See http://www.trolltech.com/gpl/ for GPL licensing information. 14 ** See http://www.trolltech.com/gpl/ for GPL licensing information.
15 ** 15 **
16 ** Contact info@trolltech.com if any conditions of this licensing are 16 ** Contact info@trolltech.com if any conditions of this licensing are
17 ** not clear to you. 17 ** not clear to you.
18 ** 18 **
19 **********************************************************************/ 19 **********************************************************************/
20 20
21#include <qfile.h> 21#include <qfile.h>
22#include <qtl.h> 22#include <qtl.h>
23#include <math.h> 23#include <math.h>
24#include <limits.h> 24#include <limits.h>
25#include <errno.h> 25#include <errno.h>
26#include <qdatastream.h> 26#include <qdatastream.h>
27#include "qimpencombining.h" 27#include "qimpencombining.h"
28#include "qimpenchar.h" 28#include "qimpenchar.h"
29#include "opie2/odebug.h"
29 30
30 #define QIMPEN_MATCH_THRESHOLD 200000 31 #define QIMPEN_MATCH_THRESHOLD 200000
31 32
32const QIMPenSpecialKeys qimpen_specialKeys[] = { 33const QIMPenSpecialKeys qimpen_specialKeys[] = {
33 { Qt::Key_Escape, "[Esc]" }, 34 { Qt::Key_Escape, "[Esc]" },
34 { Qt::Key_Tab, "[Tab]" }, 35 { Qt::Key_Tab, "[Tab]" },
35 { Qt::Key_Backspace,"[BackSpace]" }, 36 { Qt::Key_Backspace,"[BackSpace]" },
36 { Qt::Key_Return, "[Return]" }, 37 { Qt::Key_Return, "[Return]" },
37 { QIMPenChar::Caps, "[Uppercase]" }, 38 { QIMPenChar::Caps, "[Uppercase]" },
38 { QIMPenChar::CapsLock,"[Caps Lock]" }, 39 { QIMPenChar::CapsLock,"[Caps Lock]" },
39 { QIMPenChar::Shortcut,"[Shortcut]" }, 40 { QIMPenChar::Shortcut,"[Shortcut]" },
40 { QIMPenChar::Punctuation, "[Punctuation]" }, 41 { QIMPenChar::Punctuation, "[Punctuation]" },
41 { QIMPenChar::Symbol,"[Symbol]" }, 42 { QIMPenChar::Symbol,"[Symbol]" },
42 { QIMPenChar::Extended,"[Extended]" }, 43 { QIMPenChar::Extended,"[Extended]" },
43 { Qt::Key_unknown, 0 } }; 44 { Qt::Key_unknown, 0 } };
44 45
45 46
46/*! 47/*!
47 \class QIMPenChar qimpenchar.h 48 \class QIMPenChar qimpenchar.h
48 49
49 Handles a single character. Can calculate closeness of match to 50 Handles a single character. Can calculate closeness of match to
50 another character. 51 another character.
51 */ 52 */
52 53
53QIMPenChar::QIMPenChar() 54QIMPenChar::QIMPenChar()
54{ 55{
55 flags = 0; 56 flags = 0;
56 strokes.setAutoDelete( TRUE ); 57 strokes.setAutoDelete( TRUE );
57} 58}
58 59
59QIMPenChar::QIMPenChar( const QIMPenChar &chr ) 60QIMPenChar::QIMPenChar( const QIMPenChar &chr )
60{ 61{
61 strokes.setAutoDelete( TRUE ); 62 strokes.setAutoDelete( TRUE );
62 ch = chr.ch; 63 ch = chr.ch;
63 flags = chr.flags; 64 flags = chr.flags;
64 d = chr.d; 65 d = chr.d;
65 QIMPenStrokeIterator it( chr.strokes ); 66 QIMPenStrokeIterator it( chr.strokes );
66 while ( it.current() ) { 67 while ( it.current() ) {
67 strokes.append( new QIMPenStroke( *it.current() ) ); 68 strokes.append( new QIMPenStroke( *it.current() ) );
68 ++it; 69 ++it;
69 } 70 }
70} 71}
71 72
72QIMPenChar &QIMPenChar::operator=( const QIMPenChar &chr ) 73QIMPenChar &QIMPenChar::operator=( const QIMPenChar &chr )
73{ 74{
74 strokes.clear(); 75 strokes.clear();
75 ch = chr.ch; 76 ch = chr.ch;
76 flags = chr.flags; 77 flags = chr.flags;
77 d = chr.d; 78 d = chr.d;
78 QIMPenStrokeIterator it( chr.strokes ); 79 QIMPenStrokeIterator it( chr.strokes );
79 while ( it.current() ) { 80 while ( it.current() ) {
80 strokes.append( new QIMPenStroke( *it.current() ) ); 81 strokes.append( new QIMPenStroke( *it.current() ) );
81 ++it; 82 ++it;
82 } 83 }
83 84
84 return *this; 85 return *this;
85} 86}
86 87
87QString QIMPenChar::name() const 88QString QIMPenChar::name() const
88{ 89{
89 QString n; 90 QString n;
90 91
91 if ( (ch & 0x0000FFFF) == 0 ) { 92 if ( (ch & 0x0000FFFF) == 0 ) {
92 int code = ch >> 16; 93 int code = ch >> 16;
@@ -106,144 +107,144 @@ QString QIMPenChar::name() const
106void QIMPenChar::clear() 107void QIMPenChar::clear()
107{ 108{
108 ch = 0; 109 ch = 0;
109 flags = 0; 110 flags = 0;
110 d = QString::null; 111 d = QString::null;
111 strokes.clear(); 112 strokes.clear();
112} 113}
113 114
114unsigned int QIMPenChar::strokeLength( int s ) const 115unsigned int QIMPenChar::strokeLength( int s ) const
115{ 116{
116 QIMPenStrokeIterator it( strokes ); 117 QIMPenStrokeIterator it( strokes );
117 while ( it.current() && s ) { 118 while ( it.current() && s ) {
118 ++it; 119 ++it;
119 --s; 120 --s;
120 } 121 }
121 122
122 if ( it.current() ) 123 if ( it.current() )
123 return it.current()->length(); 124 return it.current()->length();
124 125
125 return 0; 126 return 0;
126} 127}
127 128
128/*! 129/*!
129 Add a stroke to the character 130 Add a stroke to the character
130 */ 131 */
131void QIMPenChar::addStroke( QIMPenStroke *st ) 132void QIMPenChar::addStroke( QIMPenStroke *st )
132{ 133{
133 QIMPenStroke *stroke = new QIMPenStroke( *st ); 134 QIMPenStroke *stroke = new QIMPenStroke( *st );
134 strokes.append( stroke ); 135 strokes.append( stroke );
135} 136}
136 137
137/*! 138/*!
138 Return an indicator of the closeness of this character to \a pen. 139 Return an indicator of the closeness of this character to \a pen.
139 Lower value is better. 140 Lower value is better.
140 */ 141 */
141int QIMPenChar::match( QIMPenChar *pen ) 142int QIMPenChar::match( QIMPenChar *pen )
142{ 143{
143 /* 144 /*
144 if ( strokes.count() > pen->strokes.count() ) 145 if ( strokes.count() > pen->strokes.count() )
145 return INT_MAX; 146 return INT_MAX;
146 */ 147 */
147 int err = 0; 148 int err = 0;
148 int maxErr = 0; 149 int maxErr = 0;
149 int diff = 0; 150 int diff = 0;
150 QIMPenStrokeIterator it1( strokes ); 151 QIMPenStrokeIterator it1( strokes );
151 QIMPenStrokeIterator it2( pen->strokes ); 152 QIMPenStrokeIterator it2( pen->strokes );
152 err = it1.current()->match( it2.current() ); 153 err = it1.current()->match( it2.current() );
153 if ( err > maxErr ) 154 if ( err > maxErr )
154 maxErr = err; 155 maxErr = err;
155 ++it1; 156 ++it1;
156 ++it2; 157 ++it2;
157 while ( err < 400000 && it1.current() && it2.current() ) { 158 while ( err < 400000 && it1.current() && it2.current() ) {
158 QPoint p1 = it1.current()->boundingRect().center() - 159 QPoint p1 = it1.current()->boundingRect().center() -
159 strokes.getFirst()->boundingRect().center(); 160 strokes.getFirst()->boundingRect().center();
160 QPoint p2 = it2.current()->boundingRect().center() - 161 QPoint p2 = it2.current()->boundingRect().center() -
161 pen->strokes.getFirst()->boundingRect().center(); 162 pen->strokes.getFirst()->boundingRect().center();
162 int xdiff = QABS( p1.x() - p2.x() ) - 6; 163 int xdiff = QABS( p1.x() - p2.x() ) - 6;
163 int ydiff = QABS( p1.y() - p2.y() ) - 5; 164 int ydiff = QABS( p1.y() - p2.y() ) - 5;
164 if ( xdiff < 0 ) 165 if ( xdiff < 0 )
165 xdiff = 0; 166 xdiff = 0;
166 if ( ydiff < 0 ) 167 if ( ydiff < 0 )
167 ydiff = 0; 168 ydiff = 0;
168 if ( xdiff > 10 || ydiff > 10 ) { // not a chance 169 if ( xdiff > 10 || ydiff > 10 ) { // not a chance
169#ifdef DEBUG_QIMPEN 170#ifdef DEBUG_QIMPEN
170 qDebug( "char %c, stroke starting pt diff excessive", pen->ch ); 171 odebug << "char " << pen->ch <<", stroke starting pt diff excessive" << oendl;
171#endif 172#endif
172 return INT_MAX; 173 return INT_MAX;
173 } 174 }
174 diff += xdiff*xdiff + ydiff*ydiff; 175 diff += xdiff*xdiff + ydiff*ydiff;
175 err = it1.current()->match( it2.current() ); 176 err = it1.current()->match( it2.current() );
176 if ( err > maxErr ) 177 if ( err > maxErr )
177 maxErr = err; 178 maxErr = err;
178 ++it1; 179 ++it1;
179 ++it2; 180 ++it2;
180 } 181 }
181 182
182 maxErr += diff * diff * 6; // magic weighting :) 183 maxErr += diff * diff * 6; // magic weighting :)
183 184
184#ifdef DEBUG_QIMPEN 185#ifdef DEBUG_QIMPEN
185 qDebug( "char: %c, maxErr %d, diff %d, (%d)", pen->ch, maxErr, diff, strokes.count() ); 186 odebug << "char: " << pen->ch << ", maxErr " << maxErr << ", diff " << diff << ", " << strokes.count() << oendl;
186#endif 187#endif
187 return maxErr; 188 return maxErr;
188} 189}
189 190
190/*! 191/*!
191 Return the bounding rect of this character. It may have sides with 192 Return the bounding rect of this character. It may have sides with
192 negative coords since its origin is where the user started drawing 193 negative coords since its origin is where the user started drawing
193 the character. 194 the character.
194 */ 195 */
195QRect QIMPenChar::boundingRect() 196QRect QIMPenChar::boundingRect()
196{ 197{
197 QRect br; 198 QRect br;
198 QIMPenStroke *st = strokes.first(); 199 QIMPenStroke *st = strokes.first();
199 while ( st ) { 200 while ( st ) {
200 br |= st->boundingRect(); 201 br |= st->boundingRect();
201 st = strokes.next(); 202 st = strokes.next();
202 } 203 }
203 204
204 return br; 205 return br;
205} 206}
206 207
207 208
208/*! 209/*!
209 Write the character's data to the stream. 210 Write the character's data to the stream.
210 */ 211 */
211QDataStream &operator<< (QDataStream &s, const QIMPenChar &ws) 212QDataStream &operator<< (QDataStream &s, const QIMPenChar &ws)
212{ 213{
213 s << ws.ch; 214 s << ws.ch;
214 s << ws.flags; 215 s << ws.flags;
215 if ( ws.flags & QIMPenChar::Data ) 216 if ( ws.flags & QIMPenChar::Data )
216 s << ws.d; 217 s << ws.d;
217 s << ws.strokes.count(); 218 s << ws.strokes.count();
218 QIMPenStrokeIterator it( ws.strokes ); 219 QIMPenStrokeIterator it( ws.strokes );
219 while ( it.current() ) { 220 while ( it.current() ) {
220 s << *it.current(); 221 s << *it.current();
221 ++it; 222 ++it;
222 } 223 }
223 224
224 return s; 225 return s;
225} 226}
226 227
227/*! 228/*!
228 Read the character's data from the stream. 229 Read the character's data from the stream.
229 */ 230 */
230QDataStream &operator>> (QDataStream &s, QIMPenChar &ws) 231QDataStream &operator>> (QDataStream &s, QIMPenChar &ws)
231{ 232{
232 s >> ws.ch; 233 s >> ws.ch;
233 s >> ws.flags; 234 s >> ws.flags;
234 if ( ws.flags & QIMPenChar::Data ) 235 if ( ws.flags & QIMPenChar::Data )
235 s >> ws.d; 236 s >> ws.d;
236 unsigned size; 237 unsigned size;
237 s >> size; 238 s >> size;
238 for ( unsigned i = 0; i < size; i++ ) { 239 for ( unsigned i = 0; i < size; i++ ) {
239 QIMPenStroke *st = new QIMPenStroke(); 240 QIMPenStroke *st = new QIMPenStroke();
240 s >> *st; 241 s >> *st;
241 ws.strokes.append( st ); 242 ws.strokes.append( st );
242 } 243 }
243 244
244 return s; 245 return s;
245} 246}
246 247
247//=========================================================================== 248//===========================================================================
248 249
249bool QIMPenCharMatch::operator>( const QIMPenCharMatch &m ) 250bool QIMPenCharMatch::operator>( const QIMPenCharMatch &m )
@@ -397,115 +398,115 @@ bool QIMPenCharSet::save( Domain d )
397 QFile::remove( tmpFn.latin1() ); 398 QFile::remove( tmpFn.latin1() );
398 ok = FALSE; 399 ok = FALSE;
399 } 400 }
400 } 401 }
401 402
402 return ok; 403 return ok;
403} 404}
404 405
405QIMPenChar *QIMPenCharSet::at( int i ) 406QIMPenChar *QIMPenCharSet::at( int i )
406{ 407{
407 return chars.at(i); 408 return chars.at(i);
408} 409}
409 410
410void QIMPenCharSet::markDeleted( uint ch ) 411void QIMPenCharSet::markDeleted( uint ch )
411{ 412{
412 QIMPenCharIterator ci( chars ); 413 QIMPenCharIterator ci( chars );
413 for ( ; ci.current(); ++ci ) { 414 for ( ; ci.current(); ++ci ) {
414 QIMPenChar *pc = ci.current(); 415 QIMPenChar *pc = ci.current();
415 if ( pc->character() == ch && pc->testFlag( QIMPenChar::System ) ) 416 if ( pc->character() == ch && pc->testFlag( QIMPenChar::System ) )
416 pc->setFlag( QIMPenChar::Deleted ); 417 pc->setFlag( QIMPenChar::Deleted );
417 } 418 }
418} 419}
419 420
420/*! 421/*!
421 Find the best matches for \a ch in this character set. 422 Find the best matches for \a ch in this character set.
422 */ 423 */
423QIMPenCharMatchList QIMPenCharSet::match( QIMPenChar *ch ) 424QIMPenCharMatchList QIMPenCharSet::match( QIMPenChar *ch )
424{ 425{
425 QIMPenCharMatchList matches; 426 QIMPenCharMatchList matches;
426 427
427 QIMPenCharIterator ci( chars ); 428 QIMPenCharIterator ci( chars );
428 for ( ; ci.current(); ++ci ) { 429 for ( ; ci.current(); ++ci ) {
429 QIMPenChar *tmplChar = ci.current(); 430 QIMPenChar *tmplChar = ci.current();
430 if ( tmplChar->testFlag( QIMPenChar::Deleted ) ) { 431 if ( tmplChar->testFlag( QIMPenChar::Deleted ) ) {
431 continue; 432 continue;
432 } 433 }
433 int err; 434 int err;
434 if ( ch->penStrokes().count() <= tmplChar->penStrokes().count() ) { 435 if ( ch->penStrokes().count() <= tmplChar->penStrokes().count() ) {
435 err = ch->match( tmplChar ); 436 err = ch->match( tmplChar );
436 if ( err <= QIMPEN_MATCH_THRESHOLD ) { 437 if ( err <= QIMPEN_MATCH_THRESHOLD ) {
437 if (tmplChar->penStrokes().count() != ch->penStrokes().count()) 438 if (tmplChar->penStrokes().count() != ch->penStrokes().count())
438 err = QMIN(err*3, QIMPEN_MATCH_THRESHOLD); 439 err = QMIN(err*3, QIMPEN_MATCH_THRESHOLD);
439 QIMPenCharMatchList::Iterator it; 440 QIMPenCharMatchList::Iterator it;
440 for ( it = matches.begin(); it != matches.end(); ++it ) { 441 for ( it = matches.begin(); it != matches.end(); ++it ) {
441 if ( (*it).penChar->character() == tmplChar->character() && 442 if ( (*it).penChar->character() == tmplChar->character() &&
442 (*it).penChar->penStrokes().count() == tmplChar->penStrokes().count() ) { 443 (*it).penChar->penStrokes().count() == tmplChar->penStrokes().count() ) {
443 if ( (*it).error > err ) 444 if ( (*it).error > err )
444 (*it).error = err; 445 (*it).error = err;
445 break; 446 break;
446 } 447 }
447 } 448 }
448 if ( it == matches.end() ) { 449 if ( it == matches.end() ) {
449 QIMPenCharMatch m; 450 QIMPenCharMatch m;
450 m.error = err; 451 m.error = err;
451 m.penChar = tmplChar; 452 m.penChar = tmplChar;
452 matches.append( m ); 453 matches.append( m );
453 } 454 }
454 } 455 }
455 } 456 }
456 } 457 }
457 qHeapSort( matches ); 458 qHeapSort( matches );
458 /* 459 /*
459 QIMPenCharMatchList::Iterator it; 460 QIMPenCharMatchList::Iterator it;
460 for ( it = matches.begin(); it != matches.end(); ++it ) { 461 for ( it = matches.begin(); it != matches.end(); ++it ) {
461 qDebug( "Match: \'%c\', error %d, strokes %d", (*it).penChar->character(), 462
462 (*it).error, (*it).penChar->penStrokes().count() ); 463 odebug << "Match: \'" << (*it).penChar->character() "\', error " << (*it).error ", strokes " <<(*it).penChar->penStrokes().count() << oendl;
463 } 464 }
464 */ 465 */
465 return matches; 466 return matches;
466} 467}
467 468
468/*! 469/*!
469 Add a character \a ch to this set. 470 Add a character \a ch to this set.
470 QIMPenCharSet will delete this character when it is no longer needed. 471 QIMPenCharSet will delete this character when it is no longer needed.
471 */ 472 */
472void QIMPenCharSet::addChar( QIMPenChar *ch ) 473void QIMPenCharSet::addChar( QIMPenChar *ch )
473{ 474{
474 if ( ch->penStrokes().count() > maxStrokes ) 475 if ( ch->penStrokes().count() > maxStrokes )
475 maxStrokes = ch->penStrokes().count(); 476 maxStrokes = ch->penStrokes().count();
476 chars.append( ch ); 477 chars.append( ch );
477} 478}
478 479
479/*! 480/*!
480 Remove a character by reference \a ch from this set. 481 Remove a character by reference \a ch from this set.
481 QIMPenCharSet will delete this character. 482 QIMPenCharSet will delete this character.
482 */ 483 */
483void QIMPenCharSet::removeChar( QIMPenChar *ch ) 484void QIMPenCharSet::removeChar( QIMPenChar *ch )
484{ 485{
485 chars.remove( ch ); 486 chars.remove( ch );
486} 487}
487 488
488/*! 489/*!
489 Move the character up the list of characters. 490 Move the character up the list of characters.
490 */ 491 */
491void QIMPenCharSet::up( QIMPenChar *ch ) 492void QIMPenCharSet::up( QIMPenChar *ch )
492{ 493{
493 int idx = chars.findRef( ch ); 494 int idx = chars.findRef( ch );
494 if ( idx > 0 ) { 495 if ( idx > 0 ) {
495 chars.take(); 496 chars.take();
496 chars.insert( idx - 1, ch ); 497 chars.insert( idx - 1, ch );
497 } 498 }
498} 499}
499 500
500/*! 501/*!
501 Move the character down the list of characters. 502 Move the character down the list of characters.
502 */ 503 */
503void QIMPenCharSet::down( QIMPenChar *ch ) 504void QIMPenCharSet::down( QIMPenChar *ch )
504{ 505{
505 int idx = chars.findRef( ch ); 506 int idx = chars.findRef( ch );
506 if ( idx >= 0 && idx < (int)chars.count() - 1 ) { 507 if ( idx >= 0 && idx < (int)chars.count() - 1 ) {
507 chars.take(); 508 chars.take();
508 chars.insert( idx + 1, ch ); 509 chars.insert( idx + 1, ch );
509 } 510 }
510} 511}
511 512
diff --git a/inputmethods/handwriting/qimpeninput.cpp b/inputmethods/handwriting/qimpeninput.cpp
index d073cdf..6ea1bb4 100644
--- a/inputmethods/handwriting/qimpeninput.cpp
+++ b/inputmethods/handwriting/qimpeninput.cpp
@@ -1,102 +1,103 @@
1/********************************************************************** 1/**********************************************************************
2** Copyright (C) 2000-2002 Trolltech AS. All rights reserved. 2** Copyright (C) 2000-2002 Trolltech AS. All rights reserved.
3** 3**
4** This file is part of the Qtopia Environment. 4** This file is part of the Qtopia Environment.
5** 5**
6** This file may be distributed and/or modified under the terms of the 6** This file may be distributed and/or modified under the terms of the
7** GNU General Public License version 2 as published by the Free Software 7** GNU General Public License version 2 as published by the Free Software
8** Foundation and appearing in the file LICENSE.GPL included in the 8** Foundation and appearing in the file LICENSE.GPL included in the
9** packaging of this file. 9** packaging of this file.
10** 10**
11** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE 11** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
12** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. 12** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
13** 13**
14** See http://www.trolltech.com/gpl/ for GPL licensing information. 14** See http://www.trolltech.com/gpl/ for GPL licensing information.
15** 15**
16** Contact info@trolltech.com if any conditions of this licensing are 16** Contact info@trolltech.com if any conditions of this licensing are
17** not clear to you. 17** not clear to you.
18** 18**
19**********************************************************************/ 19**********************************************************************/
20 20
21#include "qimpenwidget.h" 21#include "qimpenwidget.h"
22#include "qimpensetup.h" 22#include "qimpensetup.h"
23#include "qimpeninput.h" 23#include "qimpeninput.h"
24#include "qimpencombining.h" 24#include "qimpencombining.h"
25#include "qimpenwordpick.h" 25#include "qimpenwordpick.h"
26#include "qimpenmatch.h" 26#include "qimpenmatch.h"
27#include "qimpenhelp.h" 27#include "qimpenhelp.h"
28 28
29#include <qpe/qpeapplication.h> 29#include <qpe/qpeapplication.h>
30#include <qpe/qdawg.h> 30#include <qpe/qdawg.h>
31#include <qpe/config.h> 31#include <qpe/config.h>
32#include <qpe/global.h> 32#include <qpe/global.h>
33 33
34#include <qlayout.h> 34#include <qlayout.h>
35#include <qpushbutton.h> 35#include <qpushbutton.h>
36#include <qlabel.h> 36#include <qlabel.h>
37#include <qtimer.h> 37#include <qtimer.h>
38#include <qdir.h> 38#include <qdir.h>
39#include <opie2/odebug.h>
39 40
40#include <limits.h> 41#include <limits.h>
41 42
42// We'll use little pixmaps for the buttons to save screen space. 43// We'll use little pixmaps for the buttons to save screen space.
43 44
44/* XPM */ 45/* XPM */
45static const char * const pen_xpm[] = { 46static const char * const pen_xpm[] = {
46"12 12 4 1", 47"12 12 4 1",
47 " c None", 48 " c None",
48 ".c #000000", 49 ".c #000000",
49 "+c #FFFFFF", 50 "+c #FFFFFF",
50 "@c #808080", 51 "@c #808080",
51" . ", 52" . ",
52" .+. ", 53" .+. ",
53" ..@@.", 54" ..@@.",
54" .+@.. ", 55" .+@.. ",
55" .+@@. ", 56" .+@@. ",
56" .+@@. ", 57" .+@@. ",
57" .+@@. ", 58" .+@@. ",
58" .@.@. ", 59" .@.@. ",
59" .@@. ", 60" .@@. ",
60" .... ", 61" .... ",
61" .. ", 62" .. ",
62" "}; 63" "};
63 64
64 65
65/* XPM */ 66/* XPM */
66static char * bs_xpm[] = { 67static char * bs_xpm[] = {
67"12 12 5 1", 68"12 12 5 1",
68 " c None", 69 " c None",
69 ".c #333333", 70 ".c #333333",
70 "+c #000000", 71 "+c #000000",
71 "@c #FFFFFF", 72 "@c #FFFFFF",
72 "#c #666666", 73 "#c #666666",
73" ", 74" ",
74" ", 75" ",
75" ", 76" ",
76" . ", 77" . ",
77" ++ ", 78" ++ ",
78" +@#+++++. ", 79" +@#+++++. ",
79" +@@@@@@@@+ ", 80" +@@@@@@@@+ ",
80" +@#+++++. ", 81" +@#+++++. ",
81" ++ ", 82" ++ ",
82" . ", 83" . ",
83" ", 84" ",
84" "}; 85" "};
85 86
86 87
87/* XPM */ 88/* XPM */
88static char * enter_xpm[] = { 89static char * enter_xpm[] = {
89"12 12 5 1", 90"12 12 5 1",
90 " c None", 91 " c None",
91 ".c #333333", 92 ".c #333333",
92 "+c #000000", 93 "+c #000000",
93 "@c #FFFFFF", 94 "@c #FFFFFF",
94 "#c #666666", 95 "#c #666666",
95" ", 96" ",
96" .+. ", 97" .+. ",
97" +@+ ", 98" +@+ ",
98" . +@+ ", 99" . +@+ ",
99" ++ +@+ ", 100" ++ +@+ ",
100" +@#++++@+ ", 101" +@#++++@+ ",
101" +@@@@@@@@+ ", 102" +@@@@@@@@+ ",
102" +@#+++++. ", 103" +@#+++++. ",
@@ -258,258 +259,259 @@ void QIMPenInput::loadProfiles()
258 config.setGroup( "Settings" ); 259 config.setGroup( "Settings" );
259 QString prof = config.readEntry( "Profile", "Default" ); 260 QString prof = config.readEntry( "Profile", "Default" );
260 selectProfile( prof ); 261 selectProfile( prof );
261} 262}
262 263
263void QIMPenInput::selectProfile( const QString &name ) 264void QIMPenInput::selectProfile( const QString &name )
264{ 265{
265 QListIterator<QIMPenProfile> it( profileList ); 266 QListIterator<QIMPenProfile> it( profileList );
266 for ( ; it.current(); ++it ) { 267 for ( ; it.current(); ++it ) {
267 if ( it.current()->name() == name ) { 268 if ( it.current()->name() == name ) {
268 profile = it.current(); 269 profile = it.current();
269 break; 270 break;
270 } 271 }
271 } 272 }
272 273
273 if ( !it.current() ) 274 if ( !it.current() )
274 return; 275 return;
275 276
276 pw->clearCharSets(); 277 pw->clearCharSets();
277 baseSets.clear(); 278 baseSets.clear();
278 279
279 matcher->setMultiStrokeTimeout( profile->multiStrokeTimeout() ); 280 matcher->setMultiStrokeTimeout( profile->multiStrokeTimeout() );
280 matcher->setWordMatchingEnabled( profile->matchWords() ); 281 matcher->setWordMatchingEnabled( profile->matchWords() );
281 282
282 if ( !Global::fixedDawg().root() || !matcher->isWordMatchingEnabled() ) 283 if ( !Global::fixedDawg().root() || !matcher->isWordMatchingEnabled() )
283 wordPicker->hide(); 284 wordPicker->hide();
284 else 285 else
285 wordPicker->show(); 286 wordPicker->show();
286 287
287 if ( profile->uppercase() && profile->style() == QIMPenProfile::BothCases ) { 288 if ( profile->uppercase() && profile->style() == QIMPenProfile::BothCases ) {
288 baseSets.append( profile->uppercase() ); 289 baseSets.append( profile->uppercase() );
289 pw->insertCharSet( profile->uppercase() ); 290 pw->insertCharSet( profile->uppercase() );
290 } 291 }
291 292
292 if ( profile->lowercase() ) { 293 if ( profile->lowercase() ) {
293 baseSets.append( profile->lowercase() ); 294 baseSets.append( profile->lowercase() );
294 pw->insertCharSet( profile->lowercase(), profile->style() == QIMPenProfile::BothCases ? 1 : 2 ); 295 pw->insertCharSet( profile->lowercase(), profile->style() == QIMPenProfile::BothCases ? 1 : 2 );
295 } 296 }
296 297
297 if ( profile->numeric() ) { 298 if ( profile->numeric() ) {
298 baseSets.append( profile->numeric() ); 299 baseSets.append( profile->numeric() );
299 pw->insertCharSet( profile->numeric() ); 300 pw->insertCharSet( profile->numeric() );
300 } 301 }
301 302
302 if ( helpDlg ) 303 if ( helpDlg )
303 delete (HandwritingHelp*) helpDlg; 304 delete (HandwritingHelp*) helpDlg;
304} 305}
305 306
306void QIMPenInput::wordPicked( const QString &w ) 307void QIMPenInput::wordPicked( const QString &w )
307{ 308{
308 int bs = matcher->word().length(); 309 int bs = matcher->word().length();
309 for ( int i = 0; i < bs; i++ ) 310 for ( int i = 0; i < bs; i++ )
310 keypress( Qt::Key_Backspace << 16 ); 311 keypress( Qt::Key_Backspace << 16 );
311 312
312 for ( unsigned int i = 0; i < w.length(); i++ ) 313 for ( unsigned int i = 0; i < w.length(); i++ )
313 keypress( w[i].unicode() ); 314 keypress( w[i].unicode() );
314 315
315 matcher->resetState(); 316 matcher->resetState();
316 wordPicker->clear(); 317 wordPicker->clear();
317} 318}
318 319
319void QIMPenInput::selectCharSet( int idx ) 320void QIMPenInput::selectCharSet( int idx )
320{ 321{
321 if ( mode == Switch ) { 322 if ( mode == Switch ) {
322 //qDebug( "Switch back to normal" ); 323 //odebug << "Switch back to normal" << oendl;
323 pw->changeCharSet( baseSets.at(currCharSet), currCharSet ); 324 pw->changeCharSet( baseSets.at(currCharSet), currCharSet );
324 mode = Normal; 325 mode = Normal;
325 } 326 }
326 currCharSet = idx; 327 currCharSet = idx;
327} 328}
328 329
329void QIMPenInput::beginStroke() 330void QIMPenInput::beginStroke()
330{ 331{
331} 332}
332 333
333void QIMPenInput::strokeEntered( QIMPenStroke * ) 334void QIMPenInput::strokeEntered( QIMPenStroke * )
334{ 335{
335 pw->greyStroke(); 336 pw->greyStroke();
336} 337}
337 338
338void QIMPenInput::erase() 339void QIMPenInput::erase()
339{ 340{
340 keypress( Qt::Key_Backspace << 16 ); 341 keypress( Qt::Key_Backspace << 16 );
341} 342}
342 343
343void QIMPenInput::matchedCharacters( const QIMPenCharMatchList &cl ) 344void QIMPenInput::matchedCharacters( const QIMPenCharMatchList &cl )
344{ 345{
345 const QIMPenChar *ch = cl.first().penChar; 346 const QIMPenChar *ch = cl.first().penChar;
346 int scan = ch->character() >> 16; 347 int scan = ch->character() >> 16;
347 348
348 if ( scan < QIMPenChar::ModeBase ) 349 if ( scan < QIMPenChar::ModeBase )
349 return; 350 return;
350 351
351 // We matched a special character... 352 // We matched a special character...
352 353
353 switch ( scan ) { 354 switch ( scan ) {
354 case QIMPenChar::Caps: 355 case QIMPenChar::Caps:
355 if ( profile->style() == QIMPenProfile::ToggleCases ) { 356 if ( profile->style() == QIMPenProfile::ToggleCases ) {
356 // qDebug( "Caps" ); 357 // odebug << "Caps" << oendl;
358 //
357 if ( mode == SwitchLock ) { 359 if ( mode == SwitchLock ) {
358 // qDebug( "Switch to normal" ); 360 // odebug << "Switch to normal" << oendl;
359 pw->changeCharSet( profile->lowercase(), currCharSet ); 361 pw->changeCharSet( profile->lowercase(), currCharSet );
360 mode = Switch; 362 mode = Switch;
361 } else { 363 } else {
362 // qDebug( "Switch to upper" ); 364 // odebug << "Switch to upper" << oendl;
363 pw->changeCharSet( profile->uppercase(), currCharSet ); 365 pw->changeCharSet( profile->uppercase(), currCharSet );
364 mode = Switch; 366 mode = Switch;
365 } 367 }
366 } 368 }
367 break; 369 break;
368 case QIMPenChar::CapsLock: 370 case QIMPenChar::CapsLock:
369 if ( profile->style() == QIMPenProfile::ToggleCases ) { 371 if ( profile->style() == QIMPenProfile::ToggleCases ) {
370 // qDebug( "CapsLock" ); 372 // odebug << "CapsLock" << oendl;
371 if ( mode == Switch && 373 if ( mode == Switch &&
372 baseSets.at(currCharSet) == profile->uppercase() ) { 374 baseSets.at(currCharSet) == profile->uppercase() ) {
373 // qDebug( "Switch to normal" ); 375 // odebug << "Switch to normal" << oendl;
374 pw->changeCharSet( profile->lowercase(), currCharSet ); 376 pw->changeCharSet( profile->lowercase(), currCharSet );
375 // change our base set back to lower. 377 // change our base set back to lower.
376 baseSets.remove( currCharSet ); 378 baseSets.remove( currCharSet );
377 baseSets.insert( currCharSet, profile->lowercase() ); 379 baseSets.insert( currCharSet, profile->lowercase() );
378 mode = Normal; 380 mode = Normal;
379 } else { 381 } else {
380 // qDebug( "Switch to caps lock" ); 382 // odebug << "Switch to caps lock" << oendl;
381 pw->changeCharSet( profile->uppercase(), currCharSet ); 383 pw->changeCharSet( profile->uppercase(), currCharSet );
382 // change our base set to upper. 384 // change our base set to upper.
383 baseSets.remove( currCharSet ); 385 baseSets.remove( currCharSet );
384 baseSets.insert( currCharSet, profile->uppercase() ); 386 baseSets.insert( currCharSet, profile->uppercase() );
385 mode = SwitchLock; 387 mode = SwitchLock;
386 } 388 }
387 } 389 }
388 break; 390 break;
389 case QIMPenChar::Punctuation: 391 case QIMPenChar::Punctuation:
390 if ( profile->punctuation() ) { 392 if ( profile->punctuation() ) {
391 //qDebug( "Switch to punctuation" ); 393 //odebug << "Switch to punctuation" << oendl;
392 pw->changeCharSet( profile->punctuation(), currCharSet ); 394 pw->changeCharSet( profile->punctuation(), currCharSet );
393 mode = Switch; 395 mode = Switch;
394 } 396 }
395 break; 397 break;
396 case QIMPenChar::Symbol: 398 case QIMPenChar::Symbol:
397 if ( profile->symbol() ) { 399 if ( profile->symbol() ) {
398 //qDebug( "Switch to symbol" ); 400 //odebug << "Switch to symbol" << oendl ;
399 pw->changeCharSet( profile->symbol(), currCharSet ); 401 pw->changeCharSet( profile->symbol(), currCharSet );
400 mode = Switch; 402 mode = Switch;
401 } 403 }
402 break; 404 break;
403 case QIMPenChar::Shortcut: 405 case QIMPenChar::Shortcut:
404 if ( shortcutCharSet ) { 406 if ( shortcutCharSet ) {
405 pw->changeCharSet( shortcutCharSet, currCharSet ); 407 pw->changeCharSet( shortcutCharSet, currCharSet );
406 mode = Switch; 408 mode = Switch;
407 } 409 }
408 break; 410 break;
409 case QIMPenChar::Extended: 411 case QIMPenChar::Extended:
410 handleExtended( ch->data() ); 412 handleExtended( ch->data() );
411 break; 413 break;
412 } 414 }
413} 415}
414 416
415void QIMPenInput::keypress( uint scan_uni ) 417void QIMPenInput::keypress( uint scan_uni )
416{ 418{
417 int scan = scan_uni >> 16; 419 int scan = scan_uni >> 16;
418 if ( !scan ) { 420 if ( !scan ) {
419 if ( scan_uni >= 'a' && scan_uni <= 'z' ) { 421 if ( scan_uni >= 'a' && scan_uni <= 'z' ) {
420 scan = Qt::Key_A + scan_uni - 'a'; 422 scan = Qt::Key_A + scan_uni - 'a';
421 } else if ( scan_uni >= 'A' && scan_uni <= 'Z' ) { 423 } else if ( scan_uni >= 'A' && scan_uni <= 'Z' ) {
422 scan = Qt::Key_A + scan_uni - 'A'; 424 scan = Qt::Key_A + scan_uni - 'A';
423 } else if ( scan_uni == ' ' ) { 425 } else if ( scan_uni == ' ' ) {
424 scan = Qt::Key_Space; 426 scan = Qt::Key_Space;
425 } 427 }
426 } 428 }
427 429
428 switch ( scan ) { 430 switch ( scan ) {
429 case Key_Tab: 431 case Key_Tab:
430 scan_uni = 9; 432 scan_uni = 9;
431 break; 433 break;
432 case Key_Return: 434 case Key_Return:
433 scan_uni = 13; 435 scan_uni = 13;
434 break; 436 break;
435 case Key_Backspace: 437 case Key_Backspace:
436 scan_uni = 8; 438 scan_uni = 8;
437 break; 439 break;
438 case Key_Escape: 440 case Key_Escape:
439 scan_uni = 27; 441 scan_uni = 27;
440 break; 442 break;
441 default: 443 default:
442 break; 444 break;
443 } 445 }
444 446
445 if ( mode == Switch ) { 447 if ( mode == Switch ) {
446 //qDebug( "Switch back to normal" ); 448 //odebug << "Switch back to normal" << oendl ;
447 pw->changeCharSet( baseSets.at(currCharSet), currCharSet ); 449 pw->changeCharSet( baseSets.at(currCharSet), currCharSet );
448 if ( baseSets.at(currCharSet) == profile->uppercase() ) 450 if ( baseSets.at(currCharSet) == profile->uppercase() )
449 mode = SwitchLock; 451 mode = SwitchLock;
450 else 452 else
451 mode = Normal; 453 mode = Normal;
452 } 454 }
453 455
454 emit key( scan_uni&0xffff, scan, 0, true, false ); 456 emit key( scan_uni&0xffff, scan, 0, true, false );
455 emit key( scan_uni&0xffff, scan, 0, false, false ); 457 emit key( scan_uni&0xffff, scan, 0, false, false );
456} 458}
457 459
458void QIMPenInput::handleExtended( const QString &ex ) 460void QIMPenInput::handleExtended( const QString &ex )
459{ 461{
460 if ( ex.find( "Select" ) == 0 ) { 462 if ( ex.find( "Select" ) == 0 ) {
461 QString set = ex.mid( 7 ); 463 QString set = ex.mid( 7 );
462 qDebug( "Select new profile: %s", set.latin1() ); 464 odebug << "Select new profile: " << set.latin1() << oendl;
463 selectProfile( set ); 465 selectProfile( set );
464 } 466 }
465} 467}
466 468
467void QIMPenInput::help() 469void QIMPenInput::help()
468{ 470{
469 if ( helpDlg ) 471 if ( helpDlg )
470 delete (HandwritingHelp*) helpDlg; 472 delete (HandwritingHelp*) helpDlg;
471 helpDlg = new HandwritingHelp( profile, 0, 0, WDestructiveClose ); 473 helpDlg = new HandwritingHelp( profile, 0, 0, WDestructiveClose );
472 helpDlg->showMaximized(); 474 helpDlg->showMaximized();
473 helpDlg->show(); 475 helpDlg->show();
474 helpDlg->raise(); 476 helpDlg->raise();
475} 477}
476 478
477/*! 479/*!
478 Open the setup dialog 480 Open the setup dialog
479*/ 481*/
480void QIMPenInput::setup() 482void QIMPenInput::setup()
481{ 483{
482 if ( !setupDlg ) { 484 if ( !setupDlg ) {
483 // We are working with our copy of the char sets here. 485 // We are working with our copy of the char sets here.
484 setupDlg = new QIMPenSetup( profile, 0, 0, TRUE ); 486 setupDlg = new QIMPenSetup( profile, 0, 0, TRUE );
485 setupDlg->editor()->selectCharSet( profile->charSets().at(1) );// lower case? This is crap. 487 setupDlg->editor()->selectCharSet( profile->charSets().at(1) );// lower case? This is crap.
486 if ( qApp->desktop()->width() < 640 ) 488 if ( qApp->desktop()->width() < 640 )
487 setupDlg->showMaximized(); 489 setupDlg->showMaximized();
488 Global::hideInputMethod(); 490 Global::hideInputMethod();
489 setupDlg->exec(); 491 setupDlg->exec();
490 loadProfiles(); 492 loadProfiles();
491 delete setupDlg; 493 delete setupDlg;
492 setupDlg = 0; 494 setupDlg = 0;
493 Global::showInputMethod(); 495 Global::showInputMethod();
494 } else { 496 } else {
495 setupDlg->raise(); 497 setupDlg->raise();
496 } 498 }
497} 499}
498 500
499void QIMPenInput::backspace() 501void QIMPenInput::backspace()
500{ 502{
501 keypress( Qt::Key_Backspace << 16 ); 503 keypress( Qt::Key_Backspace << 16 );
502 matcher->backspace(); 504 matcher->backspace();
503} 505}
504 506
505void QIMPenInput::enter() 507void QIMPenInput::enter()
506{ 508{
507 keypress( Qt::Key_Return << 16 ); 509 keypress( Qt::Key_Return << 16 );
508 matcher->resetState(); 510 matcher->resetState();
509} 511}
510 512
511 513
512void QIMPenInput::resetState() 514void QIMPenInput::resetState()
513{ 515{
514 matcher->resetState(); 516 matcher->resetState();
515} 517}
diff --git a/inputmethods/handwriting/qimpenmatch.cpp b/inputmethods/handwriting/qimpenmatch.cpp
index 0d3e25a..a0448b6 100644
--- a/inputmethods/handwriting/qimpenmatch.cpp
+++ b/inputmethods/handwriting/qimpenmatch.cpp
@@ -1,352 +1,353 @@
1/********************************************************************** 1/**********************************************************************
2** Copyright (C) 2000 Trolltech AS. All rights reserved. 2** Copyright (C) 2000 Trolltech AS. All rights reserved.
3** 3**
4** This file is part of Qtopia Environment. 4** This file is part of Qtopia Environment.
5** 5**
6** This file may be distributed and/or modified under the terms of the 6** This file may be distributed and/or modified under the terms of the
7** GNU General Public License version 2 as published by the Free Software 7** GNU General Public License version 2 as published by the Free Software
8** Foundation and appearing in the file LICENSE.GPL included in the 8** Foundation and appearing in the file LICENSE.GPL included in the
9** packaging of this file. 9** packaging of this file.
10** 10**
11** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE 11** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
12** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. 12** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
13** 13**
14** See http://www.trolltech.com/gpl/ for GPL licensing information. 14** See http://www.trolltech.com/gpl/ for GPL licensing information.
15** 15**
16** Contact info@trolltech.com if any conditions of this licensing are 16** Contact info@trolltech.com if any conditions of this licensing are
17** not clear to you. 17** not clear to you.
18** 18**
19**********************************************************************/ 19**********************************************************************/
20 20
21#include "qimpenmatch.h" 21#include "qimpenmatch.h"
22 22
23#include <qpe/qdawg.h> 23#include <qpe/qdawg.h>
24#include <qpe/global.h> 24#include <qpe/global.h>
25 25
26#include <qapplication.h> 26#include <qapplication.h>
27#include <qtimer.h> 27#include <qtimer.h>
28#include <opie2/odebug.h>
28 29
29#include <limits.h> 30#include <limits.h>
30 31
31 #define ERROR_THRESHOLD 200000 32 #define ERROR_THRESHOLD 200000
32 #define LOOKAHEAD_ERROR 2500 33 #define LOOKAHEAD_ERROR 2500
33//#define DEBUG_QIMPEN 34//#define DEBUG_QIMPEN
34 35
35QIMPenMatch::QIMPenMatch( QObject *parent, const char *name ) 36QIMPenMatch::QIMPenMatch( QObject *parent, const char *name )
36 : QObject( parent, name ) 37 : QObject( parent, name )
37{ 38{
38 strokes.setAutoDelete( TRUE ); 39 strokes.setAutoDelete( TRUE );
39 wordChars.setAutoDelete( TRUE ); 40 wordChars.setAutoDelete( TRUE );
40 wordMatches.setAutoDelete( TRUE ); 41 wordMatches.setAutoDelete( TRUE );
41 42
42 multiTimer = new QTimer( this ); 43 multiTimer = new QTimer( this );
43 connect( multiTimer, SIGNAL(timeout()), this, SLOT(endMulti()) ); 44 connect( multiTimer, SIGNAL(timeout()), this, SLOT(endMulti()) );
44 45
45 prevMatchChar = 0; 46 prevMatchChar = 0;
46 prevMatchError = INT_MAX; 47 prevMatchError = INT_MAX;
47 charSet = 0; 48 charSet = 0;
48 multiCharSet = 0; 49 multiCharSet = 0;
49 multiTimeout = 500; 50 multiTimeout = 500;
50 canErase = FALSE; 51 canErase = FALSE;
51 doWordMatching = true; 52 doWordMatching = true;
52} 53}
53 54
54QIMPenMatch::~QIMPenMatch() 55QIMPenMatch::~QIMPenMatch()
55{ 56{
56} 57}
57 58
58void QIMPenMatch::setCharSet( QIMPenCharSet *cs ) 59void QIMPenMatch::setCharSet( QIMPenCharSet *cs )
59{ 60{
60 charSet = cs; 61 charSet = cs;
61} 62}
62 63
63void QIMPenMatch::beginStroke() 64void QIMPenMatch::beginStroke()
64{ 65{
65 multiTimer->stop(); 66 multiTimer->stop();
66} 67}
67 68
68void QIMPenMatch::strokeEntered( QIMPenStroke *st ) 69void QIMPenMatch::strokeEntered( QIMPenStroke *st )
69{ 70{
70#ifdef DEBUG_QIMPEN 71#ifdef DEBUG_QIMPEN
71 qDebug( "---------- new stroke -------------" ); 72 odebug << "---------- new stroke -------------" << oendl;
72#endif 73#endif
73 strokes.append( new QIMPenStroke( *st ) ); 74 strokes.append( new QIMPenStroke( *st ) );
74 75
75 QIMPenChar testChar; 76 QIMPenChar testChar;
76 QIMPenStrokeIterator it(strokes); 77 QIMPenStrokeIterator it(strokes);
77 for ( ; it.current(); ++it ) { 78 for ( ; it.current(); ++it ) {
78 testChar.addStroke( it.current() ); 79 testChar.addStroke( it.current() );
79 } 80 }
80 81
81 QIMPenCharMatchList ml; 82 QIMPenCharMatchList ml;
82 if ( strokes.count() > 1 && multiCharSet ) { 83 if ( strokes.count() > 1 && multiCharSet ) {
83#ifdef DEBUG_QIMPEN 84#ifdef DEBUG_QIMPEN
84 qDebug( "Matching against multi set" ); 85 odebug << "Matching against multi set" << oendl;
85#endif 86#endif
86 ml = multiCharSet->match( &testChar ); 87 ml = multiCharSet->match( &testChar );
87 } else { 88 } else {
88#ifdef DEBUG_QIMPEN 89#ifdef DEBUG_QIMPEN
89 qDebug( "Matching against single set" ); 90 odebug << "Matching against single set" << oendl;
90#endif 91#endif
91 ml = charSet->match( &testChar ); 92 ml = charSet->match( &testChar );
92 } 93 }
93 94
94 processMatches( ml ); 95 processMatches( ml );
95} 96}
96 97
97void QIMPenMatch::processMatches( QIMPenCharMatchList &ml ) 98void QIMPenMatch::processMatches( QIMPenCharMatchList &ml )
98{ 99{
99#ifdef DEBUG_QIMPEN 100#ifdef DEBUG_QIMPEN
100 qDebug( "Entering strokes.count() = %d", strokes.count() ); 101 odebug << "Entering strokes.count() = " << strokes.count() << oendl;
101#endif 102#endif
102 QIMPenCharMatch candidate1 = { INT_MAX, 0 }; 103 QIMPenCharMatch candidate1 = { INT_MAX, 0 };
103 QIMPenCharMatch candidate2 = { INT_MAX, 0 }; 104 QIMPenCharMatch candidate2 = { INT_MAX, 0 };
104 QIMPenCharMatchList ml2; 105 QIMPenCharMatchList ml2;
105 106
106 if ( ml.count() ) {//&& 107 if ( ml.count() ) {//&&
107 // ml.first().penChar->penStrokes().count() == strokes.count() ) { 108 // ml.first().penChar->penStrokes().count() == strokes.count() ) {
108 candidate1 = ml.first(); 109 candidate1 = ml.first();
109#ifdef DEBUG_QIMPEN 110#ifdef DEBUG_QIMPEN
110 qDebug( QString("Candidate1 = %1").arg(QChar(candidate1.penChar->character())) ); 111 odebug << "Candidate1 = " << candidate1.penChar->character() << oendl;
111#endif 112#endif
112 } 113 }
113 114
114 if ( strokes.count() > 1 ) { 115 if ( strokes.count() > 1 ) {
115 // See if the last stroke can match a new character 116 // See if the last stroke can match a new character
116 QIMPenChar testChar; 117 QIMPenChar testChar;
117 QIMPenStroke *st = strokes.at(strokes.count()-1); 118 QIMPenStroke *st = strokes.at(strokes.count()-1);
118 testChar.addStroke( st ); 119 testChar.addStroke( st );
119 ml2 = charSet->match( &testChar ); 120 ml2 = charSet->match( &testChar );
120 if ( ml2.count() ) { 121 if ( ml2.count() ) {
121 candidate2 = ml2.first(); 122 candidate2 = ml2.first();
122#ifdef DEBUG_QIMPEN 123#ifdef DEBUG_QIMPEN
123 qDebug( QString("Candidate2 = %1").arg(QChar(candidate2.penChar->character())) ); 124 odebug << "Candidate2 = " << candidate2.penChar->character() << oendl;
124#endif 125#endif
125 } 126 }
126 } 127 }
127 128
128 bool eraseLast = FALSE; 129 bool eraseLast = FALSE;
129 bool output = TRUE; 130 bool output = TRUE;
130 131
131 if ( candidate1.penChar && candidate2.penChar ) { 132 if ( candidate1.penChar && candidate2.penChar ) {
132 // Hmmm, a multi-stroke or a new character are both possible. 133 // Hmmm, a multi-stroke or a new character are both possible.
133 // Bias the multi-stroke case. 134 // Bias the multi-stroke case.
134 if ( QMAX(candidate2.error, prevMatchError)*3 < candidate1.error ) { 135 if ( QMAX(candidate2.error, prevMatchError)*3 < candidate1.error ) {
135 int i = strokes.count()-1; 136 int i = strokes.count()-1;
136 while ( i-- ) { 137 while ( i-- ) {
137 strokes.removeFirst(); 138 strokes.removeFirst();
138 emit removeStroke(); 139 emit removeStroke();
139 } 140 }
140 prevMatchChar = candidate2.penChar; 141 prevMatchChar = candidate2.penChar;
141 prevMatchError = candidate2.error; 142 prevMatchError = candidate2.error;
142 multiCharSet = charSet; 143 multiCharSet = charSet;
143 ml = ml2; 144 ml = ml2;
144#ifdef DEBUG_QIMPEN 145#ifdef DEBUG_QIMPEN
145 qDebug( "** Using Candidate2" ); 146 odebug << "** Using Candidate2" << oendl;
146#endif 147#endif
147 } else { 148 } else {
148 if ( (prevMatchChar->character() >> 16) != Qt::Key_Backspace && 149 if ( (prevMatchChar->character() >> 16) != Qt::Key_Backspace &&
149 (prevMatchChar->character() >> 16) < QIMPenChar::ModeBase ) 150 (prevMatchChar->character() >> 16) < QIMPenChar::ModeBase )
150 eraseLast = TRUE; 151 eraseLast = TRUE;
151 prevMatchChar = candidate1.penChar; 152 prevMatchChar = candidate1.penChar;
152 prevMatchError = candidate1.error; 153 prevMatchError = candidate1.error;
153#ifdef DEBUG_QIMPEN 154#ifdef DEBUG_QIMPEN
154 qDebug( "** Using Candidate1, with erase" ); 155 odebug << "** Using Candidate1, with erase" << oendl;
155#endif 156#endif
156 } 157 }
157 } else if ( candidate1.penChar ) { 158 } else if ( candidate1.penChar ) {
158 if ( strokes.count() != 1 ) 159 if ( strokes.count() != 1 )
159 eraseLast = TRUE; 160 eraseLast = TRUE;
160 else 161 else
161 multiCharSet = charSet; 162 multiCharSet = charSet;
162 prevMatchChar = candidate1.penChar; 163 prevMatchChar = candidate1.penChar;
163 prevMatchError = candidate1.error; 164 prevMatchError = candidate1.error;
164#ifdef DEBUG_QIMPEN 165#ifdef DEBUG_QIMPEN
165 qDebug( "** Using Candidate1" ); 166 odebug << "** Using Candidate1" << oendl;
166#endif 167#endif
167 } else if ( candidate2.penChar ) { 168 } else if ( candidate2.penChar ) {
168 int i = strokes.count()-1; 169 int i = strokes.count()-1;
169 while ( i-- ) { 170 while ( i-- ) {
170 strokes.removeFirst(); 171 strokes.removeFirst();
171 emit removeStroke(); 172 emit removeStroke();
172 } 173 }
173 prevMatchChar = candidate2.penChar; 174 prevMatchChar = candidate2.penChar;
174 prevMatchError = candidate2.error; 175 prevMatchError = candidate2.error;
175 multiCharSet = charSet; 176 multiCharSet = charSet;
176 ml = ml2; 177 ml = ml2;
177#ifdef DEBUG_QIMPEN 178#ifdef DEBUG_QIMPEN
178 qDebug( "** Using Candidate2" ); 179 odebug << "** Using Candidate2" << oendl;
179#endif 180#endif
180 } else { 181 } else {
181 if ( !ml.count() ) { 182 if ( !ml.count() ) {
182#ifdef DEBUG_QIMPEN 183#ifdef DEBUG_QIMPEN
183 qDebug( "** Failed" ); 184 odebug << "** Failed" << oendl;
184#endif 185#endif
185 canErase = FALSE; 186 canErase = FALSE;
186 } else { 187 } else {
187#ifdef DEBUG_QIMPEN 188#ifdef DEBUG_QIMPEN
188 qDebug( "Need more strokes" ); 189 odebug << "Need more strokes" << oendl;
189#endif 190#endif
190 if ( strokes.count() == 1 ) 191 if ( strokes.count() == 1 )
191 canErase = FALSE; 192 canErase = FALSE;
192 multiCharSet = charSet; 193 multiCharSet = charSet;
193 } 194 }
194 output = FALSE; 195 output = FALSE;
195 emit noMatch(); 196 emit noMatch();
196 } 197 }
197 198
198 if ( eraseLast && canErase ) { 199 if ( eraseLast && canErase ) {
199#ifdef DEBUG_QIMPEN 200#ifdef DEBUG_QIMPEN
200 qDebug( "deleting last" ); 201 odebug << "deleting last" << oendl;
201#endif 202#endif
202 emit erase(); 203 emit erase();
203 wordChars.removeLast(); 204 wordChars.removeLast();
204 wordEntered.truncate( wordEntered.length() - 1 ); 205 wordEntered.truncate( wordEntered.length() - 1 );
205 } 206 }
206 207
207 if ( output ) { 208 if ( output ) {
208 emit matchedCharacters( ml ); 209 emit matchedCharacters( ml );
209 uint code = prevMatchChar->character() >> 16; 210 uint code = prevMatchChar->character() >> 16;
210 if ( code < QIMPenChar::ModeBase ) { 211 if ( code < QIMPenChar::ModeBase ) {
211 updateWordMatch( ml ); 212 updateWordMatch( ml );
212 emit keypress( prevMatchChar->character() ); 213 emit keypress( prevMatchChar->character() );
213 } 214 }
214 canErase = TRUE; 215 canErase = TRUE;
215 } 216 }
216 217
217 if ( strokes.count() ) 218 if ( strokes.count() )
218 multiTimer->start( multiTimeout, TRUE ); 219 multiTimer->start( multiTimeout, TRUE );
219} 220}
220 221
221void QIMPenMatch::updateWordMatch( QIMPenCharMatchList &ml ) 222void QIMPenMatch::updateWordMatch( QIMPenCharMatchList &ml )
222{ 223{
223 if ( !ml.count() || !doWordMatching ) 224 if ( !ml.count() || !doWordMatching )
224 return; 225 return;
225 int ch = ml.first().penChar->character(); 226 int ch = ml.first().penChar->character();
226 QChar qch( ch ); 227 QChar qch( ch );
227 int code = ch >> 16; 228 int code = ch >> 16;
228 if ( qch.isPunct() || qch.isSpace() || 229 if ( qch.isPunct() || qch.isSpace() ||
229 code == Qt::Key_Enter || code == Qt::Key_Return || 230 code == Qt::Key_Enter || code == Qt::Key_Return ||
230 code == Qt::Key_Tab || code == Qt::Key_Escape ) { 231 code == Qt::Key_Tab || code == Qt::Key_Escape ) {
231 //qDebug( "Word Matching: Clearing word" ); 232 //odebug << "Word Matching: Clearing word" << oendl;
232 wordChars.clear(); 233 wordChars.clear();
233 wordMatches.clear(); 234 wordMatches.clear();
234 wordEntered = QString(); 235 wordEntered = QString();
235 } else if ( code == Qt::Key_Backspace ) { 236 } else if ( code == Qt::Key_Backspace ) {
236 //qDebug( "Word Matching: Handle backspace" ); 237 //odebug << "Word Matching: Handle backspace" << oendl;
237 wordChars.removeLast(); 238 wordChars.removeLast();
238 wordEntered.truncate( wordEntered.length() - 1 ); 239 wordEntered.truncate( wordEntered.length() - 1 );
239 matchWords(); 240 matchWords();
240 } else { 241 } else {
241 QIMPenChar *matchCh; 242 QIMPenChar *matchCh;
242 243
243 wordChars.append( new QIMPenCharMatchList() ); 244 wordChars.append( new QIMPenCharMatchList() );
244 wordEntered += ml.first().penChar->character(); 245 wordEntered += ml.first().penChar->character();
245 246
246 QIMPenCharMatchList::Iterator it; 247 QIMPenCharMatchList::Iterator it;
247 for ( it = ml.begin(); it != ml.end(); ++it ) { 248 for ( it = ml.begin(); it != ml.end(); ++it ) {
248 matchCh = (*it).penChar; 249 matchCh = (*it).penChar;
249 250
250 if ( matchCh->penStrokes().count() == strokes.count() ) { 251 if ( matchCh->penStrokes().count() == strokes.count() ) {
251 QChar ch(matchCh->character()); 252 QChar ch(matchCh->character());
252 if ( !ch.isPunct() && !ch.isSpace() ) { 253 if ( !ch.isPunct() && !ch.isSpace() ) {
253 wordChars.last()->append( QIMPenCharMatch( (*it) ) ); 254 wordChars.last()->append( QIMPenCharMatch( (*it) ) );
254 } 255 }
255 } 256 }
256 } 257 }
257 matchWords(); 258 matchWords();
258 } 259 }
259 if ( !wordMatches.count() || wordMatches.getFirst()->word != wordEntered ) 260 if ( !wordMatches.count() || wordMatches.getFirst()->word != wordEntered )
260 wordMatches.prepend( new MatchWord( wordEntered, 0 ) ); 261 wordMatches.prepend( new MatchWord( wordEntered, 0 ) );
261 emit matchedWords( wordMatches ); 262 emit matchedWords( wordMatches );
262} 263}
263 264
264void QIMPenMatch::matchWords() 265void QIMPenMatch::matchWords()
265{ 266{
266 if ( wordEntered.length() > 0 ) { 267 if ( wordEntered.length() > 0 ) {
267 // more leaniency if we don't have many matches 268 // more leaniency if we don't have many matches
268 if ( badMatches < 200 ) 269 if ( badMatches < 200 )
269 errorThreshold += (200 - badMatches) * 100; 270 errorThreshold += (200 - badMatches) * 100;
270 } else 271 } else
271 errorThreshold = ERROR_THRESHOLD; 272 errorThreshold = ERROR_THRESHOLD;
272 wordMatches.clear(); 273 wordMatches.clear();
273 goodMatches = 0; 274 goodMatches = 0;
274 badMatches = 0; 275 badMatches = 0;
275 if ( wordChars.count() > 0 ) { 276 if ( wordChars.count() > 0 ) {
276 maxGuess = (int)wordChars.count() * 2; 277 maxGuess = (int)wordChars.count() * 2;
277 if ( maxGuess < 3 ) 278 if ( maxGuess < 3 )
278 maxGuess = 3; 279 maxGuess = 3;
279 QString str; 280 QString str;
280 scanDict( Global::fixedDawg().root(), 0, str, 0 ); 281 scanDict( Global::fixedDawg().root(), 0, str, 0 );
281/* 282/*
282 QListIterator<MatchWord> it( wordMatches); 283 QListIterator<MatchWord> it( wordMatches);
283 for ( ; it.current(); ++it ) { 284 for ( ; it.current(); ++it ) {
284 qDebug( QString("Match word: %1").arg(it.current()->word) ); 285 odebug << "Match word: " << it.current()->word << oendl;
285 } 286 }
286*/ 287*/
287 } 288 }
288 //qDebug( "Possibles: Good %d, total %d", goodMatches, wordMatches.count() ); 289 //odebug << "Possibles: Good " << goodMatches << ", total " << wordMatches.count() << oendl;
289 wordMatches.sort(); 290 wordMatches.sort();
290} 291}
291 292
292void QIMPenMatch::scanDict( const QDawg::Node* n, int ipos, const QString& str, int error ) 293void QIMPenMatch::scanDict( const QDawg::Node* n, int ipos, const QString& str, int error )
293{ 294{
294 if ( !n ) 295 if ( !n )
295 return; 296 return;
296 if ( error / (ipos+1) > errorThreshold ) 297 if ( error / (ipos+1) > errorThreshold )
297 return; 298 return;
298 299
299 while (n) { 300 while (n) {
300 if ( goodMatches > 20 ) 301 if ( goodMatches > 20 )
301 break; 302 break;
302 if ( ipos < (int)wordChars.count() ) { 303 if ( ipos < (int)wordChars.count() ) {
303 int i; 304 int i;
304 QChar testCh = QChar(n->letter()); 305 QChar testCh = QChar(n->letter());
305 QIMPenCharMatchList::Iterator it; 306 QIMPenCharMatchList::Iterator it;
306 for ( i = 0, it = wordChars.at(ipos)->begin(); 307 for ( i = 0, it = wordChars.at(ipos)->begin();
307 it != wordChars.at(ipos)->end() && i < 8; ++it, i++ ) { 308 it != wordChars.at(ipos)->end() && i < 8; ++it, i++ ) {
308 QChar ch( (*it).penChar->character() ); 309 QChar ch( (*it).penChar->character() );
309 if ( ch == testCh || ( !ipos && ch.lower() == testCh.lower() ) ) { 310 if ( ch == testCh || ( !ipos && ch.lower() == testCh.lower() ) ) {
310 int newerr = error + (*it).error; 311 int newerr = error + (*it).error;
311 if ( testCh.category() == QChar::Letter_Uppercase ) 312 if ( testCh.category() == QChar::Letter_Uppercase )
312 ch = testCh; 313 ch = testCh;
313 QString newstr( str + ch ); 314 QString newstr( str + ch );
314 if ( n->isWord() && ipos == (int)wordChars.count() - 1 ) { 315 if ( n->isWord() && ipos == (int)wordChars.count() - 1 ) {
315 wordMatches.append( new MatchWord( newstr, newerr ) ); 316 wordMatches.append( new MatchWord( newstr, newerr ) );
316 goodMatches++; 317 goodMatches++;
317 } 318 }
318 scanDict( n->jump(), ipos+1, newstr, newerr ); 319 scanDict( n->jump(), ipos+1, newstr, newerr );
319 } 320 }
320 } 321 }
321 } else if ( badMatches < 200 && ipos < maxGuess ) { 322 } else if ( badMatches < 200 && ipos < maxGuess ) {
322 int d = ipos - wordChars.count(); 323 int d = ipos - wordChars.count();
323 int newerr = error + ERROR_THRESHOLD + LOOKAHEAD_ERROR*d; 324 int newerr = error + ERROR_THRESHOLD + LOOKAHEAD_ERROR*d;
324 QString newstr( str + n->letter() ); 325 QString newstr( str + n->letter() );
325 if ( n->isWord() ) { 326 if ( n->isWord() ) {
326 wordMatches.append( new MatchWord( newstr, newerr ) ); 327 wordMatches.append( new MatchWord( newstr, newerr ) );
327 badMatches++; 328 badMatches++;
328 } 329 }
329 scanDict( n->jump(), ipos+1, newstr, newerr ); 330 scanDict( n->jump(), ipos+1, newstr, newerr );
330 } 331 }
331 n = n->next(); 332 n = n->next();
332 } 333 }
333} 334}
334 335
335void QIMPenMatch::backspace() 336void QIMPenMatch::backspace()
336{ 337{
337 wordChars.removeLast(); 338 wordChars.removeLast();
338 wordEntered.truncate( wordEntered.length() - 1 ); 339 wordEntered.truncate( wordEntered.length() - 1 );
339 matchWords(); 340 matchWords();
340 if ( !wordMatches.count() || wordMatches.getFirst()->word != wordEntered ) 341 if ( !wordMatches.count() || wordMatches.getFirst()->word != wordEntered )
341 wordMatches.prepend( new MatchWord( wordEntered, 0 ) ); 342 wordMatches.prepend( new MatchWord( wordEntered, 0 ) );
342 emit matchedWords( wordMatches ); 343 emit matchedWords( wordMatches );
343 if ( wordEntered.length() ) 344 if ( wordEntered.length() )
344 canErase = TRUE; 345 canErase = TRUE;
345} 346}
346 347
347void QIMPenMatch::endMulti() 348void QIMPenMatch::endMulti()
348{ 349{
349 int i = strokes.count(); 350 int i = strokes.count();
350 while ( i-- ) 351 while ( i-- )
351 emit removeStroke(); 352 emit removeStroke();
352 strokes.clear(); 353 strokes.clear();
diff --git a/inputmethods/handwriting/qimpenstroke.cpp b/inputmethods/handwriting/qimpenstroke.cpp
index 3567d6d..14e435a 100644
--- a/inputmethods/handwriting/qimpenstroke.cpp
+++ b/inputmethods/handwriting/qimpenstroke.cpp
@@ -1,314 +1,315 @@
1/********************************************************************** 1/**********************************************************************
2** Copyright (C) 2000 Trolltech AS. All rights reserved. 2** Copyright (C) 2000 Trolltech AS. All rights reserved.
3** 3**
4** This file is part of Qtopia Environment. 4** This file is part of Qtopia Environment.
5** 5**
6** This file may be distributed and/or modified under the terms of the 6** This file may be distributed and/or modified under the terms of the
7** GNU General Public License version 2 as published by the Free Software 7** GNU General Public License version 2 as published by the Free Software
8** Foundation and appearing in the file LICENSE.GPL included in the 8** Foundation and appearing in the file LICENSE.GPL included in the
9** packaging of this file. 9** packaging of this file.
10** 10**
11** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE 11** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
12** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. 12** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
13** 13**
14** See http://www.trolltech.com/gpl/ for GPL licensing information. 14** See http://www.trolltech.com/gpl/ for GPL licensing information.
15** 15**
16** Contact info@trolltech.com if any conditions of this licensing are 16** Contact info@trolltech.com if any conditions of this licensing are
17** not clear to you. 17** not clear to you.
18** 18**
19**********************************************************************/ 19**********************************************************************/
20 20
21#include <qfile.h> 21#include <qfile.h>
22#include <qtl.h> 22#include <qtl.h>
23#include <math.h> 23#include <math.h>
24#include <limits.h> 24#include <limits.h>
25#include <qdatastream.h> 25#include <qdatastream.h>
26#include "qimpenstroke.h" 26#include "qimpenstroke.h"
27#include "opie2/odebug.h"
27 28
28#define QIMPEN_CORRELATION_POINTS 25 29#define QIMPEN_CORRELATION_POINTS 25
29//#define DEBUG_QIMPEN 30//#define DEBUG_QIMPEN
30 31
31/*! 32/*!
32 \class QIMPenStroke qimpenstroke.h 33 \class QIMPenStroke qimpenstroke.h
33 34
34 Handles a single stroke. Can calculate closeness of match to 35 Handles a single stroke. Can calculate closeness of match to
35 another stroke. 36 another stroke.
36*/ 37*/
37 38
38QIMPenStroke::QIMPenStroke() 39QIMPenStroke::QIMPenStroke()
39{ 40{
40} 41}
41 42
42QIMPenStroke::QIMPenStroke( const QIMPenStroke &st ) 43QIMPenStroke::QIMPenStroke( const QIMPenStroke &st )
43{ 44{
44 startPoint = st.startPoint; 45 startPoint = st.startPoint;
45 lastPoint = st.lastPoint; 46 lastPoint = st.lastPoint;
46 links = st.links.copy(); 47 links = st.links.copy();
47} 48}
48 49
49QIMPenStroke &QIMPenStroke::operator=( const QIMPenStroke &s ) 50QIMPenStroke &QIMPenStroke::operator=( const QIMPenStroke &s )
50{ 51{
51 clear(); 52 clear();
52 //qDebug( "copy strokes %d", s.links.count() ); 53 //odebug << "copy strokes " << s.links.count() << oendl;
53 startPoint = s.startPoint; 54 startPoint = s.startPoint;
54 lastPoint = s.lastPoint; 55 lastPoint = s.lastPoint;
55 links = s.links.copy(); 56 links = s.links.copy();
56 57
57 return *this; 58 return *this;
58} 59}
59 60
60void QIMPenStroke::clear() 61void QIMPenStroke::clear()
61{ 62{
62 startPoint = QPoint(0,0); 63 startPoint = QPoint(0,0);
63 lastPoint = QPoint( 0, 0 ); 64 lastPoint = QPoint( 0, 0 );
64 links.resize( 0 ); 65 links.resize( 0 );
65 tsig.resize( 0 ); 66 tsig.resize( 0 );
66 dsig.resize( 0 ); 67 dsig.resize( 0 );
67 asig.resize( 0 ); 68 asig.resize( 0 );
68} 69}
69 70
70/*! 71/*!
71 Begin inputting a new stroke. 72 Begin inputting a new stroke.
72*/ 73*/
73void QIMPenStroke::beginInput( QPoint p ) 74void QIMPenStroke::beginInput( QPoint p )
74{ 75{
75 clear(); 76 clear();
76 startPoint = p; 77 startPoint = p;
77 bounding = QRect(); 78 bounding = QRect();
78 internalAddPoint( p ); 79 internalAddPoint( p );
79} 80}
80 81
81/*! 82/*!
82 Add a point to the stroke's shape. 83 Add a point to the stroke's shape.
83 Returns TRUE if the point was successfully added. 84 Returns TRUE if the point was successfully added.
84*/ 85*/
85bool QIMPenStroke::addPoint( QPoint p ) 86bool QIMPenStroke::addPoint( QPoint p )
86{ 87{
87 if ( links.count() > 500 ) // sanity check (that the user is sane). 88 if ( links.count() > 500 ) // sanity check (that the user is sane).
88 return FALSE; 89 return FALSE;
89 90
90 int dx = p.x() - lastPoint.x(); 91 int dx = p.x() - lastPoint.x();
91 int dy = p.y() - lastPoint.y(); 92 int dy = p.y() - lastPoint.y();
92 if ( QABS( dx ) > 1 || QABS( dy ) > 1 ) { 93 if ( QABS( dx ) > 1 || QABS( dy ) > 1 ) {
93 // The point is not adjacent to the previous point, so we fill 94 // The point is not adjacent to the previous point, so we fill
94 // in with a straight line. Some kind of non-linear 95 // in with a straight line. Some kind of non-linear
95 // interpolation might be better. 96 // interpolation might be better.
96 int x = lastPoint.x(); 97 int x = lastPoint.x();
97 int y = lastPoint.y(); 98 int y = lastPoint.y();
98 int ix = 1; 99 int ix = 1;
99 int iy = 1; 100 int iy = 1;
100 if ( dx < 0 ) { 101 if ( dx < 0 ) {
101 ix = -1; 102 ix = -1;
102 dx = -dx; 103 dx = -dx;
103 } 104 }
104 if ( dy < 0 ) { 105 if ( dy < 0 ) {
105 iy = -1; 106 iy = -1;
106 dy = -dy; 107 dy = -dy;
107 } 108 }
108 int d = 0; 109 int d = 0;
109 if ( dx < dy ) { 110 if ( dx < dy ) {
110 d = dx; 111 d = dx;
111 do { 112 do {
112 y += iy; 113 y += iy;
113 d += dx; 114 d += dx;
114 if ( d > dy ) { 115 if ( d > dy ) {
115 x += ix; 116 x += ix;
116 d -= dy; 117 d -= dy;
117 } 118 }
118 internalAddPoint( QPoint( x, y ) ); 119 internalAddPoint( QPoint( x, y ) );
119 } while ( y != p.y() ); 120 } while ( y != p.y() );
120 } else { 121 } else {
121 d = dy; 122 d = dy;
122 do { 123 do {
123 x += ix; 124 x += ix;
124 d += dy; 125 d += dy;
125 if ( d > dx ) { 126 if ( d > dx ) {
126 y += iy; 127 y += iy;
127 d -= dx; 128 d -= dx;
128 } 129 }
129 internalAddPoint( QPoint( x, y ) ); 130 internalAddPoint( QPoint( x, y ) );
130 } while ( x != p.x() ); 131 } while ( x != p.x() );
131 } 132 }
132 } else { 133 } else {
133 internalAddPoint( p ); 134 internalAddPoint( p );
134 } 135 }
135 136
136 return TRUE; 137 return TRUE;
137} 138}
138 139
139/*! 140/*!
140 Finish inputting a stroke. 141 Finish inputting a stroke.
141*/ 142*/
142void QIMPenStroke::endInput() 143void QIMPenStroke::endInput()
143{ 144{
144 if ( links.count() < 3 ) { 145 if ( links.count() < 3 ) {
145 QIMPenGlyphLink gl; 146 QIMPenGlyphLink gl;
146 links.resize(1); 147 links.resize(1);
147 gl.dx = 1; 148 gl.dx = 1;
148 gl.dy = 0; 149 gl.dy = 0;
149 links[0] = gl; 150 links[0] = gl;
150 } 151 }
151 152
152 //qDebug("Points: %d", links.count() ); 153 //odebug << "Points: " << links.count() << oendl;
153} 154}
154 155
155/*! 156/*!
156 Return an indicator of the closeness of this stroke to \a pen. 157 Return an indicator of the closeness of this stroke to \a pen.
157 Lower value is better. 158 Lower value is better.
158*/ 159*/
159unsigned int QIMPenStroke::match( QIMPenStroke *pen ) 160unsigned int QIMPenStroke::match( QIMPenStroke *pen )
160{ 161{
161 double lratio; 162 double lratio;
162 163
163 if ( links.count() > pen->links.count() ) 164 if ( links.count() > pen->links.count() )
164 lratio = (links.count()+2) / (pen->links.count()+2); 165 lratio = (links.count()+2) / (pen->links.count()+2);
165 else 166 else
166 lratio = (pen->links.count()+2) / (links.count()+2); 167 lratio = (pen->links.count()+2) / (links.count()+2);
167 168
168 lratio -= 1.0; 169 lratio -= 1.0;
169 170
170 if ( lratio > 2.0 ) { 171 if ( lratio > 2.0 ) {
171#ifdef DEBUG_QIMPEN 172#ifdef DEBUG_QIMPEN
172 qDebug( "stroke length too different" ); 173 odebug << "stroke length too different" << oendl;
173#endif 174#endif
174 return 400000; 175 return 400000;
175 } 176 }
176 177
177 createSignatures(); 178 createSignatures();
178 pen->createSignatures(); 179 pen->createSignatures();
179 180
180 // Starting point offset 181 // Starting point offset
181 int vdiff = QABS(startPoint.y() - pen->startPoint.y()); 182 int vdiff = QABS(startPoint.y() - pen->startPoint.y());
182 183
183 // Insanely offset? 184 // Insanely offset?
184 if ( vdiff > 18 ) { 185 if ( vdiff > 18 ) {
185 return 400000; 186 return 400000;
186 } 187 }
187 188
188 vdiff -= 4; 189 vdiff -= 4;
189 if ( vdiff < 0 ) 190 if ( vdiff < 0 )
190 vdiff = 0; 191 vdiff = 0;
191 192
192 // Ending point offset 193 // Ending point offset
193 int evdiff = QABS(lastPoint.y() - pen->lastPoint.y()); 194 int evdiff = QABS(lastPoint.y() - pen->lastPoint.y());
194 // Insanely offset? 195 // Insanely offset?
195 if ( evdiff > 20 ) { 196 if ( evdiff > 20 ) {
196 return 400000; 197 return 400000;
197 } 198 }
198 199
199 evdiff -= 5; 200 evdiff -= 5;
200 if ( evdiff < 0 ) 201 if ( evdiff < 0 )
201 evdiff = 0; 202 evdiff = 0;
202 203
203 // do a correlation with the three available signatures. 204 // do a correlation with the three available signatures.
204 int err1 = INT_MAX; 205 int err1 = INT_MAX;
205 int err2 = INT_MAX; 206 int err2 = INT_MAX;
206 int err3 = INT_MAX; 207 int err3 = INT_MAX;
207 208
208 // base has extra points at the start and end to enable 209 // base has extra points at the start and end to enable
209 // correlation of a sliding window with the pen supplied. 210 // correlation of a sliding window with the pen supplied.
210 QArray<int> base = createBase( tsig, 2 ); 211 QArray<int> base = createBase( tsig, 2 );
211 for ( int i = 0; i < 4; i++ ) { 212 for ( int i = 0; i < 4; i++ ) {
212 int e = calcError( base, pen->tsig, i, TRUE ); 213 int e = calcError( base, pen->tsig, i, TRUE );
213 if ( e < err1 ) 214 if ( e < err1 )
214 err1 = e; 215 err1 = e;
215 } 216 }
216 if ( err1 > 40 ) { // no need for more matching 217 if ( err1 > 40 ) { // no need for more matching
217#ifdef DEBUG_QIMPEN 218#ifdef DEBUG_QIMPEN
218 qDebug( "tsig too great: %d", err1 ); 219 odebug << "tsig too great: " << err1 << oendl;
219#endif 220#endif
220 return 400000; 221 return 400000;
221 } 222 }
222 223
223 // maybe a sliding window is worthwhile for these too. 224 // maybe a sliding window is worthwhile for these too.
224 err2 = calcError( dsig, pen->dsig, 0, FALSE ); 225 err2 = calcError( dsig, pen->dsig, 0, FALSE );
225 if ( err2 > 100 ) { 226 if ( err2 > 100 ) {
226#ifdef DEBUG_QIMPEN 227#ifdef DEBUG_QIMPEN
227 qDebug( "dsig too great: %d", err2 ); 228 odebug << "dsig too great: " << err2 << oendl;
228#endif 229#endif
229 return 400000; 230 return 400000;
230 } 231 }
231 232
232 err3 = calcError( asig, pen->asig, 0, TRUE ); 233 err3 = calcError( asig, pen->asig, 0, TRUE );
233 if ( err3 > 60 ) { 234 if ( err3 > 60 ) {
234#ifdef DEBUG_QIMPEN 235#ifdef DEBUG_QIMPEN
235 qDebug( "asig too great: %d", err3 ); 236 odebug << "asig too great: " << err3 << oendl;
236#endif 237#endif
237 return 400000; 238 return 400000;
238 } 239 }
239 240
240 // Some magic numbers here - the addition reduces the weighting of 241 // Some magic numbers here - the addition reduces the weighting of
241 // the error and compensates for the different error scales. I 242 // the error and compensates for the different error scales. I
242 // consider the tangent signature to be the best indicator, so it 243 // consider the tangent signature to be the best indicator, so it
243 // has the most weight. This ain't rocket science. 244 // has the most weight. This ain't rocket science.
244 // Basically, these numbers are the tuning factors. 245 // Basically, these numbers are the tuning factors.
245 unsigned int err = (err1+1) * ( err2 + 60 ) * ( err3 + 20 ) + 246 unsigned int err = (err1+1) * ( err2 + 60 ) * ( err3 + 20 ) +
246 vdiff * 1000 + evdiff * 500 + 247 vdiff * 1000 + evdiff * 500 +
247 (unsigned int)(lratio * 5000.0); 248 (unsigned int)(lratio * 5000.0);
248 249
249#ifdef DEBUG_QIMPEN 250#ifdef DEBUG_QIMPEN
250 qDebug( "err %d ( %d, %d, %d, %d)", err, err1, err2, err3, vdiff ); 251 odebug << "err " << err << "( " << err1 << ", " << err2 << ", " << err3 << ", " << vdiff << oendl;
251#endif 252#endif
252 253
253 return err; 254 return err;
254} 255}
255 256
256/*! 257/*!
257 Return the bounding rect of this stroke. 258 Return the bounding rect of this stroke.
258*/ 259*/
259QRect QIMPenStroke::boundingRect() 260QRect QIMPenStroke::boundingRect()
260{ 261{
261 if ( !bounding.isValid() ) { 262 if ( !bounding.isValid() ) {
262 int x = startPoint.x(); 263 int x = startPoint.x();
263 int y = startPoint.y(); 264 int y = startPoint.y();
264 bounding = QRect( x, y, 1, 1 ); 265 bounding = QRect( x, y, 1, 1 );
265 266
266 for ( unsigned i = 0; i < links.count(); i++ ) { 267 for ( unsigned i = 0; i < links.count(); i++ ) {
267 x += links[i].dx; 268 x += links[i].dx;
268 y += links[i].dy; 269 y += links[i].dy;
269 if ( x < bounding.left() ) 270 if ( x < bounding.left() )
270 bounding.setLeft( x ); 271 bounding.setLeft( x );
271 if ( x > bounding.right() ) 272 if ( x > bounding.right() )
272 bounding.setRight( x ); 273 bounding.setRight( x );
273 if ( y < bounding.top() ) 274 if ( y < bounding.top() )
274 bounding.setTop( y ); 275 bounding.setTop( y );
275 if ( y > bounding.bottom() ) 276 if ( y > bounding.bottom() )
276 bounding.setBottom( y ); 277 bounding.setBottom( y );
277 } 278 }
278 } 279 }
279 280
280 return bounding; 281 return bounding;
281} 282}
282 283
283 284
284/*! 285/*!
285 Perform a correlation of the supplied arrays. \a base should have 286 Perform a correlation of the supplied arrays. \a base should have
286 win.count() + 2 * off points to enable sliding \a win over the 287 win.count() + 2 * off points to enable sliding \a win over the
287 \a base data. If \a t is TRUE, the comparison takes into account 288 \a base data. If \a t is TRUE, the comparison takes into account
288 the circular nature of the angular data. 289 the circular nature of the angular data.
289 Returns the best (lowest error) match. 290 Returns the best (lowest error) match.
290*/ 291*/
291 292
292int QIMPenStroke::calcError( const QArray<int> &base, 293int QIMPenStroke::calcError( const QArray<int> &base,
293 const QArray<int> &win, int off, bool t ) 294 const QArray<int> &win, int off, bool t )
294{ 295{
295 int err = 0; 296 int err = 0;
296 297
297 for ( unsigned i = 0; i < win.count(); i++ ) { 298 for ( unsigned i = 0; i < win.count(); i++ ) {
298 int d = QABS( base[i+off] - win[i] ); 299 int d = QABS( base[i+off] - win[i] );
299 if ( t && d > 128 ) 300 if ( t && d > 128 )
300 d -= 256; 301 d -= 256;
301 err += QABS( d ); 302 err += QABS( d );
302 } 303 }
303 304
304 err /= win.count(); 305 err /= win.count();
305 306
306 return err; 307 return err;
307} 308}
308 309
309/*! 310/*!
310 Creates signatures used in matching if not already created. 311 Creates signatures used in matching if not already created.
311*/ 312*/
312void QIMPenStroke::createSignatures() 313void QIMPenStroke::createSignatures()
313{ 314{
314 if ( tsig.isEmpty() ) 315 if ( tsig.isEmpty() )
diff --git a/inputmethods/handwriting/qimpenwordpick.cpp b/inputmethods/handwriting/qimpenwordpick.cpp
index 8ee103d..39745c6 100644
--- a/inputmethods/handwriting/qimpenwordpick.cpp
+++ b/inputmethods/handwriting/qimpenwordpick.cpp
@@ -43,71 +43,71 @@ void QIMPenWordPick::setWords( const QIMPenMatch::MatchWordList &w )
43{ 43{
44 words.clear(); 44 words.clear();
45 QListIterator<QIMPenMatch::MatchWord> it( w ); 45 QListIterator<QIMPenMatch::MatchWord> it( w );
46 for ( ; it.current(); ++it ) { 46 for ( ; it.current(); ++it ) {
47 words.append( it.current()->word ); 47 words.append( it.current()->word );
48 } 48 }
49 repaint(); 49 repaint();
50} 50}
51 51
52int QIMPenWordPick::onWord( QPoint p ) 52int QIMPenWordPick::onWord( QPoint p )
53{ 53{
54 int x = 2; 54 int x = 2;
55 int idx = 0; 55 int idx = 0;
56 for ( QStringList::Iterator it = words.begin(); it != words.end(); ++it ) { 56 for ( QStringList::Iterator it = words.begin(); it != words.end(); ++it ) {
57 QString word = *it; 57 QString word = *it;
58 int w = fontMetrics().width( word ); 58 int w = fontMetrics().width( word );
59 if ( x + w > width() ) 59 if ( x + w > width() )
60 break; 60 break;
61 if ( p.x() > x-2 && p.x() < x + w + 2 ) 61 if ( p.x() > x-2 && p.x() < x + w + 2 )
62 return idx; 62 return idx;
63 x += w + 5; 63 x += w + 5;
64 if ( !idx ) 64 if ( !idx )
65 x += 3; 65 x += 3;
66 idx++; 66 idx++;
67 } 67 }
68 68
69 return -1; 69 return -1;
70} 70}
71 71
72void QIMPenWordPick::paintEvent( QPaintEvent * ) 72void QIMPenWordPick::paintEvent( QPaintEvent * )
73{ 73{
74 QPainter p(this); 74 QPainter p(this);
75 int x = 2; 75 int x = 2;
76 int h = p.fontMetrics().ascent() + 1; 76 int h = p.fontMetrics().ascent() + 1;
77 int idx = 0; 77 int idx = 0;
78 for ( QStringList::Iterator it = words.begin(); it != words.end(); ++it ) { 78 for ( QStringList::Iterator it = words.begin(); it != words.end(); ++it ) {
79 QString word = *it; 79 QString word = *it;
80 int w = p.fontMetrics().width( word ); 80 int w = p.fontMetrics().width( word );
81 if ( x + w > width() ) 81 if ( x + w > width() )
82 break; 82 break;
83 if ( idx == clickWord ) { 83 if ( idx == clickWord ) {
84 p.fillRect( x, 0, w, height(), black ); 84 p.fillRect( x, 0, w, height(), black );
85 p.setPen( white ); 85 p.setPen( white );
86 } else { 86 } else {
87 p.setPen( colorGroup().text() ); 87 p.setPen( colorGroup().text() );
88 } 88 }
89 p.drawText( x, h, word ); 89 p.drawText( x, h, word );
90 x += w + 5; 90 x += w + 5;
91 if ( !idx ) 91 if ( !idx )
92 x += 3; 92 x += 3;
93 idx++; 93 idx++;
94 } 94 }
95} 95}
96 96
97void QIMPenWordPick::mousePressEvent( QMouseEvent *e ) 97void QIMPenWordPick::mousePressEvent( QMouseEvent *e )
98{ 98{
99 clickWord = onWord( e->pos() ); 99 clickWord = onWord( e->pos() );
100 repaint(); 100 repaint();
101} 101}
102 102
103void QIMPenWordPick::mouseReleaseEvent( QMouseEvent *e ) 103void QIMPenWordPick::mouseReleaseEvent( QMouseEvent *e )
104{ 104{
105 int wordIdx = onWord( e->pos() ); 105 int wordIdx = onWord( e->pos() );
106 if ( wordIdx >= 0 && wordIdx == clickWord ) { 106 if ( wordIdx >= 0 && wordIdx == clickWord ) {
107 //qDebug( "Clicked %s", words[wordIdx].latin1() ); 107 //odebug << "Clicked " << words[wordIdx].latin1() << oendl;
108 emit wordClicked( words[wordIdx] ); 108 emit wordClicked( words[wordIdx] );
109 } 109 }
110 clickWord = -1; 110 clickWord = -1;
111 repaint(); 111 repaint();
112} 112}
113 113