1
0
mirror of https://github.com/qTox/qTox.git synced 2024-03-22 14:00:36 +08:00
qTox/src/widget/notificationscrollarea.cpp

201 lines
6.4 KiB
C++

/*
Copyright © 2015-2018 by The qTox Project Contributors
This file is part of qTox, a Qt-based graphical interface for Tox.
qTox is libre 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.
qTox 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 qTox. If not, see <http://www.gnu.org/licenses/>.
*/
#include "notificationscrollarea.h"
#include "genericchatroomwidget.h"
#include "notificationedgewidget.h"
#include <QScrollBar>
#include <cassert>
NotificationScrollArea::NotificationScrollArea(QWidget* parent)
: AdjustingScrollArea(parent)
{
connect(verticalScrollBar(), &QAbstractSlider::valueChanged, this,
&NotificationScrollArea::updateVisualTracking);
connect(verticalScrollBar(), &QAbstractSlider::rangeChanged, this,
&NotificationScrollArea::updateVisualTracking);
}
void NotificationScrollArea::trackWidget(GenericChatroomWidget* widget)
{
if (trackedWidgets.find(widget) != trackedWidgets.end())
return;
Visibility visibility = widgetVisible(widget);
if (visibility != Visible) {
if (visibility == Above) {
if (referencesAbove++ == 0) {
assert(topEdge == nullptr);
topEdge = new NotificationEdgeWidget(NotificationEdgeWidget::Top, this);
connect(topEdge, &NotificationEdgeWidget::clicked, this,
&NotificationScrollArea::findPreviousWidget);
recalculateTopEdge();
topEdge->show();
}
topEdge->updateNotificationCount(referencesAbove);
} else {
if (referencesBelow++ == 0) {
assert(bottomEdge == nullptr);
bottomEdge = new NotificationEdgeWidget(NotificationEdgeWidget::Bottom, this);
connect(bottomEdge, &NotificationEdgeWidget::clicked, this,
&NotificationScrollArea::findNextWidget);
recalculateBottomEdge();
bottomEdge->show();
}
bottomEdge->updateNotificationCount(referencesBelow);
}
trackedWidgets.insert(widget, visibility);
}
}
/**
* @brief Delete notification bar from visible elements on scroll area
*/
void NotificationScrollArea::updateVisualTracking()
{
updateTracking(nullptr);
}
/**
* @brief Delete notification bar from visible elements and widget on scroll area
* @param widget Chatroom widget to remove from tracked widgets
*/
void NotificationScrollArea::updateTracking(GenericChatroomWidget* widget)
{
QHash<GenericChatroomWidget*, Visibility>::iterator i = trackedWidgets.begin();
while (i != trackedWidgets.end()) {
if (i.key() == widget || widgetVisible(i.key()) == Visible) {
if (i.value() == Above) {
if (--referencesAbove == 0) {
topEdge->deleteLater();
topEdge = nullptr;
} else {
topEdge->updateNotificationCount(referencesAbove);
}
} else {
if (--referencesBelow == 0) {
bottomEdge->deleteLater();
bottomEdge = nullptr;
} else {
bottomEdge->updateNotificationCount(referencesBelow);
}
}
i = trackedWidgets.erase(i);
continue;
}
++i;
}
}
void NotificationScrollArea::resizeEvent(QResizeEvent* event)
{
if (topEdge != nullptr)
recalculateTopEdge();
if (bottomEdge != nullptr)
recalculateBottomEdge();
AdjustingScrollArea::resizeEvent(event);
}
void NotificationScrollArea::findNextWidget()
{
int value = 0;
GenericChatroomWidget* next = nullptr;
QHash<GenericChatroomWidget*, Visibility>::iterator i = trackedWidgets.begin();
// Find the first next, to avoid nullptr.
for (; i != trackedWidgets.end(); ++i) {
if (i.value() == Below) {
next = i.key();
value = next->mapTo(viewport(), QPoint()).y();
break;
}
}
// Try finding a closer one.
for (; i != trackedWidgets.end(); ++i) {
if (i.value() == Below) {
int y = i.key()->mapTo(viewport(), QPoint()).y();
if (y < value) {
next = i.key();
value = y;
}
}
}
if (next != nullptr)
ensureWidgetVisible(next, 0, referencesBelow != 1 ? bottomEdge->height() : 0);
}
void NotificationScrollArea::findPreviousWidget()
{
int value = 0;
GenericChatroomWidget* next = nullptr;
QHash<GenericChatroomWidget*, Visibility>::iterator i = trackedWidgets.begin();
// Find the first next, to avoid nullptr.
for (; i != trackedWidgets.end(); ++i) {
if (i.value() == Above) {
next = i.key();
value = next->mapTo(viewport(), QPoint()).y();
break;
}
}
// Try finding a closer one.
for (; i != trackedWidgets.end(); ++i) {
if (i.value() == Above) {
int y = i.key()->mapTo(viewport(), QPoint()).y();
if (y > value) {
next = i.key();
value = y;
}
}
}
if (next != nullptr)
ensureWidgetVisible(next, 0, referencesAbove != 1 ? topEdge->height() : 0);
}
NotificationScrollArea::Visibility NotificationScrollArea::widgetVisible(QWidget* widget) const
{
int y = widget->mapTo(viewport(), QPoint()).y();
if (y < 0)
return Above;
else if (y + widget->height() - 1 > viewport()->height())
return Below;
return Visible;
}
void NotificationScrollArea::recalculateTopEdge()
{
topEdge->move(viewport()->pos());
topEdge->resize(viewport()->width(), topEdge->height());
}
void NotificationScrollArea::recalculateBottomEdge()
{
QPoint position = viewport()->pos();
position.setY(position.y() + viewport()->height() - bottomEdge->height());
bottomEdge->move(position);
bottomEdge->resize(viewport()->width(), bottomEdge->height());
}