Refactoring of project structure

This commit is contained in:
Uwe Kindler 2017-03-12 21:41:50 +01:00
parent c57d14d0d7
commit 97571e4be8
76 changed files with 265 additions and 6847 deletions

View File

@ -1,62 +0,0 @@
include($$(cetoni_repository)/build/qt/qtprojectsettings/shared_library.pri)
include(src/v2/v2.pri)
TARGET = $$qtLibraryTarget(AdvancedDockingSystem)
TEMPLATE = lib
#VERSION = 1.0.0
CONFIG += adsBuildShared
QT += core gui
greaterThan(QT_MAJOR_VERSION, 4): QT += widgets
greaterThan(QT_MAJOR_VERSION, 4): DEFINES += ADS_NAMESPACE_ENABLED
adsBuildShared {
CONFIG += shared
DEFINES += ADS_EXPORT
}
!adsBuildShared {
CONFIG += staticlib
}
INCLUDEPATH += $$PWD/include
windows {
# MinGW
*-g++* {
QMAKE_CXXFLAGS += -std=c++11
QMAKE_CXXFLAGS += -Wall -Wextra -pedantic
}
# MSVC
*-msvc* {
}
}
RESOURCES += \
res/ads.qrc
SOURCES += \
$$PWD/src/API.cpp \
$$PWD/src/MainContainerWidget.cpp \
$$PWD/src/SectionWidget.cpp \
$$PWD/src/SectionContent.cpp \
$$PWD/src/SectionTitleWidget.cpp \
$$PWD/src/SectionContentWidget.cpp \
$$PWD/src/DropOverlay.cpp \
$$PWD/src/FloatingWidget.cpp \
$$PWD/src/Internal.cpp \
$$PWD/src/Serialization.cpp \
$$PWD/src/ContainerWidget.cpp
HEADERS += \
$$PWD/src/API.h \
$$PWD/src/MainContainerWidget.h \
$$PWD/src/SectionWidget.h \
$$PWD/src/SectionContent.h \
$$PWD/src/SectionTitleWidget.h \
$$PWD/src/SectionContentWidget.h \
$$PWD/src/DropOverlay.h \
$$PWD/src/FloatingWidget.h \
$$PWD/src/Internal.h \
$$PWD/src/Serialization.h \
$$PWD/src/ContainerWidget.h

View File

@ -1,112 +0,0 @@
/*******************************************************************************
** QtAdcancedDockingSystem
** Copyright (C) 2017 Uwe Kindler
**
** This program is free software: you can redistribute it and/or modify
** it under the terms of the GNU General Public License as published by
** the Free Software Foundation, either version 3 of the License, or
** (at your option) any later version.
**
** This program is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
** GNU General Public License for more details.
**
** You should have received a copy of the GNU General Public License
** along with this program. If not, see <http://www.gnu.org/licenses/>.
******************************************************************************/
#include "MainContainerWidget.h"
#include "API.h"
#include <QWidget>
#include <QSplitter>
#include <QLayout>
#include <QVariant>
#include "SectionWidget.h"
namespace ads
{
static bool splitterContainsSectionWidget(QSplitter* splitter)
{
for (int i = 0; i < splitter->count(); ++i)
{
QWidget* w = splitter->widget(i);
QSplitter* sp = qobject_cast<QSplitter*>(w);
SectionWidget* sw = NULL;
if (sp && splitterContainsSectionWidget(sp))
return true;
else if ((sw = qobject_cast<SectionWidget*>(w)) != NULL)
return true;
}
return false;
}
void deleteEmptySplitter(CMainContainerWidget* container)
{
bool doAgain = false;
do
{
doAgain = false;
QList<QSplitter*> splitters = container->findChildren<QSplitter*>();
for (int i = 0; i < splitters.count(); ++i)
{
QSplitter* sp = splitters.at(i);
if (!sp->property("ads-splitter").toBool())
continue;
if (sp->count() > 0 && splitterContainsSectionWidget(sp))
continue;
delete splitters[i];
doAgain = true;
break;
}
}
while (doAgain);
}
QSplitter* findParentSplitter(QWidget* w)
{
QSplitter* splitter = 0;
QWidget* parentWidget = w;
do
{
if ((splitter = dynamic_cast<QSplitter*>(parentWidget)) != 0)
{
break;
}
parentWidget = parentWidget->parentWidget();
}
while (parentWidget);
return splitter;
}
QSplitter* findImmediateSplitter(QWidget* w)
{
QLayout* l = w->layout();
if (!l || l->count() <= 0)
{
return nullptr;
}
QSplitter* sp = nullptr;
for (int i = 0; i < l->count(); ++i)
{
QLayoutItem* li = l->itemAt(0);
if (!li->widget())
{
continue;
}
if ((sp = dynamic_cast<QSplitter*>(li->widget())) != nullptr)
{
break;
}
}
return sp;
}
} // namespace ads

View File

@ -1,71 +0,0 @@
#ifndef ADS_API_H
#define ADS_API_H
/*******************************************************************************
** QtAdcancedDockingSystem
** Copyright (C) 2017 Uwe Kindler
**
** This program is free software: you can redistribute it and/or modify
** it under the terms of the GNU General Public License as published by
** the Free Software Foundation, either version 3 of the License, or
** (at your option) any later version.
**
** This program is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
** GNU General Public License for more details.
**
** You should have received a copy of the GNU General Public License
** along with this program. If not, see <http://www.gnu.org/licenses/>.
******************************************************************************/
#include <QFlags>
class QWidget;
class QSplitter;
// DLL Export API
#ifdef _WIN32
#if defined(ADS_IMPORT)
#define ADS_EXPORT_API
#elif defined(ADS_EXPORT)
#define ADS_EXPORT_API __declspec(dllexport)
#else
#define ADS_EXPORT_API __declspec(dllimport)
#endif
#else
#define ADS_EXPORT_API
#endif
// Beautiful C++ stuff.
#define ADS_Expects(cond)
#define ADS_Ensures(cond)
// Indicates whether ADS should include animations.
//#define ADS_ANIMATIONS_ENABLED 1
//#define ADS_ANIMATION_DURATION 150
namespace ads
{
class CMainContainerWidget;
class SectionWidget;
enum DropArea
{
InvalidDropArea = 0,
TopDropArea = 1,
RightDropArea = 2,
BottomDropArea = 4,
LeftDropArea = 8,
CenterDropArea = 16,
OuterAreas = TopDropArea | RightDropArea | BottomDropArea | LeftDropArea,
AllAreas = OuterAreas | CenterDropArea
};
Q_DECLARE_FLAGS(DropAreas, DropArea)
void deleteEmptySplitter(CMainContainerWidget* container);
QSplitter* findParentSplitter(QWidget* w);
QSplitter* findImmediateSplitter(QWidget* w);
} // namespace ads
#endif

View File

@ -1,560 +0,0 @@
/*******************************************************************************
** QtAdcancedDockingSystem
** Copyright (C) 2017 Uwe Kindler
**
** This program is free software: you can redistribute it and/or modify
** it under the terms of the GNU General Public License as published by
** the Free Software Foundation, either version 3 of the License, or
** (at your option) any later version.
**
** This program is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
** GNU General Public License for more details.
**
** You should have received a copy of the GNU General Public License
** along with this program. If not, see <http://www.gnu.org/licenses/>.
******************************************************************************/
//============================================================================
// INCLUDES
//============================================================================
#include "MainContainerWidget.h"
#include "SectionContentWidget.h"
#include "ContainerWidget.h"
#include <QDebug>
#include <QPaintEvent>
#include <QPainter>
#include <QContextMenuEvent>
#include <QMenu>
#include <QSplitter>
#include <QDataStream>
#include <QtGlobal>
#include <QGridLayout>
#include <QPoint>
#include <QApplication>
#include <iostream>
#include "Internal.h"
#include "SectionWidget.h"
#include "SectionTitleWidget.h"
#include "DropOverlay.h"
#include "Serialization.h"
namespace ads
{
unsigned int CContainerWidget::zOrderCounter = 0;
//============================================================================
CContainerWidget::CContainerWidget(CMainContainerWidget* MainContainer, QWidget *parent)
: QFrame(parent),
m_MainContainerWidget(MainContainer)
{
m_MainLayout = new QGridLayout();
m_MainLayout->setContentsMargins(0, 1, 0, 0);
m_MainLayout->setSpacing(0);
setLayout(m_MainLayout);
}
//============================================================================
CContainerWidget::~CContainerWidget()
{
std::cout << "CContainerWidget::~CContainerWidget()" << std::endl;
m_MainContainerWidget->m_Containers.removeAll(this);
}
bool CContainerWidget::event(QEvent *e)
{
bool Result = QWidget::event(e);
if (e->type() == QEvent::WindowActivate)
{
m_zOrderIndex = ++zOrderCounter;
}
else if (e->type() == QEvent::Show && !m_zOrderIndex)
{
m_zOrderIndex = ++zOrderCounter;
}
return Result;
}
unsigned int CContainerWidget::zOrderIndex() const
{
return m_zOrderIndex;
}
void CContainerWidget::dropFloatingWidget(FloatingWidget* FloatingWidget,
const QPoint& TargetPos)
{
SectionWidget* sectionWidget = sectionWidgetAt(TargetPos);
DropArea dropArea = InvalidDropArea;
if (sectionWidget)
{
auto dropOverlay = m_MainContainerWidget->sectionDropOverlay();
dropOverlay->setAllowedAreas(AllAreas);
dropArea = dropOverlay->showDropOverlay(sectionWidget);
if (dropArea != InvalidDropArea)
{
std::cout << "Section Drop Content: " << dropArea << std::endl;
/*InternalContentData data;
FloatingWidget->takeContent(data);
FloatingWidget->deleteLater();
dropContent(data, sectionWidget, dropArea, true);*/
dropIntoSection(FloatingWidget, sectionWidget, dropArea);
}
}
// mouse is over container
if (InvalidDropArea == dropArea)
{
dropArea = m_MainContainerWidget->dropOverlay()->dropAreaUnderCursor();
std::cout << "Container Drop Content: " << dropArea << std::endl;
if (dropArea != InvalidDropArea)
{
// drop content
dropIntoContainer(FloatingWidget, dropArea);
}
}
}
void CContainerWidget::dropIntoContainer(FloatingWidget* FloatingWidget, DropArea area)
{
CContainerWidget* FloatingContainer = FloatingWidget->containerWidget();
QSplitter* FloatingMainSplitter = FloatingContainer->findChild<QSplitter*>(QString(), Qt::FindDirectChildrenOnly);
//QSplitter* oldsp = findImmediateSplitter(this);
// We use findChild here instead of findImmediateSplitter because I do not
// know what the advantage of the findImmediateSplitter function is
QSplitter* OldSplitter = this->findChild<QSplitter*>(QString(), Qt::FindDirectChildrenOnly);
//auto SectionWidgets = FloatingMainSplitter->findChildren<SectionWidget*>(QString(), Qt::FindDirectChildrenOnly);
QList<SectionWidget*> SectionWidgets;
for (int i = 0; i < FloatingMainSplitter->count(); ++i)
{
SectionWidgets.append(static_cast<SectionWidget*>(FloatingMainSplitter->widget(i)));
}
std::cout << "SectionWIdget[0] " << SectionWidgets[0] << " FloatingSplitter index 0"
<< FloatingMainSplitter->widget(0) << std::endl;
//std::cout<< "oldsp " << oldsp << " oldsp2 " << oldsp2 << std::endl;
Qt::Orientation orientation;
bool append;
switch (area)
{
case TopDropArea: orientation = Qt::Vertical; append = false; break;
case RightDropArea: orientation = Qt::Horizontal; append = true; break;
case CenterDropArea:
case BottomDropArea: orientation = Qt::Vertical; append = true; break;
case LeftDropArea: orientation = Qt::Horizontal; append = false; break;
}
auto l = m_MainLayout;
if (!OldSplitter)
{
std::cout << "Create new splitter" << std::endl;
// we have no splitter yet - let us create one
QSplitter* sp = CMainContainerWidget::newSplitter(FloatingMainSplitter->orientation());
if (l->count() > 0)
{
qWarning() << "Still items in layout. This should never happen.";
QLayoutItem* li = l->takeAt(0);
delete li;
}
l->addWidget(sp);
for (auto SectionWidget : SectionWidgets)
{
sp->addWidget(SectionWidget);
}
}
else if ((FloatingMainSplitter->orientation() == orientation || FloatingMainSplitter->count() == 1) &&
(OldSplitter->count() == 1 || OldSplitter->orientation() == orientation))
{
OldSplitter->setOrientation(orientation);
std::cout << "Splitter with right orientation" << std::endl;
// we have a splitter with only one item or with the right orientation so
// we can make it match the orientation of the floating splitter
for (int i = 0; i < SectionWidgets.count(); ++i)
{
if (append)
{
OldSplitter->addWidget(SectionWidgets[i]);
}
else
{
OldSplitter->insertWidget(i, SectionWidgets[i]);
}
}
}
else
{
std::cout << "Splitter with wrong orientation" << std::endl;
// we have a splitter but with the wrong orientation
QSplitter* sp = CMainContainerWidget::newSplitter(orientation);
if (append)
{
QLayoutItem* li = l->replaceWidget(OldSplitter, sp);
sp->addWidget(OldSplitter);
sp->addWidget(FloatingMainSplitter);
delete li;
}
else
{
sp->addWidget(FloatingMainSplitter);
QLayoutItem* li = l->replaceWidget(OldSplitter, sp);
sp->addWidget(OldSplitter);
delete li;
}
}
m_Sections.append(SectionWidgets);
FloatingWidget->deleteLater();
}
void CContainerWidget::dropIntoSection(FloatingWidget* FloatingWidget,
SectionWidget* targetSection, DropArea area)
{
CContainerWidget* FloatingContainer = FloatingWidget->containerWidget();
QSplitter* FloatingMainSplitter = FloatingContainer->findChild<QSplitter*>(QString(),
Qt::FindDirectChildrenOnly);
QList<SectionWidget*> SectionWidgets;
for (int i = 0; i < FloatingMainSplitter->count(); ++i)
{
SectionWidgets.append(static_cast<SectionWidget*>(FloatingMainSplitter->widget(i)));
}
Qt::Orientation Orientation;
int InsertIndexOffset;
switch (area)
{
case TopDropArea: Orientation = Qt::Vertical; InsertIndexOffset = 0;break;
case RightDropArea: Orientation = Qt::Horizontal; InsertIndexOffset = 1;break;
case BottomDropArea: Orientation = Qt::Vertical; InsertIndexOffset = 1;break;
case LeftDropArea: Orientation = Qt::Horizontal; InsertIndexOffset = 0;break;
case CenterDropArea:
{
QList<SectionWidget*> SectionWidgets = FloatingContainer->findChildren<SectionWidget*>(QString(), Qt::FindChildrenRecursively);
for (auto SectionWidget : SectionWidgets)
{
std::cout << "dropping into section CenterDropArea " << SectionWidget->contentCount() << std::endl;
while (SectionWidget->contentCount())
{
InternalContentData data;
if (!SectionWidget->takeContentAt(0, data))
{
qWarning() << "THIS SHOULD NOT HAPPEN!! " << 0;
return;
}
targetSection->addContent(data, false);
}
}
FloatingWidget->deleteLater();
}
return;
default:
break;
}
QSplitter* targetSectionSplitter = findParentSplitter(targetSection);
std::cout << "target->orientaton " << targetSectionSplitter->orientation()
<< " orien " << Orientation << std::endl;
int index = targetSectionSplitter->indexOf(targetSection);
std::cout << "targetSectionSplitter->indexOf(targetSection) " << index << std::endl;
if (targetSectionSplitter->orientation() == Orientation)
{
std::cout << "targetSectionSplitter->orientation() == Orientation" << std::endl;
if (FloatingMainSplitter->orientation() == Orientation || FloatingMainSplitter->count() == 1)
{
std::cout << "FloatingMainSplitter->orientation() == Orientation || FloatingMainSplitter->count() == 1" << std::endl;
for (int i = 0; i < SectionWidgets.count(); ++i)
{
targetSectionSplitter->insertWidget(index + InsertIndexOffset, SectionWidgets[i]);
}
}
else
{
targetSectionSplitter->insertWidget(index + InsertIndexOffset, FloatingMainSplitter);
}
}
else
{
std::cout << "targetSectionSplitter->orientation() != Orientation" << std::endl;
QSplitter* s = CMainContainerWidget::newSplitter(Orientation);
if (FloatingMainSplitter->orientation() == Orientation || FloatingMainSplitter->count() == 1)
{
std::cout << "FloatingMainSplitter->orientation() == Orientation || FloatingMainSplitter->count() == 1" << std::endl;
for (int i = 0; i < SectionWidgets.count(); ++i)
{
s->addWidget(SectionWidgets[i]);
}
}
else
{
s->addWidget(FloatingMainSplitter);
}
if (!InsertIndexOffset)
{
s->addWidget(targetSection);
}
else
{
s->insertWidget(0, targetSection);
}
targetSectionSplitter->insertWidget(index, s);
}
FloatingWidget->deleteLater();
m_Sections.append(SectionWidgets);
}
SectionWidget* CContainerWidget::sectionWidgetAt(const QPoint& pos) const
{
std::cout << "CContainerWidget::sectionWidgetAt m_Sections count "
<< m_Sections.count() << std::endl;
for (const auto& SectionWidget : m_Sections)
{
if (SectionWidget->rect().contains(SectionWidget->mapFromGlobal(pos)))
{
return SectionWidget;
}
}
return 0;
}
bool CContainerWidget::isInFrontOf(CContainerWidget* Other) const
{
return this->zOrderIndex() > Other->zOrderIndex();
}
SectionWidget* CContainerWidget::dropContent(const InternalContentData& data, SectionWidget* targetSectionWidget, DropArea area, bool autoActive)
{
ADS_Expects(targetSection != NULL);
SectionWidget* section_widget = nullptr;
// If no sections exists yet, create a default one and always drop into it.
if (m_Sections.isEmpty())
{
targetSectionWidget = newSectionWidget();
addSectionWidget(targetSectionWidget);
area = CenterDropArea;
}
// Drop on outer area
if (!targetSectionWidget)
{
switch (area)
{
case TopDropArea:return dropContentOuterHelper(m_MainLayout, data, Qt::Vertical, false);
case RightDropArea: return dropContentOuterHelper(m_MainLayout, data, Qt::Horizontal, true);
case CenterDropArea:
case BottomDropArea:return dropContentOuterHelper(m_MainLayout, data, Qt::Vertical, true);
case LeftDropArea: return dropContentOuterHelper(m_MainLayout, data, Qt::Horizontal, false);
default:
return nullptr;
}
return section_widget;
}
// Drop logic based on area.
switch (area)
{
case TopDropArea:return insertNewSectionWidget(data, targetSectionWidget, section_widget, Qt::Vertical, 0);
case RightDropArea: return insertNewSectionWidget(data, targetSectionWidget, section_widget, Qt::Horizontal, 1);
case BottomDropArea: return insertNewSectionWidget(data, targetSectionWidget, section_widget, Qt::Vertical, 1);
case LeftDropArea: return insertNewSectionWidget(data, targetSectionWidget, section_widget, Qt::Horizontal, 0);
case CenterDropArea:
targetSectionWidget->addContent(data, autoActive);
return targetSectionWidget;
default:
break;
}
return section_widget;
}
SectionWidget* CContainerWidget::newSectionWidget()
{
SectionWidget* sw = new SectionWidget(m_MainContainerWidget, this);
m_Sections.append(sw);
return sw;
}
void CContainerWidget::addSectionWidget(SectionWidget* section)
{
ADS_Expects(section != NULL);
if (section->containerWidget())
{
section->containerWidget()->takeSection(section);
}
// Create default splitter.
if (!m_Splitter)
{
m_Splitter = CMainContainerWidget::newSplitter(m_Orientation);
m_MainLayout->addWidget(m_Splitter, 0, 0);
}
if (m_Splitter->indexOf(section) != -1)
{
qWarning() << Q_FUNC_INFO << QString("Section has already been added");
return;
}
m_Splitter->addWidget(section);
m_Sections.append(section);
}
void CContainerWidget::takeSection(SectionWidget* Widget)
{
m_Sections.removeAll(Widget);
}
SectionWidget* CContainerWidget::dropContentOuterHelper(QLayout* l, const InternalContentData& data, Qt::Orientation orientation, bool append)
{
ADS_Expects(l != NULL);
SectionWidget* sw = newSectionWidget();
sw->addContent(data, true);
QSplitter* oldsp = findImmediateSplitter(this);
if (!oldsp)
{
QSplitter* sp = CMainContainerWidget::newSplitter(orientation);
if (l->count() > 0)
{
qWarning() << "Still items in layout. This should never happen.";
QLayoutItem* li = l->takeAt(0);
delete li;
}
l->addWidget(sp);
sp->addWidget(sw);
}
else if (oldsp->orientation() == orientation
|| oldsp->count() == 1)
{
oldsp->setOrientation(orientation);
if (append)
oldsp->addWidget(sw);
else
oldsp->insertWidget(0, sw);
}
else
{
QSplitter* sp = CMainContainerWidget::newSplitter(orientation);
if (append)
{
QLayoutItem* li = l->replaceWidget(oldsp, sp);
sp->addWidget(oldsp);
sp->addWidget(sw);
delete li;
}
else
{
sp->addWidget(sw);
QLayoutItem* li = l->replaceWidget(oldsp, sp);
sp->addWidget(oldsp);
delete li;
}
}
return sw;
}
SectionWidget* CContainerWidget::insertNewSectionWidget(
const InternalContentData& data, SectionWidget* targetSection, SectionWidget* ret,
Qt::Orientation Orientation, int InsertIndexOffset)
{
QSplitter* targetSectionSplitter = findParentSplitter(targetSection);
SectionWidget* sw = newSectionWidget();
sw->addContent(data, true);
if (targetSectionSplitter->orientation() == Orientation)
{
const int index = targetSectionSplitter->indexOf(targetSection);
targetSectionSplitter->insertWidget(index + InsertIndexOffset, sw);
}
else
{
const int index = targetSectionSplitter->indexOf(targetSection);
QSplitter* s = CMainContainerWidget::newSplitter(Orientation);
s->addWidget(sw);
s->addWidget(targetSection);
targetSectionSplitter->insertWidget(index, s);
}
ret = sw;
return ret;
}
SectionWidget* CContainerWidget::addSectionContent(const SectionContent::RefPtr& sc, SectionWidget* sw, DropArea area)
{
ADS_Expects(!sc.isNull());
// Drop it based on "area"
InternalContentData data;
data.content = sc;
data.titleWidget = new SectionTitleWidget(sc, NULL);
data.contentWidget = new CSectionContentWidget(sc, NULL);
connect(data.titleWidget, SIGNAL(activeTabChanged()), this, SLOT(onActiveTabChanged()));
return dropContent(data, sw, area, false);
}
void dumpChildSplitters(QWidget* Widget)
{
QSplitter* ParentSplitter = dynamic_cast<QSplitter*>(Widget);
auto Sections = Widget->findChildren<SectionWidget*>(QString(), Qt::FindDirectChildrenOnly);
auto Splitters = Widget->findChildren<QSplitter*>(QString(), Qt::FindDirectChildrenOnly);
std::cout << "-----------------------" << std::endl;
std::cout << "Sections " << Sections.size() << std::endl;
std::cout << "Splitters " << Splitters.size() << std::endl;
for (const auto& Splitter : Splitters)
{
if (ParentSplitter)
{
std::cout << "Orientation " << Splitter->orientation() << " index " << ParentSplitter->indexOf(Splitter) << std::endl;
}
else
{
std::cout << "Orientation " << Splitter->orientation() << std::endl;
}
dumpChildSplitters(Splitter);
}
}
void CContainerWidget::dumpLayout()
{
dumpChildSplitters(this);
}
void CContainerWidget::onActiveTabChanged()
{
SectionTitleWidget* stw = qobject_cast<SectionTitleWidget*>(sender());
if (stw)
{
emit activeTabChanged(stw->m_Content, stw->isActiveTab());
}
}
} // namespace ads
//---------------------------------------------------------------------------
// EOF ContainerWidget.cpp

