presentation/TextMarksItem.h
| Line | Branch | Exec | Source |
|---|---|---|---|
| 1 | #pragma once | ||
| 2 | |||
| 3 | #include <QColor> | ||
| 4 | #include <QPointer> | ||
| 5 | #include <QQuickPaintedItem> | ||
| 6 | #include <QVariantList> | ||
| 7 | |||
| 8 | class QTextDocument; | ||
| 9 | |||
| 10 | // Sprint 108 F108-20: the wavy marks Qt Quick's TextEdit does not draw. | ||
| 11 | // A QSyntaxHighlighter marks misspellings (ComposeHighlighter) and script | ||
| 12 | // errors (SieveSyntaxHighlighter) with QTextCharFormat::WaveUnderline, but | ||
| 13 | // QQuickTextEdit draws only single underlines and ignores the underline | ||
| 14 | // colour — the marks never appeared. This item lies over the visible part | ||
| 15 | // of a TextEdit/TextArea (in QML `MailJD.Text` 1.0 `TextMarks`), reads the | ||
| 16 | // WaveUnderline ranges of the blocks it covers from the text layout and | ||
| 17 | // draws them as wavy lines in their underline colour. A painted item, so it | ||
| 18 | // works with every scene graph backend (the tests use the software one); | ||
| 19 | // it is as large as the viewport, not the document. | ||
| 20 | class TextMarksItem : public QQuickPaintedItem { | ||
| 21 | Q_OBJECT | ||
| 22 | // The TextEdit or TextArea whose marks are drawn. | ||
| 23 | Q_PROPERTY(QQuickItem *textItem READ textItem WRITE setTextItem NOTIFY textItemChanged) | ||
| 24 | // Changes when the text scrolls under this item (bind the Flickable's | ||
| 25 | // Qt.point(contentX, contentY)). | ||
| 26 | Q_PROPERTY(QPointF scrollOffset READ scrollOffset WRITE setScrollOffset NOTIFY scrollOffsetChanged) | ||
| 27 | // The marks drawn last, [{x, y, width}] in this item's coordinates (tests). | ||
| 28 | Q_PROPERTY(QVariantList drawn READ drawn NOTIFY drawnChanged) | ||
| 29 | |||
| 30 | public: | ||
| 31 | explicit TextMarksItem(QQuickItem *parent = nullptr); | ||
| 32 | static void registerTypes(); | ||
| 33 | |||
| 34 | ✗ | QQuickItem *textItem() const { return m_textItem; } | |
| 35 | void setTextItem(QQuickItem *item); | ||
| 36 | ✗ | QPointF scrollOffset() const { return m_scrollOffset; } | |
| 37 | void setScrollOffset(QPointF offset); | ||
| 38 | 13 | QVariantList drawn() const { return m_drawnList; } | |
| 39 | |||
| 40 | void paint(QPainter *painter) override; | ||
| 41 | |||
| 42 | // At most this many marks are drawn (a document full of unknown words | ||
| 43 | // stays cheap). | ||
| 44 | static constexpr int MaxMarks = 400; | ||
| 45 | |||
| 46 | protected: | ||
| 47 | // The marks are read here, on the GUI thread (paint may run on the | ||
| 48 | // render thread). | ||
| 49 | void updatePolish() override; | ||
| 50 | |||
| 51 | |||
| 52 | private slots: | ||
| 53 | 3614 | void schedule() { polish(); } | |
| 54 | |||
| 55 | signals: | ||
| 56 | void textItemChanged(); | ||
| 57 | void scrollOffsetChanged(); | ||
| 58 | void drawnChanged(); | ||
| 59 | |||
| 60 | private: | ||
| 61 | struct Mark { | ||
| 62 | qreal x = 0, y = 0, width = 0; | ||
| 63 | QColor color; | ||
| 64 | }; | ||
| 65 | QTextDocument *document() const; | ||
| 66 | QList<Mark> collect() const; | ||
| 67 | void watchDocument(); | ||
| 68 | |||
| 69 | QPointer<QQuickItem> m_textItem; | ||
| 70 | QPointer<QTextDocument> m_document; | ||
| 71 | QPointF m_scrollOffset; | ||
| 72 | QList<Mark> m_marks; | ||
| 73 | QVariantList m_drawnList; | ||
| 74 | }; | ||
| 75 |