00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021 #include <opie2/opopupmenu.h>
00022 #include <opie2/oconfig.h>
00023 #include <opie2/odebug.h>
00024
00025
00026 #include <qdrawutil.h>
00027 #include <qtimer.h>
00028
00029
00030 using namespace Opie::Core;
00031 using namespace Opie::Ui;
00032
00033 OPopupTitle::OPopupTitle(QWidget *parent, const char *name)
00034 : QWidget(parent, name)
00035 {
00036 setMinimumSize(16, fontMetrics().height()+8);
00037 }
00038
00039 OPopupTitle::OPopupTitle(OPixmapEffect::GradientType ,
00040 const QColor &, const QColor &,
00041 QWidget *parent, const char *name)
00042 : QWidget(parent, name)
00043 {
00044 setMinimumSize(16, fontMetrics().height()+8);
00045 }
00046
00047 OPopupTitle::OPopupTitle(const OPixmap & , const QColor &,
00048 const QColor &, QWidget *parent,
00049 const char *name)
00050 : QWidget(parent, name)
00051 {
00052 setMinimumSize(16, fontMetrics().height()+8);
00053 }
00054
00055 void OPopupTitle::setTitle(const QString &text, const QPixmap *icon)
00056 {
00057 titleStr = text;
00058 if (icon)
00059 miniicon = *icon;
00060 else
00061 miniicon.resize(0, 0);
00062
00063 int w = miniicon.width()+fontMetrics().width(titleStr);
00064 int h = QMAX( fontMetrics().height(), miniicon.height() );
00065 setMinimumSize( w+16, h+8 );
00066 }
00067
00068 void OPopupTitle::setText( const QString &text )
00069 {
00070 titleStr = text;
00071 int w = miniicon.width()+fontMetrics().width(titleStr);
00072 int h = QMAX( fontMetrics().height(), miniicon.height() );
00073 setMinimumSize( w+16, h+8 );
00074 }
00075
00076 void OPopupTitle::setIcon( const QPixmap &pix )
00077 {
00078 miniicon = pix;
00079 int w = miniicon.width()+fontMetrics().width(titleStr);
00080 int h = QMAX( fontMetrics().height(), miniicon.height() );
00081 setMinimumSize( w+16, h+8 );
00082 }
00083
00084 void OPopupTitle::paintEvent(QPaintEvent *)
00085 {
00086 QRect r(rect());
00087 QPainter p(this);
00088 #if QT_VERSION >= 0x030000
00089 qApp->style().drawPrimitive(QStyle::PE_HeaderSection, &p, r, palette().active());
00090 #else
00091 #warning OPopupMenu is not fully functional on Qt2
00092 #endif
00093
00094 if (!miniicon.isNull())
00095 p.drawPixmap(4, (r.height()-miniicon.height())/2, miniicon);
00096
00097 if (!titleStr.isNull())
00098 {
00099 p.setPen(palette().active().text());
00100 QFont f = p.font();
00101 f.setBold(true);
00102 p.setFont(f);
00103 if(!miniicon.isNull())
00104 {
00105 p.drawText(miniicon.width()+8, 0, width()-(miniicon.width()+8),
00106 height(), AlignLeft | AlignVCenter | SingleLine,
00107 titleStr);
00108 }
00109 else
00110 {
00111 p.drawText(0, 0, width(), height(),
00112 AlignCenter | SingleLine, titleStr);
00113 }
00114 }
00115
00116 p.setPen(palette().active().highlight());
00117 p.drawLine(0, 0, r.right(), 0);
00118 }
00119
00120 QSize OPopupTitle::sizeHint() const
00121 {
00122 return(minimumSize());
00123 }
00124
00125 class OPopupMenu::OPopupMenuPrivate
00126 {
00127 public:
00128 OPopupMenuPrivate ()
00129 : noMatches(false)
00130 , shortcuts(false)
00131 , autoExec(false)
00132 , lastHitIndex(-1)
00133 , m_ctxMenu(0)
00134 {}
00135
00136 ~OPopupMenuPrivate ()
00137 {
00138 delete m_ctxMenu;
00139 }
00140
00141 QString m_lastTitle;
00142
00143
00144 QTimer clearTimer;
00145
00146 bool noMatches : 1;
00147 bool shortcuts : 1;
00148 bool autoExec : 1;
00149
00150 QString keySeq;
00151 QString originalText;
00152
00153 int lastHitIndex;
00154
00155
00156 QPopupMenu* m_ctxMenu;
00157 static bool s_continueCtxMenuShow;
00158 static int s_highlightedItem;
00159 static OPopupMenu* s_contextedMenu;
00160 };
00161
00162 int OPopupMenu::OPopupMenuPrivate::s_highlightedItem(-1);
00163 OPopupMenu* OPopupMenu::OPopupMenuPrivate::s_contextedMenu(0);
00164 bool OPopupMenu::OPopupMenuPrivate::s_continueCtxMenuShow(true);
00165
00166 OPopupMenu::OPopupMenu(QWidget *parent, const char *name)
00167 : QPopupMenu(parent, name)
00168 {
00169 d = new OPopupMenuPrivate;
00170 resetKeyboardVars();
00171 connect(&(d->clearTimer), SIGNAL(timeout()), SLOT(resetKeyboardVars()));
00172 }
00173
00174 OPopupMenu::~OPopupMenu()
00175 {
00176 if (OPopupMenuPrivate::s_contextedMenu == this)
00177 {
00178 OPopupMenuPrivate::s_contextedMenu = 0;
00179 OPopupMenuPrivate::s_highlightedItem = -1;
00180 }
00181
00182 delete d;
00183 }
00184
00185 int OPopupMenu::insertTitle(const QString &text, int id, int index)
00186 {
00187 OPopupTitle *titleItem = new OPopupTitle();
00188 titleItem->setTitle(text);
00189 int ret = insertItem(titleItem, id, index);
00190 setItemEnabled(id, false);
00191 return ret;
00192 }
00193
00194 int OPopupMenu::insertTitle(const QPixmap &icon, const QString &text, int id,
00195 int index)
00196 {
00197 OPopupTitle *titleItem = new OPopupTitle();
00198 titleItem->setTitle(text, &icon);
00199 int ret = insertItem(titleItem, id, index);
00200 setItemEnabled(id, false);
00201 return ret;
00202 }
00203
00204 void OPopupMenu::changeTitle(int id, const QString &text)
00205 {
00206 QMenuItem *item = findItem(id);
00207 if(item){
00208 if(item->widget())
00209 ((OPopupTitle *)item->widget())->setTitle(text);
00210 #ifndef NDEBUG
00211 else
00212 owarn << "KPopupMenu: changeTitle() called with non-title id " << id << "" << oendl;
00213 #endif
00214 }
00215 #ifndef NDEBUG
00216 else
00217 owarn << "KPopupMenu: changeTitle() called with invalid id " << id << "" << oendl;
00218 #endif
00219 }
00220
00221 void OPopupMenu::changeTitle(int id, const QPixmap &icon, const QString &text)
00222 {
00223 QMenuItem *item = findItem(id);
00224 if(item){
00225 if(item->widget())
00226 ((OPopupTitle *)item->widget())->setTitle(text, &icon);
00227 #ifndef NDEBUG
00228 else
00229 owarn << "KPopupMenu: changeTitle() called with non-title id " << id << "" << oendl;
00230 #endif
00231 }
00232 #ifndef NDEBUG
00233 else
00234 owarn << "KPopupMenu: changeTitle() called with invalid id " << id << "" << oendl;
00235 #endif
00236 }
00237
00238 QString OPopupMenu::title(int id) const
00239 {
00240 if(id == -1)
00241 return(d->m_lastTitle);
00242 QMenuItem *item = findItem(id);
00243 if(item){
00244 if(item->widget())
00245 return(((OPopupTitle *)item->widget())->title());
00246 else
00247 owarn << "OPopupMenu: title() called with non-title id " << id << "." << oendl;
00248 }
00249 else
00250 owarn << "OPopupMenu: title() called with invalid id " << id << "." << oendl;
00251 return(QString::null);
00252 }
00253
00254 QPixmap OPopupMenu::titlePixmap(int id) const
00255 {
00256 QMenuItem *item = findItem(id);
00257 if(item){
00258 if(item->widget())
00259 return(((OPopupTitle *)item->widget())->icon());
00260 else
00261 owarn << "KPopupMenu: titlePixmap() called with non-title id " << id << "." << oendl;
00262 }
00263 else
00264 owarn << "KPopupMenu: titlePixmap() called with invalid id " << id << "." << oendl;
00265 QPixmap tmp;
00266 return(tmp);
00267 }
00268
00272 void OPopupMenu::closeEvent(QCloseEvent*e)
00273 {
00274 if (d->shortcuts)
00275 resetKeyboardVars();
00276 QPopupMenu::closeEvent(e);
00277 }
00278
00279 void OPopupMenu::keyPressEvent(QKeyEvent* e)
00280 {
00281 if (!d->shortcuts) {
00282
00283
00284 QPopupMenu::keyPressEvent(e);
00285 return;
00286 }
00287
00288 int i = 0;
00289 bool firstpass = true;
00290 QString keyString = e->text();
00291
00292
00293 int key = e->key();
00294 if (key == Key_Escape || key == Key_Return || key == Key_Enter
00295 || key == Key_Up || key == Key_Down || key == Key_Left
00296 || key == Key_Right || key == Key_F1) {
00297
00298 resetKeyboardVars();
00299
00300
00301 QPopupMenu::keyPressEvent(e);
00302 return;
00303 }
00304
00305
00306
00307 if (!d->keySeq.isNull()) {
00308
00309 if (key == Key_Backspace) {
00310
00311 if (d->keySeq.length() == 1) {
00312 resetKeyboardVars();
00313 return;
00314 }
00315
00316
00317 keyString = d->keySeq.left(d->keySeq.length() - 1);
00318
00319
00320 resetKeyboardVars();
00321
00322 } else if (key == Key_Delete) {
00323 resetKeyboardVars();
00324
00325
00326 setActiveItem(0);
00327 return;
00328
00329 } else if (d->noMatches) {
00330
00331 resetKeyboardVars();
00332
00333
00334 setActiveItem(0);
00335
00336 } else {
00337
00338
00339 i = d->lastHitIndex;
00340 }
00341 } else if (key == Key_Backspace && parentMenu) {
00342
00343 hide();
00344 resetKeyboardVars();
00345 return;
00346 }
00347
00348 d->keySeq += keyString;
00349 int seqLen = d->keySeq.length();
00350
00351 for (; i < (int)count(); i++) {
00352
00353 int j = idAt(i);
00354
00355
00356 if (!isItemEnabled(j))
00357 continue;
00358
00359 QString thisText;
00360
00361
00362
00363 if (i == d->lastHitIndex)
00364 thisText = d->originalText;
00365 else
00366 thisText = text(j);
00367
00368
00369 if ((int)accel(j) != 0)
00370 thisText = thisText.replace(QRegExp("&"), "");
00371
00372
00373 thisText = thisText.left(seqLen);
00374
00375
00376 if (thisText.find(d->keySeq, 0, false) == 0) {
00377
00378 if (firstpass) {
00379
00380 setActiveItem(i);
00381
00382
00383 if (d->lastHitIndex != i)
00384
00385 changeItem(idAt(d->lastHitIndex), d->originalText);
00386
00387
00388 if (d->lastHitIndex != i || d->lastHitIndex == -1)
00389 d->originalText = text(j);
00390
00391
00392 changeItem(j, underlineText(d->originalText, d->keySeq.length()));
00393
00394
00395 d->lastHitIndex = i;
00396
00397
00398 d->clearTimer.start(5000, true);
00399
00400
00401 firstpass = false;
00402 } else {
00403
00404 return;
00405 }
00406 }
00407
00408
00409 }
00410
00411 if (!firstpass) {
00412 if (d->autoExec) {
00413
00414 activateItemAt(d->lastHitIndex);
00415 resetKeyboardVars();
00416
00417 } else if (findItem(idAt(d->lastHitIndex)) &&
00418 findItem(idAt(d->lastHitIndex))->popup()) {
00419
00420 activateItemAt(d->lastHitIndex);
00421 resetKeyboardVars();
00422 }
00423
00424 return;
00425 }
00426
00427
00428 resetKeyboardVars(true);
00429
00430 QPopupMenu::keyPressEvent(e);
00431 }
00432
00433 QString OPopupMenu::underlineText(const QString& text, uint length)
00434 {
00435 QString ret = text;
00436 for (uint i = 0; i < length; i++) {
00437 if (ret[2*i] != '&')
00438 ret.insert(2*i, "&");
00439 }
00440 return ret;
00441 }
00442
00443 void OPopupMenu::resetKeyboardVars(bool noMatches )
00444 {
00445
00446 if (d->lastHitIndex != -1) {
00447 changeItem(idAt(d->lastHitIndex), d->originalText);
00448 d->lastHitIndex = -1;
00449 }
00450
00451 if (!noMatches) {
00452 d->keySeq = QString::null;
00453 }
00454
00455 d->noMatches = noMatches;
00456 }
00457
00458 void OPopupMenu::setKeyboardShortcutsEnabled(bool enable)
00459 {
00460 d->shortcuts = enable;
00461 }
00462
00463 void OPopupMenu::setKeyboardShortcutsExecute(bool enable)
00464 {
00465 d->autoExec = enable;
00466 }
00474 QPopupMenu* OPopupMenu::contextMenu()
00475 {
00476 if (!d->m_ctxMenu)
00477 {
00478 d->m_ctxMenu = new QPopupMenu(this);
00479 installEventFilter(this);
00480 connect(d->m_ctxMenu, SIGNAL(aboutToHide()), this, SLOT(ctxMenuHiding()));
00481 }
00482
00483 return d->m_ctxMenu;
00484 }
00485
00486 void OPopupMenu::cancelContextMenuShow()
00487 {
00488 OPopupMenuPrivate::s_continueCtxMenuShow = false;
00489 }
00490
00491 int OPopupMenu::contextMenuFocusItem()
00492 {
00493 return OPopupMenuPrivate::s_highlightedItem;
00494 }
00495
00496 OPopupMenu* OPopupMenu::contextMenuFocus()
00497 {
00498 return OPopupMenuPrivate::s_contextedMenu;
00499 }
00500
00501 void OPopupMenu::itemHighlighted(int )
00502 {
00503 if (!d->m_ctxMenu || !d->m_ctxMenu->isVisible())
00504 {
00505 return;
00506 }
00507
00508 d->m_ctxMenu->hide();
00509 showCtxMenu(mapFromGlobal(QCursor::pos()));
00510 }
00511
00512 void OPopupMenu::showCtxMenu(QPoint pos)
00513 {
00514 OPopupMenuPrivate::s_highlightedItem = idAt(pos);
00515
00516 if (OPopupMenuPrivate::s_highlightedItem == -1)
00517 {
00518 OPopupMenuPrivate::s_contextedMenu = 0;
00519 return;
00520 }
00521
00522 emit aboutToShowContextMenu(this, OPopupMenuPrivate::s_highlightedItem, d->m_ctxMenu);
00523
00524 if (!OPopupMenuPrivate::s_continueCtxMenuShow)
00525 {
00526 OPopupMenuPrivate::s_continueCtxMenuShow = true;
00527 return;
00528 }
00529
00530 OPopupMenuPrivate::s_contextedMenu = this;
00531 d->m_ctxMenu->popup(this->mapToGlobal(pos));
00532 connect(this, SIGNAL(highlighted(int)), this, SLOT(itemHighlighted(int)));
00533 }
00534
00535 void OPopupMenu::ctxMenuHiding()
00536 {
00537 disconnect(this, SIGNAL(highlighted(int)), this, SLOT(itemHighlighted(int)));
00538 OPopupMenuPrivate::s_continueCtxMenuShow = true;
00539 }
00540
00541 bool OPopupMenu::eventFilter(QObject* obj, QEvent* event)
00542 {
00543 if (d->m_ctxMenu && obj == this)
00544 {
00545 if (event->type() == QEvent::MouseButtonRelease)
00546 {
00547 if (d->m_ctxMenu->isVisible())
00548 {
00549 return true;
00550 }
00551 }
00552 #if QT_VERSION >= 0x030000
00553 else if (event->type() == QEvent::ContextMenu)
00554 #else
00555 else if ( (event->type() == QEvent::MouseButtonPress) &&
00556 ( (QMouseEvent*) event )->button() == QMouseEvent::RightButton )
00557 #endif
00558 {
00559 showCtxMenu(mapFromGlobal(QCursor::pos()));
00560 return true;
00561 }
00562 }
00563
00564 return QWidget::eventFilter(obj, event);
00565 }
00566
00567 void OPopupMenu::hideEvent(QHideEvent*)
00568 {
00569 if (d->m_ctxMenu)
00570 {
00571 d->m_ctxMenu->hide();
00572 }
00573 }
00578
00579 OPopupMenu::OPopupMenu(const QString& title, QWidget *parent, const char *name)
00580 : QPopupMenu(parent, name)
00581 {
00582 d = new OPopupMenuPrivate;
00583 setTitle(title);
00584 }
00585
00586
00587 void OPopupMenu::setTitle(const QString &title)
00588 {
00589 OPopupTitle *titleItem = new OPopupTitle();
00590 titleItem->setTitle(title);
00591 insertItem(titleItem);
00592 d->m_lastTitle = title;
00593 }
00594
00595 void OPopupTitle::virtual_hook( int, void* )
00596 { }
00597
00598 void OPopupMenu::virtual_hook( int, void* )
00599 { }
00600