00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019 #include <tqcursor.h>
00020 #include <tqpainter.h>
00021 #include <tqtimer.h>
00022 #include <tqfontmetrics.h>
00023
00024 #ifdef USE_QT4
00025 #undef None
00026 #endif // USE_QT4
00027
00028 #include <tqstyle.h>
00029
00030 #include "tdepopupmenu.h"
00031
00032 #include <kdebug.h>
00033 #include <tdeapplication.h>
00034
00035 TDEPopupTitle::TDEPopupTitle(TQWidget *parent, const char *name)
00036 : TQWidget(parent, name)
00037 {
00038 setMinimumSize(16, fontMetrics().height()+8);
00039 }
00040
00041 TDEPopupTitle::TDEPopupTitle(KPixmapEffect::GradientType ,
00042 const TQColor &, const TQColor &,
00043 TQWidget *parent, const char *name)
00044 : TQWidget(parent, name)
00045 {
00046 calcSize();
00047 }
00048
00049 TDEPopupTitle::TDEPopupTitle(const KPixmap & , const TQColor &,
00050 const TQColor &, TQWidget *parent,
00051 const char *name)
00052 : TQWidget(parent, name)
00053 {
00054 calcSize();
00055 }
00056
00057 void TDEPopupTitle::setTitle(const TQString &text, const TQPixmap *icon)
00058 {
00059 titleStr = text;
00060 if (icon)
00061 miniicon = *icon;
00062 else
00063 miniicon.resize(0, 0);
00064
00065 calcSize();
00066 }
00067
00068 void TDEPopupTitle::setText( const TQString &text )
00069 {
00070 titleStr = text;
00071 calcSize();
00072 }
00073
00074 void TDEPopupTitle::setIcon( const TQPixmap &pix )
00075 {
00076 miniicon = pix;
00077 calcSize();
00078 }
00079
00080 void TDEPopupTitle::calcSize()
00081 {
00082 TQFont f = font();
00083 f.setBold(true);
00084 int w = miniicon.width()+TQFontMetrics(f).width(titleStr);
00085 int h = TQMAX( fontMetrics().height(), miniicon.height() );
00086 setMinimumSize( w+16, h+8 );
00087 }
00088
00089 void TDEPopupTitle::paintEvent(TQPaintEvent *)
00090 {
00091 TQRect r(rect());
00092 TQPainter p(this);
00093 kapp->style().tqdrawPrimitive(TQStyle::PE_HeaderSectionMenu, &p, r, palette().active());
00094
00095 if (!miniicon.isNull())
00096 p.drawPixmap(4, (r.height()-miniicon.height())/2, miniicon);
00097
00098 if (!titleStr.isNull())
00099 {
00100 p.setPen(palette().active().text());
00101 TQFont f = p.font();
00102 f.setBold(true);
00103 p.setFont(f);
00104 if(!miniicon.isNull())
00105 {
00106 p.drawText(miniicon.width()+8, 0, width()-(miniicon.width()+8),
00107 height(), AlignLeft | AlignVCenter | SingleLine,
00108 titleStr);
00109 }
00110 else
00111 {
00112 p.drawText(0, 0, width(), height(),
00113 AlignCenter | SingleLine, titleStr);
00114 }
00115 }
00116 }
00117
00118 TQSize TDEPopupTitle::sizeHint() const
00119 {
00120 return minimumSize();
00121 }
00122
00123 class TDEPopupMenu::TDEPopupMenuPrivate
00124 {
00125 public:
00126 TDEPopupMenuPrivate ()
00127 : noMatches(false)
00128 , shortcuts(false)
00129 , autoExec(false)
00130 , lastHitIndex(-1)
00131 , state(Qt::NoButton)
00132 , m_ctxMenu(0)
00133 {}
00134
00135 ~TDEPopupMenuPrivate ()
00136 {
00137 delete m_ctxMenu;
00138 }
00139
00140 TQString m_lastTitle;
00141
00142
00143 TQTimer clearTimer;
00144
00145 bool noMatches : 1;
00146 bool shortcuts : 1;
00147 bool autoExec : 1;
00148
00149 TQString keySeq;
00150 TQString originalText;
00151
00152 int lastHitIndex;
00153 TQt::ButtonState state;
00154
00155
00156 TQPopupMenu* m_ctxMenu;
00157 static bool s_continueCtxMenuShow;
00158 static int s_highlightedItem;
00159 static TDEPopupMenu* s_contextedMenu;
00160 };
00161
00162 int TDEPopupMenu::TDEPopupMenuPrivate::s_highlightedItem(-1);
00163 TDEPopupMenu* TDEPopupMenu::TDEPopupMenuPrivate::s_contextedMenu(0);
00164 bool TDEPopupMenu::TDEPopupMenuPrivate::s_continueCtxMenuShow(true);
00165
00166 TDEPopupMenu::TDEPopupMenu(TQWidget *parent, const char *name)
00167 : TQPopupMenu(parent, name)
00168 {
00169 d = new TDEPopupMenuPrivate;
00170 resetKeyboardVars();
00171 connect(&(d->clearTimer), TQT_SIGNAL(timeout()), TQT_SLOT(resetKeyboardVars()));
00172 }
00173
00174 TDEPopupMenu::~TDEPopupMenu()
00175 {
00176 if (TDEPopupMenuPrivate::s_contextedMenu == this)
00177 {
00178 TDEPopupMenuPrivate::s_contextedMenu = 0;
00179 TDEPopupMenuPrivate::s_highlightedItem = -1;
00180 }
00181
00182 delete d;
00183 }
00184
00185 int TDEPopupMenu::insertTitle(const TQString &text, int id, int index)
00186 {
00187 TDEPopupTitle *titleItem = new TDEPopupTitle();
00188 titleItem->setTitle(text);
00189 int ret = insertItem(titleItem, id, index);
00190 setItemEnabled(ret, false);
00191 return ret;
00192 }
00193
00194 int TDEPopupMenu::insertTitle(const TQPixmap &icon, const TQString &text, int id,
00195 int index)
00196 {
00197 TDEPopupTitle *titleItem = new TDEPopupTitle();
00198 titleItem->setTitle(text, &icon);
00199 int ret = insertItem(titleItem, id, index);
00200 setItemEnabled(ret, false);
00201 return ret;
00202 }
00203
00204 void TDEPopupMenu::changeTitle(int id, const TQString &text)
00205 {
00206 TQMenuItem *item = findItem(id);
00207 if(item){
00208 if(item->widget())
00209 ((TDEPopupTitle *)item->widget())->setTitle(text);
00210 #ifndef NDEBUG
00211 else
00212 kdWarning() << "TDEPopupMenu: changeTitle() called with non-title id "<< id << endl;
00213 #endif
00214 }
00215 #ifndef NDEBUG
00216 else
00217 kdWarning() << "TDEPopupMenu: changeTitle() called with invalid id " << id << endl;
00218 #endif
00219 }
00220
00221 void TDEPopupMenu::changeTitle(int id, const TQPixmap &icon, const TQString &text)
00222 {
00223 TQMenuItem *item = findItem(id);
00224 if(item){
00225 if(item->widget())
00226 ((TDEPopupTitle *)item->widget())->setTitle(text, &icon);
00227 #ifndef NDEBUG
00228 else
00229 kdWarning() << "TDEPopupMenu: changeTitle() called with non-title id "<< id << endl;
00230 #endif
00231 }
00232 #ifndef NDEBUG
00233 else
00234 kdWarning() << "TDEPopupMenu: changeTitle() called with invalid id " << id << endl;
00235 #endif
00236 }
00237
00238 TQString TDEPopupMenu::title(int id) const
00239 {
00240 if(id == -1)
00241 return d->m_lastTitle;
00242 TQMenuItem *item = findItem(id);
00243 if(item){
00244 if(item->widget())
00245 return ((TDEPopupTitle *)item->widget())->title();
00246 else
00247 tqWarning("TDEPopupMenu: title() called with non-title id %d.", id);
00248 }
00249 else
00250 tqWarning("TDEPopupMenu: title() called with invalid id %d.", id);
00251 return TQString::null;
00252 }
00253
00254 TQPixmap TDEPopupMenu::titlePixmap(int id) const
00255 {
00256 TQMenuItem *item = findItem(id);
00257 if(item){
00258 if(item->widget())
00259 return ((TDEPopupTitle *)item->widget())->icon();
00260 else
00261 tqWarning("TDEPopupMenu: titlePixmap() called with non-title id %d.", id);
00262 }
00263 else
00264 tqWarning("TDEPopupMenu: titlePixmap() called with invalid id %d.", id);
00265 TQPixmap tmp;
00266 return tmp;
00267 }
00268
00272 void TDEPopupMenu::closeEvent(TQCloseEvent*e)
00273 {
00274 if (d->shortcuts)
00275 resetKeyboardVars();
00276 TQPopupMenu::closeEvent(e);
00277 }
00278
00279 void TDEPopupMenu::activateItemAt(int index)
00280 {
00281 d->state = Qt::NoButton;
00282 TQPopupMenu::activateItemAt(index);
00283 }
00284
00285 TQt::ButtonState TDEPopupMenu::state() const
00286 {
00287 return d->state;
00288 }
00289
00290 void TDEPopupMenu::keyPressEvent(TQKeyEvent* e)
00291 {
00292 d->state = Qt::NoButton;
00293 if (!d->shortcuts) {
00294
00295
00296 d->state = e->state();
00297 TQPopupMenu::keyPressEvent(e);
00298 return;
00299 }
00300
00301 int i = 0;
00302 bool firstpass = true;
00303 TQString keyString = e->text();
00304
00305
00306 int key = e->key();
00307 if (key == Key_Escape || key == Key_Return || key == Key_Enter
00308 || key == Key_Up || key == Key_Down || key == Key_Left
00309 || key == Key_Right || key == Key_F1) {
00310
00311 resetKeyboardVars();
00312
00313
00314 d->state = e->state();
00315 TQPopupMenu::keyPressEvent(e);
00316 return;
00317 } else if ( key == Key_Shift || key == Key_Control || key == Key_Alt || key == Key_Meta )
00318 return TQPopupMenu::keyPressEvent(e);
00319
00320
00321
00322 if (!d->keySeq.isNull()) {
00323
00324 if (key == Key_Backspace) {
00325
00326 if (d->keySeq.length() == 1) {
00327 resetKeyboardVars();
00328 return;
00329 }
00330
00331
00332 keyString = d->keySeq.left(d->keySeq.length() - 1);
00333
00334
00335 resetKeyboardVars();
00336
00337 } else if (key == Key_Delete) {
00338 resetKeyboardVars();
00339
00340
00341 setActiveItem(0);
00342 return;
00343
00344 } else if (d->noMatches) {
00345
00346 resetKeyboardVars();
00347
00348
00349 setActiveItem(0);
00350
00351 } else {
00352
00353
00354 i = d->lastHitIndex;
00355 }
00356 } else if (key == Key_Backspace && parentMenu) {
00357
00358 hide();
00359 resetKeyboardVars();
00360 return;
00361 }
00362
00363 d->keySeq += keyString;
00364 int seqLen = d->keySeq.length();
00365
00366 for (; i < (int)count(); i++) {
00367
00368 int j = idAt(i);
00369
00370
00371 if (!isItemEnabled(j))
00372 continue;
00373
00374 TQString thisText;
00375
00376
00377
00378 if (i == d->lastHitIndex)
00379 thisText = d->originalText;
00380 else
00381 thisText = text(j);
00382
00383
00384 if ((int)accel(j) != 0)
00385 thisText = thisText.replace("&", TQString());
00386
00387
00388 thisText = thisText.left(seqLen);
00389
00390
00391 if (!thisText.find(d->keySeq, 0, false)) {
00392
00393 if (firstpass) {
00394
00395 setActiveItem(i);
00396
00397
00398 if (d->lastHitIndex != i)
00399
00400 changeItem(idAt(d->lastHitIndex), d->originalText);
00401
00402
00403 if (d->lastHitIndex != i || d->lastHitIndex == -1)
00404 d->originalText = text(j);
00405
00406
00407 changeItem(j, underlineText(d->originalText, d->keySeq.length()));
00408
00409
00410 d->lastHitIndex = i;
00411
00412
00413 d->clearTimer.start(5000, true);
00414
00415
00416 firstpass = false;
00417 } else {
00418
00419 return;
00420 }
00421 }
00422
00423
00424 }
00425
00426 if (!firstpass) {
00427 if (d->autoExec) {
00428
00429 activateItemAt(d->lastHitIndex);
00430 resetKeyboardVars();
00431
00432 } else if (findItem(idAt(d->lastHitIndex)) &&
00433 findItem(idAt(d->lastHitIndex))->popup()) {
00434
00435 activateItemAt(d->lastHitIndex);
00436 resetKeyboardVars();
00437 }
00438
00439 return;
00440 }
00441
00442
00443 resetKeyboardVars(true);
00444
00445 TQPopupMenu::keyPressEvent(e);
00446 }
00447
00448 bool TDEPopupMenu::focusNextPrevChild( bool next )
00449 {
00450 resetKeyboardVars();
00451 return TQPopupMenu::focusNextPrevChild( next );
00452 }
00453
00454 TQString TDEPopupMenu::underlineText(const TQString& text, uint length)
00455 {
00456 TQString ret = text;
00457 for (uint i = 0; i < length; i++) {
00458 if (ret[2*i] != '&')
00459 ret.insert(2*i, "&");
00460 }
00461 return ret;
00462 }
00463
00464 void TDEPopupMenu::resetKeyboardVars(bool noMatches )
00465 {
00466
00467 if (d->lastHitIndex != -1) {
00468 changeItem(idAt(d->lastHitIndex), d->originalText);
00469 d->lastHitIndex = -1;
00470 }
00471
00472 if (!noMatches) {
00473 d->keySeq = TQString::null;
00474 }
00475
00476 d->noMatches = noMatches;
00477 }
00478
00479 void TDEPopupMenu::setKeyboardShortcutsEnabled(bool enable)
00480 {
00481 d->shortcuts = enable;
00482 }
00483
00484 void TDEPopupMenu::setKeyboardShortcutsExecute(bool enable)
00485 {
00486 d->autoExec = enable;
00487 }
00496 void TDEPopupMenu::mousePressEvent(TQMouseEvent* e)
00497 {
00498 if (d->m_ctxMenu && d->m_ctxMenu->isVisible())
00499 {
00500
00501 d->m_ctxMenu->hide();
00502 }
00503
00504 TQPopupMenu::mousePressEvent(e);
00505 }
00506
00507 void TDEPopupMenu::mouseReleaseEvent(TQMouseEvent* e)
00508 {
00509
00510 d->state = TQt::ButtonState(e->button() | (e->state() & KeyButtonMask));
00511
00512 if ( !d->m_ctxMenu || !d->m_ctxMenu->isVisible() )
00513 TQPopupMenu::mouseReleaseEvent(e);
00514 }
00515
00516 TQPopupMenu* TDEPopupMenu::contextMenu()
00517 {
00518 if (!d->m_ctxMenu)
00519 {
00520 d->m_ctxMenu = new TQPopupMenu(this);
00521 connect(d->m_ctxMenu, TQT_SIGNAL(aboutToHide()), this, TQT_SLOT(ctxMenuHiding()));
00522 }
00523
00524 return d->m_ctxMenu;
00525 }
00526
00527 const TQPopupMenu* TDEPopupMenu::contextMenu() const
00528 {
00529 return const_cast< TDEPopupMenu* >( this )->contextMenu();
00530 }
00531
00532 void TDEPopupMenu::hideContextMenu()
00533 {
00534 TDEPopupMenuPrivate::s_continueCtxMenuShow = false;
00535 }
00536
00537 int TDEPopupMenu::contextMenuFocusItem()
00538 {
00539 return TDEPopupMenuPrivate::s_highlightedItem;
00540 }
00541
00542 TDEPopupMenu* TDEPopupMenu::contextMenuFocus()
00543 {
00544 return TDEPopupMenuPrivate::s_contextedMenu;
00545 }
00546
00547 void TDEPopupMenu::itemHighlighted(int )
00548 {
00549 if (!d->m_ctxMenu || !d->m_ctxMenu->isVisible())
00550 {
00551 return;
00552 }
00553
00554 d->m_ctxMenu->hide();
00555 showCtxMenu(mapFromGlobal(TQCursor::pos()));
00556 }
00557
00558 void TDEPopupMenu::showCtxMenu(TQPoint pos)
00559 {
00560 TQMenuItem* item = findItem(TDEPopupMenuPrivate::s_highlightedItem);
00561 if (item)
00562 {
00563 TQPopupMenu* subMenu = item->popup();
00564 if (subMenu)
00565 {
00566 disconnect(subMenu, TQT_SIGNAL(aboutToShow()), this, TQT_SLOT(ctxMenuHideShowingMenu()));
00567 }
00568 }
00569
00570 TDEPopupMenuPrivate::s_highlightedItem = idAt(pos);
00571
00572 if (TDEPopupMenuPrivate::s_highlightedItem == -1)
00573 {
00574 TDEPopupMenuPrivate::s_contextedMenu = 0;
00575 return;
00576 }
00577
00578 emit aboutToShowContextMenu(this, TDEPopupMenuPrivate::s_highlightedItem, d->m_ctxMenu);
00579
00580 TQPopupMenu* subMenu = findItem(TDEPopupMenuPrivate::s_highlightedItem)->popup();
00581 if (subMenu)
00582 {
00583 connect(subMenu, TQT_SIGNAL(aboutToShow()), TQT_SLOT(ctxMenuHideShowingMenu()));
00584 TQTimer::singleShot(100, subMenu, TQT_SLOT(hide()));
00585 }
00586
00587 if (!TDEPopupMenuPrivate::s_continueCtxMenuShow)
00588 {
00589 TDEPopupMenuPrivate::s_continueCtxMenuShow = true;
00590 return;
00591 }
00592
00593 TDEPopupMenuPrivate::s_contextedMenu = this;
00594 d->m_ctxMenu->popup(this->mapToGlobal(pos));
00595 connect(this, TQT_SIGNAL(highlighted(int)), this, TQT_SLOT(itemHighlighted(int)));
00596 }
00597
00598
00599
00600
00601
00602 void TDEPopupMenu::ctxMenuHideShowingMenu()
00603 {
00604 TQMenuItem* item = findItem(TDEPopupMenuPrivate::s_highlightedItem);
00605 if (item)
00606 {
00607 TQPopupMenu* subMenu = item->popup();
00608 if (subMenu)
00609 {
00610 TQTimer::singleShot(0, subMenu, TQT_SLOT(hide()));
00611 }
00612 }
00613 }
00614
00615 void TDEPopupMenu::ctxMenuHiding()
00616 {
00617 if (TDEPopupMenuPrivate::s_highlightedItem)
00618 {
00619 TQPopupMenu* subMenu = findItem(TDEPopupMenuPrivate::s_highlightedItem)->popup();
00620 if (subMenu)
00621 {
00622 disconnect(subMenu, TQT_SIGNAL(aboutToShow()), this, TQT_SLOT(ctxMenuHideShowingMenu()));
00623 }
00624 }
00625
00626 disconnect(this, TQT_SIGNAL(highlighted(int)), this, TQT_SLOT(itemHighlighted(int)));
00627 TDEPopupMenuPrivate::s_continueCtxMenuShow = true;
00628 }
00629
00630 void TDEPopupMenu::contextMenuEvent(TQContextMenuEvent* e)
00631 {
00632 if (d->m_ctxMenu)
00633 {
00634 if (e->reason() == TQContextMenuEvent::Mouse)
00635 {
00636 showCtxMenu(e->pos());
00637 }
00638 else if (actItem != -1)
00639 {
00640 showCtxMenu(itemGeometry(actItem).center());
00641 }
00642
00643 e->accept();
00644 return;
00645 }
00646
00647 TQPopupMenu::contextMenuEvent(e);
00648 }
00649
00650 void TDEPopupMenu::hideEvent(TQHideEvent*)
00651 {
00652 if (d->m_ctxMenu && d->m_ctxMenu->isVisible())
00653 {
00654
00655
00656
00657
00658
00659
00660
00661
00662 blockSignals(true);
00663 d->m_ctxMenu->hide();
00664 blockSignals(false);
00665 }
00666 }
00671
00672 TDEPopupMenu::TDEPopupMenu(const TQString& title, TQWidget *parent, const char *name)
00673 : TQPopupMenu(parent, name)
00674 {
00675 d = new TDEPopupMenuPrivate;
00676 insertTitle(title);
00677 }
00678
00679
00680 void TDEPopupMenu::setTitle(const TQString &title)
00681 {
00682 TDEPopupTitle *titleItem = new TDEPopupTitle();
00683 titleItem->setTitle(title);
00684 insertItem(titleItem);
00685 d->m_lastTitle = title;
00686 }
00687
00688 void TDEPopupTitle::virtual_hook( int, void* )
00689 { }
00690
00691 void TDEPopupMenu::virtual_hook( int, void* )
00692 { }
00693
00694 #include "tdepopupmenu.moc"