Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
#include "docklayout.h"
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
#include <assert.h></assert.h>
Toshihiro Shimizu 890ddd
#include <math.h></math.h>
Toshihiro Shimizu 890ddd
#include <algorithm></algorithm>
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
#include <qtextstream></qtextstream>
Toshihiro Shimizu 890ddd
#include <qapplication></qapplication>
Toshihiro Shimizu 890ddd
#include <qdesktopwidget></qdesktopwidget>
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//========================================================
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//TO DO:
Toshihiro Shimizu 890ddd
//  * Usa la macro QWIDGETSIZE_MAX per max grandezza settabile per una widget
Toshihiro Shimizu 890ddd
//      => Dopodiche', basterebbe troncare tutte le somme che eccedono quel valore... Comunque...
Toshihiro Shimizu 890ddd
//  * Il ricalcolo delle extremal sizes e' inutile nei resize events... Cerca di tagliare cose di questo tipo - ottimizza!
Toshihiro Shimizu 890ddd
//      => Pero' e' sensato in generale che redistribute possa ricalcolarle - forse si potrebbe fare una redistribute
Toshihiro Shimizu 890ddd
//         con un bool di ingresso. Se l'operazione contenitrice non puo' cambiare le extremal sizes, allora metti false..
Toshihiro Shimizu 890ddd
//  * Implementa gli stretch factors
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//  * Nascondere le finestre dockate...? Molto rognoso...
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//  * Una dock widget potrebbe non avere i soli stati docked e floating... Che succede se e' una subwindow
Toshihiro Shimizu 890ddd
//    non dockata in un dockLayout??
Toshihiro Shimizu 890ddd
//  * Spezzare tdockwindows.h in tmainwindow.h e tdockwidget.h, come in Qt?
Toshihiro Shimizu 890ddd
//  * Muovere o fare operazioni su una dockWidget allo stato attuale non e' sicuro se quella non e' assegnata ad
Toshihiro Shimizu 890ddd
//    un DockLayout!! Comunque, si puo' assumere che il parente di una DockWidget non sia nemmeno una QWidget
Toshihiro Shimizu 890ddd
//    che implementa un DockLayout. Questa cosa puo' venire meno in un'implementazione specifica come TDockWidget?
Toshihiro Shimizu 890ddd
//      Esempio: vedi calculateDockPlaceholders ad un drag, viene lanciato comunque...
Toshihiro Shimizu 890ddd
//  * Ha senso mettere DockLayout e DockWidget nella DVAPI? Forse se definissi delle inline opportune in TDockWidget...
Toshihiro Shimizu 890ddd
//  * Quanto contenuto in DockSeparator::mousePress e mouseMove dovrebbe essere reso pubblico. Anche la geometria
Toshihiro Shimizu 890ddd
//    delle regioni potrebbe essere editabile dall'utente... ma prima si dovrebbero fare gli stretch factors!!
Toshihiro Shimizu 890ddd
//      > Ossia: se si vuole esplicitamente settare la geometria di una regione, si potrebbe fare che quella
Toshihiro Shimizu 890ddd
//        si prende stretch factor infinito (o quasi), e gli altri 1...
Toshihiro Shimizu 890ddd
//  * Dovrebbe esistere un modo per specificare la posizione dei separatori da codice?
Toshihiro Shimizu 890ddd
//    Rognoso. Comunque, ora basta specificare la geometria delle widget prima del dock;
Toshihiro Shimizu 890ddd
//    la redistribute cerca di adattarsi.
Toshihiro Shimizu 890ddd
//  * Capita spesso di considerare l'ipotetica nuova radice della struttura. Perche' non metterla direttamente??
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//  X Non e' possibile coprire tutte le possibilita' di docking con il sistema attuale, anche se e' comunque piu'
Toshihiro Shimizu 890ddd
//    esteso di quello di Qt.
Toshihiro Shimizu 890ddd
//      Esempio:           |
Toshihiro Shimizu 890ddd
//                    -----|
Toshihiro Shimizu 890ddd
//                      |  |        => !!
Toshihiro Shimizu 890ddd
//                      |-----
Toshihiro Shimizu 890ddd
//                      |
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//========================================================
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//------------------------
Toshihiro Shimizu 890ddd
//    Geometry inlines
Toshihiro Shimizu 890ddd
//------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//QRectF::toRect seems to work in the commented way inside the following function.
Toshihiro Shimizu 890ddd
//Of course that way the rect borders are *not* approximated to the nearest integer
Toshihiro Shimizu 890ddd
//coordinates:
Toshihiro Shimizu 890ddd
//  e.g.:   topLeft= (1/3, 1/3); width= 4/3, height= 4/3 => left= top= right= bottom= 0.
Toshihiro Shimizu 890ddd
inline QRect toRect(const QRectF &rect)
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	//return QRect(qRound(rect.left()), qRound(rect.top()), qRound(rect.width()), qRound(rect.height()));
Toshihiro Shimizu 890ddd
	return QRect(rect.topLeft().toPoint(), rect.bottomRight().toPoint() -= QPoint(1, 1));
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//========================================================
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------
Toshihiro Shimizu 890ddd
//    Dock Layout
Toshihiro Shimizu 890ddd
//-----------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
DockLayout::DockLayout()
Toshihiro Shimizu 890ddd
	: m_maximizedDock(0), m_decoAllocator(new DockDecoAllocator())
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
DockLayout::~DockLayout()
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	//Deleting Regions (separators are Widgets with parent, so they are recursively deleted)
Toshihiro Shimizu 890ddd
	unsigned int i;
Toshihiro Shimizu 890ddd
	for (i = 0; i < m_regions.size(); ++i)
