forked from blue/squawk
an attempt to display text in a better way with QTextDocument + QTextBrowser
This commit is contained in:
parent
51ac1ac709
commit
d86e2c28a0
@ -40,5 +40,5 @@ QString Shared::processMessageBody(const QString& msg)
|
|||||||
{
|
{
|
||||||
QString processed = msg.toHtmlEscaped();
|
QString processed = msg.toHtmlEscaped();
|
||||||
processed.replace(urlReg, "<a href=\"\\1\">\\1</a>");
|
processed.replace(urlReg, "<a href=\"\\1\">\\1</a>");
|
||||||
return "<p style=\"white-space: pre-wrap;\">" + processed + "</p>";
|
return "<p style=\"white-space: pre-wrap; line-height: 1em;\">" + processed + "</p>";
|
||||||
}
|
}
|
||||||
|
@ -15,6 +15,4 @@ target_sources(squawk PRIVATE
|
|||||||
resizer.h
|
resizer.h
|
||||||
shadowoverlay.cpp
|
shadowoverlay.cpp
|
||||||
shadowoverlay.h
|
shadowoverlay.h
|
||||||
textmeter.cpp
|
|
||||||
textmeter.h
|
|
||||||
)
|
)
|
||||||
|
@ -1,233 +0,0 @@
|
|||||||
// Squawk messenger.
|
|
||||||
// Copyright (C) 2019 Yury Gubich <blue@macaw.me>
|
|
||||||
//
|
|
||||||
// This program is free 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.
|
|
||||||
//
|
|
||||||
// This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
|
|
||||||
#include "textmeter.h"
|
|
||||||
#include <QDebug>
|
|
||||||
#include <QApplication>
|
|
||||||
|
|
||||||
TextMeter::TextMeter():
|
|
||||||
base(),
|
|
||||||
fonts()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
TextMeter::~TextMeter()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
void TextMeter::initializeFonts(const QFont& font)
|
|
||||||
{
|
|
||||||
fonts.clear();
|
|
||||||
QList<QFontDatabase::WritingSystem> supported = base.writingSystems(font.family());
|
|
||||||
std::set<QFontDatabase::WritingSystem> sup;
|
|
||||||
std::set<QString> added({font.family()});
|
|
||||||
for (const QFontDatabase::WritingSystem& system : supported) {
|
|
||||||
sup.insert(system);
|
|
||||||
}
|
|
||||||
fonts.push_back(QFontMetrics(font));
|
|
||||||
QString style = base.styleString(font);
|
|
||||||
|
|
||||||
QList<QFontDatabase::WritingSystem> systems = base.writingSystems();
|
|
||||||
for (const QFontDatabase::WritingSystem& system : systems) {
|
|
||||||
if (sup.count(system) == 0) {
|
|
||||||
QStringList families = base.families(system);
|
|
||||||
if (!families.empty() && added.count(families.first()) == 0) {
|
|
||||||
QString family(families.first());
|
|
||||||
QFont nfont = base.font(family, style, font.pointSize());
|
|
||||||
if (added.count(nfont.family()) == 0) {
|
|
||||||
added.insert(family);
|
|
||||||
fonts.push_back(QFontMetrics(nfont));
|
|
||||||
qDebug() << "Added font" << nfont.family() << "for" << system;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
QSize TextMeter::boundingSize(const QString& text, const QSize& limits) const
|
|
||||||
{
|
|
||||||
// QString str("ridiculus mus. Suspendisse potenti. Cras pretium venenatis enim, faucibus accumsan ex");
|
|
||||||
// bool first = true;
|
|
||||||
// int width = 0;
|
|
||||||
// QStringList list = str.split(" ");
|
|
||||||
// QFontMetrics m = fonts.front();
|
|
||||||
// for (const QString& word : list) {
|
|
||||||
// if (first) {
|
|
||||||
// first = false;
|
|
||||||
// } else {
|
|
||||||
// width += m.horizontalAdvance(QChar::Space);
|
|
||||||
// }
|
|
||||||
// width += m.horizontalAdvance(word);
|
|
||||||
// for (const QChar& ch : word) {
|
|
||||||
// width += m.horizontalAdvance(ch);
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// qDebug() << "together:" << m.horizontalAdvance(str);
|
|
||||||
// qDebug() << "apart:" << width;
|
|
||||||
// I cant measure or wrap text this way, this simple example shows that even this gives differen result
|
|
||||||
// The Qt implementation under it is thousands and thousands lines of code in QTextEngine
|
|
||||||
// I simply can't get though it
|
|
||||||
|
|
||||||
if (text.size() == 0) {
|
|
||||||
return QSize (0, 0);
|
|
||||||
}
|
|
||||||
Helper current(limits.width());
|
|
||||||
for (const QChar& ch : text) {
|
|
||||||
if (newLine(ch)) {
|
|
||||||
current.computeNewWord();
|
|
||||||
if (current.height == 0) {
|
|
||||||
current.height = fonts.front().lineSpacing();
|
|
||||||
}
|
|
||||||
current.beginNewLine();
|
|
||||||
} else if (visible(ch)) {
|
|
||||||
bool found = false;
|
|
||||||
for (const QFontMetrics& metrics : fonts) {
|
|
||||||
if (metrics.inFont(ch)) {
|
|
||||||
current.computeChar(ch, metrics);
|
|
||||||
found = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!found) {
|
|
||||||
current.computeChar(ch, fonts.front());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
current.computeNewWord();
|
|
||||||
current.beginNewLine();
|
|
||||||
|
|
||||||
int& height = current.size.rheight();
|
|
||||||
if (height > 0) {
|
|
||||||
height -= fonts.front().leading();
|
|
||||||
}
|
|
||||||
|
|
||||||
return current.size;
|
|
||||||
}
|
|
||||||
|
|
||||||
void TextMeter::Helper::computeChar(const QChar& ch, const QFontMetrics& metrics)
|
|
||||||
{
|
|
||||||
int ha = metrics.horizontalAdvance(ch);
|
|
||||||
if (newWord(ch)) {
|
|
||||||
if (printOnLineBreak(ch)) {
|
|
||||||
if (!lineOverflow(metrics, ha, ch)){
|
|
||||||
computeNewWord();
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
computeNewWord();
|
|
||||||
delayedSpaceWidth = ha;
|
|
||||||
lastSpace = ch;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
lineOverflow(metrics, ha, ch);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void TextMeter::Helper::computeNewLine(const QFontMetrics& metrics, int horizontalAdvance, const QChar& ch)
|
|
||||||
{
|
|
||||||
if (wordBeganWithTheLine) {
|
|
||||||
text = word.chopped(1);
|
|
||||||
width = wordWidth - horizontalAdvance;
|
|
||||||
height = wordHeight;
|
|
||||||
}
|
|
||||||
if (width != metrics.horizontalAdvance(text)) {
|
|
||||||
qDebug() << "Kerning Error" << width - metrics.horizontalAdvance(text);
|
|
||||||
}
|
|
||||||
beginNewLine();
|
|
||||||
if (wordBeganWithTheLine) {
|
|
||||||
word = ch;
|
|
||||||
wordWidth = horizontalAdvance;
|
|
||||||
wordHeight = metrics.lineSpacing();
|
|
||||||
}
|
|
||||||
|
|
||||||
wordBeganWithTheLine = true;
|
|
||||||
delayedSpaceWidth = 0;
|
|
||||||
lastSpace = QChar::Null;
|
|
||||||
}
|
|
||||||
|
|
||||||
void TextMeter::Helper::beginNewLine()
|
|
||||||
{
|
|
||||||
size.rheight() += height;
|
|
||||||
size.rwidth() = qMax(size.width(), width);
|
|
||||||
qDebug() << text;
|
|
||||||
text = "";
|
|
||||||
width = 0;
|
|
||||||
height = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
void TextMeter::Helper::computeNewWord()
|
|
||||||
{
|
|
||||||
width += wordWidth + delayedSpaceWidth;
|
|
||||||
height = qMax(height, wordHeight);
|
|
||||||
if (lastSpace != QChar::Null) {
|
|
||||||
text += lastSpace;
|
|
||||||
}
|
|
||||||
text += word;
|
|
||||||
word = "";
|
|
||||||
wordWidth = 0;
|
|
||||||
wordHeight = 0;
|
|
||||||
delayedSpaceWidth = 0;
|
|
||||||
lastSpace = QChar::Null;
|
|
||||||
wordBeganWithTheLine = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool TextMeter::Helper::lineOverflow(const QFontMetrics& metrics, int horizontalAdvance, const QChar& ch)
|
|
||||||
{
|
|
||||||
wordHeight = qMax(wordHeight, metrics.lineSpacing());
|
|
||||||
wordWidth += horizontalAdvance;
|
|
||||||
word += ch;
|
|
||||||
if (width + delayedSpaceWidth + wordWidth > maxWidth) {
|
|
||||||
computeNewLine(metrics, horizontalAdvance, ch);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
bool TextMeter::newLine(const QChar& ch)
|
|
||||||
{
|
|
||||||
return ch == QChar::LineFeed;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool TextMeter::newWord(const QChar& ch)
|
|
||||||
{
|
|
||||||
return ch.isSpace() || ch.isPunct();
|
|
||||||
}
|
|
||||||
|
|
||||||
bool TextMeter::printOnLineBreak(const QChar& ch)
|
|
||||||
{
|
|
||||||
return ch != QChar::Space;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool TextMeter::visible(const QChar& ch)
|
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
TextMeter::Helper::Helper(int p_maxWidth):
|
|
||||||
width(0),
|
|
||||||
height(0),
|
|
||||||
wordWidth(0),
|
|
||||||
wordHeight(0),
|
|
||||||
delayedSpaceWidth(0),
|
|
||||||
maxWidth(p_maxWidth),
|
|
||||||
wordBeganWithTheLine(true),
|
|
||||||
text(""),
|
|
||||||
word(""),
|
|
||||||
lastSpace(QChar::Null),
|
|
||||||
size(0, 0)
|
|
||||||
{
|
|
||||||
}
|
|
@ -1,68 +0,0 @@
|
|||||||
// Squawk messenger.
|
|
||||||
// Copyright (C) 2019 Yury Gubich <blue@macaw.me>
|
|
||||||
//
|
|
||||||
// This program is free 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.
|
|
||||||
//
|
|
||||||
// This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
|
|
||||||
#ifndef TEXTMETER_H
|
|
||||||
#define TEXTMETER_H
|
|
||||||
|
|
||||||
#include <list>
|
|
||||||
#include <set>
|
|
||||||
|
|
||||||
#include <QFontMetrics>
|
|
||||||
#include <QFont>
|
|
||||||
#include <QSize>
|
|
||||||
#include <QFontDatabase>
|
|
||||||
|
|
||||||
class TextMeter
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
TextMeter();
|
|
||||||
~TextMeter();
|
|
||||||
void initializeFonts(const QFont& font);
|
|
||||||
QSize boundingSize(const QString& text, const QSize& limits) const;
|
|
||||||
|
|
||||||
private:
|
|
||||||
QFontDatabase base;
|
|
||||||
std::list<QFontMetrics> fonts;
|
|
||||||
|
|
||||||
struct Helper {
|
|
||||||
Helper(int maxWidth);
|
|
||||||
int width;
|
|
||||||
int height;
|
|
||||||
int wordWidth;
|
|
||||||
int wordHeight;
|
|
||||||
int delayedSpaceWidth;
|
|
||||||
int maxWidth;
|
|
||||||
bool wordBeganWithTheLine;
|
|
||||||
QString text;
|
|
||||||
QString word;
|
|
||||||
QChar lastSpace;
|
|
||||||
QSize size;
|
|
||||||
|
|
||||||
void computeNewLine(const QFontMetrics& metrics, int horizontalAdvance, const QChar& ch);
|
|
||||||
void computeChar(const QChar& ch, const QFontMetrics& metrics);
|
|
||||||
void computeNewWord();
|
|
||||||
void beginNewLine();
|
|
||||||
bool lineOverflow(const QFontMetrics& metrics, int horizontalAdvance, const QChar& ch);
|
|
||||||
};
|
|
||||||
|
|
||||||
static bool newLine(const QChar& ch);
|
|
||||||
static bool newWord(const QChar& ch);
|
|
||||||
static bool visible(const QChar& ch);
|
|
||||||
static bool printOnLineBreak(const QChar& ch);
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif // TEXTMETER_H
|
|
@ -343,6 +343,7 @@ void FeedView::paintEvent(QPaintEvent* event)
|
|||||||
|
|
||||||
QDateTime lastDate;
|
QDateTime lastDate;
|
||||||
bool first = true;
|
bool first = true;
|
||||||
|
QRect viewportRect = vp->rect();
|
||||||
for (const QModelIndex& index : toRener) {
|
for (const QModelIndex& index : toRener) {
|
||||||
QDateTime currentDate = index.data(Models::MessageFeed::Date).toDateTime();
|
QDateTime currentDate = index.data(Models::MessageFeed::Date).toDateTime();
|
||||||
option.rect = visualRect(index);
|
option.rect = visualRect(index);
|
||||||
@ -356,7 +357,10 @@ void FeedView::paintEvent(QPaintEvent* event)
|
|||||||
}
|
}
|
||||||
first = false;
|
first = false;
|
||||||
}
|
}
|
||||||
bool mouseOver = option.rect.contains(cursor) && vp->rect().contains(cursor);
|
QRect stripe = option.rect;
|
||||||
|
stripe.setLeft(0);
|
||||||
|
stripe.setWidth(viewportRect.width());
|
||||||
|
bool mouseOver = stripe.contains(cursor) && viewportRect.contains(cursor);
|
||||||
option.state.setFlag(QStyle::State_MouseOver, mouseOver);
|
option.state.setFlag(QStyle::State_MouseOver, mouseOver);
|
||||||
itemDelegate(index)->paint(&painter, option, index);
|
itemDelegate(index)->paint(&painter, option, index);
|
||||||
|
|
||||||
|
@ -22,6 +22,7 @@
|
|||||||
#include <QApplication>
|
#include <QApplication>
|
||||||
#include <QMouseEvent>
|
#include <QMouseEvent>
|
||||||
#include <QAbstractItemView>
|
#include <QAbstractItemView>
|
||||||
|
#include <QtMath>
|
||||||
|
|
||||||
#include "messagedelegate.h"
|
#include "messagedelegate.h"
|
||||||
#include "messagefeed.h"
|
#include "messagefeed.h"
|
||||||
@ -42,7 +43,7 @@ MessageDelegate::MessageDelegate(QObject* parent):
|
|||||||
nickFont(),
|
nickFont(),
|
||||||
dateFont(),
|
dateFont(),
|
||||||
bodyMetrics(bodyFont),
|
bodyMetrics(bodyFont),
|
||||||
bodyMeter(),
|
bodyRenderer(new QTextDocument()),
|
||||||
nickMetrics(nickFont),
|
nickMetrics(nickFont),
|
||||||
dateMetrics(dateFont),
|
dateMetrics(dateFont),
|
||||||
buttonHeight(0),
|
buttonHeight(0),
|
||||||
@ -52,11 +53,13 @@ MessageDelegate::MessageDelegate(QObject* parent):
|
|||||||
bars(new std::map<QString, QProgressBar*>()),
|
bars(new std::map<QString, QProgressBar*>()),
|
||||||
statusIcons(new std::map<QString, QLabel*>()),
|
statusIcons(new std::map<QString, QLabel*>()),
|
||||||
pencilIcons(new std::map<QString, QLabel*>()),
|
pencilIcons(new std::map<QString, QLabel*>()),
|
||||||
bodies(new std::map<QString, QLabel*>()),
|
bodies(new std::map<QString, QTextBrowser*>()),
|
||||||
previews(new std::map<QString, Preview*>()),
|
previews(new std::map<QString, Preview*>()),
|
||||||
idsToKeep(new std::set<QString>()),
|
idsToKeep(new std::set<QString>()),
|
||||||
clearingWidgets(false)
|
clearingWidgets(false)
|
||||||
{
|
{
|
||||||
|
bodyRenderer->setDocumentMargin(0);
|
||||||
|
|
||||||
QPushButton btn(QCoreApplication::translate("MessageLine", "Download"));
|
QPushButton btn(QCoreApplication::translate("MessageLine", "Download"));
|
||||||
buttonHeight = btn.sizeHint().height();
|
buttonHeight = btn.sizeHint().height();
|
||||||
buttonWidth = btn.sizeHint().width();
|
buttonWidth = btn.sizeHint().width();
|
||||||
@ -83,7 +86,7 @@ MessageDelegate::~MessageDelegate()
|
|||||||
delete pair.second;
|
delete pair.second;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (const std::pair<const QString, QLabel*>& pair: *bodies){
|
for (const std::pair<const QString, QTextBrowser*>& pair: *bodies){
|
||||||
delete pair.second;
|
delete pair.second;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -98,6 +101,7 @@ MessageDelegate::~MessageDelegate()
|
|||||||
delete bars;
|
delete bars;
|
||||||
delete bodies;
|
delete bodies;
|
||||||
delete previews;
|
delete previews;
|
||||||
|
delete bodyRenderer;
|
||||||
}
|
}
|
||||||
|
|
||||||
void MessageDelegate::paint(QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex& index) const
|
void MessageDelegate::paint(QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex& index) const
|
||||||
@ -124,8 +128,6 @@ void MessageDelegate::paint(QPainter* painter, const QStyleOptionViewItem& optio
|
|||||||
opt.displayAlignment = Qt::AlignRight | Qt::AlignTop;
|
opt.displayAlignment = Qt::AlignRight | Qt::AlignTop;
|
||||||
}
|
}
|
||||||
|
|
||||||
QSize bodySize = bodyMeter.boundingSize(data.text, opt.rect.size());
|
|
||||||
|
|
||||||
QRect rect;
|
QRect rect;
|
||||||
if (ntds) {
|
if (ntds) {
|
||||||
painter->setFont(nickFont);
|
painter->setFont(nickFont);
|
||||||
@ -168,15 +170,7 @@ void MessageDelegate::paint(QPainter* painter, const QStyleOptionViewItem& optio
|
|||||||
painter->restore();
|
painter->restore();
|
||||||
|
|
||||||
QWidget* vp = static_cast<QWidget*>(painter->device());
|
QWidget* vp = static_cast<QWidget*>(painter->device());
|
||||||
if (data.text.size() > 0) {
|
paintBody(data, painter, opt);
|
||||||
QLabel* body = getBody(data);
|
|
||||||
body->setParent(vp);
|
|
||||||
body->setMinimumSize(bodySize);
|
|
||||||
body->setMaximumSize(bodySize);
|
|
||||||
body->move(opt.rect.left(), opt.rect.y());
|
|
||||||
body->show();
|
|
||||||
opt.rect.adjust(0, bodySize.height() + textMargin, 0, 0);
|
|
||||||
}
|
|
||||||
painter->setFont(dateFont);
|
painter->setFont(dateFont);
|
||||||
QColor q = painter->pen().color();
|
QColor q = painter->pen().color();
|
||||||
QString dateString = data.date.toLocalTime().toString("hh:mm");
|
QString dateString = data.date.toLocalTime().toString("hh:mm");
|
||||||
@ -304,7 +298,12 @@ QSize MessageDelegate::sizeHint(const QStyleOptionViewItem& option, const QModel
|
|||||||
Models::FeedItem data = qvariant_cast<Models::FeedItem>(vi);
|
Models::FeedItem data = qvariant_cast<Models::FeedItem>(vi);
|
||||||
QSize messageSize(0, 0);
|
QSize messageSize(0, 0);
|
||||||
if (data.text.size() > 0) {
|
if (data.text.size() > 0) {
|
||||||
messageSize = bodyMeter.boundingSize(data.text, messageRect.size());
|
bodyRenderer->setPlainText(data.text);
|
||||||
|
bodyRenderer->setTextWidth(messageRect.size().width());
|
||||||
|
|
||||||
|
QSizeF size = bodyRenderer->size();
|
||||||
|
size.setWidth(bodyRenderer->idealWidth());
|
||||||
|
messageSize = QSize(qCeil(size.width()), qCeil(size.height()));
|
||||||
messageSize.rheight() += textMargin;
|
messageSize.rheight() += textMargin;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -393,7 +392,7 @@ void MessageDelegate::initializeFonts(const QFont& font)
|
|||||||
nickMetrics = QFontMetrics(nickFont);
|
nickMetrics = QFontMetrics(nickFont);
|
||||||
dateMetrics = QFontMetrics(dateFont);
|
dateMetrics = QFontMetrics(dateFont);
|
||||||
|
|
||||||
bodyMeter.initializeFonts(bodyFont);
|
bodyRenderer->setDefaultFont(bodyFont);
|
||||||
|
|
||||||
Preview::initializeFont(bodyFont);
|
Preview::initializeFont(bodyFont);
|
||||||
}
|
}
|
||||||
@ -573,34 +572,36 @@ QLabel * MessageDelegate::getPencilIcon(const Models::FeedItem& data) const
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
QLabel * MessageDelegate::getBody(const Models::FeedItem& data) const
|
QTextBrowser * MessageDelegate::getBody(const Models::FeedItem& data) const
|
||||||
{
|
{
|
||||||
std::map<QString, QLabel*>::const_iterator itr = bodies->find(data.id);
|
std::map<QString, QTextBrowser*>::const_iterator itr = bodies->find(data.id);
|
||||||
QLabel* result = 0;
|
QTextBrowser* result = 0;
|
||||||
|
|
||||||
if (itr != bodies->end()) {
|
if (itr != bodies->end()) {
|
||||||
result = itr->second;
|
result = itr->second;
|
||||||
} else {
|
} else {
|
||||||
result = new QLabel();
|
result = new QTextBrowser();
|
||||||
result->setFont(bodyFont);
|
result->setFont(bodyFont);
|
||||||
result->setContextMenuPolicy(Qt::NoContextMenu);
|
result->setContextMenuPolicy(Qt::NoContextMenu);
|
||||||
result->setWordWrap(true);
|
result->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
|
||||||
|
result->setContentsMargins(0, 0, 0, 0);
|
||||||
|
//result->viewport()->setAutoFillBackground(false);
|
||||||
|
result->document()->setDocumentMargin(0);
|
||||||
|
result->setFrameStyle(0);
|
||||||
|
result->setLineWidth(0);
|
||||||
|
//result->setAutoFillBackground(false);
|
||||||
|
//->setWordWrap(true);
|
||||||
|
result->setOpenExternalLinks(true);
|
||||||
|
//result->setTextInteractionFlags(result->textInteractionFlags() | Qt::TextSelectableByMouse | Qt::LinksAccessibleByMouse);
|
||||||
result->setOpenExternalLinks(true);
|
result->setOpenExternalLinks(true);
|
||||||
result->setTextInteractionFlags(result->textInteractionFlags() | Qt::TextSelectableByMouse | Qt::LinksAccessibleByMouse);
|
|
||||||
bodies->insert(std::make_pair(data.id, result));
|
bodies->insert(std::make_pair(data.id, result));
|
||||||
}
|
}
|
||||||
|
|
||||||
result->setText(Shared::processMessageBody(data.text));
|
result->setHtml(Shared::processMessageBody(data.text));
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
void MessageDelegate::beginClearWidgets()
|
|
||||||
{
|
|
||||||
idsToKeep->clear();
|
|
||||||
clearingWidgets = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
void removeElements(std::map<QString, T*>* elements, std::set<QString>* idsToKeep) {
|
void removeElements(std::map<QString, T*>* elements, std::set<QString>* idsToKeep) {
|
||||||
std::set<QString> toRemove;
|
std::set<QString> toRemove;
|
||||||
@ -615,6 +616,51 @@ void removeElements(std::map<QString, T*>* elements, std::set<QString>* idsToKee
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int MessageDelegate::paintBody(const Models::FeedItem& data, QPainter* painter, QStyleOptionViewItem& option) const
|
||||||
|
{
|
||||||
|
if (data.text.size() > 0) {
|
||||||
|
bodyRenderer->setHtml(Shared::processMessageBody(data.text));
|
||||||
|
bodyRenderer->setTextWidth(option.rect.size().width());
|
||||||
|
painter->save();
|
||||||
|
painter->translate(option.rect.topLeft());
|
||||||
|
bodyRenderer->drawContents(painter);
|
||||||
|
painter->restore();
|
||||||
|
QSize bodySize(qCeil(bodyRenderer->idealWidth()), qCeil(bodyRenderer->size().height()));
|
||||||
|
|
||||||
|
|
||||||
|
QTextBrowser* editor = nullptr;
|
||||||
|
if (option.state.testFlag(QStyle::State_MouseOver)) {
|
||||||
|
std::set<QString> ids({data.id});
|
||||||
|
removeElements(bodies, &ids);
|
||||||
|
editor = getBody(data);
|
||||||
|
editor->setParent(static_cast<QWidget*>(painter->device()));
|
||||||
|
} else {
|
||||||
|
std::map<QString, QTextBrowser*>::const_iterator itr = bodies->find(data.id);
|
||||||
|
if (itr != bodies->end()) {
|
||||||
|
editor = itr->second;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (editor != nullptr) {
|
||||||
|
editor->setMinimumSize(bodySize);
|
||||||
|
editor->setMaximumSize(bodySize);
|
||||||
|
editor->move(option.rect.left(), option.rect.y());
|
||||||
|
editor->show();
|
||||||
|
}
|
||||||
|
|
||||||
|
option.rect.adjust(0, bodySize.height() + textMargin, 0, 0);
|
||||||
|
return bodySize.width();
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void MessageDelegate::beginClearWidgets()
|
||||||
|
{
|
||||||
|
idsToKeep->clear();
|
||||||
|
clearingWidgets = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
void MessageDelegate::endClearWidgets()
|
void MessageDelegate::endClearWidgets()
|
||||||
{
|
{
|
||||||
if (clearingWidgets) {
|
if (clearingWidgets) {
|
||||||
|
@ -29,12 +29,13 @@
|
|||||||
#include <QPushButton>
|
#include <QPushButton>
|
||||||
#include <QProgressBar>
|
#include <QProgressBar>
|
||||||
#include <QLabel>
|
#include <QLabel>
|
||||||
|
#include <QTextEdit>
|
||||||
|
#include <QTextBrowser>
|
||||||
|
|
||||||
#include "shared/icons.h"
|
#include "shared/icons.h"
|
||||||
#include "shared/global.h"
|
#include "shared/global.h"
|
||||||
#include "shared/utils.h"
|
#include "shared/utils.h"
|
||||||
#include "shared/pathcheck.h"
|
#include "shared/pathcheck.h"
|
||||||
#include "ui/utils/textmeter.h"
|
|
||||||
|
|
||||||
#include "preview.h"
|
#include "preview.h"
|
||||||
|
|
||||||
@ -70,13 +71,15 @@ protected:
|
|||||||
int paintBar(QProgressBar* bar, QPainter* painter, bool sentByMe, QStyleOptionViewItem& option) const;
|
int paintBar(QProgressBar* bar, QPainter* painter, bool sentByMe, QStyleOptionViewItem& option) const;
|
||||||
int paintPreview(const Models::FeedItem& data, QPainter* painter, QStyleOptionViewItem& option) const;
|
int paintPreview(const Models::FeedItem& data, QPainter* painter, QStyleOptionViewItem& option) const;
|
||||||
int paintComment(const Models::FeedItem& data, QPainter* painter, QStyleOptionViewItem& option) const;
|
int paintComment(const Models::FeedItem& data, QPainter* painter, QStyleOptionViewItem& option) const;
|
||||||
|
int paintBody(const Models::FeedItem& data, QPainter* painter, QStyleOptionViewItem& option) const;
|
||||||
void paintAvatar(const Models::FeedItem& data, const QModelIndex& index, const QStyleOptionViewItem& option, QPainter* painter) const;
|
void paintAvatar(const Models::FeedItem& data, const QModelIndex& index, const QStyleOptionViewItem& option, QPainter* painter) const;
|
||||||
void paintBubble(const Models::FeedItem& data, QPainter* painter, const QStyleOptionViewItem& option) const;
|
void paintBubble(const Models::FeedItem& data, QPainter* painter, const QStyleOptionViewItem& option) const;
|
||||||
|
|
||||||
QPushButton* getButton(const Models::FeedItem& data) const;
|
QPushButton* getButton(const Models::FeedItem& data) const;
|
||||||
QProgressBar* getBar(const Models::FeedItem& data) const;
|
QProgressBar* getBar(const Models::FeedItem& data) const;
|
||||||
QLabel* getStatusIcon(const Models::FeedItem& data) const;
|
QLabel* getStatusIcon(const Models::FeedItem& data) const;
|
||||||
QLabel* getPencilIcon(const Models::FeedItem& data) const;
|
QLabel* getPencilIcon(const Models::FeedItem& data) const;
|
||||||
QLabel* getBody(const Models::FeedItem& data) const;
|
QTextBrowser* getBody(const Models::FeedItem& data) const;
|
||||||
void clearHelperWidget(const Models::FeedItem& data) const;
|
void clearHelperWidget(const Models::FeedItem& data) const;
|
||||||
|
|
||||||
bool needToDrawAvatar(const QModelIndex& index, const Models::FeedItem& data, const QStyleOptionViewItem& option) const;
|
bool needToDrawAvatar(const QModelIndex& index, const Models::FeedItem& data, const QStyleOptionViewItem& option) const;
|
||||||
@ -95,7 +98,7 @@ private:
|
|||||||
QFont nickFont;
|
QFont nickFont;
|
||||||
QFont dateFont;
|
QFont dateFont;
|
||||||
QFontMetrics bodyMetrics;
|
QFontMetrics bodyMetrics;
|
||||||
TextMeter bodyMeter;
|
QTextDocument* bodyRenderer;
|
||||||
QFontMetrics nickMetrics;
|
QFontMetrics nickMetrics;
|
||||||
QFontMetrics dateMetrics;
|
QFontMetrics dateMetrics;
|
||||||
|
|
||||||
@ -107,7 +110,7 @@ private:
|
|||||||
std::map<QString, QProgressBar*>* bars;
|
std::map<QString, QProgressBar*>* bars;
|
||||||
std::map<QString, QLabel*>* statusIcons;
|
std::map<QString, QLabel*>* statusIcons;
|
||||||
std::map<QString, QLabel*>* pencilIcons;
|
std::map<QString, QLabel*>* pencilIcons;
|
||||||
std::map<QString, QLabel*>* bodies;
|
std::map<QString, QTextBrowser*>* bodies;
|
||||||
std::map<QString, Preview*>* previews;
|
std::map<QString, Preview*>* previews;
|
||||||
std::set<QString>* idsToKeep;
|
std::set<QString>* idsToKeep;
|
||||||
bool clearingWidgets;
|
bool clearingWidgets;
|
||||||
|
Loading…
Reference in New Issue
Block a user