Added resize support for new QFrame based AutoHideDockContainer

This commit is contained in:
Uwe Kindler 2022-10-24 16:21:26 +02:00
parent 93d0d4b1c2
commit f549a92c01
11 changed files with 489 additions and 91 deletions

View File

@ -34,6 +34,7 @@
#include "SideTabBar.h"
#include "DockAreaWidget.h"
#include "DockingStateReader.h"
#include "ResizeHandle.h"
#include <QXmlStreamWriter>
#include <QBoxLayout>
@ -48,6 +49,51 @@ namespace ads
{
static const int ResizeMargin = 4;
//============================================================================
bool static isHorizontalArea(CDockWidgetSideTab::SideTabBarArea Area)
{
switch (Area)
{
case CDockWidgetSideTab::Top:
case CDockWidgetSideTab::Bottom: return true;
case CDockWidgetSideTab::Left:
case CDockWidgetSideTab::Right: return false;
}
return true;
}
//============================================================================
Qt::Edge static edgeFromSideTabBarArea(CDockWidgetSideTab::SideTabBarArea Area)
{
switch (Area)
{
case CDockWidgetSideTab::Top: return Qt::BottomEdge;
case CDockWidgetSideTab::Bottom: return Qt::TopEdge;
case CDockWidgetSideTab::Left: return Qt::RightEdge;
case CDockWidgetSideTab::Right: return Qt::LeftEdge;
}
return Qt::LeftEdge;
}
//============================================================================
int resizeHandleLayoutPosition(CDockWidgetSideTab::SideTabBarArea Area)
{
switch (Area)
{
case CDockWidgetSideTab::Bottom:
case CDockWidgetSideTab::Right: return 0;
case CDockWidgetSideTab::Top:
case CDockWidgetSideTab::Left: return 1;
}
return 0;
}
struct AutoHideDockContainerPrivate
{
CAutoHideDockContainer* _this;
@ -55,6 +101,9 @@ struct AutoHideDockContainerPrivate
CDockWidget* DockWidget{nullptr};
QPointer<CDockManager> DockManager{nullptr};
CDockWidgetSideTab::SideTabBarArea SideTabBarArea;
QBoxLayout* Layout;
CResizeHandle* ResizeHandle = nullptr;
QSize Size;
/**
* Private data constructor
@ -117,35 +166,15 @@ struct AutoHideDockContainerPrivate
return QPoint();
}
/*
* Convenience function to get dock area with splitter total size
*/
QRect getDockAreaWithSplitterRect() const
void updateResizeHandleSizeLimitMax()
{
const auto rect = DockArea->frameGeometry();
const auto topLeft = rect.topLeft();
const auto handleSize = 0;
if (SideTabBarArea == CDockWidgetSideTab::Bottom)
{
return QRect(QPoint(topLeft.x(), topLeft.y() - handleSize), QSize(rect.size().width(), rect.size().height() + handleSize));
}
if (SideTabBarArea == CDockWidgetSideTab::Top)
{
return QRect(QPoint(topLeft.x(), topLeft.y()), QSize(rect.size().width(), rect.size().height() + handleSize));
}
auto offset = 0;
if (SideTabBarArea == CDockWidgetSideTab::SideTabBarArea::Right)
{
offset = handleSize;
}
return QRect(QPoint(topLeft.x() - offset, topLeft.y()), QSize(rect.size().width() + handleSize, rect.size().height()));
auto Rect = DockManager->contentRect();
ResizeHandle->setMaxResizeSize(ResizeHandle->orientation() == Qt::Horizontal
? Rect.width() : Rect.height());
}
}; // struct AutoHideDockContainerPrivate
//============================================================================
AutoHideDockContainerPrivate::AutoHideDockContainerPrivate(
CAutoHideDockContainer *_public) :
@ -154,11 +183,14 @@ AutoHideDockContainerPrivate::AutoHideDockContainerPrivate(
}
//============================================================================
CDockContainerWidget* CAutoHideDockContainer::parentContainer() const
{
return internal::findParent<CDockContainerWidget*>(this);
}
//============================================================================
CAutoHideDockContainer::CAutoHideDockContainer(CDockManager* DockManager, CDockWidgetSideTab::SideTabBarArea area, CDockContainerWidget* parent) :
Super(parent),
@ -173,11 +205,16 @@ CAutoHideDockContainer::CAutoHideDockContainer(CDockManager* DockManager, CDockW
d->DockArea->updateTitleBarButtonToolTip();
setObjectName("autoHideDockContainer");
QBoxLayout *l = new QBoxLayout(QBoxLayout::TopToBottom);
l->setContentsMargins(0, 0, 0, 0);
l->setSpacing(0);
setLayout(l);
l->addWidget(d->DockArea);
d->Layout = new QBoxLayout(isHorizontalArea(area) ? QBoxLayout::TopToBottom : QBoxLayout::LeftToRight);
d->Layout->setContentsMargins(0, 0, 0, 0);
d->Layout->setSpacing(0);
setLayout(d->Layout);
d->Layout->addWidget(d->DockArea);
d->ResizeHandle = new CResizeHandle(edgeFromSideTabBarArea(area), this);
d->ResizeHandle->setMinResizeSize(64);
d->Layout->insertWidget(resizeHandleLayoutPosition(area), d->ResizeHandle);
d->Size = d->DockArea->size();
updateSize();
parent->registerAutoHideWidget(this);
@ -195,33 +232,23 @@ CAutoHideDockContainer::CAutoHideDockContainer(CDockWidget* DockWidget, CDockWid
}
//============================================================================
void CAutoHideDockContainer::updateMask()
{
//setMask(d->getDockAreaWithSplitterRect());
}
//============================================================================
void CAutoHideDockContainer::updateSize()
{
qDebug() << "CAutoHideDockContainer::updateSize()";
const auto dockContainerParent = parentContainer();
const auto rootSplitter = dockContainerParent->rootSplitter();
const auto rect = rootSplitter->frameGeometry();
auto dockContainerParent = parentContainer();
auto rect = dockContainerParent->contentRect();
switch (sideTabBarArea())
{
case CDockWidgetSideTab::Top:
move(rect.topLeft());
resize(rect.width(), height());
setContentsMargins(QMargins(0, 0, 0, ResizeMargin));
resize(rect.width(), qMin(rect.height(), d->Size.height()));
break;
case CDockWidgetSideTab::Left:
move(rect.topLeft());
resize(width(), rect.height());
setContentsMargins(QMargins(0, 0, ResizeMargin, 0));
resize(qMin(d->Size.width(), rect.width()), rect.height());
break;
case CDockWidgetSideTab::Right:
@ -229,8 +256,7 @@ void CAutoHideDockContainer::updateSize()
QPoint p = rect.topRight();
p.rx() -= (width() - 1);
move(p);
resize(width(), rect.height());
setContentsMargins(QMargins(ResizeMargin, 0, 0, 0));
resize(qMin(d->Size.width(), rect.width()), rect.height());
}
break;
@ -239,8 +265,7 @@ void CAutoHideDockContainer::updateSize()
QPoint p = rect.bottomLeft();
p.ry() -= (height() - 1);
move(p);
resize(rect.width(), height());
setContentsMargins(QMargins(0, ResizeMargin, 0, 0));
resize(rect.width(), qMin(rect.height(), d->Size.height()));
}
break;
}
@ -297,7 +322,6 @@ void CAutoHideDockContainer::addDockWidget(CDockWidget* DockWidget)
this->resize(OldDockArea ? OldDockArea->size() : d->DockWidget->size());
updateSize();
updateMask();
}
@ -450,12 +474,12 @@ void CAutoHideDockContainer::collapseView(bool Enable)
}
else
{
d->updateResizeHandleSizeLimitMax();
raise();
show();
d->DockArea->show();
d->DockWidget->show();
updateSize();
updateMask();
d->DockManager->setDockWidgetFocused(d->DockWidget);
qApp->installEventFilter(this);
}
@ -475,9 +499,11 @@ void CAutoHideDockContainer::toggleCollapseState()
bool CAutoHideDockContainer::eventFilter(QObject* watched, QEvent* event)
{
if (event->type() == QEvent::Resize)
{
if (!d->ResizeHandle->isResizing())
{
updateSize();
updateMask();
}
}
else if (event->type() == QEvent::MouseButtonPress)
{
@ -507,8 +533,7 @@ bool CAutoHideDockContainer::eventFilter(QObject* watched, QEvent* event)
// user works in it
QMouseEvent* me = static_cast<QMouseEvent*>(event);
auto pos = mapFromGlobal(me->globalPos());
auto rect = d->getDockAreaWithSplitterRect();
if (rect.contains(pos))
if (rect().contains(pos))
{
return Super::eventFilter(watched, event);
}
@ -538,39 +563,14 @@ bool CAutoHideDockContainer::eventFilter(QObject* watched, QEvent* event)
void CAutoHideDockContainer::resizeEvent(QResizeEvent* event)
{
std::cout << "ResizeEvent" << std::endl;
updateMask();
Super::resizeEvent(event);
}
//============================================================================
bool CAutoHideDockContainer::event(QEvent *event)
if (d->ResizeHandle->isResizing())
{
return Super::event(event);
}
//============================================================================
void CAutoHideDockContainer::mouseMoveEvent(QMouseEvent *event)
{
qDebug() << "mouseMoveEvent: " << event->pos();
qDebug() << "height: " << height();
auto p = event->pos();
if (p.y() > (height() - ResizeMargin - 1) && p.y() < height())
{
setCursor(Qt::SizeVerCursor);
}
else
{
setCursor(Qt::ArrowCursor);
d->Size = this->size();
qDebug() << "Size " << d->Size;
d->updateResizeHandleSizeLimitMax();
}
}
//============================================================================
void CAutoHideDockContainer::mousePressEvent(QMouseEvent *event)
{
qDebug() << "mousePressEvent: " << event->pos();
}
}

View File

@ -61,11 +61,7 @@ private:
protected:
bool eventFilter(QObject* watched, QEvent* event) override;
void resizeEvent(QResizeEvent* event) override;
void updateMask();
void updateSize();
virtual bool event(QEvent *event) override;
virtual void mouseMoveEvent(QMouseEvent *event) override;
virtual void mousePressEvent(QMouseEvent *event) override;
CDockContainerWidget* parentContainer() const;

View File

@ -2276,7 +2276,7 @@ CSideTabBar* CDockContainerWidget::sideTabBar(CDockWidgetSideTab::SideTabBarArea
//============================================================================
QRect CDockContainerWidget::contentRect()
QRect CDockContainerWidget::contentRect() const
{
if (!d->RootSplitter)
{
@ -2285,6 +2285,17 @@ QRect CDockContainerWidget::contentRect()
return d->RootSplitter->geometry();
}
//===========================================================================
QRect CDockContainerWidget::contentRectGlobal() const
{
if (!d->RootSplitter)
{
return QRect();
}
return internal::globalGeometry(d->RootSplitter);
}
} // namespace ads
//---------------------------------------------------------------------------

View File

@ -331,7 +331,16 @@ public:
/**
* Returns the content rectangle without the autohide side bars
*/
QRect contentRect();
QRect contentRect() const;
/**
* Returns the content rectangle mapped to global space.
* The content rectangle is the rectangle of the dock manager widget minus
* the auto hide side bars. So that means, it is the geometry of the
* internal root splitter mapped to global space.
*/
QRect contentRectGlobal() const;
Q_SIGNALS:
/**

View File

@ -1312,6 +1312,7 @@ void CDockManager::setFloatingContainersTitle(const QString& Title)
FloatingContainersTitle = Title;
}
//===========================================================================
QString CDockManager::floatingContainersTitle()
{

269
src/ResizeHandle.cpp Normal file
View File

@ -0,0 +1,269 @@
//============================================================================
/// \file ResizeHandle.cpp
/// \author Uwe Kindler
/// \date 24.10.2022
/// \brief Implementation of CResizeHandle class
//============================================================================
//============================================================================
// INCLUDES
//============================================================================
#include "ResizeHandle.h"
#include <QDebug>
#include <QStyle>
#include <QStyleOption>
#include <QMouseEvent>
#include "ads_globals.h"
namespace ads
{
/**
* Private data class of CResizeHandle class (pimpl)
*/
struct ResizeHandlePrivate
{
CResizeHandle *_this;
Qt::Edge HandlePosition = Qt::LeftEdge;
QWidget* Target = nullptr;
int MouseOffset = 0;
bool Pressed = false;
int MinSize = 0;
int MaxSize = 1;
/**
* Private data constructor
*/
ResizeHandlePrivate(CResizeHandle *_public);
/**
* Pick position component from pos depending on orientation
*/
int pick(const QPoint &pos) const
{
return _this->orientation() == Qt::Horizontal ? pos.x() : pos.y();
}
/**
* Returns true, if orientation is horizontal
*/
bool isHorizontal() const
{
return _this->orientation() == Qt::Horizontal;
}
};
// struct ResizeHandlePrivate
//============================================================================
ResizeHandlePrivate::ResizeHandlePrivate(CResizeHandle *_public) :
_this(_public)
{
}
//============================================================================
CResizeHandle::CResizeHandle(Qt::Edge HandlePosition, QWidget* parent) :
Super(parent),
d(new ResizeHandlePrivate(this))
{
d->Target = parent;
setHandlePosition(HandlePosition);
setMinResizeSize(48);
setMaxResizeSize(d->isHorizontal() ? parent->height() : parent->width());
if (!d->isHorizontal())
{
setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed);
}
else
{
setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Expanding);
}
}
//============================================================================
CResizeHandle::~CResizeHandle()
{
delete d;
}
//============================================================================
void CResizeHandle::mouseMoveEvent(QMouseEvent* e)
{
if (!(e->buttons() & Qt::LeftButton))
{
return;
}
int pos = d->pick(e->pos()) - d->MouseOffset;
auto OldGeometry = d->Target->geometry();
auto NewGeometry = OldGeometry;
switch (d->HandlePosition)
{
case Qt::LeftEdge:
{
NewGeometry.adjust(pos, 0, 0, 0);
int Size = qBound(d->MinSize, NewGeometry.width(), d->MaxSize);
NewGeometry.setWidth(Size);
NewGeometry.moveTopRight(OldGeometry.topRight());
}
break;
case Qt::RightEdge:
{
NewGeometry.adjust(0, 0, pos, 0);
int Size = qBound(d->MinSize, NewGeometry.width(), d->MaxSize);
NewGeometry.setWidth(Size);
}
break;
case Qt::TopEdge:
{
NewGeometry.adjust(0, pos, 0, 0);
int Size = qBound(d->MinSize, NewGeometry.height(), d->MaxSize);
NewGeometry.setHeight(Size);
NewGeometry.moveBottomLeft(OldGeometry.bottomLeft());
}
break;
case Qt::BottomEdge:
{
NewGeometry.adjust(0, 0, 0, pos);
int Size = qBound(d->MinSize, NewGeometry.height(), d->MaxSize);
NewGeometry.setHeight(Size);
}
break;
}
d->Target->setGeometry(NewGeometry);
//qDebug() << "globalGeometry(): " << internal::globalGeometry(d->Target);
//qDebug() << "parentGlobalGeometry(): " << internal::globalGeometry(d->Target->parentWidget());
/*if (opaqueResize())
{
moveSplitter(pos);
}
else
{
//d->s->setRubberBand(closestLegalPosition(pos));
}*/
}
//============================================================================
void CResizeHandle::mousePressEvent(QMouseEvent* e)
{
qDebug() << "CResizeHandle::mousePressEvent " << e;
if (e->button() == Qt::LeftButton)
{
d->MouseOffset = d->pick(e->pos());
d->Pressed = true;
update();
}
}
//============================================================================
void CResizeHandle::mouseReleaseEvent(QMouseEvent* e)
{
qDebug() << "CResizeHandle::mouseReleaseEvent " << e;
/*if (!opaqueResize() && e->button() == Qt::LeftButton) {
int pos = d->pick(parentWidget()->mapFromGlobal(e->globalPos()))
- d->mouseOffset;
d->s->setRubberBand(-1);
moveSplitter(pos);
}*/
if (e->button() == Qt::LeftButton)
{
d->Pressed = false;
update();
}
}
//============================================================================
void CResizeHandle::setHandlePosition(Qt::Edge HandlePosition)
{
d->HandlePosition = HandlePosition;
switch (d->HandlePosition)
{
case Qt::LeftEdge: // fall through
case Qt::RightEdge: setCursor(Qt::SizeHorCursor); break;
case Qt::TopEdge: // fall through
case Qt::BottomEdge: setCursor(Qt::SizeVerCursor); break;
}
}
//============================================================================
Qt::Edge CResizeHandle::handlePostion() const
{
return d->HandlePosition;
}
//============================================================================
Qt::Orientation CResizeHandle::orientation() const
{
switch (d->HandlePosition)
{
case Qt::LeftEdge: // fall through
case Qt::RightEdge: return Qt::Horizontal;
case Qt::TopEdge: // fall through
case Qt::BottomEdge: return Qt::Vertical;
}
return Qt::Horizontal;
}
//============================================================================
QSize CResizeHandle::sizeHint() const
{
QSize Result;
switch (d->HandlePosition)
{
case Qt::LeftEdge: // fall through
case Qt::RightEdge: Result = QSize(4, d->Target->height()); break;
case Qt::TopEdge: // fall through
case Qt::BottomEdge: Result = QSize(d->Target->width(), 4); break;
}
qDebug() << "CResizeHandle::sizeHint(): " << Result;
return Result;
/*parentWidget()->style()->sizeFromContents(QStyle::CT_Splitter, &opt, QSize(hw, hw), d->s)
.expandedTo(QApplication::globalStrut());*/
}
//============================================================================
bool CResizeHandle::isResizing() const
{
return d->Pressed;
}
//============================================================================
void CResizeHandle::setMinResizeSize(int MinSize)
{
qDebug() << "CResizeHandle::setMinResizeSize " << MinSize;
d->MinSize = MinSize;
}
//============================================================================
void CResizeHandle::setMaxResizeSize(int MaxSize)
{
qDebug() << "CResizeHandle::setMaxResizeSize " << MaxSize;
d->MaxSize = MaxSize;
}
} // namespace ads
//---------------------------------------------------------------------------
// EOF ResizeHandle.cpp

