| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536 |
- // This file is part of Desktop App Toolkit,
- // a set of libraries for developing nice desktop applications.
- //
- // For license and copyright information please follow this link:
- // https://github.com/desktop-app/legal/blob/master/LEGAL
- //
- #pragma once
- #include "ui/text/text_entity.h"
- #include "ui/click_handler.h"
- #include "base/flags.h"
- #include "ui/style/style_core_types.h"
- #include <crl/crl_time.h>
- #include <any>
- class Painter;
- namespace anim {
- enum class type : uchar;
- } // namespace anim
- namespace style {
- struct TextStyle;
- struct TextPalette;
- struct QuoteStyle;
- } // namespace style
- namespace Ui {
- class SpoilerMessCached;
- extern const QString kQEllipsis;
- inline constexpr auto kQFixedMax = (INT_MAX / 256);
- } // namespace Ui
- struct TextParseOptions {
- int32 flags;
- int32 maxw;
- int32 maxh;
- Qt::LayoutDirection dir;
- };
- extern const TextParseOptions kDefaultTextOptions;
- extern const TextParseOptions kMarkupTextOptions;
- extern const TextParseOptions kPlainTextOptions;
- enum class TextSelectType {
- Letters = 0x01,
- Words = 0x02,
- Paragraphs = 0x03,
- };
- struct TextSelection {
- constexpr TextSelection() = default;
- constexpr TextSelection(uint16 from, uint16 to) : from(from), to(to) {
- }
- constexpr bool empty() const {
- return from == to;
- }
- uint16 from = 0;
- uint16 to = 0;
- };
- inline bool operator==(TextSelection a, TextSelection b) {
- return a.from == b.from && a.to == b.to;
- }
- inline bool operator!=(TextSelection a, TextSelection b) {
- return !(a == b);
- }
- static constexpr TextSelection AllTextSelection = { 0, 0xFFFF };
- namespace Ui::Text {
- class CustomEmoji;
- class AbstractBlock;
- class Block;
- class Word;
- struct IsolatedEmoji;
- struct OnlyCustomEmoji;
- struct SpoilerData;
- struct QuoteDetails;
- struct QuotesData;
- struct ExtendedData;
- struct MarkedContext;
- using CustomEmojiFactory = Fn<std::unique_ptr<CustomEmoji>(
- QStringView,
- const MarkedContext &)>;
- struct MarkedContext {
- Fn<void()> repaint;
- CustomEmojiFactory customEmojiFactory;
- std::any other;
- };
- struct Modification {
- int position = 0;
- uint16 skipped = 0;
- bool added = false;
- };
- struct StateRequest {
- enum class Flag {
- BreakEverywhere = (1 << 0),
- LookupSymbol = (1 << 1),
- LookupLink = (1 << 2),
- LookupCustomTooltip = (1 << 3),
- };
- using Flags = base::flags<Flag>;
- friend inline constexpr auto is_flag_type(Flag) { return true; };
- StateRequest() {
- }
- style::align align = style::al_left;
- Flags flags = Flag::LookupLink;
- };
- struct StateResult {
- ClickHandlerPtr link;
- bool uponSymbol = false;
- bool afterSymbol = false;
- uint16 symbol = 0;
- };
- struct StateRequestElided : StateRequest {
- StateRequestElided() {
- }
- StateRequestElided(const StateRequest &other) : StateRequest(other) {
- }
- int lines = 1;
- int removeFromEnd = 0;
- };
- class SpoilerMessCache {
- public:
- explicit SpoilerMessCache(int capacity);
- ~SpoilerMessCache();
- [[nodiscard]] not_null<SpoilerMessCached*> lookup(QColor color);
- void reset();
- private:
- struct Entry;
- std::vector<Entry> _cache;
- const int _capacity = 0;
- };
- struct SpecialColor {
- const QPen *pen = nullptr;
- const QPen *penSelected = nullptr;
- };
- struct LineGeometry {
- int left = 0;
- int width = 0;
- bool elided = false;
- };
- struct GeometryDescriptor {
- Fn<LineGeometry(int line)> layout;
- bool breakEverywhere = false;
- bool *outElided = nullptr;
- };
- [[nodiscard]] not_null<SpoilerMessCache*> DefaultSpoilerCache();
- [[nodiscard]] GeometryDescriptor SimpleGeometry(
- int availableWidth,
- int elisionLines,
- int elisionRemoveFromEnd,
- bool elisionBreakEverywhere);
- constexpr auto kMaxQuoteOutlines = 3;
- struct QuotePaintCache {
- QImage corners;
- QImage outline;
- QImage expand;
- QImage collapse;
- mutable QImage bottomCorner;
- mutable QImage bottomRounding;
- mutable QImage collapsedLine;
- std::array<QColor, kMaxQuoteOutlines> outlinesCached;
- QColor headerCached;
- QColor bgCached;
- QColor iconCached;
- std::array<QColor, kMaxQuoteOutlines> outlines;
- QColor header;
- QColor bg;
- QColor icon;
- };
- void ValidateQuotePaintCache(
- QuotePaintCache &cache,
- const style::QuoteStyle &st);
- struct SkipBlockPaintParts {
- uint32 skippedTop : 29 = 0;
- uint32 skipBottom : 1 = 0;
- uint32 expandIcon : 1 = 0;
- uint32 collapseIcon : 1 = 0;
- };
- void FillQuotePaint(
- QPainter &p,
- QRect rect,
- const QuotePaintCache &cache,
- const style::QuoteStyle &st,
- SkipBlockPaintParts parts = {});
- struct HighlightInfoRequest {
- TextSelection range;
- QRect interpolateTo;
- float64 interpolateProgress = 0.;
- QPainterPath *outPath = nullptr;
- };
- struct PaintContext {
- QPoint position;
- int outerWidth = 0; // For automatic RTL Ui inversion.
- int availableWidth = 0;
- GeometryDescriptor geometry; // By default is SimpleGeometry.
- style::align align = style::al_left;
- QRect clip;
- const style::TextPalette *palette = nullptr;
- QuotePaintCache *pre = nullptr;
- QuotePaintCache *blockquote = nullptr;
- std::span<SpecialColor> colors;
- SpoilerMessCache *spoiler = nullptr;
- crl::time now = 0;
- bool paused = false;
- bool pausedEmoji = false;
- bool pausedSpoiler = false;
- bool fullWidthSelection = true;
- TextSelection selection;
- HighlightInfoRequest *highlight = nullptr;
- int elisionHeight = 0;
- int elisionLines = 0;
- int elisionRemoveFromEnd = 0;
- bool elisionBreakEverywhere = false;
- // Elision middle works only with elisionLines = 1 and is very limited.
- bool elisionMiddle = false;
- bool useFullWidth = false; // !(width = min(availableWidth, maxWidth()))
- };
- class String {
- public:
- String(int minResizeWidth = kQFixedMax);
- String(
- const style::TextStyle &st,
- const QString &text,
- const TextParseOptions &options = kDefaultTextOptions,
- int minResizeWidth = kQFixedMax);
- String(
- const style::TextStyle &st,
- const TextWithEntities &textWithEntities,
- const TextParseOptions &options = kMarkupTextOptions,
- int minResizeWidth = kQFixedMax,
- const MarkedContext &context = {});
- String(String &&other);
- String &operator=(String &&other);
- ~String();
- [[nodiscard]] int countWidth(
- int width,
- bool breakEverywhere = false) const;
- [[nodiscard]] int countHeight(
- int width,
- bool breakEverywhere = false) const;
- struct LineWidthsOptions {
- bool breakEverywhere = false;
- int reserve = 0;
- };
- [[nodiscard]] std::vector<int> countLineWidths(int width) const;
- [[nodiscard]] std::vector<int> countLineWidths(
- int width,
- LineWidthsOptions options) const;
- struct DimensionsResult {
- int width = 0;
- int height = 0;
- std::vector<int> lineWidths;
- };
- struct DimensionsRequest {
- bool breakEverywhere = false;
- bool lineWidths = false;
- int reserve = 0;
- };
- [[nodiscard]] DimensionsResult countDimensions(
- GeometryDescriptor geometry) const;
- [[nodiscard]] DimensionsResult countDimensions(
- GeometryDescriptor geometry,
- DimensionsRequest request) const;
- void setText(
- const style::TextStyle &st,
- const QString &text,
- const TextParseOptions &options = kDefaultTextOptions);
- void setMarkedText(
- const style::TextStyle &st,
- const TextWithEntities &textWithEntities,
- const TextParseOptions &options = kMarkupTextOptions,
- const MarkedContext &context = {});
- [[nodiscard]] bool hasLinks() const;
- void setLink(uint16 index, const ClickHandlerPtr &lnk);
- [[nodiscard]] bool hasSpoilers() const;
- void setSpoilerRevealed(bool revealed, anim::type animated);
- void setSpoilerLinkFilter(Fn<bool(const ClickContext&)> filter);
- [[nodiscard]] bool hasCollapsedBlockquots() const;
- [[nodiscard]] bool blockquoteCollapsed(int index) const;
- [[nodiscard]] bool blockquoteExpanded(int index) const;
- void setBlockquoteExpanded(int index, bool expanded);
- void setBlockquoteExpandCallback(
- Fn<void(int index, bool expanded)> callback);
- [[nodiscard]] bool hasSkipBlock() const;
- bool updateSkipBlock(int width, int height);
- bool removeSkipBlock();
- [[nodiscard]] int maxWidth() const {
- return _maxWidth;
- }
- [[nodiscard]] int minHeight() const {
- return _minHeight;
- }
- [[nodiscard]] int countMaxMonospaceWidth() const;
- void draw(QPainter &p, const PaintContext &context) const;
- [[nodiscard]] StateResult getState(
- QPoint point,
- GeometryDescriptor geometry,
- StateRequest request = StateRequest()) const;
- void draw(Painter &p, int32 left, int32 top, int32 width, style::align align = style::al_left, int32 yFrom = 0, int32 yTo = -1, TextSelection selection = { 0, 0 }, bool fullWidthSelection = true) const;
- void drawElided(Painter &p, int32 left, int32 top, int32 width, int32 lines = 1, style::align align = style::al_left, int32 yFrom = 0, int32 yTo = -1, int32 removeFromEnd = 0, bool breakEverywhere = false, TextSelection selection = { 0, 0 }) const;
- void drawLeft(Painter &p, int32 left, int32 top, int32 width, int32 outerw, style::align align = style::al_left, int32 yFrom = 0, int32 yTo = -1, TextSelection selection = { 0, 0 }) const;
- void drawLeftElided(Painter &p, int32 left, int32 top, int32 width, int32 outerw, int32 lines = 1, style::align align = style::al_left, int32 yFrom = 0, int32 yTo = -1, int32 removeFromEnd = 0, bool breakEverywhere = false, TextSelection selection = { 0, 0 }) const;
- void drawRight(Painter &p, int32 right, int32 top, int32 width, int32 outerw, style::align align = style::al_left, int32 yFrom = 0, int32 yTo = -1, TextSelection selection = { 0, 0 }) const;
- void drawRightElided(Painter &p, int32 right, int32 top, int32 width, int32 outerw, int32 lines = 1, style::align align = style::al_left, int32 yFrom = 0, int32 yTo = -1, int32 removeFromEnd = 0, bool breakEverywhere = false, TextSelection selection = { 0, 0 }) const;
- [[nodiscard]] StateResult getState(QPoint point, int width, StateRequest request = StateRequest()) const;
- [[nodiscard]] StateResult getStateLeft(QPoint point, int width, int outerw, StateRequest request = StateRequest()) const;
- [[nodiscard]] StateResult getStateElided(QPoint point, int width, StateRequestElided request = StateRequestElided()) const;
- [[nodiscard]] StateResult getStateElidedLeft(QPoint point, int width, int outerw, StateRequestElided request = StateRequestElided()) const;
- [[nodiscard]] TextSelection adjustSelection(TextSelection selection, TextSelectType selectType) const;
- [[nodiscard]] bool isFullSelection(TextSelection selection) const {
- return (selection.from == 0) && (selection.to >= _text.size());
- }
- [[nodiscard]] bool isEmpty() const;
- [[nodiscard]] bool isNull() const {
- return !_st;
- }
- [[nodiscard]] int length() const {
- return _text.size();
- }
- [[nodiscard]] QString toString(
- TextSelection selection = AllTextSelection) const;
- [[nodiscard]] TextWithEntities toTextWithEntities(
- TextSelection selection = AllTextSelection) const;
- [[nodiscard]] TextForMimeData toTextForMimeData(
- TextSelection selection = AllTextSelection) const;
- [[nodiscard]] bool hasPersistentAnimation() const;
- void unloadPersistentAnimation();
- [[nodiscard]] bool isIsolatedEmoji() const;
- [[nodiscard]] IsolatedEmoji toIsolatedEmoji() const;
- [[nodiscard]] bool isOnlyCustomEmoji() const;
- [[nodiscard]] OnlyCustomEmoji toOnlyCustomEmoji() const;
- [[nodiscard]] bool hasNotEmojiAndSpaces() const;
- [[nodiscard]] const std::vector<Modification> &modifications() const;
- [[nodiscard]] const style::TextStyle *style() const {
- return _st;
- }
- [[nodiscard]] int lineHeight() const;
- void clear();
- private:
- class ExtendedWrap : public std::unique_ptr<ExtendedData> {
- public:
- ExtendedWrap() noexcept;
- ExtendedWrap(ExtendedWrap &&other) noexcept;
- ExtendedWrap &operator=(ExtendedWrap &&other) noexcept;
- ~ExtendedWrap();
- ExtendedWrap(
- std::unique_ptr<ExtendedData> &&other) noexcept;
- ExtendedWrap &operator=(
- std::unique_ptr<ExtendedData> &&other) noexcept;
- private:
- void adjustFrom(const ExtendedWrap *other);
- };
- [[nodiscard]] not_null<ExtendedData*> ensureExtended();
- [[nodiscard]] not_null<QuotesData*> ensureQuotes();
- [[nodiscard]] uint16 blockPosition(
- std::vector<Block>::const_iterator i,
- int fullLengthOverride = -1) const;
- [[nodiscard]] uint16 blockEnd(
- std::vector<Block>::const_iterator i,
- int fullLengthOverride = -1) const;
- [[nodiscard]] uint16 blockLength(
- std::vector<Block>::const_iterator i,
- int fullLengthOverride = -1) const;
- [[nodiscard]] QuoteDetails *quoteByIndex(int index) const;
- [[nodiscard]] const style::QuoteStyle "eStyle(
- not_null<QuoteDetails*> quote) const;
- [[nodiscard]] QMargins quotePadding(QuoteDetails *quote) const;
- [[nodiscard]] int quoteMinWidth(QuoteDetails *quote) const;
- [[nodiscard]] const QString "eHeaderText(QuoteDetails *quote) const;
- // Returns -1 in case there is no limit.
- [[nodiscard]] int quoteLinesLimit(QuoteDetails *quote) const;
- // Block must be either nullptr or a pointer to a NewlineBlock.
- [[nodiscard]] int quoteIndex(const AbstractBlock *block) const;
- // Template method for originalText(), originalTextWithEntities().
- template <
- typename AppendPartCallback,
- typename ClickHandlerStartCallback,
- typename ClickHandlerFinishCallback,
- typename FlagsChangeCallback>
- void enumerateText(
- TextSelection selection,
- AppendPartCallback appendPartCallback,
- ClickHandlerStartCallback clickHandlerStartCallback,
- ClickHandlerFinishCallback clickHandlerFinishCallback,
- FlagsChangeCallback flagsChangeCallback) const;
- // Template method for countWidth(), countHeight(), countLineWidths().
- // callback(lineWidth, lineBottom) will be called for all lines with:
- // QFixed lineWidth, int lineBottom
- template <typename Callback>
- void enumerateLines(
- int w,
- bool breakEverywhere,
- Callback &&callback) const;
- template <typename Callback>
- void enumerateLines(
- GeometryDescriptor geometry,
- Callback &&callback) const;
- void insertModifications(int position, int delta);
- void removeModificationsAfter(int size);
- void recountNaturalSize(
- bool initial,
- Qt::LayoutDirection optionsDir = Qt::LayoutDirectionAuto);
- [[nodiscard]] TextForMimeData toText(
- TextSelection selection,
- bool composeExpanded,
- bool composeEntities) const;
- const style::TextStyle *_st = nullptr;
- QString _text;
- std::vector<Block> _blocks;
- std::vector<Word> _words;
- ExtendedWrap _extended;
- int _minResizeWidth = 0;
- int _maxWidth = 0;
- int _minHeight = 0;
- uint16 _startQuoteIndex = 0;
- bool _startParagraphLTR : 1 = false;
- bool _startParagraphRTL : 1 = false;
- bool _hasCustomEmoji : 1 = false;
- bool _isIsolatedEmoji : 1 = false;
- bool _isOnlyCustomEmoji : 1 = false;
- bool _hasNotEmojiAndSpaces : 1 = false;
- bool _skipBlockAddedNewline : 1 = false;
- bool _endsWithQuoteOrOtherDirection : 1 = false;
- friend class BlockParser;
- friend class WordParser;
- friend class Renderer;
- friend class BidiAlgorithm;
- friend class StackEngine;
- };
- [[nodiscard]] bool IsBad(QChar ch);
- [[nodiscard]] bool IsWordSeparator(QChar ch);
- [[nodiscard]] bool IsAlmostLinkEnd(QChar ch);
- [[nodiscard]] bool IsLinkEnd(QChar ch);
- [[nodiscard]] bool IsNewline(QChar ch);
- [[nodiscard]] bool IsSpace(QChar ch);
- [[nodiscard]] bool IsDiacritic(QChar ch);
- [[nodiscard]] bool IsReplacedBySpace(QChar ch);
- [[nodiscard]] bool IsTrimmed(QChar ch);
- } // namespace Ui::Text
- inline TextSelection snapSelection(int from, int to) {
- return { static_cast<uint16>(std::clamp(from, 0, 0xFFFF)), static_cast<uint16>(std::clamp(to, 0, 0xFFFF)) };
- }
- inline TextSelection shiftSelection(TextSelection selection, uint16 byLength) {
- return snapSelection(int(selection.from) + byLength, int(selection.to) + byLength);
- }
- inline TextSelection unshiftSelection(TextSelection selection, uint16 byLength) {
- return snapSelection(int(selection.from) - int(byLength), int(selection.to) - int(byLength));
- }
- inline TextSelection shiftSelection(TextSelection selection, const Ui::Text::String &byText) {
- return shiftSelection(selection, byText.length());
- }
- inline TextSelection unshiftSelection(TextSelection selection, const Ui::Text::String &byText) {
- return unshiftSelection(selection, byText.length());
- }
|