From 9fd12737c55a0119801c90c399c926b35ffee708 Mon Sep 17 00:00:00 2001 From: Manuel Nickschas Date: Thu, 30 Jul 2009 21:27:30 +0200 Subject: [PATCH] Tweak ChatItem/ChatLine layouting This makes the scene react properly to dataChanged() signals from the MessageModel. Only affected ChatLines are relayouted, the rest moved as appropriately. We can now also call updateGeometryByWidth() with unchanged width to force a relayout in case the style has changed. --- src/qtui/chatitem.cpp | 37 ++++++++++++++++++------------------- src/qtui/chatitem.h | 2 +- src/qtui/chatline.cpp | 16 ++++++++-------- src/qtui/chatscene.cpp | 39 +++++++++++++++++++++++---------------- src/qtui/chatscene.h | 2 +- 5 files changed, 51 insertions(+), 45 deletions(-) diff --git a/src/qtui/chatitem.cpp b/src/qtui/chatitem.cpp index 390e428a..b52fe3f0 100644 --- a/src/qtui/chatitem.cpp +++ b/src/qtui/chatitem.cpp @@ -387,23 +387,22 @@ ContentsChatItemPrivate *ContentsChatItem::privateData() const { } qreal ContentsChatItem::setGeometryByWidth(qreal w) { - if(w == width()) { - //qDebug() << Q_FUNC_INFO << "Geometry change requested with identical width!"; - } - // We use this for reloading layout info as well - //if(w != width()) { + // We use this for reloading layout info as well, so we can't bail out if the width doesn't change + + // compute height + int lines = 1; + WrapColumnFinder finder(this); + while(finder.nextWrapColumn(w) > 0) + lines++; + qreal h = lines * fontMetrics()->lineSpacing(); + delete _data; + _data = 0; + + if(w != width() || h != height()) { prepareGeometryChange(); - setWidth(w); - // compute height - int lines = 1; - WrapColumnFinder finder(this); - while(finder.nextWrapColumn() > 0) - lines++; - setHeight(lines * fontMetrics()->lineSpacing()); - delete _data; - _data = 0; - //} - return height(); + setGeometry(w, h); + } + return h; } void ContentsChatItem::doLayout(QTextLayout *layout) const { @@ -418,7 +417,7 @@ void ContentsChatItem::doLayout(QTextLayout *layout) const { if(!line.isValid()) break; - int col = finder.nextWrapColumn(); + int col = finder.nextWrapColumn(width()); line.setNumColumns(col >= 0 ? col - line.textStart() : layout->text().length()); line.setPosition(QPointF(0, h)); h += fontMetrics()->lineSpacing(); @@ -700,12 +699,12 @@ ContentsChatItem::WrapColumnFinder::WrapColumnFinder(const ChatItem *_item) ContentsChatItem::WrapColumnFinder::~WrapColumnFinder() { } -qint16 ContentsChatItem::WrapColumnFinder::nextWrapColumn() { +qint16 ContentsChatItem::WrapColumnFinder::nextWrapColumn(qreal width) { if(wordidx >= wrapList.count()) return -1; lineCount++; - qreal targetWidth = lineCount * item->width() + choppedTrailing; + qreal targetWidth = lineCount * width + choppedTrailing; qint16 start = wordidx; qint16 end = wrapList.count() - 1; diff --git a/src/qtui/chatitem.h b/src/qtui/chatitem.h index 10c53993..e31ce819 100644 --- a/src/qtui/chatitem.h +++ b/src/qtui/chatitem.h @@ -248,7 +248,7 @@ public: WrapColumnFinder(const ChatItem *parent); ~WrapColumnFinder(); - qint16 nextWrapColumn(); + qint16 nextWrapColumn(qreal width); private: const ChatItem *item; diff --git a/src/qtui/chatline.cpp b/src/qtui/chatline.cpp index 3c68c4b0..12268a28 100644 --- a/src/qtui/chatline.cpp +++ b/src/qtui/chatline.cpp @@ -105,20 +105,20 @@ void ChatLine::setSecondColumn(const qreal &senderWidth, const qreal &contentsWi void ChatLine::setGeometryByWidth(const qreal &width, const qreal &contentsWidth, qreal &linePos) { qreal height = _contentsItem.setGeometryByWidth(contentsWidth); linePos -= height; - bool needGeometryChange = linePos == pos().y(); + bool needGeometryChange = (height != _height || width != _width); - if(needGeometryChange) { + if(height != _height) { _timestampItem.prepareGeometryChange(); + _timestampItem.setHeight(height); _senderItem.prepareGeometryChange(); + _senderItem.setHeight(height); } - _timestampItem.setHeight(height); - _senderItem.setHeight(height); - if(needGeometryChange) + if(needGeometryChange) { prepareGeometryChange(); - - _height = height; - _width = width; + _height = height; + _width = width; + } setPos(0, linePos); // set pos is _very_ cheap if nothing changes. } diff --git a/src/qtui/chatscene.cpp b/src/qtui/chatscene.cpp index bcfea000..b159dc90 100644 --- a/src/qtui/chatscene.cpp +++ b/src/qtui/chatscene.cpp @@ -382,10 +382,7 @@ void ChatScene::rowsAboutToBeRemoved(const QModelIndex &parent, int start, int e } void ChatScene::dataChanged(const QModelIndex &tl, const QModelIndex &br) { - // This should only be sent (currently) if the style is reloaded -> re-layout the whole scene - // TODO: Check range and only do partial relayouts, if appropriate - - layout(); + layout(tl.row(), br.row(), _sceneRect.width()); } void ChatScene::updateForViewport(qreal width, qreal height) { @@ -396,27 +393,37 @@ void ChatScene::updateForViewport(qreal width, qreal height) { void ChatScene::setWidth(qreal width) { if(width == _sceneRect.width()) return; - layout(width); + layout(0, _lines.count()-1, width); } -void ChatScene::layout(qreal width) { +void ChatScene::layout(int start, int end, qreal width) { // clock_t startT = clock(); - if(width < 0) - width = _sceneRect.width(); - // disabling the index while doing this complex updates is about // 2 to 10 times faster! //setItemIndexMethod(QGraphicsScene::NoIndex); - QList::iterator lineIter = _lines.end(); - QList::iterator lineIterBegin = _lines.begin(); - qreal linePos = _sceneRect.y() + _sceneRect.height(); - qreal contentsWidth = width - secondColumnHandle()->sceneRight(); - while(lineIter != lineIterBegin) { - lineIter--; - (*lineIter)->setGeometryByWidth(width, contentsWidth, linePos); + if(end >= 0) { + int row = end; + qreal linePos = _lines.at(row)->scenePos().y() + _lines.at(row)->height(); + qreal contentsWidth = width - secondColumnHandle()->sceneRight(); + while(row >= start) { + _lines.at(row--)->setGeometryByWidth(width, contentsWidth, linePos); + } + + if(row >= 0) { + // remaining items don't need geometry changes, but maybe repositioning? + ChatLine *line = _lines.at(row); + qreal offset = linePos - (line->scenePos().y() + line->height()); + if(offset != 0) { + while(row >= 0) { + line = _lines.at(row--); + line->setPos(0, line->scenePos().y() + offset); + } + } + } } + //setItemIndexMethod(QGraphicsScene::BspTreeIndex); updateSceneRect(width); diff --git a/src/qtui/chatscene.h b/src/qtui/chatscene.h index 82ccacc2..6595ea4f 100644 --- a/src/qtui/chatscene.h +++ b/src/qtui/chatscene.h @@ -108,7 +108,7 @@ public: public slots: void updateForViewport(qreal width, qreal height); void setWidth(qreal width); - void layout(qreal width = -1); + void layout(int start, int end, qreal width); // these are used by the chatitems to notify the scene and manage selections void setSelectingItem(ChatItem *item); -- 2.20.1