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

212 lines
6.1 KiB
C++
Raw Normal View History

/*
Copyright © 2015 by The qTox Project
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 "notificationedgewidget.h"
#include "genericchatroomwidget.h"
#include <QScrollBar>
#include <cassert>
NotificationScrollArea::NotificationScrollArea(QWidget* parent)
: AdjustingScrollArea(parent)
{
connect(verticalScrollBar(), &QAbstractSlider::valueChanged, this, &NotificationScrollArea::updateTracking);
2015-06-09 22:13:49 +08:00
connect(verticalScrollBar(), &QAbstractSlider::rangeChanged, this, &NotificationScrollArea::updateTracking);
}
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);
}
}
void NotificationScrollArea::updateTracking()
{
QHash<GenericChatroomWidget*, Visibility>::iterator i = trackedWidgets.begin();
while (i != trackedWidgets.end())
{
if (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;
2015-10-10 20:49:30 +08:00
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;
2015-10-10 20:49:30 +08:00
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;
2015-06-09 22:13:49 +08:00
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());
}