Init commit for GitHub.

This commit is contained in:
mfreiholz 2015-12-09 12:21:38 +01:00
commit 343c5cc727
40 changed files with 1961 additions and 0 deletions

1
.gitignore vendored Normal file
View File

@ -0,0 +1 @@
*.pro.user

View File

@ -0,0 +1,33 @@
TARGET = AdvancedDockingSystem
QT += core gui
greaterThan(QT_MAJOR_VERSION, 4): QT += widgets
TEMPLATE = lib
CONFIG += staticlib
INCLUDEPATH += $$PWD/src
SOURCES += \
src/ads/section_content.cpp \
src/ads/ads.cpp \
src/ads/section_widget.cpp \
src/ads/section_title_widget.cpp \
src/ads/container_widget.cpp \
src/ads/drop_overlay.cpp \
src/ads/floating_widget.cpp \
src/ads/section_content_widget.cpp
HEADERS += \
src/ads/ads.h \
src/ads/container_widget.h \
src/ads/section_widget.h \
src/ads/section_content.h \
src/ads/section_title_widget.h \
src/ads/section_content_widget.h \
src/ads/drop_overlay.h \
src/ads/floating_widget.h
RESOURCES += \
res/ads.qrc

View File

@ -0,0 +1,18 @@
# Advanced Docking System
Developed by Manuel Freiholz
## Notes
- SectionContent may safe a "size-type" property, which defines how the size of the widget
should be handled.
- PerCent: Resize in proportion to other widgets.
- Fixed: Width or height are fixed (based on orientation).
## TODO / Issues
[ ] Drop indicator images should be fully visible over the DropOverlay rectangle.
[ ] Clean up of unused e.g. count()<=1 QSplitters doesn't work well.
## License notes
- Copied drop images from http://www.codeproject.com/Articles/140209/Building-a-Docking-Window-Management-Solution-in-W

View File

@ -0,0 +1,16 @@
<RCC>
<qresource prefix="/">
<file>img/dnd-thumbnail.png</file>
<file>img/dock-bottom.png</file>
<file>img/dock-center.png</file>
<file>img/dock-left.png</file>
<file>img/dock-right.png</file>
<file>img/dock-top.png</file>
<file>img/split-bottom.png</file>
<file>img/split-left.png</file>
<file>img/split-right.png</file>
<file>img/split-top.png</file>
<file>img/splitter-horizontal.png</file>
<file>img/splitter-vertical.png</file>
</qresource>
</RCC>

Binary file not shown.

After

Width:  |  Height:  |  Size: 249 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 489 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 402 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 527 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 516 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 498 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 628 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 638 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 647 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 619 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 326 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 406 B

View File

@ -0,0 +1,60 @@
#include "ads.h"
#include <QWidget>
#include <QSplitter>
#include "container_widget.h"
const QString DragData::MIMETYPE = QString("qt/ads-dragdata");
ADS_NAMESPACE_BEGIN
ContainerWidget* findParentContainerWidget(QWidget* w)
{
ContainerWidget* cw = 0;
QWidget* next = w;
do
{
if ((cw = dynamic_cast<ContainerWidget*>(next)) != 0)
{
break;
}
next = next->parentWidget();
}
while (next);
return cw;
}
SectionWidget* findParentSectionWidget(class QWidget* w)
{
SectionWidget* cw = 0;
QWidget* next = w;
do
{
if ((cw = dynamic_cast<SectionWidget*>(next)) != 0)
{
break;
}
next = next->parentWidget();
}
while (next);
return cw;
}
QSplitter* findParentSplitter(class QWidget* w)
{
QSplitter* cw = 0;
QWidget* next = w;
do
{
if ((cw = dynamic_cast<QSplitter*>(next)) != 0)
{
break;
}
next = next->parentWidget();
}
while (next);
return cw;
}
ADS_NAMESPACE_END

View File

@ -0,0 +1,85 @@
#ifndef ADS_H
#define ADS_H
#include <QByteArray>
#include <QDataStream>
#include <QIODevice>
#include <QSharedPointer>
class QSplitter;
/*
* ADS - Advanced Docking System for Qt
* Developed by Manuel Freiholz
*/
#define ADS_NAMESPACE_BEGIN namespace ads {
#define ADS_NAMESPACE_END }
// Width of the native window frame border (based on OS).
#define ADS_WINDOW_FRAME_BORDER_WIDTH 7
// Indicates whether ADS should include animations.
//#define ADS_ANIMATIONS_ENABLED 1
//#define ADS_ANIMATION_DURATION 150
// DragData contains information about dragged contents (SectionContent).
// e.g. from where is has been dragged.
class DragData
{
public:
static const QString MIMETYPE;
QByteArray serialize() const
{
QByteArray ba;
QDataStream out(&ba, QIODevice::WriteOnly);
out << contentUid;
out << sectionUid;
return ba;
}
void deserialize(const QByteArray& bytes)
{
QDataStream in(bytes);
in >> contentUid;
in >> sectionUid;
}
QString toString() const
{
return QString("content-uid=%1; section-uid=%2").arg(contentUid).arg(sectionUid);
}
public:
int contentUid;
int sectionUid;
};
ADS_NAMESPACE_BEGIN
enum DropArea
{
TopDropArea,
RightDropArea,
BottomDropArea,
LeftDropArea,
CenterDropArea,
InvalidDropArea
};
class InternalContentData
{
public:
InternalContentData() : titleWidget(0), contentWidget(0) {}
QSharedPointer<class SectionContent> content;
class SectionTitleWidget* titleWidget;
class SectionContentWidget* contentWidget;
};
class ContainerWidget* findParentContainerWidget(class QWidget* w);
class SectionWidget* findParentSectionWidget(class QWidget* w);
QSplitter* findParentSplitter(class QWidget* w);
ADS_NAMESPACE_END
#endif // ADC_H

View File

