You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
435 lines
8.8 KiB
435 lines
8.8 KiB
/**************************************************************************** |
|
** |
|
** Copyright (C) 2006-2009 fullmetalcoder <fullmetalcoder@hotmail.fr> |
|
** |
|
** This file is part of the Edyuk project <http://edyuk.org> |
|
** |
|
** This file may be used under the terms of the GNU General Public License |
|
** version 3 as published by the Free Software Foundation and appearing in the |
|
** file GPL.txt included in the packaging of this file. |
|
** |
|
** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE |
|
** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. |
|
** |
|
****************************************************************************/ |
|
|
|
#include "qpanellayout.h" |
|
|
|
/*! |
|
\file qpanellayout.cpp |
|
\brief Implementation of the QPanelLayout class. |
|
*/ |
|
|
|
#include "qpanel.h" |
|
#include "qeditor.h" |
|
|
|
#include <QWidget> |
|
#include <QScrollBar> |
|
|
|
#ifdef Q_WS_WIN |
|
// panel position fix required on some systems to work around a bug in QAbstractScrollArea |
|
#define _PANEL_POSITION_FIX_ |
|
#endif |
|
|
|
/*! |
|
\class QPanelLayout |
|
\brief A specialized layout taking care of panel display |
|
|
|
The panel layout is specialized in several ways : |
|
<ul> |
|
<li>It only operates on specific widgets (which inherit QPanel)</li> |
|
<li>It can only layout widgets in the viewport margins of a QEditor (could work with |
|
any QAbstractScrollArea if a single method was made public instead of protected...) |
|
so it does not qualify as a "real" layout (contrary to grid/box layouts)</li> |
|
<li>It positions widgets on the border of the editor in the same way the Border Layout |
|
example does (most of the layout code actually comes from there).</li> |
|
<li>It provides serialization/deserialization of its layout structure</li> |
|
</ul> |
|
*/ |
|
|
|
/* |
|
The layouting code is inspired from a Qt4 example : Border Layout |
|
*/ |
|
|
|
/*! |
|
\brief ctor |
|
*/ |
|
QPanelLayout::QPanelLayout(QEditor *p) |
|
: QLayout(p), m_parent(p) |
|
{ |
|
setSpacing(0); |
|
} |
|
|
|
/*! |
|
\brief ctor |
|
\param layout structure to deserailize |
|
*/ |
|
QPanelLayout::QPanelLayout(const QString& layout, QEditor *p) |
|
: QLayout(p), m_parent(p) |
|
{ |
|
setSpacing(0); |
|
addSerialized(layout); |
|
} |
|
|
|
/*! |
|
\brief dtor |
|
*/ |
|
QPanelLayout::~QPanelLayout() |
|
{ |
|
QLayoutItem *l; |
|
|
|
while ( (l = takeAt(0)) ) |
|
delete l; |
|
} |
|
|
|
/*! |
|
\return A serialized layout strucure |
|
*/ |
|
QString QPanelLayout::serialized() const |
|
{ |
|
/* |
|
Scheme : |
|
|
|
QPanelLayout::Position '{' comma-separated list of identifiers '}' |
|
*/ |
|
|
|
QHash<int, QString> posMap; |
|
|
|
for ( int i = 0; i < m_list.size(); ++i ) |
|
{ |
|
PanelWrapper *wrapper = m_list.at(i); |
|
Position position = wrapper->position; |
|
|
|
QPanel *panel = qobject_cast<QPanel*>(wrapper->item->widget()); |
|
|
|
if ( !panel ) |
|
continue; |
|
|
|
if ( !posMap.contains(position) ) |
|
{ |
|
posMap[position] = QString::number(position) + "{" + panel->id() + "}"; |
|
} else { |
|
QString& ref = posMap[position]; |
|
|
|
ref.insert(ref.count() - 2, QString(",") + panel->id()); |
|
} |
|
} |
|
|
|
return QStringList(posMap.values()).join(""); |
|
} |
|
|
|
/*! |
|
\brief Add the content of a serialized layout structure |
|
*/ |
|
void QPanelLayout::addSerialized(const QString& layout) |
|
{ |
|
//qDebug("layout : %s", qPrintable(layout)); |
|
|
|
int last = 0, i = 0; |
|
bool inList = false; |
|
Position position = West; |
|
|
|
while ( i < layout.length() ) |
|
{ |
|
if ( inList ) |
|
{ |
|
if ( layout.at(i) == '}' ) |
|
inList = false; |
|
|
|
if ( !inList || (layout.at(i) == ',') ) |
|
{ |
|
QPanel *panel = QPanel::panel(layout.mid(last, i - last), m_parent); |
|
|
|
if ( panel ) |
|
{ |
|
panel->attach(m_parent); |
|
addWidget(panel, position); |
|
|
|
//qDebug("\tpanel : %s", qPrintable(layout.mid(last, i - last))); |
|
} |
|
|
|
last = i + 1; |
|
} |
|
} else if ( layout.at(i) == '{' ) { |
|
inList = true; |
|
position = Position(layout.mid(last, i - last).toInt()); |
|
|
|
//qDebug("position : %i [%s]", position, qPrintable(layout.mid(last, i - last))); |
|
|
|
last = i + 1; |
|
} |
|
|
|
++i; |
|
} |
|
|
|
update(); |
|
} |
|
|
|
/*! |
|
\return the list of panels managed by the layout |
|
*/ |
|
QList<QPanel*> QPanelLayout::panels() const |
|
{ |
|
QList<QPanel*> l; |
|
|
|
foreach ( PanelWrapper *w, m_list ) |
|
{ |
|
QPanel *p = qobject_cast<QPanel*>(w->item->widget()); |
|
|
|
if ( p ) |
|
l << p; |
|
} |
|
|
|
return l; |
|
} |
|
|
|
/*! |
|
\return the count of managed panels |
|
*/ |
|
int QPanelLayout::count() const |
|
{ |
|
return m_list.count(); |
|
} |
|
|
|
/*! |
|
\internal |
|
*/ |
|
bool QPanelLayout::hasHeightForWidth() const |
|
{ |
|
return false; |
|
} |
|
|
|
/*! |
|
\internal |
|
*/ |
|
Qt::Orientations QPanelLayout::expandingDirections() const |
|
{ |
|
return Qt::Horizontal | Qt::Vertical; |
|
} |
|
|
|
/*! |
|
\internal |
|
*/ |
|
QSize QPanelLayout::sizeHint() const |
|
{ |
|
return calculateSize(SizeHint); |
|
} |
|
|
|
/*! |
|
\internal |
|
*/ |
|
QSize QPanelLayout::minimumSize() const |
|
{ |
|
return calculateSize(MinimumSize); |
|
} |
|
|
|
/*! |
|
\internal |
|
*/ |
|
void QPanelLayout::addItem(QLayoutItem *item) |
|
{ |
|
add(item, West); |
|
} |
|
|
|
/*! |
|
\brief Add a panel at a given position |
|
*/ |
|
void QPanelLayout::addWidget(QWidget *widget, Position position) |
|
{ |
|
add(new QWidgetItem(widget), position); |
|
} |
|
|
|
/*! |
|
\internal |
|
*/ |
|
QLayoutItem* QPanelLayout::itemAt(int idx) const |
|
{ |
|
PanelWrapper *wrapper = m_list.value(idx); |
|
|
|
if ( wrapper ) |
|
return wrapper->item; |
|
else |
|
return 0; |
|
|
|
} |
|
|
|
/*! |
|
\internal |
|
*/ |
|
QLayoutItem* QPanelLayout::takeAt(int idx) |
|
{ |
|
if ( (idx >= 0) && (idx < m_list.size()) ) |
|
{ |
|
QScopedPointer<PanelWrapper> layoutStruct(m_list.takeAt(idx)); |
|
return layoutStruct->item; |
|
} |
|
|
|
return 0; |
|
} |
|
|
|
/*! |
|
\internal |
|
*/ |
|
void QPanelLayout::setGeometry(const QRect &r) |
|
{ |
|
//qDebug("laying out %i panels", count()); |
|
#ifdef _PANEL_POSITION_FIX_ |
|
QScrollBar *vb = m_parent->verticalScrollBar(), |
|
*hb = m_parent->horizontalScrollBar(); |
|
|
|
QRect rect( r.x(), r.y(), |
|
r.width() - (vb->isVisibleTo(m_parent) ? vb->width() : 0), |
|
r.height() - (hb->isVisibleTo(m_parent) ? hb->height() : 0) |
|
); |
|
#else |
|
QRect rect( r.x(), r.y(), |
|
r.width(), |
|
r.height() |
|
); |
|
#endif |
|
|
|
int i, |
|
eastWidth = 0, |
|
westWidth = 0, |
|
northHeight = 0, |
|
southHeight = 0, |
|
centerHeight = 0; |
|
|
|
QLayout::setGeometry(rect); |
|
|
|
for ( i = 0; i < m_list.size(); ++i ) |
|
{ |
|
PanelWrapper *wrapper = m_list.at(i); |
|
QLayoutItem *item = wrapper->item; |
|
Position position = wrapper->position; |
|
|
|
if ( item->isEmpty() ) |
|
continue; |
|
|
|
if ( position == North ) |
|
{ |
|
item->setGeometry(QRect( |
|
rect.x(), |
|
northHeight, |
|
rect.width(), |
|
item->sizeHint().height() |
|
) |
|
); |
|
|
|
northHeight += item->geometry().height() + spacing(); |
|
} else if (position == South) { |
|
item->setGeometry(QRect(item->geometry().x(), |
|
item->geometry().y(), |
|
rect.width(), |
|
item->sizeHint().height() |
|
) |
|
); |
|
|
|
southHeight += item->geometry().height() + spacing(); |
|
|
|
item->setGeometry(QRect(rect.x(), |
|
rect.y() + rect.height() - southHeight + spacing(), |
|
item->geometry().width(), |
|
item->geometry().height() |
|
) |
|
); |
|
|
|
} |
|
} |
|
|
|
centerHeight = rect.height() - northHeight - southHeight; |
|
|
|
for ( i = 0; i < m_list.size(); ++i ) |
|
{ |
|
PanelWrapper *wrapper = m_list.at(i); |
|
QLayoutItem *item = wrapper->item; |
|
Position position = wrapper->position; |
|
|
|
if ( item->isEmpty() ) |
|
continue; |
|
|
|
if ( position == West ) |
|
{ |
|
item->setGeometry(QRect(rect.x() + westWidth, |
|
northHeight, |
|
item->sizeHint().width(), |
|
centerHeight |
|
) |
|
); |
|
|
|
westWidth += item->geometry().width() + spacing(); |
|
} else if (position == East) { |
|
item->setGeometry(QRect(item->geometry().x(), |
|
item->geometry().y(), |
|
item->sizeHint().width(), |
|
centerHeight |
|
) |
|
); |
|
|
|
eastWidth += item->geometry().width() + spacing(); |
|
|
|
item->setGeometry(QRect(rect.x() + rect.width() - eastWidth + spacing(), |
|
northHeight, |
|
item->geometry().width(), |
|
item->geometry().height() |
|
) |
|
); |
|
|
|
} |
|
} |
|
|
|
/* |
|
if ( center ) |
|
center->item->setGeometry(QRect(westWidth, northHeight, |
|
rect.width() - eastWidth - westWidth, |
|
centerHeight)); |
|
*/ |
|
//qDebug("{%i, %i, %i, %i}", westWidth, northHeight, eastWidth, southHeight); |
|
m_parent->setPanelMargins(westWidth, northHeight, eastWidth, southHeight); |
|
} |
|
|
|
/*! |
|
\internal |
|
*/ |
|
void QPanelLayout::add(QLayoutItem *item, Position position) |
|
{ |
|
QPanel *p; |
|
|
|
if ( (p = qobject_cast<QPanel*>(item->widget())) ) |
|
{ |
|
//p->setParent(m_parent); |
|
p->setVisible(p->defaultVisibility()); |
|
} |
|
|
|
m_list.append(new PanelWrapper(item, position)); |
|
} |
|
|
|
/*! |
|
\internal |
|
*/ |
|
QSize QPanelLayout::calculateSize(SizeType sizeType) const |
|
{ |
|
QSize totalSize; |
|
|
|
for ( int i = 0; i < m_list.size(); ++i ) |
|
{ |
|
QSize itemSize; |
|
PanelWrapper *wrapper = m_list.at(i); |
|
Position position = wrapper->position; |
|
|
|
if ( sizeType == MinimumSize ) |
|
itemSize = wrapper->item->minimumSize(); |
|
else // ( sizeType == SizeHint ) |
|
itemSize = wrapper->item->sizeHint(); |
|
|
|
if ( (position == North) || (position == South) ) // || (position == Center) ) |
|
totalSize.rheight() += itemSize.height(); |
|
|
|
if ( (position == West) || (position == East) ) // || (position == Center) ) |
|
totalSize.rwidth() += itemSize.width(); |
|
|
|
} |
|
|
|
return totalSize; |
|
} |
|
|
|
|