2014-11-16 19:58:43 +08:00
|
|
|
/*
|
2018-04-13 04:02:28 +08:00
|
|
|
Copyright © 2014-2018 by The qTox Project Contributors
|
2015-06-06 09:40:08 +08:00
|
|
|
|
2014-11-16 19:58:43 +08:00
|
|
|
This file is part of qTox, a Qt-based graphical interface for Tox.
|
|
|
|
|
2015-06-06 09:40:08 +08:00
|
|
|
qTox is libre software: you can redistribute it and/or modify
|
2014-11-16 19:58:43 +08:00
|
|
|
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.
|
2015-06-06 09:40:08 +08:00
|
|
|
|
|
|
|
qTox is distributed in the hope that it will be useful,
|
2014-11-16 19:58:43 +08:00
|
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
2015-06-06 09:40:08 +08:00
|
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
GNU General Public License for more details.
|
2014-11-16 19:58:43 +08:00
|
|
|
|
2015-06-06 09:40:08 +08:00
|
|
|
You should have received a copy of the GNU General Public License
|
|
|
|
along with qTox. If not, see <http://www.gnu.org/licenses/>.
|
2014-11-16 19:58:43 +08:00
|
|
|
*/
|
|
|
|
|
2014-11-12 21:11:25 +08:00
|
|
|
#include "chatline.h"
|
|
|
|
#include "chatlinecontent.h"
|
|
|
|
|
|
|
|
#include <QDebug>
|
|
|
|
#include <QGraphicsScene>
|
|
|
|
|
2015-01-05 01:21:35 +08:00
|
|
|
ChatLine::ChatLine()
|
2014-11-12 21:11:25 +08:00
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
ChatLine::~ChatLine()
|
|
|
|
{
|
2017-02-26 19:52:45 +08:00
|
|
|
for (ChatLineContent* c : content) {
|
2015-03-21 02:38:10 +08:00
|
|
|
if (c->scene())
|
2015-01-05 01:21:35 +08:00
|
|
|
c->scene()->removeItem(c);
|
2015-01-04 20:29:14 +08:00
|
|
|
|
2014-11-12 21:11:25 +08:00
|
|
|
delete c;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-01-20 17:31:50 +08:00
|
|
|
void ChatLine::setRow(int idx)
|
2014-11-12 21:11:25 +08:00
|
|
|
{
|
2015-01-20 17:31:50 +08:00
|
|
|
row = idx;
|
2014-11-12 21:11:25 +08:00
|
|
|
|
2015-03-21 02:38:10 +08:00
|
|
|
for (int c = 0; c < static_cast<int>(content.size()); ++c)
|
2015-01-20 17:31:50 +08:00
|
|
|
content[c]->setIndex(row, c);
|
2014-11-12 21:11:25 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
void ChatLine::visibilityChanged(bool visible)
|
|
|
|
{
|
2017-02-26 19:52:45 +08:00
|
|
|
if (isVisible != visible) {
|
2015-03-21 02:38:10 +08:00
|
|
|
for (ChatLineContent* c : content)
|
2014-11-12 21:11:25 +08:00
|
|
|
c->visibilityChanged(visible);
|
|
|
|
}
|
|
|
|
|
|
|
|
isVisible = visible;
|
|
|
|
}
|
|
|
|
|
2015-01-20 17:31:50 +08:00
|
|
|
int ChatLine::getRow() const
|
2014-11-12 21:11:25 +08:00
|
|
|
{
|
2015-01-20 17:31:50 +08:00
|
|
|
return row;
|
2014-11-12 21:11:25 +08:00
|
|
|
}
|
|
|
|
|
2017-02-26 19:52:45 +08:00
|
|
|
ChatLineContent* ChatLine::getContent(int col) const
|
2014-12-14 04:11:03 +08:00
|
|
|
{
|
2015-03-21 02:38:10 +08:00
|
|
|
if (col < static_cast<int>(content.size()) && col >= 0)
|
2014-12-14 04:11:03 +08:00
|
|
|
return content[col];
|
|
|
|
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
|
2017-02-26 19:52:45 +08:00
|
|
|
ChatLineContent* ChatLine::getContent(QPointF scenePos) const
|
2015-01-07 00:47:57 +08:00
|
|
|
{
|
2017-02-26 19:52:45 +08:00
|
|
|
for (ChatLineContent* c : content) {
|
2015-03-21 02:38:10 +08:00
|
|
|
if (c->sceneBoundingRect().contains(scenePos))
|
2015-01-07 00:47:57 +08:00
|
|
|
return c;
|
|
|
|
}
|
|
|
|
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
|
2015-01-04 20:29:14 +08:00
|
|
|
void ChatLine::removeFromScene()
|
|
|
|
{
|
2017-02-26 19:52:45 +08:00
|
|
|
for (ChatLineContent* c : content) {
|
2015-03-21 02:38:10 +08:00
|
|
|
if (c->scene())
|
2015-01-05 01:21:35 +08:00
|
|
|
c->scene()->removeItem(c);
|
2015-01-04 20:29:14 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-02-26 19:52:45 +08:00
|
|
|
void ChatLine::addToScene(QGraphicsScene* scene)
|
2015-01-05 01:21:35 +08:00
|
|
|
{
|
2015-03-21 02:38:10 +08:00
|
|
|
if (!scene)
|
2015-01-05 01:21:35 +08:00
|
|
|
return;
|
|
|
|
|
2015-03-21 02:38:10 +08:00
|
|
|
for (ChatLineContent* c : content)
|
2015-01-05 01:21:35 +08:00
|
|
|
scene->addItem(c);
|
|
|
|
}
|
|
|
|
|
2015-01-10 18:57:46 +08:00
|
|
|
void ChatLine::setVisible(bool visible)
|
|
|
|
{
|
2015-03-21 02:38:10 +08:00
|
|
|
for (ChatLineContent* c : content)
|
2015-01-10 18:57:46 +08:00
|
|
|
c->setVisible(visible);
|
|
|
|
}
|
|
|
|
|
2014-11-12 21:11:25 +08:00
|
|
|
void ChatLine::selectionCleared()
|
|
|
|
{
|
2015-03-21 02:38:10 +08:00
|
|
|
for (ChatLineContent* c : content)
|
2014-11-12 21:11:25 +08:00
|
|
|
c->selectionCleared();
|
|
|
|
}
|
|
|
|
|
2015-02-03 17:33:46 +08:00
|
|
|
void ChatLine::selectionFocusChanged(bool focusIn)
|
|
|
|
{
|
2015-03-21 02:38:10 +08:00
|
|
|
for (ChatLineContent* c : content)
|
2015-02-03 17:33:46 +08:00
|
|
|
c->selectionFocusChanged(focusIn);
|
|
|
|
}
|
|
|
|
|
2017-02-05 11:10:27 +08:00
|
|
|
void ChatLine::fontChanged(const QFont& font)
|
|
|
|
{
|
|
|
|
for (ChatLineContent* c : content)
|
|
|
|
c->fontChanged(font);
|
|
|
|
}
|
|
|
|
|
2014-11-12 21:11:25 +08:00
|
|
|
int ChatLine::getColumnCount()
|
|
|
|
{
|
|
|
|
return content.size();
|
|
|
|
}
|
|
|
|
|
|
|
|
void ChatLine::updateBBox()
|
|
|
|
{
|
2015-01-06 21:58:50 +08:00
|
|
|
bbox.setHeight(0);
|
2014-11-12 21:11:25 +08:00
|
|
|
bbox.setWidth(width);
|
|
|
|
|
2015-03-21 02:38:10 +08:00
|
|
|
for (ChatLineContent* c : content)
|
2017-02-26 19:52:45 +08:00
|
|
|
bbox.setHeight(qMax(c->sceneBoundingRect().top() - bbox.top() + c->sceneBoundingRect().height(),
|
|
|
|
bbox.height()));
|
2014-11-12 21:11:25 +08:00
|
|
|
}
|
|
|
|
|
2015-02-01 00:49:19 +08:00
|
|
|
QRectF ChatLine::sceneBoundingRect() const
|
2014-11-12 21:11:25 +08:00
|
|
|
{
|
|
|
|
return bbox;
|
|
|
|
}
|
|
|
|
|
|
|
|
void ChatLine::addColumn(ChatLineContent* item, ColumnFormat fmt)
|
|
|
|
{
|
2015-03-21 02:38:10 +08:00
|
|
|
if (!item)
|
2014-11-12 21:11:25 +08:00
|
|
|
return;
|
|
|
|
|
2015-01-06 22:10:37 +08:00
|
|
|
format.push_back(fmt);
|
|
|
|
content.push_back(item);
|
2014-11-12 21:11:25 +08:00
|
|
|
}
|
|
|
|
|
2017-02-26 19:52:45 +08:00
|
|
|
void ChatLine::replaceContent(int col, ChatLineContent* lineContent)
|
2014-11-12 23:45:24 +08:00
|
|
|
{
|
2017-02-26 19:52:45 +08:00
|
|
|
if (col >= 0 && col < static_cast<int>(content.size()) && lineContent) {
|
2015-01-05 01:21:35 +08:00
|
|
|
QGraphicsScene* scene = content[col]->scene();
|
2014-11-12 23:45:24 +08:00
|
|
|
delete content[col];
|
|
|
|
|
|
|
|
content[col] = lineContent;
|
2015-01-20 17:31:50 +08:00
|
|
|
lineContent->setIndex(row, col);
|
2015-01-05 01:21:35 +08:00
|
|
|
|
2015-03-21 02:38:10 +08:00
|
|
|
if (scene)
|
2015-01-05 01:21:35 +08:00
|
|
|
scene->addItem(content[col]);
|
2014-11-14 01:27:32 +08:00
|
|
|
|
2015-01-06 21:58:50 +08:00
|
|
|
layout(width, bbox.topLeft());
|
2014-11-14 01:27:32 +08:00
|
|
|
content[col]->visibilityChanged(isVisible);
|
|
|
|
content[col]->update();
|
2014-11-12 23:45:24 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-11-12 21:11:25 +08:00
|
|
|
void ChatLine::layout(qreal w, QPointF scenePos)
|
|
|
|
{
|
2016-01-16 09:23:56 +08:00
|
|
|
if (!content.size())
|
|
|
|
return;
|
|
|
|
|
2014-11-12 21:11:25 +08:00
|
|
|
width = w;
|
2015-01-06 21:58:50 +08:00
|
|
|
bbox.setTopLeft(scenePos);
|
2014-11-12 21:11:25 +08:00
|
|
|
|
2017-02-26 19:52:45 +08:00
|
|
|
qreal fixedWidth = (content.size() - 1) * columnSpacing;
|
2014-11-12 21:11:25 +08:00
|
|
|
qreal varWidth = 0.0; // used for normalisation
|
|
|
|
|
2017-02-26 19:52:45 +08:00
|
|
|
for (int i = 0; i < format.size(); ++i) {
|
2015-03-21 02:38:10 +08:00
|
|
|
if (format[i].policy == ColumnFormat::FixedSize)
|
2014-11-12 21:11:25 +08:00
|
|
|
fixedWidth += format[i].size;
|
|
|
|
else
|
|
|
|
varWidth += format[i].size;
|
|
|
|
}
|
|
|
|
|
2015-03-21 02:38:10 +08:00
|
|
|
if (varWidth == 0.0)
|
2014-11-12 21:11:25 +08:00
|
|
|
varWidth = 1.0;
|
|
|
|
|
|
|
|
qreal leftover = qMax(0.0, width - fixedWidth);
|
|
|
|
|
2014-12-09 05:08:23 +08:00
|
|
|
qreal maxVOffset = 0.0;
|
2014-11-12 21:11:25 +08:00
|
|
|
qreal xOffset = 0.0;
|
2016-07-11 17:36:08 +08:00
|
|
|
QVector<qreal> xPos(content.size());
|
2015-02-10 00:45:48 +08:00
|
|
|
|
2017-02-26 19:52:45 +08:00
|
|
|
for (int i = 0; i < content.size(); ++i) {
|
2014-11-12 21:11:25 +08:00
|
|
|
// calculate the effective width of the current column
|
|
|
|
qreal width;
|
2015-03-21 02:38:10 +08:00
|
|
|
if (format[i].policy == ColumnFormat::FixedSize)
|
2014-11-12 21:11:25 +08:00
|
|
|
width = format[i].size;
|
|
|
|
else
|
|
|
|
width = format[i].size / varWidth * leftover;
|
|
|
|
|
2014-11-14 01:27:32 +08:00
|
|
|
// set the width of the current column
|
2014-11-12 21:11:25 +08:00
|
|
|
content[i]->setWidth(width);
|
|
|
|
|
|
|
|
// calculate horizontal alignment
|
|
|
|
qreal xAlign = 0.0;
|
2015-01-04 03:37:40 +08:00
|
|
|
|
2017-02-26 19:52:45 +08:00
|
|
|
switch (format[i].hAlign) {
|
2016-07-11 17:36:08 +08:00
|
|
|
case ColumnFormat::Left:
|
|
|
|
break;
|
|
|
|
case ColumnFormat::Right:
|
|
|
|
xAlign = width - content[i]->boundingRect().width();
|
|
|
|
break;
|
|
|
|
case ColumnFormat::Center:
|
|
|
|
xAlign = (width - content[i]->boundingRect().width()) / 2.0;
|
|
|
|
break;
|
2014-11-12 21:11:25 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
// reposition
|
2015-02-10 00:45:48 +08:00
|
|
|
xPos[i] = scenePos.x() + xOffset + xAlign;
|
2014-11-12 21:11:25 +08:00
|
|
|
|
2015-01-20 18:51:34 +08:00
|
|
|
xOffset += width + columnSpacing;
|
2015-02-10 00:45:48 +08:00
|
|
|
maxVOffset = qMax(maxVOffset, content[i]->getAscent());
|
2014-11-12 21:11:25 +08:00
|
|
|
}
|
|
|
|
|
2017-02-26 19:52:45 +08:00
|
|
|
for (int i = 0; i < content.size(); ++i) {
|
2014-11-14 01:27:32 +08:00
|
|
|
// calculate vertical alignment
|
|
|
|
// vertical alignment may depend on width, so we do it in a second pass
|
2015-02-10 00:45:48 +08:00
|
|
|
qreal yOffset = maxVOffset - content[i]->getAscent();
|
2014-11-14 01:27:32 +08:00
|
|
|
|
|
|
|
// reposition
|
2015-02-10 00:45:48 +08:00
|
|
|
content[i]->setPos(xPos[i], scenePos.y() + yOffset);
|
2014-11-14 01:27:32 +08:00
|
|
|
}
|
|
|
|
|
2014-11-12 21:11:25 +08:00
|
|
|
updateBBox();
|
|
|
|
}
|
|
|
|
|
2015-01-05 21:06:14 +08:00
|
|
|
void ChatLine::moveBy(qreal deltaY)
|
2014-11-12 21:11:25 +08:00
|
|
|
{
|
|
|
|
// reposition only
|
2015-03-21 02:38:10 +08:00
|
|
|
for (ChatLineContent* c : content)
|
2015-01-05 21:06:14 +08:00
|
|
|
c->moveBy(0, deltaY);
|
2014-11-12 21:11:25 +08:00
|
|
|
|
2015-01-06 21:58:50 +08:00
|
|
|
bbox.moveTop(bbox.top() + deltaY);
|
2014-11-12 21:11:25 +08:00
|
|
|
}
|
2015-01-15 18:48:41 +08:00
|
|
|
|
2015-04-13 05:49:24 +08:00
|
|
|
bool ChatLine::lessThanBSRectTop(const ChatLine::Ptr& lhs, const qreal& rhs)
|
2015-01-15 18:48:41 +08:00
|
|
|
{
|
2015-02-01 00:49:19 +08:00
|
|
|
return lhs->sceneBoundingRect().top() < rhs;
|
2015-01-15 18:48:41 +08:00
|
|
|
}
|
|
|
|
|
2015-04-13 05:49:24 +08:00
|
|
|
bool ChatLine::lessThanBSRectBottom(const ChatLine::Ptr& lhs, const qreal& rhs)
|
2015-01-15 18:48:41 +08:00
|
|
|
{
|
2015-02-01 00:49:19 +08:00
|
|
|
return lhs->sceneBoundingRect().bottom() < rhs;
|
2015-01-15 18:48:41 +08:00
|
|
|
}
|
|
|
|
|
2015-04-13 05:49:24 +08:00
|
|
|
bool ChatLine::lessThanRowIndex(const ChatLine::Ptr& lhs, const ChatLine::Ptr& rhs)
|
2015-01-15 18:48:41 +08:00
|
|
|
{
|
2015-01-20 17:31:50 +08:00
|
|
|
return lhs->getRow() < rhs->getRow();
|
2015-01-15 18:48:41 +08:00
|
|
|
}
|