@ -0,0 +1,272 @@
#include "container_widget.h"
#include <QPaintEvent>
#include <QPainter>
#include <QContextMenuEvent>
#include <QMenu>
#include <QSplitter>
ADS_NAMESPACE_BEGIN
// Static Helper //////////////////////////////////////////////////////
static QSplitter* newSplitter(Qt::Orientation orientation = Qt::Horizontal)
{
QSplitter* s = new QSplitter();
s->setChildrenCollapsible(false);
s->setOpaqueResize(false);
s->setOrientation(orientation);
return s;
}
//static void deleteEmptySplitter(ContainerWidget* container)
//{
// auto splitters = container->findChildren<QSplitter*>();
// for (auto i = 0; i < splitters.count(); ++i)
// {
// if (splitters[i]->count() == 0 && container->_splitter != splitters[i])
// {
// qDebug() << "Delete empty QSplitter";
// splitters[i]->deleteLater();
// }
// }
//}
///////////////////////////////////////////////////////////////////////
ContainerWidget::ContainerWidget(QWidget *parent) :
QFrame(parent),
_mainLayout(NULL),
_orientation(Qt::Horizontal),
_splitter(NULL)
{
_mainLayout = new QGridLayout();
_mainLayout->setContentsMargins(9, 9, 9, 9);
_mainLayout->setSpacing(9);
setLayout(_mainLayout);
}
Qt::Orientation ContainerWidget::orientation() const
{
return _orientation;
}
void ContainerWidget::setOrientation(Qt::Orientation orientation)
{
if (_orientation != orientation)
{
_orientation = orientation;
emit orientationChanged();
}
}
void ContainerWidget::dropContent(const InternalContentData& data, SectionWidget* targetSection, DropArea area)
{
if (!targetSection)
{
qWarning() << "Drop on invalid targetSection";
return;
}
auto targetSectionSplitter = findParentSplitter(targetSection);
// Drop logic based on area.
switch (area)
{
case TopDropArea:
{
auto sw = new SectionWidget(this);
sw->addContent(data, true);
if (targetSectionSplitter->orientation() == Qt::Vertical)
{
auto index = targetSectionSplitter->indexOf(targetSection);
targetSectionSplitter->insertWidget(index, sw);
}
else
{
auto index = targetSectionSplitter->indexOf(targetSection);
auto s = newSplitter(Qt::Vertical);
s->addWidget(sw);
s->addWidget(targetSection);
targetSectionSplitter->insertWidget(index, s);
}
break;
}
case RightDropArea:
{
auto sw = new SectionWidget(this);
sw->addContent(data, true);
if (targetSectionSplitter->orientation() == Qt::Horizontal)
{
auto index = targetSectionSplitter->indexOf(targetSection);
targetSectionSplitter->insertWidget(index + 1, sw);
}
else
{
auto index = targetSectionSplitter->indexOf(targetSection);
auto s = newSplitter(Qt::Horizontal);
s->addWidget(targetSection);
s->addWidget(sw);
targetSectionSplitter->insertWidget(index, s);
}
break;
}
case BottomDropArea:
{
auto sw = new SectionWidget(this);
sw->addContent(data, true);
if (targetSectionSplitter->orientation() == Qt::Vertical)
{
auto index = targetSectionSplitter->indexOf(targetSection);
targetSectionSplitter->insertWidget(index + 1, sw);
}
else
{
auto index = targetSectionSplitter->indexOf(targetSection);
auto s = newSplitter(Qt::Vertical);
s->addWidget(targetSection);
s->addWidget(sw);
targetSectionSplitter->insertWidget(index, s);
}
break;
}
case LeftDropArea:
{
auto sw = new SectionWidget(this);
sw->addContent(data, true);
if (targetSectionSplitter->orientation() == Qt::Horizontal)
{
auto index = targetSectionSplitter->indexOf(targetSection);
targetSectionSplitter->insertWidget(index, sw);
}
else
{
auto s = newSplitter(Qt::Horizontal);
s->addWidget(sw);
auto index = targetSectionSplitter->indexOf(targetSection);
targetSectionSplitter->insertWidget(index, s);
s->addWidget(targetSection);
}
break;
}
case CenterDropArea:
{
targetSection->addContent(data, true);
break;
}
}
}
void ContainerWidget::addSection(SectionWidget* section)
{
// Create default splitter.
if (!_splitter)
{
_splitter = new QSplitter(_orientation);
_splitter->setChildrenCollapsible(false);
_splitter->setOpaqueResize(false);
_mainLayout->addWidget(_splitter, 0, 0);
}
if (_splitter->indexOf(section) != -1)
{
qWarning() << Q_FUNC_INFO << QString("Section has already been added");
return;
}
_splitter->addWidget(section);
}
void ContainerWidget::splitSections(SectionWidget* s1, SectionWidget* s2, Qt::Orientation orientation)
{
addSection(s1);
addSection(s2);
//_sections.append(s2);
auto currentSplitter = findParentSplitter(s1);
if (currentSplitter)
{
const int index = currentSplitter->indexOf(s1);
auto splitter = new QSplitter(orientation, this);
splitter->setChildrenCollapsible(false);
splitter->setOpaqueResize(false);
splitter->addWidget(s1);
splitter->addWidget(s2);
currentSplitter->insertWidget(index, splitter);
}
// _mainLayout->replaceWidget(section1, splitter);
// splitter->addWidget(section1);
// splitter->addWidget(section2);
}
SectionWidget* ContainerWidget::sectionAt(const QPoint& pos) const
{
auto gpos = mapToGlobal(pos);
for (int i = 0; i < _sections.size(); ++i)
{
auto sw = _sections[i];
if (sw->rect().contains(sw->mapFromGlobal(gpos)))
{
return sw;
}
}
return 0;
}
QRect ContainerWidget::outerTopDropRect() const
{
auto r = rect();
auto h = r.height() / 100 * 5;
return QRect(r.left(), r.top(), r.width(), h);
}
QRect ContainerWidget::outerRightDropRect() const
{
auto r = rect();
auto w = r.width() / 100 * 5;
return QRect(r.right() - w, r.top(), w, r.height());
}
QRect ContainerWidget::outerBottomDropRect() const
{
auto r = rect();
auto h = r.height() / 100 * 5;
return QRect(r.left(), r.bottom() - h, r.width(), h);
}
QRect ContainerWidget::outerLeftDropRect() const
{
auto r = rect();
auto w = r.width() / 100 * 5;
return QRect(r.left(), r.top(), w, r.height());
}
void ContainerWidget::paintEvent(QPaintEvent* e)
{
QFrame::paintEvent(e);
// QPainter p(this);
// p.fillRect(outerTopDropRect(), QBrush(QColor(Qt::red)));
// p.fillRect(outerRightDropRect(), QBrush(QColor(Qt::green)));
// p.fillRect(outerBottomDropRect(), QBrush(QColor(Qt::blue)));
// p.fillRect(outerLeftDropRect(), QBrush(QColor(Qt::yellow)));
}
void ContainerWidget::contextMenuEvent(QContextMenuEvent*)
{
qDebug() << Q_FUNC_INFO;
// if (_contents.size() <= 0)
// {
// QFrame::contextMenuEvent(e);
// return;
// }
// // Menu with all available contents.
// QMenu m;
// for (int i = 0; i < _contents.size(); ++i)
// {
// auto c = _contents[i];
// m.addAction(QIcon(), QString("Content %1").arg(c->uid()));
// }
// m.exec();
}
ADS_NAMESPACE_END

View File

