/**************************************************************************** | |
** | |
** 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 "QtGui/qapplication.h" | |
#include "QtGui/qwidget.h" | |
#include "QtGui/qtabbar.h" | |
#include "QtGui/qstyle.h" | |
#include "QtGui/qdesktopwidget.h" | |
#include "QtCore/qvariant.h" | |
#include "qdockarealayout_p.h" | |
#include "qdockwidget.h" | |
#include "qmainwindow.h" | |
#include "qwidgetanimator_p.h" | |
#include "qmainwindowlayout_p.h" | |
#include "qdockwidget_p.h" | |
#include <private/qlayoutengine_p.h> | |
#include <qpainter.h> | |
#include <qstyleoption.h> | |
#ifndef QT_NO_DOCKWIDGET | |
QT_BEGIN_NAMESPACE | |
// qmainwindow.cpp | |
extern QMainWindowLayout *qt_mainwindow_layout(const QMainWindow *window); | |
enum { StateFlagVisible = 1, StateFlagFloating = 2 }; | |
/****************************************************************************** | |
** QPlaceHolderItem | |
*/ | |
QPlaceHolderItem::QPlaceHolderItem(QWidget *w) | |
{ | |
objectName = w->objectName(); | |
hidden = w->isHidden(); | |
window = w->isWindow(); | |
if (window) | |
topLevelRect = w->geometry(); | |
} | |
/****************************************************************************** | |
** QDockAreaLayoutItem | |
*/ | |
QDockAreaLayoutItem::QDockAreaLayoutItem(QLayoutItem *_widgetItem) | |
: widgetItem(_widgetItem), subinfo(0), placeHolderItem(0), pos(0), size(-1), flags(NoFlags) | |
{ | |
} | |
QDockAreaLayoutItem::QDockAreaLayoutItem(QDockAreaLayoutInfo *_subinfo) | |
: widgetItem(0), subinfo(_subinfo), placeHolderItem(0), pos(0), size(-1), flags(NoFlags) | |
{ | |
} | |
QDockAreaLayoutItem::QDockAreaLayoutItem(QPlaceHolderItem *_placeHolderItem) | |
: widgetItem(0), subinfo(0), placeHolderItem(_placeHolderItem), pos(0), size(-1), flags(NoFlags) | |
{ | |
} | |
QDockAreaLayoutItem::QDockAreaLayoutItem(const QDockAreaLayoutItem &other) | |
: widgetItem(other.widgetItem), subinfo(0), placeHolderItem(0), pos(other.pos), | |
size(other.size), flags(other.flags) | |
{ | |
if (other.subinfo != 0) | |
subinfo = new QDockAreaLayoutInfo(*other.subinfo); | |
else if (other.placeHolderItem != 0) | |
placeHolderItem = new QPlaceHolderItem(*other.placeHolderItem); | |
} | |
QDockAreaLayoutItem::~QDockAreaLayoutItem() | |
{ | |
delete subinfo; | |
delete placeHolderItem; | |
} | |
bool QDockAreaLayoutItem::skip() const | |
{ | |
if (placeHolderItem != 0) | |
return true; | |
if (flags & GapItem) | |
return false; | |
if (widgetItem != 0) | |
return widgetItem->isEmpty(); | |
if (subinfo != 0) { | |
for (int i = 0; i < subinfo->item_list.count(); ++i) { | |
if (!subinfo->item_list.at(i).skip()) | |
return false; | |
} | |
} | |
return true; | |
} | |
QSize QDockAreaLayoutItem::minimumSize() const | |
{ | |
if (widgetItem != 0) { | |
int left, top, right, bottom; | |
widgetItem->widget()->getContentsMargins(&left, &top, &right, &bottom); | |
return widgetItem->minimumSize() + QSize(left+right, top+bottom); | |
} | |
if (subinfo != 0) | |
return subinfo->minimumSize(); | |
return QSize(0, 0); | |
} | |
QSize QDockAreaLayoutItem::maximumSize() const | |
{ | |
if (widgetItem != 0) { | |
int left, top, right, bottom; | |
widgetItem->widget()->getContentsMargins(&left, &top, &right, &bottom); | |
return widgetItem->maximumSize()+ QSize(left+right, top+bottom); | |
} | |
if (subinfo != 0) | |
return subinfo->maximumSize(); | |
return QSize(QWIDGETSIZE_MAX, QWIDGETSIZE_MAX); | |
} | |
bool QDockAreaLayoutItem::hasFixedSize(Qt::Orientation o) const | |
{ | |
return perp(o, minimumSize()) == perp(o, maximumSize()); | |
} | |
bool QDockAreaLayoutItem::expansive(Qt::Orientation o) const | |
{ | |
if ((flags & GapItem) || placeHolderItem != 0) | |
return false; | |
if (widgetItem != 0) | |
return ((widgetItem->expandingDirections() & o) == o); | |
if (subinfo != 0) | |
return subinfo->expansive(o); | |
return false; | |
} | |
QSize QDockAreaLayoutItem::sizeHint() const | |
{ | |
if (placeHolderItem != 0) | |
return QSize(0, 0); | |
if (widgetItem != 0) { | |
int left, top, right, bottom; | |
widgetItem->widget()->getContentsMargins(&left, &top, &right, &bottom); | |
return widgetItem->sizeHint() + QSize(left+right, top+bottom); | |
} | |
if (subinfo != 0) | |
return subinfo->sizeHint(); | |
return QSize(-1, -1); | |
} | |
QDockAreaLayoutItem | |
&QDockAreaLayoutItem::operator = (const QDockAreaLayoutItem &other) | |
{ | |
widgetItem = other.widgetItem; | |
if (other.subinfo == 0) | |
subinfo = 0; | |
else | |
subinfo = new QDockAreaLayoutInfo(*other.subinfo); | |
delete placeHolderItem; | |
if (other.placeHolderItem == 0) | |
placeHolderItem = 0; | |
else | |
placeHolderItem = new QPlaceHolderItem(*other.placeHolderItem); | |
pos = other.pos; | |
size = other.size; | |
flags = other.flags; | |
return *this; | |
} | |
/****************************************************************************** | |
** QDockAreaLayoutInfo | |
*/ | |
#ifndef QT_NO_TABBAR | |
static quintptr tabId(const QDockAreaLayoutItem &item) | |
{ | |
if (item.widgetItem == 0) | |
return 0; | |
return reinterpret_cast<quintptr>(item.widgetItem->widget()); | |
} | |
#endif | |
static const int zero = 0; | |
QDockAreaLayoutInfo::QDockAreaLayoutInfo() | |
: sep(&zero), dockPos(QInternal::LeftDock), o(Qt::Horizontal), mainWindow(0) | |
#ifndef QT_NO_TABBAR | |
, tabbed(false), tabBar(0), tabBarShape(QTabBar::RoundedSouth) | |
#endif | |
{ | |
} | |
QDockAreaLayoutInfo::QDockAreaLayoutInfo(const int *_sep, QInternal::DockPosition _dockPos, | |
Qt::Orientation _o, int tbshape, | |
QMainWindow *window) | |
: sep(_sep), dockPos(_dockPos), o(_o), mainWindow(window) | |
#ifndef QT_NO_TABBAR | |
, tabbed(false), tabBar(0), tabBarShape(static_cast<QTabBar::Shape>(tbshape)) | |
#endif | |
{ | |
#ifdef QT_NO_TABBAR | |
Q_UNUSED(tbshape); | |
#endif | |
} | |
QSize QDockAreaLayoutInfo::size() const | |
{ | |
return isEmpty() ? QSize(0, 0) : rect.size(); | |
} | |
void QDockAreaLayoutInfo::clear() | |
{ | |
item_list.clear(); | |
rect = QRect(); | |
#ifndef QT_NO_TABBAR | |
tabbed = false; | |
tabBar = 0; | |
#endif | |
} | |
bool QDockAreaLayoutInfo::isEmpty() const | |
{ | |
return next(-1) == -1; | |
} | |
QSize QDockAreaLayoutInfo::minimumSize() const | |
{ | |
if (isEmpty()) | |
return QSize(0, 0); | |
int a = 0, b = 0; | |
bool first = true; | |
for (int i = 0; i < item_list.size(); ++i) { | |
const QDockAreaLayoutItem &item = item_list.at(i); | |
if (item.skip()) | |
continue; | |
QSize min_size = item.minimumSize(); | |
#ifndef QT_NO_TABBAR | |
if (tabbed) { | |
a = qMax(a, pick(o, min_size)); | |
} else | |
#endif | |
{ | |
if (!first) | |
a += *sep; | |
a += pick(o, min_size); | |
} | |
b = qMax(b, perp(o, min_size)); | |
first = false; | |
} | |
QSize result; | |
rpick(o, result) = a; | |
rperp(o, result) = b; | |
#ifndef QT_NO_TABBAR | |
QSize tbm = tabBarMinimumSize(); | |
if (!tbm.isNull()) { | |
switch (tabBarShape) { | |
case QTabBar::RoundedNorth: | |
case QTabBar::RoundedSouth: | |
case QTabBar::TriangularNorth: | |
case QTabBar::TriangularSouth: | |
result.rheight() += tbm.height(); | |
result.rwidth() = qMax(tbm.width(), result.width()); | |
break; | |
case QTabBar::RoundedEast: | |
case QTabBar::RoundedWest: | |
case QTabBar::TriangularEast: | |
case QTabBar::TriangularWest: | |
result.rheight() = qMax(tbm.height(), result.height()); | |
result.rwidth() += tbm.width(); | |
break; | |
default: | |
break; | |
} | |
} | |
#endif // QT_NO_TABBAR | |
return result; | |
} | |
QSize QDockAreaLayoutInfo::maximumSize() const | |
{ | |
if (isEmpty()) | |
return QSize(QWIDGETSIZE_MAX, QWIDGETSIZE_MAX); | |
int a = 0, b = QWIDGETSIZE_MAX; | |
#ifndef QT_NO_TABBAR | |
if (tabbed) | |
a = QWIDGETSIZE_MAX; | |
#endif | |
int min_perp = 0; | |
bool first = true; | |
for (int i = 0; i < item_list.size(); ++i) { | |
const QDockAreaLayoutItem &item = item_list.at(i); | |
if (item.skip()) | |
continue; | |
QSize max_size = item.maximumSize(); | |
min_perp = qMax(min_perp, perp(o, item.minimumSize())); | |
#ifndef QT_NO_TABBAR | |
if (tabbed) { | |
a = qMin(a, pick(o, max_size)); | |
} else | |
#endif | |
{ | |
if (!first) | |
a += *sep; | |
a += pick(o, max_size); | |
} | |
b = qMin(b, perp(o, max_size)); | |
a = qMin(a, int(QWIDGETSIZE_MAX)); | |
b = qMin(b, int(QWIDGETSIZE_MAX)); | |
first = false; | |
} | |
b = qMax(b, min_perp); | |
QSize result; | |
rpick(o, result) = a; | |
rperp(o, result) = b; | |
#ifndef QT_NO_TABBAR | |
QSize tbh = tabBarSizeHint(); | |
if (!tbh.isNull()) { | |
switch (tabBarShape) { | |
case QTabBar::RoundedNorth: | |
case QTabBar::RoundedSouth: | |
result.rheight() += tbh.height(); | |
break; | |
case QTabBar::RoundedEast: | |
case QTabBar::RoundedWest: | |
result.rwidth() += tbh.width(); | |
break; | |
default: | |
break; | |
} | |
} | |
#endif // QT_NO_TABBAR | |
return result; | |
} | |
QSize QDockAreaLayoutInfo::sizeHint() const | |
{ | |
if (isEmpty()) | |
return QSize(0, 0); | |
int a = 0, b = 0; | |
int min_perp = 0; | |
int max_perp = QWIDGETSIZE_MAX; | |
const QDockAreaLayoutItem *previous = 0; | |
for (int i = 0; i < item_list.size(); ++i) { | |
const QDockAreaLayoutItem &item = item_list.at(i); | |
if (item.skip()) | |
continue; | |
bool gap = item.flags & QDockAreaLayoutItem::GapItem; | |
QSize size_hint = item.sizeHint(); | |
min_perp = qMax(min_perp, perp(o, item.minimumSize())); | |
max_perp = qMin(max_perp, perp(o, item.maximumSize())); | |
#ifndef QT_NO_TABBAR | |
if (tabbed) { | |
a = qMax(a, gap ? item.size : pick(o, size_hint)); | |
} else | |
#endif | |
{ | |
if (previous && !gap && !(previous->flags & QDockAreaLayoutItem::GapItem) | |
&& !previous->hasFixedSize(o)) { | |
a += *sep; | |
} | |
a += gap ? item.size : pick(o, size_hint); | |
} | |
b = qMax(b, perp(o, size_hint)); | |
previous = &item; | |
} | |
max_perp = qMax(max_perp, min_perp); | |
b = qMax(b, min_perp); | |
b = qMin(b, max_perp); | |
QSize result; | |
rpick(o, result) = a; | |
rperp(o, result) = b; | |
#ifndef QT_NO_TABBAR | |
if (tabbed) { | |
QSize tbh = tabBarSizeHint(); | |
switch (tabBarShape) { | |
case QTabBar::RoundedNorth: | |
case QTabBar::RoundedSouth: | |
case QTabBar::TriangularNorth: | |
case QTabBar::TriangularSouth: | |
result.rheight() += tbh.height(); | |
result.rwidth() = qMax(tbh.width(), result.width()); | |
break; | |
case QTabBar::RoundedEast: | |
case QTabBar::RoundedWest: | |
case QTabBar::TriangularEast: | |
case QTabBar::TriangularWest: | |
result.rheight() = qMax(tbh.height(), result.height()); | |
result.rwidth() += tbh.width(); | |
break; | |
default: | |
break; | |
} | |
} | |
#endif // QT_NO_TABBAR | |
return result; | |
} | |
bool QDockAreaLayoutInfo::expansive(Qt::Orientation o) const | |
{ | |
for (int i = 0; i < item_list.size(); ++i) { | |
if (item_list.at(i).expansive(o)) | |
return true; | |
} | |
return false; | |
} | |
/* QDockAreaLayoutInfo::maximumSize() doesn't return the real max size. For example, | |
if the layout is empty, it returns QWIDGETSIZE_MAX. This is so that empty dock areas | |
don't constrain the size of the QMainWindow, but sometimes we really need to know the | |
maximum size. Also, these functions take into account widgets that want to keep their | |
size (f.ex. when they are hidden and then shown, they should not change size). | |
*/ | |
static int realMinSize(const QDockAreaLayoutInfo &info) | |
{ | |
int result = 0; | |
bool first = true; | |
for (int i = 0; i < info.item_list.size(); ++i) { | |
const QDockAreaLayoutItem &item = info.item_list.at(i); | |
if (item.skip()) | |
continue; | |
int min = 0; | |
if ((item.flags & QDockAreaLayoutItem::KeepSize) && item.size != -1) | |
min = item.size; | |
else | |
min = pick(info.o, item.minimumSize()); | |
if (!first) | |
result += *info.sep; | |
result += min; | |
first = false; | |
} | |
return result; | |
} | |
static int realMaxSize(const QDockAreaLayoutInfo &info) | |
{ | |
int result = 0; | |
bool first = true; | |
for (int i = 0; i < info.item_list.size(); ++i) { | |
const QDockAreaLayoutItem &item = info.item_list.at(i); | |
if (item.skip()) | |
continue; | |
int max = 0; | |
if ((item.flags & QDockAreaLayoutItem::KeepSize) && item.size != -1) | |
max = item.size; | |
else | |
max = pick(info.o, item.maximumSize()); | |
if (!first) | |
result += *info.sep; | |
result += max; | |
if (result >= QWIDGETSIZE_MAX) | |
return QWIDGETSIZE_MAX; | |
first = false; | |
} | |
return result; | |
} | |
void QDockAreaLayoutInfo::fitItems() | |
{ | |
#ifndef QT_NO_TABBAR | |
if (tabbed) { | |
return; | |
} | |
#endif | |
QVector<QLayoutStruct> layout_struct_list(item_list.size()*2); | |
int j = 0; | |
int size = pick(o, rect.size()); | |
int min_size = realMinSize(*this); | |
int max_size = realMaxSize(*this); | |
int last_index = -1; | |
const QDockAreaLayoutItem *previous = 0; | |
for (int i = 0; i < item_list.size(); ++i) { | |
QDockAreaLayoutItem &item = item_list[i]; | |
if (item.skip()) | |
continue; | |
bool gap = item.flags & QDockAreaLayoutItem::GapItem; | |
if (previous && !gap) { | |
if (!(previous->flags & QDockAreaLayoutItem::GapItem)) { | |
QLayoutStruct &ls = layout_struct_list[j++]; | |
ls.init(); | |
ls.minimumSize = ls.maximumSize = ls.sizeHint = previous->hasFixedSize(o) ? 0 : *sep; | |
ls.empty = false; | |
} | |
} | |
if (item.flags & QDockAreaLayoutItem::KeepSize) { | |
// Check if the item can keep its size, without violating size constraints | |
// of other items. | |
if (size < min_size) { | |
// There is too little space to keep this widget's size | |
item.flags &= ~QDockAreaLayoutItem::KeepSize; | |
min_size -= item.size; | |
min_size += pick(o, item.minimumSize()); | |
min_size = qMax(0, min_size); | |
} else if (size > max_size) { | |
// There is too much space to keep this widget's size | |
item.flags &= ~QDockAreaLayoutItem::KeepSize; | |
max_size -= item.size; | |
max_size += pick(o, item.maximumSize()); | |
max_size = qMin<int>(QWIDGETSIZE_MAX, max_size); | |
} | |
} | |
last_index = j; | |
QLayoutStruct &ls = layout_struct_list[j++]; | |
ls.init(); | |
ls.empty = false; | |
if (item.flags & QDockAreaLayoutItem::KeepSize) { | |
ls.minimumSize = ls.maximumSize = ls.sizeHint = item.size; | |
ls.expansive = false; | |
ls.stretch = 0; | |
} else { | |
ls.maximumSize = pick(o, item.maximumSize()); | |
ls.expansive = item.expansive(o); | |
ls.minimumSize = pick(o, item.minimumSize()); | |
ls.sizeHint = item.size == -1 ? pick(o, item.sizeHint()) : item.size; | |
ls.stretch = ls.expansive ? ls.sizeHint : 0; | |
} | |
item.flags &= ~QDockAreaLayoutItem::KeepSize; | |
previous = &item; | |
} | |
layout_struct_list.resize(j); | |
// If there is more space than the widgets can take (due to maximum size constraints), | |
// we detect it here and stretch the last widget to take up the rest of the space. | |
if (size > max_size && last_index != -1) { | |
layout_struct_list[last_index].maximumSize = QWIDGETSIZE_MAX; | |
layout_struct_list[last_index].expansive = true; | |
} | |
qGeomCalc(layout_struct_list, 0, j, pick(o, rect.topLeft()), size, 0); | |
j = 0; | |
bool prev_gap = false; | |
bool first = true; | |
for (int i = 0; i < item_list.size(); ++i) { | |
QDockAreaLayoutItem &item = item_list[i]; | |
if (item.skip()) | |
continue; | |
bool gap = item.flags & QDockAreaLayoutItem::GapItem; | |
if (!first && !gap && !prev_gap) | |
++j; | |
const QLayoutStruct &ls = layout_struct_list.at(j++); | |
item.size = ls.size; | |
item.pos = ls.pos; | |
if (item.subinfo != 0) { | |
item.subinfo->rect = itemRect(i); | |
item.subinfo->fitItems(); | |
} | |
prev_gap = gap; | |
first = false; | |
} | |
} | |
static QInternal::DockPosition dockPosHelper(const QRect &rect, const QPoint &_pos, | |
Qt::Orientation o, | |
bool nestingEnabled, | |
QDockAreaLayoutInfo::TabMode tabMode) | |
{ | |
if (tabMode == QDockAreaLayoutInfo::ForceTabs) | |
return QInternal::DockCount; | |
QPoint pos = _pos - rect.topLeft(); | |
int x = pos.x(); | |
int y = pos.y(); | |
int w = rect.width(); | |
int h = rect.height(); | |
if (tabMode != QDockAreaLayoutInfo::NoTabs) { | |
// is it in the center? | |
if (nestingEnabled) { | |
/* 2/3 | |
+--------------+ | |
| | | |
| CCCCCCCC | | |
2/3 | CCCCCCCC | | |
| CCCCCCCC | | |
| | | |
+--------------+ */ | |
QRect center(w/6, h/6, 2*w/3, 2*h/3); | |
if (center.contains(pos)) | |
return QInternal::DockCount; | |
} else if (o == Qt::Horizontal) { | |
/* 2/3 | |
+--------------+ | |
| CCCCCCCC | | |
| CCCCCCCC | | |
| CCCCCCCC | | |
| CCCCCCCC | | |
| CCCCCCCC | | |
+--------------+ */ | |
if (x > w/6 && x < w*5/6) | |
return QInternal::DockCount; | |
} else { | |
/* | |
+--------------+ | |
| | | |
2/3 |CCCCCCCCCCCCCC| | |
|CCCCCCCCCCCCCC| | |
| | | |
+--------------+ */ | |
if (y > h/6 && y < 5*h/6) | |
return QInternal::DockCount; | |
} | |
} | |
// not in the center. which edge? | |
if (nestingEnabled) { | |
if (o == Qt::Horizontal) { | |
/* 1/3 1/3 1/3 | |
+------------+ (we've already ruled out the center) | |
|LLLLTTTTRRRR| | |
|LLLLTTTTRRRR| | |
|LLLLBBBBRRRR| | |
|LLLLBBBBRRRR| | |
+------------+ */ | |
if (x < w/3) | |
return QInternal::LeftDock; | |
if (x > 2*w/3) | |
return QInternal::RightDock; | |
if (y < h/2) | |
return QInternal::TopDock; | |
return QInternal::BottomDock; | |
} else { | |
/* +------------+ (we've already ruled out the center) | |
1/3 |TTTTTTTTTTTT| | |
|LLLLLLRRRRRR| | |
1/3 |LLLLLLRRRRRR| | |
1/3 |BBBBBBBBBBBB| | |
+------------+ */ | |
if (y < h/3) | |
return QInternal::TopDock; | |
if (y > 2*h/3) | |
return QInternal::BottomDock; | |
if (x < w/2) | |
return QInternal::LeftDock; | |
return QInternal::RightDock; | |
} | |
} else { | |
if (o == Qt::Horizontal) { | |
return x < w/2 | |
? QInternal::LeftDock | |
: QInternal::RightDock; | |
} else { | |
return y < h/2 | |
? QInternal::TopDock | |
: QInternal::BottomDock; | |
} | |
} | |
} | |
QList<int> QDockAreaLayoutInfo::gapIndex(const QPoint& _pos, | |
bool nestingEnabled, TabMode tabMode) const | |
{ | |
QList<int> result; | |
QRect item_rect; | |
int item_index = 0; | |
#ifndef QT_NO_TABBAR | |
if (tabbed) { | |
item_rect = tabContentRect(); | |
} else | |
#endif | |
{ | |
int pos = pick(o, _pos); | |
int last = -1; | |
for (int i = 0; i < item_list.size(); ++i) { | |
const QDockAreaLayoutItem &item = item_list.at(i); | |
if (item.skip()) | |
continue; | |
last = i; | |
if (item.pos + item.size < pos) | |
continue; | |
if (item.subinfo != 0 | |
#ifndef QT_NO_TABBAR | |
&& !item.subinfo->tabbed | |
#endif | |
) { | |
result = item.subinfo->gapIndex(_pos, nestingEnabled, | |
tabMode); | |
result.prepend(i); | |
return result; | |
} | |
item_rect = itemRect(i); | |
item_index = i; | |
break; | |
} | |
if (item_rect.isNull()) { | |
result.append(last + 1); | |
return result; | |
} | |
} | |
Q_ASSERT(!item_rect.isNull()); | |
QInternal::DockPosition dock_pos | |
= dockPosHelper(item_rect, _pos, o, nestingEnabled, tabMode); | |
switch (dock_pos) { | |
case QInternal::LeftDock: | |
if (o == Qt::Horizontal) | |
result << item_index; | |
else | |
result << item_index << 0; // this subinfo doesn't exist yet, but insertGap() | |
// handles this by inserting it | |
break; | |
case QInternal::RightDock: | |
if (o == Qt::Horizontal) | |
result << item_index + 1; | |
else | |
result << item_index << 1; | |
break; | |
case QInternal::TopDock: | |
if (o == Qt::Horizontal) | |
result << item_index << 0; | |
else | |
result << item_index; | |
break; | |
case QInternal::BottomDock: | |
if (o == Qt::Horizontal) | |
result << item_index << 1; | |
else | |
result << item_index + 1; | |
break; | |
case QInternal::DockCount: | |
result << (-item_index - 1) << 0; // negative item_index means "on top of" | |
// -item_index - 1, insertGap() | |
// will insert a tabbed subinfo | |
break; | |
default: | |
break; | |
} | |
return result; | |
} | |
static inline int shrink(QLayoutStruct &ls, int delta) | |
{ | |
if (ls.empty) | |
return 0; | |
int old_size = ls.size; | |
ls.size = qMax(ls.size - delta, ls.minimumSize); | |
return old_size - ls.size; | |
} | |
static inline int grow(QLayoutStruct &ls, int delta) | |
{ | |
if (ls.empty) | |
return 0; | |
int old_size = ls.size; | |
ls.size = qMin(ls.size + delta, ls.maximumSize); | |
return ls.size - old_size; | |
} | |
static int separatorMoveHelper(QVector<QLayoutStruct> &list, int index, int delta, int sep) | |
{ | |
// adjust sizes | |
int pos = -1; | |
for (int i = 0; i < list.size(); ++i) { | |
const QLayoutStruct &ls = list.at(i); | |
if (!ls.empty) { | |
pos = ls.pos; | |
break; | |
} | |
} | |
if (pos == -1) | |
return 0; | |
if (delta > 0) { | |
int growlimit = 0; | |
for (int i = 0; i<=index; ++i) { | |
const QLayoutStruct &ls = list.at(i); | |
if (ls.empty) | |
continue; | |
if (ls.maximumSize == QLAYOUTSIZE_MAX) { | |
growlimit = QLAYOUTSIZE_MAX; | |
break; | |
} | |
growlimit += ls.maximumSize - ls.size; | |
} | |
if (delta > growlimit) | |
delta = growlimit; | |
int d = 0; | |
for (int i = index + 1; d < delta && i < list.count(); ++i) | |
d += shrink(list[i], delta - d); | |
delta = d; | |
d = 0; | |
for (int i = index; d < delta && i >= 0; --i) | |
d += grow(list[i], delta - d); | |
} else if (delta < 0) { | |
int growlimit = 0; | |
for (int i = index + 1; i < list.count(); ++i) { | |
const QLayoutStruct &ls = list.at(i); | |
if (ls.empty) | |
continue; | |
if (ls.maximumSize == QLAYOUTSIZE_MAX) { | |
growlimit = QLAYOUTSIZE_MAX; | |
break; | |
} | |
growlimit += ls.maximumSize - ls.size; | |
} | |
if (-delta > growlimit) | |
delta = -growlimit; | |
int d = 0; | |
for (int i = index; d < -delta && i >= 0; --i) | |
d += shrink(list[i], -delta - d); | |
delta = -d; | |
d = 0; | |
for (int i = index + 1; d < -delta && i < list.count(); ++i) | |
d += grow(list[i], -delta - d); | |
} | |
// adjust positions | |
bool first = true; | |
for (int i = 0; i < list.size(); ++i) { | |
QLayoutStruct &ls = list[i]; | |
if (ls.empty) { | |
ls.pos = pos + (first ? 0 : sep); | |
continue; | |
} | |
if (!first) | |
pos += sep; | |
ls.pos = pos; | |
pos += ls.size; | |
first = false; | |
} | |
return delta; | |
} | |
int QDockAreaLayoutInfo::separatorMove(int index, int delta) | |
{ | |
#ifndef QT_NO_TABBAR | |
Q_ASSERT(!tabbed); | |
#endif | |
QVector<QLayoutStruct> list(item_list.size()); | |
for (int i = 0; i < list.size(); ++i) { | |
const QDockAreaLayoutItem &item = item_list.at(i); | |
QLayoutStruct &ls = list[i]; | |
Q_ASSERT(!(item.flags & QDockAreaLayoutItem::GapItem)); | |
if (item.skip()) { | |
ls.empty = true; | |
} else { | |
const int separatorSpace = item.hasFixedSize(o) ? 0 : *sep; | |
ls.empty = false; | |
ls.pos = item.pos; | |
ls.size = item.size + separatorSpace; | |
ls.minimumSize = pick(o, item.minimumSize()) + separatorSpace; | |
ls.maximumSize = pick(o, item.maximumSize()) + separatorSpace; | |
} | |
} | |
//the separator space has been added to the size, so we pass 0 as a parameter | |
delta = separatorMoveHelper(list, index, delta, 0 /*separator*/); | |
for (int i = 0; i < list.size(); ++i) { | |
QDockAreaLayoutItem &item = item_list[i]; | |
if (item.skip()) | |
continue; | |
QLayoutStruct &ls = list[i]; | |
const int separatorSpace = item.hasFixedSize(o) ? 0 : *sep; | |
item.size = ls.size - separatorSpace; | |
item.pos = ls.pos; | |
if (item.subinfo != 0) { | |
item.subinfo->rect = itemRect(i); | |
item.subinfo->fitItems(); | |
} | |
} | |
return delta; | |
} | |
void QDockAreaLayoutInfo::unnest(int index) | |
{ | |
QDockAreaLayoutItem &item = item_list[index]; | |
if (item.subinfo == 0) | |
return; | |
if (item.subinfo->item_list.count() > 1) | |
return; | |
if (item.subinfo->item_list.count() == 0) { | |
item_list.removeAt(index); | |
} else if (item.subinfo->item_list.count() == 1) { | |
QDockAreaLayoutItem &child = item.subinfo->item_list.first(); | |
if (child.widgetItem != 0) { | |
item.widgetItem = child.widgetItem; | |
delete item.subinfo; | |
item.subinfo = 0; | |
} else if (child.subinfo != 0) { | |
QDockAreaLayoutInfo *tmp = item.subinfo; | |
item.subinfo = child.subinfo; | |
child.subinfo = 0; | |
tmp->item_list.clear(); | |
delete tmp; | |
} | |
} | |
} | |
void QDockAreaLayoutInfo::remove(const QList<int> &path) | |
{ | |
Q_ASSERT(!path.isEmpty()); | |
if (path.count() > 1) { | |
const int index = path.first(); | |
QDockAreaLayoutItem &item = item_list[index]; | |
Q_ASSERT(item.subinfo != 0); | |
item.subinfo->remove(path.mid(1)); | |
unnest(index); | |
} else { | |
int index = path.first(); | |
item_list.removeAt(index); | |
} | |
} | |
QLayoutItem *QDockAreaLayoutInfo::plug(const QList<int> &path) | |
{ | |
Q_ASSERT(!path.isEmpty()); | |
int index = path.first(); | |
if (index < 0) | |
index = -index - 1; | |
if (path.count() > 1) { | |
const QDockAreaLayoutItem &item = item_list.at(index); | |
Q_ASSERT(item.subinfo != 0); | |
return item.subinfo->plug(path.mid(1)); | |
} | |
QDockAreaLayoutItem &item = item_list[index]; | |
Q_ASSERT(item.widgetItem != 0); | |
Q_ASSERT(item.flags & QDockAreaLayoutItem::GapItem); | |
item.flags &= ~QDockAreaLayoutItem::GapItem; | |
QRect result; | |
#ifndef QT_NO_TABBAR | |
if (tabbed) { | |
} else | |
#endif | |
{ | |
int prev = this->prev(index); | |
int next = this->next(index); | |
if (prev != -1 && !(item_list.at(prev).flags & QDockAreaLayoutItem::GapItem)) { | |
item.pos += *sep; | |
item.size -= *sep; | |
} | |
if (next != -1 && !(item_list.at(next).flags & QDockAreaLayoutItem::GapItem)) | |
item.size -= *sep; | |
QPoint pos; | |
rpick(o, pos) = item.pos; | |
rperp(o, pos) = perp(o, rect.topLeft()); | |
QSize s; | |
rpick(o, s) = item.size; | |
rperp(o, s) = perp(o, rect.size()); | |
result = QRect(pos, s); | |
} | |
return item.widgetItem; | |
} | |
QLayoutItem *QDockAreaLayoutInfo::unplug(const QList<int> &path) | |
{ | |
Q_ASSERT(!path.isEmpty()); | |
const int index = path.first(); | |
if (path.count() > 1) { | |
const QDockAreaLayoutItem &item = item_list.at(index); | |
Q_ASSERT(item.subinfo != 0); | |
return item.subinfo->unplug(path.mid(1)); | |
} | |
QDockAreaLayoutItem &item = item_list[index]; | |
int prev = this->prev(index); | |
int next = this->next(index); | |
Q_ASSERT(!(item.flags & QDockAreaLayoutItem::GapItem)); | |
item.flags |= QDockAreaLayoutItem::GapItem; | |
#ifndef QT_NO_TABBAR | |
if (tabbed) { | |
} else | |
#endif | |
{ | |
if (prev != -1 && !(item_list.at(prev).flags & QDockAreaLayoutItem::GapItem)) { | |
item.pos -= *sep; | |
item.size += *sep; | |
} | |
if (next != -1 && !(item_list.at(next).flags & QDockAreaLayoutItem::GapItem)) | |
item.size += *sep; | |
} | |
return item.widgetItem; | |
} | |
#ifndef QT_NO_TABBAR | |
quintptr QDockAreaLayoutInfo::currentTabId() const | |
{ | |
if (!tabbed || tabBar == 0) | |
return 0; | |
int index = tabBar->currentIndex(); | |
if (index == -1) | |
return 0; | |
return qvariant_cast<quintptr>(tabBar->tabData(index)); | |
} | |
void QDockAreaLayoutInfo::setCurrentTab(QWidget *widget) | |
{ | |
setCurrentTabId(reinterpret_cast<quintptr>(widget)); | |
} | |
void QDockAreaLayoutInfo::setCurrentTabId(quintptr id) | |
{ | |
if (!tabbed || tabBar == 0) | |
return; | |
for (int i = 0; i < tabBar->count(); ++i) { | |
if (qvariant_cast<quintptr>(tabBar->tabData(i)) == id) { | |
tabBar->setCurrentIndex(i); | |
return; | |
} | |
} | |
} | |
#endif // QT_NO_TABBAR | |
static QRect dockedGeometry(QWidget *widget) | |
{ | |
int titleHeight = 0; | |
QDockWidgetLayout *layout | |
= qobject_cast<QDockWidgetLayout*>(widget->layout()); | |
if(layout != 0 && layout->nativeWindowDeco()) | |
titleHeight = layout->titleHeight(); | |
QRect result = widget->geometry(); | |
result.adjust(0, -titleHeight, 0, 0); | |
return result; | |
} | |
bool QDockAreaLayoutInfo::insertGap(const QList<int> &path, QLayoutItem *dockWidgetItem) | |
{ | |
Q_ASSERT(!path.isEmpty()); | |
bool insert_tabbed = false; | |
int index = path.first(); | |
if (index < 0) { | |
insert_tabbed = true; | |
index = -index - 1; | |
} | |
// dump(qDebug() << "insertGap() before:" << index << tabIndex, *this, QString()); | |
if (path.count() > 1) { | |
QDockAreaLayoutItem &item = item_list[index]; | |
if (item.subinfo == 0 | |
#ifndef QT_NO_TABBAR | |
|| (item.subinfo->tabbed && !insert_tabbed) | |
#endif | |
) { | |
// this is not yet a nested layout - make it | |
QDockAreaLayoutInfo *subinfo = item.subinfo; | |
QLayoutItem *widgetItem = item.widgetItem; | |
QPlaceHolderItem *placeHolderItem = item.placeHolderItem; | |
QRect r = subinfo == 0 ? widgetItem ? dockedGeometry(widgetItem->widget()) : placeHolderItem->topLevelRect : subinfo->rect; | |
Qt::Orientation opposite = o == Qt::Horizontal ? Qt::Vertical : Qt::Horizontal; | |
#ifdef QT_NO_TABBAR | |
const int tabBarShape = 0; | |
#endif | |
QDockAreaLayoutInfo *new_info | |
= new QDockAreaLayoutInfo(sep, dockPos, opposite, tabBarShape, mainWindow); | |
//item become a new top-level | |
item.subinfo = new_info; | |
item.widgetItem = 0; | |
item.placeHolderItem = 0; | |
QDockAreaLayoutItem new_item | |
= widgetItem == 0 | |
? QDockAreaLayoutItem(subinfo) | |
: widgetItem ? QDockAreaLayoutItem(widgetItem) : QDockAreaLayoutItem(placeHolderItem); | |
new_item.size = pick(opposite, r.size()); | |
new_item.pos = pick(opposite, r.topLeft()); | |
new_info->item_list.append(new_item); | |
#ifndef QT_NO_TABBAR | |
if (insert_tabbed) { | |
new_info->tabbed = true; | |
} | |
#endif | |
} | |
return item.subinfo->insertGap(path.mid(1), dockWidgetItem); | |
} | |
// create the gap item | |
QDockAreaLayoutItem gap_item; | |
gap_item.flags |= QDockAreaLayoutItem::GapItem; | |
gap_item.widgetItem = dockWidgetItem; // so minimumSize(), maximumSize() and | |
// sizeHint() will work | |
#ifndef QT_NO_TABBAR | |
if (!tabbed) | |
#endif | |
{ | |
int prev = this->prev(index); | |
int next = this->next(index - 1); | |
// find out how much space we have in the layout | |
int space = 0; | |
if (isEmpty()) { | |
// I am an empty dock area, therefore I am a top-level dock area. | |
switch (dockPos) { | |
case QInternal::LeftDock: | |
case QInternal::RightDock: | |
if (o == Qt::Vertical) { | |
// the "size" is the height of the dock area (remember we are empty) | |
space = pick(Qt::Vertical, rect.size()); | |
} else { | |
space = pick(Qt::Horizontal, dockWidgetItem->widget()->size()); | |
} | |
break; | |
case QInternal::TopDock: | |
case QInternal::BottomDock: | |
default: | |
if (o == Qt::Horizontal) { | |
// the "size" is width of the dock area | |
space = pick(Qt::Horizontal, rect.size()); | |
} else { | |
space = pick(Qt::Vertical, dockWidgetItem->widget()->size()); | |
} | |
break; | |
} | |
} else { | |
for (int i = 0; i < item_list.count(); ++i) { | |
const QDockAreaLayoutItem &item = item_list.at(i); | |
if (item.skip()) | |
continue; | |
Q_ASSERT(!(item.flags & QDockAreaLayoutItem::GapItem)); | |
space += item.size - pick(o, item.minimumSize()); | |
} | |
} | |
// find the actual size of the gap | |
int gap_size = 0; | |
int sep_size = 0; | |
if (isEmpty()) { | |
gap_size = space; | |
sep_size = 0; | |
} else { | |
QRect r = dockedGeometry(dockWidgetItem->widget()); | |
gap_size = pick(o, r.size()); | |
if (prev != -1 && !(item_list.at(prev).flags & QDockAreaLayoutItem::GapItem)) | |
sep_size += *sep; | |
if (next != -1 && !(item_list.at(next).flags & QDockAreaLayoutItem::GapItem)) | |
sep_size += *sep; | |
} | |
if (gap_size + sep_size > space) | |
gap_size = pick(o, gap_item.minimumSize()); | |
gap_item.size = gap_size + sep_size; | |
} | |
// finally, insert the gap | |
item_list.insert(index, gap_item); | |
// dump(qDebug() << "insertGap() after:" << index << tabIndex, *this, QString()); | |
return true; | |
} | |
QDockAreaLayoutInfo *QDockAreaLayoutInfo::info(QWidget *widget) | |
{ | |
for (int i = 0; i < item_list.count(); ++i) { | |
const QDockAreaLayoutItem &item = item_list.at(i); | |
if (item.skip()) | |
continue; | |
#ifndef QT_NO_TABBAR | |
if (tabbed && widget == tabBar) | |
return this; | |
#endif | |
if (item.widgetItem != 0 && item.widgetItem->widget() == widget) | |
return this; | |
if (item.subinfo != 0) { | |
if (QDockAreaLayoutInfo *result = item.subinfo->info(widget)) | |
return result; | |
} | |
} | |
return 0; | |
} | |
QDockAreaLayoutInfo *QDockAreaLayoutInfo::info(const QList<int> &path) | |
{ | |
int index = path.first(); | |
if (index < 0) | |
index = -index - 1; | |
if (index >= item_list.count()) | |
return this; | |
if (path.count() == 1 || item_list[index].subinfo == 0) | |
return this; | |
return item_list[index].subinfo->info(path.mid(1)); | |
} | |
QRect QDockAreaLayoutInfo::itemRect(int index) const | |
{ | |
const QDockAreaLayoutItem &item = item_list.at(index); | |
if (item.skip()) | |
return QRect(); | |
QRect result; | |
#ifndef QT_NO_TABBAR | |
if (tabbed) { | |
if (tabId(item) == currentTabId()) | |
result = tabContentRect(); | |
} else | |
#endif | |
{ | |
QPoint pos; | |
rpick(o, pos) = item.pos; | |
rperp(o, pos) = perp(o, rect.topLeft()); | |
QSize s; | |
rpick(o, s) = item.size; | |
rperp(o, s) = perp(o, rect.size()); | |
result = QRect(pos, s); | |
} | |
return result; | |
} | |
QRect QDockAreaLayoutInfo::itemRect(const QList<int> &path) const | |
{ | |
Q_ASSERT(!path.isEmpty()); | |
const int index = path.first(); | |
if (path.count() > 1) { | |
const QDockAreaLayoutItem &item = item_list.at(index); | |
Q_ASSERT(item.subinfo != 0); | |
return item.subinfo->itemRect(path.mid(1)); | |
} | |
return itemRect(index); | |
} | |
QRect QDockAreaLayoutInfo::separatorRect(int index) const | |
{ | |
#ifndef QT_NO_TABBAR | |
if (tabbed) | |
return QRect(); | |
#endif | |
const QDockAreaLayoutItem &item = item_list.at(index); | |
if (item.skip()) | |
return QRect(); | |
QPoint pos = rect.topLeft(); | |
rpick(o, pos) = item.pos + item.size; | |
QSize s = rect.size(); | |
rpick(o, s) = *sep; | |
return QRect(pos, s); | |
} | |
QRect QDockAreaLayoutInfo::separatorRect(const QList<int> &path) const | |
{ | |
Q_ASSERT(!path.isEmpty()); | |
const int index = path.first(); | |
if (path.count() > 1) { | |
const QDockAreaLayoutItem &item = item_list.at(index); | |
Q_ASSERT(item.subinfo != 0); | |
return item.subinfo->separatorRect(path.mid(1)); | |
} | |
return separatorRect(index); | |
} | |
QList<int> QDockAreaLayoutInfo::findSeparator(const QPoint &_pos) const | |
{ | |
#ifndef QT_NO_TABBAR | |
if (tabbed) | |
return QList<int>(); | |
#endif | |
int pos = pick(o, _pos); | |
for (int i = 0; i < item_list.size(); ++i) { | |
const QDockAreaLayoutItem &item = item_list.at(i); | |
if (item.skip() || (item.flags & QDockAreaLayoutItem::GapItem)) | |
continue; | |
if (item.pos + item.size > pos) { | |
if (item.subinfo != 0) { | |
QList<int> result = item.subinfo->findSeparator(_pos); | |
if (!result.isEmpty()) { | |
result.prepend(i); | |
return result; | |
} else { | |
return QList<int>(); | |
} | |
} | |
} | |
int next = this->next(i); | |
if (next == -1 || (item_list.at(next).flags & QDockAreaLayoutItem::GapItem)) | |
continue; | |
QRect sepRect = separatorRect(i); | |
if (!sepRect.isNull() && *sep == 1) | |
sepRect.adjust(-2, -2, 2, 2); | |
//we also make sure we don't find a separator that's not there | |
if (sepRect.contains(_pos) && !item.hasFixedSize(o)) { | |
return QList<int>() << i; | |
} | |
} | |
return QList<int>(); | |
} | |
QList<int> QDockAreaLayoutInfo::indexOfPlaceHolder(const QString &objectName) const | |
{ | |
for (int i = 0; i < item_list.size(); ++i) { | |
const QDockAreaLayoutItem &item = item_list.at(i); | |
if (item.subinfo != 0) { | |
QList<int> result = item.subinfo->indexOfPlaceHolder(objectName); | |
if (!result.isEmpty()) { | |
result.prepend(i); | |
return result; | |
} | |
continue; | |
} | |
if (item.placeHolderItem != 0 && item.placeHolderItem->objectName == objectName) { | |
QList<int> result; | |
result << i; | |
return result; | |
} | |
} | |
return QList<int>(); | |
} | |
QList<int> QDockAreaLayoutInfo::indexOf(QWidget *widget) const | |
{ | |
for (int i = 0; i < item_list.size(); ++i) { | |
const QDockAreaLayoutItem &item = item_list.at(i); | |
if (item.placeHolderItem != 0) | |
continue; | |
if (item.subinfo != 0) { | |
QList<int> result = item.subinfo->indexOf(widget); | |
if (!result.isEmpty()) { | |
result.prepend(i); | |
return result; | |
} | |
continue; | |
} | |
if (!(item.flags & QDockAreaLayoutItem::GapItem) && item.widgetItem->widget() == widget) { | |
QList<int> result; | |
result << i; | |
return result; | |
} | |
} | |
return QList<int>(); | |
} | |
QMainWindowLayout *QDockAreaLayoutInfo::mainWindowLayout() const | |
{ | |
QMainWindowLayout *result = qt_mainwindow_layout(mainWindow); | |
Q_ASSERT(result != 0); | |
return result; | |
} | |
bool QDockAreaLayoutInfo::hasFixedSize() const | |
{ | |
return perp(o, minimumSize()) == perp(o, maximumSize()); | |
} | |
void QDockAreaLayoutInfo::apply(bool animate) | |
{ | |
QWidgetAnimator &widgetAnimator = mainWindowLayout()->widgetAnimator; | |
#ifndef QT_NO_TABBAR | |
if (tabbed) { | |
QRect tab_rect; | |
QSize tbh = tabBarSizeHint(); | |
if (!tbh.isNull()) { | |
switch (tabBarShape) { | |
case QTabBar::RoundedNorth: | |
case QTabBar::TriangularNorth: | |
tab_rect = QRect(rect.left(), rect.top(), rect.width(), tbh.height()); | |
break; | |
case QTabBar::RoundedSouth: | |
case QTabBar::TriangularSouth: | |
tab_rect = QRect(rect.left(), rect.bottom() - tbh.height() + 1, | |
rect.width(), tbh.height()); | |
break; | |
case QTabBar::RoundedEast: | |
case QTabBar::TriangularEast: | |
tab_rect = QRect(rect.right() - tbh.width() + 1, rect.top(), | |
tbh.width(), rect.height()); | |
break; | |
case QTabBar::RoundedWest: | |
case QTabBar::TriangularWest: | |
tab_rect = QRect(rect.left(), rect.top(), | |
tbh.width(), rect.height()); | |
break; | |
default: | |
break; | |
} | |
} | |
widgetAnimator.animate(tabBar, tab_rect, animate); | |
} | |
#endif // QT_NO_TABBAR | |
for (int i = 0; i < item_list.size(); ++i) { | |
QDockAreaLayoutItem &item = item_list[i]; | |
if (item.flags & QDockAreaLayoutItem::GapItem) | |
continue; | |
if (item.subinfo != 0) { | |
item.subinfo->apply(animate); | |
continue; | |
} | |
if (item.skip()) | |
continue; | |
Q_ASSERT(item.widgetItem); | |
QRect r = itemRect(i); | |
QWidget *w = item.widgetItem->widget(); | |
QRect geo = w->geometry(); | |
widgetAnimator.animate(w, r, animate); | |
if (!w->isHidden() && w->window()->isVisible()) { | |
QDockWidget *dw = qobject_cast<QDockWidget*>(w); | |
if (!r.isValid() && geo.right() >= 0 && geo.bottom() >= 0) { | |
dw->lower(); | |
emit dw->visibilityChanged(false); | |
} else if (r.isValid() | |
&& (geo.right() < 0 || geo.bottom() < 0)) { | |
emit dw->visibilityChanged(true); | |
} | |
} | |
} | |
#ifndef QT_NO_TABBAR | |
if (*sep == 1) | |
updateSeparatorWidgets(); | |
#endif //QT_NO_TABBAR | |
} | |
static void paintSep(QPainter *p, QWidget *w, const QRect &r, Qt::Orientation o, bool mouse_over) | |
{ | |
QStyleOption opt(0); | |
opt.state = QStyle::State_None; | |
if (w->isEnabled()) | |
opt.state |= QStyle::State_Enabled; | |
if (o != Qt::Horizontal) | |
opt.state |= QStyle::State_Horizontal; | |
if (mouse_over) | |
opt.state |= QStyle::State_MouseOver; | |
opt.rect = r; | |
opt.palette = w->palette(); | |
w->style()->drawPrimitive(QStyle::PE_IndicatorDockWidgetResizeHandle, &opt, p, w); | |
} | |
QRegion QDockAreaLayoutInfo::separatorRegion() const | |
{ | |
QRegion result; | |
if (isEmpty()) | |
return result; | |
#ifndef QT_NO_TABBAR | |
if (tabbed) | |
return result; | |
#endif | |
for (int i = 0; i < item_list.count(); ++i) { | |
const QDockAreaLayoutItem &item = item_list.at(i); | |
if (item.skip()) | |
continue; | |
int next = this->next(i); | |
if (item.subinfo) | |
result |= item.subinfo->separatorRegion(); | |
if (next == -1) | |
break; | |
result |= separatorRect(i); | |
} | |
return result; | |
} | |
void QDockAreaLayoutInfo::paintSeparators(QPainter *p, QWidget *widget, | |
const QRegion &clip, | |
const QPoint &mouse) const | |
{ | |
if (isEmpty()) | |
return; | |
#ifndef QT_NO_TABBAR | |
if (tabbed) | |
return; | |
#endif | |
for (int i = 0; i < item_list.count(); ++i) { | |
const QDockAreaLayoutItem &item = item_list.at(i); | |
if (item.skip()) | |
continue; | |
int next = this->next(i); | |
if ((item.flags & QDockAreaLayoutItem::GapItem) | |
|| (next != -1 && (item_list.at(next).flags & QDockAreaLayoutItem::GapItem))) | |
continue; | |
if (item.subinfo) { | |
if (clip.contains(item.subinfo->rect)) | |
item.subinfo->paintSeparators(p, widget, clip, mouse); | |
} | |
if (next == -1) | |
break; | |
QRect r = separatorRect(i); | |
if (clip.contains(r) && !item.hasFixedSize(o)) | |
paintSep(p, widget, r, o, r.contains(mouse)); | |
} | |
} | |
int QDockAreaLayoutInfo::next(int index) const | |
{ | |
for (int i = index + 1; i < item_list.size(); ++i) { | |
if (!item_list.at(i).skip()) | |
return i; | |
} | |
return -1; | |
} | |
int QDockAreaLayoutInfo::prev(int index) const | |
{ | |
for (int i = index - 1; i >= 0; --i) { | |
if (!item_list.at(i).skip()) | |
return i; | |
} | |
return -1; | |
} | |
void QDockAreaLayoutInfo::tab(int index, QLayoutItem *dockWidgetItem) | |
{ | |
#ifdef QT_NO_TABBAR | |
Q_UNUSED(index); | |
Q_UNUSED(dockWidgetItem); | |
#else | |
if (tabbed) { | |
item_list.append(QDockAreaLayoutItem(dockWidgetItem)); | |
updateTabBar(); | |
setCurrentTab(dockWidgetItem->widget()); | |
} else { | |
QDockAreaLayoutInfo *new_info | |
= new QDockAreaLayoutInfo(sep, dockPos, o, tabBarShape, mainWindow); | |
item_list[index].subinfo = new_info; | |
new_info->item_list.append(item_list.at(index).widgetItem); | |
item_list[index].widgetItem = 0; | |
new_info->item_list.append(dockWidgetItem); | |
new_info->tabbed = true; | |
new_info->updateTabBar(); | |
new_info->setCurrentTab(dockWidgetItem->widget()); | |
} | |
#endif // QT_NO_TABBAR | |
} | |
void QDockAreaLayoutInfo::split(int index, Qt::Orientation orientation, | |
QLayoutItem *dockWidgetItem) | |
{ | |
if (orientation == o) { | |
item_list.insert(index + 1, QDockAreaLayoutItem(dockWidgetItem)); | |
} else { | |
#ifdef QT_NO_TABBAR | |
const int tabBarShape = 0; | |
#endif | |
QDockAreaLayoutInfo *new_info | |
= new QDockAreaLayoutInfo(sep, dockPos, orientation, tabBarShape, mainWindow); | |
item_list[index].subinfo = new_info; | |
new_info->item_list.append(item_list.at(index).widgetItem); | |
item_list[index].widgetItem = 0; | |
new_info->item_list.append(dockWidgetItem); | |
} | |
} | |
QDockAreaLayoutItem &QDockAreaLayoutInfo::item(const QList<int> &path) | |
{ | |
Q_ASSERT(!path.isEmpty()); | |
const int index = path.first(); | |
if (path.count() > 1) { | |
const QDockAreaLayoutItem &item = item_list[index]; | |
Q_ASSERT(item.subinfo != 0); | |
return item.subinfo->item(path.mid(1)); | |
} | |
return item_list[index]; | |
} | |
QLayoutItem *QDockAreaLayoutInfo::itemAt(int *x, int index) const | |
{ | |
for (int i = 0; i < item_list.count(); ++i) { | |
const QDockAreaLayoutItem &item = item_list.at(i); | |
if (item.placeHolderItem != 0) | |
continue; | |
if (item.subinfo) { | |
if (QLayoutItem *ret = item.subinfo->itemAt(x, index)) | |
return ret; | |
} else if (item.widgetItem) { | |
if ((*x)++ == index) | |
return item.widgetItem; | |
} | |
} | |
return 0; | |
} | |
QLayoutItem *QDockAreaLayoutInfo::takeAt(int *x, int index) | |
{ | |
for (int i = 0; i < item_list.count(); ++i) { | |
QDockAreaLayoutItem &item = item_list[i]; | |
if (item.placeHolderItem != 0) | |
continue; | |
else if (item.subinfo) { | |
if (QLayoutItem *ret = item.subinfo->takeAt(x, index)) { | |
unnest(i); | |
return ret; | |
} | |
} else if (item.widgetItem) { | |
if ((*x)++ == index) { | |
item.placeHolderItem = new QPlaceHolderItem(item.widgetItem->widget()); | |
QLayoutItem *ret = item.widgetItem; | |
item.widgetItem = 0; | |
if (item.size != -1) | |
item.flags |= QDockAreaLayoutItem::KeepSize; | |
return ret; | |
} | |
} | |
} | |
return 0; | |
} | |
void QDockAreaLayoutInfo::deleteAllLayoutItems() | |
{ | |
for (int i = 0; i < item_list.count(); ++i) { | |
QDockAreaLayoutItem &item= item_list[i]; | |
if (item.subinfo) { | |
item.subinfo->deleteAllLayoutItems(); | |
} else { | |
delete item.widgetItem; | |
item.widgetItem = 0; | |
} | |
} | |
} | |
void QDockAreaLayoutInfo::saveState(QDataStream &stream) const | |
{ | |
#ifndef QT_NO_TABBAR | |
if (tabbed) { | |
stream << (uchar) TabMarker; | |
// write the index in item_list of the widget that's currently on top. | |
quintptr id = currentTabId(); | |
int index = -1; | |
for (int i = 0; i < item_list.count(); ++i) { | |
if (tabId(item_list.at(i)) == id) { | |
index = i; | |
break; | |
} | |
} | |
stream << index; | |
} else | |
#endif // QT_NO_TABBAR | |
{ | |
stream << (uchar) SequenceMarker; | |
} | |
stream << (uchar) o << item_list.count(); | |
for (int i = 0; i < item_list.count(); ++i) { | |
const QDockAreaLayoutItem &item = item_list.at(i); | |
if (item.widgetItem != 0) { | |
stream << (uchar) WidgetMarker; | |
QWidget *w = item.widgetItem->widget(); | |
QString name = w->objectName(); | |
if (name.isEmpty()) { | |
qWarning("QMainWindow::saveState(): 'objectName' not set for QDockWidget %p '%s;", | |
w, qPrintable(w->windowTitle())); | |
} | |
stream << name; | |
uchar flags = 0; | |
if (!w->isHidden()) | |
flags |= StateFlagVisible; | |
if (w->isWindow()) | |
flags |= StateFlagFloating; | |
stream << flags; | |
if (w->isWindow()) { | |
stream << w->x() << w->y() << w->width() << w->height(); | |
} else { | |
stream << item.pos << item.size << pick(o, item.minimumSize()) | |
<< pick(o, item.maximumSize()); | |
} | |
} else if (item.placeHolderItem != 0) { | |
stream << (uchar) WidgetMarker; | |
stream << item.placeHolderItem->objectName; | |
uchar flags = 0; | |
if (!item.placeHolderItem->hidden) | |
flags |= StateFlagVisible; | |
if (item.placeHolderItem->window) | |
flags |= StateFlagFloating; | |
stream << flags; | |
if (item.placeHolderItem->window) { | |
QRect r = item.placeHolderItem->topLevelRect; | |
stream << r.x() << r.y() << r.width() << r.height(); | |
} else { | |
stream << item.pos << item.size << (int)0 << (int)0; | |
} | |
} else if (item.subinfo != 0) { | |
stream << (uchar) SequenceMarker << item.pos << item.size << pick(o, item.minimumSize()) << pick(o, item.maximumSize()); | |
item.subinfo->saveState(stream); | |
} | |
} | |
} | |
static Qt::DockWidgetArea toDockWidgetArea(QInternal::DockPosition pos) | |
{ | |
switch (pos) { | |
case QInternal::LeftDock: return Qt::LeftDockWidgetArea; | |
case QInternal::RightDock: return Qt::RightDockWidgetArea; | |
case QInternal::TopDock: return Qt::TopDockWidgetArea; | |
case QInternal::BottomDock: return Qt::BottomDockWidgetArea; | |
default: break; | |
} | |
return Qt::NoDockWidgetArea; | |
} | |
static QRect constrainedRect(QRect rect, const QRect &desktop) | |
{ | |
if (desktop.isValid()) { | |
rect.setWidth(qMin(rect.width(), desktop.width())); | |
rect.setHeight(qMin(rect.height(), desktop.height())); | |
rect.moveLeft(qMax(rect.left(), desktop.left())); | |
rect.moveTop(qMax(rect.top(), desktop.top())); | |
rect.moveRight(qMin(rect.right(), desktop.right())); | |
rect.moveBottom(qMin(rect.bottom(), desktop.bottom())); | |
} | |
return rect; | |
} | |
bool QDockAreaLayoutInfo::restoreState(QDataStream &stream, QList<QDockWidget*> &widgets, bool testing) | |
{ | |
uchar marker; | |
stream >> marker; | |
if (marker != TabMarker && marker != SequenceMarker) | |
return false; | |
#ifndef QT_NO_TABBAR | |
tabbed = marker == TabMarker; | |
int index = -1; | |
if (tabbed) | |
stream >> index; | |
#endif | |
uchar orientation; | |
stream >> orientation; | |
o = static_cast<Qt::Orientation>(orientation); | |
int cnt; | |
stream >> cnt; | |
for (int i = 0; i < cnt; ++i) { | |
uchar nextMarker; | |
stream >> nextMarker; | |
if (nextMarker == WidgetMarker) { | |
QString name; | |
uchar flags; | |
stream >> name >> flags; | |
if (name.isEmpty()) { | |
int dummy; | |
stream >> dummy >> dummy >> dummy >> dummy; | |
continue; | |
} | |
QDockWidget *widget = 0; | |
for (int j = 0; j < widgets.count(); ++j) { | |
if (widgets.at(j)->objectName() == name) { | |
widget = widgets.takeAt(j); | |
break; | |
} | |
} | |
if (widget == 0) { | |
QPlaceHolderItem *placeHolder = new QPlaceHolderItem; | |
QDockAreaLayoutItem item(placeHolder); | |
placeHolder->objectName = name; | |
placeHolder->window = flags & StateFlagFloating; | |
placeHolder->hidden = !(flags & StateFlagVisible); | |
if (placeHolder->window) { | |
int x, y, w, h; | |
stream >> x >> y >> w >> h; | |
placeHolder->topLevelRect = QRect(x, y, w, h); | |
} else { | |
int dummy; | |
stream >> item.pos >> item.size >> dummy >> dummy; | |
} | |
if (item.size != -1) | |
item.flags |= QDockAreaLayoutItem::KeepSize; | |
if (!testing) | |
item_list.append(item); | |
} else { | |
QDockAreaLayoutItem item(new QDockWidgetItem(widget)); | |
if (flags & StateFlagFloating) { | |
bool drawer = false; | |
#ifdef Q_WS_MAC // drawer support | |
extern bool qt_mac_is_macdrawer(const QWidget *); //qwidget_mac.cpp | |
extern bool qt_mac_set_drawer_preferred_edge(QWidget *, Qt::DockWidgetArea); //qwidget_mac.cpp | |
drawer = qt_mac_is_macdrawer(widget); | |
#endif | |
if (!testing) { | |
widget->hide(); | |
if (!drawer) | |
widget->setFloating(true); | |
} | |
int x, y, w, h; | |
stream >> x >> y >> w >> h; | |
#ifdef Q_WS_MAC // drawer support | |
if (drawer) { | |
mainWindow->window()->createWinId(); | |
widget->window()->createWinId(); | |
qt_mac_set_drawer_preferred_edge(widget, toDockWidgetArea(dockPos)); | |
} else | |
#endif | |
if (!testing) { | |
QRect r(x, y, w, h); | |
QDesktopWidget *desktop = QApplication::desktop(); | |
if (desktop->isVirtualDesktop()) | |
r = constrainedRect(r, desktop->screenGeometry(desktop->screenNumber(r.topLeft()))); | |
else | |
r = constrainedRect(r, desktop->screenGeometry(widget)); | |
widget->move(r.topLeft()); | |
widget->resize(r.size()); | |
} | |
if (!testing) { | |
widget->setVisible(flags & StateFlagVisible); | |
item_list.append(item); | |
} | |
} else { | |
int dummy; | |
stream >> item.pos >> item.size >> dummy >> dummy; | |
if (!testing) { | |
item_list.append(item); | |
widget->setFloating(false); | |
widget->setVisible(flags & StateFlagVisible); | |
emit widget->dockLocationChanged(toDockWidgetArea(dockPos)); | |
} | |
} | |
if (testing) { | |
//was it is not really added to the layout, we need to delete the object here | |
delete item.widgetItem; | |
} | |
} | |
} else if (nextMarker == SequenceMarker) { | |
int dummy; | |
#ifdef QT_NO_TABBAR | |
const int tabBarShape = 0; | |
#endif | |
QDockAreaLayoutItem item(new QDockAreaLayoutInfo(sep, dockPos, o, | |
tabBarShape, mainWindow)); | |
stream >> item.pos >> item.size >> dummy >> dummy; | |
//we need to make sure the element is in the list so the dock widget can eventually be docked correctly | |
if (!testing) | |
item_list.append(item); | |
//here we need to make sure we change the item in the item_list | |
QDockAreaLayoutItem &lastItem = testing ? item : item_list.last(); | |
if (!lastItem.subinfo->restoreState(stream, widgets, testing)) | |
return false; | |
} else { | |
return false; | |
} | |
} | |
#ifndef QT_NO_TABBAR | |
if (!testing && tabbed && index >= 0 && index < item_list.count()) { | |
updateTabBar(); | |
setCurrentTabId(tabId(item_list.at(index))); | |
} | |
if (!testing && *sep == 1) | |
updateSeparatorWidgets(); | |
#endif | |
return true; | |
} | |
#ifndef QT_NO_TABBAR | |
void QDockAreaLayoutInfo::updateSeparatorWidgets() const | |
{ | |
if (tabbed) { | |
separatorWidgets.clear(); | |
return; | |
} | |
int j = 0; | |
for (int i = 0; i < item_list.count(); ++i) { | |
const QDockAreaLayoutItem &item = item_list.at(i); | |
if (item.skip()) | |
continue; | |
int next = this->next(i); | |
if ((item.flags & QDockAreaLayoutItem::GapItem) | |
|| (next != -1 && (item_list.at(next).flags & QDockAreaLayoutItem::GapItem))) | |
continue; | |
if (item.subinfo) { | |
item.subinfo->updateSeparatorWidgets(); | |
} | |
if (next == -1) | |
break; | |
QWidget *sepWidget; | |
if (j < separatorWidgets.size() && separatorWidgets.at(j)) { | |
sepWidget = separatorWidgets.at(j); | |
} else { | |
sepWidget = mainWindowLayout()->getSeparatorWidget(); | |
separatorWidgets.append(sepWidget); | |
} | |
j++; | |
#ifndef QT_MAC_USE_COCOA | |
sepWidget->raise(); | |
#endif | |
QRect sepRect = separatorRect(i).adjusted(-2, -2, 2, 2); | |
sepWidget->setGeometry(sepRect); | |
sepWidget->setMask( QRegion(separatorRect(i).translated( - sepRect.topLeft()))); | |
sepWidget->show(); | |
} | |
for (int k = j; k < separatorWidgets.size(); ++k) { | |
separatorWidgets[k]->hide(); | |
} | |
separatorWidgets.resize(j); | |
Q_ASSERT(separatorWidgets.size() == j); | |
} | |
#endif //QT_NO_TABBAR | |
#ifndef QT_NO_TABBAR | |
//returns whether the tabbar is visible or not | |
bool QDockAreaLayoutInfo::updateTabBar() const | |
{ | |
if (!tabbed) | |
return false; | |
QDockAreaLayoutInfo *that = const_cast<QDockAreaLayoutInfo*>(this); | |
if (that->tabBar == 0) { | |
that->tabBar = mainWindowLayout()->getTabBar(); | |
that->tabBar->setShape(static_cast<QTabBar::Shape>(tabBarShape)); | |
that->tabBar->setDrawBase(true); | |
} | |
bool blocked = tabBar->blockSignals(true); | |
bool gap = false; | |
int tab_idx = 0; | |
bool changed = false; | |
for (int i = 0; i < item_list.count(); ++i) { | |
const QDockAreaLayoutItem &item = item_list.at(i); | |
if (item.skip()) | |
continue; | |
if (item.flags & QDockAreaLayoutItem::GapItem) { | |
gap = true; | |
continue; | |
} | |
if (item.widgetItem == 0) | |
continue; | |
QDockWidget *dw = qobject_cast<QDockWidget*>(item.widgetItem->widget()); | |
QString title = dw->d_func()->fixedWindowTitle; | |
quintptr id = tabId(item); | |
if (tab_idx == tabBar->count()) { | |
tabBar->insertTab(tab_idx, title); | |
#ifndef QT_NO_TOOLTIP | |
tabBar->setTabToolTip(tab_idx, title); | |
#endif | |
tabBar->setTabData(tab_idx, id); | |
changed = true; | |
} else if (qvariant_cast<quintptr>(tabBar->tabData(tab_idx)) != id) { | |
if (tab_idx + 1 < tabBar->count() | |
&& qvariant_cast<quintptr>(tabBar->tabData(tab_idx + 1)) == id) | |
tabBar->removeTab(tab_idx); | |
else { | |
tabBar->insertTab(tab_idx, title); | |
#ifndef QT_NO_TOOLTIP | |
tabBar->setTabToolTip(tab_idx, title); | |
#endif | |
tabBar->setTabData(tab_idx, id); | |
} | |
changed = true; | |
} | |
if (title != tabBar->tabText(tab_idx)) { | |
tabBar->setTabText(tab_idx, title); | |
#ifndef QT_NO_TOOLTIP | |
tabBar->setTabToolTip(tab_idx, title); | |
#endif | |
changed = true; | |
} | |
++tab_idx; | |
} | |
while (tab_idx < tabBar->count()) { | |
tabBar->removeTab(tab_idx); | |
changed = true; | |
} | |
tabBar->blockSignals(blocked); | |
//returns if the tabbar is visible or not | |
return ( (gap ? 1 : 0) + tabBar->count()) > 1; | |
} | |
void QDockAreaLayoutInfo::setTabBarShape(int shape) | |
{ | |
if (shape == tabBarShape) | |
return; | |
tabBarShape = shape; | |
if (tabBar != 0) | |
tabBar->setShape(static_cast<QTabBar::Shape>(shape)); | |
for (int i = 0; i < item_list.count(); ++i) { | |
QDockAreaLayoutItem &item = item_list[i]; | |
if (item.subinfo != 0) | |
item.subinfo->setTabBarShape(shape); | |
} | |
} | |
QSize QDockAreaLayoutInfo::tabBarMinimumSize() const | |
{ | |
if (!updateTabBar()) | |
return QSize(0, 0); | |
return tabBar->minimumSizeHint(); | |
} | |
QSize QDockAreaLayoutInfo::tabBarSizeHint() const | |
{ | |
if (!updateTabBar()) | |
return QSize(0, 0); | |
return tabBar->sizeHint(); | |
} | |
QSet<QTabBar*> QDockAreaLayoutInfo::usedTabBars() const | |
{ | |
QSet<QTabBar*> result; | |
if (tabbed) { | |
updateTabBar(); | |
result.insert(tabBar); | |
} | |
for (int i = 0; i < item_list.count(); ++i) { | |
const QDockAreaLayoutItem &item = item_list.at(i); | |
if (item.subinfo != 0) | |
result += item.subinfo->usedTabBars(); | |
} | |
return result; | |
} | |
// returns a set of all used separator widgets for this dockarelayout info | |
// and all subinfos | |
QSet<QWidget*> QDockAreaLayoutInfo::usedSeparatorWidgets() const | |
{ | |
QSet<QWidget*> result; | |
for (int i = 0; i < separatorWidgets.count(); ++i) | |
result << separatorWidgets.at(i); | |
for (int i = 0; i < item_list.count(); ++i) { | |
const QDockAreaLayoutItem &item = item_list.at(i); | |
if (item.subinfo != 0) | |
result += item.subinfo->usedSeparatorWidgets(); | |
} | |
return result; | |
} | |
QRect QDockAreaLayoutInfo::tabContentRect() const | |
{ | |
if (!tabbed) | |
return QRect(); | |
QRect result = rect; | |
QSize tbh = tabBarSizeHint(); | |
if (!tbh.isNull()) { | |
switch (tabBarShape) { | |
case QTabBar::RoundedNorth: | |
case QTabBar::TriangularNorth: | |
result.adjust(0, tbh.height(), 0, 0); | |
break; | |
case QTabBar::RoundedSouth: | |
case QTabBar::TriangularSouth: | |
result.adjust(0, 0, 0, -tbh.height()); | |
break; | |
case QTabBar::RoundedEast: | |
case QTabBar::TriangularEast: | |
result.adjust(0, 0, -tbh.width(), 0); | |
break; | |
case QTabBar::RoundedWest: | |
case QTabBar::TriangularWest: | |
result.adjust(tbh.width(), 0, 0, 0); | |
break; | |
default: | |
break; | |
} | |
} | |
return result; | |
} | |
#endif // QT_NO_TABBAR | |
/****************************************************************************** | |
** QDockAreaLayout | |
*/ | |
QDockAreaLayout::QDockAreaLayout(QMainWindow *win) : fallbackToSizeHints(true) | |
{ | |
mainWindow = win; | |
sep = win->style()->pixelMetric(QStyle::PM_DockWidgetSeparatorExtent, 0, win); | |
#ifndef QT_NO_TABBAR | |
const int tabShape = QTabBar::RoundedSouth; | |
#else | |
const int tabShape = 0; | |
#endif | |
docks[QInternal::LeftDock] | |
= QDockAreaLayoutInfo(&sep, QInternal::LeftDock, Qt::Vertical, tabShape, win); | |
docks[QInternal::RightDock] | |
= QDockAreaLayoutInfo(&sep, QInternal::RightDock, Qt::Vertical, tabShape, win); | |
docks[QInternal::TopDock] | |
= QDockAreaLayoutInfo(&sep, QInternal::TopDock, Qt::Horizontal, tabShape, win); | |
docks[QInternal::BottomDock] | |
= QDockAreaLayoutInfo(&sep, QInternal::BottomDock, Qt::Horizontal, tabShape, win); | |
centralWidgetItem = 0; | |
corners[Qt::TopLeftCorner] = Qt::TopDockWidgetArea; | |
corners[Qt::TopRightCorner] = Qt::TopDockWidgetArea; | |
corners[Qt::BottomLeftCorner] = Qt::BottomDockWidgetArea; | |
corners[Qt::BottomRightCorner] = Qt::BottomDockWidgetArea; | |
} | |
bool QDockAreaLayout::isValid() const | |
{ | |
return rect.isValid(); | |
} | |
void QDockAreaLayout::saveState(QDataStream &stream) const | |
{ | |
stream << (uchar) DockWidgetStateMarker; | |
int cnt = 0; | |
for (int i = 0; i < QInternal::DockCount; ++i) { | |
if (!docks[i].item_list.isEmpty()) | |
++cnt; | |
} | |
stream << cnt; | |
for (int i = 0; i < QInternal::DockCount; ++i) { | |
if (docks[i].item_list.isEmpty()) | |
continue; | |
stream << i << docks[i].rect.size(); | |
docks[i].saveState(stream); | |
} | |
stream << centralWidgetRect.size(); | |
for (int i = 0; i < 4; ++i) | |
stream << static_cast<int>(corners[i]); | |
} | |
bool QDockAreaLayout::restoreState(QDataStream &stream, const QList<QDockWidget*> &_dockwidgets, bool testing) | |
{ | |
QList<QDockWidget*> dockwidgets = _dockwidgets; | |
int cnt; | |
stream >> cnt; | |
for (int i = 0; i < cnt; ++i) { | |
int pos; | |
stream >> pos; | |
QSize size; | |
stream >> size; | |
if (!testing) { | |
docks[pos].rect = QRect(QPoint(0, 0), size); | |
} | |
if (!docks[pos].restoreState(stream, dockwidgets, testing)) { | |
stream.setStatus(QDataStream::ReadCorruptData); | |
return false; | |
} | |
} | |
QSize size; | |
stream >> size; | |
centralWidgetRect = QRect(QPoint(0, 0), size); | |
bool ok = stream.status() == QDataStream::Ok; | |
if (ok) { | |
int cornerData[4]; | |
for (int i = 0; i < 4; ++i) | |
stream >> cornerData[i]; | |
if (stream.status() == QDataStream::Ok) { | |
for (int i = 0; i < 4; ++i) | |
corners[i] = static_cast<Qt::DockWidgetArea>(cornerData[i]); | |
} | |
if (!testing) | |
fallbackToSizeHints = false; | |
} | |
return ok; | |
} | |
QList<int> QDockAreaLayout::indexOfPlaceHolder(const QString &objectName) const | |
{ | |
for (int i = 0; i < QInternal::DockCount; ++i) { | |
QList<int> result = docks[i].indexOfPlaceHolder(objectName); | |
if (!result.isEmpty()) { | |
result.prepend(i); | |
return result; | |
} | |
} | |
return QList<int>(); | |
} | |
QList<int> QDockAreaLayout::indexOf(QWidget *dockWidget) const | |
{ | |
for (int i = 0; i < QInternal::DockCount; ++i) { | |
QList<int> result = docks[i].indexOf(dockWidget); | |
if (!result.isEmpty()) { | |
result.prepend(i); | |
return result; | |
} | |
} | |
return QList<int>(); | |
} | |
QList<int> QDockAreaLayout::gapIndex(const QPoint &pos) const | |
{ | |
QMainWindow::DockOptions opts = mainWindow->dockOptions(); | |
bool nestingEnabled = opts & QMainWindow::AllowNestedDocks; | |
QDockAreaLayoutInfo::TabMode tabMode = QDockAreaLayoutInfo::NoTabs; | |
#ifndef QT_NO_TABBAR | |
if (opts & QMainWindow::AllowTabbedDocks | |
|| opts & QMainWindow::VerticalTabs) | |
tabMode = QDockAreaLayoutInfo::AllowTabs; | |
if (opts & QMainWindow::ForceTabbedDocks) | |
tabMode = QDockAreaLayoutInfo::ForceTabs; | |
if (tabMode == QDockAreaLayoutInfo::ForceTabs) | |
nestingEnabled = false; | |
#endif | |
for (int i = 0; i < QInternal::DockCount; ++i) { | |
const QDockAreaLayoutInfo &info = docks[i]; | |
if (!info.isEmpty() && info.rect.contains(pos)) { | |
QList<int> result | |
= docks[i].gapIndex(pos, nestingEnabled, tabMode); | |
if (!result.isEmpty()) | |
result.prepend(i); | |
return result; | |
} | |
} | |
for (int i = 0; i < QInternal::DockCount; ++i) { | |
const QDockAreaLayoutInfo &info = docks[i]; | |
if (info.isEmpty()) { | |
QRect r; | |
switch (i) { | |
case QInternal::LeftDock: | |
r = QRect(rect.left(), rect.top(), EmptyDropAreaSize, rect.height()); | |
break; | |
case QInternal::RightDock: | |
r = QRect(rect.right() - EmptyDropAreaSize, rect.top(), | |
EmptyDropAreaSize, rect.height()); | |
break; | |
case QInternal::TopDock: | |
r = QRect(rect.left(), rect.top(), rect.width(), EmptyDropAreaSize); | |
break; | |
case QInternal::BottomDock: | |
r = QRect(rect.left(), rect.bottom() - EmptyDropAreaSize, | |
rect.width(), EmptyDropAreaSize); | |
break; | |
} | |
if (r.contains(pos)) { | |
if (opts & QMainWindow::ForceTabbedDocks && !info.item_list.isEmpty()) { | |
//in case of ForceTabbedDocks, we pass -1 in order to force the gap to be tabbed | |
//it mustn't be completely empty otherwise it won't work | |
return QList<int>() << i << -1 << 0; | |
} else { | |
return QList<int>() << i << 0; | |
} | |
} | |
} | |
} | |
return QList<int>(); | |
} | |
QList<int> QDockAreaLayout::findSeparator(const QPoint &pos) const | |
{ | |
QList<int> result; | |
for (int i = 0; i < QInternal::DockCount; ++i) { | |
const QDockAreaLayoutInfo &info = docks[i]; | |
if (info.isEmpty()) | |
continue; | |
QRect rect = separatorRect(i); | |
if (!rect.isNull() && sep == 1) | |
rect.adjust(-2, -2, 2, 2); | |
if (rect.contains(pos) && !info.hasFixedSize()) { | |
result << i; | |
break; | |
} else if (info.rect.contains(pos)) { | |
result = docks[i].findSeparator(pos); | |
if (!result.isEmpty()) { | |
result.prepend(i); | |
break; | |
} | |
} | |
} | |
return result; | |
} | |
QDockAreaLayoutInfo *QDockAreaLayout::info(QWidget *widget) | |
{ | |
for (int i = 0; i < QInternal::DockCount; ++i) { | |
if (QDockAreaLayoutInfo *result = docks[i].info(widget)) | |
return result; | |
} | |
return 0; | |
} | |
QDockAreaLayoutInfo *QDockAreaLayout::info(const QList<int> &path) | |
{ | |
Q_ASSERT(!path.isEmpty()); | |
const int index = path.first(); | |
Q_ASSERT(index >= 0 && index < QInternal::DockCount); | |
if (path.count() == 1) | |
return &docks[index]; | |
return docks[index].info(path.mid(1)); | |
} | |
const QDockAreaLayoutInfo *QDockAreaLayout::info(const QList<int> &path) const | |
{ | |
return const_cast<QDockAreaLayout*>(this)->info(path); | |
} | |
QDockAreaLayoutItem &QDockAreaLayout::item(const QList<int> &path) | |
{ | |
Q_ASSERT(!path.isEmpty()); | |
const int index = path.first(); | |
Q_ASSERT(index >= 0 && index < QInternal::DockCount); | |
return docks[index].item(path.mid(1)); | |
} | |
QRect QDockAreaLayout::itemRect(const QList<int> &path) const | |
{ | |
Q_ASSERT(!path.isEmpty()); | |
const int index = path.first(); | |
Q_ASSERT(index >= 0 && index < QInternal::DockCount); | |
return docks[index].itemRect(path.mid(1)); | |
} | |
QRect QDockAreaLayout::separatorRect(int index) const | |
{ | |
const QDockAreaLayoutInfo &dock = docks[index]; | |
if (dock.isEmpty()) | |
return QRect(); | |
QRect r = dock.rect; | |
switch (index) { | |
case QInternal::LeftDock: | |
return QRect(r.right() + 1, r.top(), sep, r.height()); | |
case QInternal::RightDock: | |
return QRect(r.left() - sep, r.top(), sep, r.height()); | |
case QInternal::TopDock: | |
return QRect(r.left(), r.bottom() + 1, r.width(), sep); | |
case QInternal::BottomDock: | |
return QRect(r.left(), r.top() - sep, r.width(), sep); | |
default: | |
break; | |
} | |
return QRect(); | |
} | |
QRect QDockAreaLayout::separatorRect(const QList<int> &path) const | |
{ | |
Q_ASSERT(!path.isEmpty()); | |
const int index = path.first(); | |
Q_ASSERT(index >= 0 && index < QInternal::DockCount); | |
if (path.count() == 1) | |
return separatorRect(index); | |
else | |
return docks[index].separatorRect(path.mid(1)); | |
} | |
bool QDockAreaLayout::insertGap(const QList<int> &path, QLayoutItem *dockWidgetItem) | |
{ | |
Q_ASSERT(!path.isEmpty()); | |
const int index = path.first(); | |
Q_ASSERT(index >= 0 && index < QInternal::DockCount); | |
return docks[index].insertGap(path.mid(1), dockWidgetItem); | |
} | |
QLayoutItem *QDockAreaLayout::plug(const QList<int> &path) | |
{ | |
Q_ASSERT(!path.isEmpty()); | |
const int index = path.first(); | |
Q_ASSERT(index >= 0 && index < QInternal::DockCount); | |
return docks[index].plug(path.mid(1)); | |
} | |
QLayoutItem *QDockAreaLayout::unplug(const QList<int> &path) | |
{ | |
Q_ASSERT(!path.isEmpty()); | |
const int index = path.first(); | |
Q_ASSERT(index >= 0 && index < QInternal::DockCount); | |
return docks[index].unplug(path.mid(1)); | |
} | |
void QDockAreaLayout::remove(const QList<int> &path) | |
{ | |
Q_ASSERT(!path.isEmpty()); | |
const int index = path.first(); | |
Q_ASSERT(index >= 0 && index < QInternal::DockCount); | |
docks[index].remove(path.mid(1)); | |
} | |
static inline int qMin(int i1, int i2, int i3) { return qMin(i1, qMin(i2, i3)); } | |
static inline int qMax(int i1, int i2, int i3) { return qMax(i1, qMax(i2, i3)); } | |
void QDockAreaLayout::getGrid(QVector<QLayoutStruct> *_ver_struct_list, | |
QVector<QLayoutStruct> *_hor_struct_list) | |
{ | |
QSize center_hint(0, 0); | |
QSize center_min(0, 0); | |
const bool have_central = centralWidgetItem != 0 && !centralWidgetItem->isEmpty(); | |
if (have_central) { | |
center_hint = centralWidgetRect.size(); | |
if (!center_hint.isValid()) | |
center_hint = centralWidgetItem->sizeHint(); | |
center_min = centralWidgetItem->minimumSize(); | |
} | |
QRect center_rect = rect; | |
if (!docks[QInternal::LeftDock].isEmpty()) | |
center_rect.setLeft(rect.left() + docks[QInternal::LeftDock].rect.width() + sep); | |
if (!docks[QInternal::TopDock].isEmpty()) | |
center_rect.setTop(rect.top() + docks[QInternal::TopDock].rect.height() + sep); | |
if (!docks[QInternal::RightDock].isEmpty()) | |
center_rect.setRight(rect.right() - docks[QInternal::RightDock].rect.width() - sep); | |
if (!docks[QInternal::BottomDock].isEmpty()) | |
center_rect.setBottom(rect.bottom() - docks[QInternal::BottomDock].rect.height() - sep); | |
QSize left_hint = docks[QInternal::LeftDock].size(); | |
if (left_hint.isNull() || fallbackToSizeHints) | |
left_hint = docks[QInternal::LeftDock].sizeHint(); | |
QSize left_min = docks[QInternal::LeftDock].minimumSize(); | |
QSize left_max = docks[QInternal::LeftDock].maximumSize(); | |
left_hint = left_hint.boundedTo(left_max).expandedTo(left_min); | |
QSize right_hint = docks[QInternal::RightDock].size(); | |
if (right_hint.isNull() || fallbackToSizeHints) | |
right_hint = docks[QInternal::RightDock].sizeHint(); | |
QSize right_min = docks[QInternal::RightDock].minimumSize(); | |
QSize right_max = docks[QInternal::RightDock].maximumSize(); | |
right_hint = right_hint.boundedTo(right_max).expandedTo(right_min); | |
QSize top_hint = docks[QInternal::TopDock].size(); | |
if (top_hint.isNull() || fallbackToSizeHints) | |
top_hint = docks[QInternal::TopDock].sizeHint(); | |
QSize top_min = docks[QInternal::TopDock].minimumSize(); | |
QSize top_max = docks[QInternal::TopDock].maximumSize(); | |
top_hint = top_hint.boundedTo(top_max).expandedTo(top_min); | |
QSize bottom_hint = docks[QInternal::BottomDock].size(); | |
if (bottom_hint.isNull() || fallbackToSizeHints) | |
bottom_hint = docks[QInternal::BottomDock].sizeHint(); | |
QSize bottom_min = docks[QInternal::BottomDock].minimumSize(); | |
QSize bottom_max = docks[QInternal::BottomDock].maximumSize(); | |
bottom_hint = bottom_hint.boundedTo(bottom_max).expandedTo(bottom_min); | |
fallbackToSizeHints = false; | |
if (_ver_struct_list != 0) { | |
QVector<QLayoutStruct> &ver_struct_list = *_ver_struct_list; | |
ver_struct_list.resize(3); | |
// top -------------------------------------------------- | |
ver_struct_list[0].init(); | |
ver_struct_list[0].stretch = 0; | |
ver_struct_list[0].sizeHint = top_hint.height(); | |
ver_struct_list[0].minimumSize = top_min.height(); | |
ver_struct_list[0].maximumSize = top_max.height(); | |
ver_struct_list[0].expansive = false; | |
ver_struct_list[0].empty = docks[QInternal::TopDock].isEmpty(); | |
ver_struct_list[0].pos = docks[QInternal::TopDock].rect.top(); | |
ver_struct_list[0].size = docks[QInternal::TopDock].rect.height(); | |
// center -------------------------------------------------- | |
ver_struct_list[1].init(); | |
ver_struct_list[1].stretch = center_hint.height(); | |
bool tl_significant = corners[Qt::TopLeftCorner] == Qt::TopDockWidgetArea | |
|| docks[QInternal::TopDock].isEmpty(); | |
bool bl_significant = corners[Qt::BottomLeftCorner] == Qt::BottomDockWidgetArea | |
|| docks[QInternal::BottomDock].isEmpty(); | |
bool tr_significant = corners[Qt::TopRightCorner] == Qt::TopDockWidgetArea | |
|| docks[QInternal::TopDock].isEmpty(); | |
bool br_significant = corners[Qt::BottomRightCorner] == Qt::BottomDockWidgetArea | |
|| docks[QInternal::BottomDock].isEmpty(); | |
int left = (tl_significant && bl_significant) ? left_hint.height() : 0; | |
int right = (tr_significant && br_significant) ? right_hint.height() : 0; | |
ver_struct_list[1].sizeHint = qMax(left, center_hint.height(), right); | |
left = (tl_significant && bl_significant) ? left_min.height() : 0; | |
right = (tr_significant && br_significant) ? right_min.height() : 0; | |
ver_struct_list[1].minimumSize = qMax(left, center_min.height(), right); | |
ver_struct_list[1].maximumSize = have_central ? QWIDGETSIZE_MAX : 0; | |
ver_struct_list[1].expansive = have_central; | |
ver_struct_list[1].empty = docks[QInternal::LeftDock].isEmpty() | |
&& !have_central | |
&& docks[QInternal::RightDock].isEmpty(); | |
ver_struct_list[1].pos = center_rect.top(); | |
ver_struct_list[1].size = center_rect.height(); | |
// bottom -------------------------------------------------- | |
ver_struct_list[2].init(); | |
ver_struct_list[2].stretch = 0; | |
ver_struct_list[2].sizeHint = bottom_hint.height(); | |
ver_struct_list[2].minimumSize = bottom_min.height(); | |
ver_struct_list[2].maximumSize = bottom_max.height(); | |
ver_struct_list[2].expansive = false; | |
ver_struct_list[2].empty = docks[QInternal::BottomDock].isEmpty(); | |
ver_struct_list[2].pos = docks[QInternal::BottomDock].rect.top(); | |
ver_struct_list[2].size = docks[QInternal::BottomDock].rect.height(); | |
for (int i = 0; i < 3; ++i) { | |
ver_struct_list[i].sizeHint | |
= qMax(ver_struct_list[i].sizeHint, ver_struct_list[i].minimumSize); | |
} | |
} | |
if (_hor_struct_list != 0) { | |
QVector<QLayoutStruct> &hor_struct_list = *_hor_struct_list; | |
hor_struct_list.resize(3); | |
// left -------------------------------------------------- | |
hor_struct_list[0].init(); | |
hor_struct_list[0].stretch = 0; | |
hor_struct_list[0].sizeHint = left_hint.width(); | |
hor_struct_list[0].minimumSize = left_min.width(); | |
hor_struct_list[0].maximumSize = left_max.width(); | |
hor_struct_list[0].expansive = false; | |
hor_struct_list[0].empty = docks[QInternal::LeftDock].isEmpty(); | |
hor_struct_list[0].pos = docks[QInternal::LeftDock].rect.left(); | |
hor_struct_list[0].size = docks[QInternal::LeftDock].rect.width(); | |
// center -------------------------------------------------- | |
hor_struct_list[1].init(); | |
hor_struct_list[1].stretch = center_hint.width(); | |
bool tl_significant = corners[Qt::TopLeftCorner] == Qt::LeftDockWidgetArea | |
|| docks[QInternal::LeftDock].isEmpty(); | |
bool tr_significant = corners[Qt::TopRightCorner] == Qt::RightDockWidgetArea | |
|| docks[QInternal::RightDock].isEmpty(); | |
bool bl_significant = corners[Qt::BottomLeftCorner] == Qt::LeftDockWidgetArea | |
|| docks[QInternal::LeftDock].isEmpty(); | |
bool br_significant = corners[Qt::BottomRightCorner] == Qt::RightDockWidgetArea | |
|| docks[QInternal::RightDock].isEmpty(); | |
int top = (tl_significant && tr_significant) ? top_hint.width() : 0; | |
int bottom = (bl_significant && br_significant) ? bottom_hint.width() : 0; | |
hor_struct_list[1].sizeHint = qMax(top, center_hint.width(), bottom); | |
top = (tl_significant && tr_significant) ? top_min.width() : 0; | |
bottom = (bl_significant && br_significant) ? bottom_min.width() : 0; | |
hor_struct_list[1].minimumSize = qMax(top, center_min.width(), bottom); | |
hor_struct_list[1].maximumSize = have_central ? QWIDGETSIZE_MAX : 0; | |
hor_struct_list[1].expansive = have_central; | |
hor_struct_list[1].empty = !have_central; | |
hor_struct_list[1].pos = center_rect.left(); | |
hor_struct_list[1].size = center_rect.width(); | |
// right -------------------------------------------------- | |
hor_struct_list[2].init(); | |
hor_struct_list[2].stretch = 0; | |
hor_struct_list[2].sizeHint = right_hint.width(); | |
hor_struct_list[2].minimumSize = right_min.width(); | |
hor_struct_list[2].maximumSize = right_max.width(); | |
hor_struct_list[2].expansive = false; | |
hor_struct_list[2].empty = docks[QInternal::RightDock].isEmpty(); | |
hor_struct_list[2].pos = docks[QInternal::RightDock].rect.left(); | |
hor_struct_list[2].size = docks[QInternal::RightDock].rect.width(); | |
for (int i = 0; i < 3; ++i) { | |
hor_struct_list[i].sizeHint | |
= qMax(hor_struct_list[i].sizeHint, hor_struct_list[i].minimumSize); | |
} | |
} | |
} | |
void QDockAreaLayout::setGrid(QVector<QLayoutStruct> *ver_struct_list, | |
QVector<QLayoutStruct> *hor_struct_list) | |
{ | |
// top --------------------------------------------------- | |
if (!docks[QInternal::TopDock].isEmpty()) { | |
QRect r = docks[QInternal::TopDock].rect; | |
if (hor_struct_list != 0) { | |
r.setLeft(corners[Qt::TopLeftCorner] == Qt::TopDockWidgetArea | |
|| docks[QInternal::LeftDock].isEmpty() | |
? rect.left() : hor_struct_list->at(1).pos); | |
r.setRight(corners[Qt::TopRightCorner] == Qt::TopDockWidgetArea | |
|| docks[QInternal::RightDock].isEmpty() | |
? rect.right() : hor_struct_list->at(2).pos - sep - 1); | |
} | |
if (ver_struct_list != 0) { | |
r.setTop(rect.top()); | |
r.setBottom(ver_struct_list->at(1).pos - sep - 1); | |
} | |
docks[QInternal::TopDock].rect = r; | |
docks[QInternal::TopDock].fitItems(); | |
} | |
// bottom --------------------------------------------------- | |
if (!docks[QInternal::BottomDock].isEmpty()) { | |
QRect r = docks[QInternal::BottomDock].rect; | |
if (hor_struct_list != 0) { | |
r.setLeft(corners[Qt::BottomLeftCorner] == Qt::BottomDockWidgetArea | |
|| docks[QInternal::LeftDock].isEmpty() | |
? rect.left() : hor_struct_list->at(1).pos); | |
r.setRight(corners[Qt::BottomRightCorner] == Qt::BottomDockWidgetArea | |
|| docks[QInternal::RightDock].isEmpty() | |
? rect.right() : hor_struct_list->at(2).pos - sep - 1); | |
} | |
if (ver_struct_list != 0) { | |
r.setTop(ver_struct_list->at(2).pos); | |
r.setBottom(rect.bottom()); | |
} | |
docks[QInternal::BottomDock].rect = r; | |
docks[QInternal::BottomDock].fitItems(); | |
} | |
// left --------------------------------------------------- | |
if (!docks[QInternal::LeftDock].isEmpty()) { | |
QRect r = docks[QInternal::LeftDock].rect; | |
if (hor_struct_list != 0) { | |
r.setLeft(rect.left()); | |
r.setRight(hor_struct_list->at(1).pos - sep - 1); | |
} | |
if (ver_struct_list != 0) { | |
r.setTop(corners[Qt::TopLeftCorner] == Qt::LeftDockWidgetArea | |
|| docks[QInternal::TopDock].isEmpty() | |
? rect.top() : ver_struct_list->at(1).pos); | |
r.setBottom(corners[Qt::BottomLeftCorner] == Qt::LeftDockWidgetArea | |
|| docks[QInternal::BottomDock].isEmpty() | |
? rect.bottom() : ver_struct_list->at(2).pos - sep - 1); | |
} | |
docks[QInternal::LeftDock].rect = r; | |
docks[QInternal::LeftDock].fitItems(); | |
} | |
// right --------------------------------------------------- | |
if (!docks[QInternal::RightDock].isEmpty()) { | |
QRect r = docks[QInternal::RightDock].rect; | |
if (hor_struct_list != 0) { | |
r.setLeft(hor_struct_list->at(2).pos); | |
r.setRight(rect.right()); | |
} | |
if (ver_struct_list != 0) { | |
r.setTop(corners[Qt::TopRightCorner] == Qt::RightDockWidgetArea | |
|| docks[QInternal::TopDock].isEmpty() | |
? rect.top() : ver_struct_list->at(1).pos); | |
r.setBottom(corners[Qt::BottomRightCorner] == Qt::RightDockWidgetArea | |
|| docks[QInternal::BottomDock].isEmpty() | |
? rect.bottom() : ver_struct_list->at(2).pos - sep - 1); | |
} | |
docks[QInternal::RightDock].rect = r; | |
docks[QInternal::RightDock].fitItems(); | |
} | |
// center --------------------------------------------------- | |
if (hor_struct_list != 0) { | |
centralWidgetRect.setLeft(hor_struct_list->at(1).pos); | |
centralWidgetRect.setWidth(hor_struct_list->at(1).size); | |
} | |
if (ver_struct_list != 0) { | |
centralWidgetRect.setTop(ver_struct_list->at(1).pos); | |
centralWidgetRect.setHeight(ver_struct_list->at(1).size); | |
} | |
} | |
void QDockAreaLayout::fitLayout() | |
{ | |
QVector<QLayoutStruct> ver_struct_list(3); | |
QVector<QLayoutStruct> hor_struct_list(3); | |
getGrid(&ver_struct_list, &hor_struct_list); | |
qGeomCalc(ver_struct_list, 0, 3, rect.top(), rect.height(), sep); | |
qGeomCalc(hor_struct_list, 0, 3, rect.left(), rect.width(), sep); | |
setGrid(&ver_struct_list, &hor_struct_list); | |
} | |
void QDockAreaLayout::clear() | |
{ | |
for (int i = 0; i < QInternal::DockCount; ++i) | |
docks[i].clear(); | |
rect = QRect(); | |
centralWidgetRect = QRect(); | |
} | |
QSize QDockAreaLayout::sizeHint() const | |
{ | |
int left_sep = 0; | |
int right_sep = 0; | |
int top_sep = 0; | |
int bottom_sep = 0; | |
if (centralWidgetItem != 0) { | |
left_sep = docks[QInternal::LeftDock].isEmpty() ? 0 : sep; | |
right_sep = docks[QInternal::RightDock].isEmpty() ? 0 : sep; | |
top_sep = docks[QInternal::TopDock].isEmpty() ? 0 : sep; | |
bottom_sep = docks[QInternal::BottomDock].isEmpty() ? 0 : sep; | |
} | |
QSize left = docks[QInternal::LeftDock].sizeHint() + QSize(left_sep, 0); | |
QSize right = docks[QInternal::RightDock].sizeHint() + QSize(right_sep, 0); | |
QSize top = docks[QInternal::TopDock].sizeHint() + QSize(0, top_sep); | |
QSize bottom = docks[QInternal::BottomDock].sizeHint() + QSize(0, bottom_sep); | |
QSize center = centralWidgetItem == 0 ? QSize(0, 0) : centralWidgetItem->sizeHint(); | |
int row1 = top.width(); | |
int row2 = left.width() + center.width() + right.width(); | |
int row3 = bottom.width(); | |
int col1 = left.height(); | |
int col2 = top.height() + center.height() + bottom.height(); | |
int col3 = right.height(); | |
if (corners[Qt::TopLeftCorner] == Qt::LeftDockWidgetArea) | |
row1 += left.width(); | |
else | |
col1 += top.height(); | |
if (corners[Qt::TopRightCorner] == Qt::RightDockWidgetArea) | |
row1 += right.width(); | |
else | |
col3 += top.height(); | |
if (corners[Qt::BottomLeftCorner] == Qt::LeftDockWidgetArea) | |
row3 += left.width(); | |
else | |
col1 += bottom.height(); | |
if (corners[Qt::BottomRightCorner] == Qt::RightDockWidgetArea) | |
row3 += right.width(); | |
else | |
col3 += bottom.height(); | |
return QSize(qMax(row1, row2, row3), qMax(col1, col2, col3)); | |
} | |
QSize QDockAreaLayout::minimumSize() const | |
{ | |
int left_sep = 0; | |
int right_sep = 0; | |
int top_sep = 0; | |
int bottom_sep = 0; | |
if (centralWidgetItem != 0) { | |
left_sep = docks[QInternal::LeftDock].isEmpty() ? 0 : sep; | |
right_sep = docks[QInternal::RightDock].isEmpty() ? 0 : sep; | |
top_sep = docks[QInternal::TopDock].isEmpty() ? 0 : sep; | |
bottom_sep = docks[QInternal::BottomDock].isEmpty() ? 0 : sep; | |
} | |
QSize left = docks[QInternal::LeftDock].minimumSize() + QSize(left_sep, 0); | |
QSize right = docks[QInternal::RightDock].minimumSize() + QSize(right_sep, 0); | |
QSize top = docks[QInternal::TopDock].minimumSize() + QSize(0, top_sep); | |
QSize bottom = docks[QInternal::BottomDock].minimumSize() + QSize(0, bottom_sep); | |
QSize center = centralWidgetItem == 0 ? QSize(0, 0) : centralWidgetItem->minimumSize(); | |
int row1 = top.width(); | |
int row2 = left.width() + center.width() + right.width(); | |
int row3 = bottom.width(); | |
int col1 = left.height(); | |
int col2 = top.height() + center.height() + bottom.height(); | |
int col3 = right.height(); | |
if (corners[Qt::TopLeftCorner] == Qt::LeftDockWidgetArea) | |
row1 += left.width(); | |
else | |
col1 += top.height(); | |
if (corners[Qt::TopRightCorner] == Qt::RightDockWidgetArea) | |
row1 += right.width(); | |
else | |
col3 += top.height(); | |
if (corners[Qt::BottomLeftCorner] == Qt::LeftDockWidgetArea) | |
row3 += left.width(); | |
else | |
col1 += bottom.height(); | |
if (corners[Qt::BottomRightCorner] == Qt::RightDockWidgetArea) | |
row3 += right.width(); | |
else | |
col3 += bottom.height(); | |
return QSize(qMax(row1, row2, row3), qMax(col1, col2, col3)); | |
} | |
bool QDockAreaLayout::restoreDockWidget(QDockWidget *dockWidget) | |
{ | |
QList<int> index = indexOfPlaceHolder(dockWidget->objectName()); | |
if (index.isEmpty()) | |
return false; | |
QDockAreaLayoutItem &item = this->item(index); | |
QPlaceHolderItem *placeHolder = item.placeHolderItem; | |
Q_ASSERT(placeHolder != 0); | |
item.widgetItem = new QDockWidgetItem(dockWidget); | |
if (placeHolder->window) { | |
QDesktopWidget desktop; | |
QRect r = constrainedRect(placeHolder->topLevelRect, desktop.screenGeometry(dockWidget)); | |
dockWidget->d_func()->setWindowState(true, true, r); | |
} | |
dockWidget->setVisible(!placeHolder->hidden); | |
#ifdef Q_WS_X11 | |
if (placeHolder->window) // gets rid of the X11BypassWindowManager window flag | |
dockWidget->d_func()->setWindowState(true); | |
#endif | |
item.placeHolderItem = 0; | |
delete placeHolder; | |
return true; | |
} | |
void QDockAreaLayout::addDockWidget(QInternal::DockPosition pos, QDockWidget *dockWidget, | |
Qt::Orientation orientation) | |
{ | |
QLayoutItem *dockWidgetItem = new QDockWidgetItem(dockWidget); | |
QDockAreaLayoutInfo &info = docks[pos]; | |
if (orientation == info.o || info.item_list.count() <= 1) { | |
// empty dock areas, or dock areas containing exactly one widget can have their orientation | |
// switched. | |
info.o = orientation; | |
QDockAreaLayoutItem new_item(dockWidgetItem); | |
info.item_list.append(new_item); | |
#ifndef QT_NO_TABBAR | |
if (info.tabbed && !new_item.skip()) { | |
info.updateTabBar(); | |
info.setCurrentTabId(tabId(new_item)); | |
} | |
#endif | |
} else { | |
#ifndef QT_NO_TABBAR | |
int tbshape = info.tabBarShape; | |
#else | |
int tbshape = 0; | |
#endif | |
QDockAreaLayoutInfo new_info(&sep, pos, orientation, tbshape, mainWindow); | |
new_info.item_list.append(new QDockAreaLayoutInfo(info)); | |
new_info.item_list.append(dockWidgetItem); | |
info = new_info; | |
} | |
QList<int> index = indexOfPlaceHolder(dockWidget->objectName()); | |
if (!index.isEmpty()) | |
remove(index); | |
} | |
void QDockAreaLayout::tabifyDockWidget(QDockWidget *first, QDockWidget *second) | |
{ | |
QList<int> path = indexOf(first); | |
if (path.isEmpty()) | |
return; | |
QDockAreaLayoutInfo *info = this->info(path); | |
Q_ASSERT(info != 0); | |
info->tab(path.last(), new QDockWidgetItem(second)); | |
QList<int> index = indexOfPlaceHolder(second->objectName()); | |
if (!index.isEmpty()) | |
remove(index); | |
} | |
void QDockAreaLayout::splitDockWidget(QDockWidget *after, | |
QDockWidget *dockWidget, | |
Qt::Orientation orientation) | |
{ | |
QList<int> path = indexOf(after); | |
if (path.isEmpty()) | |
return; | |
QDockAreaLayoutInfo *info = this->info(path); | |
Q_ASSERT(info != 0); | |
info->split(path.last(), orientation, new QDockWidgetItem(dockWidget)); | |
QList<int> index = indexOfPlaceHolder(dockWidget->objectName()); | |
if (!index.isEmpty()) | |
remove(index); | |
} | |
void QDockAreaLayout::apply(bool animate) | |
{ | |
QWidgetAnimator &widgetAnimator = qt_mainwindow_layout(mainWindow)->widgetAnimator; | |
for (int i = 0; i < QInternal::DockCount; ++i) | |
docks[i].apply(animate); | |
if (centralWidgetItem != 0 && !centralWidgetItem->isEmpty()) { | |
widgetAnimator.animate(centralWidgetItem->widget(), centralWidgetRect, | |
animate); | |
} | |
#ifndef QT_NO_TABBAR | |
if (sep == 1) | |
updateSeparatorWidgets(); | |
#endif //QT_NO_TABBAR | |
} | |
void QDockAreaLayout::paintSeparators(QPainter *p, QWidget *widget, | |
const QRegion &clip, | |
const QPoint &mouse) const | |
{ | |
for (int i = 0; i < QInternal::DockCount; ++i) { | |
const QDockAreaLayoutInfo &dock = docks[i]; | |
if (dock.isEmpty()) | |
continue; | |
QRect r = separatorRect(i); | |
if (clip.contains(r) && !dock.hasFixedSize()) { | |
Qt::Orientation opposite = dock.o == Qt::Horizontal | |
? Qt::Vertical : Qt::Horizontal; | |
paintSep(p, widget, r, opposite, r.contains(mouse)); | |
} | |
if (clip.contains(dock.rect)) | |
dock.paintSeparators(p, widget, clip, mouse); | |
} | |
} | |
QRegion QDockAreaLayout::separatorRegion() const | |
{ | |
QRegion result; | |
for (int i = 0; i < QInternal::DockCount; ++i) { | |
const QDockAreaLayoutInfo &dock = docks[i]; | |
if (dock.isEmpty()) | |
continue; | |
result |= separatorRect(i); | |
result |= dock.separatorRegion(); | |
} | |
return result; | |
} | |
int QDockAreaLayout::separatorMove(const QList<int> &separator, const QPoint &origin, | |
const QPoint &dest) | |
{ | |
int delta = 0; | |
int index = separator.last(); | |
if (separator.count() > 1) { | |
QDockAreaLayoutInfo *info = this->info(separator); | |
delta = pick(info->o, dest - origin); | |
if (delta != 0) | |
delta = info->separatorMove(index, delta); | |
info->apply(false); | |
return delta; | |
} | |
QVector<QLayoutStruct> list; | |
if (index == QInternal::LeftDock || index == QInternal::RightDock) | |
getGrid(0, &list); | |
else | |
getGrid(&list, 0); | |
int sep_index = index == QInternal::LeftDock || index == QInternal::TopDock | |
? 0 : 1; | |
Qt::Orientation o = index == QInternal::LeftDock || index == QInternal::RightDock | |
? Qt::Horizontal | |
: Qt::Vertical; | |
delta = pick(o, dest - origin); | |
delta = separatorMoveHelper(list, sep_index, delta, sep); | |
if (index == QInternal::LeftDock || index == QInternal::RightDock) | |
setGrid(0, &list); | |
else | |
setGrid(&list, 0); | |
apply(false); | |
return delta; | |
} | |
#ifndef QT_NO_TABBAR | |
// Sets the correct positions for the separator widgets | |
// Allocates new sepearator widgets with getSeparatorWidget | |
void QDockAreaLayout::updateSeparatorWidgets() const | |
{ | |
int j = 0; | |
for (int i = 0; i < QInternal::DockCount; ++i) { | |
const QDockAreaLayoutInfo &dock = docks[i]; | |
if (dock.isEmpty()) | |
continue; | |
QWidget *sepWidget; | |
if (j < separatorWidgets.size()) { | |
sepWidget = separatorWidgets.at(j); | |
} else { | |
sepWidget = qt_mainwindow_layout(mainWindow)->getSeparatorWidget(); | |
separatorWidgets.append(sepWidget); | |
} | |
j++; | |
#ifndef QT_MAC_USE_COCOA | |
sepWidget->raise(); | |
#endif | |
QRect sepRect = separatorRect(i).adjusted(-2, -2, 2, 2); | |
sepWidget->setGeometry(sepRect); | |
sepWidget->setMask( QRegion(separatorRect(i).translated( - sepRect.topLeft()))); | |
sepWidget->show(); | |
} | |
for (int i = j; i < separatorWidgets.size(); ++i) | |
separatorWidgets.at(i)->hide(); | |
separatorWidgets.resize(j); | |
} | |
#endif //QT_NO_TABBAR | |
QLayoutItem *QDockAreaLayout::itemAt(int *x, int index) const | |
{ | |
Q_ASSERT(x != 0); | |
for (int i = 0; i < QInternal::DockCount; ++i) { | |
const QDockAreaLayoutInfo &dock = docks[i]; | |
if (QLayoutItem *ret = dock.itemAt(x, index)) | |
return ret; | |
} | |
if (centralWidgetItem && (*x)++ == index) | |
return centralWidgetItem; | |
return 0; | |
} | |
QLayoutItem *QDockAreaLayout::takeAt(int *x, int index) | |
{ | |
Q_ASSERT(x != 0); | |
for (int i = 0; i < QInternal::DockCount; ++i) { | |
QDockAreaLayoutInfo &dock = docks[i]; | |
if (QLayoutItem *ret = dock.takeAt(x, index)) | |
return ret; | |
} | |
if (centralWidgetItem && (*x)++ == index) { | |
QLayoutItem *ret = centralWidgetItem; | |
centralWidgetItem = 0; | |
return ret; | |
} | |
return 0; | |
} | |
void QDockAreaLayout::deleteAllLayoutItems() | |
{ | |
for (int i = 0; i < QInternal::DockCount; ++i) | |
docks[i].deleteAllLayoutItems(); | |
} | |
#ifndef QT_NO_TABBAR | |
QSet<QTabBar*> QDockAreaLayout::usedTabBars() const | |
{ | |
QSet<QTabBar*> result; | |
for (int i = 0; i < QInternal::DockCount; ++i) { | |
const QDockAreaLayoutInfo &dock = docks[i]; | |
result += dock.usedTabBars(); | |
} | |
return result; | |
} | |
// Returns the set of all used separator widgets | |
QSet<QWidget*> QDockAreaLayout::usedSeparatorWidgets() const | |
{ | |
QSet<QWidget*> result; | |
for (int i = 0; i < separatorWidgets.count(); ++i) | |
result << separatorWidgets.at(i); | |
for (int i = 0; i < QInternal::DockCount; ++i) { | |
const QDockAreaLayoutInfo &dock = docks[i]; | |
result += dock.usedSeparatorWidgets(); | |
} | |
return result; | |
} | |
#endif | |
QRect QDockAreaLayout::gapRect(const QList<int> &path) const | |
{ | |
const QDockAreaLayoutInfo *info = this->info(path); | |
if (info == 0) | |
return QRect(); | |
const QList<QDockAreaLayoutItem> &item_list = info->item_list; | |
Qt::Orientation o = info->o; | |
int index = path.last(); | |
if (index < 0 || index >= item_list.count()) | |
return QRect(); | |
const QDockAreaLayoutItem &item = item_list.at(index); | |
if (!(item.flags & QDockAreaLayoutItem::GapItem)) | |
return QRect(); | |
QRect result; | |
#ifndef QT_NO_TABBAR | |
if (info->tabbed) { | |
result = info->tabContentRect(); | |
} else | |
#endif | |
{ | |
int pos = item.pos; | |
int size = item.size; | |
int prev = info->prev(index); | |
int next = info->next(index); | |
if (prev != -1 && !(item_list.at(prev).flags & QDockAreaLayoutItem::GapItem)) { | |
pos += sep; | |
size -= sep; | |
} | |
if (next != -1 && !(item_list.at(next).flags & QDockAreaLayoutItem::GapItem)) | |
size -= sep; | |
QPoint p; | |
rpick(o, p) = pos; | |
rperp(o, p) = perp(o, info->rect.topLeft()); | |
QSize s; | |
rpick(o, s) = size; | |
rperp(o, s) = perp(o, info->rect.size()); | |
result = QRect(p, s); | |
} | |
return result; | |
} | |
void QDockAreaLayout::keepSize(QDockWidget *w) | |
{ | |
QList<int> path = indexOf(w); | |
if (path.isEmpty()) | |
return; | |
QDockAreaLayoutItem &item = this->item(path); | |
if (item.size != -1) | |
item.flags |= QDockAreaLayoutItem::KeepSize; | |
} | |
void QDockAreaLayout::styleChangedEvent() | |
{ | |
sep = mainWindow->style()->pixelMetric(QStyle::PM_DockWidgetSeparatorExtent, 0, mainWindow); | |
fitLayout(); | |
} | |
QT_END_NAMESPACE | |
#endif // QT_NO_DOCKWIDGET |