File: FormattedTextBlock.h

package info (click to toggle)
jazz2-native 3.5.0-1
  • links: PTS, VCS
  • area: contrib
  • in suites:
  • size: 16,836 kB
  • sloc: cpp: 172,557; xml: 113; python: 36; makefile: 5; sh: 2
file content (177 lines) | stat: -rw-r--r-- 4,824 bytes parent folder | download | duplicates (3)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
#pragma once

#include "Canvas.h"
#include "Font.h"
#include "../../nCine/Primitives/Rect.h"
#include "../../nCine/Primitives/Vector2.h"

#include <Containers/SmallVector.h>
#include <Containers/String.h>
#include <Containers/StringView.h>

using namespace Death::Containers;
using namespace nCine;

namespace Jazz2::UI
{
	/** @brief Initialization parameters for formatted text block */
	struct FormattedTextBlockParams
	{
		StringView Text;
		Font* TextFont = nullptr;
		Alignment Align = Alignment::Left;
		Colorf Color = Font::DefaultColor;
		float Scale = 1.0f;
		float CharSpacing = 1.0f;
		float LineSpacing = 1.0f;
	};

	/** @brief Formatted text block */
	class FormattedTextBlock
	{
	public:
		FormattedTextBlock();
		FormattedTextBlock(const FormattedTextBlockParams& params);

		FormattedTextBlock(const FormattedTextBlock&) = delete;
		FormattedTextBlock(FormattedTextBlock&& other) noexcept;
		FormattedTextBlock& operator=(const FormattedTextBlock&) = delete;
		FormattedTextBlock& operator=(FormattedTextBlock&& other) noexcept;

		static FormattedTextBlock From(const FormattedTextBlock& source);

		void Draw(Canvas* canvas, Rectf bounds, std::uint16_t depth, std::int32_t& charOffset, float angleOffset = 0.0f, float varianceX = 4.0f, float varianceY = 4.0f, float speed = 0.4f);
		Vector2f MeasureSize(Vector2f proposedSize);
		float GetCachedWidth() const;
		float GetCachedHeight() const;

		Alignment GetAlignment() const {
			return _alignment;
		}

		void SetAlignment(Alignment value);

		Colorf GetDefaultColor() const {
			return _defaultColor;
		}

		void SetDefaultColor(Colorf color);

		Font* GetFont() {
			return _font;
		}

		void SetFont(Font* value);

		float GetScale() const {
			return _defaultScale;
		}

		void SetScale(float value);

		float GetCharSpacing() const {
			return _defaultCharSpacing;
		}

		void SetCharSpacing(float value);

		float GetLineSpacing() const {
			return _defaultLineSpacing;
		}

		void SetLineSpacing(float value);

		constexpr float GetProposedWidth() const {
			return _proposedWidth;
		}

		void SetProposedWidth(float value);

		StringView GetText() const {
			return _text;
		}

		void SetText(StringView value);
		void SetText(String&& value);

		constexpr bool IsMultiline() const {
			return (_flags & FormattedTextBlockFlags::Multiline) == FormattedTextBlockFlags::Multiline;
		}
		void SetMultiline(bool value);

		constexpr bool GetWrapping() const {
			return (_flags & FormattedTextBlockFlags::Wrapping) == FormattedTextBlockFlags::Wrapping;
		}
		void SetWrapping(bool value);

		constexpr bool IsEllipsized() const {
			return (_flags & FormattedTextBlockFlags::Ellipsized) == FormattedTextBlockFlags::Ellipsized;
		}

	private:
		static constexpr std::uint32_t Ellipsis = UINT32_MAX;

#ifndef DOXYGEN_GENERATING_OUTPUT
		// Doxygen 1.12.0 outputs also private structs/unions even if it shouldn't
		struct Part
		{
			std::uint32_t Begin;
			std::uint32_t Length;
			Vector2f Location;
			float Height;
			Colorf CurrentColor;
			float Scale;
			float CharSpacing;
			bool AllowVariance;

			Part(std::uint32_t begin, std::uint32_t length, Vector2f location, float height, Colorf color, float scale, float charSpacing, bool allowVariance) noexcept;
			
			Part(const Part& other) noexcept;
			Part(Part&& other) noexcept;
			Part& operator=(const Part& other) noexcept;
			Part& operator=(Part&& other) noexcept;
		};

		struct BackgroundPart
		{
			Rectf Bounds;
			Colorf CurrentColor;

			BackgroundPart(Colorf color);
		};
#endif

		enum class FormattedTextBlockFlags : std::uint16_t {
			None = 0,
			Multiline = 0x01,
			Wrapping = 0x02,

			Ellipsized = 0x10
		};

		DEATH_PRIVATE_ENUM_FLAGS(FormattedTextBlockFlags);

		SmallVector<Part, 1> _parts;
		SmallVector<BackgroundPart, 0> _background;
		Font* _font;
		String _text;
		FormattedTextBlockFlags _flags;
		float _proposedWidth;
		float _cachedWidth;
		Colorf _defaultColor;
		float _defaultScale;
		float _defaultCharSpacing;
		float _defaultLineSpacing;
		Alignment _alignment;

		void RecreateCache();
		void HandleEndOfLine(Vector2f currentLocation, std::int32_t& lineBeginIndex, std::int32_t& lineAlignIndex, std::int32_t& backgroundIndex);
		void InsertEllipsis(Vector2f& currentLocation, Colorf currentColor, float scale, float charSpacing, float lineSpacing, bool allowVariance, float maxWidth, float* charFitWidths);
		void InsertDottedUnderline(Part& part, float width);

		static float PerformVerticalAlignment(SmallVectorImpl<Part>& processedParts, std::int32_t firstPartOfLine);
		static void FinalizeBackgroundPart(Vector2f currentLocation, SmallVectorImpl<Part>& parts, SmallVectorImpl<BackgroundPart>& backgroundParts);
		static char* FindFirstControlSequence(char* string, std::int32_t length);
		static Colorf Uint32ToColorf(std::uint32_t value);
	};
}