@ -0,0 +1,69 @@
#ifndef ADS_CONTAINERWIDGET_H
#define ADS_CONTAINERWIDGET_H
#include <QFrame>
#include <QGridLayout>
#include <QPoint>
#include <QList>
class QSplitter;
#include "ads.h"
#include "section_content.h"
#include "section_widget.h"
#include "floating_widget.h"
ADS_NAMESPACE_BEGIN
// ContainerWidget is the main container to provide the docking
// functionality. It manages mulitple Sections and all possible areas.
class ContainerWidget : public QFrame
{
Q_OBJECT
Q_PROPERTY(Qt::Orientation orientation READ orientation WRITE setOrientation NOTIFY orientationChanged)
friend class SectionWidget;
public:
explicit ContainerWidget(QWidget *parent = NULL);
Qt::Orientation orientation() const;
void setOrientation(Qt::Orientation orientation);
void dropContent(const InternalContentData& data, SectionWidget* targetSection, DropArea area);
void addSection(SectionWidget* section);
void splitSections(SectionWidget* section1, SectionWidget* section2, Qt::Orientation orientation = Qt::Horizontal);
SectionWidget* sectionAt(const QPoint& pos) const;
// Drop areas for the ContainerWidget
QRect outerTopDropRect() const;
QRect outerRightDropRect() const;
QRect outerBottomDropRect() const;
QRect outerLeftDropRect() const;
protected:
virtual void paintEvent(QPaintEvent*);
virtual void contextMenuEvent(QContextMenuEvent*);
private: // Make private!
signals:
void orientationChanged();
public:
// Existing sections.
// SectionWidgets are always visible.
QList<SectionWidget*> _sections;
// All currently active Floatingwidgets.
QList<FloatingWidget*> _floatingWidgets;
// Layout stuff
QGridLayout* _mainLayout;
Qt::Orientation _orientation; ///< Default orientation of new sections.
QSplitter* _splitter; ///< Default/main splitter.
};
ADS_NAMESPACE_END
#endif

View File

@ -0,0 +1,203 @@
#include "drop_overlay.h"
#include <QDebug>
#include <QPointer>
#include <QPaintEvent>
#include <QResizeEvent>
#include <QMoveEvent>
#include <QPainter>
#include <QGridLayout>
#include <QCursor>
#include <QtGui/QIcon>
#include <QtWidgets/QLabel>
ADS_NAMESPACE_BEGIN
// Helper /////////////////////////////////////////////////////////////
static QWidget* createDropWidget(const QString& img)
{
auto label = new QLabel();
label->setObjectName("DropAreaLabel");
label->setPixmap(QPixmap(img));
return label;
}
///////////////////////////////////////////////////////////////////////
DropOverlay::DropOverlay(QWidget *parent) :
QFrame(parent),
_splitAreas(NULL)
{
setAttribute(Qt::WA_TransparentForMouseEvents);
setWindowFlags(windowFlags() | Qt::Tool);
setWindowFlags(windowFlags() | Qt::FramelessWindowHint);
setWindowOpacity(0.2);
auto l = new QBoxLayout(QBoxLayout::TopToBottom);
l->setContentsMargins(0, 0, 0, 0);
l->setSpacing(0);
setLayout(l);
_splitAreas = new DropSplitAreas(parent);
_splitAreas->move(pos());
_splitAreas->resize(size());
_splitAreas->setVisible(true);
}
DropOverlay::~DropOverlay()
{
if (_splitAreas)
{
delete _splitAreas;
_splitAreas = NULL;
}
}
DropArea DropOverlay::cursorLocation() const
{
auto loc = InvalidDropArea;
if (_splitAreas)
{
loc = _splitAreas->cursorLocation();
}
return loc;
}
void DropOverlay::paintEvent(QPaintEvent*)
{
QPainter p(this);
// Draw rect over the entire size + border.
auto r = rect();
r.setWidth(r.width() - 1);
r.setHeight(r.height() - 1);
p.fillRect(r, QBrush(QColor(0, 100, 255), Qt::Dense4Pattern));
p.setBrush(QBrush(QColor(0, 100, 255)));
p.drawRect(r);
}
void DropOverlay::resizeEvent(QResizeEvent* e)
{
// Keep it in center of DropOverlay
if (_splitAreas)
{
_splitAreas->resize(e->size());
}
}
void DropOverlay::moveEvent(QMoveEvent* e)
{
// Keep it in center of DropOverlay
if (_splitAreas)
{
_splitAreas->move(e->pos());
}
}
///////////////////////////////////////////////////////////////////////
DropSplitAreas::DropSplitAreas(QWidget* parent) : AbstractDropAreas(parent)
{
//setAttribute(Qt::WA_TransparentForMouseEvents);
setAttribute(Qt::WA_TranslucentBackground);
setWindowFlags(windowFlags() | Qt::Tool);
setWindowFlags(windowFlags() | Qt::FramelessWindowHint);
_top = createDropWidget(":/img/split-top.png");
_right = createDropWidget(":/img/split-right.png");
_bottom = createDropWidget(":/img/split-bottom.png");
_left = createDropWidget(":/img/split-left.png");
_center = createDropWidget(":/img/dock-center.png");
QGridLayout* grid = new QGridLayout();
grid->setContentsMargins(0, 0, 0, 0);
grid->setSpacing(6);
grid->addWidget(_top, 0, 1, Qt::AlignHCenter | Qt::AlignBottom);
grid->addWidget(_right, 1, 2, Qt::AlignLeft | Qt::AlignVCenter);
grid->addWidget(_bottom, 2, 1, Qt::AlignHCenter | Qt::AlignTop);
grid->addWidget(_left, 1, 0, Qt::AlignRight | Qt::AlignVCenter);
grid->addWidget(_center, 1, 1, Qt::AlignCenter);
QBoxLayout* bl1 = new QBoxLayout(QBoxLayout::TopToBottom);
bl1->setContentsMargins(0, 0, 0, 0);
bl1->setSpacing(0);
setLayout(bl1);
QBoxLayout* bl2 = new QBoxLayout(QBoxLayout::LeftToRight);
bl2->setContentsMargins(0, 0, 0, 0);
bl2->setSpacing(0);
bl1->addStretch(1);
bl1->addLayout(bl2);
bl2->addStretch(1);
bl2->addLayout(grid, 0);
bl2->addStretch(1);
bl1->addStretch(1);
}
DropArea DropSplitAreas::cursorLocation() const
{
auto loc = InvalidDropArea;
auto pos = mapFromGlobal(QCursor::pos());
if (_top->geometry().contains(pos))
{
loc = TopDropArea;
}
else if (_right->geometry().contains(pos))
{
loc = RightDropArea;
}
else if (_bottom->geometry().contains(pos))
{
loc = BottomDropArea;
}
else if (_left->geometry().contains(pos))
{
loc = LeftDropArea;
}
else if (_center->geometry().contains(pos))
{
loc = CenterDropArea;
}
return loc;
}
// Globals ////////////////////////////////////////////////////////////
static QPointer<DropOverlay> MyOverlay;
static QPointer<QWidget> MyOverlayParent;
DropArea showDropOverlay(QWidget* parent)
{
if (MyOverlay)
{
if (MyOverlayParent == parent)
{
// Hint: We could update geometry of overlay here.
return MyOverlay->cursorLocation();
}
hideDropOverlay();
}
// Create new overlay and move it directly over the "parent" widget.
MyOverlay = new DropOverlay(parent);
MyOverlay->resize(parent->size());
MyOverlay->move(parent->mapToGlobal(parent->rect().topLeft()));
MyOverlay->show();
MyOverlayParent = parent;
return MyOverlay->cursorLocation();
}
void hideDropOverlay()
{
if (MyOverlay)
{
MyOverlay->hide();
delete MyOverlay;
MyOverlayParent.clear();
}
}
ADS_NAMESPACE_END

View File