View File

@ -1,126 +0,0 @@
#ifndef ContainerWidgetH
#define ContainerWidgetH
/*******************************************************************************
** QtAdcancedDockingSystem
** Copyright (C) 2017 Uwe Kindler
**
** This program is free software: you can redistribute it and/or modify
** it under the terms of the GNU General Public License as published by
** the Free Software Foundation, either version 3 of the License, or
** (at your option) any later version.
**
** This program is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
** GNU General Public License for more details.
**
** You should have received a copy of the GNU General Public License
** along with this program. If not, see <http://www.gnu.org/licenses/>.
******************************************************************************/
//============================================================================
// INCLUDES
//============================================================================
#include <QFrame>
#include "API.h"
#include "Internal.h"
#include "SectionContent.h"
#include "FloatingWidget.h"
#include "Serialization.h"
#include "DropOverlay.h"
namespace ads
{
class SectionWidget;
class DropOverlay;
class InternalContentData;
class CMainContainerWidget;
/**
* @brief
*/
class CContainerWidget : public QFrame
{
Q_OBJECT
friend class SectionContent;
friend class SectionWidget;
friend class FloatingWidget;
friend class SectionTitleWidget;
friend class ContainerWidgetPrivate;
public:
explicit CContainerWidget(CMainContainerWidget* MainContainerWidget, QWidget *parent = nullptr);
virtual ~CContainerWidget();
/**
* Returns the current zOrderIndex
*/
virtual unsigned int zOrderIndex() const;
void dropFloatingWidget(FloatingWidget* FloatingWidget,
const QPoint& TargetPos);
SectionWidget* sectionWidgetAt(const QPoint& GlobalPos) const;
/**
* This function returns true if this container widgets z order index is
* higher than the index of the container widget given in Other parameter
*/
bool isInFrontOf(CContainerWidget* Other) const;
SectionWidget* dropContent(const InternalContentData& data, SectionWidget* targetSection, DropArea area, bool autoActive = true);
/*!
* Adds the section-content <em>sc</em> to this container-widget into the section-widget <em>sw</em>.
* If <em>sw</em> is not NULL, the <em>area</em> is used to indicate how the content should be arranged.
* Returns a pointer to the SectionWidget of the added SectionContent. Do not use it for anything else than adding more
* SectionContent elements with this method.
*/
SectionWidget* addSectionContent(const SectionContent::RefPtr& sc, SectionWidget* sw = NULL, DropArea area = CenterDropArea);
void dumpLayout();
CMainContainerWidget* mainContainerWidget() const {return m_MainContainerWidget;}
void addSectionWidget(SectionWidget* section);
void takeSection(SectionWidget* Widget);
signals:
/*!
* Emits whenever the "isActiveTab" state of a SectionContent changes.
* Whenever the users sets another tab as active, this signal gets invoked
* for the old tab and the new active tab (the order is unspecified).
*/
void activeTabChanged(const SectionContent::RefPtr& sc, bool active);
protected:
void dropIntoContainer(FloatingWidget* FloatingWidget, DropArea area);
void dropIntoSection(FloatingWidget* FloatingWidget, SectionWidget* targetSection, DropArea area);
virtual bool event(QEvent *e) override;
SectionWidget* newSectionWidget();
SectionWidget* dropContentOuterHelper(QLayout* l, const InternalContentData& data, Qt::Orientation orientation, bool append);
SectionWidget* insertNewSectionWidget(const InternalContentData& data,
SectionWidget* targetSection, SectionWidget* ret, Qt::Orientation Orientation, int InsertIndexOffset);
QList<SectionWidget*> m_Sections;
// Layout stuff
QGridLayout* m_MainLayout = nullptr;
Qt::Orientation m_Orientation = Qt::Horizontal;
QPointer<QSplitter> m_Splitter; // $mfreiholz: I'd like to remove this variable entirely,
// because it changes during user interaction anyway.
CMainContainerWidget* m_MainContainerWidget = 0;
unsigned int m_zOrderIndex = 0;
static unsigned int zOrderCounter;
private slots:
void onActiveTabChanged();
};
} // namespace ads
//---------------------------------------------------------------------------
#endif // ContainerWidgetH

View File

@ -1,461 +0,0 @@
/*******************************************************************************
** QtAdcancedDockingSystem
** Copyright (C) 2017 Uwe Kindler
**
** This program is free software: you can redistribute it and/or modify
** it under the terms of the GNU General Public License as published by
** the Free Software Foundation, either version 3 of the License, or
** (at your option) any later version.
**
** This program is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
** GNU General Public License for more details.
**
** You should have received a copy of the GNU General Public License
** along with this program. If not, see <http://www.gnu.org/licenses/>.
******************************************************************************/
#include "DropOverlay.h"
#include <QPointer>
#include <QPaintEvent>
#include <QResizeEvent>
#include <QMoveEvent>
#include <QPainter>
#include <QGridLayout>
#include <QCursor>
#include <QIcon>
#include <QLabel>
#include <QtGlobal>
#include <QDebug>
#include <iostream>
namespace ads
{
// Helper /////////////////////////////////////////////////////////////
static QPixmap createDropIndicatorPixmap(const QPalette& pal, const QSizeF& size, DropArea dropArea)
{
const QColor borderColor = pal.color(QPalette::Active, QPalette::Highlight);
const QColor backgroundColor = pal.color(QPalette::Active, QPalette::Base);
const QColor areaBackgroundColor = pal.color(QPalette::Active, QPalette::Highlight).lighter(150);
QPixmap pm(size.width(), size.height());
pm.fill(QColor(0, 0, 0, 0));
QPainter p(&pm);
QPen pen = p.pen();
QRectF baseRect(pm.rect());
// Fill
p.fillRect(baseRect, backgroundColor);
// Drop area rect.
p.save();
QRectF areaRect;
QLineF areaLine;
QLinearGradient gradient;
switch (dropArea)
{
case TopDropArea:
areaRect = QRectF(baseRect.x(), baseRect.y(), baseRect.width(), baseRect.height() * .5f);
areaLine = QLineF(areaRect.bottomLeft(), areaRect.bottomRight());
gradient.setStart(areaRect.topLeft());
gradient.setFinalStop(areaRect.bottomLeft());
break;
case RightDropArea:
areaRect = QRectF(baseRect.width() * .5f, baseRect.y(), baseRect.width() * .5f, baseRect.height());
areaLine = QLineF(areaRect.topLeft(), areaRect.bottomLeft());
gradient.setStart(areaRect.topLeft());
gradient.setFinalStop(areaRect.topRight());
break;
case BottomDropArea:
areaRect = QRectF(baseRect.x(), baseRect.height() * .5f, baseRect.width(), baseRect.height() * .5f);
areaLine = QLineF(areaRect.topLeft(), areaRect.topRight());
gradient.setStart(areaRect.topLeft());
gradient.setFinalStop(areaRect.bottomLeft());
break;
case LeftDropArea:
areaRect = QRectF(baseRect.x(), baseRect.y(), baseRect.width() * .5f, baseRect.height());
areaLine = QLineF(areaRect.topRight(), areaRect.bottomRight());
gradient.setStart(areaRect.topLeft());
gradient.setFinalStop(areaRect.topRight());
break;
default:
break;
}
if (areaRect.isValid())
{
gradient.setColorAt(0.f, areaBackgroundColor);
gradient.setColorAt(1.f, areaBackgroundColor.lighter(120));
p.fillRect(areaRect, gradient);
pen = p.pen();
pen.setColor(borderColor);
pen.setStyle(Qt::DashLine);
p.setPen(pen);
p.drawLine(areaLine);
}
p.restore();
p.save();
pen = p.pen();
pen.setColor(borderColor);
pen.setWidth(1);
p.setPen(pen);
p.drawRect(baseRect.adjusted(0, 0, -pen.width(), -pen.width()));
p.restore();
return pm;
}
QWidget* DropOverlay::createDropIndicatorWidget(DropArea dropArea)
{
QLabel* l = new QLabel();
l->setObjectName("DropAreaLabel");
const qreal metric = static_cast<qreal>(l->fontMetrics().height()) * 2.f;
const QSizeF size(metric, metric);
l->setPixmap(createDropIndicatorPixmap(l->palette(), size, dropArea));
l->setWindowFlags(Qt::Tool | Qt::FramelessWindowHint);
l->setAttribute(Qt::WA_TranslucentBackground);
return l;
}
///////////////////////////////////////////////////////////////////////
DropOverlay::DropOverlay(QWidget* parent, eMode Mode) :
QFrame(parent),
_allowedAreas(InvalidDropArea),
_cross(new DropOverlayCross(this)),
_lastLocation(InvalidDropArea)
{
setWindowFlags(Qt::Tool | Qt::FramelessWindowHint);
setWindowOpacity(0.2);
setWindowTitle("DropOverlay");
setAttribute(Qt::WA_NoSystemBackground);
setAttribute(Qt::WA_TranslucentBackground);
QBoxLayout* l = new QBoxLayout(QBoxLayout::TopToBottom);
l->setSpacing(0);
setLayout(l);
_cross->setupOverlayCross(Mode);
_cross->setVisible(false);
setVisible(false);
}
DropOverlay::~DropOverlay()
{
}
void DropOverlay::setAllowedAreas(DropAreas areas)
{
if (areas == _allowedAreas)
return;
_allowedAreas = areas;
_cross->reset();
}
DropAreas DropOverlay::allowedAreas() const
{
return _allowedAreas;
}
DropArea DropOverlay::dropAreaUnderCursor() const
{
return _cross->cursorLocation();
}
DropArea DropOverlay::showDropOverlay(QWidget* target)
{
//std::cout << "DropOverlay::showDropOverlay(QWidget* target)" << std::endl;
if (_target == target)
{
qInfo() << "_target == target";
// Hint: We could update geometry of overlay here.
DropArea da = dropAreaUnderCursor();
if (da != _lastLocation)
{
qInfo() << "repaint()";
repaint();
_lastLocation = da;
}
return da;
}
_target = target;
_targetRect = QRect();
_lastLocation = InvalidDropArea;
// Move it over the target.
resize(target->size());
move(target->mapToGlobal(target->rect().topLeft()));
show();
return dropAreaUnderCursor();
}
void DropOverlay::showDropOverlay(QWidget* target, const QRect& targetAreaRect)
{
qInfo() << "DropOverlay::showDropOverlay(QWidget* target, const QRect& targetAreaRect)";
if (_target == target && _targetRect == targetAreaRect)
{
return;
}
//hideDropOverlay();
_target = target;
_targetRect = targetAreaRect;
_lastLocation = InvalidDropArea;
// Move it over the target's area.
resize(targetAreaRect.size());
move(target->mapToGlobal(QPoint(targetAreaRect.x(), targetAreaRect.y())));
show();
return;
}
void DropOverlay::hideDropOverlay()
{
qInfo() << "hideDropOverlay() _fullAreaDrop = false";
hide();
#if QT_VERSION >= QT_VERSION_CHECK(5, 0, 0)
_target.clear();
#else
_target = 0;
#endif
_targetRect = QRect();
_lastLocation = InvalidDropArea;
}
void DropOverlay::paintEvent(QPaintEvent*)
{
// Draw rect based on location
QRect r = rect();
const DropArea da = dropAreaUnderCursor();
std::cout << "CursorLocation: " << dropAreaUnderCursor() << std::endl;
switch (da)
{
case TopDropArea: r.setHeight(r.height() / 2); break;
case RightDropArea: r.setX(r.width() / 2); break;
case BottomDropArea: r.setY(r.height() / 2); break;
case LeftDropArea: r.setWidth(r.width() / 2); break;
case CenterDropArea: r = rect();break;
default: return;
}
QPainter painter(this);
QColor Color = palette().color(QPalette::Active, QPalette::Highlight);
painter.fillRect(r, QBrush(Color, Qt::Dense4Pattern));
painter.setBrush(QBrush(Color));
painter.drawRect(r);
}
void DropOverlay::showEvent(QShowEvent*)
{
_cross->show();
QWidget* w = parentWidget() ? parentWidget() : _target.data();
QRect WidgetRect = w->rect();
QPoint Pos(WidgetRect.left(), WidgetRect.center().y());
}
void DropOverlay::hideEvent(QHideEvent*)
{
_cross->hide();
}
void DropOverlay::resizeEvent(QResizeEvent* e)
{
qInfo() << "DropOverlay::resizeEvent" << e->size();
_cross->resize(e->size());
}
void DropOverlay::moveEvent(QMoveEvent* e)
{
qInfo() << "DropOverlay::moveEvent" << e->pos();
_cross->move(e->pos());
}
static int areaAlignment(const DropArea area)
{
switch (area)
{
case TopDropArea: return (int) Qt::AlignHCenter | Qt::AlignBottom;
case RightDropArea: return (int) Qt::AlignLeft | Qt::AlignVCenter;
case BottomDropArea: return (int) Qt::AlignHCenter | Qt::AlignTop;
case LeftDropArea: return (int) Qt::AlignRight | Qt::AlignVCenter;
case CenterDropArea: return (int) Qt::AlignCenter;
default: return Qt::AlignCenter;
}
}
QPoint DropOverlayCross::areaGridPosition(const DropArea area)
{
if (DropOverlay::ModeSectionOverlay == m_Mode)
{
switch (area)
{
case TopDropArea: return QPoint(1, 2);
case RightDropArea: return QPoint(2, 3);
case BottomDropArea: return QPoint(3, 2);
case LeftDropArea: return QPoint(2, 1);
case CenterDropArea: return QPoint(2, 2);
default: return QPoint();
}
}
else
{
switch (area)
{
case TopDropArea: return QPoint(0, 2);
case RightDropArea: return QPoint(2, 4);
case BottomDropArea: return QPoint(4, 2);
case LeftDropArea: return QPoint(2, 0);
case CenterDropArea: return QPoint(2, 2);
default: return QPoint();
}
}
}
DropOverlayCross::DropOverlayCross(DropOverlay* overlay) :
QWidget(overlay->parentWidget()),
m_DropOverlay(overlay)
{
setWindowFlags(Qt::Tool | Qt::FramelessWindowHint);
setWindowTitle("DropOverlayCross");
setAttribute(Qt::WA_TranslucentBackground);
m_GridLayout = new QGridLayout();
m_GridLayout->setSpacing(6);
setLayout(m_GridLayout);
}
DropOverlayCross::~DropOverlayCross()
{
}
void DropOverlayCross::setupOverlayCross(DropOverlay::eMode Mode)
{
m_Mode = Mode;
QHash<DropArea, QWidget*> areaWidgets;
areaWidgets.insert(TopDropArea, DropOverlay::createDropIndicatorWidget(TopDropArea));
areaWidgets.insert(RightDropArea, DropOverlay::createDropIndicatorWidget(RightDropArea));
areaWidgets.insert(BottomDropArea, DropOverlay::createDropIndicatorWidget(BottomDropArea));
areaWidgets.insert(LeftDropArea, DropOverlay::createDropIndicatorWidget(LeftDropArea));
areaWidgets.insert(CenterDropArea, DropOverlay::createDropIndicatorWidget(CenterDropArea));
setAreaWidgets(areaWidgets);
}
void DropOverlayCross::setAreaWidgets(const QHash<DropArea, QWidget*>& widgets)
{
// Delete old widgets.
QMutableHashIterator<DropArea, QWidget*> i(m_DropIndicatorWidgets);
while (i.hasNext())
{
i.next();
QWidget* widget = i.value();
m_GridLayout->removeWidget(widget);
delete widget;
i.remove();
}
// Insert new widgets into grid.
m_DropIndicatorWidgets = widgets;
QHashIterator<DropArea, QWidget*> i2(m_DropIndicatorWidgets);
while (i2.hasNext())
{
i2.next();
const DropArea area = i2.key();
QWidget* widget = i2.value();
QPoint p = areaGridPosition(area);
m_GridLayout->addWidget(widget, p.x(), p.y(), (Qt::Alignment) areaAlignment(area));
}
if (DropOverlay::ModeSectionOverlay == m_Mode)
{
m_GridLayout->setContentsMargins(0, 0, 0, 0);
m_GridLayout->setRowStretch(0, 1);
m_GridLayout->setRowStretch(1, 0);
m_GridLayout->setRowStretch(2, 0);
m_GridLayout->setRowStretch(3, 0);
m_GridLayout->setRowStretch(4, 1);
m_GridLayout->setColumnStretch(0, 1);
m_GridLayout->setColumnStretch(1, 0);
m_GridLayout->setColumnStretch(2, 0);
m_GridLayout->setColumnStretch(3, 0);
m_GridLayout->setColumnStretch(4, 1);
}
else
{
m_GridLayout->setContentsMargins(4, 4, 4, 4);
m_GridLayout->setRowStretch(0, 0);
m_GridLayout->setRowStretch(1, 1);
m_GridLayout->setRowStretch(2, 1);
m_GridLayout->setRowStretch(3, 1);
m_GridLayout->setRowStretch(4, 0);
m_GridLayout->setColumnStretch(0, 0);
m_GridLayout->setColumnStretch(1, 1);
m_GridLayout->setColumnStretch(2, 1);
m_GridLayout->setColumnStretch(3, 1);
m_GridLayout->setColumnStretch(4, 0);
}
reset();
}
DropArea DropOverlayCross::cursorLocation() const
{
const QPoint pos = mapFromGlobal(QCursor::pos());
QHashIterator<DropArea, QWidget*> i(m_DropIndicatorWidgets);
while (i.hasNext())
{
i.next();
if (m_DropOverlay->allowedAreas().testFlag(i.key())
&& i.value()
&& i.value()->isVisible()
&& i.value()->geometry().contains(pos))
{
return i.key();
}
}
return InvalidDropArea;
}
void DropOverlayCross::showEvent(QShowEvent*)
{
resize(m_DropOverlay->size());
move(m_DropOverlay->pos());
}
void DropOverlayCross::reset()
{
QList<DropArea> allAreas;
allAreas << TopDropArea << RightDropArea
<< BottomDropArea << LeftDropArea << CenterDropArea;
const DropAreas allowedAreas = m_DropOverlay->allowedAreas();
// Update visibility of area widgets based on allowedAreas.
for (int i = 0; i < allAreas.count(); ++i)
{
QPoint p = areaGridPosition(allAreas.at(i));
QLayoutItem* item = m_GridLayout->itemAtPosition(p.x(), p.y());
QWidget* w = nullptr;
if (item && (w = item->widget()) != nullptr)
{
w->setVisible(allowedAreas.testFlag(allAreas.at(i)));
}
}
}
} // namespace ads

