TinyGPU
Loading...
Searching...
No Matches
LinePrinter.h
Go to the documentation of this file.
1#pragma once
2
3#include <string>
4
5#include "IFont.h"
6#include "ISurface.h"
7
8namespace tinygpu {
9
10/**
11 * @brief Helper for printing wrapped lines of text onto a TinyGPU target.
12 *
13 * The printer tracks a cursor position, applies configurable borders, and
14 * wraps words to the next line when text would exceed the drawable width.
15 */
16template <typename RGB_T = RGB565>
18 public:
19 LinePrinter() = default;
20 /// Creates a line printer for the given font and target.
21 LinePrinter(IFont<RGB_T>& font, ISurface<RGB_T>& target) : font_(&font), target_(&target) {
22 currentX_ = leftBorder_;
23 currentY_ = topBorder_;
24 }
25
26 void setColor(RGB_T color) { foregroundColor_ = color; }
27 void setBackgroundColor(RGB_T color) { backgroundColor_ = color; }
28
29 /// Sets the Font implementation.
30 void setFont(IFont<RGB_T>& font) { font_ = &font; }
31 /// Sets the TinyGPU target.
32 void setTarget(ISurface<RGB_T>& target) { target_ = &target; }
33
34 /// Sets the top border in pixels.
35 void setTopBorder(size_t border) { topBorder_ = border; }
36 /// Sets the left border in pixels.
37 void setLeftBorder(size_t border) { leftBorder_ = border; }
38 /// Sets the right border in pixels.
39 void setRightBorder(size_t border) { rightBorder_ = border; }
40 /// Sets the bottom border in pixels.
41 void setButtomBorder(size_t border) { buttomBorder_ = border; }
42 /// Sets all borders to the same value.
43 void setBorders(size_t border) {
44 setTopBorder(border);
45 setLeftBorder(border);
46 setRightBorder(border);
47 setButtomBorder(border);
48 }
49
50 /// Sets the current line index.
51 void setActualLine(size_t line) {
52 currentLine_ = line;
53 currentX_ = leftBorder_;
54 currentY_ = topBorder_ + (line * lineAdvance());
55 }
56
57 /// Sets the text scale factor.
58 void setScale(uint8_t scale) { this->scale = scale; }
59
60 /// Sets the spacing between glyphs.
61 void setSpacing(uint8_t spacing) { this->spacing = spacing; }
62
63 /// Prints text with word wrapping.
64 size_t print(const char* text) {
65 if (text == nullptr || *text == '\0') {
66 return 0;
67 }
68
69 ensureCursorInitialized();
70
71 std::string word;
72 size_t pendingSpaces = 0;
73 size_t printedLength = 0;
74
75 for (const char* current = text; *current != '\0'; ++current) {
76 if (*current == '\n') {
77 printWord(word, pendingSpaces);
78 pendingSpaces = 0;
79 nextLine();
80 ++printedLength;
81 continue;
82 }
83
84 if (*current == ' ') {
85 printWord(word, pendingSpaces);
86 ++pendingSpaces;
87 ++printedLength;
88 continue;
89 }
90
91 if (*current == '\t') {
92 printWord(word, pendingSpaces);
93 pendingSpaces += 4;
94 ++printedLength;
95 continue;
96 }
97
98 word.push_back(*current);
99 ++printedLength;
100 }
101
102 printWord(word, pendingSpaces);
103 flushPendingSpaces(pendingSpaces);
104 return printedLength;
105 }
106
107 /// Prints text and advances to the next line.
108 size_t println(const char* text) {
109 const size_t printedLength = print(text);
110 nextLine();
111 return printedLength;
112 }
113
114 /// Advances to the next line.
116 nextLine();
117 return 0;
118 }
119
120private:
121 IFont<RGB_T>* font_ = nullptr;
122 RGB_T backgroundColor_ = RGB_T();
123#if __cplusplus >= 201703L
124 // C++17 if constexpr for type-specific initialization
125 RGB_T foregroundColor_ = []{
126 if constexpr (std::is_same<RGB_T, bool>::value) return true;
127 else return RGB_T(255, 255, 255);
128 }();
129#else
130 RGB_T foregroundColor_ = std::is_same<RGB_T, bool>::value ? true : RGB_T(255, 255, 255);
131#endif
132 ISurface<RGB_T>* target_ = nullptr;
133 size_t topBorder_ = 20;
134 size_t leftBorder_ = 20;
135 size_t rightBorder_ = 20;
136 size_t buttomBorder_ = 20;
137 size_t currentLine_ = 0;
138 size_t currentY_ = 0;
139 size_t currentX_ = 0;
140 uint8_t scale = 1;
141 uint8_t spacing = 1;
142
143 void ensureCursorInitialized() {
144 if (currentX_ == 0 && currentY_ == 0) {
145 currentX_ = leftBorder_;
146 currentY_ = topBorder_;
147 }
148 }
149
150 size_t drawableRightEdge() const {
151 if (target_ == nullptr) {
152 return 0;
153 }
154 const size_t targetWidth = target_->width();
155 return targetWidth > rightBorder_ ? targetWidth - rightBorder_ : 0;
156 }
157
158 bool isAtLineStart() const { return currentX_ <= leftBorder_; }
159
160 size_t lineAdvance() const {
161 return font_->measureTextHeight("A", scale, 0) + spacing;
162 }
163
164 void nextLine() {
165 currentX_ = leftBorder_;
166 currentY_ += lineAdvance();
167 ++currentLine_;
168 }
169
170 void printChunk(const std::string& chunk) {
171 if (chunk.empty()) {
172 return;
173 }
174
175 target_->drawText(static_cast<int16_t>(currentX_),
176 static_cast<int16_t>(currentY_), chunk.c_str(),
177 foregroundColor_, backgroundColor_, false, scale,
178 spacing);
179 currentX_ += font_->measureTextWidth(chunk.c_str(), scale, spacing);
180 }
181
182 size_t pendingSpaceWidth(size_t pendingSpaces) const {
183 if (pendingSpaces == 0) {
184 return 0;
185 }
186
187 const std::string spaces(pendingSpaces, ' ');
188 return font_->measureTextWidth(spaces.c_str(), scale, spacing);
189 }
190
191 void flushPendingSpaces(size_t& pendingSpaces) {
192 if (pendingSpaces == 0 || isAtLineStart()) {
193 pendingSpaces = 0;
194 return;
195 }
196
197 const size_t spacesWidth = pendingSpaceWidth(pendingSpaces);
198 if ((currentX_ + spacesWidth) > drawableRightEdge()) {
199 nextLine();
200 pendingSpaces = 0;
201 return;
202 }
203
204 printChunk(std::string(pendingSpaces, ' '));
205 pendingSpaces = 0;
206 }
207
208 void printWord(std::string& word, size_t& pendingSpaces) {
209 if (word.empty()) {
210 return;
211 }
212
213 const std::string leadingSpaces =
214 isAtLineStart() ? std::string() : std::string(pendingSpaces, ' ');
215 const std::string chunk = leadingSpaces + word;
216 const size_t chunkWidth =
217 font_->measureTextWidth(chunk.c_str(), scale, spacing);
218
219 if (!isAtLineStart() && (currentX_ + chunkWidth) > drawableRightEdge()) {
220 nextLine();
221 }
222
223 if (!isAtLineStart() && pendingSpaces > 0) {
224 printChunk(leadingSpaces);
225 }
226
227 printChunk(word);
228 pendingSpaces = 0;
229 word.clear();
230 }
231};
232
233} // namespace tinygpu
Font rendering interface for TinyGPU-compatible framebuffers.
Definition: IFont.h:19
Helper for printing wrapped lines of text onto a TinyGPU target.
Definition: LinePrinter.h:17
void setBackgroundColor(RGB_T color)
Definition: LinePrinter.h:27
size_t println()
Advances to the next line.
Definition: LinePrinter.h:115
void setBorders(size_t border)
Sets all borders to the same value.
Definition: LinePrinter.h:43
void setScale(uint8_t scale)
Sets the text scale factor.
Definition: LinePrinter.h:58
void setTopBorder(size_t border)
Sets the top border in pixels.
Definition: LinePrinter.h:35
void setLeftBorder(size_t border)
Sets the left border in pixels.
Definition: LinePrinter.h:37
size_t print(const char *text)
Prints text with word wrapping.
Definition: LinePrinter.h:64
void setFont(IFont< RGB_T > &font)
Sets the Font implementation.
Definition: LinePrinter.h:30
void setSpacing(uint8_t spacing)
Sets the spacing between glyphs.
Definition: LinePrinter.h:61
void setTarget(ISurface< RGB_T > &target)
Sets the TinyGPU target.
Definition: LinePrinter.h:32
void setRightBorder(size_t border)
Sets the right border in pixels.
Definition: LinePrinter.h:39
void setActualLine(size_t line)
Sets the current line index.
Definition: LinePrinter.h:51
void setColor(RGB_T color)
Definition: LinePrinter.h:26
LinePrinter(IFont< RGB_T > &font, ISurface< RGB_T > &target)
Creates a line printer for the given font and target.
Definition: LinePrinter.h:21
size_t println(const char *text)
Prints text and advances to the next line.
Definition: LinePrinter.h:108
void setButtomBorder(size_t border)
Sets the bottom border in pixels.
Definition: LinePrinter.h:41
RGB color stored in 16-bit RGB565 format.
Definition: RGB565.h:13
Definition: AVIWriter.h:9