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