View File

@ -1,120 +0,0 @@
#ifndef DROP_OVERLAY_H
#define DROP_OVERLAY_H
/*******************************************************************************
** QtAdcancedDockingSystem
** Copyright (C) 2017 Uwe Kindler
**
** This program is free software: you can redistribute it and/or modify
** it under the terms of the GNU General Public License as published by
** the Free Software Foundation, either version 3 of the License, or
** (at your option) any later version.
**
** This program is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
** GNU General Public License for more details.
**
** You should have received a copy of the GNU General Public License
** along with this program. If not, see <http://www.gnu.org/licenses/>.
******************************************************************************/
#include <QPointer>
#include <QHash>
#include <QRect>
#include <QFrame>
class QGridLayout;
#include "API.h"
namespace ads
{
class DropOverlayCross;
/*!
* DropOverlay paints a translucent rectangle over another widget. The geometry
* of the rectangle is based on the mouse location.
*/
class ADS_EXPORT_API DropOverlay : public QFrame
{
Q_OBJECT
friend class DropOverlayCross;
public:
enum eMode
{
ModeSectionOverlay,
ModeContainerOverlay
};
DropOverlay(QWidget* parent, eMode Mode = ModeSectionOverlay);
virtual ~DropOverlay();
void setAllowedAreas(DropAreas areas);
/**
* Returns flags with all allowed drop areas
*/
DropAreas allowedAreas() const;
/**
* Returns the drop area under the current cursor location
*/
DropArea dropAreaUnderCursor() const;
DropArea showDropOverlay(QWidget* target);
void showDropOverlay(QWidget* target, const QRect& targetAreaRect);
void hideDropOverlay();
/**
* Creates a drop indicator widget for the given drop area
*/
static QWidget* createDropIndicatorWidget(DropArea dropArea);
protected:
virtual void paintEvent(QPaintEvent *e);
virtual void showEvent(QShowEvent* e);
virtual void hideEvent(QHideEvent* e);
virtual void resizeEvent(QResizeEvent* e);
virtual void moveEvent(QMoveEvent* e);
private:
DropAreas _allowedAreas;
DropOverlayCross* _cross;
QPointer<QWidget> _target;
QRect _targetRect;
DropArea _lastLocation;
};
/*!
* DropOverlayCross shows a cross with 5 different drop area possibilities.
* I could have handled everything inside DropOverlay, but because of some
* styling issues it's better to have a separate class for the cross.
*/
class DropOverlayCross : public QWidget
{
Q_OBJECT
friend class DropOverlay;
public:
DropOverlayCross(DropOverlay* overlay);
virtual ~DropOverlayCross();
DropArea cursorLocation() const;
void setupOverlayCross(DropOverlay::eMode Mode);
protected:
virtual void showEvent(QShowEvent* e);
void setAreaWidgets(const QHash<DropArea, QWidget*>& widgets);
private:
void reset();
QPoint areaGridPosition(const DropArea area);
private:
DropOverlay::eMode m_Mode = DropOverlay::ModeSectionOverlay;
DropOverlay* m_DropOverlay;
QHash<DropArea, QWidget*> m_DropIndicatorWidgets;
QGridLayout* m_GridLayout;
};
} // namespace ads
#endif

View File

@ -1,422 +0,0 @@
/*******************************************************************************
** QtAdcancedDockingSystem
** Copyright (C) 2017 Uwe Kindler
**
** This program is free software: you can redistribute it and/or modify
** it under the terms of the GNU General Public License as published by
** the Free Software Foundation, either version 3 of the License, or
** (at your option) any later version.
**
** This program is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
** GNU General Public License for more details.
**
** You should have received a copy of the GNU General Public License
** along with this program. If not, see <http://www.gnu.org/licenses/>.
******************************************************************************/
#include "FloatingWidget.h"
#include <QBoxLayout>
#include <QPushButton>
#include <QSizePolicy>
#include <QMouseEvent>
#include <QStyle>
#include <QLabel>
#include <QGuiApplication>
#include "SectionTitleWidget.h"
#include "Internal.h"
#include "SectionWidget.h"
#include "ContainerWidget.h"
#include "MainContainerWidget.h"
#include "SectionContentWidget.h"
#include <iostream>
namespace ads
{
unsigned int FloatingWidget::zOrderCounter = 0;
CFloatingTitleWidget::CFloatingTitleWidget(SectionContent::Flags Flags, FloatingWidget* Parent)
: QFrame(Parent)
{
auto Layout = new QHBoxLayout();
QLabel* Label = new QLabel(this);
Label->setText("Floating Widget");
Label->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Expanding);
Label->setAlignment(Qt::AlignLeft);
Layout->addWidget(Label, 1, Qt::AlignLeft | Qt::AlignVCenter);
Layout->setSpacing(0);
setLayout(Layout);
if (Flags.testFlag(SectionContent::Maximizable))
{
QPushButton* Button = new QPushButton();
Button->setObjectName("maximizeButton");
Button->setFlat(true);
Button->setIcon(style()->standardIcon(QStyle::SP_TitleBarMaxButton));
Button->setToolTip(tr("Close"));
Button->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Preferred);
Layout->addWidget(Button);
connect(Button, SIGNAL(clicked(bool)), this, SLOT(onMaximizeButtonClicked()));
}
if (Flags.testFlag(SectionContent::Closeable))
{
QPushButton* closeButton = new QPushButton();
closeButton->setObjectName("closeButton");
closeButton->setFlat(true);
closeButton->setIcon(style()->standardIcon(QStyle::SP_TitleBarCloseButton));
closeButton->setToolTip(tr("Maximize"));
closeButton->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Preferred);
Layout->addWidget(closeButton);
connect(closeButton, SIGNAL(clicked(bool)), this, SIGNAL(closeButtonClicked()));
}
if (Flags == 0)
{
Layout->setContentsMargins(6, 6, 6, 6);
}
else
{
Layout->setContentsMargins(6, 0, 0, 0);
}
}
FloatingWidget* CFloatingTitleWidget::floatingWidget() const
{
return dynamic_cast<FloatingWidget*>(parentWidget());
}
CMainContainerWidget* CFloatingTitleWidget::mainContainerWidget() const
{
return floatingWidget()->mainContainerWidget();
}
void CFloatingTitleWidget::mousePressEvent(QMouseEvent* ev)
{
if (ev->button() == Qt::LeftButton)
{
ev->accept();
m_DragStartPosition = floatingWidget()->pos();
m_DragStartMousePosition = ev->globalPos();
return;
}
QFrame::mousePressEvent(ev);
}
void CFloatingTitleWidget::mouseReleaseEvent(QMouseEvent* ev)
{
}
void CFloatingTitleWidget::mouseMoveEvent(QMouseEvent* ev)
{
if (!(ev->buttons() & Qt::LeftButton))
{
QFrame::mouseMoveEvent(ev);
return;
}
floatingWidget()->updateDropOverlays(ev->globalPos());
ev->accept();
moveFloatingWidget(ev);
}
void CFloatingTitleWidget::moveFloatingWidget(QMouseEvent* ev)
{
const QPoint DragDistance = ev->globalPos() - m_DragStartMousePosition;
const QPoint moveToPos = m_DragStartPosition + DragDistance;
floatingWidget()->move(moveToPos);
}
void CFloatingTitleWidget::onMaximizeButtonClicked()
{
if (floatingWidget()->isMaximized())
{
floatingWidget()->showNormal();
}
else
{
floatingWidget()->showMaximized();
}
}
FloatingWidget::FloatingWidget(CMainContainerWidget* MainContainer, SectionContent::RefPtr sc, SectionTitleWidget* titleWidget, CSectionContentWidget* contentWidget, QWidget* parent) :
QWidget(MainContainer, Qt::Window),
m_MainContainerWidget(MainContainer)
{
QBoxLayout* l = new QBoxLayout(QBoxLayout::TopToBottom);
l->setContentsMargins(0, 0, 0, 0);
l->setSpacing(0);
setLayout(l);
m_ContainerWidget = new CContainerWidget(m_MainContainerWidget, this);
m_MainContainerWidget->m_Containers.append(m_ContainerWidget);
l->addWidget(m_ContainerWidget, 1);
InternalContentData data;
data.content = sc;
data.contentWidget = contentWidget;
data.titleWidget = titleWidget;
m_ContainerWidget->dropContent(data, nullptr, CenterDropArea);
m_ContainerWidget->show();
m_zOrderIndex = ++zOrderCounter;
m_MainContainerWidget->m_Floatings.append(this);
}
FloatingWidget::FloatingWidget(CMainContainerWidget* MainContainer, SectionWidget* sectionWidget)
: QWidget(MainContainer, Qt::Window),
m_MainContainerWidget(MainContainer)
{
QBoxLayout* l = new QBoxLayout(QBoxLayout::TopToBottom);
l->setContentsMargins(0, 0, 0, 0);
l->setSpacing(0);
setLayout(l);
m_ContainerWidget = new CContainerWidget(m_MainContainerWidget, this);
m_MainContainerWidget->m_Containers.append(m_ContainerWidget);
l->addWidget(m_ContainerWidget, 1);
m_ContainerWidget->addSectionWidget(sectionWidget);
m_ContainerWidget->show();
m_zOrderIndex = ++zOrderCounter;
m_MainContainerWidget->m_Floatings.append(this);
}
FloatingWidget::~FloatingWidget()
{
std::cout << "FloatingWidget::~FloatingWidget" << std::endl;
m_MainContainerWidget->m_Floatings.removeAll(this);
}
bool FloatingWidget::takeContent(InternalContentData& data)
{
// TODO remove takeContent function
/*data.content = _content;
data.titleWidget = _titleWidget;
data.contentWidget = _contentWidget;
//_titleLayout->removeWidget(_titleWidget);
_titleWidget->setParent(m_MainContainerWidget);
_titleWidget = NULL;
layout()->removeWidget(_contentWidget);
_contentWidget->setParent(m_MainContainerWidget);
_contentWidget = NULL;*/
return true;
}
void FloatingWidget::onCloseButtonClicked()
{
//m_MainContainerWidget->hideSectionContent(_content);
}
void FloatingWidget::setDraggingActive(bool Active)
{
if (m_DraggingActive == Active)
{
return;
}
m_DraggingActive = Active;
if (Active)
{
std::cout << "FloatingWidget:: InstallEventFilter" << std::endl;
qApp->installEventFilter(this);
}
else
{
std::cout << "FloatingWidget:: RemoveEventFilter" << std::endl;
qApp->removeEventFilter(this);
}
}
void FloatingWidget::changeEvent(QEvent *event)
{
QWidget::changeEvent(event);
if (event->type() == QEvent::ActivationChange && isActiveWindow())
{
std::cout << "FloatingWidget::changeEvent QEvent::ActivationChange " << std::endl;
m_zOrderIndex = ++zOrderCounter;
return;
}
}
void FloatingWidget::moveEvent(QMoveEvent *event)
{
QWidget::moveEvent(event);
if (m_DraggingActive && qApp->mouseButtons().testFlag(Qt::LeftButton))
{
//std::cout << "Dragging" << std::endl;
updateDropOverlays(QCursor::pos());
}
}
bool FloatingWidget::event(QEvent *e)
{
if ((e->type() == QEvent::NonClientAreaMouseButtonPress))
{
if (QGuiApplication::mouseButtons() == Qt::LeftButton)
{
std::cout << "FloatingWidget::event Event::NonClientAreaMouseButtonPress" << e->type() << std::endl;
setDraggingActive(true);
}
}
else if (e->type() == QEvent::NonClientAreaMouseButtonDblClick)
{
std::cout << "FloatingWidget::event QEvent::NonClientAreaMouseButtonDblClick" << std::endl;
setDraggingActive(false);
}
else if ((e->type() == QEvent::NonClientAreaMouseButtonRelease) && m_DraggingActive)
{
std::cout << "FloatingWidget::event QEvent::NonClientAreaMouseButtonRelease" << std::endl;
titleMouseReleaseEvent();
}
return QWidget::event(e);
}
bool FloatingWidget::eventFilter(QObject *watched, QEvent *event)
{
if (event->type() == QEvent::MouseButtonRelease)
{
std::cout << "FloatingWidget::eventFilter QEvent::MouseButtonRelease" << std::endl;
titleMouseReleaseEvent();
}
else if (event->type() == QEvent::MouseMove)
{
if (m_DraggingActive)
{
QMouseEvent* MouseEvent = dynamic_cast<QMouseEvent*>(event);
int BorderSize = (frameSize().width() - size().width()) / 2;
const QPoint moveToPos = QCursor::pos() - m_DragStartMousePosition - QPoint(BorderSize, 0);
move(moveToPos);
return true;
}
}
return false;
}
void FloatingWidget::startFloating(const QPoint& Pos)
{
setDraggingActive(true);
QPoint TargetPos = QCursor::pos() - Pos;
move(TargetPos);
show();
m_DragStartMousePosition = Pos;
m_DragStartPosition = this->pos();
}
void FloatingWidget::titleMouseReleaseEvent()
{
setDraggingActive(false);
if (!m_DropContainer)
{
return;
}
std::cout << "Dropped" << std::endl;
CMainContainerWidget* MainContainerWidget = mainContainerWidget();
m_DropContainer->dropFloatingWidget(this, QCursor::pos());
MainContainerWidget->dropOverlay()->hideDropOverlay();
MainContainerWidget->sectionDropOverlay()->hideDropOverlay();
}
unsigned int FloatingWidget::zOrderIndex() const
{
return m_zOrderIndex;
}
void FloatingWidget::updateDropOverlays(const QPoint& GlobalPos)
{
if (!isVisible())
{
return;
}
CMainContainerWidget* MainContainerWidget = mainContainerWidget();
auto Containers = MainContainerWidget->m_Containers;
CContainerWidget* TopContainer = nullptr;
for (auto ContainerWidget : Containers)
{
if (!ContainerWidget->isVisible())
{
continue;
}
if (containerWidget() == ContainerWidget)
{
continue;
}
QPoint MappedPos = ContainerWidget->mapFromGlobal(GlobalPos);
if (ContainerWidget->rect().contains(MappedPos))
{
std::cout << "Container " << ContainerWidget << " contains mousepos" << std::endl;
if (!TopContainer || ContainerWidget->isInFrontOf(TopContainer))
{
TopContainer = ContainerWidget;
}
}
}
m_DropContainer = TopContainer;
DropOverlay* ContainerDropOverlay = MainContainerWidget->dropOverlay();
DropOverlay* SectionDropOverlay = MainContainerWidget->sectionDropOverlay();
if (!TopContainer)
{
ContainerDropOverlay->hideDropOverlay();
SectionDropOverlay->hideDropOverlay();
return;
}
ContainerDropOverlay->showDropOverlay(TopContainer);
ContainerDropOverlay->raise();
SectionWidget* sectionwidget = TopContainer->sectionWidgetAt(GlobalPos);
if (sectionwidget)
{
SectionDropOverlay->setAllowedAreas(AllAreas);
SectionDropOverlay->showDropOverlay(sectionwidget);
}
else
{
SectionDropOverlay->hideDropOverlay();
}
if (TopContainer)
{
ContainerDropOverlay->showDropOverlay(TopContainer);
ContainerDropOverlay->raise();
}
else
{
ContainerDropOverlay->hideDropOverlay();
}
}
} // namespace ads

View File

