Blob Blame Raw


#include "tdockwindows.h"
#include <QBoxLayout>
#include <QVBoxLayout>

#include <QRegion>

#include <QPainter>
#include <QStyleOption>

#include <QMouseEvent>

//----------------------------------------

//-------------------
//    Decorations
//-------------------

class TDockDecoAllocator : public DockDecoAllocator
{
	DockSeparator *newSeparator(DockLayout *owner, bool orientation, Region *parentRegion);
	DockPlaceholder *newPlaceholder(DockWidget *owner, Region *r, int idx, int attributes);
};

//========================================================================

//-----------------------
//    TMainWindow
//-----------------------

TMainWindow::TMainWindow(QWidget *parent, Qt::WindowFlags flags)
	: QWidget(parent, flags)
{
	//Delete on close
	setAttribute(Qt::WidgetAttribute(Qt::WA_DeleteOnClose));

	//Set a vertical layout to include menu bars
	QVBoxLayout *vlayout = new QVBoxLayout;
	vlayout->setMargin(0);
	vlayout->setSpacing(4);
	setLayout(vlayout);

	//Allocate the dock layout
	m_layout = new DockLayout;
	m_layout->setContentsMargins(0, 0, 0, 0);
	m_layout->setSpacing(8);
	m_layout->setDecoAllocator(new TDockDecoAllocator);
	vlayout->addLayout(m_layout);
	vlayout->setAlignment(m_layout, Qt::AlignTop);

	show(); //NOTA: E' NECESSARIO MOSTRARE LA FINESTRA, prima di dockare qualcosa (altrimenti non viene fatto
			//l'update della geometria della main window, e il contentsRect del layout viene sballato!!).
}

//----------------------------------------

TMainWindow::~TMainWindow()
{
}

//----------------------------------------

//!Adds input \b item to this TMainWindow. If item was already
//!assigned to \b this TMainWindow, nothing happens.
void TMainWindow::addDockWidget(TDockWidget *item)
{
	if (!m_layout->find(item))
		m_layout->addWidget(item);
}

//----------------------------------------

void TMainWindow::removeDockWidget(TDockWidget *item)
{
	m_layout->removeWidget(item);
}

//----------------------------------------

//NOTE: Unlike QMainWindow::addToolBar, we only allow one
//fixed-size undockable menu bar at top of the dock layout.
void TMainWindow::setMenuWidget(QWidget *menubar)
{
	if (menubar) {
		QVBoxLayout *vlayout = static_cast<QVBoxLayout *>(layout());

		//If necessary, remove current menu bar
		if (m_menu && m_menu != menubar)
			vlayout->removeWidget(m_menu);

		vlayout->insertWidget(0, menubar);
	}
}

//----------------------------------------

void TMainWindow::setDecoAllocator(DockDecoAllocator *allocator)
{
	m_layout->setDecoAllocator(allocator);
}

//----------------------------------------

//!Sets global thickness of separators between dock widget.
void TMainWindow::setSeparatorsThickness(int thick)
{
	if (thick > 0) {
		m_layout->setSpacing(thick);
		m_layout->redistribute();
	}
}

//----------------------------------------

void TMainWindow::resizeEvent(QResizeEvent *event)
{
	m_layout->redistribute();
}

//========================================================================

//-------------------
//    TDockWidget
//-------------------

//!Constructs a TDockWidget with given parent and window flags. If parent is
//!a TMainWindow, then the constructed dock widget is assigned to it (addDockWidget'd).
//!TDockWidgets are always floating at construction.
TDockWidget::TDockWidget(QWidget *parent, Qt::WindowFlags flags)
	: DockWidget(parent, flags), m_widget(0), m_titlebar(0), m_margin(5)
{
	setAutoFillBackground(false);
	//setFrameStyle(QFrame::StyledPanel);

	QBoxLayout *layout = new QBoxLayout(QBoxLayout::TopToBottom);
	layout->setSpacing(0);
	setLayout(layout);

	//Check if parent is a TMainWindow class
	TMainWindow *parentMain = qobject_cast<TMainWindow *>(parent);
	if (parentMain)
		parentMain->addDockWidget(this);

	setDecoAllocator(new TDockDecoAllocator);
}

//----------------------------------------

TDockWidget::TDockWidget(const QString &title, QWidget *parent, Qt::WindowFlags flags)
	: DockWidget(parent, flags), m_widget(0), m_titlebar(0), m_margin(5)
{
	setWindowTitle(title);

	QBoxLayout *layout = new QBoxLayout(QBoxLayout::TopToBottom);
	layout->setSpacing(0);
	setLayout(layout);
}

//----------------------------------------

