1 /++ 2 + Authors: Avaxar <avaxar@nekkl.org> 3 + Copyright: Copyright © 2023, Avaxar 4 + License: $(LINK2 https://mit-license.org, MIT License) 5 +/ 6 7 module dsdl2.ttf; 8 @safe: 9 10 // dfmt off 11 import bindbc.sdl; 12 static if (bindSDLTTF): 13 // dfmt on 14 15 import dsdl2.sdl; 16 import dsdl2.pixels : Color; 17 import dsdl2.surface; 18 19 import core.memory : GC; 20 import std.conv : to; 21 import std.format : format; 22 import std.string : toStringz; 23 import std.typecons : Tuple; 24 25 version (BindSDL_Static) { 26 } 27 else { 28 /++ 29 + Loads the SDL2_ttf shared dynamic library, which wraps bindbc-sdl's `loadSDLTTF` function 30 + 31 + Unless if bindbc-sdl is on static mode (by adding a `BindSDL_Static` version), this function will exist and must 32 + be called before any calls are made to the library. Otherwise, a segfault will happen upon any function calls. 33 + 34 + Params: 35 + libName = name or path to look the SDL2_ttf SO/DLL for, otherwise `null` for default searching path 36 + Throws: `dsdl2.SDLException` if failed to find the library 37 +/ 38 void loadSO(string libName = null) @trusted { 39 SDLTTFSupport current = libName is null ? loadSDLTTF() : loadSDLTTF(libName.toStringz()); 40 if (current == sdlTTFSupport) { 41 return; 42 } 43 44 Version wanted = Version(sdlTTFSupport); 45 if (current == SDLTTFSupport.badLibrary) { 46 import std.stdio : writeln; 47 48 writeln("WARNING: dsdl2 expects SDL_ttf ", wanted.format(), ", but got ", getVersion().format(), "."); 49 } 50 else if (current == SDLTTFSupport.noLibrary) { 51 throw new SDLException("No SDL2_ttf library found, especially of version " ~ wanted.format(), 52 __FILE__, __LINE__); 53 } 54 } 55 } 56 57 /++ 58 + Wraps `TTF_Init` which initializes SDL2_ttf 59 + 60 + Throws: `dsdl2.SDLException` if failed to initialize 61 + Example: 62 + --- 63 + dsdl2.ttf.init(); 64 + --- 65 +/ 66 void init() @trusted { 67 if (TTF_Init() != 0) { 68 throw new SDLException; 69 } 70 } 71 72 version (unittest) { 73 static this() { 74 version (BindSDL_Static) { 75 } 76 else { 77 dsdl2.ttf.loadSO(); 78 } 79 80 dsdl2.ttf.init(); 81 } 82 } 83 84 /++ 85 + Wraps `TTF_Quit` which deinitializes SDL2_ttf 86 +/ 87 void quit() @trusted { 88 TTF_Quit(); 89 } 90 91 /++ 92 + Wraps `TTF_WasInit` which checks whether SDL2_ttf has been initialized 93 + 94 + Returns: `true` if the library has been initialized, otherwise `false` 95 +/ 96 bool wasInit() @trusted { 97 return TTF_WasInit() > 0; 98 } 99 100 /++ 101 + Wraps `TTF_Linked_version` which gets the version of the linked SDL2_ttf library 102 + 103 + Returns: `dsdl2.Version` of the linked SDL2_ttf library 104 +/ 105 Version getVersion() @trusted { 106 return Version(*TTF_Linked_Version()); 107 } 108 109 static if (sdlTTFSupport >= SDLTTFSupport.v2_0_18) { 110 /++ 111 + Wraps `TTF_GetFreeTypeVersion` (from SDL_ttf 2.0.18) which gets the version of the FreeType library used by the 112 + linked SDL2_ttf 113 + 114 + Returns: `dsdl2.Version` of the used FreeType library 115 +/ 116 Version getFreeTypeVersion() @trusted 117 in { 118 assert(dsdl2.ttf.getVersion() >= Version(2, 0, 18)); 119 } 120 do { 121 int[3] ver = void; 122 TTF_GetFreeTypeVersion(&ver[0], &ver[1], &ver[2]); 123 return Version(ver[0].to!ubyte, ver[1].to!ubyte, ver[2].to!ubyte); 124 } 125 126 /++ 127 + Wraps `TTF_GetHarfBuzzVersion` (from SDL_ttf 2.0.18) which gets the version of the HarfBuzz library used by the 128 + linked SDL2_ttf 129 + 130 + Returns: `dsdl2.Version` of the used HarfBuzz library 131 +/ 132 Version getHarfBuzzVersion() @trusted 133 in { 134 assert(dsdl2.ttf.getVersion() >= Version(2, 0, 18)); 135 } 136 do { 137 int[3] ver = void; 138 TTF_GetHarfBuzzVersion(&ver[0], &ver[1], &ver[2]); 139 return Version(ver[0].to!ubyte, ver[1].to!ubyte, ver[2].to!ubyte); 140 } 141 } 142 143 /++ 144 + D struct that wraps a glyph's metrics information 145 +/ 146 struct GlyphMetrics { 147 int[2] min; /// Tuple of the `minX` and `minY` values 148 int[2] max; /// Tuple of the `maxX` and `maxY` values 149 int advance; /// Advancing step size of the glyph 150 151 this() @disable; 152 153 /++ 154 + Constructs a new `dsdl2.ttf.GlyphMetrics` by feeding in its attributes 155 + 156 + Params: 157 + min = tuple of the `minX` and `minY` values 158 + max = tuple of the `maxX` and `maxY` values 159 + advance = advancing step size of the glyph 160 +/ 161 this(int[2] min, int[2] max, int advance) { 162 this.min = min; 163 this.max = max; 164 this.advance = advance; 165 } 166 167 /++ 168 + Formats the `dsdl2.ttf.GlyphMetrics` into its construction representation: 169 + `"dsdl2.ttf.GlyphMetrics(<min>, <max>, <advance>)"` 170 + 171 + Returns: the formatted `string` 172 +/ 173 string toString() const { 174 return "dsdl2.ttf.GlyphMetrics(%s, %s, %d)".format(this.min, this.max, this.advance); 175 } 176 177 /++ 178 + Proxy to the minimum X value of the `dsdl2.ttf.GlyphMetrics` 179 + 180 + Returns: minimum X value of the `dsdl2.ttf.GlyphMetrics` 181 +/ 182 ref inout(int) minX() return inout @property { 183 return this.min[0]; 184 } 185 186 /++ 187 + Proxy to the minimum Y value of the `dsdl2.ttf.GlyphMetrics` 188 + 189 + Returns: minimum Y value of the `dsdl2.ttf.GlyphMetrics` 190 +/ 191 ref inout(int) minY() return inout @property { 192 return this.min[1]; 193 } 194 195 /++ 196 + Proxy to the maximum X value of the `dsdl2.ttf.GlyphMetrics` 197 + 198 + Returns: maximum X value of the `dsdl2.ttf.GlyphMetrics` 199 +/ 200 ref inout(int) maxX() return inout @property { 201 return this.max[0]; 202 } 203 204 /++ 205 + Proxy to the maximum Y value of the `dsdl2.ttf.GlyphMetrics` 206 + 207 + Returns: maximum Y value of the `dsdl2.ttf.GlyphMetrics` 208 +/ 209 ref inout(int) maxY() return inout @property { 210 return this.max[1]; 211 } 212 } 213 214 /++ 215 + D enum that wraps `TTF_HINTING_*` enumerations 216 +/ 217 enum Hinting { 218 /++ 219 + Wraps `TTF_HINTING_*` enumeration constants 220 +/ 221 normal = TTF_HINTING_NORMAL, 222 light = TTF_HINTING_LIGHT, /// ditto 223 mono = TTF_HINTING_MONO, /// ditto 224 none = TTF_HINTING_NONE, /// ditto 225 226 lightSubpixel = 4 /// Wraps `TTF_HINTING_LIGHT_SUBPIXEL` (from SDL_ttf 2.0.18) 227 } 228 229 /++ 230 + D enum that defines the render quality of font texts 231 +/ 232 enum RenderQuality { 233 solid, /// Fast quality to 8-bit surface 234 shaded, /// High quality to 8-bit surface with background color 235 blended, /// High quality to ARGB surface 236 lcd /// LCD subpixel quality to ARGB surface with background color (from SDL_ttf 2.20) 237 } 238 239 static if (sdlTTFSupport >= SDLTTFSupport.v2_20) { 240 /++ 241 + D enum that wraps `TTF_WRAPPED_ALIGN_*` enumerations (from SDL_ttf 2.20) 242 +/ 243 enum WrappedAlign { 244 /++ 245 + Wraps `TTF_WRAPPED_ALIGN_*` enumeration constants 246 +/ 247 left = TTF_WRAPPED_ALIGN_LEFT, 248 center = TTF_WRAPPED_ALIGN_CENTER, /// ditto 249 right = TTF_WRAPPED_ALIGN_RIGHT /// ditto 250 } 251 252 /++ 253 + D enum that wraps `TTF_Direction` (from SDL_ttf 2.20) 254 +/ 255 enum Direction { 256 /++ 257 + Wraps `TTF_DIRECTION_*` enumeration constants 258 +/ 259 leftToRight = TTF_DIRECTION_LTR, 260 rightToLeft = TTF_DIRECTION_RTL, /// ditto 261 topToBottom = TTF_DIRECTION_TTB, /// ditto 262 bottomToTop = TTF_DIRECTION_BTT /// ditto 263 } 264 } 265 266 /++ 267 + D class that wraps `TTF_Font` enclosing a font object to render text from 268 +/ 269 final class Font { 270 private bool isOwner = true; 271 private void* userRef = null; 272 273 @system TTF_Font* ttfFont = null; /// Internal `TTF_Font` pointer 274 275 /++ 276 + Constructs a `dsdl2.ttf.Font` from a vanilla `TTF_Font*` from bindbc-sdl 277 + 278 + Params: 279 + ttfFont = the `TTF_Font` pointer to manage 280 + isOwner = whether the instance owns the given `TTF_Font*` and should destroy it on its own 281 + userRef = optional pointer to maintain reference link, avoiding GC cleanup 282 +/ 283 this(TTF_Font* ttfFont, bool isOwner = true, void* userRef = null) @system 284 in { 285 assert(ttfFont !is null); 286 } 287 do { 288 this.ttfFont = ttfFont; 289 this.isOwner = isOwner; 290 this.userRef = userRef; 291 } 292 293 /++ 294 + Loads a `dsdl2.ttf.Font` from a font file, which wraps `TTF_OpenFont` 295 + 296 + Params: 297 + file = path to the font file 298 + size = point size of the loaded font 299 + Throws: `dsdl2.SDLException` if unable to load the font 300 +/ 301 this(string file, uint size) @trusted { 302 this.ttfFont = TTF_OpenFont(file.toStringz(), size.to!int); 303 if (this.ttfFont is null) { 304 throw new SDLException; 305 } 306 } 307 308 /++ 309 + Loads a `dsdl2.ttf.Font` from a font file with a face index, which wraps `TTF_OpenFontIndex` 310 + 311 + Params: 312 + file = path to the font file 313 + size = point size of the loaded font 314 + index = face index of the loaded font 315 + Throws: `dsdl2.SDLException` if unable to load the font 316 +/ 317 this(string file, uint size, size_t index) @trusted { 318 this.ttfFont = TTF_OpenFontIndex(file.toStringz(), size.to!int, index.to!c_long); 319 if (this.ttfFont is null) { 320 throw new SDLException; 321 } 322 } 323 324 /++ 325 + Loads a `dsdl2.ttf.Font` from a buffer, which wraps `TTF_OpenFontRW` 326 + 327 + Params: 328 + data = buffer of the font file 329 + size = point size of the loaded font 330 + Throws: `dsdl2.SDLException` if unable to load the font 331 +/ 332 this(const void[] data, uint size) @trusted { 333 SDL_RWops* sdlRWops = SDL_RWFromConstMem(data.ptr, data.length.to!int); 334 if (sdlRWops is null) { 335 throw new SDLException; 336 } 337 338 this.ttfFont = TTF_OpenFontRW(sdlRWops, 1, size.to!int); 339 if (this.ttfFont is null) { 340 throw new SDLException; 341 } 342 } 343 344 /++ 345 + Loads a `dsdl2.ttf.Font` from a buffer with a face index, which wraps `TTF_OpenFontIndexRW` 346 + 347 + Params: 348 + data = buffer of the font file 349 + size = point size of the loaded font 350 + index = face index of the loaded font 351 + Throws: `dsdl2.SDLException` if unable to load the font 352 +/ 353 this(const void[] data, uint size, size_t index) @trusted { 354 SDL_RWops* sdlRWops = SDL_RWFromConstMem(data.ptr, data.length.to!int); 355 if (sdlRWops is null) { 356 throw new SDLException; 357 } 358 359 this.ttfFont = TTF_OpenFontIndexRW(sdlRWops, 1, size.to!int, index.to!c_long); 360 if (this.ttfFont is null) { 361 throw new SDLException; 362 } 363 } 364 365 static if (sdlTTFSupport >= SDLTTFSupport.v2_0_18) { 366 /++ 367 + Loads a `dsdl2.ttf.Font` from a font file with DPI, which wraps `TTF_OpenFontDPI` (from SDL_ttf 2.0.18) 368 + 369 + Params: 370 + file = path to the font file 371 + size = point size of the loaded font 372 + hdpi = target horizontal DPI 373 + vdpi = target vertical DPI 374 + Throws: `dsdl2.SDLException` if unable to load the font 375 +/ 376 this(string file, uint size, uint hdpi, uint vdpi) @trusted 377 in { 378 assert(dsdl2.ttf.getVersion() >= Version(2, 0, 18)); 379 } 380 do { 381 this.ttfFont = TTF_OpenFontDPI(file.toStringz(), size.to!int, hdpi, vdpi); 382 if (this.ttfFont is null) { 383 throw new SDLException; 384 } 385 } 386 387 /++ 388 + Loads a `dsdl2.ttf.Font` from a font file with DPI and face index, which wraps `TTF_OpenFontIndexDPI` (from 389 + SDL_ttf 2.0.18) 390 + 391 + Params: 392 + file = path to the font file 393 + size = point size of the loaded font 394 + index = face index of the loaded font 395 + hdpi = target horizontal DPI 396 + vdpi = target vertical DPI 397 + Throws: `dsdl2.SDLException` if unable to load the font 398 +/ 399 this(string file, uint size, size_t index, uint hdpi, uint vdpi) @trusted 400 in { 401 assert(dsdl2.ttf.getVersion() >= Version(2, 0, 18)); 402 } 403 do { 404 this.ttfFont = TTF_OpenFontIndexDPI(file.toStringz(), size.to!int, index.to!c_long, hdpi, vdpi); 405 if (this.ttfFont is null) { 406 throw new SDLException; 407 } 408 } 409 410 /++ 411 + Loads a `dsdl2.ttf.Font` from a buffer with DPI, which wraps `TTF_OpenFontDPIRW` (from SDL_ttf 2.0.18) 412 + 413 + Params: 414 + data = buffer of the font file 415 + size = point size of the loaded font 416 + hdpi = target horizontal DPI 417 + vdpi = target vertical DPI 418 + Throws: `dsdl2.SDLException` if unable to load the font 419 +/ 420 this(const void[] data, uint size, uint hdpi, uint vdpi) @trusted 421 in { 422 assert(dsdl2.ttf.getVersion() >= Version(2, 0, 18)); 423 } 424 do { 425 SDL_RWops* sdlRWops = SDL_RWFromConstMem(data.ptr, data.length.to!int); 426 if (sdlRWops is null) { 427 throw new SDLException; 428 } 429 430 this.ttfFont = TTF_OpenFontDPIRW(sdlRWops, 1, size.to!int, hdpi, vdpi); 431 if (this.ttfFont is null) { 432 throw new SDLException; 433 } 434 } 435 436 /++ 437 + Loads a `dsdl2.ttf.Font` from a buffer with DPI and face index, which wraps `TTF_OpenFontIndexDPIRW` (from 438 + SDL_ttf 2.0.18) 439 + 440 + Params: 441 + data = buffer of the font file 442 + size = point size of the loaded font 443 + index = face index of the loaded font 444 + hdpi = target horizontal DPI 445 + vdpi = target vertical DPI 446 + Throws: `dsdl2.SDLException` if unable to load the font 447 +/ 448 this(const void[] data, uint size, size_t index, uint hdpi, uint vdpi) @trusted 449 in { 450 assert(dsdl2.ttf.getVersion() >= Version(2, 0, 18)); 451 } 452 do { 453 SDL_RWops* sdlRWops = SDL_RWFromConstMem(data.ptr, data.length.to!int); 454 if (sdlRWops is null) { 455 throw new SDLException; 456 } 457 458 this.ttfFont = TTF_OpenFontIndexDPIRW(sdlRWops, 1, size.to!int, index.to!c_long, hdpi, vdpi); 459 if (this.ttfFont is null) { 460 throw new SDLException; 461 } 462 } 463 } 464 465 ~this() @trusted { 466 if (this.isOwner) { 467 TTF_CloseFont(this.ttfFont); 468 } 469 } 470 471 @trusted invariant { // @suppress(dscanner.trust_too_much) 472 // Instance might be in an invalid state due to holding a non-owned externally-freed object when 473 // destructed in an unpredictable order. 474 if (!this.isOwner && GC.inFinalizer) { 475 return; 476 } 477 478 assert(this.ttfFont !is null); 479 } 480 481 /++ 482 + Equality operator overload 483 +/ 484 bool opEquals(const Font rhs) const @trusted { 485 return this.ttfFont is rhs.ttfFont; 486 } 487 488 /++ 489 + Gets the hash of the `dsdl2.ttf.Font` 490 + 491 + Returns: unique hash for the instance being the pointer of the internal `TTF_Font` pointer 492 +/ 493 override hash_t toHash() const @trusted { 494 return cast(hash_t) this.ttfFont; 495 } 496 497 /++ 498 + Formats the `dsdl2.ttf.Font` into its construction representation: `"dsdl2.ttf.Font(<ttfFont>)"` 499 + 500 + Returns: the formatted `string` 501 +/ 502 override string toString() const @trusted { 503 return "dsdl2.ttf.Font(0x%x)".format(this.ttfFont); 504 } 505 506 /++ 507 + Wraps `TTF_GetFontStyle` to get whether the `dsdl2.ttf.Font` style is bold 508 + 509 + Returns: `true` if the `dsdl2.ttf.Font` is bold, otherwise `false` 510 +/ 511 bool bold() const @property @trusted { 512 return (TTF_GetFontStyle(this.ttfFont) & TTF_STYLE_BOLD) == TTF_STYLE_BOLD; 513 } 514 515 /++ 516 + Wraps `TTF_SetFontStyle` to set the `dsdl2.ttf.Font` style to be bold 517 + 518 + Params: 519 + newBold = `true` to make the `dsdl2.ttf.Font` bold, otherwise `false` 520 +/ 521 void bold(bool newBold) @property @trusted { 522 if (newBold) { 523 TTF_SetFontStyle(this.ttfFont, TTF_GetFontStyle(this.ttfFont) | TTF_STYLE_BOLD); 524 } 525 else { 526 TTF_SetFontStyle(this.ttfFont, TTF_GetFontStyle(this.ttfFont) & ~TTF_STYLE_BOLD); 527 } 528 } 529 530 /++ 531 + Wraps `TTF_GetFontStyle` to get whether the `dsdl2.ttf.Font` style is italic 532 + 533 + Returns: `true` if the `dsdl2.ttf.Font` is italic, otherwise `false` 534 +/ 535 bool italic() const @property @trusted { 536 return (TTF_GetFontStyle(this.ttfFont) & TTF_STYLE_ITALIC) == TTF_STYLE_ITALIC; 537 } 538 539 /++ 540 + Wraps `TTF_SetFontStyle` to set the `dsdl2.ttf.Font` style to be italic 541 + 542 + Params: 543 + newItalic = `true` to make the `dsdl2.ttf.Font` italic, otherwise `false` 544 +/ 545 void italic(bool newItalic) @property @trusted { 546 if (newItalic) { 547 TTF_SetFontStyle(this.ttfFont, TTF_GetFontStyle(this.ttfFont) | TTF_STYLE_ITALIC); 548 } 549 else { 550 TTF_SetFontStyle(this.ttfFont, TTF_GetFontStyle(this.ttfFont) & ~TTF_STYLE_ITALIC); 551 } 552 } 553 554 /++ 555 + Wraps `TTF_GetFontStyle` to get whether the `dsdl2.ttf.Font` style is underlined 556 + 557 + Returns: `true` if the `dsdl2.ttf.Font` is underlined, otherwise `false` 558 +/ 559 bool underline() const @property @trusted { 560 return (TTF_GetFontStyle(this.ttfFont) & TTF_STYLE_UNDERLINE) == TTF_STYLE_UNDERLINE; 561 } 562 563 /++ 564 + Wraps `TTF_SetFontStyle` to set the `dsdl2.ttf.Font` style to be underlined 565 + 566 + Params: 567 + newUnderline = `true` to make the `dsdl2.ttf.Font` underlined, otherwise `false` 568 +/ 569 void underline(bool newUnderline) @property @trusted { 570 if (newUnderline) { 571 TTF_SetFontStyle(this.ttfFont, TTF_GetFontStyle(this.ttfFont) | TTF_STYLE_UNDERLINE); 572 } 573 else { 574 TTF_SetFontStyle(this.ttfFont, TTF_GetFontStyle(this.ttfFont) & ~TTF_STYLE_UNDERLINE); 575 } 576 } 577 578 /++ 579 + Wraps `TTF_GetFontStyle` to get whether the `dsdl2.ttf.Font` style is strikethrough 580 + 581 + Returns: `true` if the `dsdl2.ttf.Font` is strikethrough, otherwise `false` 582 +/ 583 bool strikethrough() const @property @trusted { 584 return (TTF_GetFontStyle(this.ttfFont) & TTF_STYLE_STRIKETHROUGH) == TTF_STYLE_STRIKETHROUGH; 585 } 586 587 /++ 588 + Wraps `TTF_SetFontStyle` to set the `dsdl2.ttf.Font` style to be strikethrough 589 + 590 + Params: 591 + newStrikethrough = `true` to make the `dsdl2.ttf.Font` strikethrough, otherwise `false` 592 +/ 593 void strikethrough(bool newStrikethrough) @property @trusted { 594 if (newStrikethrough) { 595 TTF_SetFontStyle(this.ttfFont, TTF_GetFontStyle(this.ttfFont) | TTF_STYLE_STRIKETHROUGH); 596 } 597 else { 598 TTF_SetFontStyle(this.ttfFont, TTF_GetFontStyle(this.ttfFont) & ~TTF_STYLE_STRIKETHROUGH); 599 } 600 } 601 602 /++ 603 + Wraps `TTF_GetFontOutline` to get the `dsdl2.ttf.Font` outline value 604 + 605 + Returns: `uint` outline value of the `dsdl2.ttf.Font` 606 +/ 607 uint outline() const @property @trusted { 608 return TTF_GetFontOutline(this.ttfFont).to!uint; 609 } 610 611 /++ 612 + Wraps `TTF_SetFontOutline` to set the `dsdl2.ttf.Font` outline value 613 + 614 + Params: 615 + newOutline = new outline value for the `dsdl2.ttf.Font`; `0` to set as default 616 +/ 617 void outline(uint newOutline) @property @trusted { 618 TTF_SetFontOutline(this.ttfFont, newOutline.to!int); 619 } 620 621 /++ 622 + Wraps `TTF_GetFontHinting` to get the `dsdl2.ttf.Font` hinting 623 + 624 + Returns: `dsdl2.ttf.Hinting` enumeration for the `dsdl2.ttf.Font` hinting 625 +/ 626 Hinting hinting() const @property @trusted { 627 return cast(Hinting) TTF_GetFontHinting(this.ttfFont); 628 } 629 630 /++ 631 + Wraps `TTF_SetFontHinting` to set the `dsdl2.ttf.Font` hinting 632 + 633 + Params: 634 + newHinting = new `dsdl2.ttf.Hinting` for the `dsdl2.ttf.Font` 635 +/ 636 void hinting(Hinting newHinting) @property @trusted { 637 TTF_SetFontHinting(this.ttfFont, newHinting); 638 } 639 640 static if (sdlTTFSupport >= SDLTTFSupport.v2_0_18) { 641 /++ 642 + Wraps `TTF_GetFontSDF` (from SDL_ttf 2.0.18) to get whether the `dsdl2.ttf.Font` has signed distance field 643 + 644 + Returns: `true` if the `dsdl2.ttf.Font` has SDF, otherwise `false` 645 +/ 646 bool sdf() const @property @trusted 647 in { 648 assert(dsdl2.ttf.getVersion() >= Version(2, 0, 18)); 649 } 650 do { 651 return TTF_GetFontSDF(this.ttfFont) == SDL_TRUE; 652 } 653 654 /++ 655 + Wraps `TTF_SetFontSDF` (from SDL_ttf 2.0.18) to set signed distance field 656 + 657 + Params: 658 + newSDF = `true` to set SDF, otherwise `false` 659 + Throws: `dsdl.SDLException` if unable to set SDF 660 +/ 661 void sdf(bool newSDF) @property @trusted 662 in { 663 assert(dsdl2.ttf.getVersion() >= Version(2, 0, 18)); 664 } 665 do { 666 if (TTF_SetFontSDF(this.ttfFont, newSDF ? SDL_TRUE : SDL_FALSE) != 0) { 667 throw new SDLException; 668 } 669 } 670 671 /++ 672 + Wraps `TTF_SetFontSize` (from SDL_ttf 2.0.18) to set the `dsdl2.ttf.Font`'s size 673 + 674 + Params: 675 + newSize = new size for the `dsdl2.ttf.Font` 676 +/ 677 void size(uint newSize) @property @trusted 678 in { 679 assert(dsdl2.ttf.getVersion() >= Version(2, 0, 18)); 680 } 681 do { 682 if (TTF_SetFontSize(this.ttfFont, newSize.to!int) != 0) { 683 throw new SDLException; 684 } 685 } 686 687 /++ 688 + Wraps `TTF_SetFontSizeDPI` (from SDL_ttf 2.0.18) to set the `dsdl2.ttf.Font`'s size in DPI 689 + 690 + Params: 691 + newSizeDPI = new DPI size tuple of the font size, `hdpi`, and `vdpi` 692 + Throws: `dsdl.SDLException` if unable to set size 693 +/ 694 void sizeDPI(Tuple!(uint, uint, uint) newSizeDPI) @property @trusted 695 in { 696 assert(dsdl2.ttf.getVersion() >= Version(2, 0, 18)); 697 } 698 do { 699 if (TTF_SetFontSizeDPI(this.ttfFont, newSizeDPI[0].to!int, newSizeDPI[1], newSizeDPI[2]) != 0) { 700 throw new SDLException; 701 } 702 } 703 } 704 705 static if (sdlTTFSupport >= SDLTTFSupport.v2_20) { 706 /++ 707 + Wraps `TTF_GetFontWrappedAlign` (from SDL_ttf 2.20) to get the `dsdl2.ttf.Font`'s wrap alignment mode 708 + 709 + Returns: `dsdl2.ttf.WrappedAlign` enumeration of the `dsdl2.ttf.Font` 710 +/ 711 WrappedAlign wrappedAlign() const @property @trusted 712 in { 713 assert(dsdl2.ttf.getVersion() >= Version(2, 20)); 714 } 715 do { 716 return cast(WrappedAlign) TTF_GetFontWrappedAlign(this.ttfFont); 717 } 718 719 /++ 720 + Wraps `TTF_SetFontWrappedAlign` (from SDL_ttf 2.20) to set the `dsdl2.ttf.Font`'s wrap alignment mode 721 + 722 + Params: 723 + newWrappedAlign = new `dsdl2.ttf.WrappedAlign` of the `dsdl2.ttf.Font` 724 +/ 725 void wrappedAlign(WrappedAlign newWrappedAlign) @property @trusted 726 in { 727 assert(dsdl2.ttf.getVersion() >= Version(2, 20)); 728 } 729 do { 730 TTF_SetFontWrappedAlign(this.ttfFont, newWrappedAlign); 731 } 732 733 /++ 734 + Wraps `TTF_SetFontDirection` (from SDL_ttf 2.20) to set the `dsdl2.ttf.Font`'s script direction 735 + 736 + Params: 737 + newDirection = new script `dsdl2.ttf.Direction` for the `dsdl2.ttf.Font` 738 + Throws: `dsdl.SDLException` if unable to set script direction 739 +/ 740 void direction(Direction newDirection) @property @trusted 741 in { 742 assert(dsdl2.ttf.getVersion() >= Version(2, 20)); 743 } 744 do { 745 if (TTF_SetFontDirection(this.ttfFont, newDirection) != 0) { 746 throw new SDLException; 747 } 748 } 749 750 /++ 751 + Wraps `TTF_SetFontScriptName` (from SDL_ttf 2.20) to set the `dsdl2.ttf.Font`'s script name 752 + 753 + Params: 754 + newScriptName = new script name for the `dsdl2.ttf.Font` 755 + Throws: `dsdl.SDLException` if unable to set script name 756 +/ 757 void scriptName(string newScriptName) @property @trusted 758 in { 759 assert(dsdl2.ttf.getVersion() >= Version(2, 20)); 760 } 761 do { 762 if (TTF_SetFontScriptName(this.ttfFont, newScriptName.toStringz()) != 0) { 763 throw new SDLException; 764 } 765 } 766 } 767 768 /++ 769 + Wraps `TTF_FontHeight` to get the `dsdl2.ttf.Font`'s height 770 + 771 + Returns: `int` height of the `dsdl2.ttf.Font` 772 +/ 773 int height() const @property @trusted { 774 return TTF_FontHeight(this.ttfFont); 775 } 776 777 /++ 778 + Wraps `TTF_FontAscent` to get the `dsdl2.ttf.Font`'s ascent 779 + 780 + Returns: `int` ascent of the `dsdl2.ttf.Font` 781 +/ 782 int ascent() const @property @trusted { 783 return TTF_FontAscent(this.ttfFont); 784 } 785 786 /++ 787 + Wraps `TTF_FontDescent` to get the `dsdl2.ttf.Font`'s descent 788 + 789 + Returns: `int` descent of the `dsdl2.ttf.Font` 790 +/ 791 int descent() const @property @trusted { 792 return TTF_FontDescent(this.ttfFont); 793 } 794 795 /++ 796 + Wraps `TTF_FontLineSkip` to get the `dsdl2.ttf.Font`'s line skip 797 + 798 + Returns: `int` line skip of the `dsdl2.ttf.Font` 799 +/ 800 int lineSkip() const @property @trusted { 801 return TTF_FontLineSkip(this.ttfFont); 802 } 803 804 /++ 805 + Wraps `TTF_GetFontKerning` to get the `dsdl2.ttf.Font`'s kerning 806 + 807 + Returns: `bool` whether the `dsdl2.ttf.Font` has kerning 808 +/ 809 bool kerning() const @property @trusted { 810 return TTF_GetFontKerning(this.ttfFont) != 0; 811 } 812 813 /++ 814 + Wraps `TTF_SetFontKerning` to set the `dsdl2.ttf.Font`'s kerning 815 + 816 + Params: 817 + newKerning = new `bool` value for the `dsdl2.ttf.Font`'s kerning 818 +/ 819 void kerning(bool newKerning) @property @trusted { 820 TTF_SetFontKerning(this.ttfFont, newKerning ? 1 : 0); 821 } 822 823 /++ 824 + Wraps `TTF_FontFaces` to get the `dsdl2.ttf.Font`'s number of font faces 825 + 826 + Returns: number of font faces of the `dsdl2.ttf.Font` 827 +/ 828 size_t faces() const @property @trusted { 829 return TTF_FontFaces(this.ttfFont); 830 } 831 832 /++ 833 + Wraps `TTF_FontFaceIsFixedWidth` to check whether the `dsdl2.ttf.Font`'s font face is fixed width 834 + 835 + Returns: `true` if the `dsdl2.ttf.Font`'s font face is fixed width, otherwise `false` 836 +/ 837 bool fixedWidth() const @property @trusted { 838 return TTF_FontFaceIsFixedWidth(this.ttfFont) != 0; 839 } 840 841 /++ 842 + Wraps `TTF_FontFaceFamilyName` to get the `dsdl2.ttf.Font` family name 843 + 844 + Returns: font family name of the `dsdl2.ttf.Font` 845 +/ 846 string familyName() const @property @trusted { 847 return TTF_FontFaceFamilyName(this.ttfFont).to!string; 848 } 849 850 /++ 851 + Wraps `TTF_FontFaceStyleName` to get the `dsdl2.ttf.Font` style name 852 + 853 + Returns: font style name of the `dsdl2.ttf.Font` 854 +/ 855 string styleName() const @property @trusted { 856 return TTF_FontFaceStyleName(this.ttfFont).to!string; 857 } 858 859 /++ 860 + Wraps `TTF_GlyphIsProvided` to check whether the `dsdl2.ttf.Font` provides a glyph 861 + 862 + Params: 863 + glyph = `wchar` glyph to check 864 + Returns: `true` if the `dsdl2.ttf.Font` provides the glyph, otherwise `false` 865 +/ 866 bool providesGlyph(wchar glyph) const @trusted { 867 return TTF_GlyphIsProvided(this.ttfFont, cast(ushort) glyph) != 0; 868 } 869 870 static if (sdlTTFSupport >= SDLTTFSupport.v2_0_18) { 871 /++ 872 + Wraps `TTF_GlyphIsProvided32` (from SDL_ttf 2.0.18) to check whether the `dsdl2.ttf.Font` provides a glyph 873 + 874 + Params: 875 + glyph = `dchar` glyph to check 876 + Returns: `true` if the `dsdl2.ttf.Font` provides the glyph, otherwise `false` 877 +/ 878 bool providesGlyph(dchar glyph) const @trusted 879 in { 880 assert(dsdl2.ttf.getVersion() >= Version(2, 0, 18)); 881 } 882 do { 883 return TTF_GlyphIsProvided32(cast(TTF_Font*) this.ttfFont, cast(uint) glyph) != 0; 884 } 885 } 886 887 /++ 888 + Wraps `TTF_GlyphMetrics` to the metrics of a glyph in the `dsdl2.ttf.Font` 889 + 890 + Params: 891 + glyph = `wchar` glyph to get the metrics of 892 + Returns: `dsdl2.ttf.GlyphMetrics` of the glyph 893 + Throws: `dsdl.SDLException` if unable to get glyph metrics 894 +/ 895 GlyphMetrics glyphMetrics(wchar glyph) const @trusted { 896 GlyphMetrics metrics = void; 897 if (TTF_GlyphMetrics(cast(TTF_Font*) this.ttfFont, cast(ushort) glyph, &metrics.min[0], &metrics.max[0], 898 &metrics.min[1], &metrics.max[1], &metrics.advance) != 0) { 899 throw new SDLException; 900 } 901 902 return metrics; 903 } 904 905 static if (sdlTTFSupport >= SDLTTFSupport.v2_0_18) { 906 /++ 907 + Wraps `TTF_GlyphMetrics32` (from SDL_ttf 2.0.18) to the metrics of a glyph in the `dsdl2.ttf.Font` 908 + 909 + Params: 910 + glyph = `dchar` glyph to get the metrics of 911 + Returns: `dsdl2.ttf.GlyphMetrics` of the glyph 912 + Throws: `dsdl.SDLException` if unable to get glyph metrics 913 +/ 914 GlyphMetrics glyphMetrics(dchar glyph) const @trusted 915 in { 916 assert(dsdl2.ttf.getVersion() >= Version(2, 0, 18)); 917 } 918 do { 919 GlyphMetrics metrics = void; 920 if (TTF_GlyphMetrics32(cast(TTF_Font*) this.ttfFont, cast(uint) glyph, &metrics.min[0], &metrics.max[0], 921 &metrics.min[1], &metrics.max[1], &metrics.advance) != 0) { 922 throw new SDLException; 923 } 924 925 return metrics; 926 } 927 } 928 929 static if (sdlTTFSupport >= SDLTTFSupport.v2_0_14) { 930 /++ 931 + Wraps `TTF_GetFontKerningSize` (from SDL_ttf 2.0.14) to get the kerning between two glyphs in the 932 + `dsdl2.ttf.Font` 933 + 934 + Params: 935 + prevGlyph = preceeding `wchar` glyph 936 + glyph = `wchar` glyph 937 + Returns: kerning between `prevGlyph` and `glyph` 938 +/ 939 int glyphKerning(wchar prevGlyph, wchar glyph) const @trusted 940 in { 941 assert(dsdl2.ttf.getVersion() >= Version(2, 0, 14)); 942 } 943 do { 944 return TTF_GetFontKerningSizeGlyphs(cast(TTF_Font*) this.ttfFont, cast(ushort) prevGlyph, 945 cast(ushort) glyph); 946 } 947 } 948 949 static if (sdlTTFSupport >= SDLTTFSupport.v2_0_18) { 950 /++ 951 + Wraps `TTF_GetFontKerningSize` (from SDL_ttf 2.0.18) to get the kerning between two glyphs in the 952 + `dsdl2.ttf.Font` 953 + 954 + Params: 955 + prevGlyph = preceeding `dchar` glyph 956 + glyph = `dchar` glyph 957 + Returns: kerning between `prevGlyph` and `glyph` 958 +/ 959 int glyphKerning(dchar prevGlyph, dchar glyph) const @trusted 960 in { 961 assert(dsdl2.ttf.getVersion() >= Version(2, 0, 18)); 962 } 963 do { 964 return TTF_GetFontKerningSizeGlyphs32(cast(TTF_Font*) this.ttfFont, cast(uint) prevGlyph, 965 cast(uint) glyph); 966 } 967 } 968 969 /++ 970 + Wraps `TTF_SizeUTF8` to get the size of a rendered text in the `dsdl2.ttf.Font` 971 + 972 + Params: 973 + text = rendered `string` text to get the size of 974 + Returns: the size of the rendered text (width and height) 975 + Throws: `dsdl.SDLException` if unable to get text size 976 +/ 977 uint[2] textSize(string text) const @trusted { 978 uint[2] wh = void; 979 if (TTF_SizeUTF8(cast(TTF_Font*) this.ttfFont, text.toStringz(), cast(int*)&wh[0], cast(int*)&wh[1]) != 0) { 980 throw new SDLException; 981 } 982 983 return wh; 984 } 985 986 /++ 987 + Wraps `TTF_SizeUNICODE` to get the size of a rendered text in the `dsdl2.ttf.Font` 988 + 989 + Params: 990 + text = rendered `wstring` text to get the size of 991 + Returns: the size of the rendered text (width and height) 992 + Throws: `dsdl.SDLException` if unable to get text size 993 +/ 994 uint[2] textSize(wstring text) const @trusted { 995 // `std.string.toStringz` doesn't have any `wstring` overloads. 996 wchar[] ctext; 997 ctext.length = text.length + 1; 998 ctext[0 .. text.length] = text; 999 ctext[text.length] = '\0'; 1000 1001 uint[2] wh = void; 1002 if (TTF_SizeUNICODE(cast(TTF_Font*) this.ttfFont, cast(ushort*) ctext.ptr, cast(int*)&wh[0], 1003 cast(int*)&wh[1]) != 0) { 1004 throw new SDLException; 1005 } 1006 1007 return wh; 1008 } 1009 1010 static if (sdlTTFSupport >= SDLTTFSupport.v2_0_18) { 1011 private alias TextMeasurement = Tuple!(uint, "extent", uint, "count"); 1012 1013 /++ 1014 + Wraps `TTF_MeasureUTF8` (from SDL_ttf 2.0.18) to calculate the maximum number of characters from a text that 1015 + can be rendered given a maximum fitting width 1016 + 1017 + Params: 1018 + text = `string` of characters to measure 1019 + measureWidth = maximum fitting width 1020 + Returns: named tuple of `extent` (calculated width) and `count` (number of characters) 1021 + Throws: `dsdl.SDLException` if unable to measure text 1022 +/ 1023 TextMeasurement measureText(string text, uint measureWidth) const @trusted 1024 in { 1025 assert(dsdl2.ttf.getVersion() >= Version(2, 0, 18)); 1026 } 1027 do { 1028 TextMeasurement measurement = void; 1029 if (TTF_MeasureUTF8(cast(TTF_Font*) this.ttfFont, text.toStringz(), measureWidth.to!int, 1030 cast(int*)&measurement.extent, cast(int*)&measurement.count) != 0) { 1031 throw new SDLException; 1032 } 1033 1034 return measurement; 1035 } 1036 1037 /++ 1038 + Wraps `TTF_MeasureUNICODE` (from SDL_ttf 2.0.18) to calculate the maximum number of characters from a text 1039 + that can be rendered given a maximum fitting width 1040 + 1041 + Params: 1042 + text = `wstring` of characters to measure 1043 + measureWidth = maximum fitting width 1044 + Returns: named tuple of `extent` (calculated width) and `count` (number of characters) 1045 + Throws: `dsdl.SDLException` if unable to measure text 1046 +/ 1047 TextMeasurement measureText(wstring text, uint measureWidth) const @trusted 1048 in { 1049 assert(dsdl2.ttf.getVersion() >= Version(2, 0, 18)); 1050 } 1051 do { 1052 // `std.string.toStringz` doesn't have any `wstring` overloads. 1053 wchar[] ctext; 1054 ctext.length = text.length + 1; 1055 ctext[0 .. text.length] = text; 1056 ctext[text.length] = '\0'; 1057 1058 TextMeasurement measurement = void; 1059 if (TTF_MeasureUNICODE(cast(TTF_Font*) this.ttfFont, cast(ushort*) ctext.ptr, measureWidth.to!int, 1060 cast(int*)&measurement[0], cast(int*)&measurement[1]) != 0) { 1061 throw new SDLException; 1062 } 1063 1064 return measurement; 1065 } 1066 } 1067 1068 /++ 1069 + Wraps `TTF_RenderGlyph_Solid`, `TTF_RenderGlyph_Shaded`, `TTF_RenderGlyph_Blended`, and additionally 1070 + `TTF_RenderGlyph_LCD` (from SDL_ttf 2.20) to render a glyph in the `dsdl2.ttf.Font` 1071 + 1072 + Params: 1073 + glyph = `wchar` glyph to render 1074 + foreground = foreground `dsdl2.Color` of the glyph 1075 + background = background `dsdl2.Color` of the resulted surface (only for `RenderQuality.shaded` and 1076 + `RenderQuality.lcd`) 1077 + quality = `dsdl2.ttf.RenderQuality` of the resulted render 1078 + Returns: `dsdl2.Surface` containing the rendered glyph 1079 + Throws: `dsdl.SDLException` if failed to render glyph 1080 +/ 1081 Surface render(wchar glyph, Color foreground, Color background = Color(0, 0, 0, 0), 1082 RenderQuality quality = RenderQuality.shaded) const @trusted 1083 in { 1084 if (quality == RenderQuality.lcd) { 1085 assert(dsdl2.ttf.getVersion() >= Version(2, 20)); 1086 } 1087 1088 if (background != Color(0, 0, 0, 0)) { 1089 assert(quality == RenderQuality.shaded || quality == RenderQuality.lcd, "Only shaded and LCD render quality" 1090 ~ " can have a background color."); 1091 } 1092 } 1093 do { 1094 SDL_Surface* sdlSurface; 1095 switch (quality) { 1096 case RenderQuality.solid: 1097 sdlSurface = TTF_RenderGlyph_Solid(cast(TTF_Font*) this.ttfFont, cast(ushort) glyph, foreground.sdlColor); 1098 break; 1099 1100 case RenderQuality.shaded: 1101 sdlSurface = TTF_RenderGlyph_Shaded(cast(TTF_Font*) this.ttfFont, cast(ushort) glyph, foreground.sdlColor, 1102 background.sdlColor); 1103 break; 1104 1105 case RenderQuality.blended: 1106 sdlSurface = TTF_RenderGlyph_Blended(cast(TTF_Font*) this.ttfFont, cast(ushort) glyph, foreground.sdlColor); 1107 break; 1108 1109 case RenderQuality.lcd: 1110 static if (sdlTTFSupport >= SDLTTFSupport.v2_20) { 1111 sdlSurface = TTF_RenderGlyph_LCD(cast(TTF_Font*) this.ttfFont, cast(ushort) glyph, foreground.sdlColor, 1112 background.sdlColor); 1113 break; 1114 } 1115 assert(0); 1116 1117 default: 1118 assert(0); 1119 } 1120 1121 if (sdlSurface is null) { 1122 throw new SDLException; 1123 } 1124 1125 return new Surface(sdlSurface); 1126 } 1127 1128 static if (sdlTTFSupport >= SDLTTFSupport.v2_0_18) { 1129 /++ 1130 + Wraps `TTF_RenderGlyph32_Solid`, `TTF_RenderGlyph32_Shaded`, `TTF_RenderGlyph32_Blended` (from SDL_ttf 1131 + 2.0.18), and additionally `TTF_RenderGlyph32_LCD` (from SDL_ttf 2.20) to render a glyph in the 1132 + `dsdl2.ttf.Font` 1133 + 1134 + Params: 1135 + glyph = `dchar` glyph to render 1136 + foreground = foreground `dsdl2.Color` of the glyph 1137 + background = background `dsdl2.Color` of the resulted surface (only for `RenderQuality.shaded` and 1138 + `RenderQuality.lcd`) 1139 + quality = `dsdl2.ttf.RenderQuality` of the resulted render 1140 + Returns: `dsdl2.Surface` containing the rendered glyph 1141 + Throws: `dsdl.SDLException` if failed to render glyph 1142 +/ 1143 Surface render(dchar glyph, Color foreground, Color background = Color(0, 0, 0, 0), 1144 RenderQuality quality = RenderQuality.shaded) const @trusted 1145 in { 1146 assert(dsdl2.ttf.getVersion() >= Version(2, 0, 18)); 1147 1148 if (quality == RenderQuality.lcd) { 1149 assert(dsdl2.ttf.getVersion() >= Version(2, 20)); 1150 } 1151 1152 if (background != Color(0, 0, 0, 0)) { 1153 assert(quality == RenderQuality.shaded || quality == RenderQuality.lcd, "Only shaded and LCD render " 1154 ~ "quality can have a background color."); 1155 } 1156 } 1157 do { 1158 SDL_Surface* sdlSurface; 1159 switch (quality) { 1160 case RenderQuality.solid: 1161 sdlSurface = TTF_RenderGlyph32_Solid(cast(TTF_Font*) this.ttfFont, cast(uint) glyph, 1162 foreground.sdlColor); 1163 break; 1164 1165 case RenderQuality.shaded: 1166 sdlSurface = TTF_RenderGlyph32_Shaded(cast(TTF_Font*) this.ttfFont, cast(uint) glyph, 1167 foreground.sdlColor, background.sdlColor); 1168 break; 1169 1170 case RenderQuality.blended: 1171 sdlSurface = TTF_RenderGlyph32_Blended(cast(TTF_Font*) this.ttfFont, cast(uint) glyph, 1172 foreground.sdlColor); 1173 break; 1174 1175 case RenderQuality.lcd: 1176 static if (sdlTTFSupport >= SDLTTFSupport.v2_20) { 1177 sdlSurface = TTF_RenderGlyph32_LCD(cast(TTF_Font*) this.ttfFont, cast(uint) glyph, 1178 foreground.sdlColor, background.sdlColor); 1179 break; 1180 } 1181 assert(0); 1182 1183 default: 1184 assert(0); 1185 } 1186 1187 if (sdlSurface is null) { 1188 throw new SDLException; 1189 } 1190 1191 return new Surface(sdlSurface); 1192 } 1193 } 1194 1195 /++ 1196 + Wraps `TTF_RenderUTF8_Solid`, `TTF_RenderUTF8_Shaded`, `TTF_RenderUTF8_Blended`, and additionally 1197 + `TTF_RenderUTF8_LCD` (from SDL_ttf 2.20), as well as `TTF_RenderUTF8_Solid_Wrapped`, 1198 + `TTF_RenderUTF8_Shaded_Wrapped`, `TTF_RenderUTF8_Blended_Wrapped` (from SDL_ttf 2.0.18), 1199 + and `TTF_RenderUTF8_LCD_Wrapped` (from SDL_ttf 2.20) to render a text string in the `dsdl2.ttf.Font` 1200 + 1201 + Params: 1202 + text = `string` text to render 1203 + foreground = foreground `dsdl2.Color` of the text 1204 + background = background `dsdl2.Color` of the resulted surface (only for `RenderQuality.shaded` and 1205 + `RenderQuality.lcd`) 1206 + quality = `dsdl2.ttf.RenderQuality` of the resulted render 1207 + wrapLength = maximum width in pixels for wrapping text to the new line; `0` to only wrap on line breaks 1208 + (wrapping only available from SDL_ttf 2.0.18) 1209 + Returns: `dsdl2.Surface` containing the rendered text 1210 + Throws: `dsdl.SDLException` if failed to render text 1211 +/ 1212 Surface render(string text, Color foreground, Color background = Color(0, 0, 0, 0), 1213 RenderQuality quality = RenderQuality.shaded, uint wrapLength = cast(uint)-1) const @trusted 1214 in { 1215 if (quality == RenderQuality.lcd) { 1216 assert(dsdl2.ttf.getVersion() >= Version(2, 20)); 1217 } 1218 1219 if (wrapLength != cast(uint)-1) { 1220 assert(dsdl2.ttf.getVersion() >= Version(2, 0, 18)); 1221 } 1222 1223 if (background != Color(0, 0, 0, 0)) { 1224 assert(quality == RenderQuality.shaded || quality == RenderQuality.lcd, "Only shaded and LCD render quality" 1225 ~ " can have a background color."); 1226 } 1227 } 1228 do { 1229 immutable char* ctext = text.toStringz(); 1230 1231 SDL_Surface* sdlSurface; 1232 switch (quality) { 1233 case RenderQuality.solid: 1234 if (wrapLength != cast(uint)-1) { 1235 static if (sdlTTFSupport >= SDLTTFSupport.v2_0_18) { 1236 sdlSurface = TTF_RenderUTF8_Solid_Wrapped(cast(TTF_Font*) this.ttfFont, ctext, foreground.sdlColor, 1237 wrapLength); 1238 } 1239 } 1240 else { 1241 sdlSurface = TTF_RenderUTF8_Solid(cast(TTF_Font*) this.ttfFont, ctext, foreground.sdlColor); 1242 } 1243 break; 1244 1245 case RenderQuality.shaded: 1246 if (wrapLength != cast(uint)-1) { 1247 static if (sdlTTFSupport >= SDLTTFSupport.v2_0_18) { 1248 sdlSurface = TTF_RenderUTF8_Shaded_Wrapped(cast(TTF_Font*) this.ttfFont, ctext, 1249 foreground.sdlColor, background.sdlColor, wrapLength); 1250 } 1251 } 1252 else { 1253 sdlSurface = TTF_RenderUTF8_Shaded(cast(TTF_Font*) this.ttfFont, ctext, foreground.sdlColor, 1254 background.sdlColor); 1255 } 1256 break; 1257 1258 case RenderQuality.blended: 1259 if (wrapLength != cast(uint)-1) { 1260 static if (sdlTTFSupport >= SDLTTFSupport.v2_0_18) { 1261 sdlSurface = TTF_RenderUTF8_Blended_Wrapped(cast(TTF_Font*) this.ttfFont, ctext, 1262 foreground.sdlColor, wrapLength); 1263 } 1264 } 1265 else { 1266 sdlSurface = TTF_RenderUTF8_Blended(cast(TTF_Font*) this.ttfFont, ctext, foreground.sdlColor); 1267 } 1268 break; 1269 1270 case RenderQuality.lcd: 1271 static if (sdlTTFSupport >= SDLTTFSupport.v2_20) { 1272 if (wrapLength != cast(uint)-1) { 1273 sdlSurface = TTF_RenderUTF8_LCD_Wrapped(cast(TTF_Font*) this.ttfFont, ctext, foreground.sdlColor, 1274 background.sdlColor, wrapLength); 1275 } 1276 else { 1277 sdlSurface = TTF_RenderUTF8_LCD(cast(TTF_Font*) this.ttfFont, ctext, foreground.sdlColor, 1278 background.sdlColor); 1279 } 1280 break; 1281 } 1282 assert(0); 1283 1284 default: 1285 assert(0); 1286 } 1287 1288 if (sdlSurface is null) { 1289 throw new SDLException; 1290 } 1291 1292 return new Surface(sdlSurface); 1293 } 1294 1295 /++ 1296 + Wraps `TTF_RenderUNICODE_Solid`, `TTF_RenderUNICODE_Shaded`, `TTF_RenderUNICODE_Blended`, and additionally 1297 + `TTF_RenderUNICODE_LCD` (from SDL_ttf 2.20), as well as `TTF_RenderUNICODE_Solid_Wrapped`, 1298 + `TTF_RenderUNICODE_Shaded_Wrapped`, `TTF_RenderUNICODE_Blended_Wrapped` (from SDL_ttf 2.0.18), 1299 + and `TTF_RenderUNICODE_LCD_Wrapped` (from SDL_ttf 2.20) to render a text string in the `dsdl2.ttf.Font` 1300 + 1301 + Params: 1302 + text = `wstring` text to render 1303 + foreground = foreground `dsdl2.Color` of the text 1304 + background = background `dsdl2.Color` of the resulted surface (only for `RenderQuality.shaded` and 1305 + `RenderQuality.lcd`) 1306 + quality = `dsdl2.ttf.RenderQuality` of the resulted render 1307 + wrapLength = maximum width in pixels for wrapping text to the new line; `0` to only wrap on line breaks 1308 + (wrapping only available from SDL_ttf 2.0.18) 1309 + Returns: `dsdl2.Surface` containing the rendered text 1310 + Throws: `dsdl.SDLException` if failed to render text 1311 +/ 1312 Surface render(wstring text, Color foreground, Color background = Color(0, 0, 0, 0), 1313 RenderQuality quality = RenderQuality.shaded, uint wrapLength = cast(uint)-1) const @trusted 1314 in { 1315 if (quality == RenderQuality.lcd) { 1316 assert(dsdl2.ttf.getVersion() >= Version(2, 20)); 1317 } 1318 1319 if (wrapLength != cast(uint)-1) { 1320 assert(dsdl2.ttf.getVersion() >= Version(2, 0, 18)); 1321 } 1322 1323 if (background != Color(0, 0, 0, 0)) { 1324 assert(quality == RenderQuality.shaded || quality == RenderQuality.lcd, "Only shaded and LCD render quality" 1325 ~ " can have a background color."); 1326 } 1327 } 1328 do { 1329 // `std.string.toStringz` doesn't have any `wstring` overloads. 1330 wchar[] ctext; 1331 ctext.length = text.length + 1; 1332 ctext[0 .. text.length] = text; 1333 ctext[text.length] = '\0'; 1334 1335 SDL_Surface* sdlSurface; 1336 switch (quality) { 1337 case RenderQuality.solid: 1338 if (wrapLength != cast(uint)-1) { 1339 static if (sdlTTFSupport >= SDLTTFSupport.v2_0_18) { 1340 sdlSurface = TTF_RenderUNICODE_Solid_Wrapped(cast(TTF_Font*) this.ttfFont, cast(ushort*) ctext.ptr, 1341 foreground.sdlColor, wrapLength); 1342 } 1343 } 1344 else { 1345 sdlSurface = TTF_RenderUNICODE_Solid(cast(TTF_Font*) this.ttfFont, cast(ushort*) ctext.ptr, 1346 foreground.sdlColor); 1347 } 1348 break; 1349 1350 case RenderQuality.shaded: 1351 if (wrapLength != cast(uint)-1) { 1352 static if (sdlTTFSupport >= SDLTTFSupport.v2_0_18) { 1353 sdlSurface = TTF_RenderUNICODE_Shaded_Wrapped(cast(TTF_Font*) this.ttfFont, cast(ushort*) ctext 1354 .ptr, 1355 foreground.sdlColor, background.sdlColor, wrapLength); 1356 } 1357 } 1358 else { 1359 sdlSurface = TTF_RenderUNICODE_Shaded(cast(TTF_Font*) this.ttfFont, cast(ushort*) ctext.ptr, 1360 foreground.sdlColor, background.sdlColor); 1361 } 1362 break; 1363 1364 case RenderQuality.blended: 1365 if (wrapLength != cast(uint)-1) { 1366 static if (sdlTTFSupport >= SDLTTFSupport.v2_0_18) { 1367 sdlSurface = TTF_RenderUNICODE_Blended_Wrapped(cast(TTF_Font*) this.ttfFont, 1368 cast(ushort*) ctext.ptr, foreground.sdlColor, wrapLength); 1369 } 1370 } 1371 else { 1372 sdlSurface = TTF_RenderUNICODE_Blended(cast(TTF_Font*) this.ttfFont, cast(ushort*) ctext.ptr, 1373 foreground.sdlColor); 1374 } 1375 break; 1376 1377 case RenderQuality.lcd: 1378 static if (sdlTTFSupport >= SDLTTFSupport.v2_20) { 1379 if (wrapLength != cast(uint)-1) { 1380 sdlSurface = TTF_RenderUNICODE_LCD_Wrapped(cast(TTF_Font*) this.ttfFont, cast(ushort*) ctext.ptr, 1381 foreground.sdlColor, background.sdlColor, wrapLength); 1382 } 1383 else { 1384 sdlSurface = TTF_RenderUNICODE_LCD(cast(TTF_Font*) this.ttfFont, cast(ushort*) ctext.ptr, 1385 foreground.sdlColor, background.sdlColor); 1386 } 1387 break; 1388 } 1389 assert(0); 1390 1391 default: 1392 assert(0); 1393 } 1394 1395 if (sdlSurface is null) { 1396 throw new SDLException; 1397 } 1398 1399 return new Surface(sdlSurface); 1400 } 1401 }