@ -1,116 +0,0 @@
#ifndef FLOATINGWIDGET_H
#define FLOATINGWIDGET_H
/*******************************************************************************
** QtAdcancedDockingSystem
** Copyright (C) 2017 Uwe Kindler
**
** This program is free software: you can redistribute it and/or modify
** it under the terms of the GNU General Public License as published by
** the Free Software Foundation, either version 3 of the License, or
** (at your option) any later version.
**
** This program is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
** GNU General Public License for more details.
**
** You should have received a copy of the GNU General Public License
** along with this program. If not, see <http://www.gnu.org/licenses/>.
******************************************************************************/
#include <QWidget>
#include <QFrame>
class QBoxLayout;
#include "API.h"
#include "SectionContent.h"
namespace ads
{
class CMainContainerWidget;
class SectionTitleWidget;
class CSectionContentWidget;
class InternalContentData;
class SectionWidget;
class CContainerWidget;
class FloatingWidget;
class CFloatingTitleWidget : public QFrame
{
Q_OBJECT
private:
QPoint m_DragStartPosition;
QPoint m_DragStartMousePosition;
FloatingWidget* floatingWidget() const;
CMainContainerWidget* mainContainerWidget() const;
void moveFloatingWidget(QMouseEvent* ev);
private slots:
void onMaximizeButtonClicked();
protected:
virtual void mousePressEvent(QMouseEvent* ev);
virtual void mouseReleaseEvent(QMouseEvent* ev);
virtual void mouseMoveEvent(QMouseEvent* ev);
public:
CFloatingTitleWidget(SectionContent::Flags Flags, FloatingWidget* Parent);
signals:
void closeButtonClicked();
};
// 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
friend class CMainContainerWidget;
friend class CFloatingTitleWidget;
public:
FloatingWidget(CMainContainerWidget* container, SectionContent::RefPtr sc, SectionTitleWidget* titleWidget, CSectionContentWidget* contentWidget, QWidget* parent = NULL);
FloatingWidget(CMainContainerWidget* container, SectionWidget* sectionWidget);
virtual ~FloatingWidget();
/**
* Returns the current zOrderIndex
*/
unsigned int zOrderIndex() const;
CContainerWidget* containerWidget() const {return m_ContainerWidget;}
CMainContainerWidget* mainContainerWidget() const {return m_MainContainerWidget;}
public://private:
bool takeContent(InternalContentData& data);
void startFloating(const QPoint& Pos);
protected:
virtual void changeEvent(QEvent *event) override;
virtual void moveEvent(QMoveEvent *event) override;
virtual bool event(QEvent *e);
void titleMouseReleaseEvent();
virtual bool eventFilter(QObject *watched, QEvent *event) override;
void updateDropOverlays(const QPoint& GlobalPos);
private slots:
void onCloseButtonClicked();
private:
void setDraggingActive(bool Active);
CMainContainerWidget* m_MainContainerWidget;
CContainerWidget* m_ContainerWidget;
CContainerWidget* m_DropContainer;
bool m_DraggingActive = false;
unsigned int m_zOrderIndex = 0;
QPoint m_DragStartPosition;
QPoint m_DragStartMousePosition;
static unsigned int zOrderCounter;
};
} // namespace ads
#endif

View File

@ -1,34 +0,0 @@
/*******************************************************************************
** QtAdcancedDockingSystem
** Copyright (C) 2017 Uwe Kindler
**
** This program is free software: you can redistribute it and/or modify
** it under the terms of the GNU General Public License as published by
** the Free Software Foundation, either version 3 of the License, or
** (at your option) any later version.
**
** This program is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
** GNU General Public License for more details.
**
** You should have received a copy of the GNU General Public License
** along with this program. If not, see <http://www.gnu.org/licenses/>.
******************************************************************************/
#include "Internal.h"
namespace ads
{
InternalContentData::InternalContentData() :
titleWidget(NULL),
contentWidget(NULL)
{
}
InternalContentData::~InternalContentData()
{
}
} // namespace ads

View File

@ -1,62 +0,0 @@
#ifndef ADS_INTERNAL_HEADER
#define ADS_INTERNAL_HEADER
/*******************************************************************************
** QtAdcancedDockingSystem
** Copyright (C) 2017 Uwe Kindler
**
** This program is free software: you can redistribute it and/or modify
** it under the terms of the GNU General Public License as published by
** the Free Software Foundation, either version 3 of the License, or
** (at your option) any later version.
**
** This program is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
** GNU General Public License for more details.
**
** You should have received a copy of the GNU General Public License
** along with this program. If not, see <http://www.gnu.org/licenses/>.
******************************************************************************/
#include <QSharedPointer>
#include <QWeakPointer>
#include "API.h"
namespace ads
{
class SectionContent;
class SectionTitleWidget;
class CSectionContentWidget;
class InternalContentData
{
public:
typedef QSharedPointer<InternalContentData> RefPtr;
typedef QWeakPointer<InternalContentData> WeakPtr;
InternalContentData();
~InternalContentData();
QSharedPointer<SectionContent> content;
SectionTitleWidget* titleWidget;
CSectionContentWidget* contentWidget;
};
class HiddenSectionItem
{
public:
HiddenSectionItem() :
preferredSectionId(-1),
preferredSectionIndex(-1)
{}
int preferredSectionId;
int preferredSectionIndex;
InternalContentData data;
};
} // namespace ads
#endif

File diff suppressed because it is too large Load Diff

View File

@ -1,189 +0,0 @@
#ifndef ADS_CONTAINERWIDGET_H
#define ADS_CONTAINERWIDGET_H
/*******************************************************************************
** QtAdcancedDockingSystem
** Copyright (C) 2017 Uwe Kindler
**
** This program is free software: you can redistribute it and/or modify
** it under the terms of the GNU General Public License as published by
** the Free Software Foundation, either version 3 of the License, or
** (at your option) any later version.
**
** This program is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
** GNU General Public License for more details.
**
** You should have received a copy of the GNU General Public License
** along with this program. If not, see <http://www.gnu.org/licenses/>.
******************************************************************************/
#include <QList>
#include <QHash>
#include <QPointer>
#include <QFrame>
#include <QGridLayout>
#include <QSplitter>
class QPoint;
class QMenu;
#include "API.h"
#include "Internal.h"
#include "SectionContent.h"
#include "FloatingWidget.h"
#include "Serialization.h"
#include "DropOverlay.h"
#include "ContainerWidget.h"
namespace ads
{
class SectionWidget;
class DropOverlay;
class InternalContentData;
class CSectionContentWidget;
/*!
* ContainerWidget is the main container to provide the docking
* functionality. It manages multiple sections with all possible areas.
*/
class ADS_EXPORT_API CMainContainerWidget : public CContainerWidget
{
Q_OBJECT
friend class SectionContent;
friend class SectionWidget;
friend class FloatingWidget;
friend class SectionTitleWidget;
friend class ContainerWidgetPrivate;
friend class CFloatingTitleWidget;
friend class CContainerWidget;
friend class CSectionContentWidget;
public:
explicit CMainContainerWidget(QWidget *parent = nullptr);
virtual ~CMainContainerWidget();
//
// Public API
//
/*!
* Completely removes the <em>sc</em> from this ContainerWidget.
* This container will no longer hold a reference to the content.
* The content can be safely deleted.
*/
bool removeSectionContent(const SectionContent::RefPtr& sc);
/*!
* Shows the specific SectionContent in UI.
* Independed of the current state, whether it is used inside a section or is floating.
*/
bool showSectionContent(const SectionContent::RefPtr& sc);
/*!
* Closes the specified SectionContent from UI.
* Independed of the current state, whether it is used inside a section or is floating.
*/
bool hideSectionContent(const SectionContent::RefPtr& sc);
/*!
* Selects the specific SectionContent as current, if it is part of a SectionWidget.
* If SC is floating, it does nothing (or should we show it?)
*/
bool raiseSectionContent(const SectionContent::RefPtr& sc);
/*!
* Indicates whether the SectionContent <em>sc</em> is visible.
*/
bool isSectionContentVisible(const SectionContent::RefPtr& sc);
/*!
* Creates a QMenu based on available SectionContents.
* The caller is responsible to delete the menu.
*/
QMenu* createContextMenu() const;
/*!
* Serializes the current state of contents and returns it as a plain byte array.
* \see restoreState(const QByteArray&)
*/
QByteArray saveState() const;
/*!
* Deserilizes the state of contents from <em>data</em>, which was written with <em>saveState()</em>.
* \see saveState()
*/
bool restoreState(const QByteArray& data);
//
// Advanced Public API
// You usually should not need access to this methods
//
/*!
* \brief contents
* \return List of known SectionContent for this ContainerWidget.
*/
QList<SectionContent::RefPtr> contents() const;
/**
* Access function for the section drop overlay
*/
QPointer<DropOverlay> sectionDropOverlay() const;
QPointer<DropOverlay> dropOverlay() const;
static QSplitter* newSplitter(Qt::Orientation orientation = Qt::Horizontal, QWidget* parent = 0);
virtual unsigned int zOrderIndex() const {return 0;}
private:
// Serialization
QByteArray saveHierarchy() const;
void saveFloatingWidgets(QDataStream& out) const;
void saveSectionWidgets(QDataStream& out, QWidget* widget) const;
bool saveSectionIndex(SectionIndexData &sid) const;
bool restoreHierarchy(const QByteArray& data);
bool restoreFloatingWidgets(QDataStream& in, int version, QList<FloatingWidget*>& floatings);
bool restoreSectionWidgets(QDataStream& in, int version, QSplitter* currentSplitter, QList<SectionWidget*>& sections, QList<SectionContent::RefPtr>& contentsToHide);
bool takeContent(const SectionContent::RefPtr& sc, InternalContentData& data);
void hideContainerOverlay();
void moveFloatingWidget(const QPoint& TargetPos);
private slots:
void onActionToggleSectionContentVisibility(bool visible);
signals:
void orientationChanged();
/*!
* Emits whenever the visibility of a SectionContent changes.
* \see showSectionContent(), hideSectionContent()
* \since 0.2
*/
void sectionContentVisibilityChanged(const SectionContent::RefPtr& sc, bool visible);
private:
QList<FloatingWidget*> m_Floatings;
QList<CContainerWidget*> m_Containers;
QHash<int, HiddenSectionItem> m_HiddenSectionContents;
// Helper lookup maps, restricted to this container.
QHash<int, SectionContent::WeakPtr> m_SectionContentIdMap;
QHash<QString, SectionContent::WeakPtr> m_SectionContentNameMap;
QHash<int, SectionWidget*> m_SectionWidgetIdMap;
QHash<int, CSectionContentWidget*> m_SectionContentWidgetIdMap;
QHash<QString, CSectionContentWidget*> m_SectionContentWidgetNameMap;
QPointer<DropOverlay> m_ContainerDropOverlay;
QPointer<DropOverlay> m_SectionDropOverlay;
};
} // namespace ads
#endif

View File

@ -1,140 +0,0 @@
/*******************************************************************************
** QtAdcancedDockingSystem
** Copyright (C) 2017 Uwe Kindler
**
** This program is free software: you can redistribute it and/or modify
** it under the terms of the GNU General Public License as published by
** the Free Software Foundation, either version 3 of the License, or
** (at your option) any later version.
**
** This program is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
** GNU General Public License for more details.
**
** You should have received a copy of the GNU General Public License
** along with this program. If not, see <http://www.gnu.org/licenses/>.
******************************************************************************/
#include "MainContainerWidget.h"
#include "SectionContent.h"
#include <QWidget>
#include <QLabel>
#include "Internal.h"
namespace ads
{
SectionContent::SectionContent() :
_uid(GetNextUid()),
_flags(AllFlags)
{
}
SectionContent::RefPtr SectionContent::newSectionContent(const QString& uniqueName, CMainContainerWidget* container, QWidget* title, QWidget* content)
{
auto SectionContentNameMap = container->m_SectionContentNameMap;
auto SectionContentIdMap = container->m_SectionContentIdMap;
if (uniqueName.isEmpty())
{
qFatal("Can not create SectionContent with empty uniqueName");
return RefPtr();
}
else if (SectionContentNameMap.contains(uniqueName))
{
qFatal("Can not create SectionContent with already used uniqueName");
return RefPtr();
}
else if (!container || !title || !content)
{
qFatal("Can not create SectionContent with NULL values");
return RefPtr();
}
QSharedPointer<SectionContent> sc(new SectionContent());
sc->_uniqueName = uniqueName;
sc->m_MainContainerWidget = container;
sc->m_TitleWidgetContent = title;
sc->m_ContentWidget = content;
SectionContentIdMap.insert(sc->uid(), sc);
SectionContentNameMap.insert(sc->uniqueName(), sc);
return sc;
}
SectionContent::~SectionContent()
{
auto SectionContentNameMap = m_MainContainerWidget->m_SectionContentNameMap;
auto SectionContentIdMap = m_MainContainerWidget->m_SectionContentIdMap;
if (m_MainContainerWidget)
{
SectionContentIdMap.remove(_uid);
SectionContentNameMap.remove(_uniqueName);
}
delete m_TitleWidgetContent;
delete m_ContentWidget;
}
int SectionContent::uid() const
{
return _uid;
}
QString SectionContent::uniqueName() const
{
return _uniqueName;
}
CMainContainerWidget* SectionContent::containerWidget() const
{
return m_MainContainerWidget;
}
QWidget* SectionContent::titleWidgetContent() const
{
return m_TitleWidgetContent;
}
QWidget* SectionContent::contentWidget() const
{
return m_ContentWidget;
}
SectionContent::Flags SectionContent::flags() const
{
return _flags;
}
QString SectionContent::visibleTitle() const
{
if (_title.isEmpty())
return _uniqueName;
return _title;
}
QString SectionContent::title() const
{
return _title;
}
void SectionContent::setTitle(const QString& title)
{
_title = title;
}
void SectionContent::setFlags(const Flags f)
{
_flags = f;
}
int SectionContent::GetNextUid()
{
static int NextUid = 0;
return ++NextUid;
}
} // namespace ads

View File

@ -1,99 +0,0 @@
#ifndef SECTIONCONTENT_H
#define SECTIONCONTENT_H
/*******************************************************************************
** QtAdcancedDockingSystem
** Copyright (C) 2017 Uwe Kindler
**
** This program is free software: you can redistribute it and/or modify
** it under the terms of the GNU General Public License as published by
** the Free Software Foundation, either version 3 of the License, or
** (at your option) any later version.
**
** This program is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
** GNU General Public License for more details.
**
** You should have received a copy of the GNU General Public License
** along with this program. If not, see <http://www.gnu.org/licenses/>.
******************************************************************************/
#include <QSharedPointer>
#include <QWeakPointer>
#include <QPointer>
class QWidget;
#include "API.h"
namespace ads
{
class CMainContainerWidget;
class ADS_EXPORT_API SectionContent
{
friend class CMainContainerWidget;
private:
SectionContent();
SectionContent(const SectionContent&);
SectionContent& operator=(const SectionContent&);
public:
typedef QSharedPointer<SectionContent> RefPtr;
typedef QWeakPointer<SectionContent> WeakPtr;
enum Flag
{
None = 0,
Closeable = 1,
Maximizable = 2,
AllFlags = Closeable | Maximizable
};
Q_DECLARE_FLAGS(Flags, Flag)
/*!
* Creates new content, associates it to <em>container</em> and takes ownership of
* <em>title</em>- and <em>content</em>- widgets.
* \param uniqueName An unique identifier across the entire process.
* \param container The parent ContainerWidget in which this content will be active.
* \param title The widget to use as title.
* \param content The widget to use as content.
* \return May return a invalid ref-pointer in case of invalid parameters.
*/
static RefPtr newSectionContent(const QString& uniqueName, CMainContainerWidget* container, QWidget* title, QWidget* content);
virtual ~SectionContent();
int uid() const;
QString uniqueName() const;
CMainContainerWidget* containerWidget() const;
QWidget* titleWidgetContent() const;
QWidget* contentWidget() const;
Flags flags() const;
QString visibleTitle() const;
QString title() const;
void setTitle(const QString& title);
void setFlags(const Flags f);
private:
const int _uid;
QString _uniqueName;
QPointer<CMainContainerWidget> m_MainContainerWidget;
QPointer<QWidget> m_TitleWidgetContent;
QPointer<QWidget> m_ContentWidget;
// Optional attributes
QString _title;
Flags _flags;
/* Note: This method could be a problem in static build environment
* since it may begin with 0 for every module which uses ADS.
*/
static int GetNextUid();
};
} // namespace ads
#endif

View File

@ -1,167 +0,0 @@
/*******************************************************************************
** QtAdcancedDockingSystem
** Copyright (C) 2017 Uwe Kindler
**
** This program is free software: you can redistribute it and/or modify
** it under the terms of the GNU General Public License as published by
** the Free Software Foundation, either version 3 of the License, or
** (at your option) any later version.
**
** This program is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
** GNU General Public License for more details.
**
** You should have received a copy of the GNU General Public License
** along with this program. If not, see <http://www.gnu.org/licenses/>.
******************************************************************************/
#include "MainContainerWidget.h"
#include <QBoxLayout>
#include "SectionContentWidget.h"
#include "SectionTitleWidget.h"
namespace ads
{
struct SectionContentWidgetPrivate
{
CSectionContentWidget* _this;
int Uid;
QString UniqueName;
QPointer<CMainContainerWidget> MainContainerWidget;
QPointer<QWidget> TitleWidgetContent;
QPointer<QWidget> ContentWidget;
// Optional attributes
QString Title;
CSectionContentWidget::Flags Flags = CSectionContentWidget::AllFlags;
/* Note: This method could be a problem in static build environment
* since it may begin with 0 for every module which uses ADS.
*/
static int GetNextUid()
{
static int NextUid = 0;
return ++NextUid;
}
SectionContentWidgetPrivate(CSectionContentWidget* _public)
: _this(_public),
Uid(GetNextUid())
{
}
};
CSectionContentWidget::CSectionContentWidget(SectionContent::RefPtr c, QWidget* parent) :
QFrame(parent),
d(new SectionContentWidgetPrivate(this)),
_content(c)
{
QBoxLayout* l = new QBoxLayout(QBoxLayout::TopToBottom);
l->setContentsMargins(0, 0, 0, 0);
l->setSpacing(0);
l->addWidget(_content->contentWidget());
setLayout(l);
}
CSectionContentWidget* CSectionContentWidget::newSectionContent(const QString& uniqueName,
CMainContainerWidget* container, QWidget* title, QWidget* content)
{
auto SectionContentNameMap = container->m_SectionContentNameMap;
auto SectionContentIdMap = container->m_SectionContentIdMap;
if (uniqueName.isEmpty())
{
qFatal("Can not create SectionContent with empty uniqueName");
return nullptr;
}
else if (SectionContentNameMap.contains(uniqueName))
{
qFatal("Can not create SectionContent with already used uniqueName");
return nullptr;
}
else if (!container || !title || !content)
{
qFatal("Can not create SectionContent with NULL values");
return nullptr;
}
CSectionContentWidget* sc(new CSectionContentWidget());
sc->d->UniqueName = uniqueName;
sc->d->MainContainerWidget = container;
sc->d->TitleWidgetContent = title;
sc->d->ContentWidget = content;
container->m_SectionContentWidgetIdMap.insert(sc->uid(), sc);
container->m_SectionContentWidgetNameMap.insert(sc->uniqueName(), sc);
return sc;
}
CSectionContentWidget::~CSectionContentWidget()
{
layout()->removeWidget(_content->contentWidget());
delete d;
}
int CSectionContentWidget::uid() const
{
return d->Uid;
}
QString CSectionContentWidget::uniqueName() const
{
return d->UniqueName;
}
CMainContainerWidget* CSectionContentWidget::containerWidget() const
{
return d->MainContainerWidget;
}
QWidget* CSectionContentWidget::titleWidgetContent() const
{
return d->TitleWidgetContent.data();
}
QWidget* CSectionContentWidget::contentWidget() const
{
return d->ContentWidget;
}
CSectionContentWidget::Flags CSectionContentWidget::flags() const
{
return d->Flags;
}
QString CSectionContentWidget::visibleTitle() const
{
return d->Title.isEmpty() ? d->UniqueName : d->Title;
}
QString CSectionContentWidget::title() const
{
return d->Title;
}
void CSectionContentWidget::setTitle(const QString& title)
{
d->Title = title;
}
void CSectionContentWidget::setFlags(const Flags f)
{
d->Flags = f;
}
} // namespace ads

View File

