|
| 1 | +#include "textlayout.h" |
| 2 | + |
| 3 | +#include <QTextLayout> |
| 4 | + |
| 5 | +#include "edbee/debug.h" |
| 6 | + |
| 7 | +namespace edbee { |
| 8 | + |
| 9 | + |
| 10 | +//================================================= |
| 11 | + |
| 12 | +TextLayout::TextLayout(TextDocument* document) |
| 13 | + : qtextLayout_( new QTextLayout()) |
| 14 | + , textDocumentRef_(document) |
| 15 | + , singleCharRanges_(nullptr) |
| 16 | +{ |
| 17 | +} |
| 18 | + |
| 19 | +TextLayout::~TextLayout() |
| 20 | +{ |
| 21 | + delete singleCharRanges_; |
| 22 | + delete qtextLayout_; |
| 23 | +} |
| 24 | + |
| 25 | +void TextLayout::setCacheEnabled(bool enable) |
| 26 | +{ |
| 27 | + qtextLayout_->setCacheEnabled(enable); |
| 28 | +} |
| 29 | + |
| 30 | +QTextLayout *TextLayout::qTextLayout() const |
| 31 | +{ |
| 32 | + return qtextLayout_; |
| 33 | +} |
| 34 | + |
| 35 | +QRectF TextLayout::boundingRect() const |
| 36 | +{ |
| 37 | + return qtextLayout_->boundingRect(); |
| 38 | +} |
| 39 | + |
| 40 | +void TextLayout::buildLayout() |
| 41 | +{ |
| 42 | + qtextLayout_->beginLayout(); |
| 43 | + qtextLine_ = qtextLayout_->createLine(); |
| 44 | + qtextLayout_->endLayout(); |
| 45 | + |
| 46 | +} |
| 47 | + |
| 48 | +/// Converts the document cursorPosition to a virtual cursorposition |
| 49 | +int TextLayout::toVirtualCursorPosition(int cursorPos) const |
| 50 | +{ |
| 51 | + int delta = 0; |
| 52 | + // convert cursor to a valid location |
| 53 | + TextRangeSet* ranges = singleCharRanges(); |
| 54 | + if(ranges) { |
| 55 | + for(int i=0, cnt = ranges->rangeCount(); i < cnt; i++ ) { |
| 56 | + TextRange& range = ranges->range(i); |
| 57 | + if( cursorPos + delta > range.min()) { |
| 58 | + delta += range.length() - 1; |
| 59 | + } |
| 60 | + } |
| 61 | + } |
| 62 | + return cursorPos + delta; |
| 63 | +} |
| 64 | + |
| 65 | +/// Converts the virtual cursorPosition to a docuemnt cursorposition |
| 66 | +int TextLayout::fromVirtualCursorPosition(int cursor) const |
| 67 | +{ |
| 68 | + // when the cursor falls in a single-character range. |
| 69 | + // Set the cursor to the start of this range |
| 70 | + int delta = 0; |
| 71 | + |
| 72 | + TextRangeSet* ranges = singleCharRanges(); |
| 73 | + if(ranges) { |
| 74 | + for(int i=0, cnt = ranges->rangeCount(); i < cnt; i++ ) { |
| 75 | + TextRange& range = ranges->range(i); |
| 76 | + if(range.min() <= cursor && cursor < range.max() ) { |
| 77 | + delta += cursor - range.min(); |
| 78 | + } else if( range.max() <= cursor ) { |
| 79 | + delta += range.length() - 1; |
| 80 | + } |
| 81 | + } |
| 82 | + } |
| 83 | + return cursor - delta; |
| 84 | +} |
| 85 | + |
| 86 | +void TextLayout::draw(QPainter *p, const QPointF &pos, const QVector<QTextLayout::FormatRange> &selections, const QRectF &clip) const |
| 87 | +{ |
| 88 | + qtextLayout_->draw(p, pos, selections, clip); |
| 89 | +} |
| 90 | + |
| 91 | +void TextLayout::drawCursor(QPainter *painter, const QPointF &position, int cursorPosition, int width) const |
| 92 | +{ |
| 93 | + int virtualCursorPosition = toVirtualCursorPosition(cursorPosition); |
| 94 | + qtextLayout_->drawCursor(painter, position, virtualCursorPosition, width); |
| 95 | +} |
| 96 | + |
| 97 | +void TextLayout::setFormats(const QVector<QTextLayout::FormatRange> &formats) |
| 98 | +{ |
| 99 | + qtextLayout_->setFormats(formats); |
| 100 | +} |
| 101 | + |
| 102 | +void TextLayout::setText(const QString &string) |
| 103 | +{ |
| 104 | + qtextLayout_->setText(string); |
| 105 | +} |
| 106 | + |
| 107 | +void TextLayout::useSingleCharRanges() |
| 108 | +{ |
| 109 | + if(!singleCharRanges_) { |
| 110 | + singleCharRanges_ = new TextRangeSet(textDocumentRef_); |
| 111 | + } |
| 112 | +} |
| 113 | + |
| 114 | +TextRangeSet *TextLayout::singleCharRanges() const |
| 115 | +{ |
| 116 | + return singleCharRanges_; |
| 117 | +} |
| 118 | + |
| 119 | +void TextLayout::addSingleCharRange(int index, int length) |
| 120 | +{ |
| 121 | + useSingleCharRanges(); |
| 122 | + singleCharRanges()->addRange(index, index+length); |
| 123 | +} |
| 124 | + |
| 125 | + |
| 126 | + |
| 127 | +qreal TextLayout::cursorToX(int cursorPos, QTextLine::Edge edge) const |
| 128 | +{ |
| 129 | + int virtualCursorPos = toVirtualCursorPosition(cursorPos); |
| 130 | + |
| 131 | + qreal x = qtextLine_.cursorToX(virtualCursorPos, edge); |
| 132 | + return x; |
| 133 | +} |
| 134 | + |
| 135 | +int TextLayout::xToCursor(qreal x, QTextLine::CursorPosition cpos) const |
| 136 | +{ |
| 137 | + int virtualCursor = qtextLine_.xToCursor(x, cpos); |
| 138 | + return fromVirtualCursorPosition(virtualCursor); |
| 139 | +} |
| 140 | + |
| 141 | + |
| 142 | +//================================================= |
| 143 | + |
| 144 | +TextLayoutBuilder::TextLayoutBuilder(TextLayout *textLayout, QString & baseString, QVector<QTextLayout::FormatRange> & baseFormatRanges) |
| 145 | + : textLayoutRef_(textLayout) |
| 146 | + , baseString_(baseString) |
| 147 | + , baseFormatRanges_(baseFormatRanges) |
| 148 | +{ |
| 149 | + |
| 150 | +} |
| 151 | + |
| 152 | +void TextLayoutBuilder::replace(int index, int length, const QString replacement, QTextCharFormat format) |
| 153 | +{ |
| 154 | + baseString_.replace(index, length, replacement); |
| 155 | + textLayoutRef_->addSingleCharRange(index, replacement.length()); /// TODO: Should we store the original length!?!?!? |
| 156 | + |
| 157 | + // change existing format ranges: |
| 158 | + int delta = replacement.length() - length; |
| 159 | + if( delta != 0 ) { |
| 160 | + for(int i=0, cnt = baseFormatRanges_.length(); i < cnt; i++ ) { |
| 161 | + QTextLayout::FormatRange& formatRange = baseFormatRanges_[i]; |
| 162 | + if( formatRange.start >= index ) { |
| 163 | + formatRange.start += delta; |
| 164 | + } |
| 165 | + } |
| 166 | + } |
| 167 | + |
| 168 | + |
| 169 | + // append the text format |
| 170 | + QTextLayout::FormatRange formatRange; |
| 171 | + formatRange.format = format; |
| 172 | + formatRange.start = index; |
| 173 | + formatRange.length = replacement.length(); |
| 174 | + baseFormatRanges_.append(formatRange); |
| 175 | +} |
| 176 | + |
| 177 | +} // edbee |
| 178 | + |
| 179 | + |
0 commit comments