@ -0,0 +1,61 @@
#ifndef DROP_OVERLAY_H
#define DROP_OVERLAY_H
#include <QFrame>
#include "ads.h"
ADS_NAMESPACE_BEGIN
// DropOverlay paints a translucent rectangle over another widget.
// It can also show different types of drop area indicators.
class DropOverlay : public QFrame
{
Q_OBJECT
public:
DropOverlay(QWidget* parent);
virtual ~DropOverlay();
DropArea cursorLocation() const;
protected:
virtual void paintEvent(QPaintEvent *e);
virtual void resizeEvent(QResizeEvent* e);
virtual void moveEvent(QMoveEvent* e);
private:
class DropSplitAreas* _splitAreas;
};
// AbstractDropAreas is used as base for drop area indicator widgets.
class AbstractDropAreas : public QWidget
{
public:
AbstractDropAreas(QWidget* parent) : QWidget(parent) {}
virtual DropArea cursorLocation() const = 0;
};
// DropSplitAreas shows a cross with 5 different drop area possibilities.
class DropSplitAreas : public AbstractDropAreas
{
Q_OBJECT
public:
DropSplitAreas(QWidget* parent);
virtual DropArea cursorLocation() const;
private:
QWidget* _top;
QWidget* _right;
QWidget* _bottom;
QWidget* _left;
QWidget* _center;
};
DropArea showDropOverlay(QWidget* parent);
void hideDropOverlay();
ADS_NAMESPACE_END
#endif

View File

@ -0,0 +1,72 @@
#include "floating_widget.h"
#include <QDebug>
#include <QBoxLayout>
#include <QPushButton>
#include <QSizePolicy>
#include <QMouseEvent>
#include <QStyle>
#include "section_title_widget.h"
#include "section_content_widget.h"
ADS_NAMESPACE_BEGIN
FloatingWidget::FloatingWidget(SectionContent::RefPtr sc, SectionTitleWidget* titleWidget, SectionContentWidget* contentWidget, QWidget* parent) :
QWidget(parent, Qt::CustomizeWindowHint | Qt::Tool),
_content(sc),
_titleWidget(titleWidget),
_contentWidget(contentWidget)
{
auto l = new QBoxLayout(QBoxLayout::TopToBottom);
l->setContentsMargins(0, 0, 0, 0);
l->setSpacing(0);
setLayout(l);
// Title + Controls
_titleLayout = new QBoxLayout(QBoxLayout::LeftToRight);
_titleLayout->addWidget(titleWidget, 1);
auto maximizeButton = new QPushButton();
maximizeButton->setObjectName("maximizeButton");
maximizeButton->setIcon(style()->standardIcon(QStyle::SP_TitleBarMaxButton));
maximizeButton->setToolTip(tr("Maximize"));
maximizeButton->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
_titleLayout->addWidget(maximizeButton);
auto closeButton = new QPushButton();
closeButton->setObjectName("closeButton");
closeButton->setIcon(style()->standardIcon(QStyle::SP_TitleBarCloseButton));
closeButton->setToolTip(tr("Close"));
closeButton->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
_titleLayout->addWidget(closeButton);
QObject::connect(closeButton, &QPushButton::clicked, this, &FloatingWidget::close);
l->addLayout(_titleLayout, 0);
// Content
l->addWidget(contentWidget, 1);
contentWidget->show();
}
InternalContentData FloatingWidget::takeContent()
{
InternalContentData data;
data.content = _content;
data.titleWidget = _titleWidget;
data.contentWidget = _contentWidget;
_titleLayout->removeWidget(_titleWidget);
_titleWidget = NULL;
layout()->removeWidget(_contentWidget);
_contentWidget = NULL;
return data;
}
void FloatingWidget::closeEvent(QCloseEvent*)
{
}
ADS_NAMESPACE_END

View File

@ -0,0 +1,39 @@
#ifndef FLOATINGWIDGET_H
#define FLOATINGWIDGET_H
#include <QWidget>
#include <QFrame>
#include "ads.h"
#include "section_content.h"
class QBoxLayout;
ADS_NAMESPACE_BEGIN
class SectionTitleWidget;
class SectionContentWidget;
// FloatingWidget holds and displays SectionContent as a floating window.
// It can be resized, moved and dropped back into a SectionWidget.
class FloatingWidget : public QWidget
{
Q_OBJECT
public:
FloatingWidget(SectionContent::RefPtr sc, SectionTitleWidget* titleWidget, SectionContentWidget* contentWidget, QWidget* parent = nullptr);
InternalContentData takeContent();
protected:
virtual void closeEvent(QCloseEvent* e);
private:
SectionContent::RefPtr _content;
SectionTitleWidget* _titleWidget;
SectionContentWidget* _contentWidget;
QBoxLayout* _titleLayout;
};
ADS_NAMESPACE_END
#endif

View File

@ -0,0 +1,56 @@
#include "section_content.h"
#include <QLabel>
ADS_NAMESPACE_BEGIN
int SectionContent::NextUid = 1;
QHash<int, SectionContent*> SectionContent::LookupMap;
SectionContent::SectionContent(QWidget* title, QWidget* content, const QString& uniqueName) :
_uid(NextUid++),
_uniqueName(uniqueName)
{
_title = title;
_content = content;
LookupMap.insert(_uid, this);
}
SectionContent::~SectionContent()
{
LookupMap.remove(_uid);
delete _title;
delete _content;
}
int SectionContent::uid() const
{
return _uid;
}
QString SectionContent::uniqueName() const
{
return _uniqueName;
}
QWidget* SectionContent::titleWidget() const
{
return _title;
}
QWidget* SectionContent::contentWidget() const
{
return _content;
}
SectionContent::RefPtr SectionContent::newSectionContent(QWidget* title, QWidget* content)
{
return QSharedPointer<SectionContent>(new SectionContent(title, content));
}
SectionContent::RefPtr SectionContent::newSectionContent(const QString& title, QWidget* content)
{
return QSharedPointer<SectionContent>(new SectionContent(new QLabel(title), content));
}
ADS_NAMESPACE_END

View File

@ -0,0 +1,40 @@
#ifndef SECTIONCONTENT_H
#define SECTIONCONTENT_H
#include <QPointer>
#include <QWidget>
#include <QHash>
#include <QSharedPointer>
#include "ads.h"
ADS_NAMESPACE_BEGIN
class SectionContent
{
public:
typedef QSharedPointer<SectionContent> RefPtr;
SectionContent(QWidget* title, QWidget* content, const QString& uniqueName = QString()); ///< Do not use!
virtual ~SectionContent();
int uid() const;
QString uniqueName() const;
QWidget* titleWidget() const;
QWidget* contentWidget() const;
static RefPtr newSectionContent(QWidget* title, QWidget* content);
static RefPtr newSectionContent(const QString& title, QWidget* content);
public:
const int _uid;
const QString _uniqueName;
QPointer<QWidget> _title;
QPointer<QWidget> _content;
static int NextUid;
static QHash<int, SectionContent*> LookupMap;
};
ADS_NAMESPACE_END
#endif

View File