@ -1,85 +0,0 @@
#ifndef SECTION_CONTENT_WIDGET_H
#define SECTION_CONTENT_WIDGET_H
/*******************************************************************************
** QtAdcancedDockingSystem
** Copyright (C) 2017 Uwe Kindler
**
** This program is free software: you can redistribute it and/or modify
** it under the terms of the GNU General Public License as published by
** the Free Software Foundation, either version 3 of the License, or
** (at your option) any later version.
**
** This program is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
** GNU General Public License for more details.
**
** You should have received a copy of the GNU General Public License
** along with this program. If not, see <http://www.gnu.org/licenses/>.
******************************************************************************/
#include <QFrame>
#include "API.h"
#include "SectionContent.h"
namespace ads
{
class CMainContainerWidget;
class SectionWidget;
class SectionTitleWidget;
struct SectionContentWidgetPrivate;
class CSectionContentWidget : public QFrame
{
Q_OBJECT
private:
SectionContentWidgetPrivate* d;
friend class SectionContentWidgetPrivate;
friend class CMainContainerWidget;
public:
enum Flag
{
None = 0,
Closeable = 1,
Maximizable = 2,
AllFlags = Closeable | Maximizable
};
Q_DECLARE_FLAGS(Flags, Flag)
CSectionContentWidget(SectionContent::RefPtr c = SectionContent::RefPtr(), QWidget* parent = 0);
virtual ~CSectionContentWidget();
/*!
* Creates new content, associates it to <em>container</em> and takes ownership of
* <em>title</em>- and <em>content</em>- widgets.
* \param uniqueName An unique identifier across the entire process.
* \param container The parent ContainerWidget in which this content will be active.
* \param title The widget to use as title.
* \param content The widget to use as content.
* \return May return a invalid ref-pointer in case of invalid parameters.
*/
static CSectionContentWidget* newSectionContent(const QString& uniqueName,
CMainContainerWidget* container, QWidget* title, QWidget* content);
int uid() const;
QString uniqueName() const;
CMainContainerWidget* containerWidget() const;
QWidget* titleWidgetContent() const;
QWidget* contentWidget() const;
Flags flags() const;
QString visibleTitle() const;
QString title() const;
void setTitle(const QString& title);
void setFlags(const Flags f);
private:
SectionContent::RefPtr _content;
};
} // namespace ads
#endif

View File

