Diffstat (limited to 'inputmethods/handwriting/qimpenchar.cpp') (more/less context) (ignore whitespace changes)
-rw-r--r-- | inputmethods/handwriting/qimpenchar.cpp | 9 |
1 files changed, 5 insertions, 4 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,76 +1,77 @@ | |||
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 | ||
32 | const QIMPenSpecialKeys qimpen_specialKeys[] = { | 33 | const 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 | ||
53 | QIMPenChar::QIMPenChar() | 54 | QIMPenChar::QIMPenChar() |
54 | { | 55 | { |
55 | flags = 0; | 56 | flags = 0; |
56 | strokes.setAutoDelete( TRUE ); | 57 | strokes.setAutoDelete( TRUE ); |
57 | } | 58 | } |
58 | 59 | ||
59 | QIMPenChar::QIMPenChar( const QIMPenChar &chr ) | 60 | QIMPenChar::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 | ||
72 | QIMPenChar &QIMPenChar::operator=( const QIMPenChar &chr ) | 73 | QIMPenChar &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; |
@@ -122,112 +123,112 @@ unsigned int QIMPenChar::strokeLength( int s ) const | |||
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 | */ |
131 | void QIMPenChar::addStroke( QIMPenStroke *st ) | 132 | void 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 | */ |
141 | int QIMPenChar::match( QIMPenChar *pen ) | 142 | int 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 | */ |
195 | QRect QIMPenChar::boundingRect() | 196 | QRect 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 | */ |
211 | QDataStream &operator<< (QDataStream &s, const QIMPenChar &ws) | 212 | QDataStream &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 | */ |
230 | QDataStream &operator>> (QDataStream &s, QIMPenChar &ws) | 231 | QDataStream &operator>> (QDataStream &s, QIMPenChar &ws) |
231 | { | 232 | { |
232 | s >> ws.ch; | 233 | s >> ws.ch; |
233 | s >> ws.flags; | 234 | s >> ws.flags; |
@@ -413,98 +414,98 @@ void QIMPenCharSet::markDeleted( uint ch ) | |||
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 | */ |
423 | QIMPenCharMatchList QIMPenCharSet::match( QIMPenChar *ch ) | 424 | QIMPenCharMatchList 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 | */ |
472 | void QIMPenCharSet::addChar( QIMPenChar *ch ) | 473 | void 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 | */ |
483 | void QIMPenCharSet::removeChar( QIMPenChar *ch ) | 484 | void 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 | */ |
491 | void QIMPenCharSet::up( QIMPenChar *ch ) | 492 | void 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 | */ |
503 | void QIMPenCharSet::down( QIMPenChar *ch ) | 504 | void 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 | } |