void TDockWidget::setTitleBarWidget(QWidget *titlebar)
{
	if (titlebar) {
		QBoxLayout *boxLayout = static_cast<QBoxLayout *>(layout());

		if (m_titlebar && m_titlebar != titlebar)
			boxLayout->removeWidget(m_titlebar);

		boxLayout->insertWidget(0, titlebar);
		//Set top/left-aligned
		boxLayout->setAlignment(titlebar, getOrientation() == vertical ? Qt::AlignTop : Qt::AlignLeft);

		m_titlebar = titlebar;
		if (m_floating)
			setFloatingAppearance();
	}
}

//----------------------------------------

void TDockWidget::windowTitleEvent(QEvent *e)
{
	if (m_titlebar)
		m_titlebar->update();
}

//----------------------------------------

void TDockWidget::setWidget(QWidget *widget)
{
	if (widget) {
		QBoxLayout *boxLayout = static_cast<QBoxLayout *>(layout());

		if (m_widget && m_widget != widget)
			boxLayout->removeWidget(m_widget);

		boxLayout->insertWidget(1, widget);
		widget->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);

		m_widget = widget;
	}
}

//----------------------------------------

void TDockWidget::setFloatingAppearance()
{
	if (m_titlebar) {
		//If has a custom title bar, impose a margin to the layout
		//to provide a frame.
		layout()->setMargin(m_margin);

		if (!m_floating) //was docked
		{
			//Adding margin to extremal sizes
			int addition = 2 * m_margin;
			setMinimumSize(QSize(minimumWidth() + addition, minimumHeight() + addition));
			setMaximumSize(QSize(maximumWidth() + addition, maximumHeight() + addition));
		}
	}
	//else
	//  setWindowFlags(Qt::Tool);
}

//----------------------------------------

void TDockWidget::setDockedAppearance()
{
	//No layout margin is visible when docked
	layout()->setMargin(0);

	if (m_floating) //was floating
	{
		//Removing margin from extremal sizes
		int addition = 2 * m_margin;
		setMinimumSize(QSize(minimumWidth() - addition, minimumHeight() - addition));
		setMaximumSize(QSize(maximumWidth() - addition, maximumHeight() - addition));
	}
}

//----------------------------------------

bool TDockWidget::isDragGrip(QPoint p)
{
	if (!m_titlebar)
		return DockWidget::isDragGrip(p);

	return m_titlebar->geometry().contains(p);
}

//----------------------------------------

int TDockWidget::isResizeGrip(QPoint p)
{
	if (m_dragging || (!m_titlebar && m_floating))
		return 0;

	int marginType = 0;
	QRect geom(QPoint(0, 0), QPoint(width(), height()));
	int margin = layout()->margin();
	QRect contGeom(geom.adjusted(margin, margin, -margin, -margin));

	if (geom.contains(p) && !contGeom.contains(p)) {
		if (p.x() < 15)
			marginType |= leftMargin;
		if (p.y() < 15)
			marginType |= topMargin;
		if (p.x() > width() - 15)
			marginType |= rightMargin;
		if (p.y() > height() - 15)
			marginType |= bottomMargin;
	}

	return marginType;
}

//----------------------------------------

//!Currently working only for \b status = true. If you need to
//!dock a TDockWidget, you \b must specify a dock location by either
//!choosing a placeholder or identifying the Region and insertion index,
//!and then running 'parentLayout()->dockItem(..)'.
void TDockWidget::setFloating(bool status)
{
	if (status) {
		setWindowFlags(Qt::Tool | Qt::FramelessWindowHint);
		if (!m_floating)
			parentLayout()->undockItem(this);
	}
}

//----------------------------------------

//!Specifies the orientation of the dock widget. It can
//!be either \b vertical (default) or \b horizontal, meaning that
//!the titlebar is laid respectively at the top or left side of
//!content widget. Directly speaking, it is equivalent to setting the
//!Qt's QDockWidget::DockWidgetVerticalTitleBar feature.
void TDockWidget::setOrientation(bool direction)
{
	QBoxLayout *boxLayout = static_cast<QBoxLayout *>(layout());
	QBoxLayout::Direction boxDirection;

	if (direction == vertical) {
		boxLayout->setAlignment(m_titlebar, Qt::AlignTop);
		boxDirection = QBoxLayout::TopToBottom;
	} else {
		boxLayout->setAlignment(m_titlebar, Qt::AlignLeft);
		boxDirection = QBoxLayout::LeftToRight;
	}

	boxLayout->setDirection(boxDirection);
}

//----------------------------------------

bool TDockWidget::getOrientation() const
{
	QBoxLayout *boxLayout = static_cast<QBoxLayout *>(layout());

	return (boxLayout->direction() == QBoxLayout::TopToBottom) ? vertical : horizontal;
}

//----------------------------------------

//!Maximizes \b this TDockWidget, if docked.
void TDockWidget::setMaximized(bool status)
{
	parentLayout()->setMaximized(this, status);
}

//----------------------------------------

QSize TDockWidget::getDockedMinimumSize()
{
	int addedSize = 2 * m_margin;
	return m_floating ? minimumSize() -= QSize(addedSize, addedSize) : minimumSize();
}