@ -1,290 +0,0 @@
/*******************************************************************************
** QtAdcancedDockingSystem
** Copyright (C) 2017 Uwe Kindler
**
** This program is free software: you can redistribute it and/or modify
** it under the terms of the GNU General Public License as published by
** the Free Software Foundation, either version 3 of the License, or
** (at your option) any later version.
**
** This program is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
** GNU General Public License for more details.
**
** You should have received a copy of the GNU General Public License
** along with this program. If not, see <http://www.gnu.org/licenses/>.
******************************************************************************/
#include "MainContainerWidget.h"
#include "SectionTitleWidget.h"
#include <QString>
#include <QApplication>
#include <QBoxLayout>
#include <QMouseEvent>
#include <QMimeData>
#include <QDrag>
#include <QCursor>
#include <QStyle>
#include <QSplitter>
#include <QPushButton>
#include <iostream>
#include "Internal.h"
#include "DropOverlay.h"
#include "SectionContent.h"
#include "SectionWidget.h"
#include "FloatingWidget.h"
#include <iostream>
namespace ads
{
SectionTitleWidget::SectionTitleWidget(SectionContent::RefPtr content, QWidget* parent) :
QFrame(parent),
m_Content(content),
m_TabMoving(false),
m_IsActiveTab(false)
{
QBoxLayout* l = new QBoxLayout(QBoxLayout::LeftToRight);
l->setContentsMargins(0, 0, 0, 0);
l->setSpacing(0);
l->addWidget(content->titleWidgetContent());
setLayout(l);
}
SectionTitleWidget::~SectionTitleWidget()
{
layout()->removeWidget(m_Content->titleWidgetContent());
}
bool SectionTitleWidget::isActiveTab() const
{
return m_IsActiveTab;
}
void SectionTitleWidget::setActiveTab(bool active)
{
if (active != m_IsActiveTab)
{
m_IsActiveTab = active;
style()->unpolish(this);
style()->polish(this);
update();
emit activeTabChanged();
}
}
void SectionTitleWidget::mousePressEvent(QMouseEvent* ev)
{
if (ev->button() == Qt::LeftButton)
{
ev->accept();
m_DragStartMousePosition = ev->pos();
m_DragStartGlobalMousePosition = ev->globalPos();
m_DragStartPosition = mapToGlobal(this->pos());
return;
}
QFrame::mousePressEvent(ev);
}
CContainerWidget* findParentContainerWidget(QWidget* w)
{
CContainerWidget* cw = 0;
QWidget* next = w;
do
{
if ((cw = dynamic_cast<CContainerWidget*>(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;
}
void SectionTitleWidget::mouseReleaseEvent(QMouseEvent* ev)
{
SectionWidget* section = nullptr;
CContainerWidget* cw = findParentContainerWidget(this);
CMainContainerWidget* mcw = cw->mainContainerWidget();
std::cout << "SectionTitleWidget::mouseReleaseEvent" << std::endl;
//m_FloatingWidget.clear();
// End of tab moving, change order now
if (m_TabMoving && (section = findParentSectionWidget(this)) != nullptr)
{
// Find tab under mouse
QPoint pos = ev->globalPos();
pos = section->mapFromGlobal(pos);
int fromIndex = section->indexOfContent(m_Content);
int toIndex = section->indexOfContentByTitlePos(pos, this);
qInfo() << "fromIndex: " << fromIndex << " toIndex: " << toIndex;
if (-1 == toIndex)
{
toIndex = section->indexOfContent(section->contents().last());
}
section->moveContent(fromIndex, toIndex);
}
if (!m_DragStartMousePosition.isNull())
{
emit clicked();
}
// Reset
m_DragStartMousePosition = QPoint();
m_TabMoving = false;
mcw->m_SectionDropOverlay->hideDropOverlay();
mcw->hideContainerOverlay();
QFrame::mouseReleaseEvent(ev);
}
void SectionTitleWidget::startFloating(QMouseEvent* ev, CMainContainerWidget* cw, SectionWidget* sectionwidget)
{
std::cout << "SectionTitleWidget::startFloating" << std::endl;
FloatingWidget* fw;
if (sectionwidget->contentCount() > 1)
{
// If section widget has multiple tabs, we take only one tab
InternalContentData data;
if (!sectionwidget->takeContent(m_Content->uid(), data))
{
qWarning() << "THIS SHOULD NOT HAPPEN!!" << m_Content->uid();
return;
}
fw = new FloatingWidget(cw, data.content, data.titleWidget, data.contentWidget, cw);
}
else
{
// If section widget has only one content widget, we can move the complete
// section widget into floating widget
QSplitter* splitter = findParentSplitter(sectionwidget);
fw = new FloatingWidget(cw, sectionwidget);
if (splitter && splitter->count() == 1)
{
// if splitter contains only one section widget, then we can
// remove the splitter and replace it with the section widget
std::cout << "splitter->count() == 1" << std::endl;
SectionWidget* sectionwidget = dynamic_cast<SectionWidget*>(splitter->widget(0));
QSplitter* parentSplitter = dynamic_cast<QSplitter*>(splitter->parentWidget());
if (parentSplitter)
{
sectionwidget->setParent(0);
int index = parentSplitter->indexOf(splitter);
splitter->setParent(0);
parentSplitter->insertWidget(index, sectionwidget);
delete splitter;
std::cout << "Index of splitter " << index << std::endl;
}
}
}
fw->resize(sectionwidget->size());
fw->setObjectName("FloatingWidget");
fw->startFloating(m_DragStartMousePosition);
// Delete old section, if it is empty now.
if (sectionwidget->contents().isEmpty())
{
delete sectionwidget;
sectionwidget = NULL;
}
deleteEmptySplitter(cw);
DropOverlay* ContainerDropOverlay = cw->dropOverlay();
ContainerDropOverlay->setAllowedAreas(OuterAreas);
ContainerDropOverlay->showDropOverlay(this);
ContainerDropOverlay->raise();
}
void SectionTitleWidget::moveTab(QMouseEvent* ev)
{
ev->accept();
int left, top, right, bottom;
getContentsMargins(&left, &top, &right, &bottom);
QPoint moveToPos = mapToParent(ev->pos()) - m_DragStartMousePosition;
moveToPos.setY(0/* + top*/);
move(moveToPos);
}
void SectionTitleWidget::mouseMoveEvent(QMouseEvent* ev)
{
std::cout << "SectionTitleWidget::mouseMoveEvent" << std::endl;
if (!(ev->buttons() & Qt::LeftButton))
{
QFrame::mouseMoveEvent(ev);
return;
}
// TODO make a member with the main container widget and assign it on
// creation
CMainContainerWidget* MainContainerWidget = findParentContainerWidget(this)->mainContainerWidget();
ev->accept();
SectionWidget* sectionwidget = findParentSectionWidget(this);
if (!sectionwidget)
{
QFrame::mouseMoveEvent(ev);
return;
}
// move tab
if (m_TabMoving)
{
moveTab(ev);
}
// leave if dragging is not active
if (m_DragStartMousePosition.isNull())
{
QFrame::mouseMoveEvent(ev);
return;
}
// Begin to drag/float the SectionContent.
if (!sectionwidget->titleAreaGeometry().contains(sectionwidget->mapFromGlobal(ev->globalPos())))
{
startFloating(ev, MainContainerWidget, sectionwidget);
return;
}
// Begin to drag title inside the title area to switch its position inside the SectionWidget.
else if ((ev->pos() - m_DragStartMousePosition).manhattanLength() >= QApplication::startDragDistance() // Wait a few pixels before start moving
&& sectionwidget->titleAreaGeometry().contains(sectionwidget->mapFromGlobal(ev->globalPos())))
{
m_TabMoving = true;
//raise(); // Raise current title-widget above other tabs
return;
}
QFrame::mouseMoveEvent(ev);
}
} // namespace ads

View File

@ -1,80 +0,0 @@
#ifndef SECTION_TITLE_WIDGET_H
#define SECTION_TITLE_WIDGET_H
/*******************************************************************************
** QtAdcancedDockingSystem
** Copyright (C) 2017 Uwe Kindler
**
** This program is free software: you can redistribute it and/or modify
** it under the terms of the GNU General Public License as published by
** the Free Software Foundation, either version 3 of the License, or
** (at your option) any later version.
**
** This program is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
** GNU General Public License for more details.
**
** You should have received a copy of the GNU General Public License
** along with this program. If not, see <http://www.gnu.org/licenses/>.
******************************************************************************/
#include <QPointer>
#include <QPoint>
#include <QFrame>
#include "API.h"
#include "SectionContent.h"
class QPushButton;
namespace ads
{
class CMainContainerWidget;
class SectionWidget;
class FloatingWidget;
class SectionTitleWidget : public QFrame
{
Q_OBJECT
Q_PROPERTY(bool activeTab READ isActiveTab WRITE setActiveTab NOTIFY activeTabChanged)
friend class CMainContainerWidget;
friend class SectionWidget;
friend class CContainerWidget;
SectionContent::RefPtr m_Content;
// Drag & Drop (Floating)
QPoint m_DragStartMousePosition;
QPoint m_DragStartGlobalMousePosition;
QPoint m_DragStartPosition;
// Drag & Drop (Title/Tabs)
bool m_TabMoving;
// Property values
bool m_IsActiveTab;
public:
SectionTitleWidget(SectionContent::RefPtr content, QWidget* parent);
virtual ~SectionTitleWidget();
bool isActiveTab() const;
void setActiveTab(bool active);
protected:
virtual void mousePressEvent(QMouseEvent* ev);
virtual void mouseReleaseEvent(QMouseEvent* ev);
virtual void mouseMoveEvent(QMouseEvent* ev);
private:
void startFloating(QMouseEvent* ev, CMainContainerWidget* cw, SectionWidget* sectionwidget);
void moveTab(QMouseEvent* ev);
signals:
void activeTabChanged();
void clicked();
};
} // namepsace ads
#endif

View File

@ -1,495 +0,0 @@
/*******************************************************************************
** QtAdcancedDockingSystem
** Copyright (C) 2017 Uwe Kindler
**
** This program is free software: you can redistribute it and/or modify
** it under the terms of the GNU General Public License as published by
** the Free Software Foundation, either version 3 of the License, or
** (at your option) any later version.
**
** This program is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
** GNU General Public License for more details.
**
** You should have received a copy of the GNU General Public License
** along with this program. If not, see <http://www.gnu.org/licenses/>.
******************************************************************************/
#include "SectionWidget.h"
#include <QApplication>
#include <QBoxLayout>
#include <QStackedLayout>
#include <QMouseEvent>
#include <QWheelEvent>
#include <QDragEnterEvent>
#include <QMimeData>
#include <QPainter>
#include <QStyle>
#include <QSplitter>
#include <QPushButton>
#include <QScrollBar>
#include <QMenu>
#include <QtGlobal>
#include <QTabBar>
#include <iostream>
#include "Internal.h"
#include "DropOverlay.h"
#include "SectionContent.h"
#include "SectionTitleWidget.h"
#include "SectionContentWidget.h"
#include "FloatingWidget.h"
#include "MainContainerWidget.h"
namespace ads
{
SectionWidget::SectionWidget(CMainContainerWidget* MainContainer, CContainerWidget* parent) :
QFrame(parent),
_uid(GetNextUid()),
m_MainContainerWidget(MainContainer),
_tabsLayout(NULL),
_tabsLayoutInitCount(0),
_contentsLayout(NULL),
_mousePressTitleWidget(NULL)
{
QBoxLayout* l = new QBoxLayout(QBoxLayout::TopToBottom);
l->setContentsMargins(0, 0, 0, 0);
l->setSpacing(0);
setLayout(l);
/* top area with tabs and close button */
_topLayout = new QBoxLayout(QBoxLayout::LeftToRight);
_topLayout->setContentsMargins(0, 0, 0, 0);
_topLayout->setSpacing(0);
l->addLayout(_topLayout);
_tabsScrollArea = new SectionWidgetTabsScrollArea(this);
_topLayout->addWidget(_tabsScrollArea, 1);
_tabsContainerWidget = new QWidget();
_tabsContainerWidget->setObjectName("tabsContainerWidget");
_tabsScrollArea->setWidget(_tabsContainerWidget);
_tabsLayout = new QBoxLayout(QBoxLayout::LeftToRight);
_tabsLayout->setContentsMargins(0, 0, 0, 0);
_tabsLayout->setSpacing(0);
_tabsLayout->addStretch(1);
_tabsContainerWidget->setLayout(_tabsLayout);
_tabsMenuButton = new QPushButton();
_tabsMenuButton->setObjectName("tabsMenuButton");
_tabsMenuButton->setFlat(true);
_tabsMenuButton->setIcon(style()->standardIcon(QStyle::SP_TitleBarUnshadeButton));
_tabsMenuButton->setMaximumWidth(_tabsMenuButton->iconSize().width());
_topLayout->addWidget(_tabsMenuButton, 0);
#if QT_VERSION >= QT_VERSION_CHECK(5, 0, 0)
//QObject::connect(_tabsMenuButton, &QPushButton::clicked, this, &SectionWidget::onTabsMenuButtonClicked);
#else
//QObject::connect(_tabsMenuButton, SIGNAL(clicked()), this, SLOT(onTabsMenuButtonClicked()));
#endif
_closeButton = new QPushButton();
_closeButton->setObjectName("closeButton");
_closeButton->setFlat(true);
_closeButton->setIcon(style()->standardIcon(QStyle::SP_TitleBarCloseButton));
_closeButton->setToolTip(tr("Close"));
_closeButton->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
_topLayout->addWidget(_closeButton, 0);
connect(_closeButton, SIGNAL(clicked(bool)), this, SLOT(onCloseButtonClicked()));
_tabsLayoutInitCount = _tabsLayout->count();
/* central area with contents */
_contentsLayout = new QStackedLayout();
_contentsLayout->setContentsMargins(0, 0, 0, 0);
_contentsLayout->setSpacing(0);
l->addLayout(_contentsLayout, 1);
m_MainContainerWidget->m_SectionWidgetIdMap.insert(_uid, this);
}
SectionWidget::~SectionWidget()
{
if (m_MainContainerWidget)
{
m_MainContainerWidget->m_SectionWidgetIdMap.remove(_uid);
m_MainContainerWidget->m_Sections.removeAll(this); // Note: I don't like this here, but we have to remove it from list...
}
// Delete empty QSplitter.
QSplitter* splitter = findParentSplitter(this);
if (splitter && splitter->count() == 0)
{
splitter->deleteLater();
}
std::cout << "SectionWidget::~SectionWidget()" << std::endl;
}
int SectionWidget::uid() const
{
return _uid;
}
CContainerWidget* SectionWidget::containerWidget() const
{
QWidget* Parent = parentWidget();
while (Parent)
{
CContainerWidget* Container = dynamic_cast<CContainerWidget*>(Parent);
if (Container)
{
return Container;
}
Parent = Parent->parentWidget();
}
return 0;
}
QRect SectionWidget::titleAreaGeometry() const
{
return _topLayout->geometry();
}
QRect SectionWidget::contentAreaGeometry() const
{
return _contentsLayout->geometry();
}
void SectionWidget::addContent(const SectionContent::RefPtr& c)
{
m_Contents.append(c);
SectionTitleWidget* title = new SectionTitleWidget(c, NULL);
m_TitleWidgets.append(title);
_tabsLayout->insertWidget(_tabsLayout->count() - _tabsLayoutInitCount, title);
QObject::connect(title, SIGNAL(clicked()), this, SLOT(onSectionTitleClicked()));
CSectionContentWidget* content = new CSectionContentWidget(c, NULL);
m_ContentWidgets.append(content);
_contentsLayout->addWidget(content);
// Active first TAB.
if (m_Contents.size() == 1)
setCurrentIndex(0);
// Switch to newest.
// else
// setCurrentIndex(_contentsLayout->count() - 1);
updateTabsMenu();
}
void SectionWidget::addContent(const InternalContentData& data, bool autoActivate)
{
m_Contents.append(data.content);
// Add title-widget to tab-bar
// #FIX: Make it visible, since it is possible that it was hidden previously.
m_TitleWidgets.append(data.titleWidget);
_tabsLayout->insertWidget(_tabsLayout->count() - _tabsLayoutInitCount, data.titleWidget);
data.titleWidget->setVisible(true);
QObject::connect(data.titleWidget, SIGNAL(clicked()), this, SLOT(onSectionTitleClicked()));
// Add content-widget to stack.
// Visibility is managed by QStackedWidget.
m_ContentWidgets.append(data.contentWidget);
_contentsLayout->addWidget(data.contentWidget);
// Activate first TAB.
if (m_Contents.size() == 1)
setCurrentIndex(0);
// Switch to just added TAB.
else if (autoActivate)
setCurrentIndex(m_Contents.count() - 1);
// Mark it as inactive tab.
else
data.titleWidget->setActiveTab(false); // or: setCurrentIndex(currentIndex())
updateTabsMenu();
}
bool SectionWidget::takeContent(int uid, InternalContentData& data)
{
for (int i = 0; i < m_Contents.count(); i++)
{
if (m_Contents[i]->uid() != uid)
{
continue;
}
return takeContentAt(i, data);
}
return false;
}
bool SectionWidget::takeContentAt(int index, InternalContentData& data)
{
SectionContent::RefPtr sc = m_Contents.takeAt(index);
if (!sc)
return false;
// Title wrapper widget (TAB)
SectionTitleWidget* title = m_TitleWidgets.takeAt(index);
if (title)
{
_tabsLayout->removeWidget(title);
title->disconnect(this);
title->setParent(m_MainContainerWidget);
}
// Content wrapper widget (CONTENT)
CSectionContentWidget* content = m_ContentWidgets.takeAt(index);
if (content)
{
_contentsLayout->removeWidget(content);
content->disconnect(this);
content->setParent(m_MainContainerWidget);
}
// Select the previous tab as activeTab.
if (m_Contents.size() > 0 && title->isActiveTab())
{
if (index > 0)
setCurrentIndex(index - 1);
else
setCurrentIndex(0);
}
updateTabsMenu();
data.content = sc;
data.titleWidget = title;
data.contentWidget = content;
return !data.content.isNull();
}
int SectionWidget::indexOfContent(const SectionContent::RefPtr& c) const
{
return m_Contents.indexOf(c);
}
int SectionWidget::indexOfContentByUid(int uid) const
{
for (int i = 0; i < m_Contents.count(); ++i)
{
if (m_Contents[i]->uid() == uid)
return i;
}
return -1;
}
int SectionWidget::indexOfContentByTitlePos(const QPoint& p, QWidget* exclude) const
{
int index = -1;
for (int i = 0; i < m_TitleWidgets.size(); ++i)
{
if (m_TitleWidgets[i]->geometry().contains(p) && (exclude == NULL || m_TitleWidgets[i] != exclude))
{
index = i;
break;
}
}
return index;
}
int SectionWidget::currentIndex() const
{
return _contentsLayout->currentIndex();
}
void SectionWidget::moveContent(int from, int to)
{
if (from >= m_Contents.size() || from < 0 || to >= m_Contents.size() || to < 0 || from == to)
{
qDebug() << "Invalid index for tab movement" << from << to;
_tabsLayout->update();
return;
}
m_Contents.move(from, to);
m_TitleWidgets.move(from, to);
m_ContentWidgets.move(from, to);
QLayoutItem* liFrom = NULL;
liFrom = _tabsLayout->takeAt(from);
_tabsLayout->insertItem(to, liFrom);
liFrom = _contentsLayout->takeAt(from);
_contentsLayout->insertWidget(to, liFrom->widget());
delete liFrom;
updateTabsMenu();
}
void SectionWidget::showEvent(QShowEvent*)
{
_tabsScrollArea->ensureWidgetVisible(m_TitleWidgets.at(currentIndex()));
}
void SectionWidget::setCurrentIndex(int index)
{
if (index < 0 || index > m_Contents.count() - 1)
{
qWarning() << Q_FUNC_INFO << "Invalid index" << index;
return;
}
// Set active TAB
for (int i = 0; i < _tabsLayout->count(); ++i)
{
QLayoutItem* item = _tabsLayout->itemAt(i);
if (item->widget())
{
SectionTitleWidget* stw = dynamic_cast<SectionTitleWidget*>(item->widget());
if (stw)
{
if (i == index)
{
stw->setActiveTab(true);
_tabsScrollArea->ensureWidgetVisible(stw);
if (stw->m_Content->flags().testFlag(SectionContent::Closeable))
_closeButton->setEnabled(true);
else
_closeButton->setEnabled(false);
}
else
stw->setActiveTab(false);
}
}
}
// Set active CONTENT
_contentsLayout->setCurrentIndex(index);
}
void SectionWidget::onSectionTitleClicked()
{
SectionTitleWidget* stw = qobject_cast<SectionTitleWidget*>(sender());
if (stw)
{
int index = _tabsLayout->indexOf(stw);
setCurrentIndex(index);
}
}
void SectionWidget::onCloseButtonClicked()
{
const int index = currentIndex();
if (index < 0 || index > m_Contents.size() - 1)
return;
SectionContent::RefPtr sc = m_Contents.at(index);
if (sc.isNull())
return;
m_MainContainerWidget->hideSectionContent(sc);
}
void SectionWidget::onTabsMenuActionTriggered(bool)
{
QAction* a = qobject_cast<QAction*>(sender());
if (a)
{
const int uid = a->data().toInt();
const int index = indexOfContentByUid(uid);
if (index >= 0)
setCurrentIndex(index);
}
}
void SectionWidget::updateTabsMenu()
{
QMenu* m = new QMenu();
for (int i = 0; i < m_Contents.count(); ++i)
{
const SectionContent::RefPtr& sc = m_Contents.at(i);
QAction* a = m->addAction(QIcon(), sc->visibleTitle());
a->setData(sc->uid());
QObject::connect(a, SIGNAL(triggered(bool)), this, SLOT(onTabsMenuActionTriggered(bool)));
}
QMenu* old = _tabsMenuButton->menu();
_tabsMenuButton->setMenu(m);
delete old;
}
int SectionWidget::GetNextUid()
{
static int NextUid = 0;
return ++NextUid;
}
/*****************************************************************************/
SectionWidgetTabsScrollArea::SectionWidgetTabsScrollArea(SectionWidget*,
QWidget* parent) :
QScrollArea(parent)
{
/* Important: QSizePolicy::Ignored makes the QScrollArea behaves
like a QLabel and automatically fits into the layout. */
setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Ignored);
setFrameStyle(QFrame::NoFrame);
setWidgetResizable(true);
setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
}
SectionWidgetTabsScrollArea::~SectionWidgetTabsScrollArea()
{
}
void SectionWidgetTabsScrollArea::wheelEvent(QWheelEvent* e)
{
e->accept();
const int direction = e->angleDelta().y();
if (direction < 0)
horizontalScrollBar()->setValue(horizontalScrollBar()->value() + 20);
else
horizontalScrollBar()->setValue(horizontalScrollBar()->value() - 20);
}
void SectionWidgetTabsScrollArea::mousePressEvent(QMouseEvent* ev)
{
qInfo() << "mousePressEvent " << ev->type();
if (ev->button() == Qt::LeftButton)
{
ev->accept();
_dragStartPos = ev->pos();
return;
}
QScrollArea::mousePressEvent(ev);
}
void SectionWidgetTabsScrollArea::mouseMoveEvent(QMouseEvent* ev)
{
/*if (_fw)
{
return;
}
ContainerWidget* cw = findParentContainerWidget(this);
SectionWidget* sectionWidget = findParentSectionWidget(this);
qInfo() << "mousePressEvent " << ev->type();
ev->accept();
_fw = new FloatingWidget(sectionWidget);
_fw->resize(sectionWidget->size());
cw->_floatings.append(_fw); // Note: I don't like this...
const QPoint moveToPos = ev->globalPos() - (_dragStartPos + QPoint(ADS_WINDOW_FRAME_BORDER_WIDTH, ADS_WINDOW_FRAME_BORDER_WIDTH));
_fw->move(moveToPos);
_fw->show();
//delete sectionWidget;
deleteEmptySplitter(cw);*/
QScrollArea::mouseMoveEvent(ev);
return;
}
} // namespace ads

View File

@ -1,130 +0,0 @@
#ifndef SECTION_WIDGET_H
#define SECTION_WIDGET_H
/*******************************************************************************
** QtAdcancedDockingSystem
** Copyright (C) 2017 Uwe Kindler
**
** This program is free software: you can redistribute it and/or modify
** it under the terms of the GNU General Public License as published by
** the Free Software Foundation, either version 3 of the License, or
** (at your option) any later version.
**
** This program is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
** GNU General Public License for more details.
**
** You should have received a copy of the GNU General Public License
** along with this program. If not, see <http://www.gnu.org/licenses/>.
******************************************************************************/
#include <QDebug>
#include <QPointer>
#include <QList>
#include <QFrame>
#include <QScrollArea>
class QBoxLayout;
class QStackedLayout;
class QPushButton;
class QMenu;
#include "API.h"
#include "Internal.h"
#include "SectionContent.h"
#include "FloatingWidget.h"
namespace ads
{
class CMainContainerWidget;
class SectionTitleWidget;
class CSectionContentWidget;
// 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 ADS_EXPORT_API SectionWidget : public QFrame
{
Q_OBJECT
friend class CMainContainerWidget;
friend class CContainerWidget;
explicit SectionWidget(CMainContainerWidget* MainContainer, CContainerWidget* parent);
public:
virtual ~SectionWidget();
int uid() const;
CContainerWidget* containerWidget() const;
QRect titleAreaGeometry() const;
QRect contentAreaGeometry() const;
const QList<SectionContent::RefPtr>& contents() const { return m_Contents; }
void addContent(const SectionContent::RefPtr& c);
void addContent(const InternalContentData& data, bool autoActivate);
bool takeContent(int uid, InternalContentData& data);
bool takeContentAt(int Index, InternalContentData& data);
int indexOfContent(const SectionContent::RefPtr& c) const;
int indexOfContentByUid(int uid) const;
int indexOfContentByTitlePos(const QPoint& pos, QWidget* exclude = NULL) const;
int currentIndex() const;
void moveContent(int from, int to);
inline int contentCount() const {return m_ContentWidgets.size();}
protected:
virtual void showEvent(QShowEvent*);
public slots:
void setCurrentIndex(int index);
private slots:
void onSectionTitleClicked();
void onCloseButtonClicked();
void onTabsMenuActionTriggered(bool);
void updateTabsMenu();
private:
const int _uid;
QPointer<CMainContainerWidget> m_MainContainerWidget;
QList<SectionContent::RefPtr> m_Contents;
QList<SectionTitleWidget*> m_TitleWidgets;
QList<CSectionContentWidget*> m_ContentWidgets;
QBoxLayout* _topLayout;
QScrollArea* _tabsScrollArea;
QWidget* _tabsContainerWidget;
QBoxLayout* _tabsLayout;
QPushButton* _tabsMenuButton;
QPushButton* _closeButton;
int _tabsLayoutInitCount; // used for calculations on _tabsLayout modification calls.
QStackedLayout *_contentsLayout;
QPoint _mousePressPoint;
SectionContent::RefPtr _mousePressContent;
SectionTitleWidget* _mousePressTitleWidget;
static int GetNextUid();
};
/* Custom scrollable implementation for tabs */
class SectionWidgetTabsScrollArea : public QScrollArea
{
public:
SectionWidgetTabsScrollArea(SectionWidget* sectionWidget, QWidget* parent = NULL);
virtual ~SectionWidgetTabsScrollArea();
protected:
QPoint _dragStartPos;
QPointer<FloatingWidget> _fw;
virtual void wheelEvent(QWheelEvent*);
virtual void mousePressEvent(QMouseEvent* ev);
virtual void mouseMoveEvent(QMouseEvent* ev);
};
} // namespace ads
#endif

View File

@ -1,459 +0,0 @@
/*******************************************************************************
** QtAdcancedDockingSystem
** Copyright (C) 2017 Uwe Kindler
**
** This program is free software: you can redistribute it and/or modify
** it under the terms of the GNU General Public License as published by
** the Free Software Foundation, either version 3 of the License, or
** (at your option) any later version.
**
** This program is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
** GNU General Public License for more details.
**
** You should have received a copy of the GNU General Public License
** along with this program. If not, see <http://www.gnu.org/licenses/>.
******************************************************************************/
#include "Serialization.h"
#include <QDebug>
namespace ads
{
/*
\namespace ads::serialization
Serialization of ContainerWidget
--------------------------------
# Data Format Header
quint32 Magic
quint32 Major Version
quint32 Minor Version
# Offsets of available contents
qint32 Number of offset headers
LOOP
qint32 Type (e.g. Hierachy, SectionIndex)
qint64 Offset
qint64 Length
# Type: Hierachy
# Used to recreate the GUI geometry and state.
int Number of floating widgets
LOOP Floating widgets
QString Unique name of content
QByteArray Geometry of floating widget
bool Visibility
int Number of layout items (Valid values: 0, 1)
IF 0
int Number of hidden contents
LOOP Contents
QString Unique name of content
ELSEIF 1
... todo ...
ENDIF
# Type: SectionIndex
# Can be used for quick lookups on details for SectionWidgets.
# It includes sizes and its contents.
qint32 Number of section-widgets
LOOP
qint32 Width
qint32 Height
qint32 Current active tab index
qint32 Number of contents
LOOP
QString Unique name of content
bool Visibility
qint32 Preferred tab index
*/
///////////////////////////////////////////////////////////////////////////////
qint32 HeaderEntity::MAGIC = 0x00001337;
qint32 HeaderEntity::MAJOR_VERSION = 2;
qint32 HeaderEntity::MINOR_VERSION = 0;
HeaderEntity::HeaderEntity() :
magic(0), majorVersion(0), minorVersion(0)
{
}
QDataStream& operator<<(QDataStream& out, const HeaderEntity& data)
{
out << data.magic;
out << data.majorVersion;
out << data.minorVersion;
return out;
}
QDataStream& operator>>(QDataStream& in, HeaderEntity& data)
{
in >> data.magic;
in >> data.majorVersion;
in >> data.minorVersion;
return in;
}
///////////////////////////////////////////////////////////////////////////////
OffsetsHeaderEntity::OffsetsHeaderEntity() :
entriesCount(0)
{
}
QDataStream& operator<<(QDataStream& out, const OffsetsHeaderEntity& data)
{
out << data.entriesCount;
for (int i = 0; i < data.entriesCount; ++i)
{
out << data.entries.at(i);
}
return out;
}
QDataStream& operator>>(QDataStream& in, OffsetsHeaderEntity& data)
{
in >> data.entriesCount;
for (int i = 0; i < data.entriesCount; ++i)
{
OffsetsHeaderEntryEntity entry;
in >> entry;
data.entries.append(entry);
}
return in;
}
///////////////////////////////////////////////////////////////////////////////
OffsetsHeaderEntryEntity::OffsetsHeaderEntryEntity() :
type(ET_Unknown), offset(0), contentSize(0)
{
}
QDataStream& operator<<(QDataStream& out, const OffsetsHeaderEntryEntity& data)
{
out << data.type;
out << data.offset;
out << data.contentSize;
return out;
}
QDataStream& operator>>(QDataStream& in, OffsetsHeaderEntryEntity& data)
{
in >> data.type;
in >> data.offset;
in >> data.contentSize;
return in;
}
///////////////////////////////////////////////////////////////////////////////
SectionEntity::SectionEntity() :
x(0), y(0), width(0), height(0), currentIndex(0), sectionContentsCount(0)
{
}
QDataStream& operator<<(QDataStream& out, const SectionEntity& data)
{
out << data.x;
out << data.y;
out << data.width;
out << data.height;
out << data.currentIndex;
out << data.sectionContentsCount;
for (int i = 0; i < data.sectionContentsCount; ++i)
{
out << data.sectionContents.at(i);
}
return out;
}
QDataStream& operator>>(QDataStream& in, SectionEntity& data)
{
in >> data.x;
in >> data.y;
in >> data.width;
in >> data.height;
in >> data.currentIndex;
in >> data.sectionContentsCount;
for (int i = 0; i < data.sectionContentsCount; ++i)
{
SectionContentEntity sc;
in >> sc;
data.sectionContents.append(sc);
}
return in;
}
///////////////////////////////////////////////////////////////////////////////
SectionContentEntity::SectionContentEntity() :
visible(false), preferredIndex(0)
{
}
QDataStream& operator<<(QDataStream& out, const SectionContentEntity& data)
{
out << data.uniqueName;
out << data.visible;
out << data.preferredIndex;
return out;
}
QDataStream& operator>>(QDataStream& in, SectionContentEntity& data)
{
in >> data.uniqueName;
in >> data.visible;
in >> data.preferredIndex;
return in;
}
///////////////////////////////////////////////////////////////////////////////
FloatingContentEntity::FloatingContentEntity() :
xpos(0), ypos(0), width(0), height(0), visible(false)
{
}
QDataStream& operator<<(QDataStream& out, const FloatingContentEntity& data)
{
out << data.uniqueName;
out << data.xpos;
out << data.ypos;
out << data.width;
out << data.height;
out << data.visible;
return out;
}
QDataStream& operator>>(QDataStream& in, FloatingContentEntity& data)
{
in >> data.uniqueName;
in >> data.xpos;
in >> data.ypos;
in >> data.width;
in >> data.height;
in >> data.visible;
return in;
}
///////////////////////////////////////////////////////////////////////////////
HierarchyData::HierarchyData()
{
}
QDataStream& operator<<(QDataStream& out, const HierarchyData& data)
{
out << data.data;
return out;
}
QDataStream& operator>>(QDataStream& in, HierarchyData& data)
{
in >> data.data;
return in;
}
///////////////////////////////////////////////////////////////////////////////
SectionIndexData::SectionIndexData() :
sectionsCount(0)
{
}
QDataStream& operator<<(QDataStream& out, const SectionIndexData& data)
{
out << data.sectionsCount;
for (int i = 0; i < data.sectionsCount; ++i)
{
out << data.sections.at(i);
}
return out;
}
QDataStream& operator>>(QDataStream& in, SectionIndexData& data)
{
in >> data.sectionsCount;
for (int i = 0; i < data.sectionsCount; ++i)
{
SectionEntity s;
in >> s;
data.sections.append(s);
}
return in;
}
///////////////////////////////////////////////////////////////////////////////
InMemoryWriter::InMemoryWriter()
{
_contentBuffer.open(QIODevice::ReadWrite);
}
bool InMemoryWriter::write(qint32 entryType, const QByteArray& data)
{
OffsetsHeaderEntryEntity entry;
entry.type = entryType;
entry.offset = _contentBuffer.pos(); // Relative offset!
entry.contentSize = data.size();
_contentBuffer.write(data);
_offsetsHeader.entries.append(entry);
_offsetsHeader.entriesCount += 1;
return true;
}
bool InMemoryWriter::write(const SectionIndexData& data)
{
OffsetsHeaderEntryEntity entry;
entry.type = ET_SectionIndex;
entry.offset = _contentBuffer.pos(); // Relative offset!
QDataStream out(&_contentBuffer);
out.setVersion(QDataStream::Qt_4_5);
out << data;
entry.contentSize = _contentBuffer.size() - entry.offset;
_offsetsHeader.entries.append(entry);
_offsetsHeader.entriesCount += 1;
return true;
}
QByteArray InMemoryWriter::toByteArray() const
{
QByteArray data;
QDataStream out(&data, QIODevice::ReadWrite);
out.setVersion(QDataStream::Qt_4_5);
// Basic format header.
HeaderEntity header;
header.magic = HeaderEntity::MAGIC;
header.majorVersion = HeaderEntity::MAJOR_VERSION;
header.minorVersion = HeaderEntity::MINOR_VERSION;
out << header;
// Offsets-Header
// - Save begin pos
// - Write OffsetsHeader
// - Convert relative- to absolute-offsets
// - Seek back to begin-pos and write OffsetsHeader again.
// Use a copy of OffsetsHeader to keep the _offsetsHeader relative.
const qint64 posOffsetHeaders = out.device()->pos();
OffsetsHeaderEntity offsetsHeader = _offsetsHeader;
out << offsetsHeader;
// Now we know the size of the entire header.
// We can update the relative- to absolute-offsets now.
const qint64 allHeaderSize = out.device()->pos();
for (int i = 0; i < offsetsHeader.entriesCount; ++i)
{
offsetsHeader.entries[i].offset += allHeaderSize; // Absolute offset!
}
// Seek back and write again with absolute offsets.
// TODO Thats not nice, but it works...
out.device()->seek(posOffsetHeaders);
out << offsetsHeader;
// Write contents.
out.writeRawData(_contentBuffer.data().constData(), _contentBuffer.size());
return data;
}
///////////////////////////////////////////////////////////////////////////////
InMemoryReader::InMemoryReader(const QByteArray& data) :
_data(data)
{
}
bool InMemoryReader::initReadHeader()
{
QDataStream in(_data);
in.setVersion(QDataStream::Qt_4_5);
// Basic format header.
HeaderEntity header;
in >> header;
if (header.magic != HeaderEntity::MAGIC)
{
qWarning() << QString("invalid format (magic=%1)").arg(header.magic);
return false;
}
if (header.majorVersion != HeaderEntity::MAJOR_VERSION)
{
qWarning() << QString("format is too new (major=%1; minor=%2)")
.arg(header.majorVersion).arg(header.minorVersion);
return false;
}
// OffsetsHeader.
in >> _offsetsHeader;
return !in.atEnd();
}
bool InMemoryReader::read(qint32 entryType, QByteArray& data)
{
// Find offset for "type".
int index = -1;
for (int i = 0; i < _offsetsHeader.entriesCount; ++i)
{
if (_offsetsHeader.entries.at(i).type == entryType)
{
index = i;
break;
}
}
if (index < 0)
return false;
else if (_offsetsHeader.entries.at(index).offset == 0)
return false;
const OffsetsHeaderEntryEntity& entry = _offsetsHeader.entries.at(index);
QDataStream in(_data);
in.setVersion(QDataStream::Qt_4_5);
in.device()->seek(entry.offset);
char* buff = new char[entry.contentSize];
in.readRawData(buff, entry.contentSize);
data.append(buff, entry.contentSize);
delete[] buff;
return true;
}
bool InMemoryReader::read(SectionIndexData& sid)
{
QByteArray sidData;
if (!read(ET_SectionIndex, sidData) || sidData.isEmpty())
return false;
QDataStream in(sidData);
in.setVersion(QDataStream::Qt_4_5);
in >> sid;
return in.atEnd();
}
///////////////////////////////////////////////////////////////////////////////
} // namespace ads

View File

@ -1,182 +0,0 @@
#ifndef ADS_SERIALIZATION_H
#define ADS_SERIALIZATION_H
/*******************************************************************************
** QtAdcancedDockingSystem
** Copyright (C) 2017 Uwe Kindler
**
** This program is free software: you can redistribute it and/or modify
** it under the terms of the GNU General Public License as published by
** the Free Software Foundation, either version 3 of the License, or
** (at your option) any later version.
**
** This program is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
** GNU General Public License for more details.
**
** You should have received a copy of the GNU General Public License
** along with this program. If not, see <http://www.gnu.org/licenses/>.
******************************************************************************/
#include <QtGlobal>
#include <QList>
#include <QString>
#include <QDataStream>
#include <QBuffer>
#include "API.h"
namespace ads
{
enum EntryType
{
ET_Unknown = 0x00000000,
ET_Hierarchy = 0x00000001,
ET_SectionIndex = 0x00000002,
// Begin of custom entry types (e.g. CustomType + 42)
ET_Custom = 0x0000ffff
};
class ADS_EXPORT_API HeaderEntity
{
public:
static qint32 MAGIC;
static qint32 MAJOR_VERSION;
static qint32 MINOR_VERSION;
HeaderEntity();
qint32 magic;
qint32 majorVersion;
qint32 minorVersion;
};
QDataStream& operator<<(QDataStream& out, const HeaderEntity& data);
QDataStream& operator>>(QDataStream& in, HeaderEntity& data);
class ADS_EXPORT_API OffsetsHeaderEntity
{
public:
OffsetsHeaderEntity();
qint64 entriesCount;
QList<class OffsetsHeaderEntryEntity> entries;
};
QDataStream& operator<<(QDataStream& out, const OffsetsHeaderEntity& data);
QDataStream& operator>>(QDataStream& in, OffsetsHeaderEntity& data);
class ADS_EXPORT_API OffsetsHeaderEntryEntity
{
public:
OffsetsHeaderEntryEntity();
qint32 type;
qint64 offset;
qint64 contentSize;
};
QDataStream& operator<<(QDataStream& out, const OffsetsHeaderEntryEntity& data);
QDataStream& operator>>(QDataStream& in, OffsetsHeaderEntryEntity& data);
class ADS_EXPORT_API SectionEntity
{
public:
SectionEntity();
qint32 x;
qint32 y;
qint32 width;
qint32 height;
qint32 currentIndex;
qint32 sectionContentsCount;
QList<class SectionContentEntity> sectionContents;
};
QDataStream& operator<<(QDataStream& out, const SectionEntity& data);
QDataStream& operator>>(QDataStream& in, SectionEntity& data);
class ADS_EXPORT_API SectionContentEntity
{
public:
SectionContentEntity();
QString uniqueName;
bool visible;
qint32 preferredIndex;
};
QDataStream& operator<<(QDataStream& out, const SectionContentEntity& data);
QDataStream& operator>>(QDataStream& in, SectionContentEntity& data);
class ADS_EXPORT_API FloatingContentEntity
{
public:
FloatingContentEntity();
QString uniqueName;
qint32 xpos;
qint32 ypos;
qint32 width;
qint32 height;
bool visible;
};
QDataStream& operator<<(QDataStream& out, const FloatingContentEntity& data);
QDataStream& operator>>(QDataStream& in, FloatingContentEntity& data);
// Type: OffsetHeaderEntry::Hierarchy
class ADS_EXPORT_API HierarchyData
{
public:
HierarchyData();
QByteArray data;
};
QDataStream& operator<<(QDataStream& out, const HierarchyData& data);
QDataStream& operator>>(QDataStream& in, HierarchyData& data);
// Type: OffsetHeaderEntry::SectionIndex
class ADS_EXPORT_API SectionIndexData
{
public:
SectionIndexData();
qint32 sectionsCount;
QList<SectionEntity> sections;
};
QDataStream& operator<<(QDataStream& out, const SectionIndexData& data);
QDataStream& operator>>(QDataStream& in, SectionIndexData& data);
/*!
* \brief The InMemoryWriter class writes into a QByteArray.
*/
class ADS_EXPORT_API InMemoryWriter
{
public:
InMemoryWriter();
bool write(qint32 entryType, const QByteArray& data);
bool write(const SectionIndexData& data);
QByteArray toByteArray() const;
qint32 offsetsCount() const { return _offsetsHeader.entriesCount; }
private:
QBuffer _contentBuffer;
OffsetsHeaderEntity _offsetsHeader;
};
/*!
* \brief The InMemoryReader class
*/
class ADS_EXPORT_API InMemoryReader
{
public:
InMemoryReader(const QByteArray& data);
bool initReadHeader();
bool read(qint32 entryType, QByteArray &data);
bool read(SectionIndexData& sid);
qint32 offsetsCount() const { return _offsetsHeader.entriesCount; }
private:
QByteArray _data;
OffsetsHeaderEntity _offsetsHeader;
};
} // namespace ads
#endif

View File

@ -1,22 +0,0 @@
DEPENDPATH *= $$PWD
HEADERS += \
$$PWD/ads_globals.h \
$$PWD/DockAreaWidget.h \
$$PWD/DockContainerWidget.h \
$$PWD/DockManager.h \
$$PWD/DockWidget.h \
$$PWD/DockWidgetTitleBar.h \
$$PWD/FloatingDockContainer.h \
$$PWD/DockOverlay.h
SOURCES += \
$$PWD/ads_globals.cpp \
$$PWD/DockAreaWidget.cpp \
$$PWD/DockContainerWidget.cpp \
$$PWD/DockManager.cpp \
$$PWD/DockWidget.cpp \
$$PWD/DockWidgetTitleBar.cpp \
$$PWD/FloatingDockContainer.cpp \
$$PWD/DockOverlay.cpp

View File

@ -1,57 +0,0 @@
include($$(cetoni_repository)/build/qt/qtprojectsettings/common.pri)
TARGET = AdvancedDockingSystemDemo
QT += core gui
greaterThan(QT_MAJOR_VERSION, 4): QT += widgets
greaterThan(QT_MAJOR_VERSION, 4): DEFINES += ADS_NAMESPACE_ENABLED
windows {
# MinGW
*-g++* {
QMAKE_CXXFLAGS += -std=c++11
}
# MSVC
*-msvc* {
}
}
SOURCES += \
src/main.cpp \
src/mainwindow.cpp \
src/icontitlewidget.cpp \
src/dialogs/SectionContentListModel.cpp \
src/dialogs/SectionContentListWidget.cpp
HEADERS += \
src/mainwindow.h \
src/icontitlewidget.h \
src/dialogs/SectionContentListModel.h \
src/dialogs/SectionContentListWidget.h
FORMS += \
src/mainwindow.ui \
src/dialogs/SectionContentListWidget.ui
# Dependency: AdvancedDockingSystem (staticlib)
#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/include
#DEPENDPATH += $$PWD/../AdvancedDockingSystem/include
#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
# Dependency: AdvancedDockingSystem (shared)
win32:CONFIG(release, debug|release): LIBS += -l$$qtLinkLibrary(AdvancedDockingSystem)
else:win32:CONFIG(debug, debug|release): LIBS += -l$$qtLinkLibrary(AdvancedDockingSystem)
else:unix: LIBS += -L$$OUT_PWD/../AdvancedDockingSystem/ -lAdvancedDockingSystem
INCLUDEPATH += $$PWD/../AdvancedDockingSystem/src
DEPENDPATH += $$PWD/../AdvancedDockingSystem/src

View File

@ -1,90 +0,0 @@
#include "SectionContentListModel.h"
SectionContentListModel::SectionContentListModel(QObject* parent) :
QAbstractTableModel(parent)
{
_headers.insert(UidColumn, "UID");
_headers.insert(UniqueNameColumn, "Unique Name");
_headers.insert(TitleColumn, "Title");
_headers.insert(VisibleColumn, "Visible");
}
SectionContentListModel::~SectionContentListModel()
{
}
void SectionContentListModel::init(ads::CMainContainerWidget* cw)
{
beginResetModel();
_cw = cw;
_contents = _cw->contents();
endResetModel();
}
int SectionContentListModel::columnCount(const QModelIndex& parent) const
{
Q_UNUSED(parent)
return _headers.count();
}
QVariant SectionContentListModel::headerData(int section, Qt::Orientation orientation, int role) const
{
if (orientation == Qt::Horizontal && role == Qt::DisplayRole)
return _headers.value(section);
return QVariant();
}
int SectionContentListModel::rowCount(const QModelIndex& parent) const
{
Q_UNUSED(parent)
return _contents.count();
}
QVariant SectionContentListModel::data(const QModelIndex& index, int role) const
{
if (!index.isValid() || index.row() > rowCount(index) - 1)
return QVariant();
const ads::SectionContent::RefPtr sc = _contents.at(index.row());
if (sc.isNull())
return QVariant();
switch (role)
{
case Qt::DisplayRole:
{
switch (index.column())
{
case UidColumn:
return sc->uid();
case UniqueNameColumn:
return sc->uniqueName();
case TitleColumn:
return sc->title();
case VisibleColumn:
return _cw->isSectionContentVisible(sc);
}
}
}
return QVariant();
}
bool SectionContentListModel::removeRows(int row, int count, const QModelIndex& parent)
{
if (row > rowCount(parent) - 1)
return false;
const int first = row;
const int last = row + count - 1;
beginRemoveRows(parent, first, last);
for (int i = last; i >= first; --i)
{
const ads::SectionContent::RefPtr sc = _contents.at(i);
_cw->removeSectionContent(sc);
_contents.removeAt(i);
}
endRemoveRows();
return true;
}

View File

@ -1,46 +0,0 @@
#ifndef ADS_SECTIONCONTENTMODEL_H
#define ADS_SECTIONCONTENTMODEL_H
#include <QHash>
#include <QList>
#include <QString>
#include <QAbstractTableModel>
#include "../../../AdvancedDockingSystem/src/SectionContent.h"
#include "MainContainerWidget.h"
#include "API.h"
namespace ads {class CMainContainerWidget;}
class SectionContentListModel : public QAbstractTableModel
{
Q_OBJECT
public:
enum Column
{
UidColumn,
UniqueNameColumn,
TitleColumn,
VisibleColumn
};
SectionContentListModel(QObject* parent);
virtual ~SectionContentListModel();
void init(ads::CMainContainerWidget* cw);
virtual int columnCount(const QModelIndex &parent) const;
virtual QVariant headerData(int section, Qt::Orientation orientation, int role) const;
virtual int rowCount(const QModelIndex &parent) const;
virtual QVariant data(const QModelIndex &index, int role) const;
virtual bool removeRows(int row, int count, const QModelIndex &parent);
private:
QHash<int, QString> _headers;
ads::CMainContainerWidget* _cw;
QList<ads::SectionContent::RefPtr> _contents;
};
#endif

View File

@ -1,38 +0,0 @@
#include "SectionContentListWidget.h"
#include "SectionContentListModel.h"
SectionContentListWidget::SectionContentListWidget(QWidget* parent) :
QDialog(parent)
{
_ui.setupUi(this);
connect(_ui.deleteButton, SIGNAL(clicked(bool)), this, SLOT(onDeleteButtonClicked()));
}
void SectionContentListWidget::setValues(const SectionContentListWidget::Values& v)
{
_v = v;
// Reset
QAbstractItemModel* m = _ui.tableView->model();
if (m)
{
_ui.tableView->setModel(NULL);
delete m;
m = NULL;
}
// Fill.
SectionContentListModel* sclm = new SectionContentListModel(this);
sclm->init(_v.cw);
_ui.tableView->setModel(sclm);
}
void SectionContentListWidget::onDeleteButtonClicked()
{
const QModelIndex mi = _ui.tableView->currentIndex();
if (!mi.isValid())
return;
_ui.tableView->model()->removeRows(mi.row(), 1, mi.parent());
}

View File

@ -1,33 +0,0 @@
#ifndef SECTIONCONTENTLISTWIDGET
#define SECTIONCONTENTLISTWIDGET
#include <QDialog>
#include "../../../AdvancedDockingSystem/src/SectionContent.h"
#include "MainContainerWidget.h"
#include "ui_SectionContentListWidget.h"
#include "API.h"
class SectionContentListWidget : public QDialog
{
Q_OBJECT
public:
class Values
{
public:
ads::CMainContainerWidget* cw;
};
SectionContentListWidget(QWidget* parent);
void setValues(const Values& v);
private slots:
void onDeleteButtonClicked();
private:
Ui::SectionContentListWidgetForm _ui;
Values _v;
};
#endif

View File

@ -1,61 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>SectionContentListWidgetForm</class>
<widget class="QWidget" name="SectionContentListWidgetForm">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>522</width>
<height>258</height>
</rect>
</property>
<property name="windowTitle">
<string>Form</string>
</property>
<layout class="QHBoxLayout" name="horizontalLayout">
<item>
<widget class="QTableView" name="tableView">
<property name="editTriggers">
<set>QAbstractItemView::NoEditTriggers</set>
</property>
<property name="alternatingRowColors">
<bool>true</bool>
</property>
<property name="selectionMode">
<enum>QAbstractItemView::SingleSelection</enum>
</property>
<property name="selectionBehavior">
<enum>QAbstractItemView::SelectRows</enum>
</property>
</widget>
</item>
<item>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<widget class="QPushButton" name="deleteButton">
<property name="text">
<string>Delete</string>
</property>
</widget>
</item>
<item>
<spacer name="verticalSpacer">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>40</height>
</size>
</property>
</spacer>
</item>
</layout>
</item>
</layout>
</widget>
<resources/>
<connections/>
</ui>

View File

@ -1,66 +0,0 @@
#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)
{
QBoxLayout* l = new QBoxLayout(QBoxLayout::LeftToRight);
l->setContentsMargins(0, 0, 0, 0);
setLayout(l);
_iconLabel = new QLabel();
_iconLabel->setAlignment(Qt::AlignVCenter);
l->addWidget(_iconLabel, Qt::AlignVCenter);
_titleLabel = new QLabel();
l->addWidget(_titleLabel, 1);
setIcon(icon);
setTitle(title);
}
void IconTitleWidget::setIcon(const QIcon& icon)
{
if (icon.isNull())
{
_iconLabel->setPixmap(QPixmap());
_iconLabel->setVisible(false);
}
else
{
_iconLabel->setPixmap(icon.pixmap(16, 16));
_iconLabel->setVisible(true);
}
}
void IconTitleWidget::setTitle(const QString& title)
{
if (title.isEmpty())
{
_titleLabel->setText(QString());
_titleLabel->setVisible(false);
}
else
{
_titleLabel->setText(title);
_titleLabel->setVisible(true);
}
}
void IconTitleWidget::polishUpdate()
{
QList<QWidget*> widgets;
widgets.append(_iconLabel);
widgets.append(_titleLabel);
foreach (QWidget* w, widgets)
{
w->style()->unpolish(w);
w->style()->polish(w);
w->update();
}
}

View File

@ -1,26 +0,0 @@
#ifndef ICONTITLEWIDGET_H
#define ICONTITLEWIDGET_H
#include <QFrame>
class QIcon;
class QString;
class QLabel;
class IconTitleWidget : public QFrame
{
Q_OBJECT
public:
explicit IconTitleWidget(const QIcon& icon, const QString& title, QWidget *parent = 0);
public slots:
void setIcon(const QIcon& icon);
void setTitle(const QString& title);
void polishUpdate();
public:
QLabel* _iconLabel;
QLabel* _titleLabel;
};
#endif // ICONTITLEWIDGET_H

View File

@ -1,28 +0,0 @@
#include <QString>
#include <QFile>
#include <QApplication>
#include "mainwindow.h"
static void initStyleSheet(QApplication& a)
{
//Q_INIT_RESOURCE(ads); // If static linked.
QFile f(":ads/stylesheets/default-windows.css");
if (f.open(QFile::ReadOnly))
{
const QByteArray ba = f.readAll();
f.close();
a.setStyleSheet(QString(ba));
}
}
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
a.setQuitOnLastWindowClosed(true);
initStyleSheet(a);
MainWindow mw;
mw.show();
return a.exec();
}

View File

@ -1,195 +0,0 @@
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <QTime>
#include <QLabel>
#include <QTextEdit>
#include <QCalendarWidget>
#include <QFrame>
#include <QTreeView>
#include <QFileSystemModel>
#include <QBoxLayout>
#include "SectionWidget.h"
#include "DropOverlay.h"
#include "dialogs/SectionContentListWidget.h"
#include "icontitlewidget.h"
///////////////////////////////////////////////////////////////////////
static int CONTENT_COUNT = 0;
static ads::SectionContent::RefPtr createLongTextLabelSC(ads::CMainContainerWidget* container)
{
QWidget* w = new QWidget();
QBoxLayout* bl = new QBoxLayout(QBoxLayout::TopToBottom);
w->setLayout(bl);
QLabel* l = new QLabel();
l->setWordWrap(true);
l->setAlignment(Qt::AlignTop | Qt::AlignLeft);
l->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."));
bl->addWidget(l);
const int index = ++CONTENT_COUNT;
ads::SectionContent::RefPtr sc = ads::SectionContent::newSectionContent(QString("uname-%1").arg(index), container, new IconTitleWidget(QIcon(), QString("Label %1").arg(index)), w);
sc->setTitle("Ein Label " + QString::number(index));
return sc;
}
static ads::SectionContent::RefPtr createCalendarSC(ads::CMainContainerWidget* container)
{
QCalendarWidget* w = new QCalendarWidget();
const int index = ++CONTENT_COUNT;
return ads::SectionContent::newSectionContent(QString("uname-%1").arg(index), container, new IconTitleWidget(QIcon(), QString("Calendar %1").arg(index)), w);
}
static ads::SectionContent::RefPtr createFileSystemTreeSC(ads::CMainContainerWidget* container)
{
QTreeView* w = new QTreeView();
w->setFrameShape(QFrame::NoFrame);
// QFileSystemModel* m = new QFileSystemModel(w);
// m->setRootPath(QDir::currentPath());
// w->setModel(m);
const int index = ++CONTENT_COUNT;
return ads::SectionContent::newSectionContent(QString("uname-%1").arg(index), container, new IconTitleWidget(QIcon(), QString("Filesystem %1").arg(index)), w);
}
static void storeDataHelper(const QString& fname, const QByteArray& ba)
{
QFile f(fname + QString(".dat"));
if (f.open(QFile::WriteOnly))
{
f.write(ba);
f.close();
}
}
static QByteArray loadDataHelper(const QString& fname)
{
QFile f(fname + QString(".dat"));
if (f.open(QFile::ReadOnly))
{
QByteArray ba = f.readAll();
f.close();
return ba;
}
return QByteArray();
}
///////////////////////////////////////////////////////////////////////
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
// Setup actions.
connect(ui->actionContentList, SIGNAL(triggered()), this, SLOT(showSectionContentListDialog()));
// ADS - Create main container (ContainerWidget).
_container = new ads::CMainContainerWidget();
connect(_container, SIGNAL(activeTabChanged(const SectionContent::RefPtr&, bool)), this, SLOT(onActiveTabChanged(const SectionContent::RefPtr&, bool)));
connect(_container, SIGNAL(sectionContentVisibilityChanged(SectionContent::RefPtr,bool)), this, SLOT(onSectionContentVisibilityChanged(SectionContent::RefPtr,bool)));
setCentralWidget(_container);
createContent();
// Default window geometry
resize(800, 600);
restoreGeometry(loadDataHelper("MainWindow"));
// ADS - Restore geometries and states of contents.
//_container->restoreState(loadDataHelper("ContainerWidget"));
_container->dumpLayout();
}
MainWindow::~MainWindow()
{
delete ui;
}
void MainWindow::createContent()
{
// ADS - Adding some contents.
// Test #1: Use high-level public API
ads::CMainContainerWidget* cw = _container;
ads::SectionWidget* sw = nullptr;
sw = _container->addSectionContent(createLongTextLabelSC(cw), nullptr, ads::CenterDropArea);
sw = _container->addSectionContent(createCalendarSC(cw), nullptr, ads::LeftDropArea);
sw = _container->addSectionContent(createFileSystemTreeSC(cw), nullptr, ads::BottomDropArea);
sw = _container->addSectionContent(createCalendarSC(cw), nullptr, ads::BottomDropArea);
/*_container->addSectionContent(createCalendarSC(_container));
_container->addSectionContent(createLongTextLabelSC(_container));
_container->addSectionContent(createLongTextLabelSC(_container));
_container->addSectionContent(createLongTextLabelSC(_container));
ads::SectionContent::RefPtr sc = createLongTextLabelSC(cw);
sc->setFlags(ads::SectionContent::AllFlags ^ ads::SectionContent::Closeable);
_container->addSectionContent(sc);*/
#if 0
// Issue #2: If the first drop is not into CenterDropArea, the application crashes.
ads::CMainContainerWidget* cw = _container;
ads::SectionWidget* sw = NULL;
sw = _container->addSectionContent(createLongTextLabelSC(cw), sw, ads::LeftDropArea);
sw = _container->addSectionContent(createCalendarSC(cw), sw, ads::LeftDropArea);
sw = _container->addSectionContent(createLongTextLabelSC(cw), sw, ads::CenterDropArea);
sw = _container->addSectionContent(createLongTextLabelSC(cw), sw, ads::CenterDropArea);
sw = _container->addSectionContent(createLongTextLabelSC(cw), sw, ads::CenterDropArea);
sw = _container->addSectionContent(createLongTextLabelSC(cw), sw, ads::RightDropArea);
sw = _container->addSectionContent(createLongTextLabelSC(cw), sw, ads::BottomDropArea);
#endif
}
void MainWindow::showSectionContentListDialog()
{
SectionContentListWidget::Values v;
v.cw = _container;
SectionContentListWidget w(this);
w.setValues(v);
w.exec();
}
void MainWindow::onActiveTabChanged(const ads::SectionContent::RefPtr& sc, bool active)
{
Q_UNUSED(active);
IconTitleWidget* itw = dynamic_cast<IconTitleWidget*>(sc->titleWidgetContent());
if (itw)
{
itw->polishUpdate();
}
}
void MainWindow::onSectionContentVisibilityChanged(const ads::SectionContent::RefPtr& sc, bool visible)
{
qDebug() << Q_FUNC_INFO << sc->uniqueName() << visible;
}
void MainWindow::onActionAddSectionContentTriggered()
{
return;
}
void MainWindow::contextMenuEvent(QContextMenuEvent* e)
{
Q_UNUSED(e);
QMenu* m = _container->createContextMenu();
m->exec(QCursor::pos());
delete m;
}
void MainWindow::closeEvent(QCloseEvent* e)
{
Q_UNUSED(e);
storeDataHelper("MainWindow", saveGeometry());
storeDataHelper("ContainerWidget", _container->saveState());
}

View File

@ -1,38 +0,0 @@
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
#include "../../AdvancedDockingSystem/src/MainContainerWidget.h"
#include "../../AdvancedDockingSystem/src/SectionContent.h"
#include "API.h"
namespace Ui {
class MainWindow;
}
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
explicit MainWindow(QWidget *parent = 0);
virtual ~MainWindow();
public slots:
private slots:
void onActiveTabChanged(const ads::SectionContent::RefPtr& sc, bool active);
void onSectionContentVisibilityChanged(const ads::SectionContent::RefPtr& sc, bool visible);
void onActionAddSectionContentTriggered();
protected:
virtual void contextMenuEvent(QContextMenuEvent* e);
virtual void closeEvent(QCloseEvent* e);
private:
Ui::MainWindow *ui;
ads::CMainContainerWidget* _container;
void createContent();
};
#endif // MAINWINDOW_H

