Files
qt5-legatus-legacy/Lts/Viewer/SituationMap/SideBar/side_bar.cpp
T
2026-08-13 18:33:10 +02:00

417 lines
10 KiB
C++
Executable File

/**
* @RDE_HEADER@
* SideBar
* $Id$
* $HeadURL$
* $Author$
* Created by Norbert Thoden, SLSE, 2015-01-19
*/
// Own
#include "side_bar.h"
#include "side_bar_model.h"
// Qt
#include <QVBoxLayout>
#include <QLabel>
#include <QPushButton>
#include <QTreeView>
#include <QKeyEvent>
#include <QSharedPointer>
#include <QPropertyAnimation>
#include <QPainter>
#include <QIcon>
#include <QTimer>
namespace SituationMap
{
class SideBar::Private
{
public:
Private() = default;
~Private() = default;
SideBarModel *m_model = nullptr;
QTreeView *m_view = nullptr;
bool m_suppressClick = false;
QTimer *m_suppressTimer = nullptr;
QSharedPointer<QPropertyAnimation> m_sideBarAniOn;
QSharedPointer<QPropertyAnimation> m_sideBarAniOff;
}; // class SideBar::Private
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
QImage SideBar::createImage(const QColor &fgColor,
const QColor &bgColor,
int size)
{
QImage burgerMenueImage(size, size, QImage::Format_ARGB32);
if (bgColor.isValid())
burgerMenueImage.fill(bgColor);
else
burgerMenueImage.fill(Qt::transparent);
QPainter p(&burgerMenueImage);
{
QPen pen(Qt::white);
pen.setWidth(size * 0.15);
pen.setCapStyle(Qt::PenCapStyle::RoundCap);
p.setPen(pen);
double yFactor = 0.1;
p.drawLine(QPointF(size * yFactor, size * 0.25), QPointF(size - size * yFactor, size * 0.25));
p.drawLine(QPointF(size * yFactor, size * 0.50), QPointF(size - size * yFactor, size * 0.50));
p.drawLine(QPointF(size * yFactor, size * 0.75), QPointF(size - size * yFactor, size * 0.75));
}
{
QPen pen(fgColor);
pen.setWidth(size * 0.1);
pen.setCapStyle(Qt::PenCapStyle::RoundCap);
p.setPen(pen);
double yFactor = 0.1;
p.drawLine(QPointF(size * yFactor, size * 0.25), QPointF(size - size * yFactor, size * 0.25));
p.drawLine(QPointF(size * yFactor, size * 0.50), QPointF(size - size * yFactor, size * 0.50));
p.drawLine(QPointF(size * yFactor, size * 0.75), QPointF(size - size * yFactor, size * 0.75));
}
return burgerMenueImage;
}
QIcon SideBar::createIcon(const QColor &fgColor,
const QColor &bgColor,
int size)
{
return QIcon(QPixmap::fromImage(SideBar::createImage(fgColor, bgColor, size)));
}
SideBar::SideBar(QWidget *parent)
: BaseClass(parent)
, d(new Private)
, m_logger(getLogger("SideBar"))
{
TRACE_LOG(m_logger) << LOGFUNCTION << " START";
// Prepare animations:
d->m_sideBarAniOn = QSharedPointer<QPropertyAnimation>(new QPropertyAnimation(this, "pos"));
connect(d->m_sideBarAniOn.data(), &QPropertyAnimation::finished, this, &SideBar::onAnimationOnFinished);
d->m_sideBarAniOff = QSharedPointer<QPropertyAnimation>(new QPropertyAnimation(this, "pos"));
connect(d->m_sideBarAniOff.data(), &QPropertyAnimation::finished, this, &SideBar::onAnimationOffFinished);
QVBoxLayout *layout = new QVBoxLayout();
layout->setObjectName(QLatin1String("SideBarLayout"));
this->setLayout(layout);
// 1st row
QHBoxLayout *layoutTopRow = new QHBoxLayout();
layoutTopRow->setObjectName(QLatin1String("SideBarTopRowLayout"));
layout->addLayout(layoutTopRow);
layoutTopRow->addStretch(2);
QPushButton *close = new QPushButton();
close->setObjectName(QLatin1String("SideBarCloseButton"));
close->setMinimumSize(QSize(0, 0));
close->setStyleSheet(QLatin1String("QPushButton {background-color: white; border: 1px solid transparent;}"));
close->setIcon(QIcon(QLatin1String("icon:dialog-close.svg")));
// close->setIcon(QIcon(QLatin1String("qrc:///icons/svg/dialog-close.svg")));
close->setIconSize(QSize(20, 20));
// close->setStyleSheet(QLatin1String("QPushButton { image: url(\"icon:dialog-close.svg\"); }"));
// lambda :-)
connect(close, &QPushButton::clicked, this, [this]()
{
emit closeRequest();
this->hideAnimated();
});
layoutTopRow->addWidget(close);
// 2nd Row
d->m_view = new QTreeView(this);
if (d->m_view)
{
d->m_view->setObjectName(QLatin1String("SideBarTreeView"));
d->m_view->setMinimumSize(QSize(0, 0));
d->m_view->setAlternatingRowColors(true);
connect(d->m_view, &QTreeView::clicked, this, &SideBar::onClicked);
layout->addWidget(d->m_view);
initModel();
d->m_view->setModel(d->m_model);
}
initAppearanceToSideBar(true);
//initAppearanceToSideBar(false);
d->m_suppressTimer = new QTimer(this);
d->m_suppressTimer->setSingleShot(true);
d->m_suppressTimer->setInterval(20);
connect(d->m_suppressTimer, &QTimer::timeout, this, [this]() {
d->m_suppressClick = false;
});
TRACE_LOG(m_logger) << LOGFUNCTION << " END";
}
SideBar::~SideBar()
{
TRACE_LOG(m_logger) << LOGFUNCTION << " START";
delete d;
TRACE_LOG(m_logger) << LOGFUNCTION << " END";
}
bool SideBar::initAppearanceToSideBar(bool toSideBar)
{
TRACE_LOG(m_logger) << LOGFUNCTION << " START, toSideBar = " << toSideBar;
if (toSideBar)
{
setWindowFlag(Qt::FramelessWindowHint);
if (d->m_view)
d->m_view->setHeaderHidden(true); // only TreeView
this->layout()->setSpacing(0);
this->layout()->setContentsMargins(0, 0, 0, 0);
// d->m_view->setStyleSheet(QLatin1String("QLabel {border: none;}"));
}
else
{
if (d->m_view)
d->m_view->setHeaderHidden(false);
this->layout()->setSpacing(2);
this->layout()->setContentsMargins(-1, -1, -1, -1); // -1 -> invalid (!?)
}
setAutoFillBackground(true);
// // this->setStyleSheet(QLatin1String("QWidget {background-color: white;}"));
TRACE_LOG(m_logger) << LOGFUNCTION << " END";
return true;
}
void SideBar::setAnimationDuration(int msecs)
{
TRACE_LOG(m_logger) << LOGFUNCTION << " START";
d->m_sideBarAniOn->setDuration(msecs);
d->m_sideBarAniOff->setDuration(msecs);
TRACE_LOG(m_logger) << LOGFUNCTION << " END";
}
void SideBar::setInvisiblePosition(const QPoint &invisiblePos)
{
TRACE_LOG(m_logger) << LOGFUNCTION << " START" << " invisiblePos=" << invisiblePos;
// x--->
d->m_sideBarAniOn->setStartValue(invisiblePos);
// x<---
d->m_sideBarAniOff->setEndValue(invisiblePos);
TRACE_LOG(m_logger) << LOGFUNCTION << " END" << " invisiblePos=" << invisiblePos;
}
void SideBar::setVisiblePosition(const QPoint &visiblePos)
{
TRACE_LOG(m_logger) << LOGFUNCTION << " START" << " visiblePos=" << visiblePos;
// --->x
d->m_sideBarAniOn->setEndValue(visiblePos);
// <---x
d->m_sideBarAniOff->setStartValue(visiblePos);
TRACE_LOG(m_logger) << LOGFUNCTION << " END" << " visiblePos=" << visiblePos;
}
void SideBar::showAnimated()
{
TRACE_LOG(m_logger) << LOGFUNCTION << " START";
this->show();
this->raise();
onAnimationStarted();
d->m_sideBarAniOn->start();
TRACE_LOG(m_logger) << LOGFUNCTION << " END";
}
bool SideBar::isCurrentlyShowing()
{
TRACE_LOG(m_logger) << LOGFUNCTION << " START";
TRACE_LOG(m_logger) << LOGFUNCTION << " END";
return d->m_sideBarAniOn->state() == QAbstractAnimation::Running;
}
void SideBar::hideAnimated()
{
TRACE_LOG(m_logger) << LOGFUNCTION << " START";
// use current position (maybe showAnimation is interrupted)
d->m_sideBarAniOff->setStartValue(this->pos());
onAnimationStarted();
d->m_sideBarAniOff->start();
TRACE_LOG(m_logger) << LOGFUNCTION << " END";
}
bool SideBar::isCurrentlyHiding()
{
TRACE_LOG(m_logger) << LOGFUNCTION << " START";
TRACE_LOG(m_logger) << LOGFUNCTION << " END";
return d->m_sideBarAniOff->state() == QAbstractAnimation::Running;
}
bool SideBar::initModel()
{
TRACE_LOG(m_logger) << LOGFUNCTION << " START";
delete d->m_model;
d->m_model = new SideBarModel(this);
d->m_model->setObjectName(QLatin1String("SideBarModel"));
connect(d->m_model, &SideBarModel::itemChanged, this, &SideBar::onItemChanged);
TRACE_LOG(m_logger) << LOGFUNCTION << " END";
return true;
}
bool SideBar::addCheckableItem(SideBarItem *item)
{
TRACE_LOG(m_logger) << LOGFUNCTION << " START";
item->setCheckable(true);
item->setEditable(false);
d->m_model->addItem(item);
TRACE_LOG(m_logger) << LOGFUNCTION << " END";
return true;
}
bool SideBar::addWidget(QWidget *widget)
{
TRACE_LOG(m_logger) << LOGFUNCTION << " START";
this->layout()->addWidget(widget);
TRACE_LOG(m_logger) << LOGFUNCTION << " END";
return true;
}
void SideBar::onItemChanged(QStandardItem *item)
{
TRACE_LOG(m_logger) << LOGFUNCTION << " START";
QString itemText(QLatin1String("-"));
if (item)
itemText = item->text();
INFO_LOG(m_logger) << LOGFUNCTION << " itemChanged, itemText='" << itemText << "'";
// hide if empty:
if (d->m_view)
d->m_view->setEnabled(d->m_model->rowCount() > 0);
emit dataChanged();
// If user clicks checkbox, 'clicked' is also emitted afterwards...
// In this case, avoid evaluating that signal for a small amount on time
d->m_suppressClick = true;
d->m_suppressTimer->start();
TRACE_LOG(m_logger) << LOGFUNCTION << " END";
}
void SideBar::onAnimationOnFinished()
{
onAnimationFinished();
}
void SideBar::onAnimationOffFinished()
{
TRACE_LOG(m_logger) << LOGFUNCTION << " START";
this->hide();
onAnimationFinished();
TRACE_LOG(m_logger) << LOGFUNCTION << " END";
}
void SideBar::onClicked(const QModelIndex &index)
{
TRACE_LOG(m_logger) << LOGFUNCTION << " START";
if (!d->m_model)
return;
if (d->m_suppressClick)
{
DEBUG_LOG(m_logger) << LOGFUNCTION << " m_suppressClick";
return;
}
QStandardItem *item = d->m_model->itemFromIndex(index);
if (!item)
return;
if (!item->isCheckable())
return;
if (!item->isEnabled())
return;
if (item->checkState() == Qt::CheckState::Checked)
item->setCheckState(Qt::CheckState::Unchecked);
else
item->setCheckState(Qt::CheckState::Checked);
TRACE_LOG(m_logger) << LOGFUNCTION << " END";
}
void SideBar::onAnimationStarted()
{
TRACE_LOG(m_logger) << LOGFUNCTION << " START";
int h = this->parentWidget()->height();
this->setFixedHeight(h); // SetFixedSize/setFixedHeight to have smooth animations, especially in case of some JumpPoints
TRACE_LOG(m_logger) << LOGFUNCTION << " END";
}
void SideBar::onAnimationFinished()
{
TRACE_LOG(m_logger) << LOGFUNCTION << " START";
this->setFixedHeight(QWIDGETSIZE_MAX);
TRACE_LOG(m_logger) << LOGFUNCTION << " END";
}
} // namespace SituationMap