1 /** 2 * Copyright © Novelate 2020 3 * License: MIT (https://github.com/Novelate/NovelateEngine/blob/master/LICENSE) 4 * Author: Jacob Jensen (bausshf) 5 * Website: https://novelate.com/ 6 * ------ 7 * Novelate is a free and open-source visual novel engine and framework written in the D programming language. 8 * It can be used freely for both personal and commercial projects. 9 * ------ 10 * Module Description: 11 * This module handles text wrapping which is an essential feature when working with text that has to fit into a specific width. It's currently not a very performant algorithm but it gets the job done. 12 */ 13 module novelate.textwrap; 14 15 import std.uni : isWhite; 16 import std.conv : to; 17 18 import dsfml.graphics : Text; 19 20 import novelate.fonts; 21 22 /** 23 * Creates text that wraps when it exceeds a given width. It does so by adding a new line at the last space given before the text exceeds the width and does so for all of the text. 24 * Params: 25 * text = The text to wrap. 26 * fontName = The font used for the text. 27 * fontSize = The size of the font used. 28 * width = The width to wrap the text at when it exceeds. 29 * Returns: 30 * A string that is wrapable based on the original given string and conditions. 31 */ 32 dstring wrapableText(dstring text, string fontName, uint fontSize, size_t width) 33 { 34 if (!text || !text.length) 35 { 36 return ""; 37 } 38 39 width -= (fontSize / 2); 40 41 auto font = retrieveFont(fontName, FontStyle.normal); 42 43 bool[] splitIndexes = new bool[text.length]; 44 bool[] includeSplitters = new bool[text.length]; 45 46 dstring calculateText = ""; 47 48 auto lastWhiteIndex = 0; 49 bool hasForeignCharacters = false; 50 51 foreach (ref i; 0 .. text.length) 52 { 53 dchar c = text[i]; 54 bool isForeighnCharacter = cast(ushort)c > 128; 55 56 if (!hasForeignCharacters && isForeighnCharacter) 57 { 58 width -= cast(uint)(cast(double)fontSize * 1.2); 59 60 hasForeignCharacters = true; 61 } 62 63 if (c.isWhite || isForeighnCharacter) 64 { 65 lastWhiteIndex = i; 66 } 67 68 calculateText ~= c; 69 70 Text textInstance = new Text(); 71 textInstance.setFont(font); 72 textInstance.setString(calculateText); 73 textInstance.setCharacterSize(fontSize); 74 75 auto textWidth = textInstance.getLocalBounds().width; 76 77 if (textWidth >= width) 78 { 79 splitIndexes[lastWhiteIndex] = true; 80 includeSplitters[lastWhiteIndex] = isForeighnCharacter; 81 calculateText = ""; 82 83 i = lastWhiteIndex + 1; 84 } 85 } 86 87 calculateText = ""; 88 89 foreach (i; 0 .. text.length) 90 { 91 dchar c = text[i]; 92 93 if (splitIndexes[i]) 94 { 95 if (includeSplitters[i]) 96 { 97 calculateText ~= c ~ to!dstring("\r\n"); 98 } 99 else 100 { 101 calculateText ~= "\r\n"; 102 } 103 } 104 else 105 { 106 calculateText ~= c; 107 } 108 } 109 110 return calculateText; 111 }