00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019 #include <qpainter.h>
00020 #include <qdrawutil.h>
00021 #include <qtimer.h>
00022 #include <qfont.h>
00023 #include <qfontmetrics.h>
00024 #include <qregexp.h>
00025
00026 #include "kpopupmenu.h"
00027
00028 #include <kconfig.h>
00029 #include <kdebug.h>
00030 #include <kapplication.h>
00031 #include <kipc.h>
00032 #include <kiconloader.h>
00033 #include <klocale.h>
00034 #include <kglobal.h>
00035 #include <kglobalsettings.h>
00036 #include <kstandarddirs.h>
00037
00038 KPopupTitle::KPopupTitle(QWidget *parent, const char *name)
00039 : QWidget(parent, name)
00040 {
00041 KConfig *config = KGlobal::config();
00042 QString oldGroup = config->group();
00043 QString tmpStr;
00044
00045 config->setGroup(QString::fromLatin1("PopupTitle"));
00046 bgColor = config->readColorEntry(QString::fromLatin1("Color"), &colorGroup().mid());
00047 grHigh = bgColor.light(150);
00048 grLow = bgColor.dark(150);
00049 fgColor = config->readColorEntry(QString::fromLatin1("TextColor"), &colorGroup().highlightedText());
00050
00051 tmpStr = config->readEntry(QString::fromLatin1("Pixmap"));
00052 if(!tmpStr.isEmpty())
00053 fill.load(KGlobal::dirs()->findResource("wallpaper", tmpStr));
00054 if(!fill.isNull()){
00055 config->setGroup(oldGroup);
00056 useGradient = false;
00057 return;
00058 }
00059
00060 tmpStr = config->readEntry(QString::fromLatin1("Gradient"));
00061 if(tmpStr.isEmpty()) {
00062 config->setGroup(oldGroup);
00063 useGradient = false;
00064 return;
00065 }
00066
00067 if(tmpStr == QString::fromLatin1("Horizontal"))
00068 grType = KPixmapEffect::HorizontalGradient;
00069 else if(tmpStr == QString::fromLatin1("Vertical"))
00070 grType = KPixmapEffect::VerticalGradient;
00071 else if(tmpStr == QString::fromLatin1("Diagonal"))
00072 grType = KPixmapEffect::DiagonalGradient;
00073 else if(tmpStr == QString::fromLatin1("Pyramid"))
00074 grType = KPixmapEffect::PyramidGradient;
00075 else if(tmpStr == QString::fromLatin1("Rectangle"))
00076 grType = KPixmapEffect::RectangleGradient;
00077 else if(tmpStr == QString::fromLatin1("Elliptic"))
00078 grType = KPixmapEffect::EllipticGradient;
00079 else{
00080 kdWarning() << "KPopupMenu: Unknown gradient type " << tmpStr << " for title item" << endl;
00081 grType = KPixmapEffect::HorizontalGradient;
00082 }
00083
00084 useGradient = true;
00085 setMinimumSize(16, fontMetrics().height()+8);
00086 config->setGroup(oldGroup);
00087 }
00088
00089 KPopupTitle::KPopupTitle(KPixmapEffect::GradientType gradient,
00090 const QColor &color, const QColor &textColor,
00091 QWidget *parent, const char *name)
00092 : QWidget(parent, name)
00093 {
00094 grType = gradient;
00095 fgColor = textColor;
00096 bgColor = color;
00097 grHigh = bgColor.light(150);
00098 grLow = bgColor.dark(150);
00099 useGradient = true;
00100 setMinimumSize(16, fontMetrics().height()+8);
00101 }
00102
00103 KPopupTitle::KPopupTitle(const KPixmap &background, const QColor &color,
00104 const QColor &textColor, QWidget *parent,
00105 const char *name)
00106 : QWidget(parent, name)
00107 {
00108 if(!background.isNull())
00109 fill = background;
00110 else
00111 kdWarning() << "KPopupMenu: Empty pixmap used for title." << endl;
00112 useGradient = false;
00113
00114 fgColor = textColor;
00115 bgColor = color;
00116 grHigh = bgColor.light(150);
00117 grLow = bgColor.dark(150);
00118 setMinimumSize(16, fontMetrics().height()+8);
00119 }
00120
00121 void KPopupTitle::setTitle(const QString &text, const QPixmap *icon)
00122 {
00123 titleStr = text;
00124 if(icon){
00125 miniicon = *icon;
00126 }
00127 else
00128 miniicon.resize(0, 0);
00129
00130 int w = miniicon.width()+fontMetrics().width(titleStr);
00131 int h = QMAX( fontMetrics().height(), miniicon.height() );
00132 setMinimumSize( w+16, h+8 );
00133 }
00134
00135 void KPopupTitle::setText( const QString &text )
00136 {
00137 titleStr = text;
00138 int w = miniicon.width()+fontMetrics().width(titleStr);
00139 int h = QMAX( fontMetrics().height(), miniicon.height() );
00140 setMinimumSize( w+16, h+8 );
00141 }
00142
00143 void KPopupTitle::setIcon( const QPixmap &pix )
00144 {
00145 miniicon = pix;
00146 int w = miniicon.width()+fontMetrics().width(titleStr);
00147 int h = QMAX( fontMetrics().height(), miniicon.height() );
00148 setMinimumSize( w+16, h+8 );
00149 }
00150
00151 void KPopupTitle::paintEvent(QPaintEvent *)
00152 {
00153 QRect r(rect());
00154 QPainter p(this);
00155
00156 if(useGradient){
00157
00158 if(fill.width() != r.width()-4 || fill.height() != r.height()-4){
00159 fill.resize(r.width()-4, r.height()-4);
00160 KPixmapEffect::gradient(fill, grHigh, grLow, grType);
00161 }
00162 p.drawPixmap(2, 2, fill);
00163 }
00164 else if(!fill.isNull())
00165 p.drawTiledPixmap(2, 2, r.width()-4, r.height()-4, fill);
00166 else{
00167 p.fillRect(2, 2, r.width()-4, r.height()-4, QBrush(bgColor));
00168 }
00169
00170 if(!miniicon.isNull())
00171 p.drawPixmap(4, (r.height()-miniicon.height())/2, miniicon);
00172 if(!titleStr.isNull()){
00173 p.setPen(fgColor);
00174 if(!miniicon.isNull())
00175 p.drawText(miniicon.width()+8, 0, width()-(miniicon.width()+8),
00176 height(), AlignLeft | AlignVCenter | SingleLine,
00177 titleStr);
00178 else
00179 p.drawText(0, 0, width(), height(),
00180 AlignCenter | SingleLine, titleStr);
00181 }
00182 p.setPen(Qt::black);
00183 p.drawRect(r);
00184 p.setPen(grLow);
00185 p.drawLine(r.x()+1, r.y()+1, r.right()-1, r.y()+1);
00186 p.drawLine(r.x()+1, r.y()+1, r.x()+1, r.bottom()-1);
00187 p.setPen(grHigh);
00188 p.drawLine(r.x()+1, r.bottom()-1, r.right()-1, r.bottom()-1);
00189 p.drawLine(r.right()-1, r.y()+1, r.right()-1, r.bottom()-1);
00190 }
00191
00192 QSize KPopupTitle::sizeHint() const
00193 {
00194 return(minimumSize());
00195 }
00196
00197 class KPopupMenu::KPopupMenuPrivate
00198 {
00199 public:
00200 KPopupMenuPrivate ()
00201 : noMatches(false)
00202 , shortcuts(false)
00203 , autoExec(false)
00204 , lastHitIndex(-1)
00205 {}
00206
00207 QString m_lastTitle;
00208
00209
00210 QTimer clearTimer;
00211
00212 bool noMatches : 1;
00213 bool shortcuts : 1;
00214 bool autoExec : 1;
00215
00216 QString keySeq;
00217 QString originalText;
00218
00219 int lastHitIndex;
00220 };
00221
00222
00223 KPopupMenu::KPopupMenu(QWidget *parent, const char *name)
00224 : QPopupMenu(parent, name)
00225 {
00226 d = new KPopupMenuPrivate;
00227 resetKeyboardVars();
00228 connect(&(d->clearTimer), SIGNAL(timeout()), SLOT(resetKeyboardVars()));
00229 }
00230
00231 KPopupMenu::~KPopupMenu()
00232 {
00233 delete d;
00234 }
00235
00236 int KPopupMenu::insertTitle(const QString &text, int id, int index)
00237 {
00238 KPopupTitle *titleItem = new KPopupTitle();
00239 titleItem->setTitle(text);
00240 int ret = insertItem(titleItem, id, index);
00241 setItemEnabled(id, false);
00242 return ret;
00243 }
00244
00245 int KPopupMenu::insertTitle(const QPixmap &icon, const QString &text, int id,
00246 int index)
00247 {
00248 KPopupTitle *titleItem = new KPopupTitle();
00249 titleItem->setTitle(text, &icon);
00250 int ret = insertItem(titleItem, id, index);
00251 setItemEnabled(id, false);
00252 return ret;
00253 }
00254
00255 void KPopupMenu::changeTitle(int id, const QString &text)
00256 {
00257 QMenuItem *item = findItem(id);
00258 if(item){
00259 if(item->widget())
00260 ((KPopupTitle *)item->widget())->setTitle(text);
00261 else
00262 qWarning("KPopupMenu: changeTitle() called with non-title id %d.", id);
00263 }
00264 else
00265 qWarning("KPopupMenu: changeTitle() called with invalid id %d.", id);
00266 }
00267
00268 void KPopupMenu::changeTitle(int id, const QPixmap &icon, const QString &text)
00269 {
00270 QMenuItem *item = findItem(id);
00271 if(item){
00272 if(item->widget())
00273 ((KPopupTitle *)item->widget())->setTitle(text, &icon);
00274 else
00275 qWarning("KPopupMenu: changeTitle() called with non-title id %d.", id);
00276 }
00277 else
00278 qWarning("KPopupMenu: changeTitle() called with invalid id %d.", id);
00279 }
00280
00281 QString KPopupMenu::title(int id) const
00282 {
00283 if(id == -1)
00284 return(d->m_lastTitle);
00285 QMenuItem *item = findItem(id);
00286 if(item){
00287 if(item->widget())
00288 return(((KPopupTitle *)item->widget())->title());
00289 else
00290 qWarning("KPopupMenu: title() called with non-title id %d.", id);
00291 }
00292 else
00293 qWarning("KPopupMenu: title() called with invalid id %d.", id);
00294 return(QString::null);
00295 }
00296
00297 QPixmap KPopupMenu::titlePixmap(int id) const
00298 {
00299 QMenuItem *item = findItem(id);
00300 if(item){
00301 if(item->widget())
00302 return(((KPopupTitle *)item->widget())->icon());
00303 else
00304 qWarning("KPopupMenu: titlePixmap() called with non-title id %d.", id);
00305 }
00306 else
00307 qWarning("KPopupMenu: titlePixmap() called with invalid id %d.", id);
00308 QPixmap tmp;
00309 return(tmp);
00310 }
00311
00315 void KPopupMenu::closeEvent(QCloseEvent*e)
00316 {
00317 if (d->shortcuts)
00318 resetKeyboardVars();
00319 QPopupMenu::closeEvent(e);
00320 }
00321
00322 void KPopupMenu::keyPressEvent(QKeyEvent* e)
00323 {
00324 if (!d->shortcuts) {
00325
00326
00327 QPopupMenu::keyPressEvent(e);
00328 return;
00329 }
00330
00331 int i = 0;
00332 bool firstpass = true;
00333 QString keyString = e->text();
00334
00335
00336 int key = e->key();
00337 if (key == Key_Escape || key == Key_Return || key == Key_Enter
00338 || key == Key_Up || key == Key_Down || key == Key_Left
00339 || key == Key_Right || key == Key_F1) {
00340
00341 resetKeyboardVars();
00342
00343
00344 QPopupMenu::keyPressEvent(e);
00345 return;
00346 }
00347
00348
00349
00350 if (d->keySeq != QString::null) {
00351
00352 if (key == Key_Backspace) {
00353
00354 if (d->keySeq.length() == 1) {
00355 resetKeyboardVars();
00356 return;
00357 }
00358
00359
00360 keyString = d->keySeq.left(d->keySeq.length() - 1);
00361
00362
00363 resetKeyboardVars();
00364
00365 } else if (key == Key_Delete) {
00366 resetKeyboardVars();
00367
00368
00369 setActiveItem(0);
00370 return;
00371
00372 } else if (d->noMatches) {
00373
00374 resetKeyboardVars();
00375
00376
00377 setActiveItem(0);
00378
00379 } else {
00380
00381
00382 i = d->lastHitIndex;
00383 }
00384 } else if (key == Key_Backspace && parentMenu) {
00385
00386 hide();
00387 resetKeyboardVars();
00388 return;
00389 }
00390
00391 d->keySeq += keyString;
00392 int seqLen = d->keySeq.length();
00393
00394 for (; i < (int)count(); i++) {
00395
00396 int j = idAt(i);
00397
00398
00399 if (!isItemEnabled(j))
00400 continue;
00401
00402 QString thisText;
00403
00404
00405
00406 if (i == d->lastHitIndex)
00407 thisText = d->originalText;
00408 else
00409 thisText = text(j);
00410
00411
00412 if ((int)accel(j) != 0)
00413 thisText = thisText.replace(QRegExp("&"), "");
00414
00415
00416 thisText = thisText.left(seqLen);
00417
00418
00419 if (thisText.find(d->keySeq, 0, false) == 0) {
00420
00421 if (firstpass) {
00422
00423 setActiveItem(i);
00424
00425
00426 if (d->lastHitIndex != i)
00427
00428 changeItem(idAt(d->lastHitIndex), d->originalText);
00429
00430
00431 if (d->lastHitIndex != i || d->lastHitIndex == -1)
00432 d->originalText = text(j);
00433
00434
00435 changeItem(j, underlineText(d->originalText, d->keySeq.length()));
00436
00437
00438 d->lastHitIndex = i;
00439
00440
00441 d->clearTimer.start(5000, true);
00442
00443
00444 firstpass = false;
00445 } else {
00446
00447 return;
00448 }
00449 }
00450
00451
00452 }
00453
00454 if (!firstpass) {
00455 if (d->autoExec) {
00456
00457 activateItemAt(d->lastHitIndex);
00458 resetKeyboardVars();
00459
00460 } else if (findItem(idAt(d->lastHitIndex)) &&
00461 findItem(idAt(d->lastHitIndex))->popup()) {
00462
00463 activateItemAt(d->lastHitIndex);
00464 resetKeyboardVars();
00465 }
00466
00467 return;
00468 }
00469
00470
00471 resetKeyboardVars(true);
00472
00473 QPopupMenu::keyPressEvent(e);
00474 }
00475
00476 QString KPopupMenu::underlineText(const QString& text, uint length)
00477 {
00478 QString ret = text;
00479 for (uint i = 0; i < length; i++) {
00480 if (ret[2*i] != '&')
00481 ret.insert(2*i, "&");
00482 }
00483 return ret;
00484 }
00485
00486 void KPopupMenu::resetKeyboardVars(bool noMatches )
00487 {
00488
00489 if (d->lastHitIndex != -1) {
00490 changeItem(idAt(d->lastHitIndex), d->originalText);
00491 d->lastHitIndex = -1;
00492 }
00493
00494 if (!noMatches) {
00495 d->keySeq = QString::null;
00496 }
00497
00498 d->noMatches = noMatches;
00499 }
00500
00501 void KPopupMenu::setKeyboardShortcutsEnabled(bool enable)
00502 {
00503 d->shortcuts = enable;
00504 }
00505
00506 void KPopupMenu::setKeyboardShortcutsExecute(bool enable)
00507 {
00508 d->autoExec = enable;
00509 }
00514
00515 KPopupMenu::KPopupMenu(const QString& title, QWidget *parent, const char *name)
00516 : QPopupMenu(parent, name)
00517 {
00518 d = new KPopupMenuPrivate;
00519 setTitle(title);
00520 }
00521
00522
00523 void KPopupMenu::setTitle(const QString &title)
00524 {
00525 KPopupTitle *titleItem = new KPopupTitle();
00526 titleItem->setTitle(title);
00527 insertItem(titleItem);
00528 d->m_lastTitle = title;
00529 }
00530
00531 void KPopupTitle::virtual_hook( int, void* )
00532 { }
00533
00534 void KPopupMenu::virtual_hook( int, void* )
00535 { }
00536
00537 #include "kpopupmenu.moc"