From: Manuel Nickschas Date: Sat, 14 Jun 2008 23:37:08 +0000 (+0200) Subject: Reworking the wordwrap stuff. X-Git-Tag: 0.3.0~177 X-Git-Url: https://git.quassel-irc.org/?p=quassel.git;a=commitdiff_plain;h=3197b8b309f09ac1f4db54fa8fa819e33b87383e Reworking the wordwrap stuff. Still has some edges and cornercases to iron out though... --- diff --git a/src/qtui/chatitem.cpp b/src/qtui/chatitem.cpp index 6efe8c2a..17189f94 100644 --- a/src/qtui/chatitem.cpp +++ b/src/qtui/chatitem.cpp @@ -60,19 +60,21 @@ int ChatItem::heightForWidth(int width) { if(data(ChatLineModel::ColumnTypeRole).toUInt() != ChatLineModel::ContentsColumn) return _lineHeight; // only contents can be multi-line - QVariantList wrapList = data(ChatLineModel::WrapListRole).toList(); + ChatLineModel::WrapList wrapList = data(ChatLineModel::WrapListRole).value(); int lines = 1; - int offset = 0; - for(int i = 0; i < wrapList.count(); i+=2) { - if(wrapList.at(i+1).toUInt() - offset < width) continue; + qreal w = 0; + for(int i = 0; i < wrapList.count(); i++) { + w += wrapList.at(i).width; + if(w <= width) { + w += wrapList.at(i).trailing; + continue; + } lines++; - if(i > 0) { - if(offset < wrapList.at(i-1).toUInt()) offset = wrapList.at(i-1).toUInt(); - else offset += width; - } else { - offset += width; + w = wrapList.at(i).width; + while(w >= width) { + lines++; + w -= width; } - i-=2; } return lines * _lineHeight; } @@ -126,6 +128,12 @@ void ChatItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, layout(); _layout->draw(painter, QPointF(0,0), QVector(), boundingRect()); painter->drawRect(boundingRect()); + int width = 0; + QVariantList wrapList = data(ChatLineModel::WrapListRole).toList(); + for(int i = 2; i < wrapList.count(); i+=2) { + QRect r(wrapList[i-1].toUInt(), 0, wrapList[i+1].toUInt() - wrapList[i-1].toUInt(), _lineHeight); + painter->drawRect(r); + } } /* diff --git a/src/qtui/chatitem.h b/src/qtui/chatitem.h index d32b3cc0..956af0e8 100644 --- a/src/qtui/chatitem.h +++ b/src/qtui/chatitem.h @@ -74,6 +74,7 @@ class ChatItem : public QGraphicsItem { QPersistentModelIndex _index; QTextLayout *_layout; + QList _wrapPositions; }; #endif diff --git a/src/qtui/chatlinemodel.cpp b/src/qtui/chatlinemodel.cpp index 3cf68b17..28d77fb5 100644 --- a/src/qtui/chatlinemodel.cpp +++ b/src/qtui/chatlinemodel.cpp @@ -23,7 +23,8 @@ #include "chatlinemodelitem.h" ChatLineModel::ChatLineModel(QObject *parent) : MessageModel(parent) { - + qRegisterMetaType("ChatLineModel::WrapList"); + qRegisterMetaTypeStreamOperators("ChatLineModel::WrapList"); } @@ -36,3 +37,24 @@ MessageModelItem *ChatLineModel::createMessageModelItem(const Message &msg) { return new ChatLineModelItem(msg); } + + +QDataStream &operator<<(QDataStream &out, const ChatLineModel::WrapList wplist) { + out << wplist.count(); + ChatLineModel::WrapList::const_iterator it = wplist.begin(); + while(it != wplist.end()) { + out << (*it).start << (*it).width << (*it).trailing; + ++it; + } + return out; +} + +QDataStream &operator>>(QDataStream &in, ChatLineModel::WrapList &wplist) { + quint16 cnt; + in >> cnt; + wplist.resize(cnt); + for(quint16 i = 0; i < cnt; i++) { + in >> wplist[i].start >> wplist[i].width >> wplist[i].trailing; + } + return in; +} diff --git a/src/qtui/chatlinemodel.h b/src/qtui/chatlinemodel.h index 779b5f2a..a1e2c692 100644 --- a/src/qtui/chatlinemodel.h +++ b/src/qtui/chatlinemodel.h @@ -34,10 +34,24 @@ class ChatLineModel : public MessageModel { ChatLineModel(QObject *parent = 0); virtual ~ChatLineModel(); + /// Used to store information about words to be used for wrapping + struct Word { + quint16 start; + qreal width; + qreal trailing; + }; + + typedef QVector WrapList; + protected: virtual MessageModelItem *createMessageModelItem(const Message &); }; +QDataStream &operator<<(QDataStream &out, const ChatLineModel::WrapList); +QDataStream &operator>>(QDataStream &in, ChatLineModel::WrapList &); + +Q_DECLARE_METATYPE(ChatLineModel::WrapList); + #endif diff --git a/src/qtui/chatlinemodelitem.cpp b/src/qtui/chatlinemodelitem.cpp index 9529412f..38663bb0 100644 --- a/src/qtui/chatlinemodelitem.cpp +++ b/src/qtui/chatlinemodelitem.cpp @@ -58,10 +58,7 @@ QVariant ChatLineModelItem::data(int column, int role) const { return QVariant::fromValue(part->formatList); case ChatLineModel::WrapListRole: if(column != ChatLineModel::ContentsColumn) return QVariant(); - QVariantList wrapList; - typedef QPair WrapPoint; // foreach can't parse templated params - foreach(WrapPoint pair, _wrapList) wrapList << pair.first << pair.second; - return wrapList; + return QVariant::fromValue(_wrapList); } return MessageModelItem::data(column, role); @@ -71,33 +68,61 @@ bool ChatLineModelItem::setData(int column, const QVariant &value, int role) { return false; } +// compute the width of a text snippet +qreal ChatLineModelItem::snippetWidth(int start, int end, QFontMetricsF *&metrics, int &formatListIdx, int &formatEnd) { + qreal width = 0; + while(start < end) { + if(formatEnd <= start) { + formatListIdx++; + formatEnd = _contents.formatList.count() > formatListIdx+1 ? _contents.formatList[formatListIdx+1].first + : _contents.plainText.length(); + metrics = QtUi::style()->fontMetrics(_contents.formatList[formatListIdx].second); + Q_ASSERT(formatEnd > start); + } + int i = qMin(end, formatEnd); + width += metrics->width(_contents.plainText.mid(start, i - start)); + start = i; + } + return width; +} + void ChatLineModelItem::computeWrapList() { - WrapList wplist; // use a temp list which we'll later copy into a QVector for efficiency + enum Mode { SearchStart, SearchEnd }; + + QList wplist; // use a temp list which we'll later copy into a QVector for efficiency QTextBoundaryFinder finder(QTextBoundaryFinder::Word, _contents.plainText); - int idx; + int idx, oldidx; + qreal pxpos = 0; int flistidx = -1; int fmtend = -1; - QFontMetricsF *metrics; - QPair wp(0, 0); + bool wordStart = false; bool wordEnd = false; + QFontMetricsF *metrics = 0; + Mode mode = SearchEnd; + ChatLineModel::Word word; + word.start = 0; do { idx = finder.toNextBoundary(); if(idx < 0) idx = _contents.plainText.length(); - else if(finder.boundaryReasons() != QTextBoundaryFinder::StartWord) continue; - int start = wp.first; - while(start < idx) { - if(fmtend <= start) { - flistidx++; - fmtend = _contents.formatList.count() > flistidx+1 ? _contents.formatList[flistidx+1].first - : _contents.plainText.length(); - metrics = QtUi::style()->fontMetrics(_contents.formatList[flistidx].second); - Q_ASSERT(fmtend > start); - } - int i = qMin(idx, fmtend); - wp.second += metrics->width(_contents.plainText.mid(start, i - start)); - start = i; + wordStart = finder.boundaryReasons().testFlag(QTextBoundaryFinder::StartWord); + wordEnd = finder.boundaryReasons().testFlag(QTextBoundaryFinder::EndWord); + + //qDebug() << wordStart << wordEnd << _contents.plainText.left(idx) << _contents.plainText.mid(idx); + + if(mode == SearchEnd || !wordStart && wordEnd) { + if(wordStart || !wordEnd) continue; + oldidx = idx; + mode = SearchStart; + continue; + } + // mode == SearchStart + word.width = snippetWidth(word.start, oldidx, metrics, flistidx, fmtend); + word.trailing = snippetWidth(oldidx, idx, metrics, flistidx, fmtend); + wplist.append(word); + + if(wordStart) { + word.start = idx; + mode = SearchEnd; } - wplist.append(wp); - wp.first = idx; } while(finder.isAtBoundary()); // A QVector needs less space than a QList diff --git a/src/qtui/chatlinemodelitem.h b/src/qtui/chatlinemodelitem.h index f01b4e1d..b76ea68e 100644 --- a/src/qtui/chatlinemodelitem.h +++ b/src/qtui/chatlinemodelitem.h @@ -24,12 +24,13 @@ #include #include -#include "messagemodel.h" +#include "chatlinemodel.h" #include "uistyle.h" class ChatLineModelItem : public MessageModelItem { public: + ChatLineModelItem(const Message &); //virtual ~ChatLineModelItem() {}; @@ -37,9 +38,8 @@ class ChatLineModelItem : public MessageModelItem { virtual bool setData(int column, const QVariant &value, int role); private: - typedef QVector > WrapList; - void computeWrapList(); + qreal snippetWidth(int start, int end, QFontMetricsF *&metrics, int &formatListIdx, int &formatEnd); struct ChatLinePart { QString plainText; @@ -47,7 +47,7 @@ class ChatLineModelItem : public MessageModelItem { }; ChatLinePart _timestamp, _sender, _contents; - WrapList _wrapList; + ChatLineModel::WrapList _wrapList; }; #endif