summaryrefslogtreecommitdiff
path: root/inputmethods/handwriting/qimpeninput.cpp
Unidiff
Diffstat (limited to 'inputmethods/handwriting/qimpeninput.cpp') (more/less context) (ignore whitespace changes)
-rw-r--r--inputmethods/handwriting/qimpeninput.cpp515
1 files changed, 515 insertions, 0 deletions
diff --git a/inputmethods/handwriting/qimpeninput.cpp b/inputmethods/handwriting/qimpeninput.cpp
new file mode 100644
index 0000000..6718b26
--- a/dev/null
+++ b/inputmethods/handwriting/qimpeninput.cpp
@@ -0,0 +1,515 @@
1/**********************************************************************
2** Copyright (C) 2000 Trolltech AS. All rights reserved.
3**
4** This file is part of Qtopia Environment.
5**
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
8** Foundation and appearing in the file LICENSE.GPL included in the
9** packaging of this file.
10**
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.
13**
14** See http://www.trolltech.com/gpl/ for GPL licensing information.
15**
16** Contact info@trolltech.com if any conditions of this licensing are
17** not clear to you.
18**
19**********************************************************************/
20
21#include "qimpenwidget.h"
22#include "qimpensetup.h"
23#include "qimpeninput.h"
24#include "qimpencombining.h"
25#include "qimpenwordpick.h"
26#include "qimpenmatch.h"
27#include "qimpenhelp.h"
28
29#include <qpe/qpeapplication.h>
30#include <qpe/qdawg.h>
31#include <qpe/config.h>
32#include <qpe/global.h>
33
34#include <qlayout.h>
35#include <qpushbutton.h>
36#include <qlabel.h>
37#include <qtimer.h>
38#include <qdir.h>
39
40#include <limits.h>
41
42// We'll use little pixmaps for the buttons to save screen space.
43
44/* XPM */
45static const char * const pen_xpm[] = {
46"12 12 4 1",
47 " c None",
48 ".c #000000",
49 "+c #FFFFFF",
50 "@c #808080",
51" . ",
52" .+. ",
53" ..@@.",
54" .+@.. ",
55" .+@@. ",
56" .+@@. ",
57" .+@@. ",
58" .@.@. ",
59" .@@. ",
60" .... ",
61" .. ",
62" "};
63
64
65/* XPM */
66static char * bs_xpm[] = {
67"12 12 5 1",
68 " c None",
69 ".c #333333",
70 "+c #000000",
71 "@c #FFFFFF",
72 "#c #666666",
73" ",
74" ",
75" ",
76" . ",
77" ++ ",
78" +@#+++++. ",
79" +@@@@@@@@+ ",
80" +@#+++++. ",
81" ++ ",
82" . ",
83" ",
84" "};
85
86
87/* XPM */
88static char * enter_xpm[] = {
89"12 12 5 1",
90 " c None",
91 ".c #333333",
92 "+c #000000",
93 "@c #FFFFFF",
94 "#c #666666",
95" ",
96" .+. ",
97" +@+ ",
98" . +@+ ",
99" ++ +@+ ",
100" +@#++++@+ ",
101" +@@@@@@@@+ ",
102" +@#+++++. ",
103" ++ ",
104" . ",
105" ",
106" "};
107
108
109
110/* XPM */
111static char * help_xpm[] = {
112"12 12 5 1",
113 " c None",
114 ".c #000000",
115 "+c #FFFFFF",
116 "@c #666666",
117 "#c #333333",
118" ",
119" ... ",
120" .+++. ",
121" .+..@+. ",
122" #.# .+. ",
123" .+. ",
124" .+. ",
125" .+. ",
126" .+. ",
127" #.# ",
128" .+. ",
129" #.# "};
130
131
132/*!
133 \class QIMPenInput qimpeninput.h
134
135 Pen input widget.
136*/
137QIMPenInput::QIMPenInput( QWidget *parent, const char *name, WFlags f )
138 : QFrame( parent, name, f ), helpDlg(0), profile(0)
139{
140 setFrameStyle( Box | Plain );
141
142 profileList.setAutoDelete( true );
143
144 matcher = new QIMPenMatch( this );
145 connect( matcher, SIGNAL(keypress(uint)), this, SLOT(keypress(uint)) );
146 connect( matcher, SIGNAL(erase()), this, SLOT(erase()) );
147
148 QGridLayout *gl = new QGridLayout( this, 5, 2, 1, 0 );
149 gl->setColStretch( 0, 1 );
150
151 wordPicker = new QIMPenWordPick( this );
152 connect( wordPicker, SIGNAL(wordClicked(const QString &)),
153 this, SLOT(wordPicked(const QString &)) );
154 connect( matcher, SIGNAL(matchedCharacters(const QIMPenCharMatchList &)),
155 this, SLOT(matchedCharacters(const QIMPenCharMatchList &)) );
156 connect( matcher, SIGNAL(matchedWords(const QIMPenMatch::MatchWordList&)),
157 wordPicker, SLOT(setWords(const QIMPenMatch::MatchWordList&)) );
158 QFont f("smallsmooth",9);
159 QFontInfo fi( f );
160 wordPicker->setFont( f );
161 wordPicker->setBackgroundColor( white );
162 gl->addMultiCellWidget( wordPicker, 0, 0, 0, 1 );
163 if ( !Global::fixedDawg().root() || !matcher->isWordMatchingEnabled() )
164 wordPicker->hide();
165
166 pw = new QIMPenWidget( this );
167 gl->addMultiCellWidget( pw, 1, 4, 0, 0 );
168
169 int bh = pw->sizeHint().height()/4;
170
171 QPushButton *b = new QPushButton( this );
172 b->setFocusPolicy( NoFocus );
173 b->setPixmap( QPixmap( (const char **)bs_xpm ) );
174 b->setFixedHeight(pw->sizeHint().height()-3*bh); // left-over space goes here
175 b->setAutoRepeat( TRUE );
176 gl->addWidget( b, 1, 1 );
177 connect( b, SIGNAL(clicked()), SLOT(backspace()));
178
179 b = new QPushButton( this );
180 b->setFocusPolicy( NoFocus );
181 b->setPixmap( QPixmap( (const char **)enter_xpm ) );
182 b->setFixedHeight(bh);
183 b->setAutoRepeat( TRUE );
184 gl->addWidget( b, 2, 1 );
185 connect( b, SIGNAL(clicked()), SLOT(enter()));
186
187 helpBtn = new QPushButton( this );
188 helpBtn->setFocusPolicy( NoFocus );
189 helpBtn->setPixmap( QPixmap( (const char **)help_xpm ) );
190 helpBtn->setFixedHeight(bh);
191 gl->addWidget( helpBtn, 3, 1 );
192 connect( helpBtn, SIGNAL(clicked()), SLOT(help()));
193
194 QPixmap pm( (const char **)pen_xpm );
195 setupBtn = new QPushButton( this );
196 setupBtn->setFocusPolicy( NoFocus );
197 setupBtn->setPixmap( pm );
198 setupBtn->setFixedHeight(bh);
199 gl->addWidget( setupBtn, 4, 1 );
200 connect( setupBtn, SIGNAL(clicked()), SLOT(setup()));
201
202 connect( matcher, SIGNAL(removeStroke()), pw, SLOT(removeStroke()) );
203 connect( pw, SIGNAL(changeCharSet( QIMPenCharSet * )),
204 matcher, SLOT(setCharSet( QIMPenCharSet * )) );
205 connect( pw, SIGNAL(changeCharSet( int )),
206 this, SLOT(selectCharSet( int )) );
207 connect( pw, SIGNAL(beginStroke()),
208 matcher, SLOT(beginStroke()) );
209 connect( pw, SIGNAL(stroke( QIMPenStroke * )),
210 this, SLOT(strokeEntered( QIMPenStroke * )) );
211 connect( pw, SIGNAL(stroke( QIMPenStroke * )),
212 matcher, SLOT(strokeEntered( QIMPenStroke * )) );
213
214 shortcutCharSet = 0;
215 currCharSet = 0;
216 setupDlg = 0;
217 profile = 0;
218 mode = Normal;
219
220 loadProfiles();
221}
222
223QIMPenInput::~QIMPenInput()
224{
225 delete (HandwritingHelp*) helpDlg;
226}
227
228QSize QIMPenInput::sizeHint() const
229{
230 int fw = frameWidth();
231 int ps = wordPicker->isHidden() ? 0 : wordPicker->sizeHint().height();
232 return pw->sizeHint() + QSize( fw*2, fw*2+ps );
233}
234
235void QIMPenInput::loadProfiles()
236{
237 profileList.clear();
238 profile = 0;
239 delete shortcutCharSet;
240 shortcutCharSet = new QIMPenCharSet();
241 shortcutCharSet->setTitle( "Shortcut" );
242 QString path = QPEApplication::qpeDir() + "etc/qimpen";
243 QDir dir( path, "*.conf" );
244 QStringList list = dir.entryList();
245 QStringList::Iterator it;
246 for ( it = list.begin(); it != list.end(); ++it ) {
247 QIMPenProfile *p = new QIMPenProfile( path + "/" + *it );
248 profileList.append( p );
249 if ( p->shortcut() ) {
250 QIMPenCharIterator it( p->shortcut()->characters() );
251 for ( ; it.current(); ++it ) {
252 shortcutCharSet->addChar( new QIMPenChar(*it.current()) );
253 }
254 }
255 }
256
257 Config config( "handwriting" );
258 config.setGroup( "Settings" );
259 QString prof = config.readEntry( "Profile", "Default" );
260 selectProfile( prof );
261}
262
263void QIMPenInput::selectProfile( const QString &name )
264{
265 QListIterator<QIMPenProfile> it( profileList );
266 for ( ; it.current(); ++it ) {
267 if ( it.current()->name() == name ) {
268 profile = it.current();
269 break;
270 }
271 }
272
273 if ( !it.current() )
274 return;
275
276 pw->clearCharSets();
277 baseSets.clear();
278
279 matcher->setMultiStrokeTimeout( profile->multiStrokeTimeout() );
280 matcher->setWordMatchingEnabled( profile->matchWords() );
281
282 if ( !Global::fixedDawg().root() || !matcher->isWordMatchingEnabled() )
283 wordPicker->hide();
284 else
285 wordPicker->show();
286
287 if ( profile->uppercase() && profile->style() == QIMPenProfile::BothCases ) {
288 baseSets.append( profile->uppercase() );
289 pw->insertCharSet( profile->uppercase() );
290 }
291
292 if ( profile->lowercase() ) {
293 baseSets.append( profile->lowercase() );
294 pw->insertCharSet( profile->lowercase(), profile->style() == QIMPenProfile::BothCases ? 1 : 2 );
295 }
296
297 if ( profile->numeric() ) {
298 baseSets.append( profile->numeric() );
299 pw->insertCharSet( profile->numeric() );
300 }
301
302 if ( helpDlg )
303 delete (HandwritingHelp*) helpDlg;
304}
305
306void QIMPenInput::wordPicked( const QString &w )
307{
308 int bs = matcher->word().length();
309 for ( int i = 0; i < bs; i++ )
310 keypress( Qt::Key_Backspace << 16 );
311
312 for ( unsigned int i = 0; i < w.length(); i++ )
313 keypress( w[i].unicode() );
314
315 matcher->resetState();
316 wordPicker->clear();
317}
318
319void QIMPenInput::selectCharSet( int idx )
320{
321 if ( mode == Switch ) {
322 //qDebug( "Switch back to normal" );
323 pw->changeCharSet( baseSets.at(currCharSet), currCharSet );
324 mode = Normal;
325 }
326 currCharSet = idx;
327}
328
329void QIMPenInput::beginStroke()
330{
331}
332
333void QIMPenInput::strokeEntered( QIMPenStroke * )
334{
335 pw->greyStroke();
336}
337
338void QIMPenInput::erase()
339{
340 keypress( Qt::Key_Backspace << 16 );
341}
342
343void QIMPenInput::matchedCharacters( const QIMPenCharMatchList &cl )
344{
345 const QIMPenChar *ch = cl.first().penChar;
346 int scan = ch->character() >> 16;
347
348 if ( scan < QIMPenChar::ModeBase )
349 return;
350
351 // We matched a special character...
352
353 switch ( scan ) {
354 case QIMPenChar::Caps:
355 if ( profile->style() == QIMPenProfile::ToggleCases ) {
356 // qDebug( "Caps" );
357 if ( mode == SwitchLock ) {
358 // qDebug( "Switch to normal" );
359 pw->changeCharSet( profile->lowercase(), currCharSet );
360 mode = Switch;
361 } else {
362 // qDebug( "Switch to upper" );
363 pw->changeCharSet( profile->uppercase(), currCharSet );
364 mode = Switch;
365 }
366 }
367 break;
368 case QIMPenChar::CapsLock:
369 if ( profile->style() == QIMPenProfile::ToggleCases ) {
370 // qDebug( "CapsLock" );
371 if ( mode == Switch &&
372 baseSets.at(currCharSet) == profile->uppercase() ) {
373 // qDebug( "Switch to normal" );
374 pw->changeCharSet( profile->lowercase(), currCharSet );
375 // change our base set back to lower.
376 baseSets.remove( currCharSet );
377 baseSets.insert( currCharSet, profile->lowercase() );
378 mode = Normal;
379 } else {
380 // qDebug( "Switch to caps lock" );
381 pw->changeCharSet( profile->uppercase(), currCharSet );
382 // change our base set to upper.
383 baseSets.remove( currCharSet );
384 baseSets.insert( currCharSet, profile->uppercase() );
385 mode = SwitchLock;
386 }
387 }
388 break;
389 case QIMPenChar::Punctuation:
390 if ( profile->punctuation() ) {
391 //qDebug( "Switch to punctuation" );
392 pw->changeCharSet( profile->punctuation(), currCharSet );
393 mode = Switch;
394 }
395 break;
396 case QIMPenChar::Symbol:
397 if ( profile->symbol() ) {
398 //qDebug( "Switch to symbol" );
399 pw->changeCharSet( profile->symbol(), currCharSet );
400 mode = Switch;
401 }
402 break;
403 case QIMPenChar::Shortcut:
404 if ( shortcutCharSet ) {
405 pw->changeCharSet( shortcutCharSet, currCharSet );
406 mode = Switch;
407 }
408 break;
409 case QIMPenChar::Extended:
410 handleExtended( ch->data() );
411 break;
412 }
413}
414
415void QIMPenInput::keypress( uint scan_uni )
416{
417 int scan = scan_uni >> 16;
418 if ( !scan ) {
419 if ( scan_uni >= 'a' && scan_uni <= 'z' ) {
420 scan = Qt::Key_A + scan_uni - 'a';
421 } else if ( scan_uni >= 'A' && scan_uni <= 'Z' ) {
422 scan = Qt::Key_A + scan_uni - 'A';
423 } else if ( scan_uni == ' ' ) {
424 scan = Qt::Key_Space;
425 }
426 }
427
428 switch ( scan ) {
429 case Key_Tab:
430 scan_uni = 9;
431 break;
432 case Key_Return:
433 scan_uni = 13;
434 break;
435 case Key_Backspace:
436 scan_uni = 8;
437 break;
438 case Key_Escape:
439 scan_uni = 27;
440 break;
441 default:
442 break;
443 }
444
445 if ( mode == Switch ) {
446 //qDebug( "Switch back to normal" );
447 pw->changeCharSet( baseSets.at(currCharSet), currCharSet );
448 if ( baseSets.at(currCharSet) == profile->uppercase() )
449 mode = SwitchLock;
450 else
451 mode = Normal;
452 }
453
454 emit key( scan_uni&0xffff, scan, 0, true, false );
455 emit key( scan_uni&0xffff, scan, 0, false, false );
456}
457
458void QIMPenInput::handleExtended( const QString &ex )
459{
460 if ( ex.find( "Select" ) == 0 ) {
461 QString set = ex.mid( 7 );
462 qDebug( "Select new profile: %s", set.latin1() );
463 selectProfile( set );
464 }
465}
466
467void QIMPenInput::help()
468{
469 if ( helpDlg )
470 delete (HandwritingHelp*) helpDlg;
471 helpDlg = new HandwritingHelp( profile, 0, 0, WDestructiveClose );
472 helpDlg->showMaximized();
473 helpDlg->show();
474 helpDlg->raise();
475}
476
477/*!
478 Open the setup dialog
479*/
480void QIMPenInput::setup()
481{
482 if ( !setupDlg ) {
483 // We are working with our copy of the char sets here.
484 setupDlg = new QIMPenSetup( profile, 0, 0, TRUE );
485 setupDlg->editor()->selectCharSet( profile->charSets().at(1) );// lower case? This is crap.
486 if ( qApp->desktop()->width() < 640 )
487 setupDlg->showMaximized();
488 Global::hideInputMethod();
489 setupDlg->exec();
490 loadProfiles();
491 delete setupDlg;
492 setupDlg = 0;
493 Global::showInputMethod();
494 } else {
495 setupDlg->raise();
496 }
497}
498
499void QIMPenInput::backspace()
500{
501 keypress( Qt::Key_Backspace << 16 );
502 matcher->backspace();
503}
504
505void QIMPenInput::enter()
506{
507 keypress( Qt::Key_Return << 16 );
508 matcher->resetState();
509}
510
511
512void QIMPenInput::resetState()
513{
514 matcher->resetState();
515}