View File

@ -1,79 +0,0 @@
<?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="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 class="QMenu" name="menuFile">
<property name="title">
<string>File</string>
</property>
<addaction name="actionExit"/>
</widget>
<widget class="QMenu" name="menuView">
<property name="title">
<string>View</string>
</property>
<addaction name="actionContentList"/>
<addaction name="actionDemo_2"/>
<addaction name="actionDemo_3"/>
</widget>
<widget class="QMenu" name="menuAbout">
<property name="title">
<string>About</string>
</property>
</widget>
<addaction name="menuFile"/>
<addaction name="menuView"/>
<addaction name="menuAbout"/>
</widget>
<action name="actionAddSectionContent">
<property name="text">
<string>Add SectionContent</string>
</property>
</action>
<action name="actionContentList">
<property name="text">
<string>Contents...</string>
</property>
</action>
<action name="actionDemo_2">
<property name="text">
<string>Demo 2</string>
</property>
</action>
<action name="actionDemo_3">
<property name="text">
<string>Demo 3</string>
</property>
</action>
<action name="actionExit">
<property name="text">
<string>Exit</string>
</property>
</action>
</widget>
<layoutdefault spacing="6" margin="11"/>
<resources/>
<connections/>
</ui>

View File

@ -1,90 +0,0 @@
#include "SectionContentListModel.h"
SectionContentListModel::SectionContentListModel(QObject* parent) :
QAbstractTableModel(parent)
{
_headers.insert(UidColumn, "UID");
_headers.insert(UniqueNameColumn, "Unique Name");
_headers.insert(TitleColumn, "Title");
_headers.insert(VisibleColumn, "Visible");
}
SectionContentListModel::~SectionContentListModel()
{
}
void SectionContentListModel::init(ads::CMainContainerWidget* cw)
{
beginResetModel();
_cw = cw;
_contents = _cw->contents();
endResetModel();
}
int SectionContentListModel::columnCount(const QModelIndex& parent) const
{
Q_UNUSED(parent)
return _headers.count();
}
QVariant SectionContentListModel::headerData(int section, Qt::Orientation orientation, int role) const
{
if (orientation == Qt::Horizontal && role == Qt::DisplayRole)
return _headers.value(section);
return QVariant();
}
int SectionContentListModel::rowCount(const QModelIndex& parent) const
{
Q_UNUSED(parent)
return _contents.count();
}
QVariant SectionContentListModel::data(const QModelIndex& index, int role) const
{
if (!index.isValid() || index.row() > rowCount(index) - 1)
return QVariant();
const ads::SectionContent::RefPtr sc = _contents.at(index.row());
if (sc.isNull())
return QVariant();
switch (role)
{
case Qt::DisplayRole:
{
switch (index.column())
{
case UidColumn:
return sc->uid();
case UniqueNameColumn:
return sc->uniqueName();
case TitleColumn:
return sc->title();
case VisibleColumn:
return _cw->isSectionContentVisible(sc);
}
}
}
return QVariant();
}
bool SectionContentListModel::removeRows(int row, int count, const QModelIndex& parent)
{
if (row > rowCount(parent) - 1)
return false;
const int first = row;
const int last = row + count - 1;
beginRemoveRows(parent, first, last);
for (int i = last; i >= first; --i)
{
const ads::SectionContent::RefPtr sc = _contents.at(i);
_cw->removeSectionContent(sc);
_contents.removeAt(i);
}
endRemoveRows();
return true;
}

