1 /*!
2  * \file
3  * \ingroup text_font
4  * \brief Classes and functions for rendering text in different fonts
5  */
6 
7 #ifndef NEW_FONT_H
8 #define NEW_FONT_H
9 
10 #define DEFAULT_FIXED_FONT_WIDTH  11
11 #define DEFAULT_FIXED_FONT_HEIGHT 18
12 #define SMALL_FIXED_FONT_WIDTH    8
13 #define SMALL_FIXED_FONT_HEIGHT   15
14 // This value of DEFAULT_SMALL_RATIO is a compromise between 8/11 = 0.7272 and 16/19=0.8421,
15 // which are the ratios of the widths and heights respectively between small and normal characters
16 // in the fixed font in earlier font handling.
17 #define DEFAULT_SMALL_RATIO       0.785f
18 
19 #define INGAME_FONT_X_LEN       0.17f
20 #define SMALL_INGAME_FONT_X_LEN 0.12f
21 #define SMALL_INGAME_FONT_Y_LEN 0.17f
22 #define ALT_INGAME_FONT_X_LEN   0.10f
23 #define ALT_INGAME_FONT_Y_LEN   0.15f
24 
25 /*!
26  * \ingroup text_font
27  * \brief Enumeration for font categories
28  *
29  * This enumeration defines the different categories of fonts used in the
30  * game. The actual enum values correspond to indices in the font_idxs array,
31  * which holds the actual font numbers.
32  */
33 typedef enum
34 {
35 	//! Index for the font used for drawing text in the user interface
36 	UI_FONT,
37 	//! Index for the font used for drawing text messages
38 	CHAT_FONT,
39 	//! Index for the font used for drawing names above the characters
40 	NAME_FONT,
41 	//! Index for the font used for drawing text in books
42 	BOOK_FONT,
43 	//! INdex for the font used to draw user notes
44 	NOTE_FONT,
45 	//! Index for the font used to draw the rules
46 	RULES_FONT,
47 	//! Index for the font used to draw the encyclopedia and help texts
48 	ENCYCLOPEDIA_FONT,
49 	//! Index used for the font used to draw map marks
50 	MAPMARK_FONT,
51 	//! Index used for the font used to draw the options window contents
52 	CONFIG_FONT,
53 	//! Number of font categories
54 	NR_FONT_CATS
55 } font_cat;
56 
57 //! Enumeration for horizontal text alignment
58 typedef enum
59 {
60 	//! Align text left to the given position
61 	LEFT,
62 	//! Center text around the given position
63 	CENTER,
64 	//! Align text right to the given position
65 	RIGHT
66 } hor_alignment;
67 
68 //! Enumeration for vertical text alignment
69 typedef enum
70 {
71 	//! Align top of the line to the given position
72 	TOP_LINE,
73 	//! Align top of the font to the given position
74 	TOP_FONT,
75 	//! Align bottom of the line to the given position
76 	BOTTOM_LINE,
77 	//! Center text around the given position, works with multiple lines
78 	CENTER_LINE,
79 	//! Center first line around given position, assuming it consists of digits
80 	CENTER_DIGITS,
81 	//! Center first line around given position, assuming it consists of password asterisks
82 	CENTER_PASSWORD
83 } ver_alignment;
84 
85 #include "client_serv.h"
86 #include "gl_init.h"
87 #include "text.h"
88 #include "widgets.h"
89 
90 #ifdef __cplusplus
91 
92 #include <array>
93 #include <stdexcept>
94 #include <string>
95 #include <unordered_map>
96 #include <vector>
97 #include <SDL_types.h>
98 #ifdef TTF
99 #include <SDL_ttf.h>
100 #endif // TTF
101 #include "platform.h"
102 
103 namespace eternal_lands
104 {
105 
106 /*!
107  * \ingroup text_font
108  * \brief Type alias for a byte string, as used in many places in EL
109  */
110 typedef std::basic_string<unsigned char> ustring;
111 
112 /*!
113  * \ingroup text_font
114  * \brief Class for font options.
115  *
116  * Class FontOption holds the information necessary to display a font option to the user: the font
117  * name, its file name, the type of font and whether it is a fixed width font.
118  */
119 class FontOption
120 {
121 public:
122 	/*!
123 	 * \brief Constructor
124 	 *
125 	 * Create a new font option for the EL bundled font with index \a font_nr. Currently there are
126 	 * 7 such fonts available:
127 	 * - 0: textures/font.dds (fixed width)
128 	 * - 1: textures/font.dds (variable width)
129 	 * - 2: textures/font2.dds
130 	 * - 3: textures/font3.dds
131 	 * - 4: textures/font5.dds
132 	 * - 5: textures/font6.dds
133 	 * - 6: textures/font7.dds
134 	 *
135 	 * \param font_nr The number of the bundled font.
136 	 */
137 	FontOption(size_t font_nr);
138 #ifdef TTF
139 	/*!
140 	 * \brief Constructor
141 	 *
142 	 * Create a new font option for the TrueType font in file \a file_name.
143 	 *
144 	 * \param file_name The name of the file of the TrueType font.
145 	 */
146     FontOption(const std::string& file_name);
147 #endif
148 
149 	//! Return the font number of a bundled font
font_number()150 	size_t font_number() const { return _font_nr; }
151 	//! Return the file name of the font
file_name()152     const std::string& file_name() const { return _file_name; }
153 	//! Return the base file name of the font, without a path prefix
file_base_name()154     const std::string& file_base_name() const { return _file_base_name; }
155     //! Return the display name of the font
font_name()156     const std::string& font_name() const { return _font_name; }
157 #ifdef TTF
158 	//! Return whether the font is a TrueType font
is_ttf()159     bool is_ttf() const { return _is_ttf; }
160 #endif
161 	//! Return whether the font is fixed width
is_fixed_width()162     bool is_fixed_width() const { return _fixed_width; }
163     //! Return \c true if the font file cannot be found, or the font is otherwise invalid
failed()164     bool failed() const { return _failed; }
165 
166 	/*!
167 	 * \brief Add this font to the multi-selects
168 	 *
169 	 * Add this font option to the various font selections in the settings window. If the optional
170 	 * parameter \a add_button is \c true, a button for the font is immediately added to the
171 	 * corresponding widget.
172 	 */
173 	void add_select_options(bool add_button=false) const;
174 
175 private:
176 	// Font number, only for bundled fonts
177 	size_t _font_nr;
178 	//! File name of the font file or texture image
179     std::string _file_name;
180 	//! Base file name of the font file or texture image, without any preceding path
181     std::string _file_base_name;
182 	//! Return the display name of the font
183     std::string _font_name;
184 #ifdef TTF
185 	//! \c true if this a a True Type font
186     bool _is_ttf;
187 #endif
188 	//! \c true if this ais a monospaced font
189     bool _fixed_width;
190 	//! \c true if the font file does not exist, or the font is otherwise invalid
191     bool _failed;
192 };
193 
194 /*!
195  * \ingroup text_font
196  * \brief Class for text drawing options.
197  *
198  * Class TextDrawOptions can hold options that specify how a text will be
199  * displayed on the screen. Things that can be specified through TextDrawOptions
200  * include:
201  * * The size and color of the text to display
202  * * The maximum width the text can occupy, and the maximum number of lines to draw,
203  * * Alignment of the text: left, right, or centered around the given x position
204  * * Whether or not to draw a semi-transparent background behind the text
205  * * Whether to use ellipsis to indicate too wide text
206  */
207 class TextDrawOptions
208 {
209 public:
210 	//! Default foreground color for text
211 	static const std::array<float, 3> default_foreground_color;
212 	//! Default background color for text
213 	static const std::array<float, 3> default_background_color;
214 	//! Default color for selected text
215 	static const std::array<float, 3> default_selection_color;
216 
217 	typedef ::hor_alignment Alignment;
218 	typedef ::ver_alignment VerticalAlignment;
219 
220 	//! Bit flags controlling the look of the text
221 	enum Flags
222 	{
223 		//! If set, draw a shadow around the text
224 		SHADOW = 1 << 0,
225 		//! If set, ignore color characters in the text
226 		IGNORE_COLOR = 1 << 1,
227 		//! If set, draw a semi-transparent background behind the text
228 		HELP = 1 << 2,
229 		//! If set, draw ellipsis (...) after truncated strings
230 		ELLIPSIS = 1 << 3,
231 		//! If set, scale text down if it is too wide
232 		SHRINK_TO_FIT = 1 << 4
233 	};
234 
235 	/*!
236 	 * \brief Constructor
237 	 *
238 	 * Create a new TextDrawOptions object, with default settings.
239 	 */
240 	TextDrawOptions();
241 
242 	//! Return the maximum width the text can occupy
max_width()243 	int max_width() const { return _max_width; }
244 	//! Return the maximum number of text lines to draw
max_lines()245 	int max_lines() const { return _max_lines; }
246 	//! Return the scale factor for the text
zoom()247 	float zoom() const { return _zoom; }
248 	//! Return the scale factor for the spacing between two lines
line_spacing()249 	float line_spacing() const { return _line_spacing; }
250 	//! Return the horizontal alignment of the text
alignment()251 	Alignment alignment() const { return _alignment; }
252 	//! Return the vertical alignment of the text
vertical_alignment()253 	VerticalAlignment vertical_alignment() const { return _vertical_alignment; }
254 	//! Return whether the text is drawn with a shadow background
shadow()255 	bool shadow() const { return _flags & SHADOW; }
256 	//! Return whether color characters in the text are ignored
ignore_color()257 	bool ignore_color() const { return _flags & IGNORE_COLOR; }
258 	//! Return whether this is a help text, with semi-transparent background
is_help()259 	bool is_help() const { return _flags & HELP; }
260 	//! Return whether to truncate wide text with ellipsis (...)
ellipsis()261 	bool ellipsis() const { return _flags & ELLIPSIS; }
262 	//! Return whether to shrink the text if it does not fit
shrink_to_fit()263 	bool shrink_to_fit() const { return _flags & SHRINK_TO_FIT; }
264 
265 	//! Return whether a valid foreground color was set for this text
has_foreground_color()266 	bool has_foreground_color() const { return _fg_color[0] >= 0.0; }
267 	//! Return whether a valid background color was set for this text
has_background_color()268 	bool has_background_color() const { return _bg_color[0] >= 0.0; }
269 
270 	//! Set the maximum width (in pixels) the text can occupy to \a width
set_max_width(int width)271 	TextDrawOptions& set_max_width(int width)
272 	{
273 		_max_width = width;
274 		return *this;
275 	}
276 
277 	//! Set the maximum number of lines to draw to \a lines
set_max_lines(int lines)278 	TextDrawOptions& set_max_lines(int lines)
279 	{
280 		_max_lines = lines;
281 		return *this;
282 	}
283 
284 	//! Set the scale factor for the text to \a zoom
set_zoom(float zoom)285 	TextDrawOptions& set_zoom(float zoom)
286 	{
287 		_zoom = zoom;
288 		return *this;
289 	}
290 
291 	//! Multiply the current scale factor by \a scale
scale_zoom(float scale)292 	TextDrawOptions& scale_zoom(float scale)
293 	{
294 		_zoom *= scale;
295 		return *this;
296 	}
297 
298 	//! Set the scale factor for the line spacing to \a scale
set_line_spacing(float scale)299 	TextDrawOptions& set_line_spacing(float scale)
300 	{
301 		_line_spacing = scale;
302 		return *this;
303 	}
304 
305 	//! Set the horizontal text alignment to \a alignment
set_alignment(Alignment alignment)306 	TextDrawOptions& set_alignment(Alignment alignment)
307 	{
308 		_alignment = alignment;
309 		return *this;
310 	}
311 
312 	//! Set the vertical text alignment to \a alignment
set_vertical_alignment(VerticalAlignment alignment)313 	TextDrawOptions& set_vertical_alignment(VerticalAlignment alignment)
314 	{
315 		_vertical_alignment = alignment;
316 		return *this;
317 	}
318 
319 	/*!
320 	 * \brief Set whether to draw a shadow in the background color around the text
321 	 * \sa set_background
322 	 */
323 	TextDrawOptions& set_shadow(bool shadow=true)
324 	{
325 		if (shadow)
326 			_flags |= SHADOW;
327 		else
328 			_flags &= ~SHADOW;
329 		return *this;
330 	}
331 
332 	/*!
333 	 * \brief Set the foreground color of the text to (\a r, \a g, \a b).
334 	 *
335 	 * If not set, text is drawn in white, unless ignore_color is set, in which
336 	 * case the current OpenGL color is used.
337 	 * \sa set_ignore_color
338 	 */
set_foreground(float r,float g,float b)339 	TextDrawOptions& set_foreground(float r, float g, float b)
340 	{
341 		_fg_color[0] = r;
342 		_fg_color[1] = g;
343 		_fg_color[2] = b;
344 		return *this;
345 	}
346 
347 	/*!
348 	 * \brief  Set the background (shadow) color of the text to (\a r, \a g, \a b).
349 	 *
350 	 * If not set, shadows are drawn in black.
351 	 *
352 	 * \sa set_shadow
353 	 */
set_background(float r,float g,float b)354 	TextDrawOptions& set_background(float r, float g, float b)
355 	{
356 		_bg_color[0] = r;
357 		_bg_color[1] = g;
358 		_bg_color[2] = b;
359 		return *this;
360 	}
361 
362 	//! Set whether to ignore color characters in the text
363 	TextDrawOptions& set_ignore_color(bool ignore=true)
364 	{
365 		if (ignore)
366 			_flags |= IGNORE_COLOR;
367 		else
368 			_flags &= ~IGNORE_COLOR;
369 		return *this;
370 	}
371 
372 	/*!
373 	 * \brief Set whether this is a help text.
374 	 *
375 	 * Help texts are drawn with a semi-transparent background behind the text,
376 	 * as if they are on a window.
377 	 */
378 	TextDrawOptions& set_help(bool is_help=true)
379 	{
380 		if (is_help)
381 			_flags |= HELP;
382 		else
383 			_flags &= ~HELP;
384 		return *this;
385 	}
386 
387 	//! Set whether to ellipsis (...) should be added to clipped text
388 	TextDrawOptions& set_ellipsis(bool ellipsis=true)
389 	{
390 		if (ellipsis)
391 			_flags |= ELLIPSIS;
392 		else
393 			_flags &= ~ELLIPSIS;
394 		return *this;
395 	}
396 
397 	//! Set the color for selected text to (\a r, \a g, \a b).
set_selection(float r,float g,float b)398 	TextDrawOptions& set_selection(float r, float g, float b)
399 	{
400 		_sel_color[0] = r;
401 		_sel_color[1] = g;
402 		_sel_color[2] = b;
403 		return *this;
404 	}
405 
406 	//! Set whether to shrink the text if it is too wide
407 	TextDrawOptions& set_shrink_to_fit(bool shrink=true)
408 	{
409 		if (shrink)
410 			_flags |= SHRINK_TO_FIT;
411 		else
412 			_flags &= ~SHRINK_TO_FIT;
413 		return *this;
414 	}
415 
416 	//! Set the current draw color to the foreground color in these options
417 	void use_foreground_color() const;
418 	//! Set the current draw color to the background color in these options
419 	void use_background_color() const;
420 	//! Set the current draw color to the selection color in these options
421 	void use_selection_color() const;
422 
423 private:
424 	//! The maximum width of the text
425 	int _max_width;
426 	//! The maximum number of lines to draw
427 	int _max_lines;
428 	//! The scale factor for the text size
429 	float _zoom;
430 	//! The scale factor for the spacing between lines
431 	float _line_spacing;
432 	//! The horizontal alignment of the text
433 	Alignment _alignment;
434 	//! The vertical alignment of the text
435 	VerticalAlignment _vertical_alignment;
436 	//! Bit flags for further options
437 	Uint32 _flags;
438 	//! The foreground color of the text
439 	std::array<float, 3> _fg_color;
440 	//! The shadow color of the text, if shadows are drawn
441 	std::array<float, 3> _bg_color;
442 	//! The color for selected text
443 	std::array<float, 3> _sel_color;
444 };
445 
446 /*!
447  * \ingroup text_font
448  * \brief A class for a text font
449  *
450  * Class Font holds information about text fonts, and provides functions to
451  * draw text in a certain font. A font can be either one of the fonts bundled
452  * with the game, or if the TTF compiled option is enabled, a TrueType font
453  * on the user's system.
454  */
455 class Font
456 {
457 public:
458 	/*!
459 	 * Move constructor
460 	 *
461 	 * Create a new font as a copy of \a font.
462 	 * \note This constructor does takes ownership of the font texture; the texture in \a font
463 	 * is invalidated.
464 	 *
465 	 * \param font The font to move into this font
466 	 */
467 	Font(Font&& font);
468 	/*!
469 	 * \brief Create a new font
470 	 *
471 	 * Initialize a new internal font. This sets the parameters for the bundled font with the font
472 	 * number stored in \a option, but does not yet load the font texture because it is called
473 	 * before OpenGL is initialized.
474 	 *
475 	 * \param option  The font option for the font to load, holding font number, file and font name
476 	 */
477 	Font(const FontOption& option);
478 #ifdef TTF
479 	/*!
480 	 * \brief Create a new font.
481 	 *
482 	 * Create a new font for the TTF font option in \a option, for text with line height \a height
483 	 * pixels. This only copies the font description, and determines the point size. It does not
484 	 * yet generate a texture. If \a outline is \c true, a shadow outline will be drawn around the
485 	 * glyphs, otherwise the glyphs are drawn as they are.
486 	 *
487 	 * \param option  The font option for the font, holding file and font name
488 	 * \param height  The line height of the opened font
489 	 * \param outline Whether to draw a shadow outline around the glyphs
490 	 */
491 	Font(const FontOption& option, int height, bool outline);
492 #endif
493 	//! Destructor
494 	~Font();
495 
496 	//! Return the name of the font
font_name()497 	const std::string& font_name() const { return _font_name; }
498 	//! Return the file name from which the font was loaded
file_name()499 	const std::string& file_name() const { return _file_name; }
500 #ifdef TTF
501 	//! Check if this font is a TTF font
is_ttf()502 	bool is_ttf() const { return _flags & Flags::IS_TTF; }
503 #endif
504 	//! Check if the font is fixed width
is_fixed_width()505 	bool is_fixed_width() const { return _flags & Flags::FIXED_WIDTH; }
506 	//! Check if a texture has been generated for this font
has_texture()507 	bool has_texture() const { return _flags & Flags::HAS_TEXTURE; }
508 	//! Check if this font is drawn with an outline or not
has_outline()509 	bool has_outline() const { return _flags & Flags::HAS_OUTLINE; }
510 	//! Check if this font failed to load
failed()511 	bool failed() const { return _flags & Flags::FAILED; }
512 
513 	/*!
514 	 * \brief Check if a character has a glyph.
515 	 *
516 	 * Check if a glyph is defined for a character \a c, i.e. if it can be printed.
517 	 *
518 	 * \param c The character to check
519 	 * \return \c true if the character has a glyph, \c false otherwise.
520 	 */
has_glyph(unsigned char c)521 	static bool has_glyph(unsigned char c)
522 	{
523 		return get_position(c) >= 0;
524 	}
525 
526 	/*!
527 	 * \brief Get the width of a character
528 	 *
529 	 * Get the drawing width of character \a c when drawn in this font at zoom level \a zoom.
530 	 *
531 	 * \param c    The character of which to determine the width
532 	 * \param zoom The zoom factor for drawing the glyph
533 	 * \return The width of \a c, in pixels.
534 	 */
535 	int width(unsigned char c, float zoom=1.0) const
536 	{
537 		return width_pos(get_position(c), zoom);
538 	}
539 	/*!
540 	 * \brief Get the pen advancement of a character, plus spacing
541 	 *
542 	 * Get how far the pen is advanced after drawing character \a c in this font at zoom level
543 	 * \a zoom. The spacing between two characters is added to the advancement.
544 	 *
545 	 * \param c    The character of which to determine the width
546 	 * \param zoom The zoom factor for drawing the glyph
547 	 * \return The width of \a c and spacing, in pixels.
548 	 */
549 	int advance_spacing(unsigned char c, float zoom=1.0) const
550 	{
551 		return advance_spacing_pos(get_position(c), zoom);
552 	}
553 	/*!
554 	 * \brief Get the maximum character width, plus spacing
555 	 *
556 	 * Get the maximum width of a single character in this font when drawn at zoom
557 	 * level \a zoom, and include the spacing between characters.
558 	 *
559 	 * \param zoom The zoom factor for drawing the character.
560 	 * \return The maximum width of a character including spacing, in pixels.
561 	 */
562 	int max_width_spacing(float zoom=1.0) const;
563 	/*!
564 	 * \brief Get the average character width, plus spacing
565 	 *
566 	 * Get an approximation to the average width of a character in this font when
567 	 * drawn at zoom level \a zoom, including the space between characters,
568 	 * for some definition of "average". The average is calculated by assigning
569 	 * a weight to each possible character, and taking the weighted average
570 	 * of all character widths. The weights are based on a study on normal
571 	 * English text, so use this function with the following caveats:
572 	 * 1. Relative frequencies are based on English text, and so may not be
573 	 *    applicable to text in to other languages,
574 	 * 2. Furthermore, weights are based on text from the New York Times, and so
575 	 *    may not be representative even for English text in EL,
576 	 * 3. Only ASCII characters were counted in the study (so accented characters
577 	 *    don't contribute), and a few ASCII characters are missing as well
578 	 *    (\c '[', \c '\\', \c ']', \c '^', \c '_', and \c '`' to be exact),
579 	 * 4. The occurance of the space character was guesstimated from the reported
580 	 *    total number of words in the corpus.
581 	 *
582 	 * Proceed to use with caution, do not use this function when you need to be
583 	 * sure a string will fit within a certain space, use max_width_spacing()
584 	 * or a monospaced font instead.
585 	 *
586 	 * \param zoom The zoom factor for drawing the character.
587 	 * \return The maximum width of a character including spacing, in pixels.
588 	 */
589 	int average_width_spacing(float zoom=1.0) const;
590 	/*!
591 	 * \brief Get the maximum width of a digit, plus spacing
592 	 *
593 	 * Get the maximum width of a single digit character (0-9) in this font when
594 	 * drawn at zoom level \a zoom, and include the spacing between characters.
595 	 *
596 	 * \param zoom The zoom factor for drawing the character.
597 	 * \return The maximum width of a digit character including spacing, in pixels.
598 	 */
599 	int max_digit_width_spacing(float zoom=1.0) const;
600 	/*!
601 	 * \brief The maximum width of a single name character
602 	 *
603 	 * Return the maximum pen advancement for a single name character ('0'-'9', 'a'-'z', 'A'-'Z', or '_')
604 	 * when drawn in this font at zoom level \a text_zoom, and include the spacing between characters.
605 	 *
606 	 * \param zoom The scale factor for the text
607 	 * \return The maximum name character width incuding spacing, in pixels.
608 	 */
609 	int max_name_width_spacing(float zoom=1.0) const;
610 	/*!
611 	 * \brief Calculate the width of a string
612 	 *
613 	 * Calculate the width in pixels of the string \a text of length \a len
614 	 * when drawn in this font with scale factor zoom.
615 	 * \note This function assumes the string is a single line. Newline
616 	 * characters are ignored, and having them in the middle of string will
617 	 * result in a too large value for the width.
618 	 *
619 	 * \param text The string for which to calculate the length
620 	 * \param len  The number of bytes in \a text
621 	 * \param zoom The scale factor for the text
622 	 * \return The width of the text in pixels
623 	 */
624 	int line_width(const unsigned char* text, size_t len, float zoom) const;
625 	/*!
626 	 * \brief Calculate the width of a string with final spacing
627 	 *
628 	 * Calculate the width in pixels of the string \a text of length \a len,
629 	 * including the spacing after the final character, when drawn in this font
630 	 * with scale factor \a zoom.
631 	 * \note This function assumes the string is a single line. Newline
632 	 * characters are ignored, and having them in the middle of string will
633 	 * result in a too large value for the width.
634 	 *
635 	 * \param text The string for which to calculate the length
636 	 * \param len  The number of bytes in \a text
637 	 * \param zoom The scale factor for the text
638 	 * \return The width of the text in pixels
639 	 */
640 	int line_width_spacing(const unsigned char* text, size_t len, float zoom) const;
641 	/*!
642 	 * \brief Calculate the width of a string with final spacing
643 	 *
644 	 * Calculate the width in pixels of the string \a text including the spacing
645 	 * after the final character, when drawn in this font with scale factor \a zoom.
646 	 * \note This function assumes the string is a single line. Newline
647 	 * characters are ignored, and having them in the middle of string will
648 	 * result in a too large value for the width.
649 	 *
650 	 * \param text The string for which to calculate the length
651 	 * \param zoom The scale factor for the text
652 	 * \return The width of the text in pixels
653 	 */
line_width_spacing(const ustring & text,float zoom)654 	int line_width_spacing(const ustring& text, float zoom) const
655 	{
656 		return line_width_spacing(text.data(), text.length(), zoom);
657 	}
658 	/*!
659 	 * \brief Get the height of a line.
660 	 *
661 	 * Get the height of a single line of text when drawing text at zoom level \a zoom.
662 	 * \note It is not necessarily the case that two consecutive lines of text consume twice
663 	 * the line height, the use of the bundled fonts (where the line height is greater than the
664 	 * spacing) or a custom line spacing may prevent that. Use dimensions() or vertical_advance()
665 	 * if you need to know the height of a text consiting of multiple lines.
666 	 *
667 	 * \param zoom The zoom factor for drawing the text
668 	 */
669 	int height(float zoom=1.0) const;
670 	/*!
671 	 * \brief Get the vertical advancement after a line.
672 	 *
673 	 * Get the number of pixels the pen is advanced in the vertical direction after drawing a
674 	 * line of text at zoom level \a zoom, with line spacing scale factor \a line_spacing.
675 	 *
676 	 * \param zoom         The zoom factor for drawing the text
677 	 * \param line_spacing The additional scale factor for the spacing between lines
678 	 */
679 	int vertical_advance(float zoom=1.0, float line_spacing=1.0) const;
680 	/*!
681 	 * \brief Calculate the number of lines that fit.
682 	 *
683 	 * Return the maximum number of lines that fit in a window of \a max_height pixels high, when
684 	 * drawing text in this font at zoom level \a zoom, and line spacing scale factor
685 	 * \a line_spacing.
686 	 *
687 	 * \param max_height   The maximum height of the text, in pixels
688 	 * \param zoom         The zoom factor for drawing the text
689 	 * \param line_spacing The additional scale factor for the spacing between lines
690 	 */
691 	int max_nr_lines(int max_height, float zoom, float line_spacing=1.0) const;
692 	/*!
693 	 * \brief Compute the height of a block of text
694 	 *
695 	 * Compute the height of a block of text of \a nr_lines lines, when drawn in this font
696 	 * at zoom level \a zoom, with line spacing scale factor \a line_spacing.
697 	 *
698 	 * \param nr_lines     The number of lines in the text
699 	 * \param text_zoom    The zoom factor for drawing the text
700 	 * \param line_spacing The additional scale factor for the spacing between lines
701 	 * \return The height of the text in pixels
702 	 */
703 	int text_height(int nr_lines, float zoom, float line_spacing=1.0);
704 	/*!
705 	 * \brief Calculate the dimensions of a block of text
706 	 *
707 	 * Calculate the width and height of string \a text of length \a len bytes when drawn in this
708 	 * font with scale factor \a zoom and with line spacing scale factor \a line_spacing. The
709 	 * string may contain multiple lines, the width returned is then the width of the widest line.
710 	 *
711 	 * \param text         The string for which to compute the dimensions
712 	 * \param len          The number of bytes in \a text
713 	 * \param zoom         The scale factor for the text
714 	 * \param line_spacing The additional scale factor for the spacing between lines
715 	 * \return The width and height of the text
716 	 */
717 	std::pair<int, int> dimensions(const unsigned char* text, size_t len, float zoom,
718 		float line_spacing=1.0) const;
719 
720 	/*!
721 	 * \brief Calculate vertical offset of center
722 	 *
723 	 * Calculate the offset of the center of the characters in \a text with respect to the center
724 	 * of the line, when drawn at zoom level \a zoom.
725 	 *
726 	 * \param text The string for which to compute center offset
727 	 * \param len  The number of bytes in \a text
728 	 * \param zoom The scale factor for the text
729 	 * \return The number of pixels between the center of the line and the center of \a text.
730 	 */
731 	int center_offset(const unsigned char* text, size_t len, float zoom);
732 	/*!
733 	 * \brief Get vertical coordinates
734 	 *
735 	 * Get the minimum and maximum offsets of the characters in \a text with respect to the top of
736 	 * the text line, when drawing the text at zoom level \a zoom.
737 	 *
738 	 * \param text The text to get the vertical offsets for
739 	 * \param len  The number of characters in \a text
740 	 * \param zoom The scale factor for the text
741 	 * \return The offsets of the top and bottom of the text
742 	 */
743 	std::pair<int, int> top_bottom(const unsigned char* text, size_t len, float zoom);
744 
745 	/*!
746 	 * \brief Recompute where the line breaks in a string should occur
747 	 *
748 	 * Recomputes the positions in string \a text where line breaks should be placed so that the
749 	 * string fits into a window. This creates a new string from the the contents of \a text and
750 	 * inserts \c '\\r' characters at the positions where the line should be broken. The parameter
751 	 * \a options specifies how the text will be drawn, currently only the \c zoom and \c max_width
752 	 * fields are used in this function. The optional parameter \a cursor contains the offset of
753 	 * the cursor position in the text; if it is non-negative the difference in cursor position
754 	 * will be returned through the third value in the result tuple. The optional parameter
755 	 * \a max_line_width can be used to retrieve the largest width in pixels of the lines in \a text
756 	 * after rewrapping.
757 	 *
758 	 * \param text       the string
759 	 * \param text_len   the actual length of the string
760 	 * \param options    the options defining the layout of the text
761 	 * \param cursor     the cursor position, or a negative number if not used
762 	 * \param max_line_width pointer the maximum line length after wrapping, or NULL if not used
763 	 *
764 	 * \return The wrapped text, the new number of lines in the text, and the difference in
765 	 * 	cursor position
766 	 */
767 	std::tuple<ustring, int, int> reset_soft_breaks(const unsigned char *text, size_t text_len,
768 		const TextDrawOptions& options, ssize_t cursor = -1, int *max_line_width = nullptr);
769 	/*!
770 	 * \brief Recompute where the line breaks in a string should occur
771 	 *
772 	 * Recomputes the positions in string \a text where line breaks should be
773 	 * placed so that the string fits into a window. This creates a new string
774 	 * from the the contents of \a text and inserts \c '\\r' characters at the
775 	 * positions where the line should be broken. The parameter \a options
776 	 * specifies how the text will be drawn, currently only the \c zoom and
777 	 * \c max_width field are used int this function.
778 	 *
779 	 * \param text       the string
780 	 * \param options    the options defining the layout of the text
781 	 *
782 	 * \return The wrapped text and the new number of lines in the text.
783 	 */
reset_soft_breaks(const ustring & text,const TextDrawOptions & options)784 	std::pair<ustring, int> reset_soft_breaks(const ustring& text, const TextDrawOptions& options)
785 	{
786 		auto res = reset_soft_breaks(text.data(), text.length(), options, -1, nullptr);
787 		return std::make_pair(std::get<0>(res), std::get<1>(res));
788 	}
789 
790 	/*!
791 	 * \brief Draw a text string
792 	 *
793 	 * Draw the text in the first \a len bytes of \a text, starting at position
794 	 * \a x, \a y, using the drawing option in \a options.
795 	 *
796 	 * \param text      The text to draw
797 	 * \param len       The number of bytes in \a text
798 	 * \param x         The left coordinate of the drawn text
799 	 * \param y         The top coordinate of the drawn text
800 	 * \param options   Options defining the layout of the text
801 	 * \param sel_begin Start index of selected text
802 	 * \param sel_end   End index of selected text (one past last selected character)
803 	 */
804 	void draw(const unsigned char* text, size_t len, int x, int y,
805 		const TextDrawOptions &options, size_t sel_begin=0, size_t sel_end=0) const;
806 	/*!
807 	 * \brief Draws messages in a buffer to the screen
808 	 *
809 	 * Draws the messages in buffer \a msgs to the screen, starting with character
810 	 * \a offset_start in message number \a msg_start.
811 	 *
812 	 * \param msgs         the message buffer
813 	 * \param msgs_size    the total number of messages that \a msgs can hold
814 	 * \param x            x coordinate of the position to start drawing
815 	 * \param y            y coordinate of the position to start drawing
816 	 * \param filter       draw only messages in channel \a filter. Choose
817 	 * 	FILTER_ALL for displaying all messages
818 	 * \param msg_start    index of the first message to display
819 	 * \param offset_start the first character in message \a msg_start to display
820 	 * \param options      Options defining the layout of the text
821 	 * \param cursor       if >= 0, the position at which to draw the cursor
822 	 * \param[in,out] select information about current selection. draw_messages()
823 	 *	 fills the select->lines array.
824 	 *
825 	 * \callgraph
826 	 */
827 	void draw_messages(const text_message *msgs, size_t msgs_size, int x, int y,
828 		Uint8 filter, size_t msg_start, size_t offset_start,
829 		const TextDrawOptions &options, ssize_t cursor, select_info* select) const;
830 	/*!
831 	 * \brief Draw the console separator
832 	 *
833 	 * When there are more messages than can fit on a single screen, the user can
834 	 * scroll up to see the previous messages. When they do, a separator is
835 	 * drawn by this function to indicate that more messages follow.
836 	 *
837 	 * \param x_space Horizontal space tokeep free on either side
838 	 * \param y       Vertical position at which the line should be drawn
839 	 * \param options Text options for drawing the separator
840 	 */
841 	void draw_console_separator(int x_space, int y, const TextDrawOptions& options) const;
842 #ifdef ELC
843 #ifndef MAP_EDITOR2
844 	void draw_ortho_ingame_string(const unsigned char* text, size_t len,
845 		float x, float y, float z, int max_lines, float zoom_x, float zoom_y) const;
846 #endif // ! MAP_EDITOR2
847 #endif // ELC
848 
849 private:
850 	//! Structure for glyph metrics
851 	struct Metrics
852 	{
853 		//! Actual width of the character in the font texture, in pixels
854 		int width;
855 		//! How far to advance the pen after drawing this glyph
856 		int advance;
857 		//! Horizontal offset for drawing the character
858 		int x_off;
859 		//! Offset from top of line to top of glyph
860 		int top;
861 		//! Offset from top of line to bottom of glyph
862 		int bottom;
863 		//! Left side of glyph in the texture
864 		float u_start;
865 		//! Top of glyph in the texture
866 		float v_start;
867 		//! Right side of glyph in the texture
868 		float u_end;
869 		//! Bottom of glyph in the texture
870 		float v_end;
871 
872 		//! Default constructor
MetricsMetrics873 		Metrics(): width(0), advance(0), x_off(0), top(0), bottom(0), u_start(0.0), v_start(0.0),
874 			u_end(0.0), v_end(0.0) {}
875 	};
876 
877 	//! The number of lines in a font texture
878 	static const size_t font_nr_lines = 10;
879 	//! The number of glyphs on a single line in a font texture
880 	static const size_t font_chars_per_line = 14;
881 	//! The total number of different glyphs we recognise
882 	static const size_t nr_glyphs = 9*14 + 6;
883 	//! Horizontal space in the texture for a single glyph in a bundled font
884 	static const int font_block_width = 18;
885 	//! Vertical space in the texture for a single glyph in a bundled font
886 	static const int font_block_height = 21;
887 	//! Normal line height for unscaled text in a bundled font
888 	static const int default_vertical_advance = 18;
889 #ifdef TTF
890 	//! Point size with which TrueType fonts are opened
891 	static const int ttf_point_size = 40;
892 #endif
893 	//! Relative frequencies for characters in normal English text
894 	static const std::array<int, nr_glyphs> letter_freqs;
895 	//! Ellipsis string for clipped text
896 	static const ustring ellipsis;
897 
898 	//! Flags indicating the status and properties of a font
899 	enum Flags
900 	{
901 #ifdef TTF
902 		//! Set if the font is a TTF Font
903 		IS_TTF       = 1 << 0,
904 #endif
905 		//! Set if the font is fixed width, i.e. all characters have the same width
906 		FIXED_WIDTH  = 1 << 1,
907 		//! Set if the texture for the font is loaded or generated
908 		HAS_TEXTURE  = 1 << 2,
909 		//! Set if this font has a shadow outline around the glyphs
910 		HAS_OUTLINE  = 1 << 3,
911 		//! Set if loading the font failed, and a fallback should be used
912 		FAILED       = 1 << 4
913 	};
914 
915 	//! Name of this font. This will be shown on the multi-select button.
916 	std::string _font_name;
917 	//! Name of the files containing the font texture or TTF font description.
918 	std::string _file_name;
919 	//! Flags indicating the type and status of this font.
920 	Uint32 _flags;
921 	//! Width of the font texture in pixels.
922 	int _texture_width;
923 	//! Height of the font texture in pixels.
924 	int _texture_height;
925 	//! Glyph metrics for each supported character
926 	std::array<Metrics, nr_glyphs> _metrics;
927 	//! Width reserved for a character in the texture
928 	int _block_width;
929 	//! Height of a single character in pixels
930 	int _line_height;
931 	//! How far to advance the pen vertically when moving to the next line
932 	int _vertical_advance;
933 	//! Distance from top of line to top of font
934 	int _font_top_offset;
935 	//! Distance from top of line to center of digits
936 	int _digit_center_offset;
937 	//! Distance from top of line to center of the asterisk
938 	int _password_center_offset;
939 	//! Maximum width of a glyph
940 	int _max_advance;
941 	//! Maximum width of a digit '0'-'9'
942 	int _max_digit_advance;
943 	//! Maximum width of a name character '0'-'9', 'A'-'Z', 'a'-'z' or '_'
944 	int _max_name_advance;
945 	//! "Typical" character width for English text
946 	int _avg_advance;
947 	//! Distance between characters when drawn (at default zoom level)
948 	int _spacing;
949 	//! Scale factor in the horizontal direction
950 	float _scale_x;
951 	//! Scale factor in the vertical direction
952 	float _scale_y;
953 #ifdef TTF
954 	//! Point size to open the font file with
955 	int _point_size;
956 	//! Outline size in pixels
957 	int _outline;
958 	union
959 	{
960 		//! ID of the texture for this font in the texture cache.
961 		Uint32 cache_id;
962 		//! Open GL texture ID for a generated texture.
963 		GLuint gl_id;
964 	} _texture_id;
965 #else
966 	//! ID of the texture for this font in the texture cache
967 	Uint32 _texture_id;
968 #endif
969 
970 	friend class FontManager;
971 
972 	/*!
973 	 * \brief Get the position of a glyph in the texture
974 	 *
975 	 * \param c The byte for which to get the position
976 	 * \return The position in the font texture, of -1 if \a c is not a valid glyph.
977 	 */
978 	static int get_position(unsigned char c);
979 	/*!
980 	 * \brief Get the width of a character
981 	 *
982 	 * Get the width of the glyph at position \a pos in the texture when drawn
983 	 * in this font at zoom level \a zoom.
984 	 *
985 	 * \param pos  The position of the glyph in the texture
986 	 * \param zoom The zoom factor for drawing the glyph
987 	 */
988 	int width_pos(int pos, float zoom=1.0) const;
989 	/*!
990 	 * \brief Get the pen advancement of a character, plus spacing
991 	 *
992 	 * Get how far the pen is advanced after drawing the glyph at position \a pos in the texture,
993 	 * when drawn in this font at zoom level \a zoom. The spacing between two characters is added
994 	 * to the advancement.
995 	 *
996 	 * \param pos  The position of the glyph in the texture
997 	 * \param zoom The zoom factor for drawing the glyph
998 	 */
999 	int advance_spacing_pos(int pos, float zoom=1.0) const;
1000 	/*!
1001 	 * \brief Get vertical coordinates
1002 	 *
1003 	 * Get the minimum and maximum offsets of the characters in \a text with respect to the top of
1004 	 * the text line, before any scaling.
1005 	 *
1006 	 * \param text The text to get the vertical offsets for
1007 	 * \param len  The number of characters in \a text
1008 	 * \return The offsets of the top and bottom of the text
1009 	 */
1010 	std::pair<int, int> top_bottom_unscaled(const unsigned char* text, size_t len);
1011 
1012 	/*!
1013 	 * \brief Load or generate the texture for this font.
1014 	 *
1015 	 * Load the texture into the texture cache for normal fonts, or generate
1016 	 * a texture atlas for TTF fonts.
1017 	 *
1018 	 * \return \c true on success, \c false on failure.
1019 	 */
1020 	bool load_texture();
1021 	//! Bind the font texture for this font
1022 	void bind_texture() const;
1023 	/*!
1024 	 * \brief Get texture coordinates for a character
1025 	 *
1026 	 * Get the texture coordinates in the font texture for the character at
1027 	 * position \a pos.
1028 	 *
1029 	 * \param pos     The position of the character within the texture
1030 	 * \param u_start On exit, the left coordinate
1031 	 * \param u_end   On exit, the right coordinate
1032 	 * \param v_start On exit, the top coordinate
1033 	 * \param v_end   On exit, the bottom coordinate
1034 	 */
1035 	void get_texture_coordinates(int pos,
1036 		float &u_start, float &u_end, float &v_start, float &v_end) const;
1037 
1038 	/*!
1039 	 * \brief Set the current draw color.
1040 	 *
1041 	 * Set the drawing color for the text to the color define in colors_list
1042 	 * at index \a color.
1043 	 *
1044 	 * \param color The index of the text color in the \see colors_list.
1045 	 */
1046 	static void set_color(int color);
1047 
1048 	/*!
1049 	 * \brief Draw a single character
1050 	 *
1051 	 * Draw a single character \a c at position \a x, \a y with its sized scaled
1052 	 * by a factor \a zoom. This function only adds the quad with the correct
1053 	 * coordinates and texture coordinates; calls to this functions should be
1054 	 * done inside a glBegin(GL_QUADS)/glEnd() pair. If \a c is a color character,
1055 	 * the color is set and nothing is drawn.
1056 	 *
1057 	 * \param c            The character to draw
1058 	 * \param x            The x coordinate of the left side of the drawn character
1059 	 * \param y            The x coordinate of the top of the drawn character
1060 	 * \param zoom         The scale factor for the character
1061 	 * \param ignore_color If \c true, color characters are ignored and the
1062 	 * 	drawing color is left unchanged.
1063 	 *
1064 	 * \return The width of the drawn character, or 0 for color characters or
1065 	 * 	invalid characters
1066 	 */
1067 	int draw_char(unsigned char c, int x, int y, float zoom, bool ignore_color) const;
1068 	/*!
1069 	 * \brief Draw background for help texts
1070 	 *
1071 	 * Draw a semi-transparent background box for tooltips.
1072 	 *
1073 	 * \param x      The x coordinate of the left side of the box
1074 	 * \param y      The y coordinate of the top of the box
1075 	 * \param width  The width of the box in pixels
1076 	 * \param height The height of the box in pixels
1077 	 */
1078 	void draw_help_background(int x, int y, int width, int height) const;
1079 	/*!
1080 	 * \brief Draw a single line of text
1081 	 *
1082 	 * Draw a single line of text in \a text of length \a len bytes, starting
1083 	 * at position \a x, \a y and drawing to the left.
1084 	 * \note This function is for drawing a single line. Any newlines in \a text
1085 	 * are ignored.
1086 	 * \note The alignment option in \a options has no effect for this function,
1087 	 * text is always drawn left to right.
1088 	 *
1089 	 * \param text      The line of text to draw
1090 	 * \param len       The number of bytes in text to draw
1091 	 * \param x         The x coordinate of the left of the line
1092 	 * \param y         The y coordinate of the top of the line
1093 	 * \param options   Drawing options for the text
1094 	 * \param sel_begin Start index of selected text
1095 	 * \param sel_end   End index of selected text (one past last selected character)
1096 	 *
1097 	 */
1098 	void draw_line(const unsigned char* text, size_t len, int x, int y,
1099 		const TextDrawOptions &options, size_t sel_begin=0, size_t sel_end=0) const;
1100 	/*!
1101 	 * \brief Clip a line of text
1102 	 *
1103 	 * Clip a line of text such that the remainder fits into \a max_width pixels.
1104 	 * This function takes alignment into account: left aligned text is clipped
1105 	 * on the right, right-aligned text on the left, centered text on both sides
1106 	 * equally. In case color characters are clipped, the last color character
1107 	 * clipped on the left and right are returned through \a before_color and
1108 	 * \a after_color.
1109 	 *
1110 	 * \param text         The text to clip
1111 	 * \param len          The number of bytes in \a text
1112 	 * \param options      Drawing options for the text
1113 	 * \param before_color On exit, the last color character clipped before the
1114 	 * 	remaining string, or 0 if there was none.
1115 	 * \param after_color  On exit, the last color character clipped after the
1116 	 * 	remaining string, or 0 if there was none.
1117 	 * \param width        On exit, the remaining width of the clipped string.
1118 	 * \return Start index and length of the clipped substring
1119 	 */
1120 	std::pair<size_t, size_t> clip_line(const unsigned char* text, size_t len,
1121 		const TextDrawOptions &options, unsigned char &before_color, unsigned char &after_color,
1122 		int &width) const;
1123 
1124 #ifdef TTF
1125 	/*!
1126 	 * \brief Render a single glyph
1127 	 *
1128 	 * Render the glyph for position \a pos with size \a size in the font atlas \a surface, using
1129 	 * font \a font. The vertical offset parameter \a y_delta is used to try and center the glyphs
1130 	 * vertically, making vertical alignment of text easier.
1131 	 *
1132 	 * \param pos          The position of the glyph to draw
1133 	 * \param size         The size of the rendered glyph
1134 	 * \param y_delta      Vertical offset for placing the glyph in the texture
1135 	 * \param font         The font with which to render the glyph
1136 	 * \param outline_size If positive, the width of a semi-transparent outline around the glyph
1137 	 * \param surface      The surface on which the glyph is rendered
1138 	 * \return \c true if the glyph was successfully rendered, \c false otherwise.
1139 	 */
1140 	bool render_glyph(size_t i_glyph, int size, int y_delta, int outline_size, TTF_Font *font,
1141 		SDL_Surface *surface);
1142 	/*!
1143 	 * \brief Find an appropriate font size
1144 	 *
1145 	 * Find a point size for this font such that the line height is \a height pixels.
1146 	 *
1147 	 * \param height The line height to target
1148 	 * \return A point size for this font which gives the correct line height, or 0 on failure
1149 	 */
1150 	int find_point_size(int height);
1151 	/*!
1152 	 * \brief Build a texture for a TTF font
1153 	 *
1154 	 * Build a texture containing all supported glyphs from the TrueType font associated with
1155 	 * this font.
1156 	 *
1157 	 * \return \c true on succes, \c false on failure.
1158 	 */
1159 	bool build_texture_atlas();
1160 #endif // TTF
1161 
1162 	/*!
1163 	 * \brief Calculate the average character width.
1164 	 *
1165 	 * Calculate a weighted average character width based on the widths of the characters and
1166 	 * estimated letter frequencies in English text.
1167 	 *
1168 	 * \return The average width
1169 	 */
1170 	int calc_average_advance();
1171 };
1172 
1173 /*!
1174  * \brief Class for managing fonts
1175  *
1176  * Class FontManager is used as an entry point to font handling. It holds a list
1177  * of all known fonts, as well as a font number and scale factor for a number
1178  * of font categories. The font categories are used for drawing different kinds
1179  * of texts; by changing the font for a certain category all windows and widgets
1180  * using this category are updated automatically. Class FontManager is a singleton
1181  * class: all access to this class must go through get_instance().
1182  * \sa font_cat
1183  */
1184 class FontManager
1185 {
1186 public:
1187 	// Use font category enumeration shared with C code.
1188 	typedef ::font_cat Category;
1189 
1190 	//! The font numbers for each font category
1191 	static std::array<size_t, NR_FONT_CATS> font_idxs;
1192 	//! The zoom factor for each font category
1193 	static std::array<float, NR_FONT_CATS> font_scales;
1194 
1195 	//! Get the singleton FontManager instance
get_instance()1196 	static FontManager& get_instance()
1197 	{
1198 		static FontManager manager;
1199 		return manager;
1200 	}
1201 
1202 	//! Check if this font manager has been initialized
is_initialized()1203 	bool is_initialized() const { return !_options.empty(); }
1204 	/*!
1205 	 * \brief Initialize the font manager.
1206 	 *
1207 	 * This adds the standard fonts bundled with EL to the font manager, and
1208 	 * if TTF fonts are enabled, scans the TTF path for True Type fonts
1209 	 * to add as well.
1210 	 */
1211 	bool initialize();
1212 
1213 	/*!
1214 	 * \brief Return the font number of a fixed width font
1215 	 *
1216 	 * Return the font number for the \a idx'th fixed width font.
1217 	 *
1218 	 * \param idx The number of the font in the list of fixed width fonts only
1219 	 * \return The index of the font in the list of all fonts
1220 	 */
fixed_width_font_number(size_t idx)1221 	size_t fixed_width_font_number(size_t idx) const
1222 	{
1223 		try
1224 		{
1225 			return _fixed_width_idxs.at(idx);
1226 		}
1227 		catch (const std::out_of_range&)
1228 		{
1229 			// Return standard fixed width font on invalid index
1230 			return 0;
1231 		}
1232 	}
1233 
1234 	/*!
1235 	 * \brief Get the pend advancement of a character, plus spacing
1236 	 *
1237 	 * Get how far the pen is advanced after drawing character \a c in the font for category \a cat,
1238 	 * at zoom level \a zoom. The spacing between two characters is added to the advancement.
1239 	 *
1240 	 * \param cat       The font category for the font used
1241 	 * \param c         The character for which to get the width
1242 	 * \param text_zoom The scale factor for the text
1243 	 * \return The width of the character and spacing, in pixels.
1244 	 */
1245 	int advance_spacing(Category cat, unsigned char c, float text_zoom=1.0)
1246 	{
1247 		return get(cat, text_zoom).advance_spacing(c, text_zoom * font_scales[cat]);
1248 	}
1249 	/*!
1250 	 * \brief The maximum width of a single character
1251 	 *
1252 	 * Return the maximum a single character can occupy when drawn in the font
1253 	 * for category \a cat at zoom level \a text_zoom, and include the spacing
1254 	 * between characters.
1255 	 *
1256 	 * \param cat       The font category for the font used
1257 	 * \param text_zoom The scale factor for the text
1258 	 * \return The maximum character width incuding spacing, in pixels.
1259 	 */
1260 	int max_width_spacing(Category cat, float text_zoom=1.0)
1261 	{
1262 		return get(cat, text_zoom).max_width_spacing(text_zoom * font_scales[cat]);
1263 	}
1264 	/*!
1265 	 * \brief Get the average character width, plus spacing
1266 	 *
1267 	 * Get an approximation to the average width of a character in the font for
1268 	 * category \a cat when drawn at zoom level \a text_zoom, including the space
1269 	 * between characters, for some definition of "average". See the note
1270 	 * in Font::average_width_spacing() for some caveats when using this function.
1271 	 *
1272 	 * \param cat       The font category for the font used
1273 	 * \param text_zoom The zoom factor for drawing the character.
1274 	 * \return The maximum width of a character including spacing, in pixels.
1275 	 */
1276 	int average_width_spacing(Category cat, float text_zoom=1.0)
1277 	{
1278 		return get(cat, text_zoom).average_width_spacing(text_zoom * font_scales[cat]);
1279 	}
1280 	/*!
1281 	 * \brief The maximum width of a single digit character
1282 	 *
1283 	 * Return the maximum a single digit character (0-9) can occupy when drawn
1284 	 * in the font for category \a cat at zoom level \a text_zoom, and include
1285 	 * the spacing between characters.
1286 	 *
1287 	 * \param cat       The font category for the font used
1288 	 * \param text_zoom The scale factor for the text
1289 	 * \return The maximum digit character width incuding spacing, in pixels.
1290 	 */
1291 	int max_digit_width_spacing(Category cat, float text_zoom=1.0)
1292 	{
1293 		return get(cat, text_zoom).max_digit_width_spacing(text_zoom * font_scales[cat]);
1294 	}
1295 	/*!
1296 	 * \brief The maximum width of a single name character
1297 	 *
1298 	 * Return the maximum pen advancement for a single name character ('0'-'9', 'a'-'z', 'A'-'Z', or '_')
1299 	 * when drawn in the font for category \a cat at zoom level \a text_zoom, and include the
1300 	 * spacing between characters.
1301 	 *
1302 	 * \param cat       The font category for the font used
1303 	 * \param text_zoom The scale factor for the text
1304 	 * \return The maximum name character width incuding spacing, in pixels.
1305 	 */
1306 	int max_name_width_spacing(Category cat, float text_zoom=1.0)
1307 	{
1308 		return get(cat, text_zoom).max_name_width_spacing(text_zoom * font_scales[cat]);
1309 	}
1310 	/*!
1311 	 * \brief Calculate the width of a string
1312 	 *
1313 	 * Calculate the width in pixels of the string \a text of length \a len
1314 	 * when drawn in the font for category \a cat.
1315 	 * \note This function assumes the string is a single line. Newline
1316 	 * characters are ignored, and having them in the middle of string will
1317 	 * result in a too large value for the width.
1318 	 *
1319 	 * \param cat       The font category for the font used
1320 	 * \param text      The string for which to calculate the length
1321 	 * \param len       The number of bytes in \a text
1322 	 * \param text_zoom The scale factor for the text
1323 	 * \return The width of the text in pixels
1324 	 */
1325 	int line_width(Category cat, const unsigned char* text, size_t len,
1326 		float text_zoom=1.0)
1327 	{
1328 		return get(cat, text_zoom).line_width(text, len, text_zoom * font_scales[cat]);
1329 	}
1330 	/*!
1331 	 * \brief The height of a text line
1332 	 *
1333 	 * Return the height of a line of text when drawn in the font for category
1334 	 * \a cat with scale factor \a text_zoom.
1335 	 * \note It is not necessarily the case that two consecutive lines of text consume twice
1336 	 * the line height, the use of the bundled fonts (where the line height is greater than the
1337 	 * spacing) or a custom line spacing may prevent that. Use dimensions() or vertical_advance()
1338 	 * if you need to know the height of a text consiting of multiple lines.
1339 	 *
1340 	 * \param cat       The font category for the font used
1341 	 * \param text_zoom The scale factor for the text
1342 	 * \return The height of the text in pixels
1343 	 */
1344 	int line_height(Category cat, float text_zoom=1.0)
1345 	{
1346 		return get(cat, text_zoom).height(text_zoom * font_scales[cat]);
1347 	}
1348 	/*!
1349 	 * \brief Get the vertical advancement after a line.
1350 	 *
1351 	 * Get the number of pixels the pen is advanced in the vertical direction after drawing a
1352 	 * line of text at zoom level \a text_zoom, with line spacing scale factor \a line_spacing.
1353 	 *
1354 	 * \param cat          The font category for the font used
1355 	 * \param text_zoom    The zoom factor for drawing the text
1356 	 * \param line_spacing The additional scale factor for the spacing between lines
1357 	 * \return The number of pixels the pen is shifted down after a line
1358 	 */
1359 	int vertical_advance(Category cat, float text_zoom=1.0, float line_spacing=1.0)
1360 	{
1361 		return get(cat, text_zoom).vertical_advance(text_zoom * font_scales[cat], line_spacing);
1362 	}
1363 	/*!
1364 	 * \brief Calculate the number of lines that fit.
1365 	 *
1366 	 * Return the maximum number of lines that fit in a window of \a max_height pixels high, when
1367 	 * drawing text in the font for category \a cat at zoom level \a text_zoom, with line spacing
1368 	 * scale factor \a line_spacing.
1369 	 *
1370 	 * \param cat          The font category for the font used
1371 	 * \param max_height   The maximum height for the text, in pixels
1372 	 * \param text_zoom    The zoom factor for drawing the text
1373 	 * \param line_spacing The additional scale factor for the spacing between lines
1374 	 * \return The maximum number of lines that fit
1375 	 */
1376 	int max_nr_lines(Category cat, int max_height, float text_zoom, float line_spacing=1.0)
1377 	{
1378 		return get(cat, text_zoom).max_nr_lines(max_height, text_zoom * font_scales[cat], line_spacing);
1379 	}
1380 	/*!
1381 	 * \brief Compute the height of a block of text
1382 	 *
1383 	 * Compute the height of a block of text of \a nr_lines lines, when drawn in the font for
1384 	 * category \a cat at zoom level \a zoom, with line spacing scale factor \a line_spacing.
1385 	 *
1386 	 * \param cat          The font category for the font used
1387 	 * \param nr_lines     The number of lines in the text
1388 	 * \param text_zoom    The zoom factor for drawing the text
1389 	 * \param line_spacing The additional scale factor for the spacing between lines
1390 	 * \return The height of the text in pixels
1391 	 */
1392 	int text_height(font_cat cat, int nr_lines, float text_zoom, float line_spacing=1.0)
1393 	{
1394 		return get(cat, text_zoom).text_height(nr_lines, text_zoom * font_scales[cat], line_spacing);
1395 	}
1396 	/*!
1397 	 * \brief Calculate the dimensions of a block of text
1398 	 *
1399 	 * Calculate the width and height of string \a text of length \a len bytes when drawn in the
1400 	 * font for category \a cat, with scale factor \a zoom and line spacing scale factor
1401 	 * \a line_spacing. The string may contain multiple lines, the width returned is then the
1402 	 * width of the widest line.
1403 	 *
1404 	 * \param cat          The font category for the font used
1405 	 * \param text         The string for which to compute the dimensions
1406 	 * \param len          The number of bytes in \a text
1407 	 * \param text_zoom    The scale factor for the text
1408 	 * \param line_spacing The additional scale factor for the spacing between lines
1409 	 * \return The width and height of the text
1410 	 */
1411 	std::pair<int, int> dimensions(Category cat, const unsigned char* text, size_t len,
1412 		float text_zoom, float line_spacing=1.0)
1413 	{
1414 		return get(cat, text_zoom).dimensions(text, len, text_zoom * font_scales[cat], line_spacing);
1415 	}
1416 
1417 	/*!
1418 	 * \brief Calculate vertical offset of center
1419 	 *
1420 	 * Calculate the offset of the center of the characters in \a text with respect to the center
1421 	 * of the line, when drawn in the font for category \a cat at zoom level \a zoom.
1422 	 *
1423 	 * \param cat       The font category for the font used
1424 	 * \param text      The string for which to compute center offset
1425 	 * \param len       The number of bytes in \a text
1426 	 * \param text_zoom The scale factor for the text
1427 	 * \return The number of pixels between the center of the line and the center of \a text.
1428 	 */
center_offset(Category cat,const unsigned char * text,size_t len,float text_zoom)1429 	int center_offset(Category cat, const unsigned char* text, size_t len, float text_zoom)
1430 	{
1431 		return get(cat, text_zoom).center_offset(text, len, text_zoom * font_scales[cat]);
1432 	}
1433 	/*!
1434 	 * \brief Get vertical coordinates
1435 	 *
1436 	 * Get the minimum and maximum offsets of the characters in \a text with respect to the top of
1437 	 * the text line, when drawing the text in the font for category \a cat at zoom level \a zoom.
1438 	 *
1439 	 * \param cat       The font category for the font used
1440 	 * \param text      The text to get the vertical offsets for
1441 	 * \param len       The number of characters in \a text
1442 	 * \param text_zoom The scale factor for the text
1443 	 * \return The offsets of the top and bottom of the text
1444 	 */
top_bottom(Category cat,const unsigned char * text,size_t len,float text_zoom)1445 	std::pair<int, int> top_bottom(Category cat, const unsigned char* text, size_t len, float text_zoom)
1446 	{
1447 		return get(cat, text_zoom).top_bottom(text, len, text_zoom * font_scales[cat]);
1448 	}
1449 
1450 
1451 	/*!
1452 	 * \brief Recompute where the line breaks in a string should occur
1453 	 *
1454 	 * Recomputes the positions in string \a text where line breaks should be placed so that the
1455 	 * string fits into a window. This creates a new string from the the contents of \a text and
1456 	 * inserts \c '\\r' characters at the positions where the line should be broken. The parameter
1457 	 * \a options specifies how the text will be drawn, currently only the \c zoom and \c max_width
1458 	 * fields are used in this function. The optional parameter \a cursor contains the offset of
1459 	 * the cursor position in the text; if it is non-negative the difference in cursor position
1460 	 * will be returned through the third value in the result tuple. The optional parameter
1461 	 * \a max_line_width can be used to retrieve the largest width in pixels of the lines in \a text
1462 	 * after rewrapping.
1463 	 *
1464 	 * \param cat        the font category in which the string is to be drawn
1465 	 * \param text       the string
1466 	 * \param text_len   the actual length of the string
1467 	 * \param options    the options defining the layout of the text
1468 	 * \param cursor     pointer to the cursor position, or NULL if not used
1469 	 * \param max_line_width pointer the maximum line length after wrapping, or NULL if not used
1470 	 *
1471 	 * \return The wrapped text, the new number of lines in the text, and the difference in
1472 	 * 	cursor position
1473 	 */
1474 	std::tuple<ustring, int, int> reset_soft_breaks(Category cat, const unsigned char *text,
1475 		size_t text_len, const TextDrawOptions& options, int cursor = -1, int *max_line_width = nullptr)
1476 	{
1477 		TextDrawOptions cat_options = TextDrawOptions(options).scale_zoom(font_scales[cat]);
1478 		return get(cat, options.zoom())
1479 			.reset_soft_breaks(text, text_len, cat_options, cursor, max_line_width);
1480 	}
1481 	/*!
1482 	 * \brief Recompute where the line breaks in a string should occur
1483 	 *
1484 	 * Recomputes the positions in string \a text where line breaks should be
1485 	 * placed so that the string fits into a window. This creates a new string
1486 	 * from the the contents of \a text and inserts \c '\\r' characters at the
1487 	 * positions where the line should be broken. The parameter \a options
1488 	 * specifies how the text will be drawn, currently only the \c zoom and
1489 	 * \c max_width field are used int this function.
1490 	 *
1491 	 * \param cat        the font category in which the string is to be drawn
1492 	 * \param text       the string
1493 	 * \param options    the options defining the layout of the text
1494 	 *
1495 	 * \return The wrapped text, the new number of lines in the text, and the difference in
1496 	 * 	cursor position
1497 	 */
reset_soft_breaks(Category cat,const ustring & text,const TextDrawOptions & options)1498 	std::pair<ustring, int> reset_soft_breaks(Category cat, const ustring& text,
1499 		const TextDrawOptions& options)
1500 	{
1501 		TextDrawOptions cat_options = TextDrawOptions(options).scale_zoom(font_scales[cat]);
1502 		return get(cat, options.zoom()).reset_soft_breaks(text, cat_options);
1503 	}
1504 
1505 	/*!
1506 	 * \brief Draw a text string
1507 	 *
1508 	 * Draw the text in the first \a len bytes of \a text, starting at position
1509 	 * \a x, \a y, using the drawing option in \a options, using the font for
1510 	 * category \a cat.
1511 	 *
1512 	 * \param cat       The font category for the text
1513 	 * \param text      The text to draw
1514 	 * \param len       The number of bytes in \a text
1515 	 * \param x         The left coordinate of the drawn text
1516 	 * \param y         The top coordinate of the drawn text
1517 	 * \param options   Options defining the layout of the text
1518 	 * \param sel_begin Start index of selected text
1519 	 * \param sel_end   End index of selected text (one past last selected character)
1520 	 */
1521 	void draw(Category cat, const unsigned char* text, size_t len, int x, int y,
1522 		const TextDrawOptions &options, size_t sel_begin=0, size_t sel_end=0)
1523 	{
1524 		TextDrawOptions cat_options = TextDrawOptions(options).scale_zoom(font_scales[cat]);
1525 		get(cat, options.zoom()).draw(text, len, x, y, cat_options, sel_begin, sel_end);
1526 	}
1527 	/*!
1528 	 * \brief Draws messages in a buffer to the screen
1529 	 *
1530 	 * Draws the messages in buffer \a msgs to the screen using the font for
1531 	 * category \a cat, starting with character \a offset_start in message
1532 	 * number \a msg_start.
1533 	 *
1534 	 * \param cat          The font category for the text
1535 	 * \param msgs         the message buffer
1536 	 * \param msgs_size    the total number of messages that \a msgs can hold
1537 	 * \param x            x coordinate of the position to start drawing
1538 	 * \param y            y coordinate of the position to start drawing
1539 	 * \param filter       draw only messages in channel \a filter. Choose
1540 	 * 	FILTER_ALL for displaying all messages
1541 	 * \param msg_start    index of the first message to display
1542 	 * \param offset_start the first character in message \a msg_start to display
1543 	 * \param options      Options defining the layout of the text
1544 	 * \param cursor       if >= 0, the position at which to draw the cursor
1545 	 * \param[in,out] select information about current selection. draw_messages()
1546 	 *	 fills the select->lines array.
1547 	 *
1548 	 * \callgraph
1549 	 */
draw_messages(Category cat,const text_message * msgs,size_t msgs_size,int x,int y,Uint8 filter,size_t msg_start,size_t offset_start,const TextDrawOptions & options,ssize_t cursor,select_info * select)1550 	void draw_messages(Category cat, const text_message *msgs, size_t msgs_size,
1551 		int x, int y, Uint8 filter, size_t msg_start, size_t offset_start,
1552 		const TextDrawOptions &options, ssize_t cursor, select_info* select)
1553 	{
1554 		TextDrawOptions cat_options = TextDrawOptions(options).scale_zoom(font_scales[cat]);
1555 		get(cat, options.zoom()).draw_messages(msgs, msgs_size, x, y, filter, msg_start, offset_start,
1556 			cat_options, cursor, select);
1557 	}
1558 	/*!
1559 	 * \brief Draw the console separator
1560 	 *
1561 	 * When there are more messages than can fit on a single screen, the user can
1562 	 * scroll up to see the previous messages. When they do, a separator is
1563 	 * drawn by this function to indicate that more messages follow. The font
1564 	 * category should normally be CHAT_FONT, as it is only used in the console
1565 	 * window.
1566 	 *
1567 	 * \param cat     The font category for the separator
1568 	 * \param x_space Horizontal space to keep free on either side
1569 	 * \param y       Vertical position at which the line should be drawn
1570 	 * \param options Text options for drawing the separator
1571 	 */
draw_console_separator(Category cat,int x_space,int y,const TextDrawOptions & options)1572 	void draw_console_separator(Category cat, int x_space, int y,
1573 		const TextDrawOptions& options)
1574 	{
1575 		TextDrawOptions cat_options = TextDrawOptions(options).scale_zoom(font_scales[cat]);
1576 		get(cat, options.zoom()).draw_console_separator(x_space, y, cat_options);
1577 	}
1578 #ifdef ELC
1579 #ifndef MAP_EDITOR2
draw_ortho_ingame_string(Category cat,const unsigned char * text,size_t len,float x,float y,float z,int max_lines,float zoom_x,float zoom_y)1580 	void draw_ortho_ingame_string(Category cat, const unsigned char* text, size_t len,
1581 		float x, float y, float z, int max_lines, float zoom_x, float zoom_y)
1582 	{
1583 		get(cat, zoom_y).draw_ortho_ingame_string(text, len, x, y, z, max_lines,
1584 			zoom_x * font_scales[cat], zoom_y * font_scales[cat]);
1585 	}
1586 #endif // !MAP_EDITOR_2
1587 #endif // ELC
1588 
1589 	/*!
1590 	 * \brief Set the config font
1591 	 *
1592 	 * Copy the current font index and scale of the UI_FONT category to that
1593 	 * of the CONFIG_FONT category. This allows us to change the UI font
1594 	 * without changing the way the options window is drawn, and hopefully
1595 	 * stops the user from then being unable to change the font back.
1596 	 */
set_config_font()1597 	void set_config_font()
1598 	{
1599 		font_idxs[CONFIG_FONT] = font_idxs[UI_FONT];
1600 		font_scales[CONFIG_FONT] = font_scales[UI_FONT];
1601 	}
1602 
1603 #ifdef TTF
1604 	//! Disable TrueType fonts, allowing bundled fonts only.
1605 	void disable_ttf();
1606 	//! Enable TrueTyoe fonts, restoring previous font indices if possible
1607 	void enable_ttf();
1608 #endif
1609 
1610 private:
1611 	//! The number of fonts bundled with EL itself
1612 	static const size_t _nr_bundled_fonts = 7;
1613 	//! The fonts to use by default for each category
1614 	static const std::array<size_t, NR_FONT_CATS> _default_font_idxs;
1615 
1616 	//! The list of known font options
1617 	std::vector<FontOption> _options;
1618 	//! Map from font number and line height to actual font
1619 	std::unordered_map<uint32_t, Font> _fonts;
1620 	//! Lookup table mapping indices of fixed width fonts to indices in the _fonts array
1621 	std::vector<size_t> _fixed_width_idxs;
1622 #ifdef TTF
1623 	/*!
1624 	 * When disabling TrueType fonts, the current font file names are stored in this
1625 	 * array. If TTF support is enabled again in the same session, they can be
1626 	 * restored again without the user having to search the fonts in the options
1627 	 * window.
1628 	 */
1629 	std::array<std::string, NR_FONT_CATS> _saved_font_files;
1630 #endif
1631 
1632 	/*!
1633 	 * \brief Constructor
1634 	 *
1635 	 * Create a new font manager, without fonts to manage so far.
1636 	 */
FontManager()1637 	FontManager(): _options(), _fonts(), _fixed_width_idxs()
1638 #ifdef TTF
1639 		, _saved_font_files()
1640 #endif
1641 		{}
1642 	// Disallow copying, since this is a singleton class
1643 	FontManager(const FontManager&) = delete;
1644 	FontManager& operator=(const FontManager&) = delete;
1645 
1646 	/*!
1647 	 * \brief Initialize TrueType fonts
1648 	 *
1649 	 * Scan the TTF font directory for TrueType fonts, and add them to the
1650 	 * current list of fonts.
1651 	 */
1652 	void initialize_ttf();
1653 	/*!
1654 	 * \brief Scan for TrueType fonts
1655 	 *
1656 	 * Scan for files matching the glob pattern \a pattern, and if they contain
1657 	 * a TTF font that supports our character set, add it to our list of known
1658 	 * fonts.
1659 	 *
1660 	 * \param pattern A glob pattern defining the search path
1661 	 */
1662 	 void add_ttf_from_pattern(const std::string& pattern);
1663 
1664 	/*!
1665 	 * \brief Add options to the configuration
1666 	 *
1667 	 * Add options for all fonts to the multi-select variables in the
1668 	 * configuration window. If the optional parameter \a add_button i \c true,
1669 	 * buttons for the fonts will immediately be added to the corresponding
1670 	 * widget.
1671 	 */
1672 	void add_select_options(bool add_button=false);
1673 
1674 	/*!
1675 	 * \brief Load a font.
1676 	 *
1677 	 * Get the font for font category \a cat and text scale factor \a zoom. If this font fails to
1678 	 * load, switch to fixed font 1.
1679 	 *
1680 	 * \param cat       The font category for which to load a font.
1681 	 * \param text_zoom The scale factor for the text
1682 	 * \return Reference to the font itself.
1683 	 */
1684 	Font& get(Category cat, float text_zoom);
1685 };
1686 
1687 } // namespace eternal_lands
1688 
1689 #endif // __cplusplus
1690 
1691 #ifdef __cplusplus
1692 extern "C"
1693 {
1694 #endif
1695 
1696 //! The font numbers for each font category
1697 extern size_t *font_idxs;
1698 //! The zoom factor for each font category
1699 extern float *font_scales;
1700 
1701 #ifdef TTF
1702 #define TTF_DIR_SIZE 256
1703 
1704 //! Flag indicating whether to use TTF fonts or not
1705 extern int use_ttf;
1706 //! The path to search for TrueType fonts
1707 extern char ttf_directory[TTF_DIR_SIZE];
1708 #endif // TTF
1709 
1710 /*!
1711  * \ingroup text_font
1712  * \brief Initialize the font manager.
1713  *
1714  * This adds the standard fonts bundled with EL to the font manager, and
1715  * if TTF fonts are enabled, scans the TTF path for True Type fonts
1716  * to add as well.
1717  */
1718 int initialize_fonts();
1719 
1720 /*!
1721  * \ingroup text_font
1722  * \brief Return the font number of a fixed width font
1723  *
1724  * Return the font number for the \a idx'th fixed width font.
1725  *
1726  * \param idx The number of the font in the list of fixed width fonts only
1727  * \return The index of the font in the list of all fonts
1728  */
1729 size_t get_fixed_width_font_number(size_t idx);
1730 
1731 /*!
1732  * \ingroup text_font
1733  * \brief The width of a single character
1734  *
1735  * Return the width of character \a c, including spacing, when drawn
1736  * in the font for category \a cat, at zoom level \a text_zoom.
1737  *
1738  * \param c         The character for which to get the width
1739  * \param cat       The font category for the font used
1740  * \param text_zoom The scale factor for the text
1741  * \return The width of the character and spacing, in pixels.
1742  */
1743 int get_char_width_zoom(unsigned char c, font_cat cat, float text_zoom);
1744 /*!
1745  * \ingroup text_font
1746  * \brief The maximum width of a single character
1747  *
1748  * Return the maximum a single character can occupy when drawn in the font
1749  * for category \a cat at zoom level \a text_zoom, and include the spacing
1750  * between characters.
1751  *
1752  * \param cat       The font category for the font used
1753  * \param text_zoom The scale factor for the text
1754  * \return The maximum character width incuding spacing, in pixels.
1755  */
1756 int get_max_char_width_zoom(font_cat cat, float text_zoom);
1757 /*!
1758  * \ingroup text_font
1759  * \brief Get the average character width, plus spacing
1760  *
1761  * Get an approximation to the average width of a character in the font for
1762  * category \a cat when drawn at zoom level \a text_zoom, including the space
1763  * between characters, for some definition of "average". See the note
1764  * in eternal_lands::Font::average_width_spacing() for some caveats when using
1765  * this function.
1766  *
1767  * \param cat       The font category for the font used
1768  * \param text_zoom The zoom factor for drawing the character.
1769  * \return The maximum width of a character including spacing, in pixels.
1770  */
1771 int get_avg_char_width_zoom(font_cat cat, float text_zoom);
1772 /*!
1773  * \ingroup text_font
1774  * \brief The maximum width of a single digit character
1775  *
1776  * Return the maximum a single digit character (0-9) can occupy when drawn
1777  * in the font for category \a cat at zoom level \a text_zoom, and include
1778  * the spacing between characters.
1779  *
1780  * \param cat       The font category for the font used
1781  * \param text_zoom The scale factor for the text
1782  * \return The maximum digit character width incuding spacing, in pixels.
1783  */
1784 int get_max_digit_width_zoom(font_cat cat, float text_zoom);
1785 /*!
1786  * \ingroup text_font
1787  * \brief The maximum width of a single name character
1788  *
1789  * Return the maximum pen advancement for a single name character ('0'-'9', 'a'-'z', 'A'-'Z', or '_')
1790  * when drawn in the font for category \a cat at zoom level \a text_zoom, and include the
1791  * spacing between characters.
1792  *
1793  * \param cat       The font category for the font used
1794  * \param text_zoom The scale factor for the text
1795  * \return The maximum name character width incuding spacing, in pixels.
1796  */
1797 int get_max_name_width_zoom(font_cat cat, float text_zoom);
1798 /*!
1799  * \ingroup text_font
1800  * \brief Calculate the width of a string
1801  *
1802  * Calculate the width in pixels of the string \a text of length \a len
1803  * when drawn in the font for category \a cat at zoom level \a text_zoom.
1804  * \note This function assumes the string is a single line. Newline
1805  * characters are ignored, and having them in the middle of string will
1806  * result in a too large value for the width.
1807  *
1808  * \param cat       The font category for the font used
1809  * \param text      The string for which to calculate the length
1810  * \param len       The number of bytes in \a text
1811  * \param text_zoom The scale factor for the text
1812  * \return The width of the text in pixels
1813  */
1814 int get_buf_width_zoom(const unsigned char* text, size_t len, font_cat cat, float text_zoom);
1815 /*!
1816  * \ingroup text_font
1817  * \brief Calculate the width of a string
1818  *
1819  * Calculate the width in pixels of the nul-terminated string \a text
1820  * when drawn in the font for category \a cat at zoom level \a text_zoom.
1821  * \note This function assumes the string is a single line. Newline
1822  * characters are ignored, and having them in the middle of string will
1823  * result in a too large value for the width.
1824  *
1825  * \param cat       The font category for the font used
1826  * \param text      The string for which to calculate the length
1827  * \param text_zoom The scale factor for the text
1828  * \return The width of the text in pixels
1829  */
get_string_width_zoom(const unsigned char * str,font_cat cat,float text_zoom)1830 static __inline__ int get_string_width_zoom(const unsigned char* str, font_cat cat,
1831 	float text_zoom)
1832 {
1833 	return get_buf_width_zoom(str, strlen((const char*)str), cat, text_zoom);
1834 }
1835 /*!
1836  * \ingroup text_font
1837  * \brief The height of a text line
1838  *
1839  * Return the height of a line of text when drawn in the font for category
1840  * \a cat with scale factor \a text_zoom.
1841  *
1842  * \param cat       The font category for the font used
1843  * \param text_zoom The scale factor for the text
1844  * \return The height of the text in pixels
1845  */
1846 int get_line_height(font_cat cat, float text_zoom);
1847 /*!
1848  * \ingroup text_font
1849  * \brief The distance between two lines
1850  *
1851  * Return the distance between two lines of text when drawn in the font for category
1852  * \a cat with scale factor \a text_zoom. This is not necessarily the same as the line
1853  * height.
1854  *
1855  * \param cat       The font category for the font used
1856  * \param text_zoom The scale factor for the text
1857  * \return The line distance
1858  */
1859 int get_line_skip(font_cat cat, float text_zoom);
1860 /*!
1861  * \brief Calculate the number of lines that fit.
1862  *
1863  * Return the maximum number of lines that fit in a window of \a height pixels high, when drawing
1864  * text in the font for category \a cat at zoom level \a zoom.
1865  *
1866  * \param max_height The maximum height of the text in pixels
1867  * \param cat        The font category for the font used
1868  * \param zoom       The zoom factor for drawing the text
1869  * \return The maximum number of lines that fit
1870  */
1871 int get_max_nr_lines(int max_height, font_cat cat, float zoom);
1872 /*!
1873  * \brief Compute the height of a block of text
1874  *
1875  * Compute the height of a block of text of \a nr_lines lines, when drawn in the font for category
1876  * \a cat at zoom level \a zoom.
1877  *
1878  * \param nr_lines The number of lines in the text
1879  * \param cat      The font category for the font used
1880  * \param zoom     The zoom factor for drawing the text
1881  * \return The height of the text in pixels
1882  */
1883 int get_text_height(int nr_lines, font_cat cat, float zoom);
1884 /*!
1885  * \ingroup text_font
1886  * \brief Calculate the dimensions of a block of text
1887  *
1888  * Calculate the width and height of string \a text of length \a len bytes
1889  * when drawn in the font for category \a cat, with scale factor \a zoom.
1890  * The string may contain multiple lines, the width returned is then the
1891  * width of the widest line.
1892  *
1893  * \param cat       The font category for the font used
1894  * \param text      The string for which to compute the dimensions
1895  * \param len       The number of bytes in \a text
1896  * \param text_zoom The scale factor for the text
1897  * \param width     Place to store the calculated width
1898  * \param height    Place to store the calculated height
1899  */
1900 void get_buf_dimensions(const unsigned char* text, size_t len, font_cat cat,
1901 	float text_zoom, int *width, int *height);
1902 
1903 /*!
1904  * \brief Calculate vertical offset of center
1905  *
1906  * Calculate the offset of the center of the characters in \a text with respect to the center
1907  * of the line, when drawn in the font for category \a cat at zoom level \a text_zoom. Subtract the
1908  * result of this function from the \c y coordinate you wish to center around, to center the
1909  * content of \a text around this position.
1910  *
1911  * \param cat       The font category for the font used
1912  * \param text      The string for which to compute center offset
1913  * \param len       The number of bytes in \a text
1914  * \param text_zoom The scale factor for the text
1915  * \return The number of pixels between the center of the line and the center of \a text.
1916  */
1917 int get_center_offset(const unsigned char* text, size_t len, font_cat cat, float text_zoom);
1918 /*!
1919  * \brief Get vertical coordinates
1920  *
1921  * Get the minimum and maximum offsets of the characters in \a text with respect to the top of
1922  * the text line, when drawing the text in the font for category \a cat at zoom level \a zoom.
1923  *
1924  * \param text      The text to get the vertical offsets for
1925  * \param len       The number of characters in \a text
1926  * \param cat       The font category for the font used
1927  * \param text_zoom The scale factor for the text
1928  * \return The offsets of the top and bottom of the text
1929  */
1930 void get_top_bottom(const unsigned char* text, size_t len, font_cat cat, float text_zoom,
1931 	int *top, int *bottom);
1932 
1933 /*!
1934  * \ingroup text_font
1935  * \brief Recompute where the line breaks in a string should occur
1936  *
1937  * Recomputes the positions in string \a text where line breaks should be placed,
1938  * when drawn in the font for category \a cat at zoom level \a text_zoom such
1939  * that the string fits into a window of width \a width pixels. This inserts
1940  * \c '\\r' characters at the positions in \a text where the line should be broken.
1941  * Parameters \a len and \a size are the current and maximum number of bytes in \a text,
1942  * respectively. If \a cursor is not \c NULL, it should point to the offset of the
1943  * cursor position in the text; it will be updated as new line breaks are inserted.
1944  * If \a max_line_width is not \c NULL, it can be used to retrieve the largest width
1945  * in pixels of the lines in \a text after rewrapping.
1946  *
1947  * \param text           the string
1948  * \param len            the actual length of the string
1949  * \param size           the maximum number of bytes in \a text
1950  * \param cat            the font category in which the string is to be drawn
1951  * \param text_zoom      the scale factor for the text
1952  * \param width          the allowed width of a line of text
1953  * \param cursor         pointer to the cursor position, or NULL if not used
1954  * \param max_line_width pointer the maximum line length after wrapping, or NULL if not used
1955  *
1956  * \return The wrapped text, and the new number of lines in the text
1957  */
1958 int reset_soft_breaks(unsigned char *text, int len, int size, font_cat cat,
1959 	float text_zoom, int width, int *cursor, int *max_line_width);
1960 /*!
1961  * \ingroup text_font
1962  * \brief Wrap a text so that it fits into a window
1963  *
1964  * Create a version of \a text with newline characters inserted so that the
1965  * line length does not exceeed \a width pixels when drawn in a small font for
1966  * the UI_FONT category, at zoom level \a zoom, and store it in \a buffer. The
1967  * parameter \a color is an index in colors_list; it will be converted to a
1968  * color character which is inserted in front of the text in \a buffer.
1969  * \warning No check is made if \a buffer is large enough to hold the output
1970  * text, the caller needs to ensure this.
1971  *
1972  * \param color     The color with which the text should be drawn
1973  * \param text      The text to wrap
1974  * \param len       The number of bytes in text
1975  * \param width     The maximum allowed width in pixels of a line of text
1976  * \param buffer    Output buffer in which the result is stored
1977  * \param text_zoom Zoom factor for the text (on top of using small text)
1978  */
1979 void put_small_colored_text_in_box_zoomed(int color,
1980 	const unsigned char* text, int len, int width,
1981 	unsigned char* buffer, float text_zoom);
1982 /*!
1983  * \ingroup text_font
1984  * \brief Wrap a text so that it fits into a window
1985  *
1986  * Create a version of \a text with newline characters inserted so that the
1987  * line length does not exceeed \a width pixels when drawn in a small font for
1988  * the UI_FONT category, at zoom level \a zoom, and store it in \a buffer. The
1989  * text will be drawn in white.
1990  * \warning No check is made if \a buffer is large enough to hold the output
1991  * text, the caller needs to ensure this.
1992  *
1993  * \param text      The text to wrap
1994  * \param len       The number of bytes in text
1995  * \param width     The maximum allowed width in pixels of a line of text
1996  * \param buffer    Output buffer in which the result is stored
1997  * \param text_zoom Zoom factor for the text (on top of using small text)
1998  */
put_small_text_in_box_zoomed(const unsigned char * text,int len,int width,unsigned char * buffer,float text_zoom)1999 static __inline__ void put_small_text_in_box_zoomed (const unsigned char* text,
2000 	int len, int width, unsigned char* buffer, float text_zoom)
2001 {
2002 	put_small_colored_text_in_box_zoomed(c_grey1, text, len, width, buffer, text_zoom);
2003 }
2004 
2005 /*!
2006  * \ingroup text_font
2007  * \brief Enumeration for text drawing options
2008  *
2009  * Various text drawing options can be passed to \ref draw text, specified by a selector from this
2010  * enumeration followed by one or more arguments.
2011  */
2012 typedef enum
2013 {
2014 	//! Set the maximum width, followed by \c int
2015 	TDO_MAX_WIDTH,
2016 	//! Set the maximum number of lines, followed by \c int
2017 	TDO_MAX_LINES,
2018 	//! Scale factor for the text, followed by \c float
2019 	TDO_ZOOM,
2020 	//! Scale factor for the spacing between lines, followed by \c float
2021 	TDO_LINE_SPACING,
2022 	//! Horizontal alignment, followed by a \c hor_alignment
2023 	TDO_ALIGNMENT,
2024 	//! Vertical alignment, followed by a \c ver_alignment
2025 	TDO_VERTICAL_ALIGNMENT,
2026 	//! Draw the text with a shadow in the background color, followed by \c bool
2027 	TDO_SHADOW,
2028 	//! Foreground color of the text, followed by 3 \c floats
2029 	TDO_FOREGROUND,
2030 	//! Background color of the text, followed by 3 \c floats
2031 	TDO_BACKGROUND,
2032 	//! Selection color of the text, followed by 3 \c floats
2033 	TDO_SELECTION,
2034 	//! Ignor color characters in the text, followed by \c bool
2035 	TDO_IGNORE_COLOR,
2036 	//! Draw the string as help text, with a semi-transparent background, followed by \c bool
2037 	TDO_HELP,
2038 	//! Indicate clipped text with ellipsis, followed by \c bool
2039 	TDO_ELLIPSIS,
2040 	//! Shrink text if it is too wide, followed by \a bool
2041 	TDO_SHRINK_TO_FIT,
2042 	//! Start index of the selected text, followed by \c int
2043 	TDO_SEL_BEGIN,
2044 	//! End index of the selected text, followed by \c int
2045 	TDO_SEL_END,
2046 	//! End of text draw options, should always be last
2047 	TDO_END
2048 } text_draw_option_sel;
2049 
2050 /*!
2051  * \ingroup text_font
2052  * \brief Draw a text string
2053  *
2054  * Draw the text in the first \a len bytes of \a text, starting at position \a x, \a y on the
2055  * screen, using the font for category \a cat, with formatting options \a options. The options
2056  * should be a (possbily empty) list of option selectors of type \ref text_draw_option_sel, each
2057  * followed by the arguments for that particular selector, and should end with \ref TDO_END.
2058  *
2059  * \param x         The left coordinate of the drawn text
2060  * \param y         The top coordinate of the drawn text
2061  * \param text      The text to draw
2062  * \param len       The number of bytes in \a text
2063  * \param cat       The font category for the text
2064  * \param options   Formatting options for the text
2065  */
2066 void vdraw_text(int x, int y, const unsigned char* text, size_t len, font_cat cat, va_list options);
2067 /*!
2068  * \ingroup text_font
2069  * \brief Draw a text string
2070  *
2071  * Draw the text in the first \a len bytes of \a text, starting at position \a x, \a y on the
2072  * screen, using the font for category \a cat, with formatting options \a options. Formatting
2073  * options for the text can be given after \a cat; the list of formatting options should always
2074  * end with \ref TDO_END.
2075  * \note Even when no formatting options are given, \ref TDO_END should be passed as the only
2076  * extra parameter to indicate the end of the options list.
2077  *
2078  * \param x         The left coordinate of the drawn text
2079  * \param y         The top coordinate of the drawn text
2080  * \param text      The text to draw
2081  * \param len       The number of bytes in \a text
2082  * \param cat       The font category for the text
2083  * \param options   Formatting options for the text
2084  * \note The type of \a cat is \c int here instead of \c font_cat. This is on purpose, as using a
2085  * type that undergoes default argument promotion as the last argument before the variable
2086  * argument list results in undefined behaviour.
2087  */
draw_text(int x,int y,const unsigned char * text,size_t len,int cat,...)2088 static __inline__ void draw_text(int x, int y, const unsigned char* text, size_t len, int cat, ...)
2089 {
2090 	va_list ap;
2091 	va_start(ap, cat);
2092 	vdraw_text(x, y, text, len, (font_cat)cat, ap);
2093 	va_end(ap);
2094 }
2095 
2096 /*!
2097  * \ingroup text_font
2098  * \brief Draw a text string
2099  *
2100  * Draw the text in the nul-terminated buffer \a text, starting at position
2101  * \a x, \a y on the screen, using the font for category \a cat. Options \a max_width and
2102  * \a max_lines specify the maximum width of the text and maximum number of lines
2103  * drawn respectively. Text outside these boundaries will not be drawn. The text
2104  * will be drawn in the default foreground color.
2105  *
2106  * \param x         The left coordinate of the drawn text
2107  * \param y         The top coordinate of the drawn text
2108  * \param text      The text to draw
2109  * \param max_width The maximum width in pixels of the text
2110  * \param max_lines The maximum number of lines to draw, or 0 for no limit
2111  * \param cat       The font category for the text
2112  * \param text_zoom Scale factor for the text size
2113  */
draw_string_zoomed_width_font(int x,int y,const unsigned char * text,int max_width,int max_lines,font_cat cat,float text_zoom)2114 static __inline__ void draw_string_zoomed_width_font(int x, int y, const unsigned char *text,
2115 	int max_width, int max_lines, font_cat cat, float text_zoom)
2116 {
2117 	draw_text(x, y, text, strlen((const char*)text), cat, TDO_MAX_WIDTH, max_width,
2118 		TDO_MAX_LINES, max_lines, TDO_ZOOM, text_zoom, TDO_END);
2119 }
2120 /*!
2121  * \ingroup text_font
2122  * \brief Draw a text string
2123  *
2124  * Draw the text in the nul-terminated buffer \a text, centered around position
2125  * \a x, \a y on the screen, using the font for the UI_FONT category. The centering is
2126  * done such that the bytes up to \a center_idx are drawn left of \a x, and the
2127  * bytes from \a center_idx onward are drawn to the right of \a x.
2128  *
2129  * \param x          The x coordinate of the center of drawn text
2130  * \param y          The top coordinate of the drawn text
2131  * \param text       The text to draw
2132  * \param center_idx The index of the character around which the centering is done
2133  * \param text_zoom  Scale factor for the text size
2134  */
2135 void draw_string_zoomed_centered_around(int x, int y, const unsigned char *text, int center_idx,
2136 	float text_zoom);
2137 /*!
2138  * \ingroup text_font
2139  * \brief Draw a text string
2140  *
2141  * Draw the text in the nul-terminated buffer \a text, starting at position
2142  * \a x, \a y on the screen, using the font for the UI_FONT category. The option
2143  * \a max_lines specifies the maximum number of lines drawn, any text after
2144  * this line will not be drawn. The text will be drawn in the default foreground
2145  * color.
2146  *
2147  * \param x         The left coordinate of the drawn text
2148  * \param y         The top coordinate of the drawn text
2149  * \param text      The text to draw
2150  * \param max_lines The maximum number of lines to draw, or 0 for no limit
2151  * \param text_zoom Scale factor for the text size
2152  */
draw_string_zoomed(int x,int y,const unsigned char * text,int max_lines,float text_zoom)2153 static __inline__ void draw_string_zoomed(int x, int y, const unsigned char* text,
2154 	int max_lines, float text_zoom)
2155 {
2156 	draw_text(x, y, text, strlen((const char*)text), UI_FONT, TDO_MAX_LINES, max_lines,
2157 		TDO_ZOOM, text_zoom, TDO_END);
2158 }
2159 /*!
2160  * \ingroup text_font
2161  * \brief Draw a text string
2162  *
2163  * Draw the text in the nul-terminated buffer \a text, centered around position
2164  * \a x, \a y on the screen, using the font for the UI_FONT category. The option
2165  * \a max_lines specifies the maximum number of lines drawn, any text after
2166  * this line will not be drawn. The text will be drawn in the default foreground
2167  * color.
2168  *
2169  * \param x         The x coordinate of the center of drawn text
2170  * \param y         The top coordinate of the drawn text
2171  * \param text      The text to draw
2172  * \param max_lines The maximum number of lines to draw, or 0 for no limit
2173  * \param text_zoom Scale factor for the text size
2174  */
draw_string_zoomed_centered(int x,int y,const unsigned char * text,int max_lines,float text_zoom)2175 static __inline__ void draw_string_zoomed_centered(int x, int y, const unsigned char *text,
2176 	int max_lines, float text_zoom)
2177 {
2178 	draw_text(x, y, text, strlen((const char*)text), UI_FONT, TDO_MAX_LINES, max_lines,
2179 		TDO_ZOOM, text_zoom, TDO_ALIGNMENT, CENTER, TDO_END);
2180 }
2181 /*!
2182  * \ingroup text_font
2183  * \brief Draw a text string
2184  *
2185  * Draw the text in the nul-terminated buffer \a text, starting at position
2186  * \a x, \a y on the screen, using the font for the UI_FONT category. The string
2187  * is drawn in the color (\a fr, \a fg, \a fb), with a background shadow in
2188  * the color (\a br, \a bg, \a bb). The option \a max_lines specifies the maximum
2189  * number of lines drawn, any text after this line will not be drawn.
2190  *
2191  *
2192  * \param x         The left coordinate of the drawn text
2193  * \param y         The top coordinate of the drawn text
2194  * \param text      The text to draw
2195  * \param max_lines The maximum number of lines to draw, or 0 for no limit
2196  * \param fr        Red component of the foreground color
2197  * \param fg        Green component of the foreground color
2198  * \param fb        Blue component of the foreground color
2199  * \param br        Red component of the background color
2200  * \param bg        Green component of the background color
2201  * \param bb        Blue component of the background color
2202  * \param text_zoom Scale factor for the text size
2203  */
draw_string_shadowed_zoomed(int x,int y,const unsigned char * text,int max_lines,float fr,float fg,float fb,float br,float bg,float bb,float text_zoom)2204 static __inline__ void draw_string_shadowed_zoomed(int x, int y, const unsigned char* text,
2205 	int max_lines, float fr, float fg, float fb, float br, float bg, float bb, float text_zoom)
2206 {
2207 	draw_text(x, y, text, strlen((const char*)text), UI_FONT, TDO_MAX_LINES, max_lines,
2208 		TDO_SHADOW, 1, TDO_FOREGROUND, fr, fg, fb, TDO_BACKGROUND, br, bg, bb, TDO_ZOOM, text_zoom,
2209 		TDO_END);
2210 }
2211 /*!
2212  * \ingroup text_font
2213  * \brief Draw a text string
2214  *
2215  * Draw the text in the nul-terminated buffer \a text, centered around position
2216  * \a x, \a y on the screen, using the font for the UI_FONT category. The string
2217  * is drawn in the color (\a fr, \a fg, \a fb), with a background shadow in
2218  * the color (\a br, \a bg, \a bb). The option \a max_lines specifies the maximum
2219  * number of lines drawn, any text after this line will not be drawn.
2220  *
2221  *
2222  * \param x         The x coordinate of the center of drawn text
2223  * \param y         The top coordinate of the drawn text
2224  * \param text      The text to draw
2225  * \param max_lines The maximum number of lines to draw, or 0 for no limit
2226  * \param fr        Red component of the foreground color
2227  * \param fg        Green component of the foreground color
2228  * \param fb        Blue component of the foreground color
2229  * \param br        Red component of the background color
2230  * \param bg        Green component of the background color
2231  * \param bb        Blue component of the background color
2232  * \param text_zoom Scale factor for the text size
2233  */
draw_string_shadowed_zoomed_centered(int x,int y,const unsigned char * text,int max_lines,float fr,float fg,float fb,float br,float bg,float bb,float text_zoom)2234 static __inline__ void draw_string_shadowed_zoomed_centered(int x, int y, const unsigned char* text,
2235 	int max_lines, float fr, float fg, float fb, float br, float bg, float bb, float text_zoom)
2236 {
2237 	draw_text(x, y, text, strlen((const char*)text), UI_FONT, TDO_MAX_LINES, max_lines,
2238 		TDO_SHADOW, 1, TDO_FOREGROUND, fr, fg, fb, TDO_BACKGROUND, br, bg, bb, TDO_ZOOM, text_zoom,
2239 		TDO_ALIGNMENT, CENTER, TDO_END);
2240 }
2241 /*!
2242  * \ingroup text_font
2243  * \brief Draw a text string
2244  *
2245  * Draw the text in the nul-terminated buffer \a text, starting at position
2246  * \a x, \a y on the screen, using the font for category \a cat. If a line
2247  * cannot fit within the maximum width \a max_width, it will be truncated and
2248  * an ellipsis is added. The option \a max_lines specifies the maximum
2249  * number of lines drawn, any text after this line will not be drawn.
2250  *
2251  * \param x         The left coordinate of the drawn text
2252  * \param y         The top coordinate of the drawn text
2253  * \param text      The text to draw
2254  * \param max_width The maximum width in pixels of the text
2255  * \param max_lines The maximum number of lines to draw, or 0 for no limit
2256  * \param cat       The font category for the text
2257  * \param text_zoom Scale factor for the text size
2258  */
draw_string_zoomed_ellipsis_font(int x,int y,const unsigned char * text,int max_width,int max_lines,font_cat cat,float text_zoom)2259 static __inline__ void draw_string_zoomed_ellipsis_font(int x, int y, const unsigned char *text,
2260 	int max_width, int max_lines, font_cat cat, float text_zoom)
2261 {
2262 	draw_text(x, y, text, strlen((const char*)text), cat, TDO_MAX_WIDTH, max_width,
2263 		TDO_MAX_LINES, max_lines, TDO_ZOOM, text_zoom, TDO_ELLIPSIS, 1, TDO_END);
2264 }
2265 
2266 //! Analogue of draw_string_zoomed(), for small text size
draw_string_small_zoomed(int x,int y,const unsigned char * text,int max_lines,float text_zoom)2267 static __inline__ void draw_string_small_zoomed(int x, int y,
2268 	const unsigned char* text, int max_lines, float text_zoom)
2269 {
2270 	draw_text(x, y, text, strlen((const char*)text), UI_FONT, TDO_MAX_LINES, max_lines,
2271 		TDO_ZOOM, text_zoom * DEFAULT_SMALL_RATIO, TDO_END);
2272 }
2273 /*!
2274  * \ingroup text_font
2275  * \brief Draw a text string
2276  *
2277  * Draw the text in the nul-terminated buffer \a text, right aligned to position
2278  * \a x, \a y on the screen, using the small font for the UI_FONT category. The option
2279  * \a max_lines specifies the maximum number of lines drawn, any text after
2280  * this line will not be drawn. The text will be drawn in the default foreground
2281  * color.
2282  *
2283  * \param x         The right coordinate of the drawn text
2284  * \param y         The top coordinate of the drawn text
2285  * \param text      The text to draw
2286  * \param max_lines The maximum number of lines to draw, or 0 for no limit
2287  * \param text_zoom Scale factor for the text size
2288  */
draw_string_small_zoomed_right(int x,int y,const unsigned char * text,int max_lines,float text_zoom)2289 static __inline__ void draw_string_small_zoomed_right(int x, int y,
2290 	const unsigned char* text, int max_lines, float text_zoom)
2291 {
2292 	draw_text(x, y, text, strlen((const char*)text), UI_FONT, TDO_MAX_LINES, max_lines,
2293 		TDO_ZOOM, text_zoom * DEFAULT_SMALL_RATIO, TDO_ALIGNMENT, RIGHT, TDO_END);
2294 }
2295 //! Analogue of draw_string_zoomed_centered(), for small text size
draw_string_small_zoomed_centered(int x,int y,const unsigned char * text,int max_lines,float text_zoom)2296 static __inline__ void draw_string_small_zoomed_centered(int x, int y,
2297 	const unsigned char* text, int max_lines, float text_zoom)
2298 {
2299 	draw_text(x, y, text, strlen((const char*)text), UI_FONT, TDO_MAX_LINES, max_lines,
2300 		TDO_ZOOM, text_zoom * DEFAULT_SMALL_RATIO, TDO_ALIGNMENT, CENTER, TDO_END);
2301 }
2302 //! Analogue of draw_string_zoomed_centered_around(), for small text size
draw_string_small_zoomed_centered_around(int x,int y,const unsigned char * text,int center_idx,float text_zoom)2303 static __inline__ void draw_string_small_zoomed_centered_around(int x, int y,
2304 	const unsigned char *text, int center_idx, float text_zoom)
2305 {
2306 	draw_string_zoomed_centered_around(x, y, text, center_idx, text_zoom * DEFAULT_SMALL_RATIO);
2307 }
2308 //! Analogue of draw_string_shadowed_zoomed(), for small text size
draw_string_small_shadowed_zoomed(int x,int y,const unsigned char * text,int max_lines,float fr,float fg,float fb,float br,float bg,float bb,float text_zoom)2309 static __inline__ void draw_string_small_shadowed_zoomed(int x, int y,
2310 	const unsigned char* text, int max_lines, float fr, float fg, float fb,
2311 	float br, float bg, float bb, float text_zoom)
2312 {
2313 	draw_text(x, y, text, strlen((const char*)text), UI_FONT, TDO_MAX_LINES, max_lines,
2314 		TDO_SHADOW, 1, TDO_FOREGROUND, fr, fg, fb, TDO_BACKGROUND, br, bg, bb,
2315 		TDO_ZOOM, text_zoom * DEFAULT_SMALL_RATIO, TDO_END);
2316 }
2317 /*!
2318  * \ingroup text_font
2319  * \brief Draw a text string
2320  *
2321  * Draw the text in the nul-terminated buffer \a text, right aligned to position
2322  * \a x, \a y on the screen, using the small font for the UI_FONT category. The string
2323  * is drawn in the color (\a fr, \a fg, \a fb), with a background shadow in
2324  * the color (\a br, \a bg, \a bb). The option \a max_lines specifies the maximum
2325  * number of lines drawn, any text after this line will not be drawn.
2326  *
2327  *
2328  * \param x         The right coordinate of the drawn text
2329  * \param y         The top coordinate of the drawn text
2330  * \param text      The text to draw
2331  * \param max_lines The maximum number of lines to draw, or 0 for no limit
2332  * \param fr        Red component of the foreground color
2333  * \param fg        Green component of the foreground color
2334  * \param fb        Blue component of the foreground color
2335  * \param br        Red component of the background color
2336  * \param bg        Green component of the background color
2337  * \param bb        Blue component of the background color
2338  * \param text_zoom Scale factor for the text size
2339  */
draw_string_small_shadowed_zoomed_right(int x,int y,const unsigned char * text,int max_lines,float fr,float fg,float fb,float br,float bg,float bb,float text_zoom)2340 static __inline__ void draw_string_small_shadowed_zoomed_right(int x, int y,
2341 	const unsigned char* text, int max_lines, float fr, float fg, float fb,
2342 	float br, float bg, float bb, float text_zoom)
2343 {
2344 	draw_text(x, y, text, strlen((const char*)text), UI_FONT, TDO_MAX_LINES, max_lines,
2345 		TDO_SHADOW, 1, TDO_FOREGROUND, fr, fg, fb, TDO_BACKGROUND, br, bg, bb,
2346 		TDO_ZOOM, text_zoom * DEFAULT_SMALL_RATIO, TDO_ALIGNMENT, RIGHT, TDO_END);
2347 }
2348 
2349 /*!
2350  * \ingroup text_font
2351  * \brief Draw a help message
2352  *
2353  * Shows the help message \a text centered horizontally around position
2354  * (\a x, \a y) in text color (\a r, \a g, \a b), with text scale factor
2355  * \a text_zoom. The message is drawn on a semi-transparent background.
2356  *
2357  * \param text      The help text to display
2358  * \param x         The x-coordinate of the center of the text
2359  * \param y         The y-coordinate of the top of text text
2360  * \param r         The red component of the text color
2361  * \param g         The green component of the text color
2362  * \param b         The blue component of the text color
2363  * \param text_zoom The scale factor for the text size
2364  */
show_help_colored_scaled_centered(const unsigned char * text,int x,int y,float r,float g,float b,float text_zoom)2365 static __inline__ void show_help_colored_scaled_centered(const unsigned char *text, int x, int y,
2366 	float r, float g, float b, float text_zoom)
2367 {
2368 	draw_text(x, y, text, strlen((const char*)text), UI_FONT, TDO_MAX_WIDTH, window_width - 80,
2369 		TDO_HELP, 1, TDO_FOREGROUND, r, g, b, TDO_ZOOM, text_zoom, TDO_ALIGNMENT, CENTER, TDO_END);
2370 }
2371 /*!
2372  * \ingroup text_font
2373  * \brief Draw a help message
2374  *
2375  * Shows the help message \a text right-aligned to position (\a x, \a y)
2376  * in text color (\a r, \a g, \a b), with text scale factor \a text_zoom.
2377  * The message is drawn on a semi-transparent background.
2378  *
2379  * \param text      The help text to display
2380  * \param x         The x-coordinate of the right side of the text
2381  * \param y         The y-coordinate of the top of text text
2382  * \param r         The red component of the text color
2383  * \param g         The green component of the text color
2384  * \param b         The blue component of the text color
2385  * \param text_zoom The scale factor for the text size
2386  */
show_help_colored_scaled_right(const unsigned char * text,int x,int y,float r,float g,float b,float text_zoom)2387 static __inline__ void show_help_colored_scaled_right(const unsigned char *text, int x, int y,
2388 	float r, float g, float b, float text_zoom)
2389 {
2390 	draw_text(x, y, text, strlen((const char*)text), UI_FONT, TDO_MAX_WIDTH, window_width - 80,
2391 		TDO_HELP, 1, TDO_FOREGROUND, r, g, b, TDO_ZOOM, text_zoom, TDO_ALIGNMENT, RIGHT, TDO_END);
2392 }
2393 /*!
2394  * \ingroup text_font
2395  * \brief Shows a help message in small font
2396  *
2397  * Shows the help message \a text at position (\a x, \a y) using a small font
2398  * size. The message is drawn on a semi-transparent background.
2399  *
2400  * \param text      the help message to show
2401  * \param x         the x coordinate of the left of the help message
2402  * \param y         the y coordinate of the top of the help message
2403  * \param text_zoom the scale for the text size
2404  */
show_help(const char * text,int x,int y,float text_zoom)2405 static __inline__ void show_help(const char *text, int x, int y, float text_zoom)
2406 {
2407 	draw_text(x, y, (const unsigned char*)text, strlen(text), UI_FONT,
2408 		TDO_MAX_WIDTH, window_width - 80, TDO_HELP, 1, TDO_FOREGROUND, 1.0, 1.0, 1.0,
2409 		TDO_ZOOM, text_zoom * DEFAULT_SMALL_RATIO, TDO_END);
2410 }
2411 /*!
2412  * \ingroup text_font
2413  * \brief Shows a help message in normal font
2414  *
2415  * Shows the help message \a text at position (\a x, \a y) using the normal
2416  * font size. The message is drawn on a semi-transparent background.
2417  *
2418  * \param text      the help message to show
2419  * \param x         the x coordinate of the left of the help message
2420  * \param y         the y coordinate of top of the help message
2421  * \param text_zoom the scale for the text size
2422  */
show_help_big(const char * text,int x,int y,float text_zoom)2423 static __inline__ void show_help_big(const char *text, int x, int y, float text_zoom)
2424 {
2425 	draw_text(x, y, (const unsigned char*)text, strlen(text), UI_FONT,
2426 		TDO_MAX_WIDTH, window_width - 80,TDO_HELP, 1, TDO_FOREGROUND, 1.0, 1.0, 1.0,
2427 		TDO_ZOOM, text_zoom, TDO_END);
2428 }
2429 
2430 /*!
2431  * \ingroup text_font
2432  * \brief Draw messages in a buffer to the screen
2433  *
2434  * Draws the messages in buffer \a msgs to the screen, starting with character
2435  * \a offset_start in message number \a msg_start.
2436  *
2437  * \param x            x coordinate of the position to start drawing
2438  * \param y            y coordinate of the position to start drawing
2439  * \param msgs         the message buffer
2440  * \param msgs_size    the total number of messages that \a msgs can hold
2441  * \param filter       draw only messages in channel \a filter. Choose
2442  * 	FILTER_ALL for displaying all messages
2443  * \param msg_start    index of the first message to display
2444  * \param offset_start the first character in message \a msg_start to display
2445  * \param cursor       if >= 0, the position at which to draw the cursor
2446  * \param width        the width of the output window
2447  * \param height       the height of the output window
2448  * \param cat          the font category for the font used to draw the messages
2449  * \param text_zoom    the scale factor for the text size
2450  * \param[in,out] select information about current selection. draw_messages()
2451  *	 fills the select->lines array.
2452  */
2453 void draw_messages(int x, int y, text_message *msgs, int msgs_size, Uint8 filter,
2454 	int msg_start, int offset_start, int cursor, int width, int height,
2455 	font_cat cat, float text_zoom, select_info* select);
2456 /*!
2457  * \ingroup text_font
2458  * \brief Draw the console separator
2459  *
2460  * When there are more messages than can fit on a single screen, the user can
2461  * scroll up to see the previous messages. When they do, a separator is
2462  * drawn by this function to indicate that more messages follow.
2463  *
2464  * \param x_space   Horizontal space tokeep free on either side
2465  * \param y         Vertical position at which the line should be drawn
2466  * \param width     The width of the console window
2467  * \param text_zoom The zoom level of the console text
2468  */
2469 void draw_console_separator(int x_space, int y, int width, float text_zoom);
2470 #ifdef ELC
2471 #ifndef MAP_EDITOR2
2472 void draw_ortho_ingame_string(float x, float y, float z, const unsigned char *text, int max_lines,
2473 	font_cat cat, float zoom_x, float zoom_y);
2474 #endif // !MAP_EDITOR2
2475 #endif // ELC
2476 
2477 /*!
2478  * \ingroup text_font
2479  * \brief Set the config font
2480  *
2481  * Copy the current font index and scale of the UI_FONT category to that
2482  * of the CONFIG_FONT category. This allows us to change the UI font
2483  * without changing the way the options window is drawn, and hopefully
2484  * stops the user from then being unable to change the font back.
2485  */
2486 void set_config_font();
2487 
2488 /*!
2489  * \ingroup text_font
2490  * \brief whether a glyph is defined for character \a c, i.e. if it is printable
2491  */
2492 int has_glyph(unsigned char c);
2493 
2494 #ifdef TTF
2495 //! Disable TrueType fonts, allowing bundled fonts only.
2496 void disable_ttf(void);
2497 //! Enable TrueTyoe fonts, restoring previous font indices if possible
2498 void enable_ttf(void);
2499 #endif
2500 
2501 #ifdef __cplusplus
2502 } // extern "C"
2503 #endif
2504 
2505 #endif // NEW_FONT_H
2506