source: trunk/src/qt3support/widgets/q3titlebar.cpp@ 561

Last change on this file since 561 was 561, checked in by Dmitry A. Kuminov, 15 years ago

trunk: Merged in qt 4.6.1 sources.

File size: 19.3 KB
Line 
1/****************************************************************************
2**
3** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
4** All rights reserved.
5** Contact: Nokia Corporation ([email protected])
6**
7** This file is part of the Qt3Support module of the Qt Toolkit.
8**
9** $QT_BEGIN_LICENSE:LGPL$
10** Commercial Usage
11** Licensees holding valid Qt Commercial licenses may use this file in
12** accordance with the Qt Commercial License Agreement provided with the
13** Software or, alternatively, in accordance with the terms contained in
14** a written agreement between you and Nokia.
15**
16** GNU Lesser General Public License Usage
17** Alternatively, this file may be used under the terms of the GNU Lesser
18** General Public License version 2.1 as published by the Free Software
19** Foundation and appearing in the file LICENSE.LGPL included in the
20** packaging of this file. Please review the following information to
21** ensure the GNU Lesser General Public License version 2.1 requirements
22** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
23**
24** In addition, as a special exception, Nokia gives you certain additional
25** rights. These rights are described in the Nokia Qt LGPL Exception
26** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
27**
28** GNU General Public License Usage
29** Alternatively, this file may be used under the terms of the GNU
30** General Public License version 3.0 as published by the Free Software
31** Foundation and appearing in the file LICENSE.GPL included in the
32** packaging of this file. Please review the following information to
33** ensure the GNU General Public License version 3.0 requirements will be
34** met: http://www.gnu.org/copyleft/gpl.html.
35**
36** If you have questions regarding the use of this file, please contact
37** Nokia at [email protected].
38** $QT_END_LICENSE$
39**
40****************************************************************************/
41
42#include "qplatformdefs.h"
43
44#ifndef QT_NO_TITLEBAR
45
46#include "qapplication.h"
47#include "qcursor.h"
48#include "qdatetime.h"
49#include "qevent.h"
50#include "qimage.h"
51#include "qpainter.h"
52#include "qiodevice.h"
53#include "qpixmap.h"
54#include "qstyle.h"
55#include "qstyleoption.h"
56#include "qtimer.h"
57#include "qtooltip.h"
58#include "qdebug.h"
59#if defined(Q_WS_WIN)
60#include "qt_windows.h"
61#endif
62
63#include "private/qapplication_p.h"
64#include "private/q3titlebar_p.h"
65#include "private/qwidget_p.h"
66
67QT_BEGIN_NAMESPACE
68
69class Q3TitleBarPrivate : public QWidgetPrivate
70{
71 Q_DECLARE_PUBLIC(Q3TitleBar)
72public:
73 Q3TitleBarPrivate()
74 : toolTip(0), act(0), window(0), movable(1), pressed(0), autoraise(0), inevent(0)
75 {
76 }
77
78 Qt::WindowFlags flags;
79 QStyle::SubControl buttonDown;
80 QPoint moveOffset;
81 QToolTip *toolTip;
82 bool act :1;
83 QWidget* window;
84 bool movable :1;
85 bool pressed :1;
86 bool autoraise :1;
87 bool inevent : 1;
88
89 int titleBarState() const;
90 QStyleOptionTitleBar getStyleOption() const;
91 void readColors();
92};
93
94inline int Q3TitleBarPrivate::titleBarState() const
95{
96 uint state = window ? window->windowState() : static_cast<Qt::WindowStates>(Qt::WindowNoState);
97 state |= uint(act ? QStyle::State_Active : QStyle::State_None);
98 return (int)state;
99}
100
101QStyleOptionTitleBar Q3TitleBarPrivate::getStyleOption() const
102{
103 Q_Q(const Q3TitleBar);
104 QStyleOptionTitleBar opt;
105 opt.init(q);
106 opt.text = q->windowTitle();
107 //################
108 QIcon icon = q->windowIcon();
109 QSize s = icon.actualSize(QSize(64, 64));
110 opt.icon = icon.pixmap(s);
111 opt.subControls = QStyle::SC_All;
112 opt.activeSubControls = QStyle::SC_None;
113 opt.titleBarState = titleBarState();
114 opt.titleBarFlags = flags;
115 return opt;
116}
117
118Q3TitleBar::Q3TitleBar(QWidget *w, QWidget *parent, Qt::WindowFlags f)
119 : QWidget(*new Q3TitleBarPrivate, parent, Qt::WStyle_Customize | Qt::WStyle_NoBorder)
120{
121 Q_D(Q3TitleBar);
122 if (f == 0 && w)
123 f = w->windowFlags();
124 d->flags = f;
125 d->window = w;
126 d->buttonDown = QStyle::SC_None;
127 d->act = 0;
128 if (w) {
129 if (w->minimumSize() == w->maximumSize())
130 d->flags &= ~Qt::WindowMaximizeButtonHint;
131 setWindowTitle(w->windowTitle());
132 }
133
134 d->readColors();
135 setSizePolicy(QSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed));
136 setMouseTracking(true);
137 setAutoRaise(style()->styleHint(QStyle::SH_TitleBar_AutoRaise, 0, this));
138}
139
140void Q3TitleBar::setFakeWindowFlags(Qt::WindowFlags f)
141{
142 Q_D(Q3TitleBar);
143 d->flags = f;
144}
145
146Qt::WindowFlags Q3TitleBar::fakeWindowFlags() const
147{
148 Q_D(const Q3TitleBar);
149 return d->flags;
150}
151
152Q3TitleBar::~Q3TitleBar()
153{
154}
155
156QStyleOptionTitleBar Q3TitleBar::getStyleOption() const
157{
158 return d_func()->getStyleOption();
159}
160
161#ifdef Q_WS_WIN
162static inline QRgb colorref2qrgb(COLORREF col)
163{
164 return qRgb(GetRValue(col),GetGValue(col),GetBValue(col));
165}
166#endif
167
168void Q3TitleBarPrivate::readColors()
169{
170 Q_Q(Q3TitleBar);
171 QPalette pal = q->palette();
172
173 bool colorsInitialized = false;
174
175#ifdef Q_WS_WIN // ask system properties on windows
176 if (QApplication::desktopSettingsAware()) {
177 pal.setColor(QPalette::Active, QPalette::Highlight, colorref2qrgb(GetSysColor(COLOR_ACTIVECAPTION)));
178 pal.setColor(QPalette::Inactive, QPalette::Highlight, colorref2qrgb(GetSysColor(COLOR_INACTIVECAPTION)));
179 pal.setColor(QPalette::Active, QPalette::HighlightedText, colorref2qrgb(GetSysColor(COLOR_CAPTIONTEXT)));
180 pal.setColor(QPalette::Inactive, QPalette::HighlightedText, colorref2qrgb(GetSysColor(COLOR_INACTIVECAPTIONTEXT)));
181 colorsInitialized = true;
182 BOOL gradient = false;
183 SystemParametersInfo(SPI_GETGRADIENTCAPTIONS, 0, &gradient, 0);
184 if (gradient) {
185 pal.setColor(QPalette::Active, QPalette::Base, colorref2qrgb(GetSysColor(COLOR_GRADIENTACTIVECAPTION)));
186 pal.setColor(QPalette::Inactive, QPalette::Base, colorref2qrgb(GetSysColor(COLOR_GRADIENTINACTIVECAPTION)));
187 } else {
188 pal.setColor(QPalette::Active, QPalette::Base, pal.color(QPalette::Active, QPalette::Highlight));
189 pal.setColor(QPalette::Inactive, QPalette::Base, pal.color(QPalette::Inactive, QPalette::Highlight));
190 }
191 }
192#endif // Q_WS_WIN
193 if (!colorsInitialized) {
194 pal.setColor(QPalette::Active, QPalette::Highlight,
195 pal.color(QPalette::Active, QPalette::Highlight));
196 pal.setColor(QPalette::Active, QPalette::Base,
197 pal.color(QPalette::Active, QPalette::Highlight));
198 pal.setColor(QPalette::Inactive, QPalette::Highlight,
199 pal.color(QPalette::Inactive, QPalette::Dark));
200 pal.setColor(QPalette::Inactive, QPalette::Base,
201 pal.color(QPalette::Inactive, QPalette::Dark));
202 pal.setColor(QPalette::Inactive, QPalette::HighlightedText,
203 pal.color(QPalette::Inactive, QPalette::Window));
204 }
205
206 q->setPalette(pal);
207 q->setActive(act);
208}
209
210void Q3TitleBar::changeEvent(QEvent *ev)
211{
212 if(ev->type() == QEvent::ModifiedChange)
213 update();
214 QWidget::changeEvent(ev);
215}
216
217void Q3TitleBar::mousePressEvent(QMouseEvent *e)
218{
219 Q_D(Q3TitleBar);
220 if (!d->act)
221 emit doActivate();
222 if (e->button() == Qt::LeftButton) {
223 d->pressed = true;
224 QStyleOptionTitleBar opt = d->getStyleOption();
225 QStyle::SubControl ctrl = style()->hitTestComplexControl(QStyle::CC_TitleBar, &opt,
226 e->pos(), this);
227 switch (ctrl) {
228 case QStyle::SC_TitleBarSysMenu:
229 if (d->flags & Qt::WindowSystemMenuHint) {
230 d->buttonDown = QStyle::SC_None;
231 static QTime *t = 0;
232 static Q3TitleBar *tc = 0;
233 if (!t)
234 t = new QTime;
235 if (tc != this || t->elapsed() > QApplication::doubleClickInterval()) {
236 emit showOperationMenu();
237 t->start();
238 tc = this;
239 } else {
240 tc = 0;
241 emit doClose();
242 return;
243 }
244 }
245 break;
246
247 case QStyle::SC_TitleBarShadeButton:
248 case QStyle::SC_TitleBarUnshadeButton:
249 if (d->flags & Qt::WindowShadeButtonHint)
250 d->buttonDown = ctrl;
251 break;
252
253 case QStyle::SC_TitleBarNormalButton:
254 if (d->flags & Qt::WindowMinMaxButtonsHint)
255 d->buttonDown = ctrl;
256 break;
257
258 case QStyle::SC_TitleBarMinButton:
259 if (d->flags & Qt::WindowMinimizeButtonHint)
260 d->buttonDown = ctrl;
261 break;
262
263 case QStyle::SC_TitleBarMaxButton:
264 if (d->flags & Qt::WindowMaximizeButtonHint)
265 d->buttonDown = ctrl;
266 break;
267
268 case QStyle::SC_TitleBarCloseButton:
269 if (d->flags & Qt::WindowSystemMenuHint)
270 d->buttonDown = ctrl;
271 break;
272
273 case QStyle::SC_TitleBarLabel:
274 d->buttonDown = ctrl;
275 d->moveOffset = mapToParent(e->pos());
276 break;
277
278 default:
279 break;
280 }
281 repaint();
282 } else {
283 d->pressed = false;
284 }
285}
286
287void Q3TitleBar::contextMenuEvent(QContextMenuEvent *e)
288{
289 Q_D(Q3TitleBar);
290 QStyleOptionTitleBar opt = d->getStyleOption();
291 QStyle::SubControl ctrl = style()->hitTestComplexControl(QStyle::CC_TitleBar, &opt, e->pos(),
292 this);
293 if(ctrl == QStyle::SC_TitleBarLabel || ctrl == QStyle::SC_TitleBarSysMenu) {
294 e->accept();
295 emit popupOperationMenu(e->globalPos());
296 } else {
297 e->ignore();
298 }
299}
300
301void Q3TitleBar::mouseReleaseEvent(QMouseEvent *e)
302{
303 Q_D(Q3TitleBar);
304 if (e->button() == Qt::LeftButton && d->pressed) {
305 e->accept();
306 QStyleOptionTitleBar opt = d->getStyleOption();
307 QStyle::SubControl ctrl = style()->hitTestComplexControl(QStyle::CC_TitleBar, &opt,
308 e->pos(), this);
309 d->pressed = false;
310 if (ctrl == d->buttonDown) {
311 d->buttonDown = QStyle::SC_None;
312 repaint();
313 switch(ctrl) {
314 case QStyle::SC_TitleBarShadeButton:
315 case QStyle::SC_TitleBarUnshadeButton:
316 if(d->flags & Qt::WindowShadeButtonHint)
317 emit doShade();
318 break;
319
320 case QStyle::SC_TitleBarNormalButton:
321 if(d->flags & Qt::WindowMaximizeButtonHint)
322 emit doNormal();
323 break;
324
325 case QStyle::SC_TitleBarMinButton:
326 if(d->flags & Qt::WindowMinimizeButtonHint) {
327 if (d->window && d->window->isMinimized())
328 emit doNormal();
329 else
330 emit doMinimize();
331 }
332 break;
333
334 case QStyle::SC_TitleBarMaxButton:
335 if(d->flags & Qt::WindowMaximizeButtonHint) {
336 if(d->window && d->window->isMaximized())
337 emit doNormal();
338 else
339 emit doMaximize();
340 }
341 break;
342
343 case QStyle::SC_TitleBarCloseButton:
344 if(d->flags & Qt::WindowSystemMenuHint) {
345 d->buttonDown = QStyle::SC_None;
346 repaint();
347 emit doClose();
348 return;
349 }
350 break;
351
352 default:
353 break;
354 }
355 }
356 } else {
357 e->ignore();
358 }
359}
360
361void Q3TitleBar::mouseMoveEvent(QMouseEvent *e)
362{
363 Q_D(Q3TitleBar);
364 e->accept();
365 switch (d->buttonDown) {
366 case QStyle::SC_None:
367 if(autoRaise())
368 repaint();
369 break;
370 case QStyle::SC_TitleBarSysMenu:
371 break;
372 case QStyle::SC_TitleBarShadeButton:
373 case QStyle::SC_TitleBarUnshadeButton:
374 case QStyle::SC_TitleBarNormalButton:
375 case QStyle::SC_TitleBarMinButton:
376 case QStyle::SC_TitleBarMaxButton:
377 case QStyle::SC_TitleBarCloseButton:
378 {
379 QStyle::SubControl last_ctrl = d->buttonDown;
380 QStyleOptionTitleBar opt = d->getStyleOption();
381 d->buttonDown = style()->hitTestComplexControl(QStyle::CC_TitleBar, &opt, e->pos(), this);
382 if (d->buttonDown != last_ctrl)
383 d->buttonDown = QStyle::SC_None;
384 repaint();
385 d->buttonDown = last_ctrl;
386 }
387 break;
388
389 case QStyle::SC_TitleBarLabel:
390 if (d->buttonDown == QStyle::SC_TitleBarLabel && d->movable && d->pressed) {
391 if ((d->moveOffset - mapToParent(e->pos())).manhattanLength() >= 4) {
392 QPoint p = mapFromGlobal(e->globalPos());
393
394 QWidget *parent = d->window ? d->window->parentWidget() : 0;
395 if(parent && parent->inherits("Q3WorkspaceChild")) {
396 QWidget *workspace = parent->parentWidget();
397 p = workspace->mapFromGlobal(e->globalPos());
398 if (!workspace->rect().contains(p)) {
399 if (p.x() < 0)
400 p.rx() = 0;
401 if (p.y() < 0)
402 p.ry() = 0;
403 if (p.x() > workspace->width())
404 p.rx() = workspace->width();
405 if (p.y() > workspace->height())
406 p.ry() = workspace->height();
407 }
408 }
409
410 QPoint pp = p - d->moveOffset;
411 if (!parentWidget()->isMaximized())
412 parentWidget()->move(pp);
413 }
414 } else {
415 QStyle::SubControl last_ctrl = d->buttonDown;
416 d->buttonDown = QStyle::SC_None;
417 if(d->buttonDown != last_ctrl)
418 repaint();
419 }
420 break;
421 default:
422 break;
423 }
424}
425
426void Q3TitleBar::resizeEvent(QResizeEvent *r)
427{
428 QWidget::resizeEvent(r);
429 cutText();
430}
431
432bool Q3TitleBar::isTool() const
433{
434 return (d_func()->flags & Qt::WindowType_Mask) == Qt::Tool;
435}
436
437void Q3TitleBar::paintEvent(QPaintEvent *)
438{
439 Q_D(Q3TitleBar);
440 QStyleOptionTitleBar opt = d->getStyleOption();
441 opt.subControls = QStyle::SC_TitleBarLabel;
442 opt.activeSubControls = d->buttonDown;
443 if (d->flags & Qt::WindowSystemMenuHint) {
444 opt.subControls |= QStyle::SC_TitleBarSysMenu | QStyle::SC_TitleBarCloseButton;
445 if (d->window && (d->flags & Qt::WindowShadeButtonHint)) {
446 if (d->window->isMinimized())
447 opt.subControls |= QStyle::SC_TitleBarUnshadeButton;
448 else
449 opt.subControls |= QStyle::SC_TitleBarShadeButton;
450 }
451 if (d->window && (d->flags & Qt::WindowMinMaxButtonsHint)) {
452 if(d->window && d->window->isMinimized())
453 opt.subControls |= QStyle::SC_TitleBarNormalButton;
454 else
455 opt.subControls |= QStyle::SC_TitleBarMinButton;
456 }
457 if (d->window && (d->flags & Qt::WindowMaximizeButtonHint) && !d->window->isMaximized())
458 opt.subControls |= QStyle::SC_TitleBarMaxButton;
459 }
460 QStyle::SubControl under_mouse = QStyle::SC_None;
461
462 if (underMouse()) {
463 under_mouse = style()->hitTestComplexControl(QStyle::CC_TitleBar, &opt,
464 mapFromGlobal(QCursor::pos()), this);
465 opt.activeSubControls |= under_mouse;
466 if (d->pressed)
467 opt.state |= QStyle::State_Sunken;
468 else if(autoRaise())
469 opt.state |= QStyle::State_MouseOver;
470 }
471
472 opt.palette.setCurrentColorGroup(usesActiveColor() ? QPalette::Active : QPalette::Inactive);
473
474 QPainter p(this);
475 if (!windowTitle().isEmpty())
476 opt.titleBarFlags |= Qt::WindowTitleHint;
477 style()->drawComplexControl(QStyle::CC_TitleBar, &opt, &p, this);
478}
479
480void Q3TitleBar::mouseDoubleClickEvent(QMouseEvent *e)
481{
482 Q_D(Q3TitleBar);
483 if (e->button() != Qt::LeftButton) {
484 e->ignore();
485 return;
486 }
487 e->accept();
488 QStyleOptionTitleBar opt = d->getStyleOption();
489 switch (style()->hitTestComplexControl(QStyle::CC_TitleBar, &opt, e->pos(), this)) {
490 case QStyle::SC_TitleBarLabel:
491 emit doubleClicked();
492 break;
493
494 case QStyle::SC_TitleBarSysMenu:
495 if (d->flags & Qt::WStyle_SysMenu)
496 emit doClose();
497 break;
498
499 default:
500 break;
501 }
502}
503
504void Q3TitleBar::cutText()
505{
506 Q_D(Q3TitleBar);
507 QFontMetrics fm(font());
508 QStyleOptionTitleBar opt = d->getStyleOption();
509 int maxw = style()->subControlRect(QStyle::CC_TitleBar, &opt, QStyle::SC_TitleBarLabel,
510 this).width();
511 if (!d->window)
512 return;
513
514 QString txt = d->window->windowTitle();
515 if (style()->styleHint(QStyle::SH_TitleBar_ModifyNotification, 0, this) && d->window
516 && d->window->isWindowModified())
517 txt += QLatin1String(" *");
518
519 QString cuttext = txt;
520 if (fm.width(txt + QLatin1Char('m')) > maxw) {
521 int i = txt.length();
522 int dotlength = fm.width(QLatin1String("..."));
523 while (i>0 && fm.width(txt.left(i)) + dotlength > maxw)
524 i--;
525 if(i != (int)txt.length())
526 cuttext = txt.left(i) + QLatin1String("...");
527 }
528
529 setWindowTitle(cuttext);
530}
531
532
533void Q3TitleBar::leaveEvent(QEvent *)
534{
535 if(autoRaise() && !d_func()->pressed)
536 repaint();
537}
538
539void Q3TitleBar::enterEvent(QEvent *)
540{
541 if(autoRaise() && !d_func()->pressed)
542 repaint();
543 QEvent e(QEvent::Leave);
544 QApplication::sendEvent(parentWidget(), &e);
545}
546
547void Q3TitleBar::setActive(bool active)
548{
549 Q_D(Q3TitleBar);
550 if (d->act == active)
551 return ;
552
553 d->act = active;
554 update();
555}
556
557bool Q3TitleBar::isActive() const
558{
559 return d_func()->act;
560}
561
562bool Q3TitleBar::usesActiveColor() const
563{
564 return (isActive() && isActiveWindow()) ||
565 (!window() && QWidget::window()->isActiveWindow());
566}
567
568QWidget *Q3TitleBar::window() const
569{
570 return d_func()->window;
571}
572
573bool Q3TitleBar::event(QEvent *e)
574{
575 Q_D(Q3TitleBar);
576 if (d->inevent)
577 return QWidget::event(e);
578 d->inevent = true;
579 if (e->type() == QEvent::ApplicationPaletteChange) {
580 d->readColors();
581 return true;
582 } else if (e->type() == QEvent::WindowActivate) {
583 setActive(d->act);
584 } else if (e->type() == QEvent::WindowDeactivate) {
585 bool wasActive = d->act;
586 setActive(false);
587 d->act = wasActive;
588 } else if (e->type() == QEvent::WindowIconChange) {
589 update();
590 } else if (e->type() == QEvent::WindowTitleChange) {
591 cutText();
592 update();
593 }
594
595 d->inevent = false;
596 return QWidget::event(e);
597}
598
599void Q3TitleBar::setMovable(bool b)
600{
601 d_func()->movable = b;
602}
603
604bool Q3TitleBar::isMovable() const
605{
606 return d_func()->movable;
607}
608
609void Q3TitleBar::setAutoRaise(bool b)
610{
611 d_func()->autoraise = b;
612}
613
614bool Q3TitleBar::autoRaise() const
615{
616 return d_func()->autoraise;
617}
618
619QSize Q3TitleBar::sizeHint() const
620{
621 ensurePolished();
622 QStyleOptionTitleBar opt = d_func()->getStyleOption();
623 QRect menur = style()->subControlRect(QStyle::CC_TitleBar, &opt,
624 QStyle::SC_TitleBarSysMenu, this);
625 return QSize(menur.width(), style()->pixelMetric(QStyle::PM_TitleBarHeight, &opt, this));
626}
627
628QT_END_NAMESPACE
629
630#endif //QT_NO_TITLEBAR
Note: See TracBrowser for help on using the repository browser.