View File

@ -1,46 +0,0 @@
#ifndef ADS_SECTIONCONTENTMODEL_H
#define ADS_SECTIONCONTENTMODEL_H
#include <QHash>
#include <QList>
#include <QString>
#include <QAbstractTableModel>
#include "../../../AdvancedDockingSystem/src/SectionContent.h"
#include "MainContainerWidget.h"
#include "API.h"
namespace ads {class CMainContainerWidget;}
class SectionContentListModel : public QAbstractTableModel
{
Q_OBJECT
public:
enum Column
{
UidColumn,
UniqueNameColumn,
TitleColumn,
VisibleColumn
};
SectionContentListModel(QObject* parent);
virtual ~SectionContentListModel();
void init(ads::CMainContainerWidget* cw);
virtual int columnCount(const QModelIndex &parent) const;
virtual QVariant headerData(int section, Qt::Orientation orientation, int role) const;
virtual int rowCount(const QModelIndex &parent) const;
virtual QVariant data(const QModelIndex &index, int role) const;
virtual bool removeRows(int row, int count, const QModelIndex &parent);
private:
QHash<int, QString> _headers;
ads::CMainContainerWidget* _cw;
QList<ads::SectionContent::RefPtr> _contents;
};
#endif

View File

@ -1,38 +0,0 @@
#include "SectionContentListWidget.h"
#include "SectionContentListModel.h"
SectionContentListWidget::SectionContentListWidget(QWidget* parent) :
QDialog(parent)
{
_ui.setupUi(this);
connect(_ui.deleteButton, SIGNAL(clicked(bool)), this, SLOT(onDeleteButtonClicked()));
}
void SectionContentListWidget::setValues(const SectionContentListWidget::Values& v)
{
_v = v;
// Reset
QAbstractItemModel* m = _ui.tableView->model();
if (m)
{
_ui.tableView->setModel(NULL);
delete m;
m = NULL;
}
// Fill.
SectionContentListModel* sclm = new SectionContentListModel(this);
sclm->init(_v.cw);
_ui.tableView->setModel(sclm);
}
void SectionContentListWidget::onDeleteButtonClicked()
{
const QModelIndex mi = _ui.tableView->currentIndex();
if (!mi.isValid())
return;
_ui.tableView->model()->removeRows(mi.row(), 1, mi.parent());
}

View File

@ -1,33 +0,0 @@
#ifndef SECTIONCONTENTLISTWIDGET
#define SECTIONCONTENTLISTWIDGET
#include <QDialog>
#include "../../../AdvancedDockingSystem/src/SectionContent.h"
#include "MainContainerWidget.h"
#include "ui_SectionContentListWidget.h"
#include "API.h"
class SectionContentListWidget : public QDialog
{
Q_OBJECT
public:
class Values
{
public:
ads::CMainContainerWidget* cw;
};
SectionContentListWidget(QWidget* parent);
void setValues(const Values& v);
private slots:
void onDeleteButtonClicked();
private:
Ui::SectionContentListWidgetForm _ui;
Values _v;
};
#endif

View File

@ -1,61 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>SectionContentListWidgetForm</class>
<widget class="QWidget" name="SectionContentListWidgetForm">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>522</width>
<height>258</height>
</rect>
</property>
<property name="windowTitle">
<string>Form</string>
</property>
<layout class="QHBoxLayout" name="horizontalLayout">
<item>
<widget class="QTableView" name="tableView">
<property name="editTriggers">
<set>QAbstractItemView::NoEditTriggers</set>
</property>
<property name="alternatingRowColors">
<bool>true</bool>
</property>
<property name="selectionMode">
<enum>QAbstractItemView::SingleSelection</enum>
</property>
<property name="selectionBehavior">
<enum>QAbstractItemView::SelectRows</enum>
</property>
</widget>
</item>
<item>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<widget class="QPushButton" name="deleteButton">
<property name="text">
<string>Delete</string>
</property>
</widget>
</item>
<item>
<spacer name="verticalSpacer">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>40</height>
</size>
</property>
</spacer>
</item>
</layout>
</item>
</layout>
</widget>
<resources/>
<connections/>
</ui>

View File

@ -1,7 +0,0 @@
HEADERS += \
$$PWD/src/TestCore.h
SOURCES += \
$$PWD/src/main.cpp \
$$PWD/src/TestCore.cpp

View File

@ -1,16 +0,0 @@
include($$(cetoni_repository)/build/qt/qtprojectsettings/common.pri)
TARGET = AdvancedDockingSystemUnitTests
QT += core gui testlib
greaterThan(QT_MAJOR_VERSION, 4): QT += widgets
greaterThan(QT_MAJOR_VERSION, 4): DEFINES += ADS_NAMESPACE_ENABLED
DEFINES += ADS_IMPORT
INCLUDEPATH += $$PWD/src
INCLUDEPATH += $$PWD/../AdvancedDockingSystem/include
DEPENDPATH += $$PWD/../AdvancedDockingSystem/include
include(AdvancedDockingSystemUnitTests.pri)
include(../AdvancedDockingSystem/AdvancedDockingSystem.pri)

View File

@ -1,68 +0,0 @@
#include "TestCore.h"
#include "ads/API.h"
#include "ads/Serialization.h"
void TestCore::serialization()
{
QList<QByteArray> datas;
datas.append(QByteArray("Custom Data Here!!!"));
datas.append(QByteArray("Even More..."));
datas.append(QByteArray("lalalaalalalalalalal").toBase64());
// WRITE some data.
ADS_NS_SER::InMemoryWriter writer;
for (int i = 0; i < datas.count(); ++i)
{
QVERIFY(writer.write(ADS_NS_SER::ET_Custom + i, datas.at(i)));
}
// Type: SectionIndexData
ADS_NS_SER::SectionIndexData sid;
for (int i = 0; i < 1; ++i)
{
ADS_NS_SER::SectionEntity se;
se.x = i;
se.y = i;
se.width = 100 + i;
se.height = 100 + i;
se.currentIndex = i;
for (int j = 0; j < 1; ++j)
{
ADS_NS_SER::SectionContentEntity sce;
sce.uniqueName = QString("uname-%1-%2").arg(i).arg(j);
sce.preferredIndex = 8;
sce.visible = true;
se.sectionContents.append(sce);
se.sectionContentsCount += 1;
}
sid.sections.append(se);
sid.sectionsCount += 1;
}
QVERIFY(writer.write(sid));
QVERIFY(writer.offsetsCount() == datas.count() + 1);
const QByteArray writtenData = writer.toByteArray();
QVERIFY(writtenData.size() > 0);
// READ and validate written data.
ADS_NS_SER::InMemoryReader reader(writtenData);
QVERIFY(reader.initReadHeader());
QVERIFY(reader.offsetsCount() == datas.count() + 1);
for (int i = 0; i < datas.count(); ++i)
{
QByteArray readData;
QVERIFY(reader.read(ADS_NS_SER::ET_Custom + i, readData));
QVERIFY(readData == datas.at(i));
}
// Type: SectionIndexData
ADS_NS_SER::SectionIndexData sidRead;
QVERIFY(reader.read(sidRead));
// TODO compare sidRead with sid
}
QTEST_MAIN(TestCore)

View File

@ -1,14 +0,0 @@
#ifndef TEST_CORE_H
#define TEST_CORE_H
#include <QtTest/QtTest>
class TestCore : public QObject
{
Q_OBJECT
private slots:
void serialization();
};
#endif

View File

@ -1 +0,0 @@
#include <QtTest/QtTest>

5
ads.pro Normal file
View File

@ -0,0 +1,5 @@
TEMPLATE = subdirs
SUBDIRS = \
src \
demo

View File

@ -1,7 +0,0 @@
TEMPLATE = subdirs
SUBDIRS = \
AdvancedDockingSystem \
AdvancedDockingSystemDemo \
AdvancedDockingSystemDemo_v2 \
AdvancedDockingSystemUnitTests

View File

@ -1,10 +1,9 @@
include($$(cetoni_repository)/build/qt/qtprojectsettings/common.pri)
TARGET = AdvancedDockingSystemDemo_v2
TARGET = AdvancedDockingSystemDemo
QT += core gui
greaterThan(QT_MAJOR_VERSION, 4): QT += widgets
greaterThan(QT_MAJOR_VERSION, 4): DEFINES += ADS_NAMESPACE_ENABLED
QT += core gui widgets
DEFINES += ADS_NAMESPACE_ENABLED
windows {
# MinGW
@ -17,15 +16,15 @@ windows {
}
SOURCES += \
src/main.cpp \
src/mainwindow.cpp
main.cpp \
mainwindow.cpp
HEADERS += \
src/mainwindow.h
mainwindow.h
FORMS += \
src/mainwindow.ui
mainwindow.ui
# Dependency: AdvancedDockingSystem (shared)
@ -33,8 +32,6 @@ win32:CONFIG(release, debug|release): LIBS += -l$$qtLinkLibrary(AdvancedDockingS
else:win32:CONFIG(debug, debug|release): LIBS += -l$$qtLinkLibrary(AdvancedDockingSystem)
else:unix: LIBS += -L$$OUT_PWD/../AdvancedDockingSystem/ -lAdvancedDockingSystem
INCLUDEPATH += $$PWD/../AdvancedDockingSystem/src \
$$PWD/../AdvancedDockingSystem/src/v2
INCLUDEPATH += ../src
DEPENDPATH += $$PWD/../AdvancedDockingSystem/src \
$$PWD/../AdvancedDockingSystem/src/v2
DEPENDPATH += ../src

View File

@ -6,7 +6,6 @@
static void initStyleSheet(QApplication& a)
{
//Q_INIT_RESOURCE(ads); // If static linked.
QFile f(":ads/stylesheets/default-windows2.css");
if (f.open(QFile::ReadOnly))
{

View File

@ -1,4 +1,5 @@
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <QTime>

View File

@ -542,6 +542,7 @@ void CDockAreaWidget::setCurrentIndex(int index)
}
d->ContentsLayout->setCurrentIndex(index);
emit currentChanged(index);
}

View File

@ -159,6 +159,19 @@ public slots:
* Updates the dock area layout and components visibility
*/
void updateDockArea();
signals:
/**
* This signal is emitted when user clicks on a tab at an index.
*/
void tabBarClicked(int index);
/**
* This signal is emitted when the tab bar's current tab changes. The new
* current has the given index, or -1 if there isn't a new one
* @param index
*/
void currentChanged(int index);
}; // class DockAreaWidget
}
// namespace ads

View File

@ -117,6 +117,7 @@ struct DockWidgetTitleBarPrivate
};
// struct DockWidgetTitleBarPrivate
//============================================================================
DockWidgetTitleBarPrivate::DockWidgetTitleBarPrivate(CDockWidgetTitleBar* _public) :
_this(_public)

54
src/src.pro Normal file
View File

@ -0,0 +1,54 @@
include($$(cetoni_repository)/build/qt/qtprojectsettings/shared_library.pri)
include(src/v2/v2.pri)
TARGET = $$qtLibraryTarget(AdvancedDockingSystem)
TEMPLATE = lib
#VERSION = 1.0.0
CONFIG += adsBuildShared
QT += core gui widgets
DEFINES += ADS_NAMESPACE_ENABLED
adsBuildShared {
CONFIG += shared
DEFINES += ADS_EXPORT
}
!adsBuildShared {
CONFIG += staticlib
}
windows {
# MinGW
*-g++* {
QMAKE_CXXFLAGS += -std=c++11
QMAKE_CXXFLAGS += -Wall -Wextra -pedantic
}
# MSVC
*-msvc* {
}
}
RESOURCES += ads.qrc
HEADERS += \
ads_globals.h \
DockAreaWidget.h \
DockContainerWidget.h \
DockManager.h \
DockWidget.h \
DockWidgetTitleBar.h \
FloatingDockContainer.h \
DockOverlay.h
SOURCES += \
ads_globals.cpp \
DockAreaWidget.cpp \
DockContainerWidget.cpp \
DockManager.cpp \
DockWidget.cpp \
DockWidgetTitleBar.cpp \
FloatingDockContainer.cpp \
DockOverlay.cpp