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,511 +1,512 @@
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;
93 for ( int i = 0; qimpen_specialKeys[i].code != Qt::Key_unknown; i++ ) { 94 for ( int i = 0; qimpen_specialKeys[i].code != Qt::Key_unknown; i++ ) {
94 if ( qimpen_specialKeys[i].code == code ) { 95 if ( qimpen_specialKeys[i].code == code ) {
95 n = qimpen_specialKeys[i].name; 96 n = qimpen_specialKeys[i].name;
96 break; 97 break;
97 } 98 }
98 } 99 }
99 } else { 100 } else {
100 n = QChar( ch & 0x0000FFFF ); 101 n = QChar( ch & 0x0000FFFF );
101 } 102 }
102 103
103 return n; 104 return n;
104} 105}
105 106
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 )
250{ 251{
251 return error > m.error; 252 return error > m.error;
252} 253}
253 254
254bool QIMPenCharMatch::operator<( const QIMPenCharMatch &m ) 255bool QIMPenCharMatch::operator<( const QIMPenCharMatch &m )
255{ 256{
256 return error < m.error; 257 return error < m.error;
257} 258}
258 259
259bool QIMPenCharMatch::operator<=( const QIMPenCharMatch &m ) 260bool QIMPenCharMatch::operator<=( const QIMPenCharMatch &m )
260{ 261{
261 return error <= m.error; 262 return error <= m.error;
262} 263}
263 264
264//=========================================================================== 265//===========================================================================
265 266
266/*! 267/*!
267 \class QIMPenCharSet qimpenchar.h 268 \class QIMPenCharSet qimpenchar.h
268 269
269 Maintains a set of related characters. 270 Maintains a set of related characters.
270 */ 271 */
271 272
272QIMPenCharSet::QIMPenCharSet() 273QIMPenCharSet::QIMPenCharSet()
273{ 274{
274 chars.setAutoDelete( TRUE ); 275 chars.setAutoDelete( TRUE );
275 desc = "Unnamed"; 276 desc = "Unnamed";
276 csTitle = "abc"; 277 csTitle = "abc";
277 csType = Unknown; 278 csType = Unknown;
278 maxStrokes = 0; 279 maxStrokes = 0;
279} 280}
280 281
281/*! 282/*!
282 Construct and load a characters set from file \a fn. 283 Construct and load a characters set from file \a fn.
283 */ 284 */
284QIMPenCharSet::QIMPenCharSet( const QString &fn ) 285QIMPenCharSet::QIMPenCharSet( const QString &fn )
285{ 286{
286 chars.setAutoDelete( TRUE ); 287 chars.setAutoDelete( TRUE );
287 desc = "Unnamed"; 288 desc = "Unnamed";
288 csTitle = "abc"; 289 csTitle = "abc";
289 csType = Unknown; 290 csType = Unknown;
290 maxStrokes = 0; 291 maxStrokes = 0;
291 load( fn, System ); 292 load( fn, System );
292} 293}
293 294
294const QString &QIMPenCharSet::filename( Domain d ) const 295const QString &QIMPenCharSet::filename( Domain d ) const
295{ 296{
296 if ( d == System ) 297 if ( d == System )
297 return sysFilename; 298 return sysFilename;
298 else 299 else
299 return userFilename; 300 return userFilename;
300} 301}
301 302
302void QIMPenCharSet::setFilename( const QString &fn, Domain d ) 303void QIMPenCharSet::setFilename( const QString &fn, Domain d )
303{ 304{
304 if ( d == System ) 305 if ( d == System )
305 sysFilename = fn; 306 sysFilename = fn;
306 else if ( d == User ) 307 else if ( d == User )
307 userFilename = fn; 308 userFilename = fn;
308} 309}
309 310
310/*! 311/*!
311 Load a character set from file \a fn. 312 Load a character set from file \a fn.
312 */ 313 */
313bool QIMPenCharSet::load( const QString &fn, Domain d ) 314bool QIMPenCharSet::load( const QString &fn, Domain d )
314{ 315{
315 setFilename( fn, d ); 316 setFilename( fn, d );
316 317
317 bool ok = FALSE; 318 bool ok = FALSE;
318 QFile file( fn ); 319 QFile file( fn );
319 if ( file.open( IO_ReadOnly ) ) { 320 if ( file.open( IO_ReadOnly ) ) {
320 QDataStream ds( &file ); 321 QDataStream ds( &file );
321 QString version; 322 QString version;
322 ds >> version; 323 ds >> version;
323 ds >> csTitle; 324 ds >> csTitle;
324 ds >> desc; 325 ds >> desc;
325 int major = version.mid( 4, 1 ).toInt(); 326 int major = version.mid( 4, 1 ).toInt();
326 int minor = version.mid( 6 ).toInt(); 327 int minor = version.mid( 6 ).toInt();
327 if ( major >= 1 && minor > 0 ) { 328 if ( major >= 1 && minor > 0 ) {
328 ds >> (Q_INT8 &)csType; 329 ds >> (Q_INT8 &)csType;
329 } else { 330 } else {
330 if ( csTitle == "abc" ) 331 if ( csTitle == "abc" )
331 csType = Lower; 332 csType = Lower;
332 else if ( csTitle == "ABC" ) 333 else if ( csTitle == "ABC" )
333 csType = Upper; 334 csType = Upper;
334 else if ( csTitle == "123" ) 335 else if ( csTitle == "123" )
335 csType = Numeric; 336 csType = Numeric;
336 else if ( fn == "Combining" ) 337 else if ( fn == "Combining" )
337 csType = Combining; 338 csType = Combining;
338 } 339 }
339 while ( !ds.atEnd() ) { 340 while ( !ds.atEnd() ) {
340 QIMPenChar *pc = new QIMPenChar; 341 QIMPenChar *pc = new QIMPenChar;
341 ds >> *pc; 342 ds >> *pc;
342 if ( d == User ) 343 if ( d == User )
343 markDeleted( pc->character() ); // override system 344 markDeleted( pc->character() ); // override system
344 addChar( pc ); 345 addChar( pc );
345 } 346 }
346 if ( file.status() == IO_Ok ) 347 if ( file.status() == IO_Ok )
347 ok = TRUE; 348 ok = TRUE;
348 } 349 }
349 setHidden ( false ); 350 setHidden ( false );
350 return ok; 351 return ok;
351} 352}
352 353
353/*! 354/*!
354 Save this character set. 355 Save this character set.
355 */ 356 */
356bool QIMPenCharSet::save( Domain d ) 357bool QIMPenCharSet::save( Domain d )
357{ 358{
358 if ( filename( d ).isEmpty() ) 359 if ( filename( d ).isEmpty() )
359 return FALSE; 360 return FALSE;
360 361
361 if ( hidden() ) 362 if ( hidden() )
362 return TRUE; 363 return TRUE;
363 364
364 bool ok = FALSE; 365 bool ok = FALSE;
365 366
366 QString fn = filename( d ); 367 QString fn = filename( d );
367 QString tmpFn = fn + ".new"; 368 QString tmpFn = fn + ".new";
368 QFile file( tmpFn ); 369 QFile file( tmpFn );
369 if ( file.open( IO_WriteOnly|IO_Raw ) ) { 370 if ( file.open( IO_WriteOnly|IO_Raw ) ) {
370 QByteArray buf; 371 QByteArray buf;
371 QDataStream ds( buf, IO_WriteOnly ); 372 QDataStream ds( buf, IO_WriteOnly );
372 ds << QString( "QPT 1.1" ); 373 ds << QString( "QPT 1.1" );
373 ds << csTitle; 374 ds << csTitle;
374 ds << desc; 375 ds << desc;
375 ds << (Q_INT8)csType; 376 ds << (Q_INT8)csType;
376 QIMPenCharIterator ci( chars ); 377 QIMPenCharIterator ci( chars );
377 for ( ; ci.current(); ++ci ) { 378 for ( ; ci.current(); ++ci ) {
378 QIMPenChar *pc = ci.current(); 379 QIMPenChar *pc = ci.current();
379 if ( ( ( (d == System) && pc->testFlag( QIMPenChar::System ) ) || 380 if ( ( ( (d == System) && pc->testFlag( QIMPenChar::System ) ) ||
380 ( (d == User) && !pc->testFlag( QIMPenChar::System ) ) ) && 381 ( (d == User) && !pc->testFlag( QIMPenChar::System ) ) ) &&
381 ( !pc->testFlag (QIMPenChar::Combined ) ) ) { 382 ( !pc->testFlag (QIMPenChar::Combined ) ) ) {
382 ds << *pc; 383 ds << *pc;
383 } 384 }
384 } 385 }
385 386
386 file.writeBlock( buf ); 387 file.writeBlock( buf );
387 file.close(); 388 file.close();
388 if ( file.status() == IO_Ok ) 389 if ( file.status() == IO_Ok )
389 ok = TRUE; 390 ok = TRUE;
390 } 391 }
391 392
392 if ( ok ) { 393 if ( ok ) {
393 if ( ::rename( tmpFn.latin1(), fn.latin1() ) < 0 ) { 394 if ( ::rename( tmpFn.latin1(), fn.latin1() ) < 0 ) {
394 qWarning( "problem renaming file %s to %s, errno: %d", 395 qWarning( "problem renaming file %s to %s, errno: %d",
395 tmpFn.latin1(), fn.latin1(), errno ); 396 tmpFn.latin1(), fn.latin1(), errno );
396 // remove the tmp file, otherwise, it will just lay around... 397 // remove the tmp file, otherwise, it will just lay around...
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,515 +1,517 @@
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" +@#+++++. ",
103" ++ ", 104" ++ ",
104" . ", 105" . ",
105" ", 106" ",
106" "}; 107" "};
107 108
108 109
109 110
110/* XPM */ 111/* XPM */
111static char * help_xpm[] = { 112static char * help_xpm[] = {
112"12 12 5 1", 113"12 12 5 1",
113 " c None", 114 " c None",
114 ".c #000000", 115 ".c #000000",
115 "+c #FFFFFF", 116 "+c #FFFFFF",
116 "@c #666666", 117 "@c #666666",
117 "#c #333333", 118 "#c #333333",
118" ", 119" ",
119" ... ", 120" ... ",
120" .+++. ", 121" .+++. ",
121" .+..@+. ", 122" .+..@+. ",
122" #.# .+. ", 123" #.# .+. ",
123" .+. ", 124" .+. ",
124" .+. ", 125" .+. ",
125" .+. ", 126" .+. ",
126" .+. ", 127" .+. ",
127" #.# ", 128" #.# ",
128" .+. ", 129" .+. ",
129" #.# "}; 130" #.# "};
130 131
131 132
132/*! 133/*!
133 \class QIMPenInput qimpeninput.h 134 \class QIMPenInput qimpeninput.h
134 135
135 Pen input widget. 136 Pen input widget.
136*/ 137*/
137QIMPenInput::QIMPenInput( QWidget *parent, const char *name, WFlags wf ) 138QIMPenInput::QIMPenInput( QWidget *parent, const char *name, WFlags wf )
138 : QFrame( parent, name, wf ), helpDlg(0), profile(0) 139 : QFrame( parent, name, wf ), helpDlg(0), profile(0)
139{ 140{
140 setFrameStyle( Box | Plain ); 141 setFrameStyle( Box | Plain );
141 142
142 profileList.setAutoDelete( true ); 143 profileList.setAutoDelete( true );
143 144
144 matcher = new QIMPenMatch( this ); 145 matcher = new QIMPenMatch( this );
145 connect( matcher, SIGNAL(keypress(uint)), this, SLOT(keypress(uint)) ); 146 connect( matcher, SIGNAL(keypress(uint)), this, SLOT(keypress(uint)) );
146 connect( matcher, SIGNAL(erase()), this, SLOT(erase()) ); 147 connect( matcher, SIGNAL(erase()), this, SLOT(erase()) );
147 148
148 QGridLayout *gl = new QGridLayout( this, 5, 2, 1, 0 ); 149 QGridLayout *gl = new QGridLayout( this, 5, 2, 1, 0 );
149 gl->setColStretch( 0, 1 ); 150 gl->setColStretch( 0, 1 );
150 151
151 wordPicker = new QIMPenWordPick( this ); 152 wordPicker = new QIMPenWordPick( this );
152 connect( wordPicker, SIGNAL(wordClicked(const QString&)), 153 connect( wordPicker, SIGNAL(wordClicked(const QString&)),
153 this, SLOT(wordPicked(const QString&)) ); 154 this, SLOT(wordPicked(const QString&)) );
154 connect( matcher, SIGNAL(matchedCharacters(const QIMPenCharMatchList&)), 155 connect( matcher, SIGNAL(matchedCharacters(const QIMPenCharMatchList&)),
155 this, SLOT(matchedCharacters(const QIMPenCharMatchList&)) ); 156 this, SLOT(matchedCharacters(const QIMPenCharMatchList&)) );
156 connect( matcher, SIGNAL(matchedWords(const QIMPenMatch::MatchWordList&)), 157 connect( matcher, SIGNAL(matchedWords(const QIMPenMatch::MatchWordList&)),
157 wordPicker, SLOT(setWords(const QIMPenMatch::MatchWordList&)) ); 158 wordPicker, SLOT(setWords(const QIMPenMatch::MatchWordList&)) );
158 QFont f("smallsmooth",9); 159 QFont f("smallsmooth",9);
159 QFontInfo fi( f ); 160 QFontInfo fi( f );
160 wordPicker->setFont( f ); 161 wordPicker->setFont( f );
161 wordPicker->setBackgroundColor( white ); 162 wordPicker->setBackgroundColor( white );
162 gl->addMultiCellWidget( wordPicker, 0, 0, 0, 1 ); 163 gl->addMultiCellWidget( wordPicker, 0, 0, 0, 1 );
163 if ( !Global::fixedDawg().root() || !matcher->isWordMatchingEnabled() ) 164 if ( !Global::fixedDawg().root() || !matcher->isWordMatchingEnabled() )
164 wordPicker->hide(); 165 wordPicker->hide();
165 166
166 pw = new QIMPenWidget( this ); 167 pw = new QIMPenWidget( this );
167 gl->addMultiCellWidget( pw, 1, 4, 0, 0 ); 168 gl->addMultiCellWidget( pw, 1, 4, 0, 0 );
168 169
169 int bh = pw->sizeHint().height()/4; 170 int bh = pw->sizeHint().height()/4;
170 171
171 QPushButton *b = new QPushButton( this ); 172 QPushButton *b = new QPushButton( this );
172 b->setFocusPolicy( NoFocus ); 173 b->setFocusPolicy( NoFocus );
173 b->setPixmap( QPixmap( (const char **)bs_xpm ) ); 174 b->setPixmap( QPixmap( (const char **)bs_xpm ) );
174 b->setFixedHeight(pw->sizeHint().height()-3*bh); // left-over space goes here 175 b->setFixedHeight(pw->sizeHint().height()-3*bh); // left-over space goes here
175 b->setAutoRepeat( TRUE ); 176 b->setAutoRepeat( TRUE );
176 gl->addWidget( b, 1, 1 ); 177 gl->addWidget( b, 1, 1 );
177 connect( b, SIGNAL(clicked()), SLOT(backspace())); 178 connect( b, SIGNAL(clicked()), SLOT(backspace()));
178 179
179 b = new QPushButton( this ); 180 b = new QPushButton( this );
180 b->setFocusPolicy( NoFocus ); 181 b->setFocusPolicy( NoFocus );
181 b->setPixmap( QPixmap( (const char **)enter_xpm ) ); 182 b->setPixmap( QPixmap( (const char **)enter_xpm ) );
182 b->setFixedHeight(bh); 183 b->setFixedHeight(bh);
183 b->setAutoRepeat( TRUE ); 184 b->setAutoRepeat( TRUE );
184 gl->addWidget( b, 2, 1 ); 185 gl->addWidget( b, 2, 1 );
185 connect( b, SIGNAL(clicked()), SLOT(enter())); 186 connect( b, SIGNAL(clicked()), SLOT(enter()));
186 187
187 helpBtn = new QPushButton( this ); 188 helpBtn = new QPushButton( this );
188 helpBtn->setFocusPolicy( NoFocus ); 189 helpBtn->setFocusPolicy( NoFocus );
189 helpBtn->setPixmap( QPixmap( (const char **)help_xpm ) ); 190 helpBtn->setPixmap( QPixmap( (const char **)help_xpm ) );
190 helpBtn->setFixedHeight(bh); 191 helpBtn->setFixedHeight(bh);
191 gl->addWidget( helpBtn, 3, 1 ); 192 gl->addWidget( helpBtn, 3, 1 );
192 connect( helpBtn, SIGNAL(clicked()), SLOT(help())); 193 connect( helpBtn, SIGNAL(clicked()), SLOT(help()));
193 194
194 QPixmap pm( (const char **)pen_xpm ); 195 QPixmap pm( (const char **)pen_xpm );
195 setupBtn = new QPushButton( this ); 196 setupBtn = new QPushButton( this );
196 setupBtn->setFocusPolicy( NoFocus ); 197 setupBtn->setFocusPolicy( NoFocus );
197 setupBtn->setPixmap( pm ); 198 setupBtn->setPixmap( pm );
198 setupBtn->setFixedHeight(bh); 199 setupBtn->setFixedHeight(bh);
199 gl->addWidget( setupBtn, 4, 1 ); 200 gl->addWidget( setupBtn, 4, 1 );
200 connect( setupBtn, SIGNAL(clicked()), SLOT(setup())); 201 connect( setupBtn, SIGNAL(clicked()), SLOT(setup()));
201 202
202 connect( matcher, SIGNAL(removeStroke()), pw, SLOT(removeStroke()) ); 203 connect( matcher, SIGNAL(removeStroke()), pw, SLOT(removeStroke()) );
203 connect( pw, SIGNAL(changeCharSet(QIMPenCharSet*)), 204 connect( pw, SIGNAL(changeCharSet(QIMPenCharSet*)),
204 matcher, SLOT(setCharSet(QIMPenCharSet*)) ); 205 matcher, SLOT(setCharSet(QIMPenCharSet*)) );
205 connect( pw, SIGNAL(changeCharSet(int)), 206 connect( pw, SIGNAL(changeCharSet(int)),
206 this, SLOT(selectCharSet(int)) ); 207 this, SLOT(selectCharSet(int)) );
207 connect( pw, SIGNAL(beginStroke()), 208 connect( pw, SIGNAL(beginStroke()),
208 matcher, SLOT(beginStroke()) ); 209 matcher, SLOT(beginStroke()) );
209 connect( pw, SIGNAL(stroke(QIMPenStroke*)), 210 connect( pw, SIGNAL(stroke(QIMPenStroke*)),
210 this, SLOT(strokeEntered(QIMPenStroke*)) ); 211 this, SLOT(strokeEntered(QIMPenStroke*)) );
211 connect( pw, SIGNAL(stroke(QIMPenStroke*)), 212 connect( pw, SIGNAL(stroke(QIMPenStroke*)),
212 matcher, SLOT(strokeEntered(QIMPenStroke*)) ); 213 matcher, SLOT(strokeEntered(QIMPenStroke*)) );
213 214
214 shortcutCharSet = 0; 215 shortcutCharSet = 0;
215 currCharSet = 0; 216 currCharSet = 0;
216 setupDlg = 0; 217 setupDlg = 0;
217 profile = 0; 218 profile = 0;
218 mode = Normal; 219 mode = Normal;
219 220
220 loadProfiles(); 221 loadProfiles();
221} 222}
222 223
223QIMPenInput::~QIMPenInput() 224QIMPenInput::~QIMPenInput()
224{ 225{
225 delete (HandwritingHelp*) helpDlg; 226 delete (HandwritingHelp*) helpDlg;
226} 227}
227 228
228QSize QIMPenInput::sizeHint() const 229QSize QIMPenInput::sizeHint() const
229{ 230{
230 int fw = frameWidth(); 231 int fw = frameWidth();
231 int ps = wordPicker->isHidden() ? 0 : wordPicker->sizeHint().height(); 232 int ps = wordPicker->isHidden() ? 0 : wordPicker->sizeHint().height();
232 return pw->sizeHint() + QSize( fw*2, fw*2+ps ); 233 return pw->sizeHint() + QSize( fw*2, fw*2+ps );
233} 234}
234 235
235void QIMPenInput::loadProfiles() 236void QIMPenInput::loadProfiles()
236{ 237{
237 profileList.clear(); 238 profileList.clear();
238 profile = 0; 239 profile = 0;
239 delete shortcutCharSet; 240 delete shortcutCharSet;
240 shortcutCharSet = new QIMPenCharSet(); 241 shortcutCharSet = new QIMPenCharSet();
241 shortcutCharSet->setTitle( tr("Shortcut") ); 242 shortcutCharSet->setTitle( tr("Shortcut") );
242 QString path = QPEApplication::qpeDir() + "etc/qimpen"; 243 QString path = QPEApplication::qpeDir() + "etc/qimpen";
243 QDir dir( path, "*.conf" ); 244 QDir dir( path, "*.conf" );
244 QStringList list = dir.entryList(); 245 QStringList list = dir.entryList();
245 QStringList::Iterator it; 246 QStringList::Iterator it;
246 for ( it = list.begin(); it != list.end(); ++it ) { 247 for ( it = list.begin(); it != list.end(); ++it ) {
247 QIMPenProfile *p = new QIMPenProfile( path + "/" + *it ); 248 QIMPenProfile *p = new QIMPenProfile( path + "/" + *it );
248 profileList.append( p ); 249 profileList.append( p );
249 if ( p->shortcut() ) { 250 if ( p->shortcut() ) {
250 QIMPenCharIterator it( p->shortcut()->characters() ); 251 QIMPenCharIterator it( p->shortcut()->characters() );
251 for ( ; it.current(); ++it ) { 252 for ( ; it.current(); ++it ) {
252 shortcutCharSet->addChar( new QIMPenChar(*it.current()) ); 253 shortcutCharSet->addChar( new QIMPenChar(*it.current()) );
253 } 254 }
254 } 255 }
255 } 256 }
256 257
257 Config config( "handwriting" ); 258 Config config( "handwriting" );
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,365 +1,366 @@
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();
353 multiCharSet = 0; 354 multiCharSet = 0;
354} 355}
355 356
356void QIMPenMatch::resetState() 357void QIMPenMatch::resetState()
357{ 358{
358 if ( !wordEntered.isEmpty() ) { 359 if ( !wordEntered.isEmpty() ) {
359 wordChars.clear(); 360 wordChars.clear();
360 wordMatches.clear(); 361 wordMatches.clear();
361 wordEntered = QString(); 362 wordEntered = QString();
362 emit matchedWords( wordMatches ); 363 emit matchedWords( wordMatches );
363 canErase = FALSE; 364 canErase = FALSE;
364 } 365 }
365} 366}
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,646 +1,647 @@
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() )
315 createTanSignature(); 316 createTanSignature();
316 if ( asig.isEmpty() ) 317 if ( asig.isEmpty() )
317 createAngleSignature(); 318 createAngleSignature();
318 if ( dsig.isEmpty() ) 319 if ( dsig.isEmpty() )
319 createDistSignature(); 320 createDistSignature();
320} 321}
321 322
322/*! 323/*!
323 Create a signature of the tangents to the user's stroke. 324 Create a signature of the tangents to the user's stroke.
324*/ 325*/
325void QIMPenStroke::createTanSignature() 326void QIMPenStroke::createTanSignature()
326{ 327{
327 int dist = 5; // number of points to include in calculation 328 int dist = 5; // number of points to include in calculation
328 if ( (int)links.count() <= dist ) { 329 if ( (int)links.count() <= dist ) {
329 tsig.resize(1); 330 tsig.resize(1);
330 int dx = 0; 331 int dx = 0;
331 int dy = 0; 332 int dy = 0;
332 for ( unsigned j = 0; j < links.count(); j++ ) { 333 for ( unsigned j = 0; j < links.count(); j++ ) {
333 dx += links[j].dx; 334 dx += links[j].dx;
334 dy += links[j].dy; 335 dy += links[j].dy;
335 } 336 }
336 tsig[0] = arcTan( dy, dx ); 337 tsig[0] = arcTan( dy, dx );
337 } else { 338 } else {
338 tsig.resize( (links.count()-dist+1) / 2 ); 339 tsig.resize( (links.count()-dist+1) / 2 );
339 int idx = 0; 340 int idx = 0;
340 for ( unsigned i = 0; i < links.count() - dist; i += 2 ) { 341 for ( unsigned i = 0; i < links.count() - dist; i += 2 ) {
341 int dx = 0; 342 int dx = 0;
342 int dy = 0; 343 int dy = 0;
343 for ( int j = 0; j < dist; j++ ) { 344 for ( int j = 0; j < dist; j++ ) {
344 dx += links[i+j].dx; 345 dx += links[i+j].dx;
345 dy += links[i+j].dy; 346 dy += links[i+j].dy;
346 } 347 }
347 tsig[idx++] = arcTan( dy, dx ); 348 tsig[idx++] = arcTan( dy, dx );
348 } 349 }
349 } 350 }
350 351
351 tsig = scale( tsig, QIMPEN_CORRELATION_POINTS, TRUE ); 352 tsig = scale( tsig, QIMPEN_CORRELATION_POINTS, TRUE );
352// smooth(tsig); 353// smooth(tsig);
353} 354}
354 355
355/*! 356/*!
356 Create a signature of the change in angle. 357 Create a signature of the change in angle.
357*/ 358*/
358void QIMPenStroke::createAngleSignature() 359void QIMPenStroke::createAngleSignature()
359{ 360{
360 QPoint c = calcCenter(); 361 QPoint c = calcCenter();
361 362
362 int dist = 3; // number of points to include in calculation 363 int dist = 3; // number of points to include in calculation
363 if ( (int)links.count() <= dist ) { 364 if ( (int)links.count() <= dist ) {
364 asig.resize(1); 365 asig.resize(1);
365 asig[0] = 1; 366 asig[0] = 1;
366 } else { 367 } else {
367 asig.resize( links.count() ); 368 asig.resize( links.count() );
368 QPoint current(0, 0); 369 QPoint current(0, 0);
369 int idx = 0; 370 int idx = 0;
370 for ( unsigned i = 0; i < links.count(); i++ ) { 371 for ( unsigned i = 0; i < links.count(); i++ ) {
371 int dx = c.x() - current.x(); 372 int dx = c.x() - current.x();
372 int dy = c.y() - current.y(); 373 int dy = c.y() - current.y();
373 int md = QMAX( QABS(dx), QABS(dy) ); 374 int md = QMAX( QABS(dx), QABS(dy) );
374 if ( md > 5 ) { 375 if ( md > 5 ) {
375 dx = dx * 5 / md; 376 dx = dx * 5 / md;
376 dy = dy * 5 / md; 377 dy = dy * 5 / md;
377 } 378 }
378 asig[idx++] = arcTan( dy, dx ); 379 asig[idx++] = arcTan( dy, dx );
379 current += QPoint( links[i].dx, links[i].dy ); 380 current += QPoint( links[i].dx, links[i].dy );
380 } 381 }
381 } 382 }
382 383
383 asig = scale( asig, QIMPEN_CORRELATION_POINTS, TRUE ); 384 asig = scale( asig, QIMPEN_CORRELATION_POINTS, TRUE );
384 385
385/* 386/*
386 if ( tsig.isEmpty() ) 387 if ( tsig.isEmpty() )
387 createTanSignature(); 388 createTanSignature();
388 389
389 if ( tsig.count() < 5 ) { 390 if ( tsig.count() < 5 ) {
390 asig.resize( 1 ); 391 asig.resize( 1 );
391 asig[0] = 0; 392 asig[0] = 0;
392 } else { 393 } else {
393 asig.resize( tsig.count() - 5 ); 394 asig.resize( tsig.count() - 5 );
394 395
395 for ( unsigned i = 0; i < asig.count(); i++ ) { 396 for ( unsigned i = 0; i < asig.count(); i++ ) {
396 asig[i] = QABS(tsig[i] - tsig[i+5]); 397 asig[i] = QABS(tsig[i] - tsig[i+5]);
397 } 398 }
398 } 399 }
399*/ 400*/
400} 401}
401 402
402/*! 403/*!
403 Create a signature of the distance from the char's center of gravity 404 Create a signature of the distance from the char's center of gravity
404 to its points. 405 to its points.
405*/ 406*/
406void QIMPenStroke::createDistSignature() 407void QIMPenStroke::createDistSignature()
407{ 408{
408 dsig.resize( (links.count()+1)/2 ); 409 dsig.resize( (links.count()+1)/2 );
409 QPoint c = calcCenter(); 410 QPoint c = calcCenter();
410 QPoint pt( 0, 0 ); 411 QPoint pt( 0, 0 );
411 412
412 int minval = INT_MAX; 413 int minval = INT_MAX;
413 int maxval = 0; 414 int maxval = 0;
414 int idx = 0; 415 int idx = 0;
415 for ( unsigned i = 0; i < links.count(); i += 2 ) { 416 for ( unsigned i = 0; i < links.count(); i += 2 ) {
416 int dx = c.x() - pt.x(); 417 int dx = c.x() - pt.x();
417 int dy = c.y() - pt.y(); 418 int dy = c.y() - pt.y();
418 if ( dx == 0 && dy == 0 ) 419 if ( dx == 0 && dy == 0 )
419 dsig[idx] = 0; 420 dsig[idx] = 0;
420 else 421 else
421 dsig[idx] = dx*dx + dy*dy; 422 dsig[idx] = dx*dx + dy*dy;
422 423
423 if ( dsig[idx] > maxval ) 424 if ( dsig[idx] > maxval )
424 maxval = dsig[idx]; 425 maxval = dsig[idx];
425 if ( dsig[idx] < minval ) 426 if ( dsig[idx] < minval )
426 minval = dsig[idx]; 427 minval = dsig[idx];
427 pt.rx() += links[i].dx; 428 pt.rx() += links[i].dx;
428 pt.ry() += links[i].dy; 429 pt.ry() += links[i].dy;
429 idx++; 430 idx++;
430 } 431 }
431 432
432 // normalise 0-255 433 // normalise 0-255
433 int div = maxval - minval; 434 int div = maxval - minval;
434 if ( div == 0 ) div = 1; 435 if ( div == 0 ) div = 1;
435 for ( unsigned i = 0; i < dsig.count(); i++ ) { 436 for ( unsigned i = 0; i < dsig.count(); i++ ) {
436 dsig[i] = (dsig[i] - minval ) * 255 / div; 437 dsig[i] = (dsig[i] - minval ) * 255 / div;
437 } 438 }
438 439
439 dsig = scale( dsig, QIMPEN_CORRELATION_POINTS ); 440 dsig = scale( dsig, QIMPEN_CORRELATION_POINTS );
440} 441}
441 442
442 443
443/*! 444/*!
444 Scale the points in a array to \a count points. 445 Scale the points in a array to \a count points.
445 This is braindead at the moment (no smooth scaling) and fixing this is 446 This is braindead at the moment (no smooth scaling) and fixing this is
446 probably one of the simpler ways to improve performance. 447 probably one of the simpler ways to improve performance.
447*/ 448*/
448QArray<int> QIMPenStroke::scale( const QArray<int> &s, unsigned count, bool t ) 449QArray<int> QIMPenStroke::scale( const QArray<int> &s, unsigned count, bool t )
449{ 450{
450 QArray<int> d(count); 451 QArray<int> d(count);
451 452
452 unsigned si = 0; 453 unsigned si = 0;
453 if ( s.count() > count ) { 454 if ( s.count() > count ) {
454 unsigned next = 0; 455 unsigned next = 0;
455 for ( unsigned i = 0; i < count; i++ ) { 456 for ( unsigned i = 0; i < count; i++ ) {
456 next = (i+1) * s.count() / count; 457 next = (i+1) * s.count() / count;
457 int maxval = 0; 458 int maxval = 0;
458 if ( t ) { 459 if ( t ) {
459 for ( unsigned j = si; j < next; j++ ) { 460 for ( unsigned j = si; j < next; j++ ) {
460 maxval = s[j] > maxval ? s[j] : maxval; 461 maxval = s[j] > maxval ? s[j] : maxval;
461 } 462 }
462 } 463 }
463 int sum = 0; 464 int sum = 0;
464 for ( unsigned j = si; j < next; j++ ) { 465 for ( unsigned j = si; j < next; j++ ) {
465 if ( t && maxval - s[j] > 128 ) 466 if ( t && maxval - s[j] > 128 )
466 sum += 256; 467 sum += 256;
467 sum += s[j]; 468 sum += s[j];
468 } 469 }
469 d[i] = sum / (next-si); 470 d[i] = sum / (next-si);
470 if ( t && d[i] > 256 ) 471 if ( t && d[i] > 256 )
471 d[i] %= 256; 472 d[i] %= 256;
472 si = next; 473 si = next;
473 } 474 }
474 } else { 475 } else {
475 for ( unsigned i = 0; i < count; i++ ) { 476 for ( unsigned i = 0; i < count; i++ ) {
476 si = i * s.count() / count; 477 si = i * s.count() / count;
477 d[i] = s[si]; 478 d[i] = s[si];
478 } 479 }
479 } 480 }
480 481
481 return d; 482 return d;
482} 483}
483 484
484/*! 485/*!
485 Add another point to the stroke's shape. 486 Add another point to the stroke's shape.
486*/ 487*/
487void QIMPenStroke::internalAddPoint( QPoint p ) 488void QIMPenStroke::internalAddPoint( QPoint p )
488{ 489{
489 if ( p == lastPoint ) 490 if ( p == lastPoint )
490 return; 491 return;
491 492
492 if ( !lastPoint.isNull() ) { 493 if ( !lastPoint.isNull() ) {
493 QIMPenGlyphLink gl; 494 QIMPenGlyphLink gl;
494 gl.dx = p.x() - lastPoint.x(); 495 gl.dx = p.x() - lastPoint.x();
495 gl.dy = p.y() - lastPoint.y(); 496 gl.dy = p.y() - lastPoint.y();
496 links.resize( links.size() + 1 ); //### resize by 1 is bad 497 links.resize( links.size() + 1 ); //### resize by 1 is bad
497 links[links.size() - 1] = gl; 498 links[links.size() - 1] = gl;
498 } 499 }
499 500
500 lastPoint = p; 501 lastPoint = p;
501 bounding = QRect(); 502 bounding = QRect();
502} 503}
503 504
504/*! 505/*!
505 Calculate the center of gravity of the stroke. 506 Calculate the center of gravity of the stroke.
506*/ 507*/
507QPoint QIMPenStroke::calcCenter() 508QPoint QIMPenStroke::calcCenter()
508{ 509{
509 QPoint pt( 0, 0 ); 510 QPoint pt( 0, 0 );
510 int ax = 0; 511 int ax = 0;
511 int ay = 0; 512 int ay = 0;
512 513
513 for ( unsigned i = 0; i < links.count(); i++ ) { 514 for ( unsigned i = 0; i < links.count(); i++ ) {
514 pt.rx() += links[i].dx; 515 pt.rx() += links[i].dx;
515 pt.ry() += links[i].dy; 516 pt.ry() += links[i].dy;
516 ax += pt.x(); 517 ax += pt.x();
517 ay += pt.y(); 518 ay += pt.y();
518 } 519 }
519 520
520 ax /= (int)links.count(); 521 ax /= (int)links.count();
521 ay /= (int)links.count(); 522 ay /= (int)links.count();
522 523
523 return QPoint( ax, ay ); 524 return QPoint( ax, ay );
524} 525}
525 526
526/*! 527/*!
527 Calculate the arctan of the lengths supplied. 528 Calculate the arctan of the lengths supplied.
528 The angle returned is in the range 0-255. 529 The angle returned is in the range 0-255.
529 \a dy and \a dx MUST be in the range 0-5 - I dont even check :-P 530 \a dy and \a dx MUST be in the range 0-5 - I dont even check :-P
530*/ 531*/
531int QIMPenStroke::arcTan( int dy, int dx ) 532int QIMPenStroke::arcTan( int dy, int dx )
532{ 533{
533 if ( dx == 0 ) { 534 if ( dx == 0 ) {
534 if ( dy >= 0 ) 535 if ( dy >= 0 )
535 return 64; 536 return 64;
536 else 537 else
537 return 192; 538 return 192;
538 } 539 }
539 540
540 if ( dy == 0 ) { 541 if ( dy == 0 ) {
541 if ( dx >= 0 ) 542 if ( dx >= 0 )
542 return 0; 543 return 0;
543 else 544 else
544 return 128; 545 return 128;
545 } 546 }
546 547
547 static int table[5][5] = { 548 static int table[5][5] = {
548 { 32, 19, 13, 10, 8 }, 549 { 32, 19, 13, 10, 8 },
549 { 45, 32, 24, 19, 16 }, 550 { 45, 32, 24, 19, 16 },
550 { 51, 40, 32, 26, 22 }, 551 { 51, 40, 32, 26, 22 },
551 { 54, 45, 37, 32, 27 }, 552 { 54, 45, 37, 32, 27 },
552 { 56, 49, 42, 37, 32 } }; 553 { 56, 49, 42, 37, 32 } };
553 554
554 if ( dy > 0 ) { 555 if ( dy > 0 ) {
555 if ( dx > 0 ) 556 if ( dx > 0 )
556 return table[dy-1][dx-1]; 557 return table[dy-1][dx-1];
557 else 558 else
558 return 128 - table[dy-1][QABS(dx)-1]; 559 return 128 - table[dy-1][QABS(dx)-1];
559 } else { 560 } else {
560 if ( dx > 0 ) 561 if ( dx > 0 )
561 return 256 - table[QABS(dy)-1][dx-1]; 562 return 256 - table[QABS(dy)-1][dx-1];
562 else 563 else
563 return 128 + table[QABS(dy)-1][QABS(dx)-1]; 564 return 128 + table[QABS(dy)-1][QABS(dx)-1];
564 } 565 }
565 566
566 return 0; 567 return 0;
567} 568}
568 569
569 570
570/*! 571/*!
571 Silly name. Create an array that has \a e points extra at the start and 572 Silly name. Create an array that has \a e points extra at the start and
572 end to enable a sliding correlation to be performed. 573 end to enable a sliding correlation to be performed.
573*/ 574*/
574QArray<int> QIMPenStroke::createBase( const QArray<int> a, int e ) 575QArray<int> QIMPenStroke::createBase( const QArray<int> a, int e )
575{ 576{
576 QArray<int> ra( a.count() + 2*e ); 577 QArray<int> ra( a.count() + 2*e );
577 578
578 for ( int i = 0; i < e; i++ ) { 579 for ( int i = 0; i < e; i++ ) {
579 ra[i] = a[e - i - 1]; 580 ra[i] = a[e - i - 1];
580 ra[a.count() + i] = a[a.count() - i - 1]; 581 ra[a.count() + i] = a[a.count() - i - 1];
581 } 582 }
582 for ( unsigned i = 0; i < a.count(); i++ ) { 583 for ( unsigned i = 0; i < a.count(); i++ ) {
583 ra[i+e] = a[i]; 584 ra[i+e] = a[i];
584 } 585 }
585 586
586 return ra; 587 return ra;
587} 588}
588 589
589 590
590/*! 591/*!
591 Smooth the points in an array. Probably a bad idea. 592 Smooth the points in an array. Probably a bad idea.
592*/ 593*/
593void QIMPenStroke::smooth( QArray<int> &sig) 594void QIMPenStroke::smooth( QArray<int> &sig)
594{ 595{
595 QArray<int> nsig = sig.copy(); 596 QArray<int> nsig = sig.copy();
596 597
597 int a; 598 int a;
598 for ( unsigned i = 1; i < sig.count()-2; i++ ) { 599 for ( unsigned i = 1; i < sig.count()-2; i++ ) {
599 a = 0; 600 a = 0;
600 for ( int j = -1; j <= 1; j++ ) { 601 for ( int j = -1; j <= 1; j++ ) {
601 a += sig[ i + j ]; 602 a += sig[ i + j ];
602 } 603 }
603 nsig[i] = a / 3; 604 nsig[i] = a / 3;
604 } 605 }
605 606
606 sig = nsig; 607 sig = nsig;
607} 608}
608 609
609/*! 610/*!
610 Write the character's data to the stream. 611 Write the character's data to the stream.
611*/ 612*/
612QDataStream &operator<< (QDataStream &s, const QIMPenStroke &ws) 613QDataStream &operator<< (QDataStream &s, const QIMPenStroke &ws)
613{ 614{
614 s << ws.startPoint; 615 s << ws.startPoint;
615 s << ws.links.count(); 616 s << ws.links.count();
616 for ( unsigned i = 0; i < ws.links.count(); i++ ) { 617 for ( unsigned i = 0; i < ws.links.count(); i++ ) {
617 s << (Q_INT8)ws.links[i].dx; 618 s << (Q_INT8)ws.links[i].dx;
618 s << (Q_INT8)ws.links[i].dy; 619 s << (Q_INT8)ws.links[i].dy;
619 } 620 }
620 621
621 return s; 622 return s;
622} 623}
623 624
624/*! 625/*!
625 Read the character's data from the stream. 626 Read the character's data from the stream.
626*/ 627*/
627QDataStream &operator>> (QDataStream &s, QIMPenStroke &ws) 628QDataStream &operator>> (QDataStream &s, QIMPenStroke &ws)
628{ 629{
629 Q_INT8 i8; 630 Q_INT8 i8;
630 s >> ws.startPoint; 631 s >> ws.startPoint;
631 ws.lastPoint = ws.startPoint; 632 ws.lastPoint = ws.startPoint;
632 unsigned size; 633 unsigned size;
633 s >> size; 634 s >> size;
634 ws.links.resize( size ); 635 ws.links.resize( size );
635 for ( unsigned i = 0; i < size; i++ ) { 636 for ( unsigned i = 0; i < size; i++ ) {
636 s >> i8; 637 s >> i8;
637 ws.links[i].dx = i8; 638 ws.links[i].dx = i8;
638 s >> i8; 639 s >> i8;
639 ws.links[i].dy = i8; 640 ws.links[i].dy = i8;
640 ws.lastPoint += QPoint( ws.links[i].dx, ws.links[i].dy ); 641 ws.lastPoint += QPoint( ws.links[i].dx, ws.links[i].dy );
641 } 642 }
642 643
643 return s; 644 return s;
644} 645}
645 646
646 647
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
@@ -1,113 +1,113 @@
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 <qpainter.h> 21#include <qpainter.h>
22#include "qimpenwordpick.h" 22#include "qimpenwordpick.h"
23 23
24QIMPenWordPick::QIMPenWordPick( QWidget *parent, const char *name, WFlags f ) 24QIMPenWordPick::QIMPenWordPick( QWidget *parent, const char *name, WFlags f )
25 : QFrame( parent, name, f ) 25 : QFrame( parent, name, f )
26{ 26{
27 clickWord = -1; 27 clickWord = -1;
28 setSizePolicy( QSizePolicy( QSizePolicy::Minimum, QSizePolicy::Fixed ) ); 28 setSizePolicy( QSizePolicy( QSizePolicy::Minimum, QSizePolicy::Fixed ) );
29} 29}
30 30
31void QIMPenWordPick::clear() 31void QIMPenWordPick::clear()
32{ 32{
33 words.clear(); 33 words.clear();
34 repaint(); 34 repaint();
35} 35}
36 36
37QSize QIMPenWordPick::sizeHint() const 37QSize QIMPenWordPick::sizeHint() const
38{ 38{
39 return QSize( -1, font().pixelSize()+2 ); 39 return QSize( -1, font().pixelSize()+2 );
40} 40}
41 41
42void QIMPenWordPick::setWords( const QIMPenMatch::MatchWordList &w ) 42void 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