Toshihiro Shimizu 890ddd
		delete m_regions[i];
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	//Deleting dockWidgets
Toshihiro Shimizu 890ddd
	for (i = 0; i < m_items.size(); ++i) {
Toshihiro Shimizu 890ddd
		//delete m_items[i]->widget();
Toshihiro Shimizu 890ddd
		delete m_items[i];
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	//Delete deco allocator
Toshihiro Shimizu 890ddd
	delete m_decoAllocator;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
inline int DockLayout::count() const
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	return m_items.size();
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
inline void DockLayout::addItem(QLayoutItem *item)
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	DockWidget *addedItem = dynamic_cast<dockwidget *="">(item->widget());</dockwidget>
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	//Ensure that added item is effectively a DockWidget type;
Toshihiro Shimizu 890ddd
	assert(addedItem);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	//Check if item is already under layout's control. If so, quit.
Toshihiro Shimizu 890ddd
	if (find(addedItem))
Toshihiro Shimizu 890ddd
		return;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	//Force reparentation. This is required in order to ensure that all items possess
Toshihiro Shimizu 890ddd
	//the same geometry() reference. Also store parentLayout for convenience.
Toshihiro Shimizu 890ddd
	addedItem->m_parentLayout = this;
Toshihiro Shimizu 890ddd
	addedItem->setParent(parentWidget());
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	//Remember that reparenting a widget produces a window flags reset if the new
Toshihiro Shimizu 890ddd
	//parent is not the current one (see Qt's manual). So, first reassign standard
Toshihiro Shimizu 890ddd
	//floating flags, then call for custom appearance (which may eventually reassign the flags).
Toshihiro Shimizu 890ddd
	addedItem->setWindowFlags(Qt::Tool | Qt::FramelessWindowHint);
Toshihiro Shimizu 890ddd
	addedItem->setFloatingAppearance();
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	m_items.push_back(item);
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
inline QLayoutItem *DockLayout::takeAt(int idx)
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	if (idx < 0 || idx >= (int)m_items.size())
Toshihiro Shimizu 890ddd
		return 0;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	QLayoutItem *item = m_items[idx];
Toshihiro Shimizu 890ddd
	DockWidget *dw = static_cast<dockwidget *="">(item->widget());</dockwidget>
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	//If docked, undock item
Toshihiro Shimizu 890ddd
	if (!dw->isFloating())
Toshihiro Shimizu 890ddd
		undockItem(dw);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	//Reset item's parentLayout
Toshihiro Shimizu 890ddd
	dw->m_parentLayout = 0;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	m_items.erase(m_items.begin() + idx);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	return item;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
inline QLayoutItem *DockLayout::itemAt(int idx) const
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	if (idx >= (int)m_items.size())
Toshihiro Shimizu 890ddd
		return 0;
Toshihiro Shimizu 890ddd
	return m_items[idx];
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
QWidget *DockLayout::widgetAt(int idx) const
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	return itemAt(idx)->widget();
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
inline QSize DockLayout::minimumSize() const
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	if (!m_regions.empty()) {
Toshihiro Shimizu 890ddd
		Region *r = m_regions.front();
Toshihiro Shimizu 890ddd
		r->calculateExtremalSizes();
Toshihiro Shimizu 890ddd
		return QSize(r->m_minimumSize[0], r->m_minimumSize[1]);
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	return QSize(0, 0);
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
inline QSize DockLayout::maximumSize() const
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	if (!m_regions.empty()) {
Toshihiro Shimizu 890ddd
		Region *r = m_regions.front();
Toshihiro Shimizu 890ddd
		r->calculateExtremalSizes();
Toshihiro Shimizu 890ddd
		return QSize(r->m_maximumSize[0], r->m_maximumSize[1]);
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	return QSize(QWIDGETSIZE_MAX, QWIDGETSIZE_MAX);
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
inline QSize DockLayout::sizeHint() const
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	QSize s(0, 0);
Toshihiro Shimizu 890ddd
	int n = m_items.size();
Toshihiro Shimizu 890ddd
	if (n > 0)
Toshihiro Shimizu 890ddd
		s = QSize(100, 70); //start with a nice default size
Toshihiro Shimizu 890ddd
	int i = 0;
Toshihiro Shimizu 890ddd
	while (i < n) {
Toshihiro Shimizu 890ddd
		QLayoutItem *o = m_items[i];
Toshihiro Shimizu 890ddd
		s = s.expandedTo(o->sizeHint());
Toshihiro Shimizu 890ddd
		++i;
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
	return s + n * QSize(spacing(), spacing());
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	//return QSize(0,0);
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//----------------------
Toshihiro Shimizu 890ddd
//    Custom methods
Toshihiro Shimizu 890ddd
//----------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
QWidget *DockLayout::containerOf(QPoint point) const
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	//Search among regions, from leaf regions to root.
Toshihiro Shimizu 890ddd
	int i;
Toshihiro Shimizu 890ddd
	unsigned int j;
Toshihiro Shimizu 890ddd
	for (i = m_regions.size() - 1; i >= 0; --i) {
Toshihiro Shimizu 890ddd
		Region *currRegion = m_regions[i];
Toshihiro Shimizu 890ddd
		DockWidget *item = currRegion->getItem();
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		//First check if item contains it
Toshihiro Shimizu 890ddd
		if (item && item->geometry().contains(point))
Toshihiro Shimizu 890ddd
			return currRegion->getItem();
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		//Then, search among separators
Toshihiro Shimizu 890ddd
		for (j = 0; j < currRegion->separators().size(); ++j)
Toshihiro Shimizu 890ddd
			if (currRegion->separator(j)->geometry().contains(point))
Toshihiro Shimizu 890ddd
				return currRegion->separator(j);
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	return 0;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
inline void DockLayout::setMaximized(DockWidget *item, bool state)
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	if (item && state != item->m_maximized) {
Toshihiro Shimizu 890ddd
		if (state) {
Toshihiro Shimizu 890ddd
			//Maximize
Toshihiro Shimizu 890ddd
			if (m_maximizedDock) {
Toshihiro Shimizu 890ddd
				//If maximized already exists, normalize it
Toshihiro Shimizu 890ddd
				Region *r = find(m_maximizedDock);
Toshihiro Shimizu 890ddd
				m_maximizedDock->setGeometry(toRect(r->getGeometry()));
Toshihiro Shimizu 890ddd
				m_maximizedDock->m_maximized = false;
Toshihiro Shimizu 890ddd
			}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
			//Now, attempt requested item maximization
Toshihiro Shimizu 890ddd
			QSize minimumSize = item->minimumSize();
Toshihiro Shimizu 890ddd
			QSize maximumSize = item->maximumSize();
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
			if (contentsRect().width() > minimumSize.width() && contentsRect().height() > minimumSize.height() &&
Toshihiro Shimizu 890ddd
				contentsRect().width() < maximumSize.width() && contentsRect().height() < maximumSize.height()) {
Toshihiro Shimizu 890ddd
				//Maximization succeeds
Toshihiro Shimizu 890ddd
				item->setGeometry(contentsRect());
Toshihiro Shimizu 890ddd
				item->raise();
Toshihiro Shimizu 890ddd
				item->m_maximized = true;
Toshihiro Shimizu 890ddd
				m_maximizedDock = item;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
				//Hide all the other docked widgets (no need to update them. Moreover, doing so
Toshihiro Shimizu 890ddd
				//could eventually result in painting over the newly maximized widget)
Toshihiro Shimizu 890ddd
				DockWidget *currWidget;
Toshihiro Shimizu 890ddd
				for (int i = 0; i < count(); ++i) {
Toshihiro Shimizu 890ddd
					currWidget = (DockWidget *)itemAt(i)->widget();
Toshihiro Shimizu 890ddd
					if (currWidget != item && !currWidget->isFloating())
Toshihiro Shimizu 890ddd
						currWidget->hide();
Toshihiro Shimizu 890ddd
				}
Toshihiro Shimizu 890ddd
			}
Toshihiro Shimizu 890ddd
		} else {
Toshihiro Shimizu 890ddd
			//Normalize
Toshihiro Shimizu 890ddd
			Region *r = find(m_maximizedDock);
Toshihiro Shimizu 890ddd
			if (r)
Toshihiro Shimizu 890ddd
				m_maximizedDock->setGeometry(toRect(r->getGeometry()));
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
			m_maximizedDock->m_maximized = false;
Toshihiro Shimizu 890ddd
			m_maximizedDock = 0;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
			//Show all other docked widgets
Toshihiro Shimizu 890ddd
			DockWidget *currWidget;
Toshihiro Shimizu 890ddd
			for (int i = 0; i < count(); ++i) {
Toshihiro Shimizu 890ddd
				currWidget = (DockWidget *)itemAt(i)->widget();
Toshihiro Shimizu 890ddd
				if (currWidget != item && !currWidget->isFloating())
Toshihiro Shimizu 890ddd
					currWidget->show();
Toshihiro Shimizu 890ddd
			}
Toshihiro Shimizu 890ddd
		}
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//======================================================================
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//======================================
Toshihiro Shimizu 890ddd
//      Layout Geometry Handler
Toshihiro Shimizu 890ddd
//======================================
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//!NOTE: This method is currently unused by DockLayout implementation...
Toshihiro Shimizu 890ddd
void DockLayout::setGeometry(const QRect &rect)
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	//Just pass the info to the widget (it's somehow necessary...)
Toshihiro Shimizu 890ddd
	QLayout::setGeometry(rect);
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//--------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//!Defines cursors for separators of the layout: if it is not possible to
Toshihiro Shimizu 890ddd
//!move a separator, its cursor must be an arrow.
Toshihiro Shimizu 890ddd
inline void DockLayout::updateSeparatorCursors()
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	Region *r, *child;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	unsigned int i, j;
Toshihiro Shimizu 890ddd
	int k, jInt;
Toshihiro Shimizu 890ddd
	for (i = 0; i < m_regions.size(); ++i) {
Toshihiro Shimizu 890ddd
		r = m_regions[i];
Toshihiro Shimizu 890ddd
		bool orientation = r->getOrientation();
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		//If region geometry is minimal or maximal, its separators are blocked
Toshihiro Shimizu 890ddd
		//NOTE: If this update follows only from a dock/undock, this should be disabled 'til 'Otherwise'
Toshihiro Shimizu 890ddd
		QSize size = toRect(r->getGeometry()).size();
Toshihiro Shimizu 890ddd
		bool isExtremeSize = (orientation == Region::horizontal) ? size.width() == r->getMinimumSize(Region::horizontal) || size.width() == r->getMaximumSize(Region::horizontal) : size.height() == r->getMinimumSize(Region::vertical) || size.height() == r->getMaximumSize(Region::vertical);
Toshihiro Shimizu 890ddd
		if (isExtremeSize) {
Toshihiro Shimizu 890ddd
			for (j = 0; j < r->separators().size(); ++j)
Toshihiro Shimizu 890ddd
				r->separator(j)->setCursor(Qt::ArrowCursor);
Toshihiro Shimizu 890ddd
			continue;
Toshihiro Shimizu 890ddd
		}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		//Otherwise...
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		//Arrowize all separators as long as the preceding region has equal
Toshihiro Shimizu 890ddd
		//maximum and minimum sizes
Toshihiro Shimizu 890ddd
		for (j = 0; j < r->getChildList().size(); ++j) {
Toshihiro Shimizu 890ddd
			child = r->childRegion(j);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
			if (child->getMaximumSize(orientation) == child->getMinimumSize(orientation))
Toshihiro Shimizu 890ddd
				r->separator(j)->setCursor(Qt::ArrowCursor);
Toshihiro Shimizu 890ddd
			else
Toshihiro Shimizu 890ddd
				break;
Toshihiro Shimizu 890ddd
		}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		jInt = j;
Toshihiro Shimizu 890ddd
		//The same as above in reverse order
Toshihiro Shimizu 890ddd
		for (k = r->getChildList().size() - 1; k > jInt; --k) {
Toshihiro Shimizu 890ddd
			child = r->childRegion(k);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
			if (child->getMaximumSize(orientation) == child->getMinimumSize(orientation))
Toshihiro Shimizu 890ddd
				r->separator(k - 1)->setCursor(Qt::ArrowCursor);
Toshihiro Shimizu 890ddd
			else
Toshihiro Shimizu 890ddd
				break;
Toshihiro Shimizu 890ddd
		}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		//Middle separators have a split cursor
Toshihiro Shimizu 890ddd
		Qt::CursorShape shape = (orientation == Region::horizontal) ? Qt::SplitHCursor : Qt::SplitVCursor;
Toshihiro Shimizu 890ddd
		for (; jInt < k; ++jInt)
Toshihiro Shimizu 890ddd
			r->separator(jInt)->setCursor(shape);
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//--------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//!Applies Regions geometry to dock widgets and separators.
Toshihiro Shimizu 890ddd
void DockLayout::applyGeometry()
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	//Update docked window's geometries
Toshihiro Shimizu 890ddd
	unsigned int i, j;
Toshihiro Shimizu 890ddd
	for (i = 0; i < m_regions.size(); ++i) {
Toshihiro Shimizu 890ddd
		Region *r = m_regions[i];
Toshihiro Shimizu 890ddd
		const std::deque<region *=""> &childList = r->getChildList();</region>
Toshihiro Shimizu 890ddd
		std::deque<dockseparator *=""> &sepList = r->m_separators;</dockseparator>
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		if (m_regions[i]->getItem()) {
Toshihiro Shimizu 890ddd
			m_regions[i]->getItem()->setGeometry(toRect(m_regions[i]->getGeometry()));
Toshihiro Shimizu 890ddd
		} else {
Toshihiro Shimizu 890ddd
			for (j = 0; j < sepList.size(); ++j) {
Toshihiro Shimizu 890ddd
				QRect leftAdjRect = toRect(childList[j]->getGeometry());
Toshihiro Shimizu 890ddd
				if (r->getOrientation() == Region::horizontal) {
Toshihiro Shimizu 890ddd
					leftAdjRect.adjust(0, 0, 1, 0); //Take adjacent-to topRight pixel
Toshihiro Shimizu 890ddd
					sepList[j]->setGeometry(QRect(leftAdjRect.topRight(), QSize(spacing(), leftAdjRect.height())));
Toshihiro Shimizu 890ddd
					sepList[j]->m_index = j;
Toshihiro Shimizu 890ddd
				} else {
Toshihiro Shimizu 890ddd
					leftAdjRect.adjust(0, 0, 0, 1);
Toshihiro Shimizu 890ddd
					sepList[j]->setGeometry(QRect(leftAdjRect.bottomLeft(), QSize(leftAdjRect.width(), spacing())));
Toshihiro Shimizu 890ddd
					sepList[j]->m_index = j;
Toshihiro Shimizu 890ddd
				}
Toshihiro Shimizu 890ddd
			}
Toshihiro Shimizu 890ddd
		}
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	//If there is a maximized widget, reset its geometry to that of the main region
Toshihiro Shimizu 890ddd
	if (m_maximizedDock) {
Toshihiro Shimizu 890ddd
		m_maximizedDock->setGeometry(toRect(m_regions[0]->getGeometry()));
Toshihiro Shimizu 890ddd
		m_maximizedDock->raise();
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	//Finally, update separator cursors.
Toshihiro Shimizu 890ddd
	updateSeparatorCursors();
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
void DockLayout::applyTransform(const QTransform &transform)
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	unsigned int i;
Toshihiro Shimizu 890ddd
	for (i = 0; i < m_regions.size(); ++i)
Toshihiro Shimizu 890ddd
		m_regions[i]->setGeometry(transform.mapRect(m_regions[i]->getGeometry()));
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
void DockLayout::redistribute()
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	if (!m_regions.empty()) {
Toshihiro Shimizu 890ddd
		//Recompute extremal region sizes
Toshihiro Shimizu 890ddd
		//NOTA: Sarebbe da fare solo se un certo flag lo richiede; altrimenti tipo per resize events e' inutile...
Toshihiro Shimizu 890ddd
		m_regions.front()->calculateExtremalSizes();
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		int parentWidth = contentsRect().width();
Toshihiro Shimizu 890ddd
		int parentHeight = contentsRect().height();
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		//Always check main window consistency before effective redistribution. DO NOT ERASE or crashes may occur...
Toshihiro Shimizu 890ddd
		if (m_regions.front()->getMinimumSize(Region::horizontal) > parentWidth ||
Toshihiro Shimizu 890ddd
			m_regions.front()->getMinimumSize(Region::vertical) > parentHeight ||
Toshihiro Shimizu 890ddd
			m_regions.front()->getMaximumSize(Region::horizontal) < parentWidth ||
Toshihiro Shimizu 890ddd
			m_regions.front()->getMaximumSize(Region::vertical) < parentHeight)
Toshihiro Shimizu 890ddd
			return;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		//Recompute Layout geometry
Toshihiro Shimizu 890ddd
		m_regions.front()->setGeometry(contentsRect());
Toshihiro Shimizu 890ddd
		m_regions.front()->redistribute();
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	//Finally, apply Region geometries found
Toshihiro Shimizu 890ddd
	applyGeometry();
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//======================================================================
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//=============================
Toshihiro Shimizu 890ddd
//    Region implementation
Toshihiro Shimizu 890ddd
//=============================
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
Region::~Region()
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	//Delete separators
Toshihiro Shimizu 890ddd
	unsigned int i;
Toshihiro Shimizu 890ddd
	for (i = 0; i < m_separators.size(); ++i)
Toshihiro Shimizu 890ddd
		delete m_separators[i];
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//!Inserts DockSeparator \b sep in \b this Region
Toshihiro Shimizu 890ddd
inline void Region::insertSeparator(DockSeparator *sep)
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	m_separators.push_back(sep);
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//!Removes a DockSeparator from \b this Region
Toshihiro Shimizu 890ddd
inline void Region::removeSeparator()
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	delete m_separators.back();
Toshihiro Shimizu 890ddd
	m_separators.pop_back();
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
inline void Region::insertSubRegion(Region *subRegion, int idx)
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	m_childList.insert(m_childList.begin() + idx, subRegion);
Toshihiro Shimizu 890ddd
	subRegion->m_parent = this;
Toshihiro Shimizu 890ddd
	subRegion->m_orientation = !m_orientation;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//!Inserts input \b item before position \b idx. Returns associated new region.
Toshihiro Shimizu 890ddd
inline Region *Region::insertItem(DockWidget *item, int idx)
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	Region *newRegion = new Region(m_owner, item);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	if (this)
Toshihiro Shimizu 890ddd
		insertSubRegion(newRegion, idx);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	return newRegion;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//=============================================================
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
unsigned int Region::find(const Region *subRegion) const
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	unsigned int i;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	for (i = 0; i < m_childList.size(); ++i)
Toshihiro Shimizu 890ddd
		if (m_childList[i] == subRegion)
Toshihiro Shimizu 890ddd
			return i;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	return -1;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
Region *DockLayout::find(DockWidget *item) const
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	unsigned int i;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	for (i = 0; i < m_regions.size(); ++i)
Toshihiro Shimizu 890ddd
		if (m_regions[i]->getItem() == item)
Toshihiro Shimizu 890ddd
			return m_regions[i];
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	return 0;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//!Calculates possible docking solutions for \b this
Toshihiro Shimizu 890ddd
//!dock widget. They are stored into the dock widget.
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//!\b NOTE: Placeholders are here calculated by decreasing importance;
Toshihiro Shimizu 890ddd
//!in other words, if two rects are part of the layout, and the first
Toshihiro Shimizu 890ddd
//!contains the second, placeholders of the first are found before
Toshihiro Shimizu 890ddd
//!those of the second. This fact may be exploited when selecting an
Toshihiro Shimizu 890ddd
//!appropriate placeholder for docking.
Toshihiro Shimizu 890ddd
void DockLayout::calculateDockPlaceholders(DockWidget *item)
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	assert(item);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	//If the DockLayout's owner widget is hidden, avoid
Toshihiro Shimizu 890ddd
	if (!parentWidget()->isVisible())
Toshihiro Shimizu 890ddd
		return;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	if (!m_regions.size()) {
Toshihiro Shimizu 890ddd
		if (isPossibleInsertion(item, 0, 0)) {
Toshihiro Shimizu 890ddd
			//Then insert a root placeholder only
Toshihiro Shimizu 890ddd
			item->m_placeholders.push_back(item->m_decoAllocator->newPlaceBuilt(item, 0, 0, DockPlaceholder::root));
Toshihiro Shimizu 890ddd
			return;
Toshihiro Shimizu 890ddd
		}
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	//For all regions (and for all insertion index), check if
Toshihiro Shimizu 890ddd
	//insertion may succeed.
Toshihiro Shimizu 890ddd
	//NOTE: Insertion chance is just the same for all indexes in a given
Toshihiro Shimizu 890ddd
	//parent region...
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	//First check parentRegion=0 (under a new Root - External cases)
Toshihiro Shimizu 890ddd
	if (isPossibleInsertion(item, 0, 0)) {
Toshihiro Shimizu 890ddd
		QRect contRect = contentsRect();
Toshihiro Shimizu 890ddd
		if (m_regions.front()->getOrientation() == Region::horizontal) {
Toshihiro Shimizu 890ddd
			item->m_placeholders.push_back(item->m_decoAllocator->newPlaceBuilt(item, 0, 0, DockPlaceholder::top));
Toshihiro Shimizu 890ddd
			item->m_placeholders.push_back(item->m_decoAllocator->newPlaceBuilt(item, 0, 1, DockPlaceholder::bottom));
Toshihiro Shimizu 890ddd
		} else {
Toshihiro Shimizu 890ddd
			item->m_placeholders.push_back(item->m_decoAllocator->newPlaceBuilt(item, 0, 0, DockPlaceholder::left));
Toshihiro Shimizu 890ddd
			item->m_placeholders.push_back(item->m_decoAllocator->newPlaceBuilt(item, 0, 1, DockPlaceholder::right));
Toshihiro Shimizu 890ddd
		}
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	unsigned int i;
Toshihiro Shimizu 890ddd
	for (i = 0; i < m_regions.size(); ++i) {
Toshihiro Shimizu 890ddd
		Region *r = m_regions[i];
Toshihiro Shimizu 890ddd
		r->m_placeholders.clear();
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		if (isPossibleInsertion(item, r, 0)) {
Toshihiro Shimizu 890ddd
			unsigned int j;
Toshihiro Shimizu 890ddd
			QRect cellRect;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
			//For all indices, insert a placeholder
Toshihiro Shimizu 890ddd
			if (r->getOrientation() == Region::horizontal) {
Toshihiro Shimizu 890ddd
				//Left side
Toshihiro Shimizu 890ddd
				item->m_placeholders.push_back(item->m_decoAllocator->newPlaceBuilt(item, r, 0, DockPlaceholder::left));
Toshihiro Shimizu 890ddd
				r->m_placeholders.push_back(item->m_placeholders.back());
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
				//Separators
Toshihiro Shimizu 890ddd
				for (j = 1; j < r->getChildList().size(); ++j) {
Toshihiro Shimizu 890ddd
					item->m_placeholders.push_back(item->m_decoAllocator->newPlaceBuilt(item, r, j, DockPlaceholder::sepVert));
Toshihiro Shimizu 890ddd
					r->m_placeholders.push_back(item->m_placeholders.back());
Toshihiro Shimizu 890ddd
				}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
				//Right side
Toshihiro Shimizu 890ddd
				item->m_placeholders.push_back(item->m_decoAllocator->newPlaceBuilt(item, r, j, DockPlaceholder::right));
Toshihiro Shimizu 890ddd
				r->m_placeholders.push_back(item->m_placeholders.back());
Toshihiro Shimizu 890ddd
			} else {
Toshihiro Shimizu 890ddd
				//Top side
Toshihiro Shimizu 890ddd
				item->m_placeholders.push_back(item->m_decoAllocator->newPlaceBuilt(item, r, 0, DockPlaceholder::top));
Toshihiro Shimizu 890ddd
				r->m_placeholders.push_back(item->m_placeholders.back());
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
				for (j = 1; j < r->getChildList().size(); ++j) {
Toshihiro Shimizu 890ddd
					item->m_placeholders.push_back(item->m_decoAllocator->newPlaceBuilt(item, r, j, DockPlaceholder::sepHor));
Toshihiro Shimizu 890ddd
					r->m_placeholders.push_back(item->m_placeholders.back());
Toshihiro Shimizu 890ddd
				}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
				//Bottom side
Toshihiro Shimizu 890ddd
				item->m_placeholders.push_back(item->m_decoAllocator->newPlaceBuilt(item, r, j, DockPlaceholder::bottom));
Toshihiro Shimizu 890ddd
				r->m_placeholders.push_back(item->m_placeholders.back());
Toshihiro Shimizu 890ddd
			}
Toshihiro Shimizu 890ddd
		}
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	//Disable all placeholders
Toshihiro Shimizu 890ddd
	//for(i=0; i<item->m_placeholders.size(); ++i)</item->
Toshihiro Shimizu 890ddd
	//  item->m_placeholders[i]->setDisabled(true);
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//!Docks input \b item before position \b idx of region \b r. Deals with overall region hierarchy.
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//!\b NOTE: Docked items are forcedly shown.
Toshihiro Shimizu 890ddd
void DockLayout::dockItem(DockWidget *item, DockPlaceholder *place)
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	place->hide();
Toshihiro Shimizu 890ddd
	item->hide();
Toshihiro Shimizu 890ddd
	dockItemPrivate(item, place->m_region, place->m_idx);
Toshihiro Shimizu 890ddd
	redistribute();
Toshihiro Shimizu 890ddd
	parentWidget()->repaint();
Toshihiro Shimizu 890ddd
	item->setWindowFlags(Qt::SubWindow);
Toshihiro Shimizu 890ddd
	item->show();
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//!Docks input \b item at side \b regionside of \b target dock widget.
Toshihiro Shimizu 890ddd
//!RegionSide can be Region::left, right, top or bottom.
Toshihiro Shimizu 890ddd
void DockLayout::dockItem(DockWidget *item, DockWidget *target, int regionSide)
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	Region *targetRegion = find(target);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	short var = regionSide >> 2 * (int)targetRegion->getOrientation();
Toshihiro Shimizu 890ddd
	bool pos = regionSide & 0xa;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	item->setWindowFlags(Qt::SubWindow);
Toshihiro Shimizu 890ddd
	item->show();
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	if (var & 0x3) {
Toshihiro Shimizu 890ddd
		//Side is coherent with orientation => Direct insertion at position 0 or 1
Toshihiro Shimizu 890ddd
		dockItemPrivate(item, targetRegion, pos);
Toshihiro Shimizu 890ddd
	} else {
Toshihiro Shimizu 890ddd
		//Side is not coherent - have to find target's index in parent region
Toshihiro Shimizu 890ddd
		Region *parentRegion = targetRegion->getParent();
Toshihiro Shimizu 890ddd
		unsigned int idx = parentRegion ? parentRegion->find(targetRegion) + pos : pos;
Toshihiro Shimizu 890ddd
		dockItemPrivate(item, parentRegion, idx);
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//!Docks input \b item into Region \b r, at position \b idx; returns region corresponding to
Toshihiro Shimizu 890ddd
//!newly inserted item.
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//!\b NOTE: Unlike dockItem(DockWidget*,DockPlaceholder*) and undockItem, this
Toshihiro Shimizu 890ddd
//!method is supposedly called directly into application code; therefore, no \b redistribution
Toshihiro Shimizu 890ddd
//!is done after a single dock - you are supposed to manually call redistribute() after
Toshihiro Shimizu 890ddd
//!all widgets have been docked.
Toshihiro Shimizu 890ddd
Region *DockLayout::dockItem(DockWidget *item, Region *r, int idx)
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	item->setWindowFlags(Qt::SubWindow);
Toshihiro Shimizu 890ddd
	item->show();
Toshihiro Shimizu 890ddd
	return dockItemPrivate(item, r, idx);
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//Internal docking function. Contains raw docking code, excluded reparenting (setWindowFlags)
Toshihiro Shimizu 890ddd
//which may slow down a bit - should be done only after a redistribute() and a repaint() on
Toshihiro Shimizu 890ddd
//real-time docking.
Toshihiro Shimizu 890ddd
inline Region *DockLayout::dockItemPrivate(DockWidget *item, Region *r, int idx)
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	// hide minimize button in FlipboolPanel
Toshihiro Shimizu 890ddd
	item->onDock(true);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	item->setDockedAppearance();
Toshihiro Shimizu 890ddd
	item->m_floating = false;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	if (!r) {
Toshihiro Shimizu 890ddd
		//Insert new root region
Toshihiro Shimizu 890ddd
		Region *newRoot = new Region(this);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		m_regions.push_front(newRoot);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		newRoot->setSize(item->size());
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		if (m_regions.size() == 1) {
Toshihiro Shimizu 890ddd
			newRoot->setItem(item);
Toshihiro Shimizu 890ddd
			return newRoot;
Toshihiro Shimizu 890ddd
		}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		newRoot->setOrientation(!m_regions[1]->getOrientation());
Toshihiro Shimizu 890ddd
		newRoot->insertSubRegion(m_regions[1], 0);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		r = newRoot;
Toshihiro Shimizu 890ddd
	} else if (r->getItem()) {
Toshihiro Shimizu 890ddd
		//Then the Layout gets further subdived - r's item has to be moved
Toshihiro Shimizu 890ddd
		Region *regionForOldItem = r->insertItem(r->getItem(), 0);
Toshihiro Shimizu 890ddd
		regionForOldItem->setSize(r->getItem()->size());
Toshihiro Shimizu 890ddd
		//regionForOldItem->setSize(r->getItem()->frameSize());
Toshihiro Shimizu 890ddd
		r->setItem(0);
Toshihiro Shimizu 890ddd
		m_regions.push_back(regionForOldItem);
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	Region *newRegion = r->insertItem(item, idx);
Toshihiro Shimizu 890ddd
	m_regions.push_back(newRegion);
Toshihiro Shimizu 890ddd
	//Temporarily setting suggested size for newly inserted region
Toshihiro Shimizu 890ddd
	newRegion->setSize(item->size());
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	//Finally, insert a new DockSeparator in parent region r.
Toshihiro Shimizu 890ddd
	r->insertSeparator(m_decoAllocator->newSeparator(this, r->getOrientation(), r));
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	return newRegion;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//!A region is empty, if contains no item and no children.
Toshihiro Shimizu 890ddd
inline bool isEmptyRegion(Region *r)
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	if ((!r->getItem()) && (r->getChildList().size() == 0)) {
Toshihiro Shimizu 890ddd
		delete r; //Be', e' un po' improprio, ma funziona...
Toshihiro Shimizu 890ddd
		return true;
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
	return false;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//!Removes input item from region
Toshihiro Shimizu 890ddd
inline void Region::removeItem(DockWidget *item)
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	if (item == 0)
Toshihiro Shimizu 890ddd
		return;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	unsigned int i;
Toshihiro Shimizu 890ddd
	for (i = 0; i < m_childList.size(); ++i)
Toshihiro Shimizu 890ddd
		if (item == m_childList[i]->getItem()) {
Toshihiro Shimizu 890ddd
			m_childList.erase(m_childList.begin() + i);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
			removeSeparator();
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
			//parent Region may collapse; then move item back to parent and update its parent
Toshihiro Shimizu 890ddd
			if (m_childList.size() == 1) {
Toshihiro Shimizu 890ddd
				Region *parent = getParent();
Toshihiro Shimizu 890ddd
				if (parent) {
Toshihiro Shimizu 890ddd
					Region *remainingSon = m_childList[0];
Toshihiro Shimizu 890ddd
					if (!remainingSon->m_childList.size()) {
Toshihiro Shimizu 890ddd
						//remainingSon is a leaf: better keep this and move son's item and childList
Toshihiro Shimizu 890ddd
						setItem(remainingSon->getItem());
Toshihiro Shimizu 890ddd
						remainingSon->setItem(0);
Toshihiro Shimizu 890ddd
					} else {
Toshihiro Shimizu 890ddd
						//remainingSon is a branch: append remainingSon childList to parent one and
Toshihiro Shimizu 890ddd
						//sign this and remainingSon nodes for destruction.
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
						//First find this position in parent
Toshihiro Shimizu 890ddd
						unsigned int j = parent->find(this);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
						parent->m_childList.erase(parent->m_childList.begin() + j);
Toshihiro Shimizu 890ddd
						parent->m_childList.insert(parent->m_childList.begin() + j, remainingSon->m_childList.begin(),
Toshihiro Shimizu 890ddd
												   remainingSon->m_childList.end());
Toshihiro Shimizu 890ddd
						parent->m_separators.insert(parent->m_separators.begin() + j, remainingSon->m_separators.begin(),
Toshihiro Shimizu 890ddd
													remainingSon->m_separators.end());
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
						//Update remainingSon children's and DockSeparator's parent
Toshihiro Shimizu 890ddd
						for (j = 0; j < remainingSon->m_childList.size(); ++j)
Toshihiro Shimizu 890ddd
							remainingSon->m_childList[j]->m_parent = parent;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
						for (j = 0; j < remainingSon->m_separators.size(); ++j)
Toshihiro Shimizu 890ddd
							remainingSon->m_separators[j]->m_parentRegion = parent;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
						remainingSon->m_childList.clear();
Toshihiro Shimizu 890ddd
						remainingSon->m_separators.clear();
Toshihiro Shimizu 890ddd
					}
Toshihiro Shimizu 890ddd
				} else {
Toshihiro Shimizu 890ddd
					//Root case; better keep the remaining child
Toshihiro Shimizu 890ddd
					m_childList[0]->setParent(0);
Toshihiro Shimizu 890ddd
				}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
				m_childList.clear();
Toshihiro Shimizu 890ddd
			}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
			break;
Toshihiro Shimizu 890ddd
		}
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//!Undocks \b item and updates geometry.
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//!\b NOTE: Window flags are resetted to floating appearance (thus hiding the widget). Since the geometry
Toshihiro Shimizu 890ddd
//!reference changes a geometry() update may be needed - so item's show() is not forced here. You should
Toshihiro Shimizu 890ddd
//!eventually remember to call it manually after this.
Toshihiro Shimizu 890ddd
bool DockLayout::undockItem(DockWidget *item)
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	//Find item's region index in m_regions
Toshihiro Shimizu 890ddd
	Region *itemCarrier = find(item);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	Region *parent = itemCarrier->getParent();
Toshihiro Shimizu 890ddd
	if (parent) {
Toshihiro Shimizu 890ddd
		int removalIdx = 0;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		//Find removal index in parent's childList
Toshihiro Shimizu 890ddd
		unsigned int j;
Toshihiro Shimizu 890ddd
		for (j = 0; j < parent->getChildList().size(); ++j)
Toshihiro Shimizu 890ddd
			if (parent->getChildList()[j]->getItem() == item)
Toshihiro Shimizu 890ddd
				break;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		if (isPossibleRemoval(item, parent, removalIdx))
Toshihiro Shimizu 890ddd
			parent->removeItem(item);
Toshihiro Shimizu 890ddd
		else
Toshihiro Shimizu 890ddd
			return false;
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	//Remove region in regions list
Toshihiro Shimizu 890ddd
	//m_regions.erase(i);   //Don't - m_regions is cleaned before the end by remove_if
Toshihiro Shimizu 890ddd
	itemCarrier->setItem(0);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	std::deque<region *="">::iterator j;</region>
Toshihiro Shimizu 890ddd
	j = std::remove_if(m_regions.begin(), m_regions.end(), isEmptyRegion);
Toshihiro Shimizu 890ddd
	m_regions.resize(j - m_regions.begin());
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	//Update status
Toshihiro Shimizu 890ddd
	//qDebug("Undock");
Toshihiro Shimizu 890ddd
	item->setWindowFlags(Qt::Tool | Qt::FramelessWindowHint);
Toshihiro Shimizu 890ddd
	//NOTA: Usando la flag Qt::Window il focus viene automaticamente riassegnato, con un po' di ritardo.
Toshihiro Shimizu 890ddd
	//Usando Tool questo non accade. In questo caso, i placeholder devono essere disattivati...
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	item->setFloatingAppearance();
Toshihiro Shimizu 890ddd
	item->m_floating = true;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	//show minimize button in FlipbookPanel
Toshihiro Shimizu 890ddd
	item->onDock(false);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	setMaximized(item, false);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	redistribute();
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	return true;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//=============================================================
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//!Search for the \b nearest n-ple from a \b target one, under conditions:
Toshihiro Shimizu 890ddd
//!\b 1) nearest elements belong to \b fixed \b intervals; \b 2) their \b sum is \b fixed too.
Toshihiro Shimizu 890ddd
inline void calculateNearest(std::vector<double> target, std::vector<double> &nearest,</double></double>
Toshihiro Shimizu 890ddd
							 std::vector<std::pair<int, int="">> intervals, double sum)</std::pair<int,>
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	//Solving a small Lagrange multipliers problem to find solution on constraint (2)
Toshihiro Shimizu 890ddd
	assert(target.size() == intervals.size());
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	unsigned int i;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	double targetSum = 0;
Toshihiro Shimizu 890ddd
	for (i = 0; i < target.size(); ++i)
Toshihiro Shimizu 890ddd
		targetSum += target[i];
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	double multiplier = (sum - targetSum) / (double)target.size();
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	nearest.resize(target.size());
Toshihiro Shimizu 890ddd
	for (i = 0; i < target.size(); ++i)
Toshihiro Shimizu 890ddd
		nearest[i] = target[i] + multiplier;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	//Now, constraint (1) is not met; however, satisfying also (2) yields a hyperRect
Toshihiro Shimizu 890ddd
	//on which we must find the nearest point to our above partial solution. In particular,
Toshihiro Shimizu 890ddd
	//it can be demonstrated that at least one coordinate of the current partial solution is related
Toshihiro Shimizu 890ddd
	//to the final one (...). This mean that we may have to solve sub-problems of this same kind,
Toshihiro Shimizu 890ddd
	//with less variable coordinates.
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	unsigned int max;
Toshihiro Shimizu 890ddd
	double distance, maxDistance = 0;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	for (i = 0; i < target.size(); ++i) {
Toshihiro Shimizu 890ddd
		if (nearest[i] < intervals[i].first || nearest[i] > intervals[i].second) {
Toshihiro Shimizu 890ddd
			distance = nearest[i] < intervals[i].first ? intervals[i].first - nearest[i] : nearest[i] - intervals[i].second;
Toshihiro Shimizu 890ddd
			nearest[i] = nearest[i] < intervals[i].first ? intervals[i].first : intervals[i].second;
Toshihiro Shimizu 890ddd
			if (maxDistance < distance) {
Toshihiro Shimizu 890ddd
				maxDistance = distance;
Toshihiro Shimizu 890ddd
				max = i;
Toshihiro Shimizu 890ddd
			}
Toshihiro Shimizu 890ddd
		}
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	std::vector<double> newTarget = target;</double>
Toshihiro Shimizu 890ddd
	std::vector<double> newNearest;</double>
Toshihiro Shimizu 890ddd
	std::vector<std::pair<int, int="">> newIntervals = intervals;</std::pair<int,>
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	if (maxDistance) {
Toshihiro Shimizu 890ddd
		newTarget.erase(newTarget.begin() + max);
Toshihiro Shimizu 890ddd
		newIntervals.erase(newIntervals.begin() + max);
Toshihiro Shimizu 890ddd
		sum -= nearest[max];
Toshihiro Shimizu 890ddd
		calculateNearest(newTarget, newNearest, newIntervals, sum);
Toshihiro Shimizu 890ddd
		for (i = 0; i < max; ++i)
Toshihiro Shimizu 890ddd
			nearest[i] = newNearest[i];
Toshihiro Shimizu 890ddd
		for (i = max + 1; i < nearest.size(); ++i)
Toshihiro Shimizu 890ddd
			nearest[i] = newNearest[i - 1];
Toshihiro Shimizu 890ddd
	} else
Toshihiro Shimizu 890ddd
		return;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//!Equally redistribute separators and children regions' internal geometry
Toshihiro Shimizu 890ddd
//!according to current subregion sizes.
Toshihiro Shimizu 890ddd
void Region::redistribute()
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	if (!m_childList.size())
Toshihiro Shimizu 890ddd
		return;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	bool expansion =
Toshihiro Shimizu 890ddd
		m_minimumSize[Region::horizontal] > m_rect.width() ||
Toshihiro Shimizu 890ddd
		m_minimumSize[Region::vertical] > m_rect.height();
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	double regionSize[2];
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	//If there is no need to expand this region, maintain current geometry; otherwise, expand at minimum.
Toshihiro Shimizu 890ddd
	regionSize[Region::horizontal] = expansion ? m_minimumSize[Region::horizontal] : m_rect.width();
Toshihiro Shimizu 890ddd
	regionSize[Region::vertical] = expansion ? m_minimumSize[Region::vertical] : m_rect.height();
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	//However, expansion in the oriented direction has to take care of parent's consense.
Toshihiro Shimizu 890ddd
	if (m_parent != 0)
Toshihiro Shimizu 890ddd
		regionSize[m_orientation] = std::min((double)m_parent->m_maximumSize[m_orientation], regionSize[m_orientation]);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	//Now find nearest-to-preferred window sizes, according to size constraints.
Toshihiro Shimizu 890ddd
	unsigned int i;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	//First build target sizes vector
Toshihiro Shimizu 890ddd
	std::vector<double> targetSizes(m_childList.size());</double>
Toshihiro Shimizu 890ddd
	for (i = 0; i < m_childList.size(); ++i) {
Toshihiro Shimizu 890ddd
		//Assuming preferred sizes are those already present before redistribution.
Toshihiro Shimizu 890ddd
		targetSizes[i] = (m_orientation == Region::horizontal) ? m_childList[i]->m_rect.width() : m_childList[i]->m_rect.height();
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	//Build minimum and maximum size constraints
Toshihiro Shimizu 890ddd
	std::vector<std::pair<int, int="">> sizeIntervals(m_childList.size());</std::pair<int,>
Toshihiro Shimizu 890ddd
	for (i = 0; i < m_childList.size(); ++i) {
Toshihiro Shimizu 890ddd
		sizeIntervals[i].first = m_childList[i]->m_minimumSize[m_orientation];
Toshihiro Shimizu 890ddd
		sizeIntervals[i].second = m_childList[i]->m_maximumSize[m_orientation];
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	//Build width sum
Toshihiro Shimizu 890ddd
	int separatorWidth = m_owner->spacing();
Toshihiro Shimizu 890ddd
	double sum = regionSize[m_orientation] - (m_childList.size() - 1) * separatorWidth;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	std::vector<double> nearestSizes;</double>
Toshihiro Shimizu 890ddd
	calculateNearest(targetSizes, nearestSizes, sizeIntervals, sum);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	//NearestSizes stores optimal subregion sizes; calculate their geometries and assign them.
Toshihiro Shimizu 890ddd
	QPointF topLeftCorner = m_rect.topLeft();
Toshihiro Shimizu 890ddd
	if (m_orientation == horizontal) {
Toshihiro Shimizu 890ddd
		for (i = 0; i < m_childList.size(); ++i) {
Toshihiro Shimizu 890ddd
			QSizeF currSize = QSizeF(nearestSizes[i], regionSize[vertical]);
Toshihiro Shimizu 890ddd
			m_childList[i]->setGeometry(QRectF(topLeftCorner, currSize));
Toshihiro Shimizu 890ddd
			topLeftCorner = m_childList[i]->getGeometry().topRight() + QPointF(separatorWidth, 0);
Toshihiro Shimizu 890ddd
		}
Toshihiro Shimizu 890ddd
	} else {
Toshihiro Shimizu 890ddd
		for (i = 0; i < m_childList.size(); ++i) {
Toshihiro Shimizu 890ddd
			QSizeF currSize = QSizeF(regionSize[horizontal], nearestSizes[i]);
Toshihiro Shimizu 890ddd
			m_childList[i]->setGeometry(QRectF(topLeftCorner, currSize));
Toshihiro Shimizu 890ddd
			topLeftCorner = m_childList[i]->getGeometry().bottomLeft() + QPointF(0, separatorWidth);
Toshihiro Shimizu 890ddd
		}
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	//Finally, redistribute region's children
Toshihiro Shimizu 890ddd
	for (i = 0; i < m_childList.size(); ++i)
Toshihiro Shimizu 890ddd
		m_childList[i]->redistribute();
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//!Calculates maximum and minimum sizes for each sub-region.
Toshihiro Shimizu 890ddd
void Region::calculateExtremalSizes()
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	calculateMinimumSize(horizontal, true);
Toshihiro Shimizu 890ddd
	calculateMinimumSize(vertical, true);
Toshihiro Shimizu 890ddd
	calculateMaximumSize(horizontal, true);
Toshihiro Shimizu 890ddd
	calculateMaximumSize(vertical, true);
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//!Calculates minimum occupiable space in \b this region on given \b direction. Also stores cache for it.
Toshihiro Shimizu 890ddd
int Region::calculateMinimumSize(bool direction, bool recalcChildren)
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	int sumMinSizes = 0, maxMinSizes = 0;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	if (m_item) {
Toshihiro Shimizu 890ddd
		sumMinSizes = maxMinSizes = (direction == horizontal) ? m_item->minimumSize().width() : m_item->minimumSize().height();
Toshihiro Shimizu 890ddd
	} else {
Toshihiro Shimizu 890ddd
		unsigned int i;
Toshihiro Shimizu 890ddd
		int currMinSize;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		//If required, recalculate children sizes along our direction.
Toshihiro Shimizu 890ddd
		if (recalcChildren) {
Toshihiro Shimizu 890ddd
			for (i = 0; i < m_childList.size(); ++i)
Toshihiro Shimizu 890ddd
				m_childList[i]->calculateMinimumSize(direction, true);
Toshihiro Shimizu 890ddd
		}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		for (i = 0; i < m_childList.size(); ++i) {
Toshihiro Shimizu 890ddd
			sumMinSizes += currMinSize = m_childList[i]->getMinimumSize(direction);
Toshihiro Shimizu 890ddd
			if (maxMinSizes < currMinSize)
Toshihiro Shimizu 890ddd
				maxMinSizes = currMinSize;
Toshihiro Shimizu 890ddd
		}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		//Add separators width
Toshihiro Shimizu 890ddd
		sumMinSizes += m_separators.size() * m_owner->spacing();
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	//If m_orientation is coherent with input direction, minimum occupied space is the sum
Toshihiro Shimizu 890ddd
	//of childs' minimumSizes. Otherwise, the maximum is taken.
Toshihiro Shimizu 890ddd
	if (m_orientation == direction) {
Toshihiro Shimizu 890ddd
		return m_minimumSize[direction] = sumMinSizes;
Toshihiro Shimizu 890ddd
	} else {
Toshihiro Shimizu 890ddd
		return m_minimumSize[direction] = maxMinSizes;
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//!Calculates maximum occupiable space in \b this region on given \b direction. Also stores cache for it.
Toshihiro Shimizu 890ddd
//NOTE: Effectively the dual of calculateMinimumSize(int).
Toshihiro Shimizu 890ddd
int Region::calculateMaximumSize(bool direction, bool recalcChildren)
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	const int inf = 1000000;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	int sumMaxSizes = 0, minMaxSizes = inf;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	if (m_item) {
Toshihiro Shimizu 890ddd
		sumMaxSizes = minMaxSizes = (direction == horizontal) ? m_item->maximumSize().width() : m_item->maximumSize().height();
Toshihiro Shimizu 890ddd
	} else {
Toshihiro Shimizu 890ddd
		unsigned int i;
Toshihiro Shimizu 890ddd
		int currMaxSize;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		//If required, recalculate children sizes along our direction.
Toshihiro Shimizu 890ddd
		if (recalcChildren) {
Toshihiro Shimizu 890ddd
			for (i = 0; i < m_childList.size(); ++i)
Toshihiro Shimizu 890ddd
				m_childList[i]->calculateMaximumSize(direction, true);
Toshihiro Shimizu 890ddd
		}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		for (i = 0; i < m_childList.size(); ++i) {
Toshihiro Shimizu 890ddd
			sumMaxSizes += currMaxSize = m_childList[i]->getMaximumSize(direction);
Toshihiro Shimizu 890ddd
			if (minMaxSizes > currMaxSize)
Toshihiro Shimizu 890ddd
				minMaxSizes = currMaxSize;
Toshihiro Shimizu 890ddd
		}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		//Add separators width
Toshihiro Shimizu 890ddd
		sumMaxSizes += m_separators.size() * m_owner->spacing();
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	//If m_orientation is coherent with input direction, maximum occupied space is the sum
Toshihiro Shimizu 890ddd
	//of childs' maximumSizes. Otherwise, the minimum is taken.
Toshihiro Shimizu 890ddd
	if (m_orientation == direction) {
Toshihiro Shimizu 890ddd
		return m_maximumSize[direction] = sumMaxSizes;
Toshihiro Shimizu 890ddd
	} else {
Toshihiro Shimizu 890ddd
		return m_maximumSize[direction] = minMaxSizes;
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
inline bool Region::addItemSize(DockWidget *item)
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	int sepWidth = m_owner->spacing();
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	if (m_orientation == horizontal) {
Toshihiro Shimizu 890ddd
		//Add minimum and maximum horizontal sizes
Toshihiro Shimizu 890ddd
		m_minimumSize[horizontal] += item->getDockedMinimumSize().width() + sepWidth;
Toshihiro Shimizu 890ddd
		m_maximumSize[horizontal] += item->getDockedMaximumSize().width() + sepWidth;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		//Make max and min with vertical extremal sizes
Toshihiro Shimizu 890ddd
		m_minimumSize[vertical] = std::max(m_minimumSize[vertical], item->getDockedMinimumSize().height());
Toshihiro Shimizu 890ddd
		m_maximumSize[vertical] = std::min(m_maximumSize[vertical], item->getDockedMaximumSize().height());
Toshihiro Shimizu 890ddd
	} else {
Toshihiro Shimizu 890ddd
		//Viceversa
Toshihiro Shimizu 890ddd
		m_minimumSize[vertical] += item->getDockedMinimumSize().height() + sepWidth;
Toshihiro Shimizu 890ddd
		m_maximumSize[vertical] += item->getDockedMaximumSize().height() + sepWidth;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		m_minimumSize[horizontal] = std::max(m_minimumSize[horizontal], item->getDockedMinimumSize().width());
Toshihiro Shimizu 890ddd
		m_maximumSize[horizontal] = std::min(m_maximumSize[horizontal], item->getDockedMaximumSize().width());
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	if (m_minimumSize[horizontal] > m_maximumSize[horizontal] ||
Toshihiro Shimizu 890ddd
		m_minimumSize[vertical] > m_maximumSize[vertical])
Toshihiro Shimizu 890ddd
		return false;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	//Now, climb parent hierarchy and update extremal sizes. If minSizes get > maxSizes, return failed insertion
Toshihiro Shimizu 890ddd
	Region *r = m_parent;
Toshihiro Shimizu 890ddd
	while (r) {
Toshihiro Shimizu 890ddd
		r->calculateMinimumSize(horizontal, false);
Toshihiro Shimizu 890ddd
		r->calculateMinimumSize(vertical, false);
Toshihiro Shimizu 890ddd
		r->calculateMaximumSize(horizontal, false);
Toshihiro Shimizu 890ddd
		r->calculateMaximumSize(vertical, false);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		if (r->getMinimumSize(horizontal) > r->getMaximumSize(horizontal) ||
Toshihiro Shimizu 890ddd
			r->getMinimumSize(vertical) > r->getMaximumSize(vertical))
Toshihiro Shimizu 890ddd
			return false;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		r = r->m_parent;
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	return true;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
inline bool Region::subItemSize(DockWidget *item)
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	int sepWidth = m_owner->spacing();
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	if (m_orientation == horizontal) {
Toshihiro Shimizu 890ddd
		//Subtract minimum and maximum horizontal sizes
Toshihiro Shimizu 890ddd
		m_minimumSize[horizontal] -= item->minimumSize().width() + sepWidth;
Toshihiro Shimizu 890ddd
		m_maximumSize[horizontal] -= item->maximumSize().width() + sepWidth;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		//Recalculate opposite extremal sizes (without considering item)
Toshihiro Shimizu 890ddd
		unsigned int i;
Toshihiro Shimizu 890ddd
		for (i = 0; i < m_childList.size(); ++i)
Toshihiro Shimizu 890ddd
			if (m_childList[i]->getItem() != item) {
Toshihiro Shimizu 890ddd
				m_minimumSize[vertical] = std::max(m_minimumSize[vertical], m_childList[i]->getMinimumSize(vertical));
Toshihiro Shimizu 890ddd
				m_maximumSize[vertical] = std::min(m_maximumSize[vertical], m_childList[i]->getMaximumSize(vertical));
Toshihiro Shimizu 890ddd
			}
Toshihiro Shimizu 890ddd
	} else {
Toshihiro Shimizu 890ddd
		//Viceversa
Toshihiro Shimizu 890ddd
		m_minimumSize[vertical] -= item->minimumSize().height() + sepWidth;
Toshihiro Shimizu 890ddd
		m_maximumSize[vertical] -= item->maximumSize().height() + sepWidth;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		//Recalculate opposite extremal sizes (without considering item)
Toshihiro Shimizu 890ddd
		unsigned int i;
Toshihiro Shimizu 890ddd
		for (i = 0; i < m_childList.size(); ++i)
Toshihiro Shimizu 890ddd
			if (m_childList[i]->getItem() != item) {
Toshihiro Shimizu 890ddd
				m_minimumSize[horizontal] = std::max(m_minimumSize[horizontal], m_childList[i]->getMinimumSize(horizontal));
Toshihiro Shimizu 890ddd
				m_maximumSize[horizontal] = std::min(m_maximumSize[horizontal], m_childList[i]->getMaximumSize(horizontal));
Toshihiro Shimizu 890ddd
			}
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	if (m_minimumSize[horizontal] > m_maximumSize[horizontal] ||
Toshihiro Shimizu 890ddd
		m_minimumSize[vertical] > m_maximumSize[vertical])
Toshihiro Shimizu 890ddd
		return false;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	//Now, climb parent hierarchy and update extremal sizes. If minSizes get > maxSizes, return failed insertion
Toshihiro Shimizu 890ddd
	Region *r = m_parent;
Toshihiro Shimizu 890ddd
	while (r) {
Toshihiro Shimizu 890ddd
		r->calculateMinimumSize(horizontal, false);
Toshihiro Shimizu 890ddd
		r->calculateMinimumSize(vertical, false);
Toshihiro Shimizu 890ddd
		r->calculateMaximumSize(horizontal, false);
Toshihiro Shimizu 890ddd
		r->calculateMaximumSize(vertical, false);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		if (r->getMinimumSize(horizontal) > r->getMaximumSize(horizontal) ||
Toshihiro Shimizu 890ddd
			r->getMinimumSize(vertical) > r->getMaximumSize(vertical))
Toshihiro Shimizu 890ddd
			return false;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		r = r->m_parent;
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	return true;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//=============================================================
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//!Checks insertion validity of \b item inside \b parentRegion at position \b insertionIdx.
Toshihiro Shimizu 890ddd
inline bool DockLayout::isPossibleInsertion(DockWidget *item, Region *parentRegion, int insertionIdx)
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	const int inf = 1000000;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	int mainWindowWidth = contentsRect().width();
Toshihiro Shimizu 890ddd
	int mainWindowHeight = contentsRect().height();
Toshihiro Shimizu 890ddd
	std::deque<region *="">::iterator i;</region>
Toshihiro Shimizu 890ddd
	bool result = true;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	if (m_regions.size()) {
Toshihiro Shimizu 890ddd
		//Calculate original extremal sizes
Toshihiro Shimizu 890ddd
		m_regions.front()->calculateExtremalSizes();
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		if (parentRegion) //Common case
Toshihiro Shimizu 890ddd
		{
Toshihiro Shimizu 890ddd
			//And update parent region extremal size after hypothetic insertion took place
Toshihiro Shimizu 890ddd
			result &= parentRegion->addItemSize(item);
Toshihiro Shimizu 890ddd
		} else //With root insertion
Toshihiro Shimizu 890ddd
		{
Toshihiro Shimizu 890ddd
			//Insertion under new root: simulated by adding with m_regions.front() on its opposite direction;
Toshihiro Shimizu 890ddd
			bool frontOrientation = m_regions.front()->getOrientation();
Toshihiro Shimizu 890ddd
			m_regions.front()->setOrientation(!frontOrientation);
Toshihiro Shimizu 890ddd
			result &= m_regions.front()->addItemSize(item);
Toshihiro Shimizu 890ddd
			m_regions.front()->setOrientation(frontOrientation);
Toshihiro Shimizu 890ddd
		}
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	QSize rootMinSize;
Toshihiro Shimizu 890ddd
	QSize rootMaxSize;
Toshihiro Shimizu 890ddd
	if (m_regions.size()) {
Toshihiro Shimizu 890ddd
		rootMinSize =
Toshihiro Shimizu 890ddd
			QSize(m_regions[0]->getMinimumSize(Region::horizontal), m_regions[0]->getMinimumSize(Region::vertical));
Toshihiro Shimizu 890ddd
		rootMaxSize =
Toshihiro Shimizu 890ddd
			QSize(m_regions[0]->getMaximumSize(Region::horizontal), m_regions[0]->getMaximumSize(Region::vertical));
Toshihiro Shimizu 890ddd
	} else {
Toshihiro Shimizu 890ddd
		//New Root
Toshihiro Shimizu 890ddd
		rootMinSize = item->minimumSize();
Toshihiro Shimizu 890ddd
		rootMaxSize = item->maximumSize();
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	//Finally, check updated root against main window sizes
Toshihiro Shimizu 890ddd
	if (rootMinSize.width() > mainWindowWidth ||
Toshihiro Shimizu 890ddd
		rootMinSize.height() > mainWindowHeight ||
Toshihiro Shimizu 890ddd
		rootMaxSize.width() < mainWindowWidth ||
Toshihiro Shimizu 890ddd
		rootMaxSize.height() < mainWindowHeight) {
Toshihiro Shimizu 890ddd
		result = false;
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	return result;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//!Checks insertion validity of \b item inside \b parentRegion at position \b insertionIdx.
Toshihiro Shimizu 890ddd
inline bool DockLayout::isPossibleRemoval(DockWidget *item, Region *parentRegion, int removalIdx)
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	//NOTE: parentRegion is necessarily !=0 or there's no need to check anything
Toshihiro Shimizu 890ddd
	if (!parentRegion)
Toshihiro Shimizu 890ddd
		return true;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	const int inf = 1000000;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	int mainWindowWidth = contentsRect().width();
Toshihiro Shimizu 890ddd
	int mainWindowHeight = contentsRect().height();
Toshihiro Shimizu 890ddd
	std::deque<region *="">::iterator i;</region>
Toshihiro Shimizu 890ddd
	bool result = true;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	//Calculate original extremal sizes
Toshihiro Shimizu 890ddd
	m_regions.front()->calculateExtremalSizes();
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	//And update parent region extremal size after hypothetic insertion took place
Toshihiro Shimizu 890ddd
	result &= parentRegion->subItemSize(item);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	QSize rootMinSize;
Toshihiro Shimizu 890ddd
	QSize rootMaxSize;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	rootMinSize =
Toshihiro Shimizu 890ddd
		QSize(m_regions[0]->getMinimumSize(Region::horizontal), m_regions[0]->getMinimumSize(Region::vertical));
Toshihiro Shimizu 890ddd
	rootMaxSize =
Toshihiro Shimizu 890ddd
		QSize(m_regions[0]->getMaximumSize(Region::horizontal), m_regions[0]->getMaximumSize(Region::vertical));
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	//Finally, check updated root against main window sizes
Toshihiro Shimizu 890ddd
	if (rootMinSize.width() > mainWindowWidth ||
Toshihiro Shimizu 890ddd
		rootMinSize.height() > mainWindowHeight ||
Toshihiro Shimizu 890ddd
		rootMaxSize.width() < mainWindowWidth ||
Toshihiro Shimizu 890ddd
		rootMaxSize.height() < mainWindowHeight) {
Toshihiro Shimizu 890ddd
		result = false;
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	return result;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//========================================================
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//===================
Toshihiro Shimizu 890ddd
//    Save & Load
Toshihiro Shimizu 890ddd
//===================
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//!Returns the current \b State of the layout. A State is a typedef
Toshihiro Shimizu 890ddd
//!for a pair containing the (normal) geometries of all layout items,
Toshihiro Shimizu 890ddd
//!and a string indicating their hierarchycal structure.
Toshihiro Shimizu 890ddd
DockLayout::State DockLayout::saveState()
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	QString hierarchy;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	//Set save indices so we don't need to find anything
Toshihiro Shimizu 890ddd
	unsigned int i;
Toshihiro Shimizu 890ddd
	for (i = 0; i < m_regions.size(); ++i)
Toshihiro Shimizu 890ddd
		m_regions[i]->m_saveIndex = i;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	DockWidget *item;
Toshihiro Shimizu 890ddd
	for (i = 0; i < m_items.size(); ++i) {
Toshihiro Shimizu 890ddd
		item = static_cast<dockwidget *="">(m_items[i]->widget());</dockwidget>
Toshihiro Shimizu 890ddd
		item->m_saveIndex = i;
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	//Write item geometries
Toshihiro Shimizu 890ddd
	std::vector<qrect> geometries;</qrect>
Toshihiro Shimizu 890ddd
	for (i = 0; i < m_items.size(); ++i)
Toshihiro Shimizu 890ddd
		geometries.push_back(m_items[i]->geometry());
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	QTextStream stream(&hierarchy, QIODevice::WriteOnly);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	//Save maximimized Dock index and geometry
Toshihiro Shimizu 890ddd
	stream << QString::number(m_maximizedDock ? m_maximizedDock->m_saveIndex : -1) << " ";
Toshihiro Shimizu 890ddd
	if (m_maximizedDock) {
Toshihiro Shimizu 890ddd
		Region *r = find(m_maximizedDock);
Toshihiro Shimizu 890ddd
		geometries[m_maximizedDock->m_saveIndex] = toRect(r->getGeometry());
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	//Save regions
Toshihiro Shimizu 890ddd
	Region *r = rootRegion();
Toshihiro Shimizu 890ddd
	if (r) {
Toshihiro Shimizu 890ddd
		stream << QString::number(r->getOrientation()) << " ";
Toshihiro Shimizu 890ddd
		writeRegion(r, hierarchy);
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	return std::pair<std::vector<qrect>, QString>(geometries, hierarchy);</std::vector<qrect>
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
void DockLayout::writeRegion(Region *r, QString &hierarchy)
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	DockWidget *item = static_cast<dockwidget *="">(r->getItem());</dockwidget>
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	//If Region has item, write it.
Toshihiro Shimizu 890ddd
	if (item) {
Toshihiro Shimizu 890ddd
		hierarchy.append(QString::number(item->m_saveIndex) + " ");
Toshihiro Shimizu 890ddd
	} else {
Toshihiro Shimizu 890ddd
		hierarchy.append("[ ");
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		//Scan childList
Toshihiro Shimizu 890ddd
		unsigned int i, size = r->getChildList().size();
Toshihiro Shimizu 890ddd
		for (i = 0; i < size; ++i) {
Toshihiro Shimizu 890ddd
			writeRegion(r->childRegion(i), hierarchy);
Toshihiro Shimizu 890ddd
		}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		hierarchy.append("] ");
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//!Restores the given internal structure of the layout.
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//!This method is intended to restore the
Toshihiro Shimizu 890ddd
//!geometry of a set of items that was handled by the layout
Toshihiro Shimizu 890ddd
//!at the time the state was saved. Input are the geometries of
Toshihiro Shimizu 890ddd
//!the items involved and the dock hierarchy in form of a string.
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//!\b IMPORTANT \b NOTE: No check is performed on the item themselves,
Toshihiro Shimizu 890ddd
//!except for the consistency of their geometrical constraints
Toshihiro Shimizu 890ddd
//!inside the layout. Furthermore, this method does not ensure the
Toshihiro Shimizu 890ddd
//!identity of the items involved, assuming that the set of dock
Toshihiro Shimizu 890ddd
//!widget has ever been left unchanged or completely restored
Toshihiro Shimizu 890ddd
//!as it were when saved. In particular, their ordering must be preserved.
Toshihiro Shimizu 890ddd
bool DockLayout::restoreState(const State &state)
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	QStringList vars = state.second.split(" ", QString::SkipEmptyParts);
Toshihiro Shimizu 890ddd
	if (vars.size() < 1)
Toshihiro Shimizu 890ddd
		return 0;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	//Check number of items
Toshihiro Shimizu 890ddd
	unsigned int count = state.first.size();
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	if (m_items.size() != count)
Toshihiro Shimizu 890ddd
		return false; //Items list is not coherent
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	//Initialize new Regions hierarchy
Toshihiro Shimizu 890ddd
	std::deque<region *=""> newHierarchy;</region>
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	//Load it
Toshihiro Shimizu 890ddd
	int maximizedItem = vars[0].toInt();
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	if (vars.size() > 1) {
Toshihiro Shimizu 890ddd
		//Scan hierarchy
Toshihiro Shimizu 890ddd
		Region *r = 0, *newRegion;
Toshihiro Shimizu 890ddd
		int orientation = !vars[1].toInt();
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		int i;
Toshihiro Shimizu 890ddd
		for (i = 2; i < vars.size(); ++i) {
Toshihiro Shimizu 890ddd
			if (vars[i] == "]") {
Toshihiro Shimizu 890ddd
				//End region and get parent
Toshihiro Shimizu 890ddd
				r = r->getParent();
Toshihiro Shimizu 890ddd
			} else {
Toshihiro Shimizu 890ddd
				//Allocate new Region
Toshihiro Shimizu 890ddd
				newRegion = new Region(this);
Toshihiro Shimizu 890ddd
				newHierarchy.push_back(newRegion);
Toshihiro Shimizu 890ddd
				newRegion->m_orientation = !orientation;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
				if (r)
Toshihiro Shimizu 890ddd
					r->insertSubRegion(newRegion, r->getChildList().size());
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
				if (vars[i] == "[") {
Toshihiro Shimizu 890ddd
					//Current region has children
Toshihiro Shimizu 890ddd
					r = newRegion;
Toshihiro Shimizu 890ddd
				} else {
Toshihiro Shimizu 890ddd
					//newRegion has item
Toshihiro Shimizu 890ddd
					newRegion->m_item = static_cast<dockwidget *="">(m_items[vars[i].toInt()]->widget());</dockwidget>
Toshihiro Shimizu 890ddd
				}
Toshihiro Shimizu 890ddd
			}
Toshihiro Shimizu 890ddd
		}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		//Check if size constraints are satisfied
Toshihiro Shimizu 890ddd
		newHierarchy[0]->calculateExtremalSizes();
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	unsigned int j;
Toshihiro Shimizu 890ddd
	for (j = 0; j < newHierarchy.size(); ++j) {
Toshihiro Shimizu 890ddd
		//Check if their extremal sizes are valid
Toshihiro Shimizu 890ddd
		Region *r = newHierarchy[j];
Toshihiro Shimizu 890ddd
		if (r->getMinimumSize(Region::horizontal) > r->getMaximumSize(Region::horizontal) ||
Toshihiro Shimizu 890ddd
			r->getMinimumSize(Region::vertical) > r->getMaximumSize(Region::vertical)) {
Toshihiro Shimizu 890ddd
			//If not, deallocate attempted hierarchy and quit
Toshihiro Shimizu 890ddd
			for (j = 0; j < newHierarchy.size(); ++j)
Toshihiro Shimizu 890ddd
				delete newHierarchy[j];
Toshihiro Shimizu 890ddd
			return false;
Toshihiro Shimizu 890ddd
		}
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	//Else, deallocate old regions and substitute with new ones
Toshihiro Shimizu 890ddd
	for (j = 0; j < m_regions.size(); ++j)
Toshihiro Shimizu 890ddd
		delete m_regions[j];
Toshihiro Shimizu 890ddd
	m_regions = newHierarchy;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	//Now re-initialize dock widgets' infos.
Toshihiro Shimizu 890ddd
	const std::vector<qrect> &geoms = state.first;</qrect>
Toshihiro Shimizu 890ddd
	DockWidget *item;
Toshihiro Shimizu 890ddd
	for (j = 0; j < m_items.size(); ++j) {
Toshihiro Shimizu 890ddd
		item = static_cast<dockwidget *="">(m_items[j]->widget());</dockwidget>
Toshihiro Shimizu 890ddd
		item->setGeometry(geoms[j]);
Toshihiro Shimizu 890ddd
		item->m_maximized = false;
Toshihiro Shimizu 890ddd
		item->m_saveIndex = j;
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	//Docked widgets are found in hierarchy
Toshihiro Shimizu 890ddd
	for (j = 0; j < m_regions.size(); ++j)
Campbell Barton 5ea53c
		if ((item = m_regions[j]->m_item)) {
Toshihiro Shimizu 890ddd
			item->setWindowFlags(Qt::SubWindow);
Toshihiro Shimizu 890ddd
			item->setDockedAppearance();
Toshihiro Shimizu 890ddd
			item->m_floating = false;
Toshihiro Shimizu 890ddd
			item->m_saveIndex = -1;
Toshihiro Shimizu 890ddd
			item->show();
Toshihiro Shimizu 890ddd
		}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	//Recover available geometry infos
Toshihiro Shimizu 890ddd
	//QRect availableRect= QApplication::desktop()->availableGeometry();
Toshihiro Shimizu 890ddd
	int recoverX = 0, recoverY = 0;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	//Deal with floating panels
Toshihiro Shimizu 890ddd
	for (j = 0; j < m_items.size(); ++j) {
Toshihiro Shimizu 890ddd
		item = static_cast<dockwidget *="">(m_items[j]->widget());</dockwidget>
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		if (item->m_saveIndex > 0) {
Toshihiro Shimizu 890ddd
			//Ensure that floating panels are not placed in
Toshihiro Shimizu 890ddd
			//unavailable positions
Toshihiro Shimizu 890ddd
			if ((geoms[j] & QApplication::desktop()->availableGeometry(item)).isEmpty())
Toshihiro Shimizu 890ddd
				item->move(recoverX += 50, recoverY += 50);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
			//Set floating appearances
Toshihiro Shimizu 890ddd
			item->setWindowFlags(Qt::Tool | Qt::FramelessWindowHint);
Toshihiro Shimizu 890ddd
			item->setFloatingAppearance();
Toshihiro Shimizu 890ddd
			item->m_floating = true;
Toshihiro Shimizu 890ddd
		}
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	//Allocate region separators
Toshihiro Shimizu 890ddd
	unsigned int k;
Toshihiro Shimizu 890ddd
	for (j = 0; j < m_regions.size(); ++j) {
Toshihiro Shimizu 890ddd
		Region *r = m_regions[j];
Toshihiro Shimizu 890ddd
		for (k = 1; k < r->m_childList.size(); ++k) {
Toshihiro Shimizu 890ddd
			r->insertSeparator(m_decoAllocator->newSeparator(this, r->getOrientation(), r));
Toshihiro Shimizu 890ddd
		}
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	//Calculate regions' geometry starting from leaves (items)
Toshihiro Shimizu 890ddd
	if (m_regions.size())
Toshihiro Shimizu 890ddd
		m_regions[0]->restoreGeometry();
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	//Then, ensure the result is correctly fitting the contents rect
Toshihiro Shimizu 890ddd
	//redistribute();
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	//NOTE: The previous might be tempting to ensure all is right - unfortunately, it may
Toshihiro Shimizu 890ddd
	//be that the main window's content rect is not yet defined before it is shown the first
Toshihiro Shimizu 890ddd
	//time (like on MAC), and that is needed to redistribute. Se we force the saved values
Toshihiro Shimizu 890ddd
	//(assuming they are right)...
Toshihiro Shimizu 890ddd
	applyGeometry();
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	//Finally, set maximized dock widget
Toshihiro Shimizu 890ddd
	if (maximizedItem != -1) {
Toshihiro Shimizu 890ddd
		item = static_cast<dockwidget *="">(m_items[maximizedItem]->widget());</dockwidget>
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		//Problema: Puo' essere, in fase di caricamento dati, che la contentsRect del layout
Toshihiro Shimizu 890ddd
		//venga sballata! (vv. lo ctor di TMainWindow) Allora, evitiamo il controllo fatto
Toshihiro Shimizu 890ddd
		//in setMazimized, e assumiamo sia per forza corretto...
Toshihiro Shimizu 890ddd
		//setMaximized(item, true);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		m_maximizedDock = item;
Toshihiro Shimizu 890ddd
		item->m_maximized = true;
Toshihiro Shimizu 890ddd
		item->raise();
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		//Hide all other widgets
Toshihiro Shimizu 890ddd
		QWidget *currWidget;
Toshihiro Shimizu 890ddd
		for (int i = 0; i < this->count(); ++i)
Toshihiro Shimizu 890ddd
			if ((currWidget = itemAt(i)->widget()) != item)
Toshihiro Shimizu 890ddd
				currWidget->hide();
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	return true;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//!Recalculates the geometry of \b this Region and of its branches,
Toshihiro Shimizu 890ddd
//!assuming those of 'leaf items' are correct.
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//!Regions always tend to keep their geometry by default. However,
Toshihiro Shimizu 890ddd
//!it may be useful (for example, when restoring the state of a DockLayout)
Toshihiro Shimizu 890ddd
//!the possibility of recalculating its current geometry directly from the
Toshihiro Shimizu 890ddd
//!items that are contained in the branches.
Toshihiro Shimizu 890ddd
void Region::restoreGeometry()
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	//Applying a head-recursive algorithm to update the geometry of a Region
Toshihiro Shimizu 890ddd
	//after those of its children have been updated
Toshihiro Shimizu 890ddd
	if (m_item) {
Toshihiro Shimizu 890ddd
		//Place item's geometry
Toshihiro Shimizu 890ddd
		setGeometry(m_item->geometry());
Toshihiro Shimizu 890ddd
		return;
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	//First do children
Toshihiro Shimizu 890ddd
	unsigned int i;
Toshihiro Shimizu 890ddd
	for (i = 0; i < m_childList.size(); ++i)
Toshihiro Shimizu 890ddd
		m_childList[i]->restoreGeometry();
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	//Then, update this one: just take the edges of its children.
Toshihiro Shimizu 890ddd
	unsigned int last = m_childList.size() - 1;
Toshihiro Shimizu 890ddd
	QPoint topLeft(m_childList[0]->getGeometry().left(), m_childList[0]->getGeometry().top());
Toshihiro Shimizu 890ddd
	QPoint bottomRight(m_childList[last]->getGeometry().right(), m_childList[last]->getGeometry().bottom());
Toshihiro Shimizu 890ddd
	setGeometry(QRect(topLeft, bottomRight));
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	return;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//========================================================================
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//---------------------------
Toshihiro Shimizu 890ddd
//    Dock Deco Allocator
Toshihiro Shimizu 890ddd
//---------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//!Allocates a new DockSeparator with input parameters. This function can be re-implemented
Toshihiro Shimizu 890ddd
//!to allocate derived DockSeparator classes.
Toshihiro Shimizu 890ddd
inline DockSeparator *DockDecoAllocator::newSeparator(DockLayout *owner, bool orientation, Region *parentRegion)
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	return new DockSeparator(owner, orientation, parentRegion);
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//!When inheriting a DockLayout class, new custom placeholders gets allocated by this method.
Toshihiro Shimizu 890ddd
inline DockPlaceholder *DockDecoAllocator::newPlaceholder(DockWidget *owner, Region *r, int idx, int attributes)
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	return new DockPlaceholder(owner, r, idx, attributes);
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//BuildGeometry() method should not be called inside the base contructor - because it's a virtual method.
Toshihiro Shimizu 890ddd
//So we provide this little inline...
Toshihiro Shimizu 890ddd
inline DockPlaceholder *DockDecoAllocator::newPlaceBuilt(DockWidget *owner, Region *r, int idx, int attributes)
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	DockPlaceholder *res = newPlaceholder(owner, r, idx, attributes);
Toshihiro Shimizu 890ddd
	res->buildGeometry();
Toshihiro Shimizu 890ddd
	return res;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//!Sets current deco allocator to decoAllocator. A default deco allocator
Toshihiro Shimizu 890ddd
//!is already provided at construction.
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//!\b NOTE: DockLayout takes ownership of the allocator.
Toshihiro Shimizu 890ddd
void DockLayout::setDecoAllocator(DockDecoAllocator *decoAllocator)
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	//Delete old one
Toshihiro Shimizu 890ddd
	if (m_decoAllocator)
Toshihiro Shimizu 890ddd
		delete m_decoAllocator;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	//Place new one
Toshihiro Shimizu 890ddd
	m_decoAllocator = decoAllocator;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//!Sets current deco allocator to decoAllocator. A default deco allocator
Toshihiro Shimizu 890ddd
//!is already provided at construction.
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//!\b NOTE: DockWidget takes ownership of the allocator.
Toshihiro Shimizu 890ddd
void DockWidget::setDecoAllocator(DockDecoAllocator *decoAllocator)
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	//Delete old one
Toshihiro Shimizu 890ddd
	if (m_decoAllocator)
Toshihiro Shimizu 890ddd
		delete m_decoAllocator;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	//Place a copy of new one
Toshihiro Shimizu 890ddd
	m_decoAllocator = decoAllocator;
Toshihiro Shimizu 890ddd
}