//----------------------------------------

QSize TDockWidget::getDockedMaximumSize()
{
	int addedSize = 2 * m_margin;
	return m_floating ? maximumSize() -= QSize(addedSize, addedSize) : maximumSize();
}

//========================================================================

//--------------------------
//    Custom Decorations
//--------------------------

class TDockSeparator : public DockSeparator
{
public:
	TDockSeparator(DockLayout *owner, bool orientation, Region *parentRegion)
		: DockSeparator(owner, orientation, parentRegion) {}

	void paintEvent(QPaintEvent *pe);
};

//----------------------------------------

class TDockPlaceholder : public DockPlaceholder
{
	QWidget *m_associated[3];

public:
	TDockPlaceholder(DockWidget *owner, Region *r, int idx, int attributes);
	~TDockPlaceholder();

	void buildGeometry();

	void showEvent(QShowEvent *se);
	void hideEvent(QHideEvent *he);
};

//----------------------------------------

TDockPlaceholder::TDockPlaceholder(DockWidget *owner, Region *r, int idx, int attributes)
	: DockPlaceholder(owner, r, idx, attributes)
{
	setAutoFillBackground(true);

	setObjectName("TDockPlaceholder");

	setWindowOpacity(0.8);
}

//----------------------------------------

TDockPlaceholder::~TDockPlaceholder()
{
	if (isRoot()) {
		delete m_associated[0];
		delete m_associated[1];
		delete m_associated[2];
	}
}

//----------------------------------------

inline void TDockPlaceholder::buildGeometry()
{
	DockPlaceholder::buildGeometry();

	if (isRoot()) {
		//Solution 2: Set associated widgets
		QRect geom(geometry());
		QSize horSize(geom.width(), 6);
		QSize vertSize(6, geom.height() + 12);

		setGeometry(QRect(geom.topLeft() - QPoint(6, 6), vertSize));

		m_associated[0] = new TDockPlaceholder(0, 0, 0, 0);
		m_associated[0]->setGeometry(QRect(geom.topLeft() - QPoint(0, 6), horSize));

		m_associated[1] = new TDockPlaceholder(0, 0, 0, 0);
		m_associated[1]->setGeometry(QRect(geom.topRight() + QPoint(1, -6), vertSize));

		m_associated[2] = new TDockPlaceholder(0, 0, 0, 0);
		m_associated[2]->setGeometry(QRect(geom.bottomLeft() + QPoint(0, 1), horSize));
	}
}

//-------------------------------------

void TDockPlaceholder::showEvent(QShowEvent *se)
{
	if (isRoot()) {
		//Show associated widgets
		m_associated[0]->show();
		m_associated[1]->show();
		m_associated[2]->show();
	}
}

//-------------------------------------

void TDockPlaceholder::hideEvent(QHideEvent *he)
{
	if (isRoot()) {
		//Show associated widgets
		m_associated[0]->hide();
		m_associated[1]->hide();
		m_associated[2]->hide();
	}
}

//-------------------------------------

void TDockSeparator::paintEvent(QPaintEvent *pe)
{
	QPainter p(this);
	QStyleOption opt(0);
	opt.state = (getOrientation() == Region::horizontal) ? QStyle::State_None : QStyle::State_Horizontal;

	/*if (w->isEnabled())
      opt.state |= QStyle::State_Enabled;
  if (o != Qt::Horizontal)
      opt.state |= QStyle::State_Horizontal;
  if (mouse_over)
      opt.state |= QStyle::State_MouseOver;*/

	opt.rect = QRect(QPoint(0, 0), QSize(geometry().size()));
	opt.palette = palette();

	style()->drawPrimitive(QStyle::PE_IndicatorDockWidgetResizeHandle, &opt, &p, this);

	p.end();
}

//-------------------------------------

DockSeparator *TDockDecoAllocator::newSeparator(DockLayout *owner, bool orientation, Region *parentRegion)
{
	return new TDockSeparator(owner, orientation, parentRegion);
}

//-------------------------------------

DockPlaceholder *TDockDecoAllocator::newPlaceholder(DockWidget *owner, Region *r, int idx, int attributes)
{
	return new TDockPlaceholder(owner, r, idx, attributes);
}

//-------------------------------------

void TDockWidget::selectDockPlaceholder(QMouseEvent *me)
{
	if (m_placeholders.size() && m_placeholders[0]->isRoot()) {
		DockPlaceholder *selected = 0;

		QPoint pos = parentWidget()->mapFromGlobal(me->globalPos());
		if (parentLayout()->contentsRect().contains(pos))
			selected = m_placeholders[0];

		if (m_selectedPlace != selected) {
			if (m_selectedPlace)
				m_selectedPlace->hide();
			if (selected)
				selected->show();
		}

		m_selectedPlace = selected;
	} else
		DockWidget::selectDockPlaceholder(me);
}