00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021 #include "pickboardcfg.h"
00022 #include "pickboardpicks.h"
00023
00024 #include <qpe/global.h>
00025
00026 #include <qpainter.h>
00027 #include <qlist.h>
00028 #include <qbitmap.h>
00029 #include <qlayout.h>
00030 #include <qvbox.h>
00031 #include <qdialog.h>
00032 #include <qscrollview.h>
00033 #include <qpopupmenu.h>
00034 #include <qhbuttongroup.h>
00035 #include <qpushbutton.h>
00036 #include <qmessagebox.h>
00037 #ifdef QWS
00038 #include <qwindowsystem_qws.h>
00039 #endif
00040
00041 static const char * pickboard_help =
00042 QT_TRANSLATE_NOOP("PickboardConfig", "<h1>The Pickboard</h1>"
00043 "<i>The smallest and fastest way to type.</i>"
00044 "<p>"
00045 "Enter a word by tapping letter-groups and picking the word."
00046 "<br>Enter spaces with \"Space\", or other keys through \"KEY\"."
00047 "<br>Use \"Shift\" to capitalize words that are not normally capitalized."
00048 "<br>Press \"Shift\" twice for an all-capitals word."
00049 "<br>Add custom words by picking them, then selecting \"Add...\" from the menu on the right." )
00050 ;
00051
00052 const int intermatchmargin=5;
00053
00054
00055 PickboardConfig::~PickboardConfig() { }
00056
00057 void PickboardConfig::updateRows(int from, int to)
00058 {
00059 if ( from != to ) {
00060 parent->update();
00061 } else {
00062 QFontMetrics fm = parent->fontMetrics();
00063 parent->update(QRect(0,1+fm.descent() + from * fm.lineSpacing(), parent->width(),
00064 fm.lineSpacing()));
00065 }
00066 }
00067
00068 void PickboardConfig::updateItem(int r, int)
00069 {
00070 updateRows(r,r);
00071 }
00072
00073 void PickboardConfig::changeMode(int m)
00074 {
00075 parent->setMode(m);
00076 }
00077 void PickboardConfig::generateText(const QString& s)
00078 {
00079 #if defined(Q_WS_QWS) || defined(_WS_QWS_)
00080 for (int i=0; i<(int)s.length(); i++) {
00081 uint code = 0;
00082 if ( s[i].unicode() >= 'a' && s[i].unicode() <= 'z' ) {
00083 code = s[i].unicode() - 'a' + Key_A;
00084 }
00085 parent->emitKey(s[i].unicode(), code, 0, true, false);
00086 parent->emitKey(s[i].unicode(), code, 0, false, false);
00087 }
00088 #endif
00089 }
00090 void PickboardConfig::generateKey( int k )
00091 {
00092 #if defined(Q_WS_QWS) || defined(_WS_QWS_)
00093 parent->emitKey(0, k, 0, true, false);
00094 parent->emitKey(0, k, 0, false, false);
00095 #endif
00096 }
00097
00098 void PickboardConfig::pickPoint(const QPoint& p, bool press)
00099 {
00100 if ( press ) {
00101 int ls=parent->height()/nrows;
00102 int y=0;
00103 pressx = -1;
00104 for (int r=0; r<nrows; r++) {
00105 if ( p.y() >= y && p.y() < y+ls ) {
00106 pressrow = r;
00107 pressx = p.x();
00108 pickInRow( pressrow, pressx, TRUE );
00109 return;
00110 }
00111 y += ls;
00112 }
00113 } else if ( pressx >= 0 ) {
00114 pickInRow( pressrow, pressx, FALSE );
00115 pressx = -1;
00116 }
00117 }
00118
00119 void PickboardConfig::fillMenu(QPopupMenu& menu)
00120 {
00121 menu.insertItem(tr("Reset"),100);
00122 menu.insertSeparator();
00123 menu.insertItem(tr("Help"),1);
00124 }
00125
00126 void PickboardConfig::doMenu(int i)
00127 {
00128 switch (i) {
00129 case 100:
00130 if ( parent->currentMode() ) {
00131 changeMode(0);
00132 updateRows(0,1);
00133 }
00134 break;
00135 case 1: {
00136 QMessageBox help(tr("Pickboard Help"), tr(pickboard_help),
00137 QMessageBox::NoIcon, 1, 0, 0);
00138 help.showMaximized();
00139 help.exec();
00140 }
00141 }
00142 }
00143
00144 void StringConfig::draw(QPainter* p)
00145 {
00146 QFontMetrics fm = p->fontMetrics();
00147
00148 for (int r=0; r<nrows; r++) {
00149 p->translate(0,fm.lineSpacing());
00150 p->setPen(rowColor(r));
00151
00152 int tw=0;
00153 QString s;
00154 int i=0;
00155 for (; !(s=text(r,i)).isNull(); ++i) {
00156 int w = fm.width(s);
00157 tw += w;
00158 }
00159 bool spread = spreadRow(r);
00160 int xw = spread ? (parent->width()-tw)/(i-1) : 3;
00161 int x = spread ? (parent->width()-tw-xw*(i-1))/2 : 2;
00162
00163 i=0;
00164 for (; !(s=text(r,i)).isNull(); ++i) {
00165 int w = fm.width(s)+xw;
00166 if ( highlight(r,i) ) {
00167 p->fillRect(x-xw/2,1+fm.descent()-fm.lineSpacing(),w,fm.lineSpacing(),Qt::black);
00168 p->setPen(Qt::white);
00169 }else{
00170 p->setPen(Qt::black);
00171 }
00172 p->drawText(x,-fm.descent()-1,s);
00173 x += w;
00174 }
00175 }
00176 }
00177
00178 void StringConfig::pickInRow(int r, int xpos, bool press)
00179 {
00180 QFontMetrics fm = parent->fontMetrics();
00181
00182 int tw=0;
00183 QString s;
00184 int i=0;
00185 for (; !(s=text(r,i)).isNull(); ++i) {
00186 int w = fm.width(s);
00187 tw += w;
00188 }
00189 bool spread = spreadRow(r) && parent->width() > tw;
00190 int xw = spread ? (parent->width()-tw)/(i-1) : 3;
00191 int x = spread ? (parent->width()-tw-xw*(i-1))/2 : 2;
00192
00193 i=0;
00194 for (; !(s=text(r,i)).isNull(); ++i) {
00195 int x2 = x + fm.width(s)+xw;
00196 if ( xpos >= x && xpos < x2 ) {
00197 pick(press, r, i);
00198 return;
00199 }
00200 x = x2;
00201 }
00202 }
00203
00204 void StringConfig::updateItem(int r, int item)
00205 {
00206 QFontMetrics fm = parent->fontMetrics();
00207
00208 int y = r * fm.lineSpacing();
00209
00210 int tw=0;
00211 QString s;
00212 int i=0;
00213 for (; !(s=text(r,i)).isNull(); ++i) {
00214 int w = fm.width(s);
00215 tw += w;
00216 }
00217 bool spread = spreadRow(r) && parent->width() > tw;
00218 int xw = spread ? (parent->width()-tw)/(i-1) : 3;
00219 int x = spread ? (parent->width()-tw-xw*(i-1))/2 : 2;
00220
00221 i=0;
00222 for (; !(s=text(r,i)).isNull(); ++i) {
00223 int w = fm.width(s)+xw;
00224 if ( i == item ) {
00225 parent->update(QRect(x-xw/2,y+1+fm.descent(),w,fm.lineSpacing()));
00226 return;
00227 }
00228 x += w;
00229 }
00230 }
00231
00232 bool StringConfig::highlight(int,int) const
00233 {
00234 return FALSE;
00235 }
00236
00237 LetterButton::LetterButton(const QChar& letter, QWidget* parent) :
00238 QPushButton(letter,parent)
00239 {
00240 setToggleButton(TRUE);
00241 setAutoDefault(FALSE);
00242 connect(this,SIGNAL(clicked()),this,SLOT(toggleCase()));
00243 skip=TRUE;
00244 }
00245
00246 void LetterButton::toggleCase()
00247 {
00248 if ( skip ) {
00249
00250 skip=FALSE;
00251 return;
00252 }
00253
00254 QChar ch = text()[0];
00255 QChar nch = ch.lower();
00256 if ( ch == nch )
00257 nch = ch.upper();
00258 setText(nch);
00259 }
00260
00261 LetterChoice::LetterChoice(QWidget* parent, const QString& set) :
00262 QButtonGroup(parent)
00263 {
00264 QHBoxLayout *l = new QHBoxLayout(this);
00265 setFrameStyle(0);
00266 setExclusive(TRUE);
00267 for (int i=0; i<(int)set.length(); i++) {
00268 LetterButton* b = new LetterButton(set[i],this);
00269 l->addWidget(b,1,AlignCenter);
00270 connect(b,SIGNAL(clicked()),this,SLOT(change()));
00271 }
00272 }
00273
00274 void LetterChoice::change()
00275 {
00276 LetterButton* b = (LetterButton*)sender();
00277 ch = b->text()[0];
00278 emit changed();
00279 }
00280
00281
00282 PickboardAdd::PickboardAdd(QWidget* owner, const QStringList& setlist) :
00283 QDialog( owner, 0, TRUE )
00284 {
00285 QVBoxLayout* l = new QVBoxLayout(this);
00286 l->setAutoAdd(TRUE);
00287
00288 QScrollView *sv = new QScrollView(this);
00289 sv->setResizePolicy(QScrollView::AutoOneFit);
00290 setMaximumHeight(200);
00291 QVBox *letters = new QVBox(sv);
00292 letters->setSpacing(0);
00293 lc = new LetterChoice*[setlist.count()];
00294 nlc = (int)setlist.count();
00295 for (int i=0; i<nlc; i++) {
00296 lc[i] = new LetterChoice(letters,setlist[i]);
00297 connect(lc[i],SIGNAL(changed()),this,SLOT(checkAllDone()));
00298 }
00299 sv->addChild(letters);
00300 QHBox* hb = new QHBox(this);
00301 hb->setSpacing(0);
00302 yes = new QPushButton(tr("OK"),hb);
00303 yes->setEnabled(FALSE);
00304 QPushButton *no = new QPushButton(tr("Cancel"),hb);
00305 connect(yes, SIGNAL(clicked()), this, SLOT(accept()));
00306 connect(no, SIGNAL(clicked()), this, SLOT(reject()));
00307 }
00308
00309 PickboardAdd::~PickboardAdd()
00310 {
00311 delete [] lc;
00312 }
00313
00314 QString PickboardAdd::word() const
00315 {
00316 QString str;
00317 for (int i=0; i<nlc; i++) {
00318 str += lc[i]->choice();
00319 }
00320 return str;
00321 }
00322
00323 bool PickboardAdd::exec()
00324 {
00325 QPoint pos = parentWidget()->mapToGlobal(QPoint(0,0));
00326 pos.ry() -= height();
00327 if ( QDialog::exec() ) {
00328 Global::addWords(QStringList(word()));
00329 return TRUE;
00330 } else {
00331 return FALSE;
00332 }
00333 }
00334
00335 void PickboardAdd::checkAllDone()
00336 {
00337 if ( !yes->isEnabled() ) {
00338 for (int i=0; i<nlc; i++) {
00339 if ( lc[i]->choice().isNull() )
00340 return;
00341 }
00342 yes->setEnabled(TRUE);
00343 }
00344 }
00345
00346
00347 void DictFilterConfig::doMenu(int i)
00348 {
00349 switch (i) {
00350 case 300:
00351 if ( input.count() == 0 ) {
00352 QMessageBox::information(0, tr("Adding Words"),
00353 tr("To add words, pick the letters,\nthen "
00354 "open the Add dialog. In that\ndialog, tap "
00355 "the correct letters\nfrom the list "
00356 "(tap twice for\ncapitals)."));
00357 } else {
00358 PickboardAdd add(parent,capitalize(input));
00359 if ( add.exec() )
00360 generateText(add.word());
00361 input.clear();
00362 matches.clear();
00363 updateRows(0,0);
00364 }
00365 break;
00366 case 100:
00367 if ( !input.isEmpty() ) {
00368 input.clear();
00369 matches.clear();
00370 StringConfig::doMenu(i);
00371 updateRows(0,1);
00372 break;
00373 }
00374 default:
00375 StringConfig::doMenu(i);
00376 }
00377 shift = 0;
00378 lit0 = -1;
00379 }
00380
00381 QString DictFilterConfig::text(int r, int i)
00382 {
00383 QStringList l = r ? sets_a : input.isEmpty() ? othermodes : matches;
00384 return i < (int)l.count() ?
00385 (input.isEmpty() ? l[i] : capitalize(l[i]))
00386 : QString::null;
00387 }
00388
00389 bool DictFilterConfig::spreadRow(int r)
00390 {
00391 return r ? TRUE : input.isEmpty() ? TRUE : FALSE;
00392 }
00393
00394 QStringList DictFilterConfig::capitalize(const QStringList& l)
00395 {
00396 switch ( shift ) {
00397 case 1: {
00398 QStringList r;
00399 QStringList::ConstIterator it = l.begin();
00400 r.append((*it).upper());
00401 for (++it; it != l.end(); ++it)
00402 r.append(*it);
00403 return r;
00404 } case 2: {
00405 QStringList r;
00406 for (QStringList::ConstIterator it = l.begin(); it != l.end(); ++it)
00407 r.append((*it).upper());
00408 return r;
00409 }
00410 }
00411 return l;
00412 }
00413
00414 QString DictFilterConfig::capitalize(const QString& s)
00415 {
00416 switch ( shift ) {
00417 case 1: {
00418 QString u = s;
00419 u[0] = u[0].upper();
00420 return u;
00421 break;
00422 } case 2:
00423 return s.upper();
00424 break;
00425 }
00426 return s;
00427 }
00428
00429 void DictFilterConfig::pick(bool press, int row, int item)
00430 {
00431 if ( row == 0 ) {
00432 if ( press ) {
00433 if ( input.isEmpty() ) {
00434 lit0 = item;
00435 if ( othermodes[item] == PickboardPicks::tr("Space") ) {
00436 updateItem(row,item);
00437 generateText(" ");
00438 } else if ( othermodes[item] == PickboardPicks::tr("Back") ) {
00439 updateItem(row,item);
00440 generateKey(::Qt::Key_Backspace);
00441 } else if ( othermodes[item] == PickboardPicks::tr("Enter") ) {
00442 updateItem(row,item);
00443 generateKey(::Qt::Key_Return);
00444 } else if ( othermodes[item] == PickboardPicks::tr("Shift") ) {
00445 updateItem(row,item);
00446 shift = (shift+1)%3;
00447 }
00448 }
00449 } else {
00450 if ( !input.isEmpty() ) {
00451 input.clear();
00452 if ( item>=0 ) {
00453 generateText(capitalize(matches[item]));
00454 }
00455 shift = 0;
00456 matches.clear();
00457 updateRows(0,0);
00458 } else if ( item < 3 ) {
00459 lit0 = -1;
00460 changeMode(item+1);
00461 updateRows(0,1);
00462 }
00463 if ( lit0 >= 0 ) {
00464 if ( !shift || othermodes[lit0] != PickboardPicks::tr("Shift") ) {
00465 updateItem(0,lit0);
00466 lit0 = -1;
00467 }
00468 }
00469 }
00470 } else {
00471 lit0 = -1;
00472 if ( press && item >= 0 ) {
00473 lit1 = item;
00474 add(sets[item]);
00475 updateItem(1,item);
00476 updateRows(0,0);
00477 } else {
00478 updateItem(1,lit1);
00479 lit1 = -1;
00480 }
00481 }
00482 }
00483
00484 bool DictFilterConfig::scanMatch(const QString& set, const QChar& l) const
00485 {
00486 return set == "?" || set == "*" || set.contains(l);
00487 }
00488
00489
00490
00491
00492 void DictFilterConfig::scan(const QDawg::Node* n, int ipos, const QString& str, int length, bool extend)
00493 {
00494 if ( n ) {
00495 do {
00496
00497 bool pastend = ipos >= (int)input.count();
00498 if ( pastend && extend || !pastend && scanMatch(input[ipos],n->letter().lower()) ) {
00499 if ( length>1 ) {
00500 if ( !pastend && input[ipos] == "*" ) {
00501 scan(n->jump(),ipos+1,str+n->letter(),length-1,FALSE);
00502 scan(n->jump(),ipos,str+n->letter(),length,FALSE);
00503 } else {
00504 scan(n->jump(),ipos+1,str+n->letter(),length-1,extend);
00505 }
00506 } else {
00507 if ( n->isWord() ) {
00508 matches.append(str+n->letter());
00509 }
00510 }
00511 }
00512 n = n->next();
00513 } while (n);
00514 }
00515 }
00516
00517 void DictFilterConfig::scanLengths(const QDawg::Node* n, int ipos, int& length_bitarray)
00518 {
00519 if ( n ) {
00520 do {
00521
00522 bool pastend = ipos >= (int)input.count();
00523 if ( pastend || scanMatch(input[ipos],n->letter().lower()) ) {
00524 scanLengths(n->jump(),ipos+1,length_bitarray);
00525 if ( n->isWord() )
00526 length_bitarray |= (1<<(ipos+1));
00527 }
00528 n = n->next();
00529 } while (n);
00530 }
00531 }
00532
00533 void DictFilterConfig::add(const QString& set)
00534 {
00535 QFontMetrics fm = parent->fontMetrics();
00536 input.append(set.lower());
00537 matches.clear();
00538
00539
00540 int length_bitarray = 0;
00541 if ( input.count() > 4 ) {
00542 scanLengths(Global::addedDawg().root(),0,length_bitarray);
00543 scanLengths(Global::fixedDawg().root(),0,length_bitarray);
00544 } else {
00545 length_bitarray = 0xffffffff;
00546 }
00547 for (int len=input.count(); len<22 ; ++len) {
00548 if ( length_bitarray & (1<<len) ) {
00549 scan(Global::addedDawg().root(),0,"",len,TRUE);
00550 scan(Global::fixedDawg().root(),0,"",len,TRUE);
00551 int x = 2;
00552 for (QStringList::Iterator it=matches.begin(); it!=matches.end(); ++it) {
00553 x += fm.width(*it)+intermatchmargin;
00554 if ( x >= parent->width() ) {
00555
00556 return;
00557 }
00558 }
00559 }
00560 if ( len == 1 && input.count() == 1 ) {
00561
00562 for ( int i=0; i<(int)set.length(); i++ ) {
00563 QChar ch = set[i].lower();
00564 matches.append(ch);
00565 }
00566 }
00567 }
00568
00569 }
00570
00571 bool DictFilterConfig::highlight(int r,int c) const
00572 {
00573 return r == 0 ? c == lit0 : c == lit1;
00574 }
00575
00576
00577 void DictFilterConfig::addSet(const QString& appearance, const QString& set)
00578 {
00579 sets_a.append( appearance );
00580 sets.append( set );
00581 }
00582
00583 void DictFilterConfig::addMode(const QString& s)
00584 {
00585 othermodes.append(s);
00586 }
00587
00588 void DictFilterConfig::fillMenu(QPopupMenu& menu)
00589 {
00590 menu.insertItem(tr("Add..."),300);
00591 StringConfig::fillMenu(menu);
00592 }
00593
00594 QValueList<QPixmap> KeycodeConfig::row(int i)
00595 {
00596 return i ? keypm2 : keypm1;
00597 }
00598
00599 void KeycodeConfig::pickInRow(int r, int xpos, bool press)
00600 {
00601 QValueList<QPixmap> pl = row(r);
00602 QValueList<QPixmap>::Iterator it;
00603 int item=0;
00604 int x=xmarg;
00605 for (it=pl.begin(); it!=pl.end(); ++it) {
00606 int x2 = x + (*it).width();
00607 if ( (*it).height() > 1 )
00608 x2 += xw;
00609 if ( xpos >= x && xpos < x2 ) {
00610 pick(press, r, item);
00611 return;
00612 }
00613 x = x2;
00614 item++;
00615 }
00616 }
00617
00618 void KeycodeConfig::pick(bool press, int row, int item)
00619 {
00620 if ( !press ) {
00621 if ( item >= 0 ) {
00622 int k = row == 0 ? keys1[item] : keys2[item];
00623 if ( k )
00624 generateKey(k);
00625 }
00626 changeMode(0);
00627 updateRows(0,1);
00628 }
00629 }
00630
00631 void KeycodeConfig::draw(QPainter* p)
00632 {
00633 int y=3;
00634 QValueList<QPixmap>::Iterator it;
00635 for (int r=0; r<nrows; r++) {
00636 QValueList<QPixmap> pl = row(r);
00637 int x = xmarg;
00638 for (it=pl.begin(); it!=pl.end(); ++it) {
00639 if ( (*it).height() == 1 ) {
00640
00641 x += (*it).width();
00642 } else {
00643 p->drawPixmap(x,y,*it);
00644 x += (*it).width()+xw;
00645 }
00646 }
00647 y += parent->height()/nrows;
00648 }
00649 }
00650
00651
00652 void KeycodeConfig::addKey(int r, const QPixmap& pm, int code)
00653 {
00654 if ( r == 0 ) {
00655 keypm1.append(pm);
00656 keys1.append(code);
00657 } else {
00658 keypm2.append(pm);
00659 keys2.append(code);
00660 }
00661 }
00662 void KeycodeConfig::addGap(int r, int w)
00663 {
00664 QBitmap pm(w,1);
00665 addKey(r,pm,0);
00666 }
00667
00668 QString CharConfig::text(int r, int i)
00669 {
00670 QStringList l = r ? chars2 : chars1;
00671 return i < (int)l.count() ? l[i] : QString::null;
00672 }
00673 bool CharConfig::spreadRow(int)
00674 {
00675 return TRUE;
00676 }
00677
00678 void CharConfig::pick(bool press, int row, int item)
00679 {
00680 if ( !press ) {
00681 if ( item >= 0 ) {
00682 generateText(row == 0 ? chars1[item] : chars2[item]);
00683 }
00684 changeMode(0);
00685 updateRows(0,1);
00686 }
00687 }
00688
00689 void CharConfig::addChar(int r, const QString& s)
00690 {
00691 if ( r ) chars2.append(s); else chars1.append(s);
00692 }
00693
00694 QString CharStringConfig::text(int r, int i)
00695 {
00696 QStringList l = r ? chars : QStringList(input);
00697 return i < (int)l.count() ? l[i] : QString::null;
00698 }
00699
00700 bool CharStringConfig::spreadRow(int i)
00701 {
00702 return i ? TRUE : FALSE;
00703 }
00704
00705 void CharStringConfig::pick(bool press, int row, int item)
00706 {
00707 if ( row == 0 ) {
00708 if ( !press ) {
00709 if ( item>=0 ) {
00710 generateText(input);
00711 }
00712 input = "";
00713 changeMode(0);
00714 updateRows(0,1);
00715 }
00716 } else {
00717 if ( press && item >= 0 ) {
00718 input.append(chars[item]);
00719 updateRows(0,0);
00720 }
00721 }
00722 }
00723
00724 void CharStringConfig::addChar(const QString& s)
00725 {
00726 chars.append(s);
00727 }
00728
00729 void CharStringConfig::doMenu(int i)
00730 {
00731 if ( i == 100 ) {
00732 input = "";
00733 updateRows(0,0);
00734 }
00735
00736 StringConfig::doMenu(i);
00737 }
00738