Diffstat (limited to 'libopie2/opieui/opopupmenu.cpp') (more/less context) (ignore whitespace changes)
-rw-r--r-- | libopie2/opieui/opopupmenu.cpp | 604 |
1 files changed, 604 insertions, 0 deletions
diff --git a/libopie2/opieui/opopupmenu.cpp b/libopie2/opieui/opopupmenu.cpp new file mode 100644 index 0000000..ac73188 --- a/dev/null +++ b/libopie2/opieui/opopupmenu.cpp | |||
@@ -0,0 +1,604 @@ | |||
1 | /* This file is part of the KDE libraries | ||
2 | Copyright (C) 2000 Daniel M. Duley <mosfet@kde.org> | ||
3 | Copyright (C) 2002 Hamish Rodda <meddie@yoyo.its.monash.edu.au> | ||
4 | |||
5 | This library is free software; you can redistribute it and/or | ||
6 | modify it under the terms of the GNU Library General Public | ||
7 | License version 2 as published by the Free Software Foundation. | ||
8 | |||
9 | This library is distributed in the hope that it will be useful, | ||
10 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
12 | Library General Public License for more details. | ||
13 | |||
14 | You should have received a copy of the GNU Library General Public License | ||
15 | along with this library; see the file COPYING.LIB. If not, write to | ||
16 | the Free Software Foundation, Inc., 59 Temple Place - Suite 330, | ||
17 | Boston, MA 02111-1307, USA. | ||
18 | */ | ||
19 | |||
20 | /* QT */ | ||
21 | |||
22 | #include <qapplication.h> | ||
23 | #include <qcursor.h> | ||
24 | #include <qpainter.h> | ||
25 | #include <qdrawutil.h> | ||
26 | #include <qtimer.h> | ||
27 | #include <qfont.h> | ||
28 | #include <qfontmetrics.h> | ||
29 | #include <qregexp.h> | ||
30 | #include <qstyle.h> | ||
31 | |||
32 | /* OPIE */ | ||
33 | |||
34 | #include <opie2/opopupmenu.h> | ||
35 | #include <opie2/oconfig.h> | ||
36 | |||
37 | OPopupTitle::OPopupTitle(QWidget *parent, const char *name) | ||
38 | : QWidget(parent, name) | ||
39 | { | ||
40 | setMinimumSize(16, fontMetrics().height()+8); | ||
41 | } | ||
42 | |||
43 | OPopupTitle::OPopupTitle(OPixmapEffect::GradientType /* gradient */, | ||
44 | const QColor &/* color */, const QColor &/* textColor */, | ||
45 | QWidget *parent, const char *name) | ||
46 | : QWidget(parent, name) | ||
47 | { | ||
48 | setMinimumSize(16, fontMetrics().height()+8); | ||
49 | } | ||
50 | |||
51 | OPopupTitle::OPopupTitle(const OPixmap & /* background */, const QColor &/* color */, | ||
52 | const QColor &/* textColor */, QWidget *parent, | ||
53 | const char *name) | ||
54 | : QWidget(parent, name) | ||
55 | { | ||
56 | setMinimumSize(16, fontMetrics().height()+8); | ||
57 | } | ||
58 | |||
59 | void OPopupTitle::setTitle(const QString &text, const QPixmap *icon) | ||
60 | { | ||
61 | titleStr = text; | ||
62 | if (icon) | ||
63 | miniicon = *icon; | ||
64 | else | ||
65 | miniicon.resize(0, 0); | ||
66 | |||
67 | int w = miniicon.width()+fontMetrics().width(titleStr); | ||
68 | int h = QMAX( fontMetrics().height(), miniicon.height() ); | ||
69 | setMinimumSize( w+16, h+8 ); | ||
70 | } | ||
71 | |||
72 | void OPopupTitle::setText( const QString &text ) | ||
73 | { | ||
74 | titleStr = text; | ||
75 | int w = miniicon.width()+fontMetrics().width(titleStr); | ||
76 | int h = QMAX( fontMetrics().height(), miniicon.height() ); | ||
77 | setMinimumSize( w+16, h+8 ); | ||
78 | } | ||
79 | |||
80 | void OPopupTitle::setIcon( const QPixmap &pix ) | ||
81 | { | ||
82 | miniicon = pix; | ||
83 | int w = miniicon.width()+fontMetrics().width(titleStr); | ||
84 | int h = QMAX( fontMetrics().height(), miniicon.height() ); | ||
85 | setMinimumSize( w+16, h+8 ); | ||
86 | } | ||
87 | |||
88 | void OPopupTitle::paintEvent(QPaintEvent *) | ||
89 | { | ||
90 | QRect r(rect()); | ||
91 | QPainter p(this); | ||
92 | #if QT_VERSION > 290 | ||
93 | qApp->style().drawPrimitive(QStyle::PE_HeaderSection, &p, r, palette().active()); | ||
94 | #else | ||
95 | #warning OPopupMenu is not fully functional on Qt2 | ||
96 | #endif | ||
97 | |||
98 | if (!miniicon.isNull()) | ||
99 | p.drawPixmap(4, (r.height()-miniicon.height())/2, miniicon); | ||
100 | |||
101 | if (!titleStr.isNull()) | ||
102 | { | ||
103 | p.setPen(palette().active().text()); | ||
104 | QFont f = p.font(); | ||
105 | f.setBold(true); | ||
106 | p.setFont(f); | ||
107 | if(!miniicon.isNull()) | ||
108 | { | ||
109 | p.drawText(miniicon.width()+8, 0, width()-(miniicon.width()+8), | ||
110 | height(), AlignLeft | AlignVCenter | SingleLine, | ||
111 | titleStr); | ||
112 | } | ||
113 | else | ||
114 | { | ||
115 | p.drawText(0, 0, width(), height(), | ||
116 | AlignCenter | SingleLine, titleStr); | ||
117 | } | ||
118 | } | ||
119 | |||
120 | p.setPen(palette().active().highlight()); | ||
121 | p.drawLine(0, 0, r.right(), 0); | ||
122 | } | ||
123 | |||
124 | QSize OPopupTitle::sizeHint() const | ||
125 | { | ||
126 | return(minimumSize()); | ||
127 | } | ||
128 | |||
129 | class OPopupMenu::OPopupMenuPrivate | ||
130 | { | ||
131 | public: | ||
132 | OPopupMenuPrivate () | ||
133 | : noMatches(false) | ||
134 | , shortcuts(false) | ||
135 | , autoExec(false) | ||
136 | , lastHitIndex(-1) | ||
137 | , m_ctxMenu(0) | ||
138 | {} | ||
139 | |||
140 | ~OPopupMenuPrivate () | ||
141 | { | ||
142 | delete m_ctxMenu; | ||
143 | } | ||
144 | |||
145 | QString m_lastTitle; | ||
146 | |||
147 | // variables for keyboard navigation | ||
148 | QTimer clearTimer; | ||
149 | |||
150 | bool noMatches : 1; | ||
151 | bool shortcuts : 1; | ||
152 | bool autoExec : 1; | ||
153 | |||
154 | QString keySeq; | ||
155 | QString originalText; | ||
156 | |||
157 | int lastHitIndex; | ||
158 | |||
159 | // support for RMB menus on menus | ||
160 | QPopupMenu* m_ctxMenu; | ||
161 | static bool s_continueCtxMenuShow; | ||
162 | static int s_highlightedItem; | ||
163 | static OPopupMenu* s_contextedMenu; | ||
164 | }; | ||
165 | |||
166 | int OPopupMenu::OPopupMenuPrivate::s_highlightedItem(-1); | ||
167 | OPopupMenu* OPopupMenu::OPopupMenuPrivate::s_contextedMenu(0); | ||
168 | bool OPopupMenu::OPopupMenuPrivate::s_continueCtxMenuShow(true); | ||
169 | |||
170 | OPopupMenu::OPopupMenu(QWidget *parent, const char *name) | ||
171 | : QPopupMenu(parent, name) | ||
172 | { | ||
173 | d = new OPopupMenuPrivate; | ||
174 | resetKeyboardVars(); | ||
175 | connect(&(d->clearTimer), SIGNAL(timeout()), SLOT(resetKeyboardVars())); | ||
176 | } | ||
177 | |||
178 | OPopupMenu::~OPopupMenu() | ||
179 | { | ||
180 | if (OPopupMenuPrivate::s_contextedMenu == this) | ||
181 | { | ||
182 | OPopupMenuPrivate::s_contextedMenu = 0; | ||
183 | OPopupMenuPrivate::s_highlightedItem = -1; | ||
184 | } | ||
185 | |||
186 | delete d; | ||
187 | } | ||
188 | |||
189 | int OPopupMenu::insertTitle(const QString &text, int id, int index) | ||
190 | { | ||
191 | OPopupTitle *titleItem = new OPopupTitle(); | ||
192 | titleItem->setTitle(text); | ||
193 | int ret = insertItem(titleItem, id, index); | ||
194 | setItemEnabled(id, false); | ||
195 | return ret; | ||
196 | } | ||
197 | |||
198 | int OPopupMenu::insertTitle(const QPixmap &icon, const QString &text, int id, | ||
199 | int index) | ||
200 | { | ||
201 | OPopupTitle *titleItem = new OPopupTitle(); | ||
202 | titleItem->setTitle(text, &icon); | ||
203 | int ret = insertItem(titleItem, id, index); | ||
204 | setItemEnabled(id, false); | ||
205 | return ret; | ||
206 | } | ||
207 | |||
208 | void OPopupMenu::changeTitle(int id, const QString &text) | ||
209 | { | ||
210 | QMenuItem *item = findItem(id); | ||
211 | if(item){ | ||
212 | if(item->widget()) | ||
213 | ((OPopupTitle *)item->widget())->setTitle(text); | ||
214 | #ifndef NDEBUG | ||
215 | else | ||
216 | qWarning( "KPopupMenu: changeTitle() called with non-title id %d", id ); | ||
217 | #endif | ||
218 | } | ||
219 | #ifndef NDEBUG | ||
220 | else | ||
221 | qWarning( "KPopupMenu: changeTitle() called with invalid id %d", id ); | ||
222 | #endif | ||
223 | } | ||
224 | |||
225 | void OPopupMenu::changeTitle(int id, const QPixmap &icon, const QString &text) | ||
226 | { | ||
227 | QMenuItem *item = findItem(id); | ||
228 | if(item){ | ||
229 | if(item->widget()) | ||
230 | ((OPopupTitle *)item->widget())->setTitle(text, &icon); | ||
231 | #ifndef NDEBUG | ||
232 | else | ||
233 | qWarning( "KPopupMenu: changeTitle() called with non-title id %d", id ); | ||
234 | #endif | ||
235 | } | ||
236 | #ifndef NDEBUG | ||
237 | else | ||
238 | qWarning( "KPopupMenu: changeTitle() called with invalid id %d", id ); | ||
239 | #endif | ||
240 | } | ||
241 | |||
242 | QString OPopupMenu::title(int id) const | ||
243 | { | ||
244 | if(id == -1) // obsolete | ||
245 | return(d->m_lastTitle); | ||
246 | QMenuItem *item = findItem(id); | ||
247 | if(item){ | ||
248 | if(item->widget()) | ||
249 | return(((OPopupTitle *)item->widget())->title()); | ||
250 | else | ||
251 | qWarning("OPopupMenu: title() called with non-title id %d.", id); | ||
252 | } | ||
253 | else | ||
254 | qWarning("OPopupMenu: title() called with invalid id %d.", id); | ||
255 | return(QString::null); | ||
256 | } | ||
257 | |||
258 | QPixmap OPopupMenu::titlePixmap(int id) const | ||
259 | { | ||
260 | QMenuItem *item = findItem(id); | ||
261 | if(item){ | ||
262 | if(item->widget()) | ||
263 | return(((OPopupTitle *)item->widget())->icon()); | ||
264 | else | ||
265 | qWarning("KPopupMenu: titlePixmap() called with non-title id %d.", id); | ||
266 | } | ||
267 | else | ||
268 | qWarning("KPopupMenu: titlePixmap() called with invalid id %d.", id); | ||
269 | QPixmap tmp; | ||
270 | return(tmp); | ||
271 | } | ||
272 | |||
273 | /** | ||
274 | * This is re-implemented for keyboard navigation. | ||
275 | */ | ||
276 | void OPopupMenu::closeEvent(QCloseEvent*e) | ||
277 | { | ||
278 | if (d->shortcuts) | ||
279 | resetKeyboardVars(); | ||
280 | QPopupMenu::closeEvent(e); | ||
281 | } | ||
282 | |||
283 | void OPopupMenu::keyPressEvent(QKeyEvent* e) | ||
284 | { | ||
285 | if (!d->shortcuts) { | ||
286 | // continue event processing by Qpopup | ||
287 | //e->ignore(); | ||
288 | QPopupMenu::keyPressEvent(e); | ||
289 | return; | ||
290 | } | ||
291 | |||
292 | int i = 0; | ||
293 | bool firstpass = true; | ||
294 | QString keyString = e->text(); | ||
295 | |||
296 | // check for common commands dealt with by QPopup | ||
297 | int key = e->key(); | ||
298 | if (key == Key_Escape || key == Key_Return || key == Key_Enter | ||
299 | || key == Key_Up || key == Key_Down || key == Key_Left | ||
300 | || key == Key_Right || key == Key_F1) { | ||
301 | |||
302 | resetKeyboardVars(); | ||
303 | // continue event processing by Qpopup | ||
304 | //e->ignore(); | ||
305 | QPopupMenu::keyPressEvent(e); | ||
306 | return; | ||
307 | } | ||
308 | |||
309 | // check to see if the user wants to remove a key from the sequence (backspace) | ||
310 | // or clear the sequence (delete) | ||
311 | if (!d->keySeq.isNull()) { | ||
312 | |||
313 | if (key == Key_Backspace) { | ||
314 | |||
315 | if (d->keySeq.length() == 1) { | ||
316 | resetKeyboardVars(); | ||
317 | return; | ||
318 | } | ||
319 | |||
320 | // keep the last sequence in keyString | ||
321 | keyString = d->keySeq.left(d->keySeq.length() - 1); | ||
322 | |||
323 | // allow sequence matching to be tried again | ||
324 | resetKeyboardVars(); | ||
325 | |||
326 | } else if (key == Key_Delete) { | ||
327 | resetKeyboardVars(); | ||
328 | |||
329 | // clear active item | ||
330 | setActiveItem(0); | ||
331 | return; | ||
332 | |||
333 | } else if (d->noMatches) { | ||
334 | // clear if there are no matches | ||
335 | resetKeyboardVars(); | ||
336 | |||
337 | // clear active item | ||
338 | setActiveItem(0); | ||
339 | |||
340 | } else { | ||
341 | // the key sequence is not a null string | ||
342 | // therefore the lastHitIndex is valid | ||
343 | i = d->lastHitIndex; | ||
344 | } | ||
345 | } else if (key == Key_Backspace && parentMenu) { | ||
346 | // backspace with no chars in the buffer... go back a menu. | ||
347 | hide(); | ||
348 | resetKeyboardVars(); | ||
349 | return; | ||
350 | } | ||
351 | |||
352 | d->keySeq += keyString; | ||
353 | int seqLen = d->keySeq.length(); | ||
354 | |||
355 | for (; i < (int)count(); i++) { | ||
356 | // compare typed text with text of this entry | ||
357 | int j = idAt(i); | ||
358 | |||
359 | // don't search disabled entries | ||
360 | if (!isItemEnabled(j)) | ||
361 | continue; | ||
362 | |||
363 | QString thisText; | ||
364 | |||
365 | // retrieve the right text | ||
366 | // (the last selected item one may have additional ampersands) | ||
367 | if (i == d->lastHitIndex) | ||
368 | thisText = d->originalText; | ||
369 | else | ||
370 | thisText = text(j); | ||
371 | |||
372 | // if there is an accelerator present, remove it | ||
373 | if ((int)accel(j) != 0) | ||
374 | thisText = thisText.replace(QRegExp("&"), ""); | ||
375 | |||
376 | // chop text to the search length | ||
377 | thisText = thisText.left(seqLen); | ||
378 | |||
379 | // do the search | ||
380 | if (thisText.find(d->keySeq, 0, false) == 0) { | ||
381 | |||
382 | if (firstpass) { | ||
383 | // match | ||
384 | setActiveItem(i); | ||
385 | |||
386 | // check to see if we're underlining a different item | ||
387 | if (d->lastHitIndex != i) | ||
388 | // yes; revert the underlining | ||
389 | changeItem(idAt(d->lastHitIndex), d->originalText); | ||
390 | |||
391 | // set the original text if it's a different item | ||
392 | if (d->lastHitIndex != i || d->lastHitIndex == -1) | ||
393 | d->originalText = text(j); | ||
394 | |||
395 | // underline the currently selected item | ||
396 | changeItem(j, underlineText(d->originalText, d->keySeq.length())); | ||
397 | |||
398 | // remeber what's going on | ||
399 | d->lastHitIndex = i; | ||
400 | |||
401 | // start/restart the clear timer | ||
402 | d->clearTimer.start(5000, true); | ||
403 | |||
404 | // go around for another try, to see if we can execute | ||
405 | firstpass = false; | ||
406 | } else { | ||
407 | // don't allow execution | ||
408 | return; | ||
409 | } | ||
410 | } | ||
411 | |||
412 | // fall through to allow execution | ||
413 | } | ||
414 | |||
415 | if (!firstpass) { | ||
416 | if (d->autoExec) { | ||
417 | // activate anything | ||
418 | activateItemAt(d->lastHitIndex); | ||
419 | resetKeyboardVars(); | ||
420 | |||
421 | } else if (findItem(idAt(d->lastHitIndex)) && | ||
422 | findItem(idAt(d->lastHitIndex))->popup()) { | ||
423 | // only activate sub-menus | ||
424 | activateItemAt(d->lastHitIndex); | ||
425 | resetKeyboardVars(); | ||
426 | } | ||
427 | |||
428 | return; | ||
429 | } | ||
430 | |||
431 | // no matches whatsoever, clean up | ||
432 | resetKeyboardVars(true); | ||
433 | //e->ignore(); | ||
434 | QPopupMenu::keyPressEvent(e); | ||
435 | } | ||
436 | |||
437 | QString OPopupMenu::underlineText(const QString& text, uint length) | ||
438 | { | ||
439 | QString ret = text; | ||
440 | for (uint i = 0; i < length; i++) { | ||
441 | if (ret[2*i] != '&') | ||
442 | ret.insert(2*i, "&"); | ||
443 | } | ||
444 | return ret; | ||
445 | } | ||
446 | |||
447 | void OPopupMenu::resetKeyboardVars(bool noMatches /* = false */) | ||
448 | { | ||
449 | // Clean up keyboard variables | ||
450 | if (d->lastHitIndex != -1) { | ||
451 | changeItem(idAt(d->lastHitIndex), d->originalText); | ||
452 | d->lastHitIndex = -1; | ||
453 | } | ||
454 | |||
455 | if (!noMatches) { | ||
456 | d->keySeq = QString::null; | ||
457 | } | ||
458 | |||
459 | d->noMatches = noMatches; | ||
460 | } | ||
461 | |||
462 | void OPopupMenu::setKeyboardShortcutsEnabled(bool enable) | ||
463 | { | ||
464 | d->shortcuts = enable; | ||
465 | } | ||
466 | |||
467 | void OPopupMenu::setKeyboardShortcutsExecute(bool enable) | ||
468 | { | ||
469 | d->autoExec = enable; | ||
470 | } | ||
471 | /** | ||
472 | * End keyboard navigation. | ||
473 | */ | ||
474 | |||
475 | /** | ||
476 | * RMB menus on menus | ||
477 | */ | ||
478 | QPopupMenu* OPopupMenu::contextMenu() | ||
479 | { | ||
480 | if (!d->m_ctxMenu) | ||
481 | { | ||
482 | d->m_ctxMenu = new QPopupMenu(this); | ||
483 | installEventFilter(this); | ||
484 | connect(d->m_ctxMenu, SIGNAL(aboutToHide()), this, SLOT(ctxMenuHiding())); | ||
485 | } | ||
486 | |||
487 | return d->m_ctxMenu; | ||
488 | } | ||
489 | |||
490 | void OPopupMenu::cancelContextMenuShow() | ||
491 | { | ||
492 | OPopupMenuPrivate::s_continueCtxMenuShow = false; | ||
493 | } | ||
494 | |||
495 | int OPopupMenu::contextMenuFocusItem() | ||
496 | { | ||
497 | return OPopupMenuPrivate::s_highlightedItem; | ||
498 | } | ||
499 | |||
500 | OPopupMenu* OPopupMenu::contextMenuFocus() | ||
501 | { | ||
502 | return OPopupMenuPrivate::s_contextedMenu; | ||
503 | } | ||
504 | |||
505 | void OPopupMenu::itemHighlighted(int /* whichItem */) | ||
506 | { | ||
507 | if (!d->m_ctxMenu || !d->m_ctxMenu->isVisible()) | ||
508 | { | ||
509 | return; | ||
510 | } | ||
511 | |||
512 | d->m_ctxMenu->hide(); | ||
513 | showCtxMenu(mapFromGlobal(QCursor::pos())); | ||
514 | } | ||
515 | |||
516 | void OPopupMenu::showCtxMenu(QPoint pos) | ||
517 | { | ||
518 | OPopupMenuPrivate::s_highlightedItem = idAt(pos); | ||
519 | |||
520 | if (OPopupMenuPrivate::s_highlightedItem == -1) | ||
521 | { | ||
522 | OPopupMenuPrivate::s_contextedMenu = 0; | ||
523 | return; | ||
524 | } | ||
525 | |||
526 | emit aboutToShowContextMenu(this, OPopupMenuPrivate::s_highlightedItem, d->m_ctxMenu); | ||
527 | |||
528 | if (!OPopupMenuPrivate::s_continueCtxMenuShow) | ||
529 | { | ||
530 | OPopupMenuPrivate::s_continueCtxMenuShow = true; | ||
531 | return; | ||
532 | } | ||
533 | |||
534 | OPopupMenuPrivate::s_contextedMenu = this; | ||
535 | d->m_ctxMenu->popup(this->mapToGlobal(pos)); | ||
536 | connect(this, SIGNAL(highlighted(int)), this, SLOT(itemHighlighted(int))); | ||
537 | } | ||
538 | |||
539 | void OPopupMenu::ctxMenuHiding() | ||
540 | { | ||
541 | disconnect(this, SIGNAL(highlighted(int)), this, SLOT(itemHighlighted(int))); | ||
542 | OPopupMenuPrivate::s_continueCtxMenuShow = true; | ||
543 | } | ||
544 | |||
545 | bool OPopupMenu::eventFilter(QObject* obj, QEvent* event) | ||
546 | { | ||
547 | if (d->m_ctxMenu && obj == this) | ||
548 | { | ||
549 | if (event->type() == QEvent::MouseButtonRelease) | ||
550 | { | ||
551 | if (d->m_ctxMenu->isVisible()) | ||
552 | { | ||
553 | return true; | ||
554 | } | ||
555 | } | ||
556 | #if QT_VERSION > 290 | ||
557 | else if (event->type() == QEvent::ContextMenu) | ||
558 | #else | ||
559 | else if ( (event->type() == QEvent::MouseButtonPress) && | ||
560 | ( (QMouseEvent*) event )->button() == QMouseEvent::RightButton ) | ||
561 | #endif | ||
562 | { | ||
563 | showCtxMenu(mapFromGlobal(QCursor::pos())); | ||
564 | return true; | ||
565 | } | ||
566 | } | ||
567 | |||
568 | return QWidget::eventFilter(obj, event); | ||
569 | } | ||
570 | |||
571 | void OPopupMenu::hideEvent(QHideEvent*) | ||
572 | { | ||
573 | if (d->m_ctxMenu) | ||
574 | { | ||
575 | d->m_ctxMenu->hide(); | ||
576 | } | ||
577 | } | ||
578 | /** | ||
579 | * end of RMB menus on menus support | ||
580 | */ | ||
581 | |||
582 | // Obsolete | ||
583 | OPopupMenu::OPopupMenu(const QString& title, QWidget *parent, const char *name) | ||
584 | : QPopupMenu(parent, name) | ||
585 | { | ||
586 | d = new OPopupMenuPrivate; | ||
587 | setTitle(title); | ||
588 | } | ||
589 | |||
590 | // Obsolete | ||
591 | void OPopupMenu::setTitle(const QString &title) | ||
592 | { | ||
593 | OPopupTitle *titleItem = new OPopupTitle(); | ||
594 | titleItem->setTitle(title); | ||
595 | insertItem(titleItem); | ||
596 | d->m_lastTitle = title; | ||
597 | } | ||
598 | |||
599 | void OPopupTitle::virtual_hook( int, void* ) | ||
600 | { /*BASE::virtual_hook( id, data );*/ } | ||
601 | |||
602 | void OPopupMenu::virtual_hook( int, void* ) | ||
603 | { /*BASE::virtual_hook( id, data );*/ } | ||
604 | |||