90
src/ResizeHandle.h Normal file
View File

@ -0,0 +1,90 @@
#ifndef ResizeHandleH
#define ResizeHandleH
//============================================================================
/// \file ResizeHandle.h
/// \author Uwe Kindler
/// \date 24.10.2022
/// \brief Declaration of CResizeHandle class
//============================================================================
//============================================================================
// INCLUDES
//============================================================================
#include <QFrame>
namespace ads
{
struct ResizeHandlePrivate;
/**
* Resize handle for resizing its parent widget
*/
class CResizeHandle : public QFrame
{
Q_OBJECT
Q_DISABLE_COPY(CResizeHandle)
private:
ResizeHandlePrivate* d; ///< private data (pimpl)
friend struct ResizeHandlePrivate;
protected:
void mouseMoveEvent(QMouseEvent *) override;
void mousePressEvent(QMouseEvent *) override;
void mouseReleaseEvent(QMouseEvent *) override;
public:
using Super = QFrame;
/**
* Default Constructor
*/
CResizeHandle(Qt::Edge HandlePosition, QWidget* parent);
/**
* Virtual Destructor
*/
virtual ~CResizeHandle();
/**
* Sets the handle position
*/
void setHandlePosition(Qt::Edge HandlePosition);
/**
* Returns the handle position
*/
Qt::Edge handlePostion() const;
/**
* Returns the orientation of this resize handle
*/
Qt::Orientation orientation() const;
/**
* Returns the size hint
*/
QSize sizeHint() const override;
/**
* Returns true, if resizing is active
*/
bool isResizing() const;
/**
* Sets the minimum size for the widget that is going to be resized.
* The resize handle will not resize the target widget to a size smaller
* than this value
*/
void setMinResizeSize(int MinSize);
/**
* Sets the maximum size for the widget that is going to be resized
* The resize handle will not resize the target widget to a size bigger
* than this value
*/
void setMaxResizeSize(int MaxSize);
}; // class name
}
// namespace ads
//-----------------------------------------------------------------------------
#endif // ResizeHandleH