@ -0,0 +1,18 @@
#include "section_content_widget.h"
#include <QBoxLayout>
ADS_NAMESPACE_BEGIN
SectionContentWidget::SectionContentWidget(SectionContent::RefPtr c, QWidget* parent) :
QFrame(parent),
_content(c)
{
auto l = new QBoxLayout(QBoxLayout::TopToBottom);
l->setContentsMargins(0, 0, 0, 0);
l->setSpacing(0);
l->addWidget(_content->contentWidget());
setLayout(l);
}
ADS_NAMESPACE_END

View File

@ -0,0 +1,25 @@
#ifndef SECTION_CONTENT_WIDGET_H
#define SECTION_CONTENT_WIDGET_H
#include <QFrame>
#include "ads.h"
#include "section_content.h"
ADS_NAMESPACE_BEGIN
class SectionWidget;
class SectionContentWidget : public QFrame
{
Q_OBJECT
public:
SectionContentWidget(SectionContent::RefPtr c, QWidget* parent = 0);
private:
SectionContent::RefPtr _content;
};
ADS_NAMESPACE_END
#endif

View File

@ -0,0 +1,212 @@
#include "section_title_widget.h"
#include <QDebug>
#include <QString>
#include <QApplication>
#include <QBoxLayout>
#include <QMouseEvent>
#include <QMimeData>
#include <QDrag>
#include <QCursor>
#include <QStyle>
#ifdef ADS_ANIMATIONS_ENABLED
#include <QPropertyAnimation>
#include <QParallelAnimationGroup>
#endif
#include "drop_overlay.h"
#include "section_content.h"
#include "section_widget.h"
#include "floating_widget.h"
#include "container_widget.h"
ADS_NAMESPACE_BEGIN
SectionTitleWidget::SectionTitleWidget(SectionContent::RefPtr content, QWidget* parent) :
QFrame(parent),
_content(content),
_activeTab(false)
{
auto l = new QBoxLayout(QBoxLayout::LeftToRight);
l->addWidget(content->titleWidget());
setLayout(l);
}
bool SectionTitleWidget::isActiveTab() const
{
return _activeTab;
}
void SectionTitleWidget::setActiveTab(bool active)
{
if (active != _activeTab)
{
_activeTab = active;
style()->unpolish(this);
style()->polish(this);
update();
emit activeTabChanged();
}
}
void SectionTitleWidget::mousePressEvent(QMouseEvent* ev)
{
// qDebug() << Q_FUNC_INFO << ev->pos();
if (ev->button() == Qt::LeftButton)
{
_dragStartPos = ev->pos();
ev->accept();
return;
}
QFrame::mousePressEvent(ev);
}
void SectionTitleWidget::mouseReleaseEvent(QMouseEvent* ev)
{
// qDebug() << Q_FUNC_INFO << ev->pos();
if (!_dragStartPos.isNull())
{
emit clicked();
}
// Drop contents of FloatingWidget into SectionWidget.
if (_fw)
{
auto cw = findParentContainerWidget(this);
auto sw = cw->sectionAt(cw->mapFromGlobal(ev->globalPos()));
if (sw)
{
auto loc = showDropOverlay(sw);
if (loc == InvalidDropArea)
{
qDebug() << "Invalid drop area";
}
else
{
#if !defined(ADS_ANIMATIONS_ENABLED)
auto data = _fw->takeContent();
_fw->deleteLater();
_fw.clear();
cw->dropContent(data, sw, loc);
#else
auto moveAnim = new QPropertyAnimation(_fw, "pos", this);
moveAnim->setStartValue(_fw->pos());
moveAnim->setEndValue(sw->mapToGlobal(sw->rect().topLeft()));
moveAnim->setDuration(ADS_ANIMATION_DURATION);
auto resizeAnim = new QPropertyAnimation(_fw, "size", this);
resizeAnim->setStartValue(_fw->size());
resizeAnim->setEndValue(sw->size());
resizeAnim->setDuration(ADS_ANIMATION_DURATION);
auto animGroup = new QParallelAnimationGroup(this);
QObject::connect(animGroup, &QPropertyAnimation::finished, [this, sw]()
{
auto data = _fw->takeContent();
_fw->deleteLater();
_fw.clear();
sw->addContent(data, true);
});
animGroup->addAnimation(moveAnim);
animGroup->addAnimation(resizeAnim);
animGroup->start(QAbstractAnimation::DeleteWhenStopped);
#endif
}
}
// Mouse is over a outer-edge drop area
else if (false)
{
}
}
// Reset
_dragStartPos = QPoint();
hideDropOverlay();
QFrame::mouseReleaseEvent(ev);
}
void SectionTitleWidget::mouseMoveEvent(QMouseEvent* ev)
{
ContainerWidget* cw = findParentContainerWidget(this);
SectionWidget* section = NULL;
// Move already existing FloatingWidget
if (_fw)
{
const QPoint moveToPos = ev->globalPos() - (_dragStartPos + QPoint(ADS_WINDOW_FRAME_BORDER_WIDTH, ADS_WINDOW_FRAME_BORDER_WIDTH));
_fw->move(moveToPos);
// Show drop indicator
if (true)
{
// Mouse is over a SectionWidget
section = cw->sectionAt(cw->mapFromGlobal(QCursor::pos()));
if (section)
{
showDropOverlay(section);
}
// Mouse is at the edge of the ContainerWidget
// Top, Right, Bottom, Left
else if (cw->outerTopDropRect().contains(cw->mapFromGlobal(QCursor::pos())))
{
qDebug() << "Top area...";
}
else if (cw->outerRightDropRect().contains(cw->mapFromGlobal(QCursor::pos())))
{
qDebug() << "Right area...";
}
else if (cw->outerBottomDropRect().contains(cw->mapFromGlobal(QCursor::pos())))
{
qDebug() << "Bottom area...";
}
else if (cw->outerLeftDropRect().contains(cw->mapFromGlobal(QCursor::pos())))
{
qDebug() << "Left area...";
}
else
{
hideDropOverlay();
}
}
ev->accept();
return;
}
// Begin to drag title inside the title area to switch its position inside the SectionWidget.
else if (!_dragStartPos.isNull() && (ev->buttons() & Qt::LeftButton)
&& (section = findParentSectionWidget(this)) != NULL && section->titleAreaGeometry().contains(section->mapFromGlobal(ev->globalPos())))
{
// qDebug() << "Move inside title area" << ev->pos();
}
// Begin to drag/float the SectionContent.
else if (!_dragStartPos.isNull() && (ev->buttons() & Qt::LeftButton) && (ev->globalPos() - _dragStartPos).manhattanLength() >= QApplication::startDragDistance()
&& (section = findParentSectionWidget(this)) != NULL)
{
// Create floating widget.
auto data = section->take(_content->uid(), false);
_fw = new FloatingWidget(data.content, data.titleWidget, data.contentWidget, cw);
_fw->resize(section->size());
setActiveTab(false);
const QPoint moveToPos = ev->globalPos() - (_dragStartPos + QPoint(ADS_WINDOW_FRAME_BORDER_WIDTH, ADS_WINDOW_FRAME_BORDER_WIDTH));
_fw->move(moveToPos);
_fw->show();
// Delete old section, if it is empty now.
if (section->contents().isEmpty())
{
delete section;
section = NULL;
}
ev->accept();
return;
}
QFrame::mouseMoveEvent(ev);
}
ADS_NAMESPACE_END

