Tweak ChatItem/ChatLine layouting
authorManuel Nickschas <sputnick@quassel-irc.org>
Thu, 30 Jul 2009 19:27:30 +0000 (21:27 +0200)
committerManuel Nickschas <sputnick@quassel-irc.org>
Thu, 6 Aug 2009 18:25:58 +0000 (20:25 +0200)
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
src/qtui/chatitem.h
src/qtui/chatline.cpp
src/qtui/chatscene.cpp
src/qtui/chatscene.h

index 390e428..b52fe3f 100644 (file)
@@ -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;
index 10c5399..e31ce81 100644 (file)
@@ -248,7 +248,7 @@ public:
   WrapColumnFinder(const ChatItem *parent);
   ~WrapColumnFinder();
 
-  qint16 nextWrapColumn();
+  qint16 nextWrapColumn(qreal width);
 
 private:
   const ChatItem *item;
index 3c68c4b..12268a2 100644 (file)
@@ -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.
 }
index bcfea00..b159dc9 100644 (file)
@@ -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<ChatLine *>::iterator lineIter = _lines.end();
-  QList<ChatLine *>::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);
index 82ccacc..6595ea4 100644 (file)
@@ -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);