-rw-r--r-- | inputmethods/handwriting/qimpenchar.cpp | 9 | ||||
-rw-r--r-- | inputmethods/handwriting/qimpeninput.cpp | 24 | ||||
-rw-r--r-- | inputmethods/handwriting/qimpenmatch.cpp | 35 | ||||
-rw-r--r-- | inputmethods/handwriting/qimpenstroke.cpp | 15 | ||||
-rw-r--r-- | inputmethods/handwriting/qimpenwordpick.cpp | 2 |
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 | ||
32 | const QIMPenSpecialKeys qimpen_specialKeys[] = { | 33 | const QIMPenSpecialKeys qimpen_specialKeys[] = { |
33 | { Qt::Key_Escape, "[Esc]" }, | 34 | { Qt::Key_Escape, "[Esc]" }, |
34 | { Qt::Key_Tab, "[Tab]" }, | 35 | { Qt::Key_Tab, "[Tab]" }, |
35 | { Qt::Key_Backspace,"[BackSpace]" }, | 36 | { Qt::Key_Backspace,"[BackSpace]" }, |
36 | { Qt::Key_Return, "[Return]" }, | 37 | { Qt::Key_Return, "[Return]" }, |
37 | { QIMPenChar::Caps, "[Uppercase]" }, | 38 | { QIMPenChar::Caps, "[Uppercase]" }, |
38 | { QIMPenChar::CapsLock,"[Caps Lock]" }, | 39 | { QIMPenChar::CapsLock,"[Caps Lock]" }, |
39 | { QIMPenChar::Shortcut,"[Shortcut]" }, | 40 | { QIMPenChar::Shortcut,"[Shortcut]" }, |
40 | { QIMPenChar::Punctuation, "[Punctuation]" }, | 41 | { QIMPenChar::Punctuation, "[Punctuation]" }, |
41 | { QIMPenChar::Symbol,"[Symbol]" }, | 42 | { QIMPenChar::Symbol,"[Symbol]" }, |
42 | { QIMPenChar::Extended,"[Extended]" }, | 43 | { QIMPenChar::Extended,"[Extended]" }, |
43 | { Qt::Key_unknown, 0 } }; | 44 | { Qt::Key_unknown, 0 } }; |
44 | 45 | ||
45 | 46 | ||
46 | /*! | 47 | /*! |
47 | \class QIMPenChar qimpenchar.h | 48 | \class QIMPenChar qimpenchar.h |
48 | 49 | ||
49 | Handles a single character. Can calculate closeness of match to | 50 | Handles a single character. Can calculate closeness of match to |
50 | another character. | 51 | another character. |
51 | */ | 52 | */ |
52 | 53 | ||
53 | QIMPenChar::QIMPenChar() | 54 | QIMPenChar::QIMPenChar() |
54 | { | 55 | { |
55 | flags = 0; | 56 | flags = 0; |
56 | strokes.setAutoDelete( TRUE ); | 57 | strokes.setAutoDelete( TRUE ); |
57 | } | 58 | } |
58 | 59 | ||
59 | QIMPenChar::QIMPenChar( const QIMPenChar &chr ) | 60 | QIMPenChar::QIMPenChar( const QIMPenChar &chr ) |
60 | { | 61 | { |
61 | strokes.setAutoDelete( TRUE ); | 62 | strokes.setAutoDelete( TRUE ); |
62 | ch = chr.ch; | 63 | ch = chr.ch; |
63 | flags = chr.flags; | 64 | flags = chr.flags; |
64 | d = chr.d; | 65 | d = chr.d; |
65 | QIMPenStrokeIterator it( chr.strokes ); | 66 | QIMPenStrokeIterator it( chr.strokes ); |
66 | while ( it.current() ) { | 67 | while ( it.current() ) { |
67 | strokes.append( new QIMPenStroke( *it.current() ) ); | 68 | strokes.append( new QIMPenStroke( *it.current() ) ); |
68 | ++it; | 69 | ++it; |
69 | } | 70 | } |
70 | } | 71 | } |
71 | 72 | ||
72 | QIMPenChar &QIMPenChar::operator=( const QIMPenChar &chr ) | 73 | QIMPenChar &QIMPenChar::operator=( const QIMPenChar &chr ) |
73 | { | 74 | { |
74 | strokes.clear(); | 75 | strokes.clear(); |
75 | ch = chr.ch; | 76 | ch = chr.ch; |
76 | flags = chr.flags; | 77 | flags = chr.flags; |
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 | ||
87 | QString QIMPenChar::name() const | 88 | QString 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 | ||
106 | void QIMPenChar::clear() | 107 | void 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 | ||
114 | unsigned int QIMPenChar::strokeLength( int s ) const | 115 | unsigned 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 | */ |
131 | void QIMPenChar::addStroke( QIMPenStroke *st ) | 132 | void QIMPenChar::addStroke( QIMPenStroke *st ) |
132 | { | 133 | { |
133 | QIMPenStroke *stroke = new QIMPenStroke( *st ); | 134 | QIMPenStroke *stroke = new QIMPenStroke( *st ); |
134 | strokes.append( stroke ); | 135 | strokes.append( stroke ); |
135 | } | 136 | } |
136 | 137 | ||
137 | /*! | 138 | /*! |
138 | Return an indicator of the closeness of this character to \a pen. | 139 | Return an indicator of the closeness of this character to \a pen. |
139 | Lower value is better. | 140 | Lower value is better. |
140 | */ | 141 | */ |
141 | int QIMPenChar::match( QIMPenChar *pen ) | 142 | int QIMPenChar::match( QIMPenChar *pen ) |
142 | { | 143 | { |
143 | /* | 144 | /* |
144 | if ( strokes.count() > pen->strokes.count() ) | 145 | if ( strokes.count() > pen->strokes.count() ) |
145 | return INT_MAX; | 146 | return INT_MAX; |
146 | */ | 147 | */ |
147 | int err = 0; | 148 | int err = 0; |
148 | int maxErr = 0; | 149 | int maxErr = 0; |
149 | int diff = 0; | 150 | int diff = 0; |
150 | QIMPenStrokeIterator it1( strokes ); | 151 | QIMPenStrokeIterator it1( strokes ); |
151 | QIMPenStrokeIterator it2( pen->strokes ); | 152 | QIMPenStrokeIterator it2( pen->strokes ); |
152 | err = it1.current()->match( it2.current() ); | 153 | err = it1.current()->match( it2.current() ); |
153 | if ( err > maxErr ) | 154 | if ( err > maxErr ) |
154 | maxErr = err; | 155 | maxErr = err; |
155 | ++it1; | 156 | ++it1; |
156 | ++it2; | 157 | ++it2; |
157 | while ( err < 400000 && it1.current() && it2.current() ) { | 158 | while ( err < 400000 && it1.current() && it2.current() ) { |
158 | QPoint p1 = it1.current()->boundingRect().center() - | 159 | QPoint p1 = it1.current()->boundingRect().center() - |
159 | strokes.getFirst()->boundingRect().center(); | 160 | strokes.getFirst()->boundingRect().center(); |
160 | QPoint p2 = it2.current()->boundingRect().center() - | 161 | QPoint p2 = it2.current()->boundingRect().center() - |
161 | pen->strokes.getFirst()->boundingRect().center(); | 162 | pen->strokes.getFirst()->boundingRect().center(); |
162 | int xdiff = QABS( p1.x() - p2.x() ) - 6; | 163 | int xdiff = QABS( p1.x() - p2.x() ) - 6; |
163 | int ydiff = QABS( p1.y() - p2.y() ) - 5; | 164 | int ydiff = QABS( p1.y() - p2.y() ) - 5; |
164 | if ( xdiff < 0 ) | 165 | if ( xdiff < 0 ) |
165 | xdiff = 0; | 166 | xdiff = 0; |
166 | if ( ydiff < 0 ) | 167 | if ( ydiff < 0 ) |
167 | ydiff = 0; | 168 | ydiff = 0; |
168 | if ( xdiff > 10 || ydiff > 10 ) { // not a chance | 169 | if ( xdiff > 10 || ydiff > 10 ) { // not a chance |
169 | #ifdef DEBUG_QIMPEN | 170 | #ifdef DEBUG_QIMPEN |
170 | qDebug( "char %c, stroke starting pt diff excessive", pen->ch ); | 171 | odebug << "char " << pen->ch <<", stroke starting pt diff excessive" << oendl; |
171 | #endif | 172 | #endif |
172 | return INT_MAX; | 173 | return INT_MAX; |
173 | } | 174 | } |
174 | diff += xdiff*xdiff + ydiff*ydiff; | 175 | diff += xdiff*xdiff + ydiff*ydiff; |
175 | err = it1.current()->match( it2.current() ); | 176 | err = it1.current()->match( it2.current() ); |
176 | if ( err > maxErr ) | 177 | if ( err > maxErr ) |
177 | maxErr = err; | 178 | maxErr = err; |
178 | ++it1; | 179 | ++it1; |
179 | ++it2; | 180 | ++it2; |
180 | } | 181 | } |
181 | 182 | ||
182 | maxErr += diff * diff * 6; // magic weighting :) | 183 | maxErr += diff * diff * 6; // magic weighting :) |
183 | 184 | ||
184 | #ifdef DEBUG_QIMPEN | 185 | #ifdef DEBUG_QIMPEN |
185 | qDebug( "char: %c, maxErr %d, diff %d, (%d)", pen->ch, maxErr, diff, strokes.count() ); | 186 | odebug << "char: " << pen->ch << ", maxErr " << maxErr << ", diff " << diff << ", " << strokes.count() << oendl; |
186 | #endif | 187 | #endif |
187 | return maxErr; | 188 | return maxErr; |
188 | } | 189 | } |
189 | 190 | ||
190 | /*! | 191 | /*! |
191 | Return the bounding rect of this character. It may have sides with | 192 | Return the bounding rect of this character. It may have sides with |
192 | negative coords since its origin is where the user started drawing | 193 | negative coords since its origin is where the user started drawing |
193 | the character. | 194 | the character. |
194 | */ | 195 | */ |
195 | QRect QIMPenChar::boundingRect() | 196 | QRect QIMPenChar::boundingRect() |
196 | { | 197 | { |
197 | QRect br; | 198 | QRect br; |
198 | QIMPenStroke *st = strokes.first(); | 199 | QIMPenStroke *st = strokes.first(); |
199 | while ( st ) { | 200 | while ( st ) { |
200 | br |= st->boundingRect(); | 201 | br |= st->boundingRect(); |
201 | st = strokes.next(); | 202 | st = strokes.next(); |
202 | } | 203 | } |
203 | 204 | ||
204 | return br; | 205 | return br; |
205 | } | 206 | } |
206 | 207 | ||
207 | 208 | ||
208 | /*! | 209 | /*! |
209 | Write the character's data to the stream. | 210 | Write the character's data to the stream. |
210 | */ | 211 | */ |
211 | QDataStream &operator<< (QDataStream &s, const QIMPenChar &ws) | 212 | QDataStream &operator<< (QDataStream &s, const QIMPenChar &ws) |
212 | { | 213 | { |
213 | s << ws.ch; | 214 | s << ws.ch; |
214 | s << ws.flags; | 215 | s << ws.flags; |
215 | if ( ws.flags & QIMPenChar::Data ) | 216 | if ( ws.flags & QIMPenChar::Data ) |
216 | s << ws.d; | 217 | s << ws.d; |
217 | s << ws.strokes.count(); | 218 | s << ws.strokes.count(); |
218 | QIMPenStrokeIterator it( ws.strokes ); | 219 | QIMPenStrokeIterator it( ws.strokes ); |
219 | while ( it.current() ) { | 220 | while ( it.current() ) { |
220 | s << *it.current(); | 221 | s << *it.current(); |
221 | ++it; | 222 | ++it; |
222 | } | 223 | } |
223 | 224 | ||
224 | return s; | 225 | return s; |
225 | } | 226 | } |
226 | 227 | ||
227 | /*! | 228 | /*! |
228 | Read the character's data from the stream. | 229 | Read the character's data from the stream. |
229 | */ | 230 | */ |
230 | QDataStream &operator>> (QDataStream &s, QIMPenChar &ws) | 231 | QDataStream &operator>> (QDataStream &s, QIMPenChar &ws) |
231 | { | 232 | { |
232 | s >> ws.ch; | 233 | s >> ws.ch; |
233 | s >> ws.flags; | 234 | s >> ws.flags; |
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 | ||
249 | bool QIMPenCharMatch::operator>( const QIMPenCharMatch &m ) | 250 | bool QIMPenCharMatch::operator>( const QIMPenCharMatch &m ) |
250 | { | 251 | { |
251 | return error > m.error; | 252 | return error > m.error; |
252 | } | 253 | } |
253 | 254 | ||
254 | bool QIMPenCharMatch::operator<( const QIMPenCharMatch &m ) | 255 | bool QIMPenCharMatch::operator<( const QIMPenCharMatch &m ) |
255 | { | 256 | { |
256 | return error < m.error; | 257 | return error < m.error; |
257 | } | 258 | } |
258 | 259 | ||
259 | bool QIMPenCharMatch::operator<=( const QIMPenCharMatch &m ) | 260 | bool 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 | ||
272 | QIMPenCharSet::QIMPenCharSet() | 273 | QIMPenCharSet::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 | */ |
284 | QIMPenCharSet::QIMPenCharSet( const QString &fn ) | 285 | QIMPenCharSet::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 | ||
294 | const QString &QIMPenCharSet::filename( Domain d ) const | 295 | const 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 | ||
302 | void QIMPenCharSet::setFilename( const QString &fn, Domain d ) | 303 | void 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 | */ |
313 | bool QIMPenCharSet::load( const QString &fn, Domain d ) | 314 | bool 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 | */ |
356 | bool QIMPenCharSet::save( Domain d ) | 357 | bool 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 | ||
405 | QIMPenChar *QIMPenCharSet::at( int i ) | 406 | QIMPenChar *QIMPenCharSet::at( int i ) |
406 | { | 407 | { |
407 | return chars.at(i); | 408 | return chars.at(i); |
408 | } | 409 | } |
409 | 410 | ||
410 | void QIMPenCharSet::markDeleted( uint ch ) | 411 | void 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 | */ |
423 | QIMPenCharMatchList QIMPenCharSet::match( QIMPenChar *ch ) | 424 | QIMPenCharMatchList QIMPenCharSet::match( QIMPenChar *ch ) |
424 | { | 425 | { |
425 | QIMPenCharMatchList matches; | 426 | QIMPenCharMatchList matches; |
426 | 427 | ||
427 | QIMPenCharIterator ci( chars ); | 428 | QIMPenCharIterator ci( chars ); |
428 | for ( ; ci.current(); ++ci ) { | 429 | for ( ; ci.current(); ++ci ) { |
429 | QIMPenChar *tmplChar = ci.current(); | 430 | QIMPenChar *tmplChar = ci.current(); |
430 | if ( tmplChar->testFlag( QIMPenChar::Deleted ) ) { | 431 | if ( tmplChar->testFlag( QIMPenChar::Deleted ) ) { |
431 | continue; | 432 | continue; |
432 | } | 433 | } |
433 | int err; | 434 | int err; |
434 | if ( ch->penStrokes().count() <= tmplChar->penStrokes().count() ) { | 435 | if ( ch->penStrokes().count() <= tmplChar->penStrokes().count() ) { |
435 | err = ch->match( tmplChar ); | 436 | err = ch->match( tmplChar ); |
436 | if ( err <= QIMPEN_MATCH_THRESHOLD ) { | 437 | if ( err <= QIMPEN_MATCH_THRESHOLD ) { |
437 | if (tmplChar->penStrokes().count() != ch->penStrokes().count()) | 438 | if (tmplChar->penStrokes().count() != ch->penStrokes().count()) |
438 | err = QMIN(err*3, QIMPEN_MATCH_THRESHOLD); | 439 | err = QMIN(err*3, QIMPEN_MATCH_THRESHOLD); |
439 | QIMPenCharMatchList::Iterator it; | 440 | QIMPenCharMatchList::Iterator it; |
440 | for ( it = matches.begin(); it != matches.end(); ++it ) { | 441 | for ( it = matches.begin(); it != matches.end(); ++it ) { |
441 | if ( (*it).penChar->character() == tmplChar->character() && | 442 | if ( (*it).penChar->character() == tmplChar->character() && |
442 | (*it).penChar->penStrokes().count() == tmplChar->penStrokes().count() ) { | 443 | (*it).penChar->penStrokes().count() == tmplChar->penStrokes().count() ) { |
443 | if ( (*it).error > err ) | 444 | if ( (*it).error > err ) |
444 | (*it).error = err; | 445 | (*it).error = err; |
445 | break; | 446 | break; |
446 | } | 447 | } |
447 | } | 448 | } |
448 | if ( it == matches.end() ) { | 449 | if ( it == matches.end() ) { |
449 | QIMPenCharMatch m; | 450 | QIMPenCharMatch m; |
450 | m.error = err; | 451 | m.error = err; |
451 | m.penChar = tmplChar; | 452 | m.penChar = tmplChar; |
452 | matches.append( m ); | 453 | matches.append( m ); |
453 | } | 454 | } |
454 | } | 455 | } |
455 | } | 456 | } |
456 | } | 457 | } |
457 | qHeapSort( matches ); | 458 | qHeapSort( matches ); |
458 | /* | 459 | /* |
459 | QIMPenCharMatchList::Iterator it; | 460 | QIMPenCharMatchList::Iterator it; |
460 | for ( it = matches.begin(); it != matches.end(); ++it ) { | 461 | for ( it = matches.begin(); it != matches.end(); ++it ) { |
461 | qDebug( "Match: \'%c\', error %d, strokes %d", (*it).penChar->character(), | 462 | |
462 | (*it).error, (*it).penChar->penStrokes().count() ); | 463 | odebug << "Match: \'" << (*it).penChar->character() "\', error " << (*it).error ", strokes " <<(*it).penChar->penStrokes().count() << oendl; |
463 | } | 464 | } |
464 | */ | 465 | */ |
465 | return matches; | 466 | return matches; |
466 | } | 467 | } |
467 | 468 | ||
468 | /*! | 469 | /*! |
469 | Add a character \a ch to this set. | 470 | Add a character \a ch to this set. |
470 | QIMPenCharSet will delete this character when it is no longer needed. | 471 | QIMPenCharSet will delete this character when it is no longer needed. |
471 | */ | 472 | */ |
472 | void QIMPenCharSet::addChar( QIMPenChar *ch ) | 473 | void QIMPenCharSet::addChar( QIMPenChar *ch ) |
473 | { | 474 | { |
474 | if ( ch->penStrokes().count() > maxStrokes ) | 475 | if ( ch->penStrokes().count() > maxStrokes ) |
475 | maxStrokes = ch->penStrokes().count(); | 476 | maxStrokes = ch->penStrokes().count(); |
476 | chars.append( ch ); | 477 | chars.append( ch ); |
477 | } | 478 | } |
478 | 479 | ||
479 | /*! | 480 | /*! |
480 | Remove a character by reference \a ch from this set. | 481 | Remove a character by reference \a ch from this set. |
481 | QIMPenCharSet will delete this character. | 482 | QIMPenCharSet will delete this character. |
482 | */ | 483 | */ |
483 | void QIMPenCharSet::removeChar( QIMPenChar *ch ) | 484 | void QIMPenCharSet::removeChar( QIMPenChar *ch ) |
484 | { | 485 | { |
485 | chars.remove( ch ); | 486 | chars.remove( ch ); |
486 | } | 487 | } |
487 | 488 | ||
488 | /*! | 489 | /*! |
489 | Move the character up the list of characters. | 490 | Move the character up the list of characters. |
490 | */ | 491 | */ |
491 | void QIMPenCharSet::up( QIMPenChar *ch ) | 492 | void QIMPenCharSet::up( QIMPenChar *ch ) |
492 | { | 493 | { |
493 | int idx = chars.findRef( ch ); | 494 | int idx = chars.findRef( ch ); |
494 | if ( idx > 0 ) { | 495 | if ( idx > 0 ) { |
495 | chars.take(); | 496 | chars.take(); |
496 | chars.insert( idx - 1, ch ); | 497 | chars.insert( idx - 1, ch ); |
497 | } | 498 | } |
498 | } | 499 | } |
499 | 500 | ||
500 | /*! | 501 | /*! |
501 | Move the character down the list of characters. | 502 | Move the character down the list of characters. |
502 | */ | 503 | */ |
503 | void QIMPenCharSet::down( QIMPenChar *ch ) | 504 | void QIMPenCharSet::down( QIMPenChar *ch ) |
504 | { | 505 | { |
505 | int idx = chars.findRef( ch ); | 506 | int idx = chars.findRef( ch ); |
506 | if ( idx >= 0 && idx < (int)chars.count() - 1 ) { | 507 | if ( idx >= 0 && idx < (int)chars.count() - 1 ) { |
507 | chars.take(); | 508 | chars.take(); |
508 | chars.insert( idx + 1, ch ); | 509 | chars.insert( idx + 1, ch ); |
509 | } | 510 | } |
510 | } | 511 | } |
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 */ |
45 | static const char * const pen_xpm[] = { | 46 | static 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 */ |
66 | static char * bs_xpm[] = { | 67 | static 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 */ |
88 | static char * enter_xpm[] = { | 89 | static 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 */ |
111 | static char * help_xpm[] = { | 112 | static 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 | */ |
137 | QIMPenInput::QIMPenInput( QWidget *parent, const char *name, WFlags wf ) | 138 | QIMPenInput::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 | ||
223 | QIMPenInput::~QIMPenInput() | 224 | QIMPenInput::~QIMPenInput() |
224 | { | 225 | { |
225 | delete (HandwritingHelp*) helpDlg; | 226 | delete (HandwritingHelp*) helpDlg; |
226 | } | 227 | } |
227 | 228 | ||
228 | QSize QIMPenInput::sizeHint() const | 229 | QSize 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 | ||
235 | void QIMPenInput::loadProfiles() | 236 | void 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 | ||
263 | void QIMPenInput::selectProfile( const QString &name ) | 264 | void 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 | ||
306 | void QIMPenInput::wordPicked( const QString &w ) | 307 | void 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 | ||
319 | void QIMPenInput::selectCharSet( int idx ) | 320 | void 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 | ||
329 | void QIMPenInput::beginStroke() | 330 | void QIMPenInput::beginStroke() |
330 | { | 331 | { |
331 | } | 332 | } |
332 | 333 | ||
333 | void QIMPenInput::strokeEntered( QIMPenStroke * ) | 334 | void QIMPenInput::strokeEntered( QIMPenStroke * ) |
334 | { | 335 | { |
335 | pw->greyStroke(); | 336 | pw->greyStroke(); |
336 | } | 337 | } |
337 | 338 | ||
338 | void QIMPenInput::erase() | 339 | void QIMPenInput::erase() |
339 | { | 340 | { |
340 | keypress( Qt::Key_Backspace << 16 ); | 341 | keypress( Qt::Key_Backspace << 16 ); |
341 | } | 342 | } |
342 | 343 | ||
343 | void QIMPenInput::matchedCharacters( const QIMPenCharMatchList &cl ) | 344 | void 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 | ||
415 | void QIMPenInput::keypress( uint scan_uni ) | 417 | void 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 | ||
458 | void QIMPenInput::handleExtended( const QString &ex ) | 460 | void 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 | ||
467 | void QIMPenInput::help() | 469 | void 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 | */ |
480 | void QIMPenInput::setup() | 482 | void 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 | ||
499 | void QIMPenInput::backspace() | 501 | void 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 | ||
505 | void QIMPenInput::enter() | 507 | void 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 | ||
512 | void QIMPenInput::resetState() | 514 | void 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 | ||
35 | QIMPenMatch::QIMPenMatch( QObject *parent, const char *name ) | 36 | QIMPenMatch::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 | ||
54 | QIMPenMatch::~QIMPenMatch() | 55 | QIMPenMatch::~QIMPenMatch() |
55 | { | 56 | { |
56 | } | 57 | } |
57 | 58 | ||
58 | void QIMPenMatch::setCharSet( QIMPenCharSet *cs ) | 59 | void QIMPenMatch::setCharSet( QIMPenCharSet *cs ) |
59 | { | 60 | { |
60 | charSet = cs; | 61 | charSet = cs; |
61 | } | 62 | } |
62 | 63 | ||
63 | void QIMPenMatch::beginStroke() | 64 | void QIMPenMatch::beginStroke() |
64 | { | 65 | { |
65 | multiTimer->stop(); | 66 | multiTimer->stop(); |
66 | } | 67 | } |
67 | 68 | ||
68 | void QIMPenMatch::strokeEntered( QIMPenStroke *st ) | 69 | void 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 | ||
97 | void QIMPenMatch::processMatches( QIMPenCharMatchList &ml ) | 98 | void 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 | ||
221 | void QIMPenMatch::updateWordMatch( QIMPenCharMatchList &ml ) | 222 | void 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 | ||
264 | void QIMPenMatch::matchWords() | 265 | void 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 | ||
292 | void QIMPenMatch::scanDict( const QDawg::Node* n, int ipos, const QString& str, int error ) | 293 | void 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 | ||
335 | void QIMPenMatch::backspace() | 336 | void 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 | ||
347 | void QIMPenMatch::endMulti() | 348 | void 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 | ||
356 | void QIMPenMatch::resetState() | 357 | void 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 | ||
38 | QIMPenStroke::QIMPenStroke() | 39 | QIMPenStroke::QIMPenStroke() |
39 | { | 40 | { |
40 | } | 41 | } |
41 | 42 | ||
42 | QIMPenStroke::QIMPenStroke( const QIMPenStroke &st ) | 43 | QIMPenStroke::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 | ||
49 | QIMPenStroke &QIMPenStroke::operator=( const QIMPenStroke &s ) | 50 | QIMPenStroke &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 | ||
60 | void QIMPenStroke::clear() | 61 | void 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 | */ |
73 | void QIMPenStroke::beginInput( QPoint p ) | 74 | void 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 | */ |
85 | bool QIMPenStroke::addPoint( QPoint p ) | 86 | bool 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 | */ |
142 | void QIMPenStroke::endInput() | 143 | void 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 | */ |
159 | unsigned int QIMPenStroke::match( QIMPenStroke *pen ) | 160 | unsigned 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 | */ |
259 | QRect QIMPenStroke::boundingRect() | 260 | QRect 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 | ||
292 | int QIMPenStroke::calcError( const QArray<int> &base, | 293 | int 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 | */ |
312 | void QIMPenStroke::createSignatures() | 313 | void 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 | */ |
325 | void QIMPenStroke::createTanSignature() | 326 | void 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 | */ |
358 | void QIMPenStroke::createAngleSignature() | 359 | void 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 | */ |
406 | void QIMPenStroke::createDistSignature() | 407 | void 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 | */ |
448 | QArray<int> QIMPenStroke::scale( const QArray<int> &s, unsigned count, bool t ) | 449 | QArray<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 | */ |
487 | void QIMPenStroke::internalAddPoint( QPoint p ) | 488 | void 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 | */ |
507 | QPoint QIMPenStroke::calcCenter() | 508 | QPoint 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 | */ |
531 | int QIMPenStroke::arcTan( int dy, int dx ) | 532 | int 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 | */ |
574 | QArray<int> QIMPenStroke::createBase( const QArray<int> a, int e ) | 575 | QArray<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 | */ |
593 | void QIMPenStroke::smooth( QArray<int> &sig) | 594 | void 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 | */ |
612 | QDataStream &operator<< (QDataStream &s, const QIMPenStroke &ws) | 613 | QDataStream &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 | */ |
627 | QDataStream &operator>> (QDataStream &s, QIMPenStroke &ws) | 628 | QDataStream &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 | ||
24 | QIMPenWordPick::QIMPenWordPick( QWidget *parent, const char *name, WFlags f ) | 24 | QIMPenWordPick::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 | ||
31 | void QIMPenWordPick::clear() | 31 | void QIMPenWordPick::clear() |
32 | { | 32 | { |
33 | words.clear(); | 33 | words.clear(); |
34 | repaint(); | 34 | repaint(); |
35 | } | 35 | } |
36 | 36 | ||
37 | QSize QIMPenWordPick::sizeHint() const | 37 | QSize QIMPenWordPick::sizeHint() const |
38 | { | 38 | { |
39 | return QSize( -1, font().pixelSize()+2 ); | 39 | return QSize( -1, font().pixelSize()+2 ); |
40 | } | 40 | } |
41 | 41 | ||
42 | void QIMPenWordPick::setWords( const QIMPenMatch::MatchWordList &w ) | 42 | void QIMPenWordPick::setWords( const QIMPenMatch::MatchWordList &w ) |
43 | { | 43 | { |
44 | words.clear(); | 44 | words.clear(); |
45 | QListIterator<QIMPenMatch::MatchWord> it( w ); | 45 | QListIterator<QIMPenMatch::MatchWord> it( w ); |
46 | for ( ; it.current(); ++it ) { | 46 | for ( ; it.current(); ++it ) { |
47 | words.append( it.current()->word ); | 47 | words.append( it.current()->word ); |
48 | } | 48 | } |
49 | repaint(); | 49 | repaint(); |
50 | } | 50 | } |
51 | 51 | ||
52 | int QIMPenWordPick::onWord( QPoint p ) | 52 | int 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 | ||
72 | void QIMPenWordPick::paintEvent( QPaintEvent * ) | 72 | void 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 | ||
97 | void QIMPenWordPick::mousePressEvent( QMouseEvent *e ) | 97 | void QIMPenWordPick::mousePressEvent( QMouseEvent *e ) |
98 | { | 98 | { |
99 | clickWord = onWord( e->pos() ); | 99 | clickWord = onWord( e->pos() ); |
100 | repaint(); | 100 | repaint(); |
101 | } | 101 | } |
102 | 102 | ||
103 | void QIMPenWordPick::mouseReleaseEvent( QMouseEvent *e ) | 103 | void 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 | ||