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

Last change on this file was 846, checked in by Dmitry A. Kuminov, 14 years ago

trunk: Merged in qt 4.7.2 sources from branches/vendor/nokia/qt.

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