- 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++;
- w = wrapList.at(i).width;
- while(w >= width) { // handle words longer than a line
- _lines++;
- // We do not want to compute an exact split position (that would require us to calculate glyph widths
- // and also apply formats in this step...)
- // Just using width should be a good estimate, but since a character can't be split in the middle, we
- // subtract averageCharWidth as well... sometimes this won't be enough, but meh.
- w -= width - fontMetrics()->averageCharWidth();
+ QTextLine line;
+ WrapColumnFinder finder(this);
+ while(finder.nextWrapColumn(line) > 0) _lines++;
+ return _lines * fontMetrics()->lineSpacing();
+}
+
+ChatItem::WrapColumnFinder::WrapColumnFinder(ChatItem *_item) : item(_item) {
+ wrapList = item->data(ChatLineModel::WrapListRole).value<ChatLineModel::WrapList>();
+ wordidx = 0;
+ layout = 0;
+ lastwrapcol = 0;
+ lastwrappos = 0;
+ w = 0;
+}
+
+ChatItem::WrapColumnFinder::~WrapColumnFinder() {
+ delete layout;
+}
+
+int ChatItem::WrapColumnFinder::nextWrapColumn(QTextLine &line) {
+ while(wordidx < wrapList.count()) {
+ w += wrapList.at(wordidx).width;
+ if(w >= item->width()) {
+ if(lastwrapcol == wrapList.at(wordidx).start) {
+ // first word, and it doesn't fit
+ if(!line.isValid()) {
+ layout = item->createLayout();
+ layout->beginLayout();
+ line = layout->createLine();
+ line.setLineWidth(item->width());
+ layout->endLayout();
+ }
+ int idx = line.xToCursor((line.textStart() ? 0 : lastwrappos) + item->width());
+ qreal x = line.cursorToX(idx);
+ idx += line.textStart();
+ w = w - x - wrapList.at(wordidx).width;
+ if(line.textStart()) lastwrappos += x;
+ else lastwrappos = x;
+ lastwrapcol = idx;
+ return idx;
+ }
+ // not the first word, so just wrap before this
+ lastwrapcol = wrapList.at(wordidx).start;
+ lastwrappos = lastwrappos + w - wrapList.at(wordidx).width;
+ w = 0;
+ return lastwrapcol;