source: psi/trunk/libpsi/psiwidgets/fancypopup.cpp@ 82

Last change on this file since 82 was 15, checked in by dmik, 19 years ago

libps/psiwidgetsi: Don't specify WRepaintNoErase and WResizeNoErase flags on OS/2 because these are real flags there (as opposed to other platforms when WRepaintNoErase is ineffective).

File size: 9.7 KB
Line 
1/*
2 * fancypopup.cpp - the FancyPopup passive popup widget
3 * Copyright (C) 2003 Michail Pishchagin
4 *
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Lesser General Public
7 * License as published by the Free Software Foundation; either
8 * version 2.1 of the License, or (at your option) any later version.
9 *
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Lesser General Public License for more details.
14 *
15 * You should have received a copy of the GNU Lesser General Public
16 * License along with this library; if not, write to the Free Software
17 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18 *
19 */
20
21#include "fancypopup.h"
22
23#include <qpixmap.h>
24#include <qapplication.h>
25#include <qlabel.h>
26#include <qlayout.h>
27#include <qtimer.h>
28#include <qtooltip.h>
29#include <qpointarray.h>
30#include <qpainter.h>
31#include <qptrlist.h>
32#include <qtoolbutton.h>
33#include <qstyle.h>
34
35#include "iconset.h"
36#include "fancylabel.h"
37
38#define BUTTON_WIDTH 16
39#define BUTTON_HEIGHT 14
40
41/*static int checkComponent(int b)
42{
43 int c = b;
44 if ( c > 0xFF )
45 c = 0xFF;
46 return c;
47}
48
49static QColor makeColor(QColor baseColor, int percent)
50{
51 float p = (float)percent/100;
52 int r = checkComponent( (int)(baseColor.red() + ((float)p * baseColor.red())) );
53 int g = checkComponent( (int)(baseColor.green() + ((float)p * baseColor.green())) );
54 int b = checkComponent( (int)(baseColor.blue() + ((float)p * baseColor.blue())) );
55
56 return QColor(r, g, b);
57}*/
58
59//----------------------------------------------------------------------------
60// FancyPopup::Private
61//----------------------------------------------------------------------------
62
63class FancyPopup::Private : public QObject
64{
65 Q_OBJECT
66public:
67 Private(FancyPopup *p);
68 ~Private();
69
70 QPoint position();
71
72public slots:
73 void hide();
74 void popupDestroyed(QObject *);
75
76public:
77 // parameters
78 static int hideTimeout;
79 static QColor backgroundColor;
80
81 enum PopupLayout {
82 TopToBottom = 1,
83 BottomToTop = -1
84 };
85 PopupLayout popupLayout;
86
87 QPtrList<FancyPopup> prevPopups, nextPopups;
88 QBoxLayout *layout;
89 FancyPopup *popup;
90 QTimer *hideTimer;
91};
92
93int FancyPopup::Private::hideTimeout = 5 * 1000; // 5 seconds
94QColor FancyPopup::Private::backgroundColor = QColor (0x52, 0x97, 0xF9);
95
96FancyPopup::Private::Private(FancyPopup *p)
97: QObject(p)
98{
99 popup = p;
100
101 hideTimer = new QTimer(this);
102 connect(hideTimer, SIGNAL(timeout()), SLOT(hide()));
103}
104
105FancyPopup::Private::~Private()
106{
107}
108
109void FancyPopup::Private::hide()
110{
111 popup->hide();
112}
113
114void FancyPopup::Private::popupDestroyed(QObject *obj)
115{
116 if ( prevPopups.contains((FancyPopup *)obj) ) {
117 prevPopups.remove((FancyPopup *)obj);
118 popup->move( position() );
119 }
120 else if ( nextPopups.contains((FancyPopup *)obj) ) {
121 nextPopups.remove((FancyPopup *)obj);
122 }
123}
124
125QPoint FancyPopup::Private::position()
126{
127 QRect geom = qApp->desktop()->availableGeometry(popup);
128 QPoint destination(geom.x() + geom.width(), geom.y() + geom.height()); // in which corner popup should appear
129
130 if ( destination.y() > (qApp->desktop()->screenGeometry().height()/2) )
131 popupLayout = Private::BottomToTop;
132 else
133 popupLayout = Private::TopToBottom;
134
135 if ( (destination.x() + popup->width()) > (geom.x() + geom.width()) )
136 destination.setX( geom.x() + geom.width() - popup->width() );
137
138 if ( destination.x() < 0 )
139 destination.setX( 0 );
140
141 if ( (destination.y() + popup->height()) > (geom.y() + geom.height()) )
142 destination.setY( geom.y() + geom.height() - popup->height() );
143
144 if ( destination.y() < 0 )
145 destination.setY( 0 );
146
147 QPtrListIterator<FancyPopup> it ( prevPopups );
148 FancyPopup *p;
149 for ( ; (p = it.current()); ++it) {
150 destination.setY( destination.y() + popupLayout * p->height() );
151 }
152
153 return destination;
154}
155
156//----------------------------------------------------------------------------
157// FancyPopup
158//----------------------------------------------------------------------------
159
160static const int POPUP_FLAGS = Qt::WStyle_Customize | Qt::WDestructiveClose | Qt::WX11BypassWM
161 | Qt::WStyle_StaysOnTop | Qt::WStyle_Tool | Qt::WStyle_NoBorder;
162
163FancyPopup::FancyPopup(QString title, const Icon *icon, FancyPopup *prev, bool copyIcon)
164#ifdef Q_WS_PM
165// r=dmik: Why should we specify WRepaintNoErase and WResizeNoErase flags?
166// middlehbox->addSpacing(5) below leaves unpainted areas not covered by child
167// widgets. On other platforms it works just because these flags are *ineffective*
168// there (see the WM_ERASEBKGND handler in Qt/Win32); on OS/2 they are not.
169: QFrame( 0, 0, POPUP_FLAGS )
170#else
171: QFrame( 0, 0, POPUP_FLAGS | WRepaintNoErase | WResizeNoErase | WDestructiveClose )
172#endif
173{
174 d = new Private(this);
175
176 if ( prev ) {
177 QPtrListIterator<FancyPopup> it ( prev->d->prevPopups );
178 FancyPopup *popup;
179 bool finished = false;
180 for ( ; !finished; ++it) {
181 popup = it.current();
182 if ( !popup ) {
183 popup = prev;
184 finished = true;
185 }
186
187 d->prevPopups.append( popup );
188 connect(popup, SIGNAL(destroyed(QObject *)), d, SLOT(popupDestroyed(QObject *)));
189 }
190
191 prev->d->nextPopups.append( this );
192 connect(this, SIGNAL(destroyed(QObject *)), prev->d, SLOT(popupDestroyed(QObject *)));
193 }
194
195 // TODO: use darker color on popup borders
196 QPixmap back(1, 1);
197 QPainter p(&back);
198 p.setPen( d->backgroundColor );
199 p.drawPoint( 0, 0 );
200 p.end();
201
202 QVBoxLayout *vbox = new QVBoxLayout(this, 0, 0);
203
204 // top row
205 QHBoxLayout *tophbox = new QHBoxLayout(vbox);
206 QLabel *top1 = new QLabel(this);
207 top1->setFixedWidth(3);
208 top1->setPaletteBackgroundPixmap(back);
209 tophbox->addWidget(top1);
210
211 QVBoxLayout *topvbox = new QVBoxLayout(tophbox);
212 QLabel *top2 = new QLabel(this);
213 top2->setFixedHeight(1);
214 top2->setPaletteBackgroundPixmap(back);
215 topvbox->addWidget(top2);
216
217 QHBoxLayout *tophbox2 = new QHBoxLayout(topvbox);
218 IconLabel *titleIcon = new IconLabel(this);
219 titleIcon->setIcon(icon, copyIcon);
220 titleIcon->setPaletteBackgroundPixmap(back);
221 tophbox2->addWidget(titleIcon);
222
223 QLabel *top5 = new QLabel(this);
224 top5->setFixedWidth(3);
225 top5->setPaletteBackgroundPixmap(back);
226 tophbox2->addWidget(top5);
227
228 QLabel *titleText = new QLabel(this);
229 QString backgroundColorStr;
230 if ( (d->backgroundColor.red() + d->backgroundColor.green() + d->backgroundColor.blue())/3 > 128 )
231 backgroundColorStr = "white";
232 else
233 backgroundColorStr = "black";
234 titleText->setText( QString("<font color='%1'><nobr><b>%1</b></nobr></font>").arg( backgroundColorStr ).arg(title) );
235 titleText->setBackgroundPixmap(back);
236 titleText->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Preferred);
237 tophbox2->addWidget(titleText);
238
239 QWidget *closeButtonBack = new QWidget(this);
240 closeButtonBack->setPaletteBackgroundPixmap( back );
241 tophbox2->addWidget(closeButtonBack);
242
243 QVBoxLayout *closeButtonBackLayout = new QVBoxLayout(closeButtonBack);
244 closeButtonBackLayout->addStretch();
245
246 QToolButton *closeButton = new QToolButton( closeButtonBack, "close" );
247 QToolTip::add( closeButton, tr( "Close" ) );
248 closeButtonBackLayout->addWidget( closeButton );
249 closeButtonBackLayout->addStretch();
250 closeButton->setFocusPolicy( NoFocus );
251 closeButton->setIconSet( style().stylePixmap(QStyle::SP_TitleBarCloseButton) );
252 closeButton->setFixedSize(BUTTON_WIDTH, BUTTON_HEIGHT);
253 connect(closeButton, SIGNAL(clicked()), SLOT(hide()));
254
255 QLabel *top3 = new QLabel(this);
256 top3->setFixedHeight(1);
257 top3->setPaletteBackgroundPixmap(back);
258 topvbox->addWidget(top3);
259
260 QLabel *top4 = new QLabel(this);
261 top4->setFixedWidth(3);
262 top4->setPaletteBackgroundPixmap(back);
263 tophbox->addWidget(top4);
264
265 // middle row
266 QHBoxLayout *middlehbox = new QHBoxLayout(vbox);
267 QLabel *middle1 = new QLabel(this);
268 middle1->setFixedWidth(4);
269 middle1->setPaletteBackgroundPixmap(back);
270 middlehbox->addWidget(middle1);
271
272 middlehbox->addSpacing(5);
273 QVBoxLayout *middlevbox = new QVBoxLayout(middlehbox);
274 middlevbox->addSpacing(5);
275 d->layout = middlevbox; // we'll add more items later in addLayout()
276 middlehbox->addSpacing(5);
277
278 QLabel *middle3 = new QLabel(this);
279 middle3->setFixedWidth(4);
280 middle3->setPaletteBackgroundPixmap(back);
281 middlehbox->addWidget(middle3);
282
283 // bottom row
284 QHBoxLayout *bottomhbox = new QHBoxLayout(vbox);
285 QLabel *bottom1 = new QLabel(this);
286 bottom1->setFixedSize( 4, 4 );
287 bottom1->setPaletteBackgroundPixmap(back);
288 bottomhbox->addWidget(bottom1);
289
290 QLabel *bottom2 = new QLabel(this);
291 bottom2->setFixedHeight(4);
292 bottom2->setPaletteBackgroundPixmap(back);
293 bottomhbox->addWidget(bottom2);
294
295 QLabel *bottom3 = new QLabel(this);
296 bottom3->setFixedSize( 4, 4 );
297 bottom3->setPaletteBackgroundPixmap(back);
298 bottomhbox->addWidget(bottom3);
299}
300
301FancyPopup::~FancyPopup()
302{
303}
304
305void FancyPopup::addLayout(QLayout *layout, int stretch)
306{
307 d->layout->addLayout(layout, stretch);
308 d->layout->addSpacing(5);
309}
310
311void FancyPopup::show()
312{
313 if ( size() != sizeHint() )
314 resize( sizeHint() ); // minimumSizeHint()
315
316 // position popup
317 move ( d->position() );
318
319 // display popup
320 d->hideTimer->start( d->hideTimeout );
321 QFrame::show();
322}
323
324void FancyPopup::hideEvent(QHideEvent *e)
325{
326 d->hideTimer->stop();
327 deleteLater();
328
329 QFrame::hideEvent(e);
330}
331
332void FancyPopup::mouseReleaseEvent(QMouseEvent *e)
333{
334 QWidget *closeButton = (QWidget *)child("closeButton");
335 if ( closeButton ) {
336 QPoint p = closeButton->mapFromParent( e->pos() );
337 if ( p.x() >= 0 && p.y() >= 0 && p.x() < closeButton->width() && p.y() < closeButton->height() )
338 QFrame::mouseReleaseEvent(e);
339 }
340
341 emit clicked();
342 emit clicked((int)e->button());
343}
344
345void FancyPopup::restartHideTimer()
346{
347 d->hideTimer->stop();
348 d->hideTimer->start( d->hideTimeout );
349}
350
351void FancyPopup::setHideTimeout(int time)
352{
353 FancyPopup::Private::hideTimeout = time;
354}
355
356void FancyPopup::setBorderColor(QColor c)
357{
358 FancyPopup::Private::backgroundColor = c;
359}
360
361#include "fancypopup.moc"
Note: See TracBrowser for help on using the repository browser.