View File

@ -406,6 +406,15 @@ void repolishStyle(QWidget* w, eRepolishChildOptions Options)
}
}
//============================================================================
QRect globalGeometry(QWidget* w)
{
QRect g = w->geometry();
g.moveTopLeft(w->mapToGlobal(QPoint(0, 0)));
return g;
}
} // namespace internal
} // namespace ads

View File

@ -307,6 +307,11 @@ enum eRepolishChildOptions
void repolishStyle(QWidget* w, eRepolishChildOptions Options = RepolishIgnoreChildren);
/**
* Returns the geometry of the given widget in global space
*/
QRect globalGeometry(QWidget* w);
} // namespace internal
} // namespace ads

View File

@ -51,7 +51,8 @@ HEADERS += \
AutoHideDockContainer.h \
SideTabBar.h \
DockWidgetSideTab.h \
PushButton.h
PushButton.h \
ResizeHandle.h
SOURCES += \
@ -75,7 +76,8 @@ SOURCES += \
AutoHideDockContainer.cpp \
SideTabBar.cpp \
DockWidgetSideTab.cpp \
PushButton.cpp
PushButton.cpp \
ResizeHandle.cpp
unix:!macx {

View File

@ -197,3 +197,9 @@ ads--CAutoHideDockContainer #dockAreaAutoHideButton
#autoHideTitleLabel {
padding-left: 4px;
}
ads--CResizeHandle
{
background: red;
border: 1px solid green;
}