View File

@ -0,0 +1,44 @@
#ifndef SECTION_TITLE_WIDGET_H
#define SECTION_TITLE_WIDGET_H
#include <QFrame>
#include <QPoint>
#include "ads.h"
#include "section_content.h"
ADS_NAMESPACE_BEGIN
class SectionWidget;
class FloatingWidget;
class SectionTitleWidget : public QFrame
{
Q_OBJECT
Q_PROPERTY(bool activeTab MEMBER _activeTab NOTIFY activeTabChanged)
friend class SectionWidget;
SectionContent::RefPtr _content;
QPointer<FloatingWidget> _fw;
QPoint _dragStartPos;
bool _activeTab;
public:
SectionTitleWidget(SectionContent::RefPtr content, QWidget* parent);
bool isActiveTab() const;
void setActiveTab(bool active);
protected:
virtual void mousePressEvent(QMouseEvent* ev);
virtual void mouseReleaseEvent(QMouseEvent* ev);
virtual void mouseMoveEvent(QMouseEvent* ev);
signals:
void activeTabChanged();
void clicked();
};
ADS_NAMESPACE_END
#endif

View File

@ -0,0 +1,231 @@
#include "section_widget.h"
#include <QApplication>
#include <QBoxLayout>
#include <QStackedLayout>
#include <QMouseEvent>
#include <QDragEnterEvent>
#include <QMimeData>
#include <QPainter>
#include <QStyle>
#include <QtWidgets/QSplitter>
#if defined(ADS_ANIMATIONS_ENABLED)
#include <QGraphicsDropShadowEffect>
#endif
#include "drop_overlay.h"
#include "section_content.h"
#include "section_title_widget.h"
#include "section_content_widget.h"
#include "floating_widget.h"
#include "container_widget.h"
ADS_NAMESPACE_BEGIN
int SectionWidget::NextUid = 1;
QHash<int, SectionWidget*> SectionWidget::LookupMap;
SectionWidget::SectionWidget(ContainerWidget* parent) :
QFrame(parent),
_uid(NextUid++),
_container(parent)
{
//setAttribute(Qt::WA_DeleteOnClose, true);
auto l = new QBoxLayout(QBoxLayout::TopToBottom);
l->setContentsMargins(0, 0, 0, 0);
l->setSpacing(0);
setLayout(l);
_tabsLayout = new QBoxLayout(QBoxLayout::LeftToRight);
_tabsLayout->setContentsMargins(0, 0, 0, 0);
_tabsLayout->setSpacing(0);
_tabsLayout->addStretch(1);
l->addLayout(_tabsLayout);
_contentsLayout = new QStackedLayout();
_contentsLayout->setContentsMargins(0, 0, 0, 0);
_contentsLayout->setSpacing(0);
l->addLayout(_contentsLayout, 1);
#if defined(ADS_ANIMATIONS_ENABLED)
auto shadow = new QGraphicsDropShadowEffect(this);
shadow->setOffset(0, 0);
shadow->setBlurRadius(8);
setGraphicsEffect(shadow);
#endif
LookupMap.insert(_uid, this);
_container->_sections.append(this);
}
SectionWidget::~SectionWidget()
{
qDebug() << Q_FUNC_INFO;
LookupMap.remove(_uid);
_container->_sections.removeAll(this);
// Delete empty QSplitter.
auto splitter = findParentSplitter(this);
if (splitter && splitter->count() == 0)
{
splitter->deleteLater();
qDebug() << "Delete empty splitter";
}
}
int SectionWidget::uid() const
{
return _uid;
}
ContainerWidget* SectionWidget::containerWidget() const
{
return _container;
}
QRect SectionWidget::titleAreaGeometry() const
{
return _tabsLayout->geometry();
}
QRect SectionWidget::contentAreaGeometry() const
{
return _contentsLayout->geometry();
}
void SectionWidget::addContent(SectionContent::RefPtr c)
{
_contents.append(c);
auto title = new SectionTitleWidget(c, nullptr);
_sectionTitles.append(title);
_tabsLayout->insertWidget(_tabsLayout->count() - 1, title);
QObject::connect(title, &SectionTitleWidget::clicked, this, &SectionWidget::onSectionTitleClicked);
auto content = new SectionContentWidget(c, nullptr);
_sectionContents.append(content);
_contentsLayout->addWidget(content);
// Active first TAB.
if (_contents.size() == 1)
setCurrentIndex(0);
// Switch to newest.
// else
// setCurrentIndex(_contentsLayout->count() - 1);
}
void SectionWidget::addContent(const InternalContentData& data, bool autoActivate)
{
_contents.append(data.content);
_sectionTitles.append(data.titleWidget);
_tabsLayout->insertWidget(_tabsLayout->count() - 1, data.titleWidget);
QObject::connect(data.titleWidget, &SectionTitleWidget::clicked, this, &SectionWidget::onSectionTitleClicked);
_sectionContents.append(data.contentWidget);
_contentsLayout->addWidget(data.contentWidget);
// Active first TAB.
if (_contents.size() == 1)
setCurrentIndex(0);
// Switch to newest.
else if (autoActivate)
setCurrentIndex(_contentsLayout->count() - 1);
}
// take removes a widget from the SectionWidget but does not delete
// the used SectionTitle- and SectionContent-Widget. Instead it returns
// these objects.
InternalContentData SectionWidget::take(int uid, bool del)
{
InternalContentData data;
// Find SectionContent.
SectionContent::RefPtr sc;
int index = -1;
for (int i = 0; i < _contents.count(); i++)
{
if (_contents[i]->uid() != uid)
continue;
index = i;
sc = _contents.takeAt(i);
break;
}
// Title wrapper widget (TAB)
auto title = _sectionTitles.takeAt(index);
if (title)
{
_tabsLayout->removeWidget(title);
title->disconnect(this);
if (del)
title->deleteLater();
}
// Content wrapper widget (CONTENT)
auto content = _sectionContents.takeAt(index);
if (content)
{
_contentsLayout->removeWidget(content);
content->disconnect(this);
if (del)
content->deleteLater();
}
// Select the previous tab as activeTab.
if (_contents.size() > 0 && title->isActiveTab())
{
if (index > 0)
setCurrentIndex(index - 1);
else
setCurrentIndex(0);
}
data.content = sc;
data.titleWidget = title;
data.contentWidget = content;
return data;
}
void SectionWidget::setCurrentIndex(int index)
{
// Set active TAB.
for (int i = 0; i < _tabsLayout->count(); ++i)
{
auto item = _tabsLayout->itemAt(i);
if (item->widget())
{
auto stw = dynamic_cast<SectionTitleWidget*>(item->widget());
if (i == index)
stw->setActiveTab(true);
else
stw->setActiveTab(false);
}
}
// Set active CONTENT.
_contentsLayout->setCurrentIndex(index);
}
void SectionWidget::paintEvent(QPaintEvent* e)
{
QFrame::paintEvent(e);
// QPainter p(this);
// auto r = rect();
// p.drawText(rect(), Qt::AlignCenter | Qt::AlignVCenter, QString("x=%1; y=%2; w=%3; h=%4").arg(r.x()).arg(r.y()).arg(r.width()).arg(r.height()));
}
void SectionWidget::onSectionTitleClicked()
{
auto stw = qobject_cast<SectionTitleWidget*>(sender());
if (stw)
{
auto index = _tabsLayout->indexOf(stw);
setCurrentIndex(index);
}
}
ADS_NAMESPACE_END

