/**************************************************************************** | |
** | |
** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). | |
** All rights reserved. | |
** Contact: Nokia Corporation (qt-info@nokia.com) | |
** | |
** This file is part of the QtGui module of the Qt Toolkit. | |
** | |
** $QT_BEGIN_LICENSE:LGPL$ | |
** GNU Lesser General Public License Usage | |
** This file may be used under the terms of the GNU Lesser General Public | |
** License version 2.1 as published by the Free Software Foundation and | |
** appearing in the file LICENSE.LGPL included in the packaging of this | |
** file. Please review the following information to ensure the GNU Lesser | |
** General Public License version 2.1 requirements will be met: | |
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. | |
** | |
** In addition, as a special exception, Nokia gives you certain additional | |
** rights. These rights are described in the Nokia Qt LGPL Exception | |
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. | |
** | |
** GNU General Public License Usage | |
** Alternatively, this file may be used under the terms of the GNU General | |
** Public License version 3.0 as published by the Free Software Foundation | |
** and appearing in the file LICENSE.GPL included in the packaging of this | |
** file. Please review the following information to ensure the GNU General | |
** Public License version 3.0 requirements will be met: | |
** http://www.gnu.org/copyleft/gpl.html. | |
** | |
** Other Usage | |
** Alternatively, this file may be used in accordance with the terms and | |
** conditions contained in a signed written agreement between you and Nokia. | |
** | |
** | |
** | |
** | |
** | |
** $QT_END_LICENSE$ | |
** | |
****************************************************************************/ | |
#include "qglobal.h" | |
#ifndef QT_NO_GRAPHICSVIEW | |
#include <QtCore/qdebug.h> | |
#include <QtCore/qnumeric.h> | |
#include "qgraphicswidget_p.h" | |
#include "qgraphicslayout.h" | |
#include "qgraphicsscene_p.h" | |
#include <QtGui/qapplication.h> | |
#include <QtGui/qgraphicsscene.h> | |
#include <QtGui/qstyleoption.h> | |
#include <QtGui/QStyleOptionTitleBar> | |
#include <QtGui/QGraphicsSceneMouseEvent> | |
#if defined(Q_WS_MAC) && !defined(QT_NO_STYLE_MAC) | |
# include <QMacStyle> | |
#endif | |
QT_BEGIN_NAMESPACE | |
void QGraphicsWidgetPrivate::init(QGraphicsItem *parentItem, Qt::WindowFlags wFlags) | |
{ | |
Q_Q(QGraphicsWidget); | |
attributes = 0; | |
isWidget = 1; // QGraphicsItem::isWidget() returns true. | |
focusNext = focusPrev = q; | |
focusPolicy = Qt::NoFocus; | |
adjustWindowFlags(&wFlags); | |
windowFlags = wFlags; | |
if (parentItem) | |
setParentItemHelper(parentItem, 0, 0); | |
q->setSizePolicy(QSizePolicy(QSizePolicy::Preferred, QSizePolicy::Preferred, QSizePolicy::DefaultType)); | |
q->setGraphicsItem(q); | |
resolveLayoutDirection(); | |
q->unsetWindowFrameMargins(); | |
flags |= QGraphicsItem::ItemUsesExtendedStyleOption; | |
flags |= QGraphicsItem::ItemSendsGeometryChanges; | |
if (windowFlags & Qt::Window) | |
flags |= QGraphicsItem::ItemIsPanel; | |
} | |
qreal QGraphicsWidgetPrivate::titleBarHeight(const QStyleOptionTitleBar &options) const | |
{ | |
Q_Q(const QGraphicsWidget); | |
int height = q->style()->pixelMetric(QStyle::PM_TitleBarHeight, &options); | |
#if defined(Q_WS_MAC) && !defined(QT_NO_STYLE_MAC) | |
if (qobject_cast<QMacStyle*>(q->style())) { | |
height -=4; | |
} | |
#endif | |
return (qreal)height; | |
} | |
/*! | |
\internal | |
*/ | |
QGraphicsWidgetPrivate::~QGraphicsWidgetPrivate() | |
{ | |
// Remove any lazily allocated data | |
delete[] margins; | |
delete[] windowFrameMargins; | |
delete windowData; | |
} | |
/*! | |
\internal | |
Ensures that margins is allocated. | |
This function must be called before any dereferencing. | |
*/ | |
void QGraphicsWidgetPrivate::ensureMargins() const | |
{ | |
if (!margins) { | |
margins = new qreal[4]; | |
for (int i = 0; i < 4; ++i) | |
margins[i] = 0; | |
} | |
} | |
/*! | |
\internal | |
Ensures that windowFrameMargins is allocated. | |
This function must be called before any dereferencing. | |
*/ | |
void QGraphicsWidgetPrivate::ensureWindowFrameMargins() const | |
{ | |
if (!windowFrameMargins) { | |
windowFrameMargins = new qreal[4]; | |
for (int i = 0; i < 4; ++i) | |
windowFrameMargins[i] = 0; | |
} | |
} | |
/*! | |
\internal | |
Ensures that windowData is allocated. | |
This function must be called before any dereferencing. | |
*/ | |
void QGraphicsWidgetPrivate::ensureWindowData() | |
{ | |
if (!windowData) | |
windowData = new WindowData; | |
} | |
void QGraphicsWidgetPrivate::setPalette_helper(const QPalette &palette) | |
{ | |
if (this->palette == palette && this->palette.resolve() == palette.resolve()) | |
return; | |
updatePalette(palette); | |
} | |
void QGraphicsWidgetPrivate::resolvePalette(uint inheritedMask) | |
{ | |
inheritedPaletteResolveMask = inheritedMask; | |
QPalette naturalPalette = naturalWidgetPalette(); | |
QPalette resolvedPalette = palette.resolve(naturalPalette); | |
updatePalette(resolvedPalette); | |
} | |
void QGraphicsWidgetPrivate::updatePalette(const QPalette &palette) | |
{ | |
Q_Q(QGraphicsWidget); | |
// Update local palette setting. | |
this->palette = palette; | |
// Calculate new mask. | |
if (q->isWindow() && !q->testAttribute(Qt::WA_WindowPropagation)) | |
inheritedPaletteResolveMask = 0; | |
int mask = palette.resolve() | inheritedPaletteResolveMask; | |
// Propagate to children. | |
for (int i = 0; i < children.size(); ++i) { | |
QGraphicsItem *item = children.at(i); | |
if (item->isWidget()) { | |
QGraphicsWidget *w = static_cast<QGraphicsWidget *>(item); | |
if (!w->isWindow() || w->testAttribute(Qt::WA_WindowPropagation)) | |
w->d_func()->resolvePalette(mask); | |
} else { | |
item->d_ptr->resolvePalette(mask); | |
} | |
} | |
// Notify change. | |
QEvent event(QEvent::PaletteChange); | |
QApplication::sendEvent(q, &event); | |
} | |
void QGraphicsWidgetPrivate::setLayoutDirection_helper(Qt::LayoutDirection direction) | |
{ | |
Q_Q(QGraphicsWidget); | |
if ((direction == Qt::RightToLeft) == (testAttribute(Qt::WA_RightToLeft))) | |
return; | |
q->setAttribute(Qt::WA_RightToLeft, (direction == Qt::RightToLeft)); | |
// Propagate this change to all children. | |
for (int i = 0; i < children.size(); ++i) { | |
QGraphicsItem *item = children.at(i); | |
if (item->isWidget()) { | |
QGraphicsWidget *widget = static_cast<QGraphicsWidget *>(item); | |
if (widget->parentWidget() && !widget->testAttribute(Qt::WA_SetLayoutDirection)) | |
widget->d_func()->setLayoutDirection_helper(direction); | |
} | |
} | |
// Send the notification event to this widget item. | |
QEvent e(QEvent::LayoutDirectionChange); | |
QApplication::sendEvent(q, &e); | |
} | |
void QGraphicsWidgetPrivate::resolveLayoutDirection() | |
{ | |
Q_Q(QGraphicsWidget); | |
if (q->testAttribute(Qt::WA_SetLayoutDirection)) { | |
return; | |
} | |
if (QGraphicsWidget *parentWidget = q->parentWidget()) { | |
setLayoutDirection_helper(parentWidget->layoutDirection()); | |
} else if (scene) { | |
// ### shouldn't the scene have a layoutdirection really? how does | |
// ### QGraphicsWidget get changes from QApplication::layoutDirection? | |
setLayoutDirection_helper(QApplication::layoutDirection()); | |
} else { | |
setLayoutDirection_helper(QApplication::layoutDirection()); | |
} | |
} | |
/* private slot */ | |
void QGraphicsWidgetPrivate::_q_relayout() | |
{ | |
--refCountInvokeRelayout; | |
if (refCountInvokeRelayout == 0) { | |
Q_Q(QGraphicsWidget); | |
bool wasResized = q->testAttribute(Qt::WA_Resized); | |
q->resize(q->size()); // this will restrict the size | |
q->setAttribute(Qt::WA_Resized, wasResized); | |
} | |
} | |
QPalette QGraphicsWidgetPrivate::naturalWidgetPalette() const | |
{ | |
Q_Q(const QGraphicsWidget); | |
QPalette palette; | |
if (QGraphicsWidget *parent = q->parentWidget()) { | |
palette = parent->palette(); | |
} else if (scene) { | |
palette = scene->palette(); | |
} | |
palette.resolve(0); | |
return palette; | |
} | |
void QGraphicsWidgetPrivate::setFont_helper(const QFont &font) | |
{ | |
if (this->font == font && this->font.resolve() == font.resolve()) | |
return; | |
updateFont(font); | |
} | |
void QGraphicsWidgetPrivate::resolveFont(uint inheritedMask) | |
{ | |
Q_Q(QGraphicsWidget); | |
inheritedFontResolveMask = inheritedMask; | |
if (QGraphicsWidget *p = q->parentWidget()) | |
inheritedFontResolveMask |= p->d_func()->inheritedFontResolveMask; | |
QFont naturalFont = naturalWidgetFont(); | |
QFont resolvedFont = font.resolve(naturalFont); | |
updateFont(resolvedFont); | |
} | |
void QGraphicsWidgetPrivate::updateFont(const QFont &font) | |
{ | |
Q_Q(QGraphicsWidget); | |
// Update the local font setting. | |
this->font = font; | |
// Calculate new mask. | |
if (q->isWindow() && !q->testAttribute(Qt::WA_WindowPropagation)) | |
inheritedFontResolveMask = 0; | |
int mask = font.resolve() | inheritedFontResolveMask; | |
// Propagate to children. | |
for (int i = 0; i < children.size(); ++i) { | |
QGraphicsItem *item = children.at(i); | |
if (item->isWidget()) { | |
QGraphicsWidget *w = static_cast<QGraphicsWidget *>(item); | |
if (!w->isWindow() || w->testAttribute(Qt::WA_WindowPropagation)) | |
w->d_func()->resolveFont(mask); | |
} else { | |
item->d_ptr->resolveFont(mask); | |
} | |
} | |
if (!polished) | |
return; | |
// Notify change. | |
QEvent event(QEvent::FontChange); | |
QApplication::sendEvent(q, &event); | |
} | |
QFont QGraphicsWidgetPrivate::naturalWidgetFont() const | |
{ | |
Q_Q(const QGraphicsWidget); | |
QFont naturalFont; // ### no application font support | |
if (QGraphicsWidget *parent = q->parentWidget()) { | |
naturalFont = parent->font(); | |
} else if (scene) { | |
naturalFont = scene->font(); | |
} | |
naturalFont.resolve(0); | |
return naturalFont; | |
} | |
void QGraphicsWidgetPrivate::initStyleOptionTitleBar(QStyleOptionTitleBar *option) | |
{ | |
Q_Q(QGraphicsWidget); | |
ensureWindowData(); | |
q->initStyleOption(option); | |
option->rect.setHeight(titleBarHeight(*option)); | |
option->titleBarFlags = windowFlags; | |
option->subControls = QStyle::SC_TitleBarCloseButton | QStyle::SC_TitleBarLabel | QStyle::SC_TitleBarSysMenu; | |
option->activeSubControls = windowData->hoveredSubControl; | |
bool isActive = q->isActiveWindow(); | |
if (isActive) { | |
option->state |= QStyle::State_Active; | |
option->titleBarState = Qt::WindowActive; | |
option->titleBarState |= QStyle::State_Active; | |
} else { | |
option->state &= ~QStyle::State_Active; | |
option->titleBarState = Qt::WindowNoState; | |
} | |
QFont windowTitleFont = QApplication::font("QWorkspaceTitleBar"); | |
QRect textRect = q->style()->subControlRect(QStyle::CC_TitleBar, option, QStyle::SC_TitleBarLabel, 0); | |
option->text = QFontMetrics(windowTitleFont).elidedText( | |
windowData->windowTitle, Qt::ElideRight, textRect.width()); | |
} | |
void QGraphicsWidgetPrivate::adjustWindowFlags(Qt::WindowFlags *flags) | |
{ | |
bool customize = (*flags & (Qt::CustomizeWindowHint | |
| Qt::FramelessWindowHint | |
| Qt::WindowTitleHint | |
| Qt::WindowSystemMenuHint | |
| Qt::WindowMinimizeButtonHint | |
| Qt::WindowMaximizeButtonHint | |
| Qt::WindowContextHelpButtonHint)); | |
uint type = (*flags & Qt::WindowType_Mask); | |
if (customize) | |
; | |
else if (type == Qt::Dialog || type == Qt::Sheet) | |
*flags |= Qt::WindowTitleHint | Qt::WindowSystemMenuHint | Qt::WindowContextHelpButtonHint; | |
else if (type == Qt::Tool) | |
*flags |= Qt::WindowTitleHint | Qt::WindowSystemMenuHint; | |
else if (type == Qt::Window || type == Qt::SubWindow) | |
*flags |= Qt::WindowTitleHint | Qt::WindowSystemMenuHint | |
| Qt::WindowMinimizeButtonHint | Qt::WindowMaximizeButtonHint; | |
} | |
void QGraphicsWidgetPrivate::windowFrameMouseReleaseEvent(QGraphicsSceneMouseEvent *event) | |
{ | |
Q_Q(QGraphicsWidget); | |
ensureWindowData(); | |
if (windowData->grabbedSection != Qt::NoSection) { | |
if (windowData->grabbedSection == Qt::TitleBarArea) { | |
windowData->buttonSunken = false; | |
QStyleOptionTitleBar bar; | |
initStyleOptionTitleBar(&bar); | |
// make sure that the coordinates (rect and pos) we send to the style are positive. | |
bar.rect = q->windowFrameRect().toRect(); | |
bar.rect.moveTo(0,0); | |
bar.rect.setHeight(q->style()->pixelMetric(QStyle::PM_TitleBarHeight, &bar)); | |
QPointF pos = event->pos(); | |
if (windowFrameMargins) { | |
pos.rx() += windowFrameMargins[Left]; | |
pos.ry() += windowFrameMargins[Top]; | |
} | |
bar.subControls = QStyle::SC_TitleBarCloseButton; | |
if (q->style()->subControlRect(QStyle::CC_TitleBar, &bar, | |
QStyle::SC_TitleBarCloseButton, | |
event->widget()).contains(pos.toPoint())) { | |
q->close(); | |
} | |
} | |
if (!(static_cast<QGraphicsSceneMouseEvent *>(event)->buttons())) | |
windowData->grabbedSection = Qt::NoSection; | |
event->accept(); | |
} | |
} | |
void QGraphicsWidgetPrivate::windowFrameMousePressEvent(QGraphicsSceneMouseEvent *event) | |
{ | |
Q_Q(QGraphicsWidget); | |
if (event->button() != Qt::LeftButton) | |
return; | |
ensureWindowData(); | |
windowData->startGeometry = q->geometry(); | |
windowData->grabbedSection = q->windowFrameSectionAt(event->pos()); | |
ensureWindowData(); | |
if (windowData->grabbedSection == Qt::TitleBarArea | |
&& windowData->hoveredSubControl == QStyle::SC_TitleBarCloseButton) { | |
windowData->buttonSunken = true; | |
q->update(); | |
} | |
event->setAccepted(windowData->grabbedSection != Qt::NoSection); | |
} | |
/*! | |
Used to calculate the | |
Precondition: | |
\a widget should support either hfw or wfh | |
If \a heightForWidth is set to false, this function will query the width for height | |
instead. \a width will then be interpreted as height, \a minh and \a maxh will be interpreted | |
as minimum width and maximum width. | |
*/ | |
static qreal minimumHeightForWidth(qreal width, qreal minh, qreal maxh, | |
const QGraphicsWidget *widget, | |
bool heightForWidth = true) | |
{ | |
qreal minimumHeightForWidth = -1; | |
const QSizePolicy sp = widget->layout() ? widget->layout()->sizePolicy() : widget->sizePolicy(); | |
const bool hasHFW = sp.hasHeightForWidth(); | |
if (hasHFW == heightForWidth) { | |
minimumHeightForWidth = hasHFW | |
? widget->effectiveSizeHint(Qt::MinimumSize, QSizeF(width, -1)).height() | |
: widget->effectiveSizeHint(Qt::MinimumSize, QSizeF(-1, width)).width(); //"width" is here height! | |
} else { | |
// widthForHeight | |
const qreal constraint = width; | |
while (maxh - minh > 0.1) { | |
qreal middle = minh + (maxh - minh)/2; | |
// ### really bad, if we are a widget with a layout it will call | |
// layout->effectiveSizeHint(Qt::MiniumumSize), which again will call | |
// sizeHint three times because of how the cache works | |
qreal hfw = hasHFW | |
? widget->effectiveSizeHint(Qt::MinimumSize, QSizeF(middle, -1)).height() | |
: widget->effectiveSizeHint(Qt::MinimumSize, QSizeF(-1, middle)).width(); | |
if (hfw > constraint) { | |
minh = middle; | |
} else if (hfw <= constraint) { | |
maxh = middle; | |
} | |
} | |
minimumHeightForWidth = maxh; | |
} | |
return minimumHeightForWidth; | |
} | |
static qreal minimumWidthForHeight(qreal height, qreal minw, qreal maxw, | |
const QGraphicsWidget *widget) | |
{ | |
return minimumHeightForWidth(height, minw, maxw, widget, false); | |
} | |
static QSizeF closestAcceptableSize(const QSizeF &proposed, | |
const QGraphicsWidget *widget) | |
{ | |
const QSizeF current = widget->size(); | |
qreal minw = proposed.width(); | |
qreal maxw = current.width(); | |
qreal minh = proposed.height(); | |
qreal maxh = current.height(); | |
qreal middlew = maxw; | |
qreal middleh = maxh; | |
qreal min_hfw; | |
min_hfw = minimumHeightForWidth(maxw, minh, maxh, widget); | |
do { | |
if (maxw - minw < 0.1) { | |
// we still havent found anything, cut off binary search | |
minw = maxw; | |
minh = maxh; | |
} | |
middlew = minw + (maxw - minw)/2.0; | |
middleh = minh + (maxh - minh)/2.0; | |
min_hfw = minimumHeightForWidth(middlew, minh, maxh, widget); | |
if (min_hfw > middleh) { | |
minw = middlew; | |
minh = middleh; | |
} else if (min_hfw <= middleh) { | |
maxw = middlew; | |
maxh = middleh; | |
} | |
} while (maxw != minw); | |
min_hfw = minimumHeightForWidth(middlew, minh, maxh, widget); | |
QSizeF result; | |
if (min_hfw < maxh) { | |
result = QSizeF(middlew, min_hfw); | |
} else { | |
// Needed because of the cut-off we do above. | |
result = QSizeF(minimumWidthForHeight(maxh, proposed.width(), current.width(), widget), maxh); | |
} | |
return result; | |
} | |
static void _q_boundGeometryToSizeConstraints(const QRectF &startGeometry, | |
QRectF *rect, Qt::WindowFrameSection section, | |
const QSizeF &min, const QSizeF &max, | |
const QGraphicsWidget *widget) | |
{ | |
const QRectF proposedRect = *rect; | |
qreal width = qBound(min.width(), proposedRect.width(), max.width()); | |
qreal height = qBound(min.height(), proposedRect.height(), max.height()); | |
QSizePolicy sp = widget->sizePolicy(); | |
if (const QGraphicsLayout *l = widget->layout()) { | |
sp = l->sizePolicy(); | |
} | |
const bool hasHFW = sp.hasHeightForWidth(); // || sp.hasWidthForHeight(); | |
const bool widthChanged = proposedRect.width() < widget->size().width(); | |
const bool heightChanged = proposedRect.height() < widget->size().height(); | |
if (hasHFW) { | |
if (widthChanged || heightChanged) { | |
const qreal minh = min.height(); | |
const qreal maxh = max.height(); | |
const qreal proposedHFW = minimumHeightForWidth(width, minh, maxh, widget); | |
if (proposedHFW > proposedRect.height()) { | |
QSizeF effectiveSize = closestAcceptableSize(QSizeF(width, height), widget); | |
width = effectiveSize.width(); | |
height = effectiveSize.height(); | |
} | |
} | |
} | |
switch (section) { | |
case Qt::LeftSection: | |
rect->setRect(startGeometry.right() - qRound(width), startGeometry.top(), | |
qRound(width), startGeometry.height()); | |
break; | |
case Qt::TopLeftSection: | |
rect->setRect(startGeometry.right() - qRound(width), startGeometry.bottom() - qRound(height), | |
qRound(width), qRound(height)); | |
break; | |
case Qt::TopSection: | |
rect->setRect(startGeometry.left(), startGeometry.bottom() - qRound(height), | |
startGeometry.width(), qRound(height)); | |
break; | |
case Qt::TopRightSection: | |
rect->setTop(rect->bottom() - qRound(height)); | |
rect->setWidth(qRound(width)); | |
break; | |
case Qt::RightSection: | |
rect->setWidth(qRound(width)); | |
break; | |
case Qt::BottomRightSection: | |
rect->setWidth(qRound(width)); | |
rect->setHeight(qRound(height)); | |
break; | |
case Qt::BottomSection: | |
rect->setHeight(qRound(height)); | |
break; | |
case Qt::BottomLeftSection: | |
rect->setRect(startGeometry.right() - qRound(width), startGeometry.top(), | |
qRound(width), qRound(height)); | |
break; | |
default: | |
break; | |
} | |
} | |
void QGraphicsWidgetPrivate::windowFrameMouseMoveEvent(QGraphicsSceneMouseEvent *event) | |
{ | |
Q_Q(QGraphicsWidget); | |
ensureWindowData(); | |
if (!(event->buttons() & Qt::LeftButton) || windowData->hoveredSubControl != QStyle::SC_TitleBarLabel) | |
return; | |
QLineF delta(q->mapFromScene(event->buttonDownScenePos(Qt::LeftButton)), event->pos()); | |
QLineF parentDelta(q->mapToParent(delta.p1()), q->mapToParent(delta.p2())); | |
QLineF parentXDelta(q->mapToParent(QPointF(delta.p1().x(), 0)), q->mapToParent(QPointF(delta.p2().x(), 0))); | |
QLineF parentYDelta(q->mapToParent(QPointF(0, delta.p1().y())), q->mapToParent(QPointF(0, delta.p2().y()))); | |
QRectF newGeometry; | |
switch (windowData->grabbedSection) { | |
case Qt::LeftSection: | |
newGeometry = QRectF(windowData->startGeometry.topLeft() | |
+ QPointF(parentXDelta.dx(), parentXDelta.dy()), | |
windowData->startGeometry.size() - QSizeF(delta.dx(), delta.dy())); | |
break; | |
case Qt::TopLeftSection: | |
newGeometry = QRectF(windowData->startGeometry.topLeft() | |
+ QPointF(parentDelta.dx(), parentDelta.dy()), | |
windowData->startGeometry.size() - QSizeF(delta.dx(), delta.dy())); | |
break; | |
case Qt::TopSection: | |
newGeometry = QRectF(windowData->startGeometry.topLeft() | |
+ QPointF(parentYDelta.dx(), parentYDelta.dy()), | |
windowData->startGeometry.size() - QSizeF(0, delta.dy())); | |
break; | |
case Qt::TopRightSection: | |
newGeometry = QRectF(windowData->startGeometry.topLeft() | |
+ QPointF(parentYDelta.dx(), parentYDelta.dy()), | |
windowData->startGeometry.size() - QSizeF(-delta.dx(), delta.dy())); | |
break; | |
case Qt::RightSection: | |
newGeometry = QRectF(windowData->startGeometry.topLeft(), | |
windowData->startGeometry.size() + QSizeF(delta.dx(), 0)); | |
break; | |
case Qt::BottomRightSection: | |
newGeometry = QRectF(windowData->startGeometry.topLeft(), | |
windowData->startGeometry.size() + QSizeF(delta.dx(), delta.dy())); | |
break; | |
case Qt::BottomSection: | |
newGeometry = QRectF(windowData->startGeometry.topLeft(), | |
windowData->startGeometry.size() + QSizeF(0, delta.dy())); | |
break; | |
case Qt::BottomLeftSection: | |
newGeometry = QRectF(windowData->startGeometry.topLeft() | |
+ QPointF(parentXDelta.dx(), parentXDelta.dy()), | |
windowData->startGeometry.size() - QSizeF(delta.dx(), -delta.dy())); | |
break; | |
case Qt::TitleBarArea: | |
newGeometry = QRectF(windowData->startGeometry.topLeft() | |
+ QPointF(parentDelta.dx(), parentDelta.dy()), | |
windowData->startGeometry.size()); | |
break; | |
case Qt::NoSection: | |
break; | |
} | |
if (windowData->grabbedSection != Qt::NoSection) { | |
_q_boundGeometryToSizeConstraints(windowData->startGeometry, &newGeometry, | |
windowData->grabbedSection, | |
q->effectiveSizeHint(Qt::MinimumSize), | |
q->effectiveSizeHint(Qt::MaximumSize), | |
q); | |
q->setGeometry(newGeometry); | |
} | |
} | |
void QGraphicsWidgetPrivate::windowFrameHoverMoveEvent(QGraphicsSceneHoverEvent *event) | |
{ | |
Q_Q(QGraphicsWidget); | |
if (!hasDecoration()) | |
return; | |
ensureWindowData(); | |
if (q->rect().contains(event->pos())) { | |
if (windowData->buttonMouseOver || windowData->hoveredSubControl != QStyle::SC_None) | |
windowFrameHoverLeaveEvent(event); | |
return; | |
} | |
bool wasMouseOver = windowData->buttonMouseOver; | |
QRect oldButtonRect = windowData->buttonRect; | |
windowData->buttonRect = QRect(); | |
windowData->buttonMouseOver = false; | |
QPointF pos = event->pos(); | |
QStyleOptionTitleBar bar; | |
// make sure that the coordinates (rect and pos) we send to the style are positive. | |
if (windowFrameMargins) { | |
pos.rx() += windowFrameMargins[Left]; | |
pos.ry() += windowFrameMargins[Top]; | |
} | |
initStyleOptionTitleBar(&bar); | |
bar.rect = q->windowFrameRect().toRect(); | |
bar.rect.moveTo(0,0); | |
bar.rect.setHeight(int(titleBarHeight(bar))); | |
Qt::CursorShape cursorShape = Qt::ArrowCursor; | |
bool needsSetCursorCall = true; | |
switch (q->windowFrameSectionAt(event->pos())) { | |
case Qt::TopLeftSection: | |
case Qt::BottomRightSection: | |
cursorShape = Qt::SizeFDiagCursor; | |
break; | |
case Qt::TopRightSection: | |
case Qt::BottomLeftSection: | |
cursorShape = Qt::SizeBDiagCursor; | |
break; | |
case Qt::LeftSection: | |
case Qt::RightSection: | |
cursorShape = Qt::SizeHorCursor; | |
break; | |
case Qt::TopSection: | |
case Qt::BottomSection: | |
cursorShape = Qt::SizeVerCursor; | |
break; | |
case Qt::TitleBarArea: | |
windowData->buttonRect = q->style()->subControlRect( | |
QStyle::CC_TitleBar, &bar, QStyle::SC_TitleBarCloseButton, 0); | |
#ifdef Q_WS_MAC | |
// On mac we should hover if we are in the 'area' of the buttons | |
windowData->buttonRect |= q->style()->subControlRect( | |
QStyle::CC_TitleBar, &bar, QStyle::SC_TitleBarMinButton, 0); | |
windowData->buttonRect |= q->style()->subControlRect( | |
QStyle::CC_TitleBar, &bar, QStyle::SC_TitleBarMaxButton, 0); | |
#endif | |
if (windowData->buttonRect.contains(pos.toPoint())) | |
windowData->buttonMouseOver = true; | |
event->ignore(); | |
break; | |
default: | |
needsSetCursorCall = false; | |
event->ignore(); | |
} | |
#ifndef QT_NO_CURSOR | |
if (needsSetCursorCall) | |
q->setCursor(cursorShape); | |
#endif | |
// update buttons if we hover over them | |
windowData->hoveredSubControl = q->style()->hitTestComplexControl(QStyle::CC_TitleBar, &bar, pos.toPoint(), 0); | |
if (windowData->hoveredSubControl != QStyle::SC_TitleBarCloseButton) | |
windowData->hoveredSubControl = QStyle::SC_TitleBarLabel; | |
if (windowData->buttonMouseOver != wasMouseOver) { | |
if (!oldButtonRect.isNull()) | |
q->update(QRectF(oldButtonRect).translated(q->windowFrameRect().topLeft())); | |
if (!windowData->buttonRect.isNull()) | |
q->update(QRectF(windowData->buttonRect).translated(q->windowFrameRect().topLeft())); | |
} | |
} | |
void QGraphicsWidgetPrivate::windowFrameHoverLeaveEvent(QGraphicsSceneHoverEvent *event) | |
{ | |
Q_UNUSED(event); | |
Q_Q(QGraphicsWidget); | |
if (hasDecoration()) { | |
// ### restore the cursor, don't override it | |
#ifndef QT_NO_CURSOR | |
q->unsetCursor(); | |
#endif | |
ensureWindowData(); | |
bool needsUpdate = false; | |
if (windowData->hoveredSubControl == QStyle::SC_TitleBarCloseButton | |
|| windowData->buttonMouseOver) | |
needsUpdate = true; | |
// update the hover state (of buttons etc...) | |
windowData->hoveredSubControl = QStyle::SC_None; | |
windowData->buttonMouseOver = false; | |
windowData->buttonRect = QRect(); | |
if (needsUpdate) | |
q->update(windowData->buttonRect); | |
} | |
} | |
bool QGraphicsWidgetPrivate::hasDecoration() const | |
{ | |
return (windowFlags & Qt::Window) && (windowFlags & Qt::WindowTitleHint); | |
} | |
/** | |
* is called after a reparent has taken place to fix up the focus chain(s) | |
*/ | |
void QGraphicsWidgetPrivate::fixFocusChainBeforeReparenting(QGraphicsWidget *newParent, QGraphicsScene *oldScene, QGraphicsScene *newScene) | |
{ | |
Q_Q(QGraphicsWidget); | |
Q_ASSERT(focusNext && focusPrev); | |
QGraphicsWidget *n = q; //last one in 'new' list | |
QGraphicsWidget *o = 0; //last one in 'old' list | |
QGraphicsWidget *w = focusNext; | |
QGraphicsWidget *firstOld = 0; | |
bool wasPreviousNew = true; | |
while (w != q) { | |
bool isCurrentNew = q->isAncestorOf(w); | |
if (isCurrentNew) { | |
if (!wasPreviousNew) { | |
n->d_func()->focusNext = w; | |
w->d_func()->focusPrev = n; | |
} | |
n = w; | |
} else /*if (!isCurrentNew)*/ { | |
if (wasPreviousNew) { | |
if (o) { | |
o->d_func()->focusNext = w; | |
w->d_func()->focusPrev = o; | |
} else { | |
firstOld = w; | |
} | |
} | |
o = w; | |
} | |
w = w->d_func()->focusNext; | |
wasPreviousNew = isCurrentNew; | |
} | |
// repair the 'old' chain | |
if (firstOld) { | |
o->d_func()->focusNext = firstOld; | |
firstOld->d_func()->focusPrev = o; | |
} | |
// update tabFocusFirst for oldScene if the item is going to be removed from oldScene | |
if (newParent) | |
newScene = newParent->scene(); | |
if (oldScene && newScene != oldScene) | |
oldScene->d_func()->tabFocusFirst = (firstOld && firstOld->scene() == oldScene) ? firstOld : 0; | |
QGraphicsItem *topLevelItem = newParent ? newParent->topLevelItem() : 0; | |
QGraphicsWidget *topLevel = 0; | |
if (topLevelItem && topLevelItem->isWidget()) | |
topLevel = static_cast<QGraphicsWidget *>(topLevelItem); | |
if (topLevel && newParent) { | |
QGraphicsWidget *last = topLevel->d_func()->focusPrev; | |
// link last with new chain | |
last->d_func()->focusNext = q; | |
focusPrev = last; | |
// link last in chain with | |
topLevel->d_func()->focusPrev = n; | |
n->d_func()->focusNext = topLevel; | |
} else { | |
// q is the start of the focus chain | |
n->d_func()->focusNext = q; | |
focusPrev = n; | |
} | |
} | |
void QGraphicsWidgetPrivate::setLayout_helper(QGraphicsLayout *l) | |
{ | |
delete (this->layout); | |
layout = l; | |
if (!l) { | |
Q_Q(QGraphicsWidget); | |
q->updateGeometry(); | |
} | |
} | |
qreal QGraphicsWidgetPrivate::width() const | |
{ | |
Q_Q(const QGraphicsWidget); | |
return q->geometry().width(); | |
} | |
void QGraphicsWidgetPrivate::setWidth(qreal w) | |
{ | |
if (qIsNaN(w)) | |
return; | |
Q_Q(QGraphicsWidget); | |
if (q->geometry().width() == w) | |
return; | |
QRectF oldGeom = q->geometry(); | |
q->setGeometry(QRectF(q->x(), q->y(), w, height())); | |
} | |
void QGraphicsWidgetPrivate::resetWidth() | |
{ | |
Q_Q(QGraphicsWidget); | |
q->setGeometry(QRectF(q->x(), q->y(), 0, height())); | |
} | |
qreal QGraphicsWidgetPrivate::height() const | |
{ | |
Q_Q(const QGraphicsWidget); | |
return q->geometry().height(); | |
} | |
void QGraphicsWidgetPrivate::setHeight(qreal h) | |
{ | |
if (qIsNaN(h)) | |
return; | |
Q_Q(QGraphicsWidget); | |
if (q->geometry().height() == h) | |
return; | |
QRectF oldGeom = q->geometry(); | |
q->setGeometry(QRectF(q->x(), q->y(), width(), h)); | |
} | |
void QGraphicsWidgetPrivate::resetHeight() | |
{ | |
Q_Q(QGraphicsWidget); | |
q->setGeometry(QRectF(q->x(), q->y(), width(), 0)); | |
} | |
void QGraphicsWidgetPrivate::setGeometryFromSetPos() | |
{ | |
if (inSetGeometry) | |
return; | |
Q_Q(QGraphicsWidget); | |
inSetPos = 1; | |
// Ensure setGeometry is called (avoid recursion when setPos is | |
// called from within setGeometry). | |
q->setGeometry(QRectF(pos, q->size())); | |
inSetPos = 0 ; | |
} | |
QT_END_NAMESPACE | |
#include "moc_qgraphicswidget.cpp" | |
#endif //QT_NO_GRAPHICSVIEW |