+int ChatItem::setWidth(int w) {
+ w -= 10;
+ if(w == _boundingRect.width()) return _boundingRect.height();
+ int h = heightForWidth(w);
+ _boundingRect.setWidth(w);
+ _boundingRect.setHeight(h);
+ if(haveLayout()) updateLayout();
+ return h;
+}
+
+int ChatItem::heightForWidth(int width) {
+ if(data(ChatLineModel::ColumnTypeRole).toUInt() != ChatLineModel::ContentsColumn)
+ return fontMetrics()->lineSpacing(); // only contents can be multi-line
+
+ ChatLineModel::WrapList wrapList = data(ChatLineModel::WrapListRole).value<ChatLineModel::WrapList>();
+ _lines = 1;
+ 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();
+ }
+ w += wrapList.at(i).trailing;
+ }
+ return _lines * fontMetrics()->lineSpacing();
+}
+
+void ChatItem::layout() {
+ if(haveLayout()) return;
+ _layout = new QTextLayout(data(MessageModel::DisplayRole).toString());
+
+ QTextOption option;
+ option.setWrapMode(QTextOption::WrapAnywhere);
+ _layout->setTextOption(option);
+
+ // Convert format information into a FormatRange
+ QList<QTextLayout::FormatRange> formatRanges;
+ UiStyle::FormatList formatList = data(MessageModel::FormatRole).value<UiStyle::FormatList>();
+ QTextLayout::FormatRange range;
+ int i = 0;
+ for(i = 0; i < formatList.count(); i++) {
+ range.format = QtUi::style()->mergedFormat(formatList.at(i).second);
+ range.start = formatList.at(i).first;
+ if(i > 0) formatRanges.last().length = range.start - formatRanges.last().start;
+ formatRanges.append(range);
+ }
+ if(i > 0) formatRanges.last().length = _layout->text().length() - formatRanges.last().start;
+ _layout->setAdditionalFormats(formatRanges);
+ updateLayout();