View File

@ -0,0 +1,72 @@
#ifndef SECTION_WIDGET_H
#define SECTION_WIDGET_H
#include <QDebug>
#include <QList>
#include <QHash>
#include <QFrame>
#include "ads.h"
#include "section_content.h"
class QBoxLayout;
class QStackedLayout;
ADS_NAMESPACE_BEGIN
class ContainerWidget;
class SectionTitleWidget;
class SectionContentWidget;
// SectionWidget manages multiple instances of SectionContent.
// It displays a title TAB, which is clickable and will switch to
// the contents associated to the title when clicked.
class SectionWidget : public QFrame
{
Q_OBJECT
public:
explicit SectionWidget(ContainerWidget* parent);
virtual ~SectionWidget();
int uid() const;
ContainerWidget* containerWidget() const;
QRect titleAreaGeometry() const;
QRect contentAreaGeometry() const;
QList<SectionContent::RefPtr> contents() const { return _contents; }
void addContent(SectionContent::RefPtr c);
void addContent(const InternalContentData& data, bool autoActivate);
InternalContentData take(int uid, bool del = true);
public slots:
void setCurrentIndex(int index);
protected:
virtual void paintEvent(QPaintEvent*);
private slots:
void onSectionTitleClicked();
private:
const int _uid;
ContainerWidget* _container;
QList<SectionContent::RefPtr> _contents;
QList<SectionTitleWidget*> _sectionTitles;
QList<SectionContentWidget*> _sectionContents;
QBoxLayout *_tabsLayout;
QStackedLayout *_contentsLayout;
QPoint _mousePressPoint;
SectionContent::RefPtr _mousePressContent;
SectionTitleWidget* _mousePressTitleWidget;
static int NextUid;
static QHash<int, SectionWidget*> LookupMap;
};
ADS_NAMESPACE_END
#endif

View File

@ -0,0 +1,33 @@
TARGET = AdvancedDockingSystemDemo
QT += core gui
greaterThan(QT_MAJOR_VERSION, 4): QT += widgets
TEMPLATE = app
SOURCES += \
src/main.cpp \
src/mainwindow.cpp \
src/icontitlewidget.cpp
HEADERS += \
src/mainwindow.h \
src/icontitlewidget.h
FORMS += \
src/mainwindow.ui
# Dependency: AdvancedDockingSystem
win32:CONFIG(release, debug|release): LIBS += -L$$OUT_PWD/../AdvancedDockingSystem/release/ -lAdvancedDockingSystem
else:win32:CONFIG(debug, debug|release): LIBS += -L$$OUT_PWD/../AdvancedDockingSystem/debug/ -lAdvancedDockingSystem
else:unix: LIBS += -L$$OUT_PWD/../AdvancedDockingSystem/ -lAdvancedDockingSystem
INCLUDEPATH += $$PWD/../AdvancedDockingSystem/src
DEPENDPATH += $$PWD/../AdvancedDockingSystem/src
win32-g++:CONFIG(release, debug|release): PRE_TARGETDEPS += $$OUT_PWD/../AdvancedDockingSystem/release/libAdvancedDockingSystem.a
else:win32-g++:CONFIG(debug, debug|release): PRE_TARGETDEPS += $$OUT_PWD/../AdvancedDockingSystem/debug/libAdvancedDockingSystem.a
else:win32:!win32-g++:CONFIG(release, debug|release): PRE_TARGETDEPS += $$OUT_PWD/../AdvancedDockingSystem/release/AdvancedDockingSystem.lib
else:win32:!win32-g++:CONFIG(debug, debug|release): PRE_TARGETDEPS += $$OUT_PWD/../AdvancedDockingSystem/debug/AdvancedDockingSystem.lib
else:unix: PRE_TARGETDEPS += $$OUT_PWD/../AdvancedDockingSystem/libAdvancedDockingSystem.a

View File

@ -0,0 +1,32 @@
#include "icontitlewidget.h"
#include <QIcon>
#include <QString>
#include <QBoxLayout>
#include <QLabel>
#include <QStyle>
IconTitleWidget::IconTitleWidget(const QIcon& icon, const QString& title, QWidget *parent) :
QFrame(parent)
{
auto l = new QBoxLayout(QBoxLayout::LeftToRight);
l->setContentsMargins(0, 0, 0, 0);
setLayout(l);
auto titleIcon = new QLabel();
if (icon.isNull())
{
titleIcon->setPixmap(style()->standardIcon(QStyle::SP_MessageBoxInformation).pixmap(16, 16));
}
else
{
titleIcon->setPixmap(icon.pixmap(16, 16));
}
l->addWidget(titleIcon);
auto titleText = new QLabel(title);
auto titleFont = titleText->font();
titleFont.setBold(true);
titleText->setFont(titleFont);
l->addWidget(titleText, 1);
}

View File

@ -0,0 +1,19 @@
#ifndef ICONTITLEWIDGET_H
#define ICONTITLEWIDGET_H
#include <QFrame>
class QIcon;
class QString;
class IconTitleWidget : public QFrame
{
Q_OBJECT
public:
explicit IconTitleWidget(const QIcon& icon, const QString& title, QWidget *parent = 0);
signals:
public slots:
};
#endif // ICONTITLEWIDGET_H

View File

