1
/****************************************************************************
3
** Copyright (C) 1992-2005 Trolltech AS. All rights reserved.
5
** This file is part of the widgets module of the Qt Toolkit.
7
** This file may be distributed under the terms of the Q Public License
8
** as defined by Trolltech AS of Norway and appearing in the file
9
** LICENSE.QPL included in the packaging of this file.
11
** This file may be distributed and/or modified under the terms of the
12
** GNU General Public License version 2 as published by the Free Software
13
** Foundation and appearing in the file LICENSE.GPL included in the
14
** packaging of this file.
16
** See http://www.trolltech.com/pricing.html or email sales@trolltech.com for
17
** information about Qt Commercial License Agreements.
18
** See http://www.trolltech.com/qpl/ for QPL licensing information.
19
** See http://www.trolltech.com/gpl/ for GPL licensing information.
21
** Contact info@trolltech.com if any conditions of this licensing are
24
** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
25
** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
27
****************************************************************************/
29
#include "qmainwindowlayout_p.h"
30
#include "qdockseparator_p.h"
31
#include "qdockwidgetlayout_p.h"
33
#include "qdockwidget.h"
34
#include "qmainwindow.h"
37
#include <qapplication.h>
39
#include <qstatusbar.h>
41
#include <qvarlengtharray.h>
45
#include <private/qlayoutengine_p.h>
47
// #define LAYOUT_DEBUG
48
#if defined(LAYOUT_DEBUG)
51
# define DEBUG if(false)qDebug
54
// #define LAYOUT_DEBUG_VERBOSE
55
#if defined(LAYOUT_DEBUG_VERBOSE)
56
# define VDEBUG qDebug
58
# define VDEBUG if(false)qDebug
61
// #define TOOLBAR_DEBUG
62
#if defined(TOOLBAR_DEBUG)
63
# define TBDEBUG qDebug
65
# define TBDEBUG if(false)qDebug
79
static inline uint areaForPosition(int pos)
80
{ return ((1u << pos) & 0xf); }
82
static inline POSITION positionForArea(uint area)
85
case Qt::LeftDockWidgetArea: return LEFT;
86
case Qt::RightDockWidgetArea: return RIGHT;
87
case Qt::TopDockWidgetArea: return TOP;
88
case Qt::BottomDockWidgetArea: return BOTTOM;
94
static inline POSITION positionForArea(Qt::ToolBarArea area)
97
case Qt::LeftToolBarArea: return LEFT;
98
case Qt::RightToolBarArea: return RIGHT;
99
case Qt::TopToolBarArea: return TOP;
100
case Qt::BottomToolBarArea: return BOTTOM;
106
static inline int pick(POSITION p, const QSize &s)
107
{ return p == TOP || p == BOTTOM ? s.height() : s.width(); }
109
static inline int pick(POSITION p, const QPoint &pt)
110
{ return p == TOP || p == BOTTOM ? pt.y() : pt.x(); }
112
static inline void set(POSITION p, QSize &s, int x)
113
{ if (p == LEFT || p == RIGHT) s.setWidth(x); else s.setHeight(x); }
115
static inline int pick_perp(POSITION p, const QSize &s)
116
{ return p == TOP || p == BOTTOM ? s.width() : s.height(); }
118
static inline int pick_perp(POSITION p, const QPoint &pt)
119
{ return p == TOP || p == BOTTOM ? pt.x() : pt.y(); }
121
static inline void set_perp(POSITION p, QSize &s, int x)
122
{ if (p == TOP || p == BOTTOM) s.setWidth(x); else s.setHeight(x); }
124
static inline void set_perp(POSITION p, QPoint &pt, int x)
125
{ if (p == TOP || p == BOTTOM) pt.setX(x); else pt.setY(x); }
127
class QMainWindowLayoutItem : public QWidgetItem
130
inline QMainWindowLayoutItem(QWidget *w, const QRect &r)
131
: QWidgetItem(w), rect(r)
134
inline QSize sizeHint() const
135
{ return rect.size(); }
136
inline void setGeometry( const QRect &r)
138
inline QRect geometry() const
140
inline bool isEmpty() const
148
QMainWindowLayout::QMainWindowLayout(QMainWindow *mainwindow)
149
: QLayout(mainwindow), statusbar(0), relayout_type(QInternal::RelayoutNormal), save_layout_info(0),
150
save_tb_layout_info(0)
152
setObjectName(mainwindow->objectName() + "_layout");
154
corners[Qt::TopLeftCorner] = Qt::TopDockWidgetArea;
155
corners[Qt::TopRightCorner] = Qt::TopDockWidgetArea;
156
corners[Qt::BottomLeftCorner] = Qt::BottomDockWidgetArea;
157
corners[Qt::BottomRightCorner] = Qt::BottomDockWidgetArea;
159
for (int i = 0; i < Qt::NDockWidgetAreas + 1; ++i) {
160
QMainWindowLayoutInfo info;
163
info.is_dummy = false;
164
layout_info.append(info);
168
QMainWindowLayout::~QMainWindowLayout()
170
for (int line = 0; line < tb_layout_info.size(); ++line) {
171
const ToolBarLineInfo &lineInfo = tb_layout_info.at(line);
172
for (int i = 0; i < lineInfo.list.size(); ++i)
173
delete lineInfo.list.at(i).item;
175
tb_layout_info.clear();
176
for (int i = 0; i < NPOSITIONS; ++i) {
177
delete layout_info[i].item;
178
if (layout_info[i].sep)
179
delete layout_info[i].sep->widget();
180
delete layout_info[i].sep;
181
layout_info[i].item = 0;
182
layout_info[i].sep = 0;
187
QStatusBar *QMainWindowLayout::statusBar() const
188
{ return statusbar ? qobject_cast<QStatusBar *>(statusbar->widget()) : 0; }
190
void QMainWindowLayout::setStatusBar(QStatusBar *sb)
195
statusbar = sb ? new QWidgetItem(sb) : 0;
198
QWidget *QMainWindowLayout::centralWidget() const
199
{ return layout_info[CENTER].item ? layout_info[CENTER].item->widget() : 0; }
201
void QMainWindowLayout::setCentralWidget(QWidget *cw)
203
delete layout_info[CENTER].item;
206
layout_info[CENTER].item = new QWidgetItem(cw);
208
layout_info[CENTER].item = 0;
210
layout_info[CENTER].size = QSize();
214
void QMainWindowLayout::addToolBarBreak(Qt::ToolBarArea area)
216
ToolBarLineInfo newLine;
217
newLine.pos = positionForArea(area);
218
switch (newLine.pos) {
222
for (int line = 0; line < tb_layout_info.size(); ++line) {
223
ToolBarLineInfo &lineInfo = tb_layout_info[line];
224
if (lineInfo.pos == LEFT || lineInfo.pos == RIGHT) {
225
tb_layout_info.insert(line, newLine);
230
// fall through intended
232
tb_layout_info.append(newLine);
233
TBDEBUG() << "appended new line";
238
void QMainWindowLayout::insertToolBarBreak(QToolBar *before)
240
for (int line = 0; line < tb_layout_info.size(); ++line) {
241
ToolBarLineInfo &lineInfo = tb_layout_info[line];
242
for (int i = 0; i < lineInfo.list.size(); ++i) {
243
const ToolBarLayoutInfo &info = lineInfo.list.at(i);
244
if (info.item->widget() == before) {
245
ToolBarLineInfo newLine;
246
newLine.pos = lineInfo.pos;
247
for (; i < lineInfo.list.size(); ++i)
248
newLine.list += lineInfo.list.takeAt(i);
249
tb_layout_info.insert(line + 1, newLine);
257
Adds \a toolbar to \a area, continuing the current line.
259
void QMainWindowLayout::addToolBar(Qt::ToolBarArea area,
261
bool needAddChildWidget)
263
if (needAddChildWidget)
264
addChildWidget(toolbar);
266
removeToolBarInfo(toolbar);
268
POSITION pos = positionForArea(area);
269
// see if we have an existing line in the tb - append it in the last in line
270
for (int line = 0; line < tb_layout_info.size(); ++line) {
271
if (tb_layout_info.at(line).pos == pos) {
272
while (line < tb_layout_info.size() - 1 && tb_layout_info.at(line + 1).pos == pos)
278
toolbar->setOrientation(Qt::Horizontal);
282
toolbar->setOrientation(Qt::Vertical);
288
ToolBarLineInfo &lineInfo = tb_layout_info[line];
289
ToolBarLayoutInfo newinfo;
290
newinfo.item = new QWidgetItem(toolbar);
291
lineInfo.list.append(newinfo);
296
// no line to continue, add one and recurse
297
addToolBarBreak(area);
298
addToolBar(area, toolbar, false);
302
Adds \a toolbar before \a before
304
void QMainWindowLayout::insertToolBar(QToolBar *before, QToolBar *toolbar)
306
addChildWidget(toolbar);
308
for (int line = 0; line < tb_layout_info.size(); ++line) {
309
const ToolBarLineInfo &lineInfo = tb_layout_info.at(line);
310
for (int i = 0; i < lineInfo.list.size(); ++i) {
311
const ToolBarLayoutInfo &info = lineInfo.list.at(i);
312
if (info.item->widget() == before) {
314
ToolBarLayoutInfo newInfo;
315
newInfo.item = new QWidgetItem(toolbar);
316
tb_layout_info[line].list.insert(i, newInfo);
323
Qt::ToolBarArea QMainWindowLayout::toolBarArea(QToolBar *toolbar) const
325
for (int line = 0; line < tb_layout_info.size(); ++line) {
326
const ToolBarLineInfo &lineInfo = tb_layout_info.at(line);
327
for (int i = 0; i < lineInfo.list.size(); ++i) {
328
const ToolBarLayoutInfo &info = lineInfo.list.at(i);
329
if (info.item->widget() == toolbar)
330
return static_cast<Qt::ToolBarArea>(areaForPosition(lineInfo.pos));
333
Q_ASSERT_X(false, "QMainWindow::toolBarArea", "'toolbar' is not managed by this main window.");
334
return Qt::TopToolBarArea;
337
QDockWidgetLayout *QMainWindowLayout::layoutForArea(Qt::DockWidgetArea area)
339
POSITION pos = positionForArea(area);
340
QMainWindowLayoutInfo &info = layout_info[pos];
341
QDockWidgetLayout *l = 0;
344
// create new dock window layout
345
static const Qt::Orientation orientations[] = {
346
Qt::Vertical, // LEFT
347
Qt::Vertical, // RIGHT
348
Qt::Horizontal, // TOP
349
Qt::Horizontal, // BOTTOM
352
l = new QDockWidgetLayout(area, orientations[pos]);
354
l->setObjectName(objectName() + "_dockwidgetLayout" + QString::number(area, 16));
360
info.sep = new QWidgetItem(new QDockSeparator(l, parentWidget()));
362
l = qobject_cast<QDockWidgetLayout *>(info.item->layout());
368
void QMainWindowLayout::addDockWidget(Qt::DockWidgetArea area, QDockWidget *dockwidget,
369
Qt::Orientation orientation)
371
removeRecursive(dockwidget);
373
QDockWidgetLayout * const layout = layoutForArea(area);
374
layout->extend(dockwidget, orientation);
377
void QMainWindowLayout::splitDockWidget(QDockWidget *after, QDockWidget *dockwidget,
378
Qt::Orientation orientation)
380
removeRecursive(dockwidget);
382
const Qt::DockWidgetArea area = dockWidgetArea(after);
383
QDockWidgetLayout * const layout = layoutForArea(area);
384
layout->split(after, dockwidget, (orientation == Qt::Horizontal
385
? Qt::RightDockWidgetArea
386
: Qt::BottomDockWidgetArea));
389
static bool findWidgetRecursively(QLayoutItem *li, QWidget *w)
391
QLayout *lay = li->layout();
396
while ((child = lay->itemAt(i))) {
397
if (child->widget() == w) {
399
} else if (findWidgetRecursively(child, w)) {
408
Qt::DockWidgetArea QMainWindowLayout::dockWidgetArea(QDockWidget *dockwidget) const
410
for (int pos = 0; pos < NPOSITIONS - 1; ++pos) {
411
if (!layout_info[pos].item)
413
if (findWidgetRecursively(layout_info[pos].item, dockwidget))
414
return static_cast<Qt::DockWidgetArea>(areaForPosition(pos));
416
Q_ASSERT_X(false, "QMainWindow::dockWidgetArea",
417
"'dockwidget' is not managed by this main window.");
418
return Qt::TopDockWidgetArea;
422
void QMainWindowLayout::saveState(QDataStream &stream) const
424
// save toolbar state
425
stream << (uchar) ToolBarStateMarker;
426
stream << tb_layout_info.size(); // number of toolbar lines
427
if (!tb_layout_info.isEmpty()) {
428
for (int line = 0; line < tb_layout_info.size(); ++line) {
429
const ToolBarLineInfo &lineInfo = tb_layout_info.at(line);
430
stream << lineInfo.pos;
431
stream << lineInfo.list.size();
432
for (int i = 0; i < lineInfo.list.size(); ++i) {
433
const ToolBarLayoutInfo &info = lineInfo.list.at(i);
434
QWidget *widget = info.item->widget();
435
if (widget->objectName().isEmpty()) {
436
qWarning("QMainWindow::saveState(): 'objectName' not set for QToolBar "
437
"%p '%s', using 'windowTitle' instead",
438
widget, widget->windowTitle().toLocal8Bit().constData());
439
stream << widget->windowTitle();
441
stream << widget->objectName();
443
stream << (uchar) !widget->isHidden();
446
stream << info.offset;
451
// save dockwidget state
452
stream << (uchar) DockWidgetStateMarker;
454
for (int i = 0; i < NPOSITIONS - 1; ++i) {
455
if (!layout_info[i].item)
460
for (int i = 0; i < NPOSITIONS - 1; ++i) {
461
if (!layout_info[i].item) {
465
stream << layout_info[i].size;
466
const QDockWidgetLayout * const layout =
467
qobject_cast<const QDockWidgetLayout *>(layout_info[i].item->layout());
468
Q_ASSERT(layout != 0);
469
layout->saveState(stream);
472
// save center widget state
473
stream << layout_info[CENTER].size;
476
bool QMainWindowLayout::restoreState(QDataStream &stream)
478
// restore toolbar layout
481
if (tmarker != ToolBarStateMarker)
486
QList<ToolBarLineInfo> toolBarState;
487
QList<QToolBar *> toolbars = qFindChildren<QToolBar *>(parentWidget());
488
for (int line = 0; line < lines; ++line) {
489
ToolBarLineInfo lineInfo;
490
stream >> lineInfo.pos;
493
for (int i = 0; i < size; ++i) {
494
ToolBarLayoutInfo info;
496
stream >> objectName;
501
stream >> info.offset;
504
QToolBar *toolbar = 0;
505
for (int t = 0; t < toolbars.size(); ++t) {
506
QToolBar *tb = toolbars.at(t);
507
if (tb && tb->objectName() == objectName) {
514
qWarning("QMainWindow::restoreState(): cannot find a QToolBar named "
515
"'%s', trying to match using 'windowTitle' instead.",
516
objectName.toLocal8Bit().constData());
517
// try matching the window title
518
for (int t = 0; t < toolbars.size(); ++t) {
519
QToolBar *tb = toolbars.at(t);
520
if (tb && tb->windowTitle() == objectName) {
526
qWarning("QMainWindow::restoreState(): cannot find a QToolBar with "
527
"matching 'windowTitle' (looking for '%s').",
528
objectName.toLocal8Bit().constData());
533
info.item = new QWidgetItem(toolbar);
534
toolbar->setVisible(shown);
535
toolbar->setOrientation((lineInfo.pos == LEFT || lineInfo.pos == RIGHT)
538
lineInfo.list << info;
540
toolBarState << lineInfo;
543
if (stream.status() != QDataStream::Ok)
546
// replace existing toolbar layout
547
for (int line = 0; line < tb_layout_info.size(); ++line) {
548
const ToolBarLineInfo &lineInfo = tb_layout_info.at(line);
549
for (int i = 0; i < lineInfo.list.size(); ++i)
550
delete lineInfo.list.at(i).item;
552
tb_layout_info = toolBarState;
554
// restore dockwidget layout
557
if (dmarker != DockWidgetStateMarker)
560
save_layout_info = new QVector<QMainWindowLayoutInfo>(layout_info);
562
// clear out our working copy
563
for (int i = 0; i < NPOSITIONS - 1; ++i) {
564
layout_info[i].item = 0;
565
layout_info[i].sep = 0;
566
layout_info[i].size = QSize();
567
layout_info[i].is_dummy = false;
572
for (int area = 0; area < areas; ++area) {
575
stream >> layout_info[pos].size;
576
QDockWidgetLayout * const layout =
577
layoutForArea(static_cast<Qt::DockWidgetArea>(areaForPosition(pos)));
578
if (!layout->restoreState(stream)) {
579
stream.setStatus(QDataStream::ReadCorruptData);
584
// restore center widget size
585
stream >> layout_info[CENTER].size;
587
if (stream.status() != QDataStream::Ok) {
588
// restore failed, get rid of the evidence
589
for (int i = 0; i < NPOSITIONS - 1; ++i) {
590
if (layout_info[i].sep)
591
delete layout_info[i].sep->widget();
592
delete layout_info[i].sep;
593
delete layout_info[i].item;
595
layout_info = *save_layout_info;
597
delete save_layout_info;
598
save_layout_info = 0;
599
relayout_type = QInternal::RelayoutNormal;
604
// replace existing dockwidget layout
605
for (int i = 0; i < NPOSITIONS - 1; ++i) {
606
if ((*save_layout_info)[i].sep)
607
delete (*save_layout_info)[i].sep->widget();
608
delete (*save_layout_info)[i].sep;
609
delete (*save_layout_info)[i].item;
612
delete save_layout_info;
613
save_layout_info = 0;
614
relayout_type = QInternal::RelayoutNormal;
620
int QMainWindowLayout::count() const
622
qWarning("QMainWindowLayout::count()");
623
return 10; //#################################################
626
QLayoutItem *QMainWindowLayout::itemAt(int index) const
629
for (int line = 0; line < tb_layout_info.size(); ++line) {
630
const ToolBarLineInfo &lineInfo = tb_layout_info.at(line);
631
for (int i = 0; i < lineInfo.list.size(); ++i) {
633
const ToolBarLayoutInfo &info = lineInfo.list.at(i);
638
for (int i = 0; i < NPOSITIONS; ++i) {
639
if (!layout_info[i].item)
642
return layout_info[i].item;
647
QLayoutItem *QMainWindowLayout::takeAt(int index)
649
DEBUG("QMainWindowLayout::takeAt: index %d", index);
652
for (int line = 0; line < tb_layout_info.size(); ++line) {
653
ToolBarLineInfo &lineInfo = tb_layout_info[line];
654
for (int i = 0; i < lineInfo.list.size(); ++i) {
656
QLayoutItem *ret = lineInfo.list.at(i).item;
657
lineInfo.list.removeAt(i);
658
if (lineInfo.list.size() == 0)
659
tb_layout_info.removeAt(line);
665
for (int i = 0; i < NPOSITIONS; ++i) {
666
if (!layout_info[i].item) continue;
668
VDEBUG() << " where" << i;
669
QLayoutItem *ret = layout_info[i].item;
671
if (!save_layout_info) {
672
layout_info[i].size = QSize();
674
if (layout_info[i].sep) {
675
delete layout_info[i].sep->widget();
676
delete layout_info[i].sep;
680
layout_info[i].item = 0;
681
layout_info[i].sep = 0;
683
VDEBUG() << "END of QMainWindowLayout::takeAt (removed" << i << ")";
688
VDEBUG() << "END of QMainWindowLayout::takeAt (not found)";
693
Fixes the mininum and maximum sizes depending on the current corner
696
void fix_minmax(QVector<QLayoutStruct> &ls,
697
const QMainWindowLayout * const layout,
700
const Qt::DockWidgetArea area = static_cast<Qt::DockWidgetArea>(areaForPosition(pos));
704
Qt::Corner corner1, corner2;
705
POSITION perp1, perp2;
710
Qt::BottomLeftCorner,
717
Qt::BottomRightCorner,
730
Qt::BottomLeftCorner,
731
Qt::BottomRightCorner,
737
if (!layout->layout_info[pos].item)
740
if ((layout->corners[order[pos].corner1] != area
741
|| !layout->layout_info[order[pos].perp1].item)
742
&& (layout->corners[order[pos].corner2] != area
743
|| !layout->layout_info[order[pos].perp2].item)) {
744
// if the area does not occupy any corner, we constrain the
745
// minimum size of the center to the minimum size of the area
746
ls[1].minimumSize = qMax(pick_perp(pos, layout->layout_info[pos].item->minimumSize()),
748
ls[1].maximumSize = qMin(pick_perp(pos, layout->layout_info[pos].item->maximumSize()),
751
// if the area occupies only a single corner, then we
752
// distribute the minimum size of the area across the center
753
// and opposite side equally
754
const int min = pick_perp(pos, layout->layout_info[pos].item->minimumSize());
755
if (layout->layout_info[order[pos].perp1].item
756
&& layout->corners[order[pos].corner1] == area
757
&& layout->corners[order[pos].corner2] != area) {
758
ls[1].minimumSize = qMax(ls[1].minimumSize, min - ls[0].minimumSize);
759
} else if (layout->layout_info[order[pos].perp2].item
760
&& layout->corners[order[pos].corner2] == area
761
&& layout->corners[order[pos].corner1] != area) {
762
ls[1].minimumSize = qMax(ls[1].minimumSize, min - ls[2].minimumSize);
768
Initializes the layout struct with information from the specified
771
static void init_layout_struct(const QMainWindowLayout * const layout,
776
const QMainWindowLayout::QMainWindowLayoutInfo &info = layout->layout_info[pos];
777
ls.empty = info.item->isEmpty();
779
ls.minimumSize = pick(pos, info.item->minimumSize()) + ext;
780
ls.maximumSize = pick(pos, info.item->maximumSize()) + ext;
781
ls.sizeHint = !info.size.isEmpty()
782
? pick(pos, info.size)
783
: pick(pos, info.item->sizeHint()) + ext;
784
// constrain sizeHint
785
ls.sizeHint = qMin(ls.maximumSize, ls.sizeHint);
786
ls.sizeHint = qMax(ls.minimumSize, ls.sizeHint);
791
Returns the size hint for the first user item in a tb layout. This
792
is used to contrain the minimum size a tb can have.
794
static QSize get_item_sh(QLayout *layout)
796
QLayoutItem *item = layout->itemAt(1);
797
if (item && item->widget())
798
return item->widget()->sizeHint();
804
Returns the real size hint for items in a layout - including sizes
807
static QSize get_real_sh(QLayout *layout)
811
while (layout && layout->itemAt(i))
812
real_sh += layout->itemAt(i++)->widget()->sizeHint();
814
int spacing = layout->spacing();
815
int margin = layout->margin();
816
real_sh += QSize(spacing*i + margin*2, spacing*i + margin*2);
820
void QMainWindowLayout::setGeometry(const QRect &_r)
822
QLayout::setGeometry(_r);
826
QRect sbr(QPoint(0, 0),
827
QSize(r.width(), statusbar->heightForWidth(r.width()))
828
.expandedTo(statusbar->minimumSize()));
829
sbr.moveBottom(r.bottom());
830
statusbar->setGeometry(sbr);
831
r.setBottom(sbr.top() - 1);
836
// calculate the respective tool bar rectangles and store the
837
// width/height of the largest tb on each line
838
QVarLengthArray<QRect> tb_rect(tb_layout_info.size());
840
QMap<int, QSize> rest_sz;
841
QStack<QSize> bottom_sz;
842
QStack<QSize> right_sz;
844
QStack<QRect> bottom_rect;
845
QStack<QRect> right_rect;
847
// calculate the width/height of the different tool bar lines -
848
// the order of the bottom and right tool bars needs to reversed
849
for (int line = 0; line < tb_layout_info.size(); ++line) {
850
const ToolBarLineInfo &lineInfo = tb_layout_info.at(line);
852
for (int i = 0; i < lineInfo.list.size(); ++i) {
853
const ToolBarLayoutInfo &info = lineInfo.list.at(i);
854
if (info.item->isEmpty())
856
QSize sh = info.item->sizeHint();
857
if (tb_sz.width() < sh.width())
858
tb_sz.setWidth(sh.width());
859
if (tb_sz.height() < sh.height())
860
tb_sz.setHeight(sh.height());
862
switch(lineInfo.pos) {
865
rest_sz[line] = tb_sz;
868
bottom_sz.push(tb_sz);
871
right_sz.push(tb_sz);
874
Q_ASSERT_X(false, "QMainWindowLayout", "internal error");
878
// calculate the rect for each tool bar line
879
for (int line = 0; line < tb_layout_info.size(); ++line) {
880
const ToolBarLineInfo &lineInfo = tb_layout_info.at(line);
884
switch (lineInfo.pos) {
886
tb_sz = rest_sz[line];
887
tb_rect[line].setBottom(tb_rect[line].top() + tb_sz.height() - 1);
888
r.setTop(tb_rect[line].bottom() + 1);
891
tb_sz = rest_sz[line];
892
tb_rect[line].setRight(tb_rect[line].x() + tb_sz.width() - 1);
893
r.setLeft(tb_rect[line].right() + 1);
896
tb_sz = bottom_sz.pop();
897
tb_rect[line].setTop(tb_rect[line].bottom() - tb_sz.height() + 1);
898
bottom_rect.push(tb_rect[line]);
899
r.setBottom(tb_rect[line].top() - 1);
902
tb_sz = right_sz.pop();
903
tb_rect[line].setLeft(tb_rect[line].right() - tb_sz.width() + 1);
904
right_rect.push(tb_rect[line]);
905
r.setRight(tb_rect[line].left() - 1);
908
Q_ASSERT_X(false, "QMainWindowLayout", "internal error");
912
// put the right and bottom rects back in correct order
913
for (int line = 0; line < tb_layout_info.size(); ++line) {
914
const ToolBarLineInfo &lineInfo = tb_layout_info.at(line);
915
if (lineInfo.pos == BOTTOM)
916
tb_rect[line] = bottom_rect.pop();
917
else if (lineInfo.pos == RIGHT)
918
tb_rect[line] = right_rect.pop();
921
// at this point the space for the tool bars have been shaved off
922
// the main rect, continue laying out each tool bar line
924
if (tb_layout_info.size() != 0) {
925
tb_fill = tb_layout_info.at(0).list.at(0).item->widget()->layout()->margin() * 2
926
+ QApplication::style()->pixelMetric(QStyle::PM_ToolBarHandleExtent)
927
+ QApplication::style()->pixelMetric(QStyle::PM_ToolBarItemSpacing) * 2
928
+ QApplication::style()->pixelMetric(QStyle::PM_ToolBarExtensionExtent);
930
for (int line = 0; line < tb_layout_info.size(); ++line) {
931
ToolBarLineInfo &lineInfo = tb_layout_info[line];
932
int num_tbs = lineInfo.list.size();
933
POSITION where = static_cast<POSITION>(lineInfo.pos);
936
for (int i = 0; i < num_tbs; ++i) {
937
ToolBarLayoutInfo &info = lineInfo.list[i];
938
if (info.item->isEmpty())
941
set(where, info.size, pick(where, tb_rect[line].size()));
944
if (first) { // first tool bar can't have an offset
946
int nextIndex = nextVisible(i, lineInfo);
947
if (nextIndex != -1 && !info.size.isEmpty()
948
&& pick_perp(where, info.offset) > pick_perp(where, info.size)) {
949
// swap if dragging it past the next one
950
ToolBarLayoutInfo &next = lineInfo.list[nextIndex];
951
next.pos = tb_rect[line].topLeft();
952
next.size.setHeight(pick_perp(where, get_item_sh(next.item->widget()->layout())) + tb_fill);
953
next.offset = QPoint();
954
if (where == LEFT || where == RIGHT)
955
info.pos = QPoint(tb_rect[line].left(), next.pos.y() + next.size.height());
957
info.pos = QPoint(next.pos.x() + next.size.width(), tb_rect[line].top());
958
info.offset = QPoint(); // has to be done before swapping
959
lineInfo.list.swap(i, nextIndex);
961
info.pos = tb_rect[line].topLeft();
962
info.offset = QPoint();
965
int prevIndex = prevVisible(i, lineInfo);
966
Q_ASSERT_X(prevIndex != -1, "QMainWindowLayout", "internal error");
968
ToolBarLayoutInfo &prev = lineInfo.list[prevIndex];
969
QSize min_size = get_item_sh(info.item->widget()->layout());
970
set_perp(where, min_size, pick_perp(where, min_size) + tb_fill);
971
const int cur_pt = info.size.isEmpty()
972
? (pick_perp(where, prev.pos) + pick_perp(where, get_real_sh(prev.item->widget()->layout())))
973
: pick_perp(where, prev.pos) + pick_perp(where, prev.size);
974
const int prev_min = pick_perp(where, get_item_sh(prev.item->widget()->layout())) + tb_fill;
975
const int snap_dist = 12;
977
info.pos = tb_rect[line].topLeft();
978
set_perp(where, info.pos, cur_pt + pick_perp(where, info.offset));
980
if (pick_perp(where, info.offset) < 0) { // left/up motion
981
if (pick_perp(where, prev.size) + pick_perp(where, info.offset) >= prev_min) {
982
// shrink the previous one and increase size of current with same
983
QSize real_sh = get_real_sh(prev.item->widget()->layout());
985
set_perp(where, sz, pick_perp(where, info.offset));
986
if ((pick_perp(where, prev.size) + pick_perp(where, sz)
987
< pick_perp(where, real_sh) - snap_dist)
988
|| (pick_perp(where, prev.size) + pick_perp(where, sz)
989
> pick_perp(where, real_sh) + snap_dist))
994
info.pos = tb_rect[line].topLeft();
995
set_perp(where, prev.size, pick_perp(where, real_sh));
996
int pt = pick_perp(where, prev.pos) + pick_perp(where, prev.size);
997
set_perp(where, info.pos, pt);
1000
// can't shrink - push the previous one if possible
1001
bool can_push = false;
1002
for (int l = i-2; l >= 0; --l) {
1003
ToolBarLayoutInfo &t = lineInfo.list[l];
1004
if (pick_perp(where, t.size) + pick_perp(where, info.offset) >
1005
pick_perp(where, get_item_sh(t.item->widget()->layout())) + tb_fill) {
1007
set_perp(where, sz, pick_perp(where, info.offset) + pick_perp(where, prev.size) - prev_min);
1014
set_perp(where, prev.pos, pick_perp(where, prev.pos) + pick_perp(where, info.offset));
1015
set_perp(where, prev.size, prev_min);
1016
set_perp(where, info.pos, pick_perp(where, info.pos) + pick_perp(where, info.offset));
1018
set_perp(where, sz, pick_perp(where, info.offset));
1022
set_perp(where, sz, pick_perp(where, prev.size) - prev_min);
1024
set_perp(where, prev.size, prev_min);
1025
if (pick_perp(where, info.pos) < pick_perp(where, prev.pos))
1026
lineInfo.list.swap(i, i-1);
1028
set_perp(where, info.pos, pick_perp(where, prev.pos) + prev_min);
1032
} else if (pick_perp(where, info.offset) > 0) { // right/down motion
1033
if (pick_perp(where, info.size) - pick_perp(where, info.offset) > pick_perp(where, min_size)) {
1034
QSize real_sh = get_real_sh(prev.item->widget()->layout());
1036
set_perp(where, sz, pick_perp(where, info.offset));
1037
if ((pick_perp(where, prev.size) + pick_perp(where, sz)
1038
> pick_perp(where, real_sh) + snap_dist)
1039
|| (pick_perp(where, prev.size) < pick_perp(where, real_sh) - snap_dist))
1043
info.pos = tb_rect[line].topLeft();
1044
set_perp(where, prev.size, pick_perp(where, real_sh));
1045
int pt = pick_perp(where, prev.pos) + pick_perp(where, prev.size);
1046
set_perp(where, info.pos, pt);
1049
bool can_push = false;
1050
for (int l = i+1; l < num_tbs; ++l) {
1051
ToolBarLayoutInfo &t = lineInfo.list[l];
1052
if (pick_perp(where, t.size) - pick_perp(where, info.offset)
1053
> pick_perp(where, get_item_sh(t.item->widget()->layout())) + tb_fill) {
1055
set_perp(where, pt, pick_perp(where, info.offset));
1057
t.size -= QSize(pt.x(), pt.y());
1063
int can_remove = pick_perp(where, info.size) - pick_perp(where, min_size);
1064
set_perp(where, info.pos, cur_pt + can_remove);
1066
set_perp(where, sz, can_remove);
1069
int nextIndex = nextVisible(i, lineInfo);
1070
if (nextIndex != -1) {
1071
ToolBarLayoutInfo &t = lineInfo.list[nextIndex];
1072
if (pick_perp(where, info.pos) + pick_perp(where, info.offset) > pick_perp(where, t.pos))
1073
lineInfo.list.swap(i, nextIndex);
1079
// Figure out a suitable default pos/size
1080
if (pick_perp(where, info.pos) < pick_perp(where, prev.pos) + prev_min) {
1081
int sz = pick_perp(where, prev.item->widget()->sizeHint());
1082
// use min size hint if size hint is smaller
1085
set_perp(where, info.pos, pick_perp(where, prev.pos) + sz);
1087
info.offset = QPoint();
1092
set_perp(where, info.size, pick_perp(where, tb_rect[line].size()));
1094
int nextIndex = nextVisible(i, lineInfo);
1095
if (nextIndex == -1) {
1096
// do a sanity check on the pos
1097
if (pick_perp(where, info.pos) >= pick_perp(where, tb_rect[line].size())) {
1098
int min = pick_perp(where, get_item_sh(info.item->widget()->layout())) + tb_fill;
1099
set_perp(where, info.pos, pick_perp(where, tb_rect[line].size()) - min);
1101
set_perp(where, info.size, pick_perp(where, tb_rect[line].size()));
1102
if (where == LEFT || where == RIGHT)
1103
info.size.setHeight(tb_rect[line].bottom() - info.pos.y() + 1);
1105
info.size.setWidth(tb_rect[line].right() - info.pos.x() + 1);
1106
if (pick_perp(where, info.size) < 1)
1107
set_perp(where, info.size, pick_perp(where, get_item_sh(info.item->widget()->layout())) + tb_fill);
1112
// assumes that all tbs are positioned at the correct
1113
// pos - fill in the gaps btw them
1114
int prevIndex = prevVisible(i, lineInfo);
1115
if (prevIndex != -1) {
1116
ToolBarLayoutInfo &prev = lineInfo.list[prevIndex];
1117
set_perp(where, prev.size, pick_perp(where, info.pos) - pick_perp(where, prev.pos));
1122
for (int i = 0; i < num_tbs; ++i) {
1123
ToolBarLayoutInfo &info = lineInfo.list[i];
1124
if (info.item->isEmpty()) {
1125
info.size = QSize();
1129
QRect tb(info.pos, info.size);
1130
tb = QStyle::visualRect(QApplication::layoutDirection(), tb_rect[line], tb);
1131
if (!tb.isEmpty() && relayout_type == QInternal::RelayoutNormal)
1132
info.item->setGeometry(tb);
1136
// layout dockwidgets and center widget
1137
const int ext = QApplication::style()->pixelMetric(QStyle::PM_DockWidgetSeparatorExtent);
1139
if (relayout_type == QInternal::RelayoutNormal) {
1140
// hide separators for empty layouts
1141
for (int i = 0; i < 4; ++i) {
1142
if (!layout_info[i].item) continue;
1143
layout_info[i].sep->widget()->setHidden(layout_info[i].item->isEmpty());
1148
QVector<QLayoutStruct> lsH(3);
1149
for (int i = 0; i < 3; ++i)
1152
if (layout_info[LEFT].item)
1153
init_layout_struct(this, lsH[0], LEFT, ext);
1154
if (layout_info[RIGHT].item)
1155
init_layout_struct(this, lsH[2], RIGHT, ext);
1157
lsH[1].empty = false;
1158
lsH[1].minimumSize =
1159
layout_info[CENTER].item ? layout_info[CENTER].item->minimumSize().width() : 0;
1160
lsH[1].maximumSize =
1161
layout_info[CENTER].item ? layout_info[CENTER].item->maximumSize().width() : INT_MAX;
1163
!layout_info[CENTER].size.isEmpty()
1164
? layout_info[CENTER].size.width()
1165
: (layout_info[CENTER].item ? layout_info[CENTER].item->sizeHint().width() : 0);
1166
// fix min/max sizes
1167
fix_minmax(lsH, this, TOP);
1168
fix_minmax(lsH, this, BOTTOM);
1169
// constrain sizeHint
1170
lsH[1].sizeHint = qMin(lsH[1].maximumSize, lsH[1].sizeHint);
1171
lsH[1].sizeHint = qMax(lsH[1].minimumSize, lsH[1].sizeHint);
1172
// the center widget always gets stretch
1173
lsH[1].stretch = lsH[1].sizeHint;
1175
qGeomCalc(lsH, 0, lsH.count(), 0, r.width(), 0);
1178
layout_info[LEFT].size.setWidth(lsH[0].size);
1179
layout_info[CENTER].size.setWidth(lsH[1].size);
1181
layout_info[RIGHT].size.setWidth(lsH[2].size);
1185
QVector<QLayoutStruct> lsV(3);
1186
for (int i = 0; i < 3; ++i)
1189
if (layout_info[TOP].item)
1190
init_layout_struct(this, lsV[0], TOP, ext);
1191
if (layout_info[BOTTOM].item)
1192
init_layout_struct(this, lsV[2], BOTTOM, ext);
1194
lsV[1].empty = false;
1195
lsV[1].minimumSize =
1196
layout_info[CENTER].item ? layout_info[CENTER].item->minimumSize().height() : 0;
1197
lsV[1].maximumSize =
1198
layout_info[CENTER].item ? layout_info[CENTER].item->maximumSize().height() : INT_MAX;
1200
!layout_info[CENTER].size.isEmpty()
1201
? layout_info[CENTER].size.height()
1202
: (layout_info[CENTER].item ? layout_info[CENTER].item->sizeHint().height() : 0);
1203
// fix min/max sizes
1204
fix_minmax(lsV, this, LEFT);
1205
fix_minmax(lsV, this, RIGHT);
1206
// constrain sizeHint
1207
lsV[1].sizeHint = qMin(lsV[1].maximumSize, lsV[1].sizeHint);
1208
lsV[1].sizeHint = qMax(lsV[1].minimumSize, lsV[1].sizeHint);
1209
// the center widget always gets stretch
1210
lsV[1].stretch = lsV[1].sizeHint;
1212
qGeomCalc(lsV, 0, lsV.count(), 0, r.height(), 0);
1215
layout_info[TOP].size.setHeight(lsV[0].size);
1216
layout_info[CENTER].size.setHeight(lsV[1].size);
1218
layout_info[BOTTOM].size.setHeight(lsV[2].size);
1223
&right = rect[RIGHT],
1225
&bottom = rect[BOTTOM];
1227
for (int i = 0; i < 4; ++i) {
1228
if (!layout_info[i].item || layout_info[i].item->isEmpty())
1229
rect[i].setSize(QSize(0, 0));
1231
rect[i].setSize(layout_info[i].size);
1234
left.moveLeft(r.left());
1235
right.moveRight(r.right());
1236
top.moveTop(r.top());
1237
bottom.moveBottom(r.bottom());
1239
switch (corners[Qt::TopLeftCorner]) {
1240
case Qt::TopDockWidgetArea:
1241
top.setLeft(r.left());
1242
left.setTop(top.bottom() + 1);
1244
case Qt::LeftDockWidgetArea:
1245
left.setTop(r.top());
1246
top.setLeft(left.right() + 1);
1252
switch (corners[Qt::BottomLeftCorner]) {
1253
case Qt::BottomDockWidgetArea:
1254
bottom.setLeft(r.left());
1255
left.setBottom(bottom.top() - 1);
1257
case Qt::LeftDockWidgetArea:
1258
left.setBottom(r.bottom());
1259
bottom.setLeft(left.right() + 1);
1265
switch (corners[Qt::TopRightCorner]) {
1266
case Qt::TopDockWidgetArea:
1267
top.setRight(r.right());
1268
right.setTop(top.bottom() + 1);
1270
case Qt::RightDockWidgetArea:
1271
right.setTop(r.top());
1272
top.setRight(right.left() - 1);
1278
switch (corners[Qt::BottomRightCorner]) {
1279
case Qt::BottomDockWidgetArea:
1280
bottom.setRight(r.right());
1281
right.setBottom(bottom.top() - 1);
1283
case Qt::RightDockWidgetArea:
1284
right.setBottom(r.bottom());
1285
bottom.setRight(right.left() - 1);
1291
for (int i = 0; i < 4; ++i) {
1292
if (!layout_info[i].item) continue;
1293
layout_info[i].size = rect[i].size();
1298
x.setCoords(rect[i].left(),
1300
rect[i].right() - ext,
1302
s.setCoords(x.right() + 1,
1308
x.setCoords(rect[i].left() + ext,
1312
s.setCoords(rect[i].left(),
1318
x.setCoords(rect[i].left(),
1321
rect[i].bottom() - ext);
1322
s.setCoords(rect[i].left(),
1328
x.setCoords(rect[i].left(),
1329
rect[i].top() + ext,
1332
s.setCoords(rect[i].left(),
1341
if (relayout_type == QInternal::RelayoutNormal || layout_info[i].is_dummy)
1342
layout_info[i].item->setGeometry(x);
1343
if (relayout_type == QInternal::RelayoutNormal)
1344
layout_info[i].sep->setGeometry(s);
1347
if (layout_info[CENTER].item) {
1349
c.setCoords(left.right() + 1,
1353
layout_info[CENTER].size = c.size();
1354
if (relayout_type == QInternal::RelayoutNormal)
1355
layout_info[CENTER].item->setGeometry(c);
1359
void QMainWindowLayout::addItem(QLayoutItem *)
1360
{ qWarning("QMainWindowLayout: please use the public QMainWindow API instead."); }
1362
QSize QMainWindowLayout::sizeHint() const
1364
if (!szHint.isValid()) {
1365
int left = 0, right = 0, top = 0, bottom = 0;
1368
for (int line = 0; line < tb_layout_info.size(); ++line) {
1369
const ToolBarLineInfo &lineInfo = tb_layout_info.at(line);
1371
// need to get the biggest size hint for all tool bars on each line
1372
for (int i = 0; i < lineInfo.list.size(); ++i) {
1373
const ToolBarLayoutInfo &info = lineInfo.list.at(i);
1374
QSize ms = info.item->sizeHint();
1376
if (((lineInfo.pos == LEFT || lineInfo.pos == RIGHT) && (ms.width() > sz.width()))
1377
|| (ms.height() > sz.height()))
1380
switch (lineInfo.pos) {
1386
right += sz.width();
1394
bottom += sz.height();
1398
Q_ASSERT_X(false, "QMainWindowLayout", "internal error");
1402
const QSize szC = layout_info[CENTER].item
1403
? layout_info[CENTER].item->sizeHint()
1405
szL = layout_info[LEFT].item
1406
? layout_info[LEFT].item->sizeHint()
1408
szT = layout_info[TOP].item
1409
? layout_info[TOP].item->sizeHint()
1411
szR = layout_info[RIGHT].item
1412
? layout_info[RIGHT].item->sizeHint()
1414
szB = layout_info[BOTTOM].item
1415
? layout_info[BOTTOM].item->sizeHint()
1417
int h1, h2, h3, w1, w2, w3;
1419
w1 = (corners[Qt::TopLeftCorner] == Qt::LeftDockWidgetArea ? szL.width() : 0)
1421
+ (corners[Qt::TopRightCorner] == Qt::RightDockWidgetArea ? szR.width() : 0);
1422
w2 = szL.width() + szR.width() + szC.width();
1423
w3 = (corners[Qt::BottomLeftCorner] == Qt::LeftDockWidgetArea ? szL.width() : 0)
1425
+ (corners[Qt::BottomRightCorner] == Qt::RightDockWidgetArea ? szR.width(): 0);
1427
h1 = (corners[Qt::TopLeftCorner] == Qt::TopDockWidgetArea ? szT.height() : 0)
1429
+ (corners[Qt::BottomLeftCorner] == Qt::BottomDockWidgetArea ? szB.height(): 0);
1430
h2 = szT.height() + szB.height() + szC.height();
1431
h3 = (corners[Qt::TopRightCorner] == Qt::TopDockWidgetArea ? szT.height() : 0)
1433
+ (corners[Qt::BottomRightCorner] == Qt::BottomDockWidgetArea ? szB.height() : 0);
1435
const int ext = QApplication::style()->pixelMetric(QStyle::PM_DockWidgetSeparatorExtent);
1436
if (layout_info[LEFT].item && !szL.isEmpty())
1438
if (layout_info[RIGHT].item && !szR.isEmpty())
1440
if (layout_info[TOP].item && !szT.isEmpty())
1442
if (layout_info[BOTTOM].item && !szB.isEmpty())
1445
VDEBUG("QMainWindowLayout::sizeHint:\n"
1446
" %4dx%4d (l %4d r %4d t %4d b %4d w1 %4d w2 %4d w3 %4d, h1 %4d h2 %4d h3 %4d)",
1447
qMax(qMax(w1,w2),w3), qMax(qMax(h1,h2),h3),
1448
left, right, top, bottom, w1, w2, w3, h1, h2, h3);
1450
QSize szSB = statusbar ? statusbar->sizeHint() : QSize(0, 0);
1451
szHint = QSize(qMax(szSB.width(), qMax(qMax(w1,w2),w3) + left + right),
1452
szSB.height() + qMax(qMax(h1,h2),h3) + top + bottom);
1457
QSize QMainWindowLayout::minimumSize() const
1459
if (!minSize.isValid()) {
1460
int left = 0, right = 0, top = 0, bottom = 0;
1463
for (int line = 0; line < tb_layout_info.size(); ++line) {
1464
const ToolBarLineInfo &lineInfo = tb_layout_info.at(line);
1466
// need to get the biggest min size for all tool bars on each line
1467
for (int i = 0; i < lineInfo.list.size(); ++i) {
1468
const ToolBarLayoutInfo &info = lineInfo.list.at(i);
1469
QSize ms = info.item->minimumSize();
1471
if (((lineInfo.pos == LEFT || lineInfo.pos == RIGHT) && (ms.width() > sz.width()))
1472
|| (ms.height() > sz.height()))
1475
switch (lineInfo.pos) {
1481
right += sz.width();
1489
bottom += sz.height();
1493
Q_ASSERT_X(false, "QMainWindowLayout", "internal error");
1497
const QSize szC = layout_info[CENTER].item
1498
? layout_info[CENTER].item->minimumSize()
1500
szL = layout_info[LEFT].item
1501
? layout_info[LEFT].item->minimumSize()
1503
szT = layout_info[TOP].item
1504
? layout_info[TOP].item->minimumSize()
1506
szR = layout_info[RIGHT].item
1507
? layout_info[RIGHT].item->minimumSize()
1509
szB = layout_info[BOTTOM].item
1510
? layout_info[BOTTOM].item->minimumSize()
1512
int h1, h2, h3, w1, w2, w3;
1514
w1 = (corners[Qt::TopLeftCorner] == Qt::LeftDockWidgetArea ? szL.width() : 0)
1516
+ (corners[Qt::TopRightCorner] == Qt::RightDockWidgetArea ? szR.width() : 0);
1517
w2 = szL.width() + szR.width() + szC.width();
1518
w3 = (corners[Qt::BottomLeftCorner] == Qt::LeftDockWidgetArea ? szL.width() : 0)
1520
+ (corners[Qt::BottomRightCorner] == Qt::RightDockWidgetArea ? szR.width() : 0);
1522
h1 = (corners[Qt::TopLeftCorner] == Qt::TopDockWidgetArea ? szT.height() : 0)
1524
+ (corners[Qt::BottomLeftCorner] == Qt::BottomDockWidgetArea ? szB.height() : 0);
1525
h2 = szT.height() + szB.height() + szC.height();
1526
h3 = (corners[Qt::TopRightCorner] == Qt::TopDockWidgetArea ? szT.height() : 0)
1528
+ (corners[Qt::BottomRightCorner] == Qt::BottomDockWidgetArea ? szB.height() : 0);
1530
const int ext = QApplication::style()->pixelMetric(QStyle::PM_DockWidgetSeparatorExtent);
1531
if (layout_info[LEFT].item && !szL.isEmpty())
1533
if (layout_info[RIGHT].item && !szR.isEmpty())
1535
if (layout_info[TOP].item && !szT.isEmpty())
1537
if (layout_info[BOTTOM].item && !szB.isEmpty())
1540
VDEBUG("QMainWindowLayout::minimumSize:\n"
1541
" %4dx%4d (l %4d r %4d t %4d b %4d w1 %4d w2 %4d w3 %4d, h1 %4d h2 %4d h3 %4d)",
1542
qMax(qMax(w1,w2),w3), qMax(qMax(h1,h2),h3),
1543
left, right, top, bottom, w1, w2, w3, h1, h2, h3);
1545
QSize szSB = statusbar ? statusbar->minimumSize() : QSize(0, 0);
1546
minSize = QSize(qMax(szSB.width(), qMax(qMax(w1,w2),w3) + left + right),
1547
szSB.height() + qMax(qMax(h1,h2),h3) + top + bottom);
1552
void QMainWindowLayout::relayout(QInternal::RelayoutType type)
1554
QRect g = geometry();
1556
QInternal::RelayoutType save_type = relayout_type;
1557
relayout_type = type;
1559
relayout_type = save_type;
1565
void QMainWindowLayout::invalidate()
1567
if (relayout_type != QInternal::RelayoutDragging) {
1568
QLayout::invalidate();
1569
minSize = szHint = QSize();
1573
void QMainWindowLayout::saveLayoutInfo()
1575
Q_ASSERT(save_layout_info == 0);
1576
save_layout_info = new QVector<QMainWindowLayoutInfo>(layout_info);
1577
relayout_type = QInternal::RelayoutDragging;
1579
for (int i = 0; i < 4; ++i) {
1580
if (!layout_info[i].item) continue;
1582
QDockWidgetLayout *layout =
1583
qobject_cast<QDockWidgetLayout *>(layout_info[i].item->layout());
1584
Q_ASSERT(layout != 0);
1585
layout->saveLayoutInfo();
1589
void QMainWindowLayout::resetLayoutInfo()
1591
Q_ASSERT(save_layout_info != 0);
1592
layout_info = *save_layout_info;
1594
for (int i = 0; i < 4; ++i) {
1595
if (!layout_info[i].item) continue;
1597
QDockWidgetLayout *layout =
1598
qobject_cast<QDockWidgetLayout *>(layout_info[i].item->layout());
1599
Q_ASSERT(layout != 0);
1600
layout->resetLayoutInfo();
1604
void QMainWindowLayout::discardLayoutInfo()
1606
Q_ASSERT(save_layout_info != 0);
1607
delete save_layout_info;
1608
save_layout_info = 0;
1610
relayout_type = QInternal::RelayoutNormal;
1612
for (int i = 0; i < 4; ++i) {
1613
if (!layout_info[i].item) continue;
1615
QDockWidgetLayout *layout =
1616
qobject_cast<QDockWidgetLayout *>(layout_info[i].item->layout());
1617
Q_ASSERT(layout != 0);
1618
layout->discardLayoutInfo();
1622
void QMainWindowLayout::beginConstrain()
1624
save_tb_layout_info = new QList<ToolBarLineInfo>(tb_layout_info);
1627
void QMainWindowLayout:: endConstrain()
1629
delete save_tb_layout_info;
1630
save_tb_layout_info = 0;
1633
int QMainWindowLayout::constrain(QDockWidgetLayout *dock, int delta)
1635
QVector<QMainWindowLayoutInfo> info = save_layout_info ? *save_layout_info : layout_info;
1637
const POSITION order[] = {
1648
// which dock are we constraining?
1650
if (info[LEFT].item && info[LEFT].item->layout() == dock) {
1652
} else if (info[TOP].item && info[TOP].item->layout() == dock) {
1654
} else if (info[RIGHT].item && info[RIGHT].item->layout() == dock) {
1658
Q_ASSERT(info[BOTTOM].item && info[BOTTOM].item->layout() == dock);
1663
// remove delta from 'dock'
1664
int current = pick(pos, info[pos].size)
1665
+ pick(pos, info[CENTER].size)
1666
+ pick(pos, info[order[pos]].size);
1668
const int _ext = QApplication::style()->pixelMetric(QStyle::PM_DockWidgetSeparatorExtent);
1669
const QSize ext(_ext, _ext);
1670
const QSize dmin = info[pos].item->minimumSize() + ext,
1671
dmax = info[pos].item->maximumSize() + ext;
1672
if (pick(pos, info[pos].size) + delta < pick(pos, dmin))
1673
delta = pick(pos, dmin) - pick(pos, info[pos].size);
1674
if (pick(pos, info[pos].size) + delta > pick(pos, dmax))
1675
delta = pick(pos, dmax) - pick(pos, info[pos].size);
1677
// remove delta from the center widget
1678
int from_center = delta;
1680
const QSize cmin = info[CENTER].item->minimumSize(),
1681
cmax = info[CENTER].item->maximumSize();
1682
if (pick(pos, info[CENTER].size) - from_center < pick(pos, cmin))
1683
from_center = pick(pos, info[CENTER].size) - pick(pos, cmin);
1684
if (pick(pos, info[CENTER].size) - from_center > pick(pos, cmax))
1685
from_center = pick(pos, cmax) - pick(pos, info[CENTER].size);
1686
set(pos, info[CENTER].size, pick(pos, info[CENTER].size) - from_center);
1689
// remove remaining delta from the other dock (i.e. the one opposite us)
1691
if (info[order[pos]].item) {
1692
from_other = delta - from_center;
1694
const QSize omin = info[order[pos]].item->minimumSize() + ext,
1695
omax = info[order[pos]].item->maximumSize() + ext;
1696
if (pick(pos, info[order[pos]].size) - from_other < pick(pos, omin))
1697
from_other = pick(pos, info[order[pos]].size) - pick(pos, omin);
1698
if (pick(pos, info[order[pos]].size) - from_other > pick(pos, omax))
1699
from_other = pick(pos, omax) - pick(pos, info[order[pos]].size);
1700
set(pos, info[order[pos]].size, pick(pos, info[order[pos]].size) - from_other);
1704
// the real delta is how much we stole from the center and right widgets
1705
delta = from_center + from_other;
1706
set(pos, info[pos].size, pick(pos, info[pos].size) + delta);
1708
int new_current = (pick(pos, info[pos].size)
1709
+ pick(pos, info[CENTER].size)
1710
+ pick(pos, info[order[pos]].size));
1712
Q_UNUSED(new_current);
1713
Q_ASSERT(current == new_current);
1715
delta = info[pos].size == layout_info[pos].size ? 0 : 1;
1723
Qt::DockWidgetAreas areasForMousePosition(const QRect &r, const QPoint &p, bool floatable = false)
1725
const int dl = qAbs(r.left() - p.x()),
1726
dr = qAbs(r.right() - p.x()),
1727
dt = qAbs(r.top() - p.y()),
1728
db = qAbs(r.bottom() - p.y()),
1729
delta = qMin(dl, qMin(dr, qMin(dt, db))),
1731
dx = qAbs(r.center().x() - p.x()),
1732
dy = qAbs(r.center().y() - p.y());
1734
Qt::DockWidgetAreas areas = 0;
1735
if (delta < threshold) {
1736
VDEBUG() << " below threshold";
1737
if (delta == dl || delta == dr) {
1739
areas = Qt::LeftDockWidgetArea;
1741
areas = Qt::RightDockWidgetArea;
1744
areas |= Qt::TopDockWidgetArea;
1745
else if (db < threshold)
1746
areas |= Qt::BottomDockWidgetArea;
1747
} else if (delta == dt || delta == db) {
1749
areas = Qt::TopDockWidgetArea;
1751
areas = Qt::BottomDockWidgetArea;
1754
areas |= Qt::LeftDockWidgetArea;
1755
else if (dr < threshold)
1756
areas |= Qt::RightDockWidgetArea;
1758
} else if (!floatable) {
1759
VDEBUG() << " not floatable";
1761
? ((p.x() < r.center().x())
1762
? Qt::LeftDockWidgetArea
1763
: Qt::RightDockWidgetArea)
1764
: ((p.y() < r.center().y())
1765
? Qt::TopDockWidgetArea
1766
: Qt::BottomDockWidgetArea));
1768
VDEBUG() << " floatable";
1774
Qt::DockWidgetArea QMainWindowLayout::locateDockWidget(QDockWidget *dockwidget,
1775
const QPoint &mouse) const
1777
VDEBUG() << " locate: mouse" << mouse;
1779
const QPoint p = parentWidget()->mapFromGlobal(mouse);
1782
if there is a window dock layout under the mouse, forward the
1785
for (int i = 0; i < 4; ++i) {
1786
if (!layout_info[i].item)
1788
const Qt::DockWidgetArea area = static_cast<Qt::DockWidgetArea>(areaForPosition(i));
1789
if (!dockwidget->isAreaAllowed(area))
1791
if (layout_info[i].item->isEmpty() ||
1792
(!layout_info[i].item->geometry().contains(p)
1793
&& !layout_info[i].sep->geometry().contains(p)))
1795
VDEBUG() << " result: mouse over item" << i;
1799
Qt::DockWidgetAreas areas =
1800
areasForMousePosition(layout_info[4].item->geometry(), p,
1801
(dockwidget->features() & QDockWidget::DockWidgetFloatable));
1802
Qt::DockWidgetArea area;
1804
if (areas == (Qt::LeftDockWidgetArea | Qt::TopDockWidgetArea))
1805
area = corners[Qt::TopLeftCorner];
1806
else if (areas == (Qt::LeftDockWidgetArea | Qt::BottomDockWidgetArea))
1807
area = corners[Qt::BottomLeftCorner];
1808
else if (areas == (Qt::RightDockWidgetArea | Qt::TopDockWidgetArea))
1809
area = corners[Qt::TopRightCorner];
1810
else if (areas == (Qt::RightDockWidgetArea | Qt::BottomDockWidgetArea))
1811
area = corners[Qt::BottomRightCorner];
1813
area = (Qt::DockWidgetArea)(uint)areas;
1815
VDEBUG() << " result:" << area;
1819
QRect QMainWindowLayout::placeDockWidget(QDockWidget *dockwidget,
1821
const QPoint &mouse)
1823
DEBUG("QMainWindowLayout::placeDockWidget");
1825
Qt::DockWidgetArea area = locateDockWidget(dockwidget, mouse);
1828
if (!area || !dockwidget->isAreaAllowed(area)) {
1829
DEBUG() << "END of QMainWindowLayout::placeDockWidget (failed to place)";
1833
// if there is a window dock layout already here, forward the place
1834
const int pos = positionForArea(area);
1835
if (layout_info[pos].item && !layout_info[pos].item->isEmpty()) {
1836
DEBUG(" forwarding...");
1837
QDockWidgetLayout *l = qobject_cast<QDockWidgetLayout *>(layout_info[pos].item->layout());
1839
target = l->place(dockwidget, r, mouse);
1840
DEBUG("END of QMainWindowLayout::placeDockWidget (forwarded)");
1844
// remove dockwidget from current position in the layout
1845
removeRecursive(dockwidget);
1847
// see if the tool window will fix in the main window
1848
const QSize cur = parentWidget()->size();
1850
QMainWindowLayoutItem layoutitem(dockwidget, r);
1851
layout_info[pos].item = &layoutitem;
1852
layout_info[pos].size = r.size();
1853
DEBUG() << " pos" << pos << " size" << layout_info[pos].size;
1854
layout_info[pos].is_dummy = true;
1856
relayout(QInternal::RelayoutDragging);
1858
const QSize new_min = minimumSize();
1859
const bool forbid = cur.width() < new_min.width() || cur.height() < new_min.height();
1862
DEBUG() << " placed at " << layoutitem.geometry();
1863
target = layoutitem.geometry();
1864
target.moveTopLeft(parentWidget()->mapToGlobal(target.topLeft()));
1866
DEBUG() << " forbidden, minimum size" << new_min << " larger than current size" << cur;
1869
DEBUG() << "END of QMainWindowLayout::placeDockWidget, target" << target;
1874
void QMainWindowLayout::dropDockWidget(QDockWidget *dockwidget,
1876
const QPoint &mouse)
1878
DEBUG("QMainWindowLayout::dropDockWidget");
1880
Qt::DockWidgetArea area = locateDockWidget(dockwidget, mouse);
1882
if (!area || !dockwidget->isAreaAllowed(area)) {
1883
DEBUG() << "END of QMainWindowLayout::dropDockWidget (failed to place)";
1887
// if there is a window dock layout already here, forward the drop
1888
const int pos = positionForArea(area);
1889
if (layout_info[pos].item) {
1890
DEBUG() << " forwarding...";
1891
QDockWidgetLayout *l = qobject_cast<QDockWidgetLayout *>(layout_info[pos].item->layout());
1893
l->drop(dockwidget, r, mouse);
1895
DEBUG() << "END of QMainWindowLayout::dropDockWidget (forwarded)";
1899
// remove dockwidget from current position in the layout
1900
removeRecursive(dockwidget);
1902
QWidget *parent = qobject_cast<QMainWindow *>(parentWidget());
1903
dockwidget->setParent(parent);
1904
QDockWidgetLayout *dwl = layoutForArea(static_cast<Qt::DockWidgetArea>(areaForPosition(pos)));
1905
dwl->addWidget(dockwidget);
1907
layout_info[pos].size = r.size();
1912
layout_info[pos].sep->widget()->show();
1914
DEBUG() << "END of QMainWindowLayout::dropDockWidget";
1917
static bool removeWidgetRecursively(QLayoutItem *li, QWidget *w, bool dummy)
1919
QLayout *lay = li->layout();
1924
while ((child = lay->itemAt(i))) {
1925
if (child->widget() == w) {
1926
QLayoutItem *item = lay->takeAt(i);
1930
} else if (removeWidgetRecursively(child, w, dummy)) {
1939
void QMainWindowLayout::removeRecursive(QDockWidget *dockwidget)
1941
removeWidgetRecursively(this, dockwidget, save_layout_info != 0);
1944
int QMainWindowLayout::locateToolBar(QToolBar *toolbar, const QPoint &mouse) const
1946
const int width = parentWidget()->width(),
1947
height = parentWidget()->height();
1948
const QPoint p = parentWidget()->mapFromGlobal(mouse),
1949
p2 = QPoint(width / 2, height / 2);
1950
const int dx = qAbs(p.x() - p2.x()),
1951
dy = qAbs(p.y() - p2.y());
1953
POSITION pos = CENTER;
1955
if (p.x() < p2.x() && toolbar->isAreaAllowed(Qt::LeftToolBarArea)) {
1957
} else if (p.x() >= p2.x() && toolbar->isAreaAllowed(Qt::RightToolBarArea)) {
1960
if (p.y() < p2.y() && toolbar->isAreaAllowed(Qt::TopToolBarArea))
1962
else if (p.y() >= p2.y() && toolbar->isAreaAllowed(Qt::BottomToolBarArea))
1966
if (p.y() < p2.y() && toolbar->isAreaAllowed(Qt::TopToolBarArea)) {
1968
} else if (p.y() >= p2.y() && toolbar->isAreaAllowed(Qt::BottomToolBarArea)) {
1971
if (p.x() < p2.x() && toolbar->isAreaAllowed(Qt::LeftToolBarArea))
1973
else if (p.x() >= p2.x() && toolbar->isAreaAllowed(Qt::RightToolBarArea))
1977
Q_ASSERT(pos != CENTER);
1979
for (int line = 0; line < tb_layout_info.size(); ++line) {
1980
const ToolBarLineInfo &lineInfo = tb_layout_info.at(line);
1981
bool break_it = false;
1982
for (int i = 0; i < lineInfo.list.size(); ++i) {
1983
const ToolBarLayoutInfo &info = lineInfo.list.at(i);
1986
if (info.item->isEmpty())
1988
if (!info.item->geometry().contains(p))
1990
pos = static_cast<POSITION>(lineInfo.pos);
2000
void QMainWindowLayout::dropToolBar(QToolBar *toolbar, const QPoint &mouse, const QPoint &offset)
2002
POSITION where = static_cast<POSITION>(locateToolBar(toolbar, mouse));
2004
if (positionForArea(toolBarArea(toolbar)) == where) {
2005
#ifdef TOOLBAR_DEBUG
2007
for (int l = 0; l < tb_layout_info.size(); ++l) {
2008
const ToolBarLineInfo &lineInfo = tb_layout_info.at(l);
2009
for (int i = 0; i < lineInfo.list.size(); ++i) {
2010
const ToolBarLayoutInfo &tmp = lineInfo.list.at(i);
2011
qDebug() << "bar: " << lineInfo.pos << l << i << tmp.item->widget() << tmp.item->widget()->geometry();
2015
// move the tool bars more than magic_offset pixels past a boundary
2016
// in either dir in order to move it to a different tb line
2017
const int magic_offset = 5;
2019
ToolBarLayoutInfo info;
2021
for (l = 0; l < tb_layout_info.size(); ++l) {
2022
ToolBarLineInfo &lineInfo = tb_layout_info[l];
2023
bool break_it = false;
2024
for (i = 0; i < lineInfo.list.size(); ++i) {
2025
ToolBarLayoutInfo &tmp = lineInfo.list[i];
2026
if (tmp.item->widget() == toolbar) {
2028
tmp.offset += offset;
2037
if (pick(where, offset) < -magic_offset) { // move left/up
2038
TBDEBUG() << "left/up" << offset << "line: " << l << where;
2039
if (l > 0 && tb_layout_info.at(l-1).pos == where) { // is this the first line in this tb area?
2040
tb_layout_info[l].list.removeAt(i);
2041
if (tb_layout_info[l].list.size() == 0)
2042
tb_layout_info.removeAt(l);
2043
if (tb_layout_info.at(l-1).pos == where) {
2044
TBDEBUG() << "1. appending to existing" << info.item->widget() << info.item->widget()->geometry();
2045
if (tb_layout_info[l-1].list.size() > 0) {
2046
const ToolBarLayoutInfo &tmp = tb_layout_info.at(l-1).list.last();
2047
if (pick_perp(where, tmp.pos) == pick_perp(where, info.pos))
2048
info.offset = info.pos - (tmp.pos + QPoint(tmp.size.width(), tmp.size.height()) - offset);
2049
else if (pick_perp(where, tmp.pos) < pick_perp(where, info.pos))
2050
info.offset = -(tmp.pos + QPoint(tmp.size.width(), tmp.size.height()) - info.pos + offset);
2052
tb_layout_info[l-1].list.append(info);
2055
ToolBarLineInfo line;
2057
line.list.append(info);
2058
tb_layout_info.insert(l, line);
2059
TBDEBUG() << "2. inserting new";
2061
} else if ((tb_layout_info.at(l).list.size() > 1)
2062
&& ((l > 0 && tb_layout_info.at(l-1).pos == where)
2063
|| where == BOTTOM || where == RIGHT))
2065
tb_layout_info[l].list.removeAt(i);
2066
ToolBarLineInfo line;
2068
line.list.append(info);
2069
tb_layout_info.insert(l, line);
2070
TBDEBUG() << "3. inserting new" << l << toolbar;
2072
} else if (pick(where, offset) > pick(where, info.size) + magic_offset) { // move right/down
2073
TBDEBUG() << "right/down" << offset << "line: " << l;
2074
if (l < tb_layout_info.size()-1 && tb_layout_info.at(l+1).pos == where) {
2075
tb_layout_info[l].list.removeAt(i);
2076
if (tb_layout_info.at(l).list.size() == 0)
2077
tb_layout_info.removeAt(l--);
2078
if (tb_layout_info.at(l+1).pos == where) {
2079
if (tb_layout_info[l+1].list.size() > 0) {
2080
const ToolBarLayoutInfo &tmp = tb_layout_info.at(l+1).list.last();
2081
if (pick_perp(where, tmp.pos) == pick_perp(where, info.pos))
2082
info.offset = info.pos -(tmp.pos + QPoint(tmp.size.width(), tmp.size.height()) - offset);
2083
else if (pick_perp(where, tmp.pos) < pick_perp(where, info.pos))
2084
info.offset = -(tmp.pos + QPoint(tmp.size.width(), tmp.size.height()) - info.pos + offset);
2086
tb_layout_info[l+1].list.append(info);
2087
TBDEBUG() << "1. appending to exisitng";
2089
ToolBarLineInfo line;
2091
line.list.append(info);
2092
tb_layout_info.insert(l, line);
2093
TBDEBUG() << "2. inserting new line";
2095
} else if ((tb_layout_info.at(l).list.size() > 1)
2096
&& ((l < tb_layout_info.size()-1 && tb_layout_info.at(l+1).pos == where)
2097
|| where == TOP || where == LEFT))
2099
tb_layout_info[l].list.removeAt(i);
2100
ToolBarLineInfo line;
2102
line.list.append(info);
2103
tb_layout_info.insert(l+1, line);
2104
TBDEBUG() << "3. inserting new line";
2108
TBDEBUG() << "changed area";
2109
addToolBar(static_cast<Qt::ToolBarArea>(areaForPosition(where)), toolbar, false);
2110
dropToolBar(toolbar, mouse, offset);
2116
void QMainWindowLayout::removeToolBarInfo(QToolBar *toolbar)
2118
for (int line = 0; line < tb_layout_info.size(); ++line) {
2119
ToolBarLineInfo &lineInfo = tb_layout_info[line];
2120
for (int i = 0; i < lineInfo.list.size(); ++i) {
2121
const ToolBarLayoutInfo &info = lineInfo.list.at(i);
2122
if (info.item->widget() == toolbar) {
2124
lineInfo.list.removeAt(i);
2125
if (lineInfo.list.size() == 0)
2126
tb_layout_info.removeAt(line);
2133
int QMainWindowLayout::nextVisible(int index, const ToolBarLineInfo &lineInfo)
2135
for (++index; index < lineInfo.list.size(); ++index) {
2136
if (!lineInfo.list.at(index).item->isEmpty())
2139
return (index >= 0 && index < lineInfo.list.size()) ? index : -1;
2142
int QMainWindowLayout::prevVisible(int index, const ToolBarLineInfo &lineInfo)
2144
for (--index; index >= 0; --index) {
2145
if (!lineInfo.list.at(index).item->isEmpty())
2148
return (index >= 0 && index < lineInfo.list.size()) ? index : -1;