lxgui
Loading...
Searching...
No Matches
gui_font_string.cpp
1#include "lxgui/gui_font_string.hpp"
2
3#include "lxgui/gui_layered_region.hpp"
4#include "lxgui/gui_localizer.hpp"
5#include "lxgui/gui_manager.hpp"
6#include "lxgui/gui_out.hpp"
7#include "lxgui/gui_region_tpl.hpp"
8#include "lxgui/gui_renderer.hpp"
9
10#include <sstream>
11
12namespace lxgui::gui {
13
15 utils::control_block& block, manager& mgr, const region_core_attributes& attr) :
16 layered_region(block, mgr, attr) {
17
18 initialize_(*this, attr);
19
20 // Render font_string above other regions
21 region_level_ = 1;
22}
23
24void font_string::render() const {
26
27 if (!text_ || !is_valid_ || !is_visible())
28 return;
29
30 text_->set_use_vertex_cache(is_vertex_cache_used_());
31
32 vector2f pos;
33
34 if (std::isinf(text_->get_box_width())) {
35 switch (align_x_) {
36 case alignment_x::left: pos.x = borders_.left; break;
37 case alignment_x::center: pos.x = (borders_.left + borders_.right) / 2; break;
38 case alignment_x::right: pos.x = borders_.right; break;
39 }
40 } else {
41 pos.x = borders_.left;
42 }
43
44 if (std::isinf(text_->get_box_height())) {
45 switch (align_y_) {
46 case alignment_y::top: pos.y = borders_.top; break;
47 case alignment_y::middle: pos.y = (borders_.top + borders_.bottom) / 2; break;
48 case alignment_y::bottom: pos.y = borders_.bottom; break;
49 }
50 } else {
51 pos.y = borders_.top;
52 }
53
54 pos += offset_;
55
56 text_->set_alpha(get_effective_alpha());
57
58 if (is_shadow_enabled_) {
59 text_->set_color(shadow_color_, true);
60 text_->render(matrix4f::translation(round_to_pixel(pos + shadow_offset_)));
61 }
62
63 text_->set_color(text_color_);
64 text_->render(matrix4f::translation(round_to_pixel(pos)));
65}
66
67std::string font_string::serialize(const std::string& tab) const {
68 std::ostringstream str;
69
70 str << base::serialize(tab);
71
72 str << tab << " # Font name : " << font_name_ << "\n";
73 str << tab << " # Font height: " << height_ << "\n";
74 str << tab << " # Text ready : " << (text_ != nullptr) << "\n";
75 str << tab << " # Text : \"" << utils::unicode_to_utf8(content_) << "\"\n";
76 str << tab << " # Outlined : " << is_outlined_ << "\n";
77 str << tab << " # Text color : " << text_color_ << "\n";
78 str << tab << " # Spacing : " << spacing_ << "\n";
79 str << tab << " # Justify :\n";
80 str << tab << " #-###\n";
81 str << tab << " | # horizontal: " << utils::to_string(align_x_) << "\n";
82 str << tab << " | # vertical : " << utils::to_string(align_y_) << "\n";
83 str << tab << " #-###\n";
84 str << tab << " # NonSpaceW. : " << non_space_wrap_enabled_ << "\n";
85 if (is_shadow_enabled_) {
86 str << tab << " # Shadow off.: (" << shadow_offset_.x << ", " << shadow_offset_.y << ")\n";
87 str << tab << " # Shadow col.: " << shadow_color_ << "\n";
88 }
89
90 return str.str();
91}
92
94 base::copy_from(obj);
95
96 const font_string* fstr_obj = down_cast<font_string>(&obj);
97 if (!fstr_obj)
98 return;
99
100 std::string font_name = fstr_obj->get_font_name();
101 float height = fstr_obj->get_font_height();
102 if (!font_name.empty() && height != 0)
103 this->set_font(font_name, height);
104
105 this->set_alignment_x(fstr_obj->get_alignment_x());
106 this->set_alignment_y(fstr_obj->get_alignment_y());
107 this->set_spacing(fstr_obj->get_spacing());
108 this->set_line_spacing(fstr_obj->get_line_spacing());
109 this->set_text(fstr_obj->get_text());
110 this->set_outlined(fstr_obj->is_outlined());
111 if (fstr_obj->is_shadow_enabled()) {
112 this->set_shadow_enabled(true);
113 this->set_shadow_color(fstr_obj->get_shadow_color());
114 this->set_shadow_offset(fstr_obj->get_shadow_offset());
115 }
116 this->set_text_color(fstr_obj->get_text_color());
118}
119
120const std::string& font_string::get_font_name() const {
121 return font_name_;
122}
123
125 return height_;
126}
127
128void font_string::set_outlined(bool is_outlined) {
129 if (is_outlined_ == is_outlined)
130 return;
131
132 is_outlined_ = is_outlined;
133
134 if (!is_virtual_) {
135 create_text_object_();
136
138 }
139}
140
142 return is_outlined_;
143}
144
146 return align_x_;
147}
148
150 return align_y_;
151}
152
154 return shadow_color_;
155}
156
158 return shadow_offset_;
159}
160
162 return offset_;
163}
164
166 return spacing_;
167}
168
170 return line_spacing_;
171}
172
174 return text_color_;
175}
176
179
180 if (text_)
181 set_font(font_name_, height_);
182}
183
184void font_string::create_text_object_() {
185 if (font_name_.empty())
186 return;
187
188 std::size_t pixel_height = static_cast<std::size_t>(
189 std::round(get_manager().get_interface_scaling_factor() * height_));
190
192 const auto& localizer = get_manager().get_localizer();
193
194 const auto& code_points = localizer.get_allowed_code_points();
195 const char32_t default_code_point = localizer.get_fallback_code_point();
196
197 std::shared_ptr<gui::font> outline_font;
198 if (is_outlined_) {
199 outline_font = renderer.create_atlas_font(
200 "GUI", font_name_, pixel_height,
201 std::min<std::size_t>(2u, static_cast<std::size_t>(std::round(0.2 * pixel_height))),
202 code_points, default_code_point);
203 }
204
205 auto fnt = renderer.create_atlas_font(
206 "GUI", font_name_, pixel_height, 0u, code_points, default_code_point);
207
208 text_ = std::unique_ptr<text>(new text(renderer, fnt, outline_font));
209
210 text_->set_scaling_factor(1.0f / get_manager().get_interface_scaling_factor());
211 text_->set_remove_starting_spaces(true);
212 text_->set_text(content_);
213 text_->set_alignment_x(align_x_);
214 text_->set_alignment_y(align_y_);
215 text_->set_tracking(spacing_);
216 text_->set_word_wrap_enabled(word_wrap_enabled_);
217 text_->set_word_ellipsis_enabled(ellipsis_enabled_);
218 text_->set_formatting_enabled(formatting_enabled_);
219}
220
221void font_string::set_font(const std::string& font_name, float height) {
222 font_name_ = parse_file_name(font_name);
223 height_ = height;
224
225 create_text_object_();
226
227 if (!is_virtual_) {
230 }
231}
232
234 if (align_x_ == justify_h)
235 return;
236
237 align_x_ = justify_h;
238 if (text_) {
239 text_->set_alignment_x(align_x_);
240
241 if (!is_virtual_)
243 }
244}
245
247 if (align_y_ == justify_v)
248 return;
249
250 align_y_ = justify_v;
251 if (text_) {
252 text_->set_alignment_y(align_y_);
253
254 if (!is_virtual_)
256 }
257}
258
259void font_string::set_shadow_color(const color& shadow_color) {
260 if (shadow_color_ == shadow_color)
261 return;
262
263 shadow_color_ = shadow_color;
264 if (is_shadow_enabled_ && !is_virtual_)
266}
267
268void font_string::set_shadow_offset(const vector2f& shadow_offset) {
269 if (shadow_offset_ == shadow_offset)
270 return;
271
272 shadow_offset_ = shadow_offset;
273 if (is_shadow_enabled_ && !is_virtual_)
275}
276
278 if (offset_ == offset)
279 return;
280
281 offset_ = offset;
282 if (!is_virtual_)
284}
285
286void font_string::set_spacing(float spacing) {
287 if (spacing_ == spacing)
288 return;
289
290 spacing_ = spacing;
291 if (text_) {
292 text_->set_tracking(spacing_);
293 if (!is_virtual_)
295 }
296}
297
298void font_string::set_line_spacing(float line_spacing) {
299 if (line_spacing_ == line_spacing)
300 return;
301
302 line_spacing_ = line_spacing;
303 if (text_) {
304 text_->set_line_spacing(line_spacing_);
305 if (!is_virtual_)
307 }
308}
309
310void font_string::set_text_color(const color& text_color) {
311 if (text_color_ == text_color)
312 return;
313
314 text_color_ = text_color;
315 if (!is_virtual_)
317}
318
320 return non_space_wrap_enabled_;
321}
322
324 if (text_)
325 return text_->get_text_height();
326 else
327 return 0.0f;
328}
329
331 if (text_)
332 return text_->get_text_width();
333 else
334 return 0.0f;
335}
336
337float font_string::get_string_width(const utils::ustring& content) const {
338 if (text_)
339 return text_->get_string_width(content);
340 else
341 return 0.0f;
342}
343
344const utils::ustring& font_string::get_text() const {
345 return content_;
346}
347
348void font_string::set_non_space_wrap_enabled(bool is_non_space_wrap_enabled) {
349 if (non_space_wrap_enabled_ == is_non_space_wrap_enabled)
350 return;
351
352 non_space_wrap_enabled_ = is_non_space_wrap_enabled;
353
354 if (!is_virtual_)
356}
357
359 return is_shadow_enabled_;
360}
361
362void font_string::set_shadow_enabled(bool is_shadow_enabled) {
363 if (is_shadow_enabled_ == is_shadow_enabled)
364 return;
365
366 is_shadow_enabled_ = is_shadow_enabled;
367
368 if (!is_virtual_)
370}
371
373 if (word_wrap_enabled_ == enabled)
374 return;
375
376 word_wrap_enabled_ = enabled;
377
378 if (text_) {
379 text_->set_word_wrap_enabled(word_wrap_enabled_);
380 if (!is_virtual_)
382 }
383}
384
386 return word_wrap_enabled_;
387}
388
390 if (ellipsis_enabled_ == enabled)
391 return;
392
393 ellipsis_enabled_ = enabled;
394
395 if (text_) {
396 text_->set_word_ellipsis_enabled(ellipsis_enabled_);
397 if (!is_virtual_)
399 }
400}
401
403 return ellipsis_enabled_;
404}
405
407 if (formatting_enabled_ == formatting)
408 return;
409
410 formatting_enabled_ = formatting;
411
412 if (text_) {
413 text_->set_formatting_enabled(formatting_enabled_);
414 if (!is_virtual_)
416 }
417}
418
420 return formatting_enabled_;
421}
422
423void font_string::set_text(const utils::ustring& content) {
424 if (content_ == content)
425 return;
426
427 content_ = content;
428
429 if (text_) {
430 text_->set_text(content_);
431 if (!is_virtual_) {
434 }
435 }
436}
437
438bool font_string::is_vertex_cache_used_() const {
440 switch (vertex_cache_strategy_) {
446 default: return false;
447 }
448}
449
451 vertex_cache_strategy_ = strategy;
452}
453
455 return vertex_cache_strategy_;
456}
457
459 return text_.get();
460}
461
463 return text_.get();
464}
465
466void font_string::update_borders_() {
467 if (!text_)
468 return base::update_borders_();
469
470//#define DEBUG_LOG(msg) gui::out << (msg) << std::endl
471#define DEBUG_LOG(msg)
472
473 const bool old_valid = is_valid_;
474 const auto old_border_list = borders_;
475 is_valid_ = true;
476
477 if (!anchor_list_.empty()) {
478 float left = 0.0f, right = 0.0f, top = 0.0f, bottom = 0.0f;
479 float x_center = 0.0f, y_center = 0.0f;
480
481 DEBUG_LOG(" Read anchors");
482 read_anchors_(left, right, top, bottom, x_center, y_center);
483
484 float box_width = std::numeric_limits<float>::infinity();
485 if (get_dimensions().x != 0.0f)
486 box_width = get_dimensions().x;
488 box_width = right - left;
489
490 float box_height = std::numeric_limits<float>::infinity();
491 if (get_dimensions().y != 0.0f)
492 box_height = get_dimensions().y;
494 box_height = bottom - top;
495
498
499 text_->set_box_dimensions(box_width, box_height);
500
501 DEBUG_LOG(" Make borders");
502 if (std::isinf(box_height))
503 box_height = text_->get_height();
504 if (std::isinf(box_width))
505 box_width = text_->get_width();
506
507 if (!make_borders_(top, bottom, y_center, box_height)) {
508 is_valid_ = false;
509 }
510
511 if (!make_borders_(left, right, x_center, box_width)) {
512 is_valid_ = false;
513 }
514
515 if (is_valid_) {
516 if (right < left) {
517 right = left + 1.0f;
518 }
519 if (bottom < top) {
520 bottom = top + 1.0f;
521 }
522
525 borders_.top = top;
527 } else {
529 }
530 } else {
531 float box_width = get_dimensions().x;
532 if (box_width == 0.0) {
533 box_width = text_->get_width();
534 }
535
536 float box_height = get_dimensions().y;
537 if (box_height == 0.0) {
538 box_height = text_->get_height();
539 }
540
541 borders_ = bounds2f(0.0, 0.0, box_width, box_height);
542 is_valid_ = false;
543 }
544
549
550 if (borders_ != old_border_list || is_valid_ != old_valid) {
551 DEBUG_LOG(" Fire redraw");
553 }
554 DEBUG_LOG(" @");
555}
556
557const std::vector<std::string>& font_string::get_type_list_() const {
558 return get_type_list_impl_<font_string>();
559}
560
561} // namespace lxgui::gui
Holds a single color (float RGBA, 128 bits)
Definition gui_color.hpp:13
A layered_region that can draw text on the screen.
const color & get_text_color() const
Returns the text color.
void set_word_wrap_enabled(bool enabled)
Enables/disables word wrap.
void set_non_space_wrap_enabled(bool enabled)
Sets whether large text without whitespace is truncated or wrapped.
const std::string & get_font_name() const
Returns the name of the font file.
const vector2f & get_offset() const
Returns this font_string's offset.
void set_formatting_enabled(bool enabled)
Enables color formatting.
const color & get_shadow_color() const
Returns this font_string's shadow color.
float get_string_width() const
Returns the width of the string if no format or wrapping is applied.
bool is_word_ellipsis_enabled() const
Checks if word ellipsis is enabled.
void set_shadow_color(const color &shadow_color)
Sets this font_string's shadow color.
void copy_from(const region &obj) override
Copies a region's parameters into this font_string (inheritance).
bool is_non_space_wrap_enabled() const
Checks if large text is truncated or wrapped.
float get_string_height() const
Returns the height of the string if no format or wrapping is applied.
const vector2f & get_shadow_offset() const
Returns this font_string's shadow offset.
void set_line_spacing(float line_spacing)
Sets the space between each line as a fraction of the font height.
std::string serialize(const std::string &tab) const override
Prints all relevant information about this region in a string.
void set_alignment_x(alignment_x align_x)
Sets this font_string's horizontal alignment behavior.
bool is_formatting_enabled() const
Checks if color formatting is enabled.
float get_font_height() const
Returns the height of the font.
void render() const override
Renders this region on the current render target.
void set_vertex_cache_strategy(vertex_cache_strategy strategy)
Selects the strategy for using vertex caches.
void set_alignment_y(alignment_y align_y)
Sets this font_string's vertical alignment behavior.
void notify_scaling_factor_updated() override
Tells this region that the global interface scaling factor has changed.
text * get_text_object()
Returns the text used to render this font_string.
void set_offset(const vector2f &offset)
Sets this font_string's offset.
void set_outlined(bool outlined)
Adds or remove the outline around the text.
void set_shadow_offset(const vector2f &shadow_offset)
Sets this font_string's shadow offset.
bool is_outlined() const
Check if this font_string is outlined.
void set_text(const utils::ustring &content)
Sets the rendered text.
float get_line_spacing() const
Returns the space between each line as a fraction of the font height.
bool is_word_wrap_enabled() const
Checks if word wrap is enabled.
font_string(utils::control_block &block, manager &mgr, const region_core_attributes &attr)
Constructor.
void set_text_color(const color &text_color)
Sets the text color.
alignment_y get_alignment_y() const
Returns the vertical alignment behavior.
void set_shadow_enabled(bool enabled)
Sets whether this font_string should draw a shadow under its text.
vertex_cache_strategy get_vertex_cache_strategy() const
Gets the strategy for using vertex caches.
bool is_shadow_enabled() const
Checks if this font_string draws a shadow under its text.
void set_word_ellipsis_enabled(bool enabled)
Sets whether to show an ellipsis "..." if words don't fit in the text box.
float get_spacing() const
Returns the space between each letter.
void set_font(const std::string &font_name, float height)
Sets this font_string's font (file and size).
const utils::ustring & get_text() const
Returns the rendered text (with format tags).
void set_spacing(float spacing)
Sets the space between each letter.
alignment_x get_alignment_x() const
Returns the horizontal alignment behavior.
A region that can be rendered in a layer.
void notify_renderer_need_redraw() override
Notifies the renderer of this region that it needs to be redrawn.
std::string serialize(const std::string &tab) const override
Prints all relevant information about this region in a string.
Utility class to translate strings for display in GUI.
char32_t get_fallback_code_point() const
Returns the default character to display if a character is missing from a font.
const std::vector< code_point_range > & get_allowed_code_points() const
Returns the list of allowed code points (Unicode characters), for text rendering.
Manages the user interface.
const renderer & get_renderer() const
Returns the renderer implementation.
localizer & get_localizer()
Returns the object used for localizing strings.
The base class of all elements in the GUI.
manager & get_manager()
Returns this region's manager.
void initialize_(T &self, const region_core_attributes &attr)
Set up function to call in all derived class constructors.
float get_effective_alpha() const
Returns this region's effective alpha (opacity).
bool is_visible() const
Checks if this region can be seen on the screen.
float round_to_pixel(float value, utils::rounding_method method=utils::rounding_method::nearest) const
Round an absolute position on screen to the nearest physical pixel.
void read_anchors_(float &left, float &right, float &top, float &bottom, float &x_center, float &y_center) const
virtual void render() const
Renders this region on the current render target.
const vector2f & get_dimensions() const
Returns this region's explicitly-defined width and height (in pixels).
std::array< std::optional< anchor >, 9 > anchor_list_
virtual void notify_borders_need_update()
Tells this region that its borders need updating.
bounds2< bool > defined_borders_
bool make_borders_(float &min, float &max, float center, float size) const
virtual void copy_from(const region &obj)
Copies a region's parameters into this region (inheritance).
std::string parse_file_name(const std::string &file_name) const
Convert an addon-relative file path to a application-relative path.
virtual void notify_scaling_factor_updated()
Tells this region that the global interface scaling factor has changed.
virtual void update_borders_()
Abstract type for implementation specific management.
bool is_quad_batching_enabled() const
Checks if the renderer has quad render batching enabled.
std::shared_ptr< font > create_atlas_font(const std::string &atlas_category, const std::string &font_file, std::size_t size, std::size_t outline, const std::vector< code_point_range > &code_points, char32_t default_code_point)
Creates a new font.
bool is_vertex_cache_enabled() const
Checks if the renderer has enabled support for vertex caches.
Used to draw some text on the screen.
Definition gui_text.hpp:29
bounds2< float > bounds2f
Holds 2D bounds of a region (as floats).
vertex_cache_strategy
Strategy for using a vertex cache.
@ prefer_enabled
Use vertex cache if renderer supports and allows.
@ automatic
Choose automatically to maximize performance on common case.
@ always_disabled
Never use vertex cache.
@ always_enabled
Use vertex cache if renderer supports, even if not allowed.
@ nearest_not_zero
Equivalent to round() but only returns 0 if input is exactly 0.
static const bounds2 zero
static matrix4f translation(const vector2f &dx) noexcept
Struct holding all the core information about a region necessary for its creation.