source: vendor/trolltech/current/src/widgets/qtitlebar.cpp

Last change on this file was 2, checked in by dmik, 20 years ago

Imported xplatform parts of the official release 3.3.1 from Trolltech

  • Property svn:keywords set to Id
File size: 18.3 KB
Line 
1/****************************************************************************
2** $Id: qtitlebar.cpp 2 2005-11-16 15:49:26Z dmik $
3**
4** Implementation of some Qt private functions.
5**
6** Created : 001101
7**
8** Copyright (C) 2000-2003 Trolltech AS. All rights reserved.
9**
10** This file is part of the widgets module of the Qt GUI Toolkit.
11**
12** This file may be distributed under the terms of the Q Public License
13** as defined by Trolltech AS of Norway and appearing in the file
14** LICENSE.QPL included in the packaging of this file.
15**
16** This file may be distributed and/or modified under the terms of the
17** GNU General Public License version 2 as published by the Free Software
18** Foundation and appearing in the file LICENSE.GPL included in the
19** packaging of this file.
20**
21** Licensees holding valid Qt Enterprise Edition or Qt Professional Edition
22** licenses may use this file in accordance with the Qt Commercial License
23** Agreement provided with the Software.
24**
25** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
26** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
27**
28** See http://www.trolltech.com/pricing.html or email sales@trolltech.com for
29** information about Qt Commercial License Agreements.
30** See http://www.trolltech.com/qpl/ for QPL licensing information.
31** See http://www.trolltech.com/gpl/ for GPL licensing information.
32**
33** Contact info@trolltech.com if any conditions of this licensing are
34** not clear to you.
35**
36**********************************************************************/
37
38#include "qplatformdefs.h"
39
40#include "qtitlebar_p.h"
41
42#ifndef QT_NO_TITLEBAR
43
44#include <qcursor.h>
45#include "qapplication.h"
46#include "qstyle.h"
47#include "qdatetime.h"
48#include "private/qapplication_p.h"
49#include "qtooltip.h"
50#include "qimage.h"
51#include "qtimer.h"
52#include "qpainter.h"
53#include "qstyle.h"
54#include "private/qinternal_p.h"
55#ifndef QT_NO_WORKSPACE
56#include "qworkspace.h"
57#endif
58#if defined(Q_WS_WIN)
59#include "qt_windows.h"
60#endif
61
62#ifndef QT_NO_TOOLTIP
63class QTitleBarTip : public QToolTip
64{
65public:
66 QTitleBarTip( QWidget * parent ) : QToolTip( parent ) { }
67
68 void maybeTip( const QPoint &pos )
69 {
70 if ( !::qt_cast<QTitleBar*>(parentWidget()) )
71 return;
72 QTitleBar *t = (QTitleBar *)parentWidget();
73
74 QString tipstring;
75 QStyle::SubControl ctrl = t->style().querySubControl(QStyle::CC_TitleBar, t, pos);
76 QSize controlSize = t->style().querySubControlMetrics(QStyle::CC_TitleBar, t, ctrl).size();
77
78 QWidget *window = t->window();
79 if ( window ) {
80 switch(ctrl) {
81 case QStyle::SC_TitleBarSysMenu:
82 if ( t->testWFlags( WStyle_SysMenu ) )
83 tipstring = QTitleBar::tr( "System Menu" );
84 break;
85
86 case QStyle::SC_TitleBarShadeButton:
87 if ( t->testWFlags( WStyle_Tool ) && t->testWFlags( WStyle_MinMax ) )
88 tipstring = QTitleBar::tr( "Shade" );
89 break;
90
91 case QStyle::SC_TitleBarUnshadeButton:
92 if ( t->testWFlags( WStyle_Tool ) && t->testWFlags( WStyle_MinMax ) )
93 tipstring = QTitleBar::tr( "Unshade" );
94 break;
95
96 case QStyle::SC_TitleBarNormalButton:
97 case QStyle::SC_TitleBarMinButton:
98 if ( !t->testWFlags( WStyle_Tool ) && t->testWFlags( WStyle_Minimize ) ) {
99 if( window->isMinimized() )
100 tipstring = QTitleBar::tr( "Normalize" );
101 else
102 tipstring = QTitleBar::tr( "Minimize" );
103 }
104 break;
105
106 case QStyle::SC_TitleBarMaxButton:
107 if ( !t->testWFlags( WStyle_Tool ) && t->testWFlags( WStyle_Maximize ) )
108 tipstring = QTitleBar::tr( "Maximize" );
109 break;
110
111 case QStyle::SC_TitleBarCloseButton:
112 if ( t->testWFlags( WStyle_SysMenu ) )
113 tipstring = QTitleBar::tr( "Close" );
114 break;
115
116 default:
117 break;
118 }
119 }
120#ifndef QT_NO_WIDGET_TOPEXTRA
121 if ( tipstring.isEmpty() ) {
122 if ( t->visibleText() != t->caption() )
123 tipstring = t->caption();
124 }
125#endif
126 if(!tipstring.isEmpty())
127 tip( QRect(pos, controlSize), tipstring );
128 }
129};
130#endif
131
132class QTitleBarPrivate
133{
134public:
135 QTitleBarPrivate()
136 : toolTip( 0 ), act( 0 ), window( 0 ), movable( 1 ), pressed( 0 ), autoraise(0)
137 {
138 }
139
140 QStyle::SCFlags buttonDown;
141 QPoint moveOffset;
142 QToolTip *toolTip;
143 bool act :1;
144 QWidget* window;
145 bool movable :1;
146 bool pressed :1;
147 bool autoraise :1;
148 QString cuttext;
149#ifdef QT_NO_WIDGET_TOPEXTRA
150 QString cap;
151#endif
152};
153
154QTitleBar::QTitleBar(QWidget* w, QWidget* parent, const char* name)
155 : QWidget( parent, name, WStyle_Customize | WStyle_NoBorder | WNoAutoErase )
156{
157 d = new QTitleBarPrivate();
158
159#ifndef QT_NO_TOOLTIP
160 d->toolTip = new QTitleBarTip( this );
161#endif
162 d->window = w;
163 d->buttonDown = QStyle::SC_None;
164 d->act = 0;
165 if ( w ) {
166 setWFlags( ((QTitleBar*)w)->getWFlags() | WNoAutoErase );
167 if ( w->minimumSize() == w->maximumSize() )
168 clearWFlags( WStyle_Maximize );
169#ifndef QT_NO_WIDGET_TOPEXTRA
170 setCaption( w->caption() );
171#endif
172 } else {
173 setWFlags( WStyle_Customize | WNoAutoErase );
174 }
175
176 readColors();
177 setSizePolicy( QSizePolicy( QSizePolicy::Expanding, QSizePolicy::Fixed ) );
178 setMouseTracking(TRUE);
179}
180
181QTitleBar::~QTitleBar()
182{
183#ifndef QT_NO_TOOLTIP
184 delete d->toolTip;
185#endif
186
187 delete d;
188 d = 0;
189}
190
191#ifdef Q_WS_WIN
192extern QRgb qt_colorref2qrgb(COLORREF col);
193#endif
194
195void QTitleBar::readColors()
196{
197 QPalette pal = palette();
198
199 bool colorsInitialized = FALSE;
200
201#ifdef Q_WS_WIN // ask system properties on windows
202#ifndef SPI_GETGRADIENTCAPTIONS
203#define SPI_GETGRADIENTCAPTIONS 0x1008
204#endif
205#ifndef COLOR_GRADIENTACTIVECAPTION
206#define COLOR_GRADIENTACTIVECAPTION 27
207#endif
208#ifndef COLOR_GRADIENTINACTIVECAPTION
209#define COLOR_GRADIENTINACTIVECAPTION 28
210#endif
211 if ( QApplication::desktopSettingsAware() ) {
212 pal.setColor( QPalette::Active, QColorGroup::Highlight, qt_colorref2qrgb(GetSysColor(COLOR_ACTIVECAPTION)) );
213 pal.setColor( QPalette::Inactive, QColorGroup::Highlight, qt_colorref2qrgb(GetSysColor(COLOR_INACTIVECAPTION)) );
214 pal.setColor( QPalette::Active, QColorGroup::HighlightedText, qt_colorref2qrgb(GetSysColor(COLOR_CAPTIONTEXT)) );
215 pal.setColor( QPalette::Inactive, QColorGroup::HighlightedText, qt_colorref2qrgb(GetSysColor(COLOR_INACTIVECAPTIONTEXT)) );
216 if ( qt_winver != Qt::WV_95 && qt_winver != WV_NT ) {
217 colorsInitialized = TRUE;
218 BOOL gradient;
219 QT_WA( {
220 SystemParametersInfo( SPI_GETGRADIENTCAPTIONS, 0, &gradient, 0 );
221 } , {
222 SystemParametersInfoA( SPI_GETGRADIENTCAPTIONS, 0, &gradient, 0 );
223 } );
224 if ( gradient ) {
225 pal.setColor( QPalette::Active, QColorGroup::Base, qt_colorref2qrgb(GetSysColor(COLOR_GRADIENTACTIVECAPTION)) );
226 pal.setColor( QPalette::Inactive, QColorGroup::Base, qt_colorref2qrgb(GetSysColor(COLOR_GRADIENTINACTIVECAPTION)) );
227 } else {
228 pal.setColor( QPalette::Active, QColorGroup::Base, palette().active().highlight() );
229 pal.setColor( QPalette::Inactive, QColorGroup::Base, palette().inactive().highlight() );
230 }
231 }
232 }
233#endif // Q_WS_WIN
234 if ( !colorsInitialized ) {
235 pal.setColor( QPalette::Active, QColorGroup::Highlight, palette().active().highlight() );
236 pal.setColor( QPalette::Active, QColorGroup::Base, palette().active().highlight() );
237 pal.setColor( QPalette::Inactive, QColorGroup::Highlight, palette().inactive().dark() );
238 pal.setColor( QPalette::Inactive, QColorGroup::Base, palette().inactive().dark() );
239 pal.setColor( QPalette::Inactive, QColorGroup::HighlightedText, palette().inactive().background() );
240 }
241
242 setPalette( pal );
243 setActive( d->act );
244}
245
246void QTitleBar::mousePressEvent( QMouseEvent * e)
247{
248 if ( !d->act )
249 emit doActivate();
250 if ( e->button() == LeftButton ) {
251 d->pressed = TRUE;
252 QStyle::SCFlags ctrl = style().querySubControl(QStyle::CC_TitleBar, this, e->pos());
253 switch (ctrl) {
254 case QStyle::SC_TitleBarSysMenu:
255 if ( testWFlags( WStyle_SysMenu ) && !testWFlags( WStyle_Tool ) ) {
256 d->buttonDown = QStyle::SC_None;
257 static QTime* t = 0;
258 static QTitleBar* tc = 0;
259 if ( !t )
260 t = new QTime;
261 if ( tc != this || t->elapsed() > QApplication::doubleClickInterval() ) {
262 emit showOperationMenu();
263 t->start();
264 tc = this;
265 } else {
266 tc = 0;
267 emit doClose();
268 return;
269 }
270 }
271 break;
272
273 case QStyle::SC_TitleBarShadeButton:
274 case QStyle::SC_TitleBarUnshadeButton:
275 if ( testWFlags( WStyle_MinMax ) && testWFlags( WStyle_Tool ) )
276 d->buttonDown = ctrl;
277 break;
278
279 case QStyle::SC_TitleBarNormalButton:
280 if( testWFlags( WStyle_Minimize ) && !testWFlags( WStyle_Tool ) )
281 d->buttonDown = ctrl;
282 break;
283
284 case QStyle::SC_TitleBarMinButton:
285 if( testWFlags( WStyle_Minimize ) && !testWFlags( WStyle_Tool ) )
286 d->buttonDown = ctrl;
287 break;
288
289 case QStyle::SC_TitleBarMaxButton:
290 if ( testWFlags( WStyle_Maximize ) && !testWFlags( WStyle_Tool ) )
291 d->buttonDown = ctrl;
292 break;
293
294 case QStyle::SC_TitleBarCloseButton:
295 if ( testWFlags( WStyle_SysMenu ) )
296 d->buttonDown = ctrl;
297 break;
298
299 case QStyle::SC_TitleBarLabel:
300 d->buttonDown = ctrl;
301 d->moveOffset = mapToParent( e->pos() );
302 break;
303
304 default:
305 break;
306 }
307 repaint( FALSE );
308 } else {
309 d->pressed = FALSE;
310 }
311}
312
313void QTitleBar::contextMenuEvent( QContextMenuEvent *e )
314{
315 QStyle::SCFlags ctrl = style().querySubControl(QStyle::CC_TitleBar, this, e->pos());
316 if( ctrl == QStyle::SC_TitleBarLabel || ctrl == QStyle::SC_TitleBarSysMenu )
317 emit popupOperationMenu(e->globalPos());
318 else
319 e->ignore();
320}
321
322void QTitleBar::mouseReleaseEvent( QMouseEvent * e)
323{
324 if ( e->button() == LeftButton && d->pressed) {
325 QStyle::SCFlags ctrl = style().querySubControl(QStyle::CC_TitleBar, this, e->pos());
326
327 if (ctrl == d->buttonDown) {
328 switch(ctrl) {
329 case QStyle::SC_TitleBarShadeButton:
330 case QStyle::SC_TitleBarUnshadeButton:
331 if( testWFlags( WStyle_MinMax ) && testWFlags( WStyle_Tool ) )
332 emit doShade();
333 break;
334
335 case QStyle::SC_TitleBarNormalButton:
336 if( testWFlags( WStyle_MinMax ) && !testWFlags( WStyle_Tool ) )
337 emit doNormal();
338 break;
339
340 case QStyle::SC_TitleBarMinButton:
341 if( testWFlags( WStyle_Minimize ) && !testWFlags( WStyle_Tool ) )
342 emit doMinimize();
343 break;
344
345 case QStyle::SC_TitleBarMaxButton:
346 if( d->window && testWFlags( WStyle_Maximize ) && !testWFlags( WStyle_Tool ) ) {
347 if(d->window->isMaximized())
348 emit doNormal();
349 else
350 emit doMaximize();
351 }
352 break;
353
354 case QStyle::SC_TitleBarCloseButton:
355 if( testWFlags( WStyle_SysMenu ) ) {
356 d->buttonDown = QStyle::SC_None;
357 repaint(FALSE);
358 emit doClose();
359 return;
360 }
361 break;
362
363 default:
364 break;
365 }
366 }
367 d->buttonDown = QStyle::SC_None;
368 repaint(FALSE);
369 d->pressed = FALSE;
370 }
371}
372
373void QTitleBar::mouseMoveEvent( QMouseEvent * e)
374{
375 switch (d->buttonDown) {
376 case QStyle::SC_None:
377 if(autoRaise())
378 repaint( FALSE );
379 break;
380 case QStyle::SC_TitleBarSysMenu:
381 break;
382 case QStyle::SC_TitleBarShadeButton:
383 case QStyle::SC_TitleBarUnshadeButton:
384 case QStyle::SC_TitleBarNormalButton:
385 case QStyle::SC_TitleBarMinButton:
386 case QStyle::SC_TitleBarMaxButton:
387 case QStyle::SC_TitleBarCloseButton:
388 {
389 QStyle::SCFlags last_ctrl = d->buttonDown;
390 d->buttonDown = style().querySubControl(QStyle::CC_TitleBar, this, e->pos());
391 if( d->buttonDown != last_ctrl)
392 d->buttonDown = QStyle::SC_None;
393 repaint(FALSE);
394 d->buttonDown = last_ctrl;
395 }
396 break;
397
398 case QStyle::SC_TitleBarLabel:
399 if ( d->buttonDown == QStyle::SC_TitleBarLabel && d->movable && d->pressed ) {
400 if ( (d->moveOffset - mapToParent( e->pos() ) ).manhattanLength() >= 4 ) {
401 QPoint p = mapFromGlobal(e->globalPos());
402#ifndef QT_NO_WORKSPACE
403 if(d->window && d->window->parentWidget()->inherits("QWorkspaceChild")) {
404 QWorkspace *workspace = ::qt_cast<QWorkspace*>(d->window->parentWidget()->parentWidget());
405 if(workspace) {
406 p = workspace->mapFromGlobal( e->globalPos() );
407 if ( !workspace->rect().contains(p) ) {
408 if ( p.x() < 0 )
409 p.rx() = 0;
410 if ( p.y() < 0 )
411 p.ry() = 0;
412 if ( p.x() > workspace->width() )
413 p.rx() = workspace->width();
414 if ( p.y() > workspace->height() )
415 p.ry() = workspace->height();
416 }
417 }
418 }
419#endif
420 QPoint pp = p - d->moveOffset;
421 if (!parentWidget()->isMaximized())
422 parentWidget()->move( pp );
423 }
424 } else {
425 QStyle::SCFlags last_ctrl = d->buttonDown;
426 d->buttonDown = QStyle::SC_None;
427 if( d->buttonDown != last_ctrl)
428 repaint(FALSE);
429 }
430 break;
431 }
432}
433
434void QTitleBar::resizeEvent( QResizeEvent *r)
435{
436 QWidget::resizeEvent(r);
437 cutText();
438}
439
440void QTitleBar::paintEvent(QPaintEvent *)
441{
442 QStyle::SCFlags ctrls = QStyle::SC_TitleBarLabel;
443 if ( testWFlags( WStyle_SysMenu) ) {
444 if ( testWFlags( WStyle_Tool ) ) {
445 ctrls |= QStyle::SC_TitleBarCloseButton;
446 if ( d->window && testWFlags( WStyle_MinMax ) ) {
447 if ( d->window->isMinimized() )
448 ctrls |= QStyle::SC_TitleBarUnshadeButton;
449 else
450 ctrls |= QStyle::SC_TitleBarShadeButton;
451 }
452 } else {
453 ctrls |= QStyle::SC_TitleBarSysMenu | QStyle::SC_TitleBarCloseButton;
454 if ( d->window && testWFlags( WStyle_Minimize ) ) {
455 if( d->window && d->window->isMinimized() )
456 ctrls |= QStyle::SC_TitleBarNormalButton;
457 else
458 ctrls |= QStyle::SC_TitleBarMinButton;
459 }
460 if ( d->window && testWFlags( WStyle_Maximize ) && !d->window->isMaximized() )
461 ctrls |= QStyle::SC_TitleBarMaxButton;
462 }
463 }
464
465 QStyle::SCFlags under_mouse = QStyle::SC_None;
466 if( autoRaise() && hasMouse() ) {
467 QPoint p(mapFromGlobal(QCursor::pos()));
468 under_mouse = style().querySubControl(QStyle::CC_TitleBar, this, p);
469 ctrls ^= under_mouse;
470 }
471
472 QSharedDoubleBuffer buffer( this, rect() );
473 style().drawComplexControl(QStyle::CC_TitleBar, buffer.painter(), this, rect(),
474 colorGroup(),
475 isEnabled() ? QStyle::Style_Enabled :
476 QStyle::Style_Default, ctrls, d->buttonDown);
477 if(under_mouse != QStyle::SC_None)
478 style().drawComplexControl(QStyle::CC_TitleBar, buffer.painter(), this, rect(),
479 colorGroup(),
480 QStyle::Style_MouseOver |
481 (isEnabled() ? QStyle::Style_Enabled : 0),
482 under_mouse, d->buttonDown);
483}
484
485void QTitleBar::mouseDoubleClickEvent( QMouseEvent *e )
486{
487 if ( e->button() != LeftButton )
488 return;
489
490 switch(style().querySubControl(QStyle::CC_TitleBar, this, e->pos())) {
491 case QStyle::SC_TitleBarLabel:
492 emit doubleClicked();
493 break;
494
495 case QStyle::SC_TitleBarSysMenu:
496 if ( testWFlags( WStyle_SysMenu ) )
497 emit doClose();
498 break;
499
500 default:
501 break;
502 }
503}
504
505#ifdef QT_NO_WIDGET_TOPEXTRA
506// We provide one, since titlebar is useless otherwise.
507QString QTitleBar::caption() const
508{
509 return d->cap;
510}
511#endif
512
513void QTitleBar::cutText()
514{
515 QFontMetrics fm( font() );
516
517 int maxw = style().querySubControlMetrics(QStyle::CC_TitleBar, this,
518 QStyle::SC_TitleBarLabel).width();
519 if ( !d->window )
520 maxw = width() - 20;
521 const QString txt = caption();
522 d->cuttext = txt;
523 if ( fm.width( txt + "m" ) > maxw ) {
524 int i = txt.length();
525 int dotlength = fm.width( "..." );
526 while ( i>0 && fm.width(txt.left( i )) + dotlength > maxw )
527 i--;
528 if(i != (int)txt.length())
529 d->cuttext = txt.left( i ) + "...";
530 }
531}
532
533void QTitleBar::setCaption( const QString& title )
534{
535 if( caption() == title)
536 return;
537#ifndef QT_NO_WIDGET_TOPEXTRA
538 QWidget::setCaption( title );
539#else
540 d->cap = title;
541#endif
542 cutText();
543
544 update();
545}
546
547
548void QTitleBar::setIcon( const QPixmap& icon )
549{
550#ifndef QT_NO_WIDGET_TOPEXTRA
551#ifndef QT_NO_IMAGE_SMOOTHSCALE
552 QRect menur = style().querySubControlMetrics(QStyle::CC_TitleBar, this,
553 QStyle::SC_TitleBarSysMenu);
554
555 QPixmap theIcon;
556 if (icon.width() > menur.width()) {
557 // try to keep something close to the same aspect
558 int aspect = (icon.height() * 100) / icon.width();
559 int newh = (aspect * menur.width()) / 100;
560 theIcon.convertFromImage( icon.convertToImage().smoothScale(menur.width(),
561 newh) );
562 } else if (icon.height() > menur.height()) {
563 // try to keep something close to the same aspect
564 int aspect = (icon.width() * 100) / icon.height();
565 int neww = (aspect * menur.height()) / 100;
566 theIcon.convertFromImage( icon.convertToImage().smoothScale(neww,
567 menur.height()) );
568 } else
569 theIcon = icon;
570
571 QWidget::setIcon( theIcon );
572#else
573 QWidget::setIcon( icon );
574#endif
575
576 update();
577#endif
578}
579
580void QTitleBar::leaveEvent( QEvent * )
581{
582 if(autoRaise() && !d->pressed)
583 repaint( FALSE );
584}
585
586void QTitleBar::enterEvent( QEvent * )
587{
588 if(autoRaise() && !d->pressed)
589 repaint( FALSE );
590 QEvent e( QEvent::Leave );
591 QApplication::sendEvent( parentWidget(), &e );
592}
593
594void QTitleBar::setActive( bool active )
595{
596 if ( d->act == active )
597 return ;
598
599 d->act = active;
600 update();
601}
602
603bool QTitleBar::isActive() const
604{
605 return d->act;
606}
607
608bool QTitleBar::usesActiveColor() const
609{
610 return ( isActive() && isActiveWindow() ) ||
611 ( !window() && topLevelWidget()->isActiveWindow() );
612}
613
614QString QTitleBar::visibleText() const
615{
616 return d->cuttext;
617}
618
619QWidget *QTitleBar::window() const
620{
621 return d->window;
622}
623
624bool QTitleBar::event( QEvent* e )
625{
626 if ( e->type() == QEvent::ApplicationPaletteChange ) {
627 readColors();
628 return TRUE;
629 } else if ( e->type() == QEvent::WindowActivate ) {
630 setActive( d->act );
631 } else if ( e->type() == QEvent::WindowDeactivate ) {
632 bool wasActive = d->act;
633 setActive( FALSE );
634 d->act = wasActive;
635 }
636
637 return QWidget::event( e );
638}
639
640void QTitleBar::setMovable(bool b)
641{
642 d->movable = b;
643}
644
645bool QTitleBar::isMovable() const
646{
647 return d->movable;
648}
649
650void QTitleBar::setAutoRaise(bool b)
651{
652 d->autoraise = b;
653}
654
655bool QTitleBar::autoRaise() const
656{
657 return d->autoraise;
658}
659
660QSize QTitleBar::sizeHint() const
661{
662 constPolish();
663 QRect menur = style().querySubControlMetrics(QStyle::CC_TitleBar, this,
664 QStyle::SC_TitleBarSysMenu);
665 return QSize( menur.width(), style().pixelMetric( QStyle::PM_TitleBarHeight, this ) );
666}
667
668#endif //QT_NO_TITLEBAR
Note: See TracBrowser for help on using the repository browser.