@ -0,0 +1,70 @@
#include <QString>
#include <QRect>
#include <QApplication>
#include <QDesktopWidget>
#include "mainwindow.h"
static void centerWidget(QWidget* widget)
{
if (widget)
{
QDesktopWidget deskWidget;
const auto screenIndex = deskWidget.primaryScreen();
const auto deskRect = deskWidget.availableGeometry(screenIndex);
const auto x = (deskRect.width() - widget->rect().width()) / 2;
const auto y = (deskRect.height() - widget->rect().height()) / 2;
widget->move(x, y);
}
}
static void resizeWidgetPerCent(QWidget* widget, qreal widthPC, qreal heightPC)
{
if (widget && widthPC >= 0.0 && heightPC >= 0.0)
{
QDesktopWidget deskWidget;
const auto screenIndex = deskWidget.primaryScreen();
const auto deskRect = deskWidget.availableGeometry(screenIndex);
const auto w = (deskRect.width() / 100) * widthPC;
const auto h = (deskRect.height() / 100) * heightPC;
widget->resize(w, h);
}
}
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
a.setQuitOnLastWindowClosed(true);
Q_INIT_RESOURCE(ads);
// Development style.
// a.setStyleSheet(""
// " QSplitter::handle { border: 1px solid #000000; background: #000000; } "
// " ads--ContainerWidget { border: 1px solid #ff0000; background: #FFE6E6; } "
// " ads--SectionWidget { border: 1px solid #00ff00; background: #E6FFE6; } "
// " ads--SectionTitleWidget { border: 1px solid #0000ff; background: #E6E6FF; } "
// " ads--SectionTitleWidget[activeTab=\"true\"] { border: 1px solid #0000ff; background: #9696FF; } "
// " ads--SectionContentWidget { border: 1px solid #FFFF00; background: #FFFFE6; } "
// );
// PARTsolutions style.
a.setStyleSheet(""
" QSplitter::handle:vertical { image: url(:/img/splitter-horizontal.png); } "
" QSplitter::handle:horizontal { image: url(:/img/splitter-vertical.png); } "
" ads--ContainerWidget { border: 0; background: #9ab6ca; } "
" ads--SectionWidget { border-width: 1px; border-color: #ffffff; border-style: solid; background: #7c9eb3; padding: 0; margin: 0; } "
" ads--SectionTitleWidget { border-right: 1px solid #E7F3F8; background: #7c9eb3; } "
" ads--SectionTitleWidget[activeTab=\"true\"] { border: 1px solid #E7F3F8; background: #E7F3F8; } "
" ads--SectionTitleWidget IconTitleWidget QLabel { color: #000000; } "
" ads--SectionContentWidget { border: 0px solid #E7F3F8; background: #ffffff; } "
" ads--FloatingWidget QPushButton { background: #E7F3F8; } "
);
MainWindow mw;
resizeWidgetPerCent(&mw, 60, 80);
centerWidget(&mw);
mw.show();
return a.exec();
}

View File

@ -0,0 +1,98 @@
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <QTime>
#include <QLabel>
#include <QTextEdit>
#include <QCalendarWidget>
#include <QFrame>
#include <QTreeView>
#include <QFileSystemModel>
#include "ads/container_widget.h"
#include "ads/section_widget.h"
#include "ads/section_content.h"
#include "icontitlewidget.h"
///////////////////////////////////////////////////////////////////////
static int CONTENT_COUNT = 0;
static ads::SectionContent::RefPtr createLongTextLabelSC()
{
auto w = new QLabel();
w->setWordWrap(true);
w->setAlignment(Qt::AlignTop | Qt::AlignLeft);
w->setText(QString("Lorem Ipsum ist ein einfacher Demo-Text für die Print- und Schriftindustrie. Lorem Ipsum ist in der Industrie bereits der Standard Demo-Text seit 1500, als ein unbekannter Schriftsteller eine Hand voll Wörter nahm und diese durcheinander warf um ein Musterbuch zu erstellen. Es hat nicht nur 5 Jahrhunderte überlebt, sondern auch in Spruch in die elektronische Schriftbearbeitung geschafft (bemerke, nahezu unverändert). Bekannt wurde es 1960, mit dem erscheinen von Letrase, welches Passagen von Lorem Ipsum enhielt, so wie Desktop Software wie Aldus PageMaker - ebenfalls mit Lorem Ipsum."));
return ads::SectionContent::newSectionContent(new IconTitleWidget(QIcon(), QString("Title %1").arg(++CONTENT_COUNT)), w);
}
static ads::SectionContent::RefPtr createCalendarSC()
{
auto w = new QCalendarWidget();
return ads::SectionContent::newSectionContent(new IconTitleWidget(QIcon(), QString("Title %1").arg(++CONTENT_COUNT)), w);
}
static ads::SectionContent::RefPtr createTreeSC()
{
auto m = new QFileSystemModel();
m->setRootPath(QDir::currentPath());
auto w = new QTreeView();
w->setModel(m);
return ads::SectionContent::newSectionContent(new IconTitleWidget(QIcon(), QString("Title %1").arg(++CONTENT_COUNT)), w);
}
///////////////////////////////////////////////////////////////////////
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
QObject::connect(ui->actionAddSectionContent, &QAction::triggered, this, &MainWindow::onActionAddSectionContentTriggered);
// CREATE SOME TESTING DOCKS
_container = new ads::ContainerWidget();
_container->setOrientation(Qt::Vertical);
setCentralWidget(_container);
auto leftSection = new ads::SectionWidget(_container);
leftSection->addContent(createLongTextLabelSC());
_container->addSection(leftSection);
auto middleSection = new ads::SectionWidget(_container);
middleSection->addContent(createCalendarSC());
_container->addSection(middleSection);
auto middleBottom = new ads::SectionWidget(_container);
middleBottom->addContent(createLongTextLabelSC());
_container->addSection(middleBottom);
// _container->splitSections(middleSection, middleBottom, Qt::Vertical);
auto rightSection = new ads::SectionWidget(_container);
rightSection->addContent(createLongTextLabelSC());
_container->addSection(rightSection);
// auto middleTopRight = new ads::SectionWidget(_container);
// middleTopRight->addContent(createLongTextLabelSC());
// _container->splitSections(middleSection, middleTopRight);
}
MainWindow::~MainWindow()
{
delete ui;
}
void MainWindow::onActionAddSectionContentTriggered()
{
return;
// auto titleWidget = new IconTitleWidget(QIcon(), QString("Title"));
// auto contentWidget = createRandomWidget(-1, -1);
// auto content = ads::SectionContent::newSectionContent(titleWidget, contentWidget);
// auto section = new ads::SectionWidget(_container);
// _container->addSection(section);
// section->addContent(content);
}

View File

@ -0,0 +1,31 @@
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
#include "ads/ads.h"
namespace Ui {
class MainWindow;
}
ADS_NAMESPACE_BEGIN
class ContainerWidget;
ADS_NAMESPACE_END
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
explicit MainWindow(QWidget *parent = 0);
virtual ~MainWindow();
private slots:
void onActionAddSectionContentTriggered();
private:
Ui::MainWindow *ui;
ads::ContainerWidget* _container;
};
#endif // MAINWINDOW_H

View File

@ -0,0 +1,46 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>MainWindow</class>
<widget class="QMainWindow" name="MainWindow">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>400</width>
<height>300</height>
</rect>
</property>
<property name="windowTitle">
<string>MainWindow</string>
</property>
<widget class="QWidget" name="centralWidget"/>
<widget class="QToolBar" name="mainToolBar">
<attribute name="toolBarArea">
<enum>TopToolBarArea</enum>
</attribute>
<attribute name="toolBarBreak">
<bool>false</bool>
</attribute>
<addaction name="actionAddSectionContent"/>
</widget>
<widget class="QStatusBar" name="statusBar"/>
<widget class="QMenuBar" name="menuBar">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>400</width>
<height>21</height>
</rect>
</property>
</widget>
<action name="actionAddSectionContent">
<property name="text">
<string>Add SectionContent</string>
</property>
</action>
</widget>
<layoutdefault spacing="6" margin="11"/>
<resources/>
<connections/>
</ui>

5
build.pro Normal file
View File

@ -0,0 +1,5 @@
TEMPLATE = subdirs
SUBDIRS = \
AdvancedDockingSystem \
AdvancedDockingSystemDemo