source: trunk/src/gui/graphicsview/qgraphicswidget_p.cpp@ 661

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

trunk: Merged in qt 4.6.2 sources.

File size: 28.9 KB
Line 
1/****************************************************************************
2**
3** Copyright (C) 2010 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 QtGui 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 "qglobal.h"
43
44#ifndef QT_NO_GRAPHICSVIEW
45
46#include <QtCore/qdebug.h>
47#include "qgraphicswidget_p.h"
48#include "qgraphicslayout.h"
49#include "qgraphicsscene_p.h"
50#include <QtGui/qapplication.h>
51#include <QtGui/qgraphicsscene.h>
52#include <QtGui/qstyleoption.h>
53#include <QtGui/QStyleOptionTitleBar>
54#include <QtGui/QGraphicsSceneMouseEvent>
55#if defined(Q_WS_MAC) && !defined(QT_NO_STYLE_MAC)
56# include <QMacStyle>
57#endif
58
59QT_BEGIN_NAMESPACE
60
61void QGraphicsWidgetPrivate::init(QGraphicsItem *parentItem, Qt::WindowFlags wFlags)
62{
63 Q_Q(QGraphicsWidget);
64
65 attributes = 0;
66 isWidget = 1; // QGraphicsItem::isWidget() returns true.
67 focusNext = focusPrev = q;
68 focusPolicy = Qt::NoFocus;
69
70 adjustWindowFlags(&wFlags);
71 windowFlags = wFlags;
72
73 q->setParentItem(parentItem);
74 q->setSizePolicy(QSizePolicy(QSizePolicy::Preferred, QSizePolicy::Preferred, QSizePolicy::DefaultType));
75 q->setGraphicsItem(q);
76
77 resolveLayoutDirection();
78 q->unsetWindowFrameMargins();
79 q->setFlag(QGraphicsItem::ItemUsesExtendedStyleOption);
80 q->setFlag(QGraphicsItem::ItemSendsGeometryChanges);
81}
82
83qreal QGraphicsWidgetPrivate::titleBarHeight(const QStyleOptionTitleBar &options) const
84{
85 Q_Q(const QGraphicsWidget);
86 int height = q->style()->pixelMetric(QStyle::PM_TitleBarHeight, &options);
87#if defined(Q_WS_MAC) && !defined(QT_NO_STYLE_MAC)
88 if (qobject_cast<QMacStyle*>(q->style())) {
89 height -=4;
90 }
91#endif
92 return (qreal)height;
93}
94
95/*!
96 \internal
97*/
98QGraphicsWidgetPrivate::~QGraphicsWidgetPrivate()
99{
100 // Remove any lazily allocated data
101 delete[] margins;
102 delete[] windowFrameMargins;
103 delete windowData;
104}
105
106/*!
107 \internal
108
109 Ensures that margins is allocated.
110 This function must be called before any dereferencing.
111*/
112void QGraphicsWidgetPrivate::ensureMargins() const
113{
114 if (!margins) {
115 margins = new qreal[4];
116 for (int i = 0; i < 4; ++i)
117 margins[i] = 0;
118 }
119}
120
121/*!
122 \internal
123
124 Ensures that windowFrameMargins is allocated.
125 This function must be called before any dereferencing.
126*/
127void QGraphicsWidgetPrivate::ensureWindowFrameMargins() const
128{
129 if (!windowFrameMargins) {
130 windowFrameMargins = new qreal[4];
131 for (int i = 0; i < 4; ++i)
132 windowFrameMargins[i] = 0;
133 }
134}
135
136/*!
137 \internal
138
139 Ensures that windowData is allocated.
140 This function must be called before any dereferencing.
141*/
142void QGraphicsWidgetPrivate::ensureWindowData()
143{
144 if (!windowData)
145 windowData = new WindowData;
146}
147
148void QGraphicsWidgetPrivate::setPalette_helper(const QPalette &palette)
149{
150 if (this->palette == palette && this->palette.resolve() == palette.resolve())
151 return;
152 updatePalette(palette);
153}
154
155void QGraphicsWidgetPrivate::resolvePalette(uint inheritedMask)
156{
157 inheritedPaletteResolveMask = inheritedMask;
158 QPalette naturalPalette = naturalWidgetPalette();
159 QPalette resolvedPalette = palette.resolve(naturalPalette);
160 updatePalette(resolvedPalette);
161}
162
163void QGraphicsWidgetPrivate::updatePalette(const QPalette &palette)
164{
165 Q_Q(QGraphicsWidget);
166 // Update local palette setting.
167 this->palette = palette;
168
169 // Calculate new mask.
170 if (q->isWindow() && !q->testAttribute(Qt::WA_WindowPropagation))
171 inheritedPaletteResolveMask = 0;
172 int mask = palette.resolve() | inheritedPaletteResolveMask;
173
174 // Propagate to children.
175 for (int i = 0; i < children.size(); ++i) {
176 QGraphicsItem *item = children.at(i);
177 if (item->isWidget()) {
178 QGraphicsWidget *w = static_cast<QGraphicsWidget *>(item);
179 if (!w->isWindow() || w->testAttribute(Qt::WA_WindowPropagation))
180 w->d_func()->resolvePalette(mask);
181 } else {
182 item->d_ptr->resolvePalette(mask);
183 }
184 }
185
186 // Notify change.
187 QEvent event(QEvent::PaletteChange);
188 QApplication::sendEvent(q, &event);
189}
190
191void QGraphicsWidgetPrivate::setLayoutDirection_helper(Qt::LayoutDirection direction)
192{
193 Q_Q(QGraphicsWidget);
194 if ((direction == Qt::RightToLeft) == (testAttribute(Qt::WA_RightToLeft)))
195 return;
196 q->setAttribute(Qt::WA_RightToLeft, (direction == Qt::RightToLeft));
197
198 // Propagate this change to all children.
199 for (int i = 0; i < children.size(); ++i) {
200 QGraphicsItem *item = children.at(i);
201 if (item->isWidget()) {
202 QGraphicsWidget *widget = static_cast<QGraphicsWidget *>(item);
203 if (widget->parentWidget() && !widget->testAttribute(Qt::WA_SetLayoutDirection))
204 widget->d_func()->setLayoutDirection_helper(direction);
205 }
206 }
207
208 // Send the notification event to this widget item.
209 QEvent e(QEvent::LayoutDirectionChange);
210 QApplication::sendEvent(q, &e);
211}
212
213void QGraphicsWidgetPrivate::resolveLayoutDirection()
214{
215 Q_Q(QGraphicsWidget);
216 if (q->testAttribute(Qt::WA_SetLayoutDirection)) {
217 return;
218 }
219 if (QGraphicsWidget *parentWidget = q->parentWidget()) {
220 setLayoutDirection_helper(parentWidget->layoutDirection());
221 } else if (scene) {
222 // ### shouldn't the scene have a layoutdirection really? how does
223 // ### QGraphicsWidget get changes from QApplication::layoutDirection?
224 setLayoutDirection_helper(QApplication::layoutDirection());
225 } else {
226 setLayoutDirection_helper(QApplication::layoutDirection());
227 }
228}
229
230QPalette QGraphicsWidgetPrivate::naturalWidgetPalette() const
231{
232 Q_Q(const QGraphicsWidget);
233 QPalette palette;
234 if (QGraphicsWidget *parent = q->parentWidget()) {
235 palette = parent->palette();
236 } else if (scene) {
237 palette = scene->palette();
238 }
239 palette.resolve(0);
240 return palette;
241}
242
243void QGraphicsWidgetPrivate::setFont_helper(const QFont &font)
244{
245 if (this->font == font && this->font.resolve() == font.resolve())
246 return;
247 updateFont(font);
248}
249
250void QGraphicsWidgetPrivate::resolveFont(uint inheritedMask)
251{
252 inheritedFontResolveMask = inheritedMask;
253 QFont naturalFont = naturalWidgetFont();
254 QFont resolvedFont = font.resolve(naturalFont);
255 updateFont(resolvedFont);
256}
257
258void QGraphicsWidgetPrivate::updateFont(const QFont &font)
259{
260 Q_Q(QGraphicsWidget);
261 // Update the local font setting.
262 this->font = font;
263
264 // Calculate new mask.
265 if (q->isWindow() && !q->testAttribute(Qt::WA_WindowPropagation))
266 inheritedFontResolveMask = 0;
267 int mask = font.resolve() | inheritedFontResolveMask;
268
269 // Propagate to children.
270 for (int i = 0; i < children.size(); ++i) {
271 QGraphicsItem *item = children.at(i);
272 if (item->isWidget()) {
273 QGraphicsWidget *w = static_cast<QGraphicsWidget *>(item);
274 if (!w->isWindow() || w->testAttribute(Qt::WA_WindowPropagation))
275 w->d_func()->resolveFont(mask);
276 } else {
277 item->d_ptr->resolveFont(mask);
278 }
279 }
280
281 if (!polished)
282 return;
283 // Notify change.
284 QEvent event(QEvent::FontChange);
285 QApplication::sendEvent(q, &event);
286}
287
288QFont QGraphicsWidgetPrivate::naturalWidgetFont() const
289{
290 Q_Q(const QGraphicsWidget);
291 QFont naturalFont; // ### no application font support
292 if (QGraphicsWidget *parent = q->parentWidget()) {
293 naturalFont = parent->font();
294 } else if (scene) {
295 naturalFont = scene->font();
296 }
297 naturalFont.resolve(0);
298 return naturalFont;
299}
300
301void QGraphicsWidgetPrivate::initStyleOptionTitleBar(QStyleOptionTitleBar *option)
302{
303 Q_Q(QGraphicsWidget);
304 ensureWindowData();
305 q->initStyleOption(option);
306 option->rect.setHeight(titleBarHeight(*option));
307 option->titleBarFlags = windowFlags;
308 option->subControls = QStyle::SC_TitleBarCloseButton | QStyle::SC_TitleBarLabel | QStyle::SC_TitleBarSysMenu;
309 option->activeSubControls = windowData->hoveredSubControl;
310 bool isActive = q->isActiveWindow();
311 if (isActive) {
312 option->state |= QStyle::State_Active;
313 option->titleBarState = Qt::WindowActive;
314 option->titleBarState |= QStyle::State_Active;
315 } else {
316 option->state &= ~QStyle::State_Active;
317 option->titleBarState = Qt::WindowNoState;
318 }
319 QFont windowTitleFont = QApplication::font("QWorkspaceTitleBar");
320 QRect textRect = q->style()->subControlRect(QStyle::CC_TitleBar, option, QStyle::SC_TitleBarLabel, 0);
321 option->text = QFontMetrics(windowTitleFont).elidedText(
322 windowData->windowTitle, Qt::ElideRight, textRect.width());
323}
324
325void QGraphicsWidgetPrivate::adjustWindowFlags(Qt::WindowFlags *flags)
326{
327 bool customize = (*flags & (Qt::CustomizeWindowHint
328 | Qt::FramelessWindowHint
329 | Qt::WindowTitleHint
330 | Qt::WindowSystemMenuHint
331 | Qt::WindowMinimizeButtonHint
332 | Qt::WindowMaximizeButtonHint
333 | Qt::WindowContextHelpButtonHint));
334
335 uint type = (*flags & Qt::WindowType_Mask);
336 if (customize)
337 ;
338 else if (type == Qt::Dialog || type == Qt::Sheet)
339 *flags |= Qt::WindowTitleHint | Qt::WindowSystemMenuHint | Qt::WindowContextHelpButtonHint;
340 else if (type == Qt::Tool)
341 *flags |= Qt::WindowTitleHint | Qt::WindowSystemMenuHint;
342 else if (type == Qt::Window || type == Qt::SubWindow)
343 *flags |= Qt::WindowTitleHint | Qt::WindowSystemMenuHint
344 | Qt::WindowMinimizeButtonHint | Qt::WindowMaximizeButtonHint;
345}
346
347void QGraphicsWidgetPrivate::windowFrameMouseReleaseEvent(QGraphicsSceneMouseEvent *event)
348{
349 Q_Q(QGraphicsWidget);
350 ensureWindowData();
351 if (windowData->grabbedSection != Qt::NoSection) {
352 if (windowData->grabbedSection == Qt::TitleBarArea) {
353 windowData->buttonSunken = false;
354 QStyleOptionTitleBar bar;
355 initStyleOptionTitleBar(&bar);
356 // make sure that the coordinates (rect and pos) we send to the style are positive.
357 bar.rect = q->windowFrameRect().toRect();
358 bar.rect.moveTo(0,0);
359 bar.rect.setHeight(q->style()->pixelMetric(QStyle::PM_TitleBarHeight, &bar));
360 QPointF pos = event->pos();
361 if (windowFrameMargins) {
362 pos.rx() += windowFrameMargins[Left];
363 pos.ry() += windowFrameMargins[Top];
364 }
365 bar.subControls = QStyle::SC_TitleBarCloseButton;
366 if (q->style()->subControlRect(QStyle::CC_TitleBar, &bar,
367 QStyle::SC_TitleBarCloseButton,
368 event->widget()).contains(pos.toPoint())) {
369 q->close();
370 }
371 }
372 if (!(static_cast<QGraphicsSceneMouseEvent *>(event)->buttons()))
373 windowData->grabbedSection = Qt::NoSection;
374 event->accept();
375 }
376}
377
378void QGraphicsWidgetPrivate::windowFrameMousePressEvent(QGraphicsSceneMouseEvent *event)
379{
380 Q_Q(QGraphicsWidget);
381 if (event->button() != Qt::LeftButton)
382 return;
383
384 ensureWindowData();
385 windowData->startGeometry = q->geometry();
386 windowData->grabbedSection = q->windowFrameSectionAt(event->pos());
387 ensureWindowData();
388 if (windowData->grabbedSection == Qt::TitleBarArea
389 && windowData->hoveredSubControl == QStyle::SC_TitleBarCloseButton) {
390 windowData->buttonSunken = true;
391 q->update();
392 }
393 event->setAccepted(windowData->grabbedSection != Qt::NoSection);
394}
395
396/*!
397 Used to calculate the
398 Precondition:
399 \a widget should support either hfw or wfh
400
401 If \a heightForWidth is set to false, this function will query the width for height
402 instead. \a width will then be interpreted as height, \a minh and \a maxh will be interpreted
403 as minimum width and maximum width.
404 */
405static qreal minimumHeightForWidth(qreal width, qreal minh, qreal maxh,
406 const QGraphicsWidget *widget,
407 bool heightForWidth = true)
408{
409 qreal minimumHeightForWidth = -1;
410 const QSizePolicy sp = widget->layout() ? widget->layout()->sizePolicy() : widget->sizePolicy();
411 const bool hasHFW = sp.hasHeightForWidth();
412 if (hasHFW == heightForWidth) {
413 minimumHeightForWidth = hasHFW
414 ? widget->effectiveSizeHint(Qt::MinimumSize, QSizeF(width, -1)).height()
415 : widget->effectiveSizeHint(Qt::MinimumSize, QSizeF(-1, width)).width(); //"width" is here height!
416 } else {
417 // widthForHeight
418 const qreal constraint = width;
419 while (maxh - minh > 0.1) {
420 qreal middle = minh + (maxh - minh)/2;
421 // ### really bad, if we are a widget with a layout it will call
422 // layout->effectiveSizeHint(Qt::MiniumumSize), which again will call
423 // sizeHint three times because of how the cache works
424 qreal hfw = hasHFW
425 ? widget->effectiveSizeHint(Qt::MinimumSize, QSizeF(middle, -1)).height()
426 : widget->effectiveSizeHint(Qt::MinimumSize, QSizeF(-1, middle)).width();
427 if (hfw > constraint) {
428 minh = middle;
429 } else if (hfw <= constraint) {
430 maxh = middle;
431 }
432 }
433 minimumHeightForWidth = maxh;
434 }
435 return minimumHeightForWidth;
436}
437
438static qreal minimumWidthForHeight(qreal height, qreal minw, qreal maxw,
439 const QGraphicsWidget *widget)
440{
441 return minimumHeightForWidth(height, minw, maxw, widget, false);
442}
443
444static QSizeF closestAcceptableSize(const QSizeF &proposed,
445 const QGraphicsWidget *widget)
446{
447 const QSizeF current = widget->size();
448
449 qreal minw = proposed.width();
450 qreal maxw = current.width();
451 qreal minh = proposed.height();
452 qreal maxh = current.height();
453
454 qreal middlew = maxw;
455 qreal middleh = maxh;
456 qreal min_hfw;
457 min_hfw = minimumHeightForWidth(maxw, minh, maxh, widget);
458
459 do {
460 if (maxw - minw < 0.1) {
461 // we still havent found anything, cut off binary search
462 minw = maxw;
463 minh = maxh;
464 }
465 middlew = minw + (maxw - minw)/2.0;
466 middleh = minh + (maxh - minh)/2.0;
467
468 min_hfw = minimumHeightForWidth(middlew, minh, maxh, widget);
469
470 if (min_hfw > middleh) {
471 minw = middlew;
472 minh = middleh;
473 } else if (min_hfw <= middleh) {
474 maxw = middlew;
475 maxh = middleh;
476 }
477 } while (maxw != minw);
478
479 min_hfw = minimumHeightForWidth(middlew, minh, maxh, widget);
480
481 QSizeF result;
482 if (min_hfw < maxh) {
483 result = QSizeF(middlew, min_hfw);
484 } else {
485 // Needed because of the cut-off we do above.
486 result = QSizeF(minimumWidthForHeight(maxh, proposed.width(), current.width(), widget), maxh);
487 }
488 return result;
489}
490
491static void _q_boundGeometryToSizeConstraints(const QRectF &startGeometry,
492 QRectF *rect, Qt::WindowFrameSection section,
493 const QSizeF &min, const QSizeF &max,
494 const QGraphicsWidget *widget)
495{
496 const QRectF proposedRect = *rect;
497 qreal width = qBound(min.width(), proposedRect.width(), max.width());
498 qreal height = qBound(min.height(), proposedRect.height(), max.height());
499
500 QSizePolicy sp = widget->sizePolicy();
501 if (const QGraphicsLayout *l = widget->layout()) {
502 sp = l->sizePolicy();
503 }
504 const bool hasHFW = sp.hasHeightForWidth(); // || sp.hasWidthForHeight();
505
506 const bool widthChanged = proposedRect.width() < widget->size().width();
507 const bool heightChanged = proposedRect.height() < widget->size().height();
508
509 if (hasHFW) {
510 if (widthChanged || heightChanged) {
511 const qreal minh = min.height();
512 const qreal maxh = max.height();
513 const qreal proposedHFW = minimumHeightForWidth(width, minh, maxh, widget);
514 if (proposedHFW > proposedRect.height()) {
515 QSizeF effectiveSize = closestAcceptableSize(QSizeF(width, height), widget);
516 width = effectiveSize.width();
517 height = effectiveSize.height();
518 }
519 }
520 }
521
522 switch (section) {
523 case Qt::LeftSection:
524 rect->setRect(startGeometry.right() - qRound(width), startGeometry.top(),
525 qRound(width), startGeometry.height());
526 break;
527 case Qt::TopLeftSection:
528 rect->setRect(startGeometry.right() - qRound(width), startGeometry.bottom() - qRound(height),
529 qRound(width), qRound(height));
530 break;
531 case Qt::TopSection:
532 rect->setRect(startGeometry.left(), startGeometry.bottom() - qRound(height),
533 startGeometry.width(), qRound(height));
534 break;
535 case Qt::TopRightSection:
536 rect->setTop(rect->bottom() - qRound(height));
537 rect->setWidth(qRound(width));
538 break;
539 case Qt::RightSection:
540 rect->setWidth(qRound(width));
541 break;
542 case Qt::BottomRightSection:
543 rect->setWidth(qRound(width));
544 rect->setHeight(qRound(height));
545 break;
546 case Qt::BottomSection:
547 rect->setHeight(qRound(height));
548 break;
549 case Qt::BottomLeftSection:
550 rect->setRect(startGeometry.right() - qRound(width), startGeometry.top(),
551 qRound(width), qRound(height));
552 break;
553 default:
554 break;
555 }
556}
557
558void QGraphicsWidgetPrivate::windowFrameMouseMoveEvent(QGraphicsSceneMouseEvent *event)
559{
560 Q_Q(QGraphicsWidget);
561 ensureWindowData();
562 if (!(event->buttons() & Qt::LeftButton) || windowData->hoveredSubControl != QStyle::SC_TitleBarLabel)
563 return;
564
565 QLineF delta(q->mapFromScene(event->buttonDownScenePos(Qt::LeftButton)), event->pos());
566 QLineF parentDelta(q->mapToParent(delta.p1()), q->mapToParent(delta.p2()));
567 QLineF parentXDelta(q->mapToParent(QPointF(delta.p1().x(), 0)), q->mapToParent(QPointF(delta.p2().x(), 0)));
568 QLineF parentYDelta(q->mapToParent(QPointF(0, delta.p1().y())), q->mapToParent(QPointF(0, delta.p2().y())));
569
570 QRectF newGeometry;
571 switch (windowData->grabbedSection) {
572 case Qt::LeftSection:
573 newGeometry = QRectF(windowData->startGeometry.topLeft()
574 + QPointF(parentXDelta.dx(), parentXDelta.dy()),
575 windowData->startGeometry.size() - QSizeF(delta.dx(), delta.dy()));
576 break;
577 case Qt::TopLeftSection:
578 newGeometry = QRectF(windowData->startGeometry.topLeft()
579 + QPointF(parentDelta.dx(), parentDelta.dy()),
580 windowData->startGeometry.size() - QSizeF(delta.dx(), delta.dy()));
581 break;
582 case Qt::TopSection:
583 newGeometry = QRectF(windowData->startGeometry.topLeft()
584 + QPointF(parentYDelta.dx(), parentYDelta.dy()),
585 windowData->startGeometry.size() - QSizeF(0, delta.dy()));
586 break;
587 case Qt::TopRightSection:
588 newGeometry = QRectF(windowData->startGeometry.topLeft()
589 + QPointF(parentYDelta.dx(), parentYDelta.dy()),
590 windowData->startGeometry.size() - QSizeF(-delta.dx(), delta.dy()));
591 break;
592 case Qt::RightSection:
593 newGeometry = QRectF(windowData->startGeometry.topLeft(),
594 windowData->startGeometry.size() + QSizeF(delta.dx(), 0));
595 break;
596 case Qt::BottomRightSection:
597 newGeometry = QRectF(windowData->startGeometry.topLeft(),
598 windowData->startGeometry.size() + QSizeF(delta.dx(), delta.dy()));
599 break;
600 case Qt::BottomSection:
601 newGeometry = QRectF(windowData->startGeometry.topLeft(),
602 windowData->startGeometry.size() + QSizeF(0, delta.dy()));
603 break;
604 case Qt::BottomLeftSection:
605 newGeometry = QRectF(windowData->startGeometry.topLeft()
606 + QPointF(parentXDelta.dx(), parentXDelta.dy()),
607 windowData->startGeometry.size() - QSizeF(delta.dx(), -delta.dy()));
608 break;
609 case Qt::TitleBarArea:
610 newGeometry = QRectF(windowData->startGeometry.topLeft()
611 + QPointF(parentDelta.dx(), parentDelta.dy()),
612 windowData->startGeometry.size());
613 break;
614 case Qt::NoSection:
615 break;
616 }
617
618 if (windowData->grabbedSection != Qt::NoSection) {
619 _q_boundGeometryToSizeConstraints(windowData->startGeometry, &newGeometry,
620 windowData->grabbedSection,
621 q->effectiveSizeHint(Qt::MinimumSize),
622 q->effectiveSizeHint(Qt::MaximumSize),
623 q);
624 q->setGeometry(newGeometry);
625 }
626}
627
628void QGraphicsWidgetPrivate::windowFrameHoverMoveEvent(QGraphicsSceneHoverEvent *event)
629{
630 Q_Q(QGraphicsWidget);
631 if (!hasDecoration())
632 return;
633
634 ensureWindowData();
635
636 if (q->rect().contains(event->pos())) {
637 if (windowData->buttonMouseOver || windowData->hoveredSubControl != QStyle::SC_None)
638 windowFrameHoverLeaveEvent(event);
639 return;
640 }
641
642 bool wasMouseOver = windowData->buttonMouseOver;
643 QRect oldButtonRect = windowData->buttonRect;
644 windowData->buttonRect = QRect();
645 windowData->buttonMouseOver = false;
646 QPointF pos = event->pos();
647 QStyleOptionTitleBar bar;
648 // make sure that the coordinates (rect and pos) we send to the style are positive.
649 if (windowFrameMargins) {
650 pos.rx() += windowFrameMargins[Left];
651 pos.ry() += windowFrameMargins[Top];
652 }
653 initStyleOptionTitleBar(&bar);
654 bar.rect = q->windowFrameRect().toRect();
655 bar.rect.moveTo(0,0);
656 bar.rect.setHeight(int(titleBarHeight(bar)));
657
658 Qt::CursorShape cursorShape = Qt::ArrowCursor;
659 bool needsSetCursorCall = true;
660 switch (q->windowFrameSectionAt(event->pos())) {
661 case Qt::TopLeftSection:
662 case Qt::BottomRightSection:
663 cursorShape = Qt::SizeFDiagCursor;
664 break;
665 case Qt::TopRightSection:
666 case Qt::BottomLeftSection:
667 cursorShape = Qt::SizeBDiagCursor;
668 break;
669 case Qt::LeftSection:
670 case Qt::RightSection:
671 cursorShape = Qt::SizeHorCursor;
672 break;
673 case Qt::TopSection:
674 case Qt::BottomSection:
675 cursorShape = Qt::SizeVerCursor;
676 break;
677 case Qt::TitleBarArea:
678 windowData->buttonRect = q->style()->subControlRect(
679 QStyle::CC_TitleBar, &bar, QStyle::SC_TitleBarCloseButton, 0);
680#ifdef Q_WS_MAC
681 // On mac we should hover if we are in the 'area' of the buttons
682 windowData->buttonRect |= q->style()->subControlRect(
683 QStyle::CC_TitleBar, &bar, QStyle::SC_TitleBarMinButton, 0);
684 windowData->buttonRect |= q->style()->subControlRect(
685 QStyle::CC_TitleBar, &bar, QStyle::SC_TitleBarMaxButton, 0);
686#endif
687 if (windowData->buttonRect.contains(pos.toPoint()))
688 windowData->buttonMouseOver = true;
689 event->ignore();
690 break;
691 default:
692 needsSetCursorCall = false;
693 event->ignore();
694 }
695#ifndef QT_NO_CURSOR
696 if (needsSetCursorCall)
697 q->setCursor(cursorShape);
698#endif
699 // update buttons if we hover over them
700 windowData->hoveredSubControl = q->style()->hitTestComplexControl(QStyle::CC_TitleBar, &bar, pos.toPoint(), 0);
701 if (windowData->hoveredSubControl != QStyle::SC_TitleBarCloseButton)
702 windowData->hoveredSubControl = QStyle::SC_TitleBarLabel;
703
704 if (windowData->buttonMouseOver != wasMouseOver) {
705 if (!oldButtonRect.isNull())
706 q->update(QRectF(oldButtonRect).translated(q->windowFrameRect().topLeft()));
707 if (!windowData->buttonRect.isNull())
708 q->update(QRectF(windowData->buttonRect).translated(q->windowFrameRect().topLeft()));
709 }
710}
711
712void QGraphicsWidgetPrivate::windowFrameHoverLeaveEvent(QGraphicsSceneHoverEvent *event)
713{
714 Q_UNUSED(event);
715 Q_Q(QGraphicsWidget);
716 if (hasDecoration()) {
717 // ### restore the cursor, don't override it
718#ifndef QT_NO_CURSOR
719 q->unsetCursor();
720#endif
721
722 ensureWindowData();
723
724 bool needsUpdate = false;
725 if (windowData->hoveredSubControl == QStyle::SC_TitleBarCloseButton
726 || windowData->buttonMouseOver)
727 needsUpdate = true;
728
729 // update the hover state (of buttons etc...)
730 windowData->hoveredSubControl = QStyle::SC_None;
731 windowData->buttonMouseOver = false;
732 windowData->buttonRect = QRect();
733 if (needsUpdate)
734 q->update(windowData->buttonRect);
735 }
736}
737
738bool QGraphicsWidgetPrivate::hasDecoration() const
739{
740 return (windowFlags & Qt::Window) && (windowFlags & Qt::WindowTitleHint);
741}
742
743/**
744 * is called after a reparent has taken place to fix up the focus chain(s)
745 */
746void QGraphicsWidgetPrivate::fixFocusChainBeforeReparenting(QGraphicsWidget *newParent, QGraphicsScene *oldScene, QGraphicsScene *newScene)
747{
748 Q_Q(QGraphicsWidget);
749
750 Q_ASSERT(focusNext && focusPrev);
751
752 QGraphicsWidget *n = q; //last one in 'new' list
753 QGraphicsWidget *o = 0; //last one in 'old' list
754
755 QGraphicsWidget *w = focusNext;
756
757 QGraphicsWidget *firstOld = 0;
758 bool wasPreviousNew = true;
759
760 while (w != q) {
761 bool isCurrentNew = q->isAncestorOf(w);
762 if (isCurrentNew) {
763 if (!wasPreviousNew) {
764 n->d_func()->focusNext = w;
765 w->d_func()->focusPrev = n;
766 }
767 n = w;
768 } else /*if (!isCurrentNew)*/ {
769 if (wasPreviousNew) {
770 if (o) {
771 o->d_func()->focusNext = w;
772 w->d_func()->focusPrev = o;
773 } else {
774 firstOld = w;
775 }
776 }
777 o = w;
778 }
779 w = w->d_func()->focusNext;
780 wasPreviousNew = isCurrentNew;
781 }
782
783 // repair the 'old' chain
784 if (firstOld) {
785 o->d_func()->focusNext = firstOld;
786 firstOld->d_func()->focusPrev = o;
787 }
788
789 // update tabFocusFirst for oldScene if the item is going to be removed from oldScene
790 if (newParent)
791 newScene = newParent->scene();
792
793 if (oldScene && newScene != oldScene)
794 oldScene->d_func()->tabFocusFirst = firstOld;
795
796 QGraphicsItem *topLevelItem = newParent ? newParent->topLevelItem() : 0;
797 QGraphicsWidget *topLevel = 0;
798 if (topLevelItem && topLevelItem->isWidget())
799 topLevel = static_cast<QGraphicsWidget *>(topLevelItem);
800
801 if (topLevel && newParent) {
802 QGraphicsWidget *last = topLevel->d_func()->focusPrev;
803 // link last with new chain
804 last->d_func()->focusNext = q;
805 focusPrev = last;
806
807 // link last in chain with
808 topLevel->d_func()->focusPrev = n;
809 n->d_func()->focusNext = topLevel;
810 } else {
811 // q is the start of the focus chain
812 n->d_func()->focusNext = q;
813 focusPrev = n;
814 }
815
816}
817
818void QGraphicsWidgetPrivate::setLayout_helper(QGraphicsLayout *l)
819{
820 delete (this->layout);
821 layout = l;
822 if (!l) {
823 Q_Q(QGraphicsWidget);
824 q->updateGeometry();
825 }
826}
827
828QT_END_NAMESPACE
829
830#endif //QT_NO_GRAPHICSVIEW
Note: See TracBrowser for help on using the repository browser.