WingHexExplorer2/3rdparty/qcodeedit2/lib/qpanellayout.cpp

360 lines
9.5 KiB
C++

/****************************************************************************
**
** 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 "qeditor.h"
#include "qpanel.h"
/*!
\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 = QPanelLayout::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.length() - 2, QStringLiteral(",") + panel->id());
}
}
auto values = posMap.values();
return 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;
auto pos = layout.mid(last, i - last);
position = Position(pos.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())) {
PanelWrapper *layoutStruct = m_list.takeAt(idx);
Q_ASSERT(layoutStruct);
if (!layoutStruct)
return 0;
QLayoutItem *li = layoutStruct->item;
delete layoutStruct;
return li;
}
return 0;
}
/*!
\internal
*/
void QPanelLayout::setGeometry(const QRect &r) {
// qDebug("laying out %i panels", count());
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));
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(), rect.y() + northHeight,
rect.width(), item->sizeHint().height()));
northHeight += item->geometry().height() + spacing();
} else if (position == South) {
int ht = item->sizeHint().height();
if (item->hasHeightForWidth()) {
ht = item->heightForWidth(rect.width());
}
item->setGeometry(QRect(item->geometry().x(), item->geometry().y(),
rect.width(), ht));
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,
rect.y() + 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(),
rect.y() + northHeight, item->geometry().width(),
item->geometry().height()));
}
}
m_parent->setPanelMargins(westWidth, rect.y() + 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;
}