1 /* 2 ******************************************************************************************* 3 * Dgame (a D game framework) - Copyright (c) Randy Schütt 4 * 5 * This software is provided 'as-is', without any express or implied warranty. 6 * In no event will the authors be held liable for any damages arising from 7 * the use of this software. 8 * 9 * Permission is granted to anyone to use this software for any purpose, 10 * including commercial applications, and to alter it and redistribute it 11 * freely, subject to the following restrictions: 12 * 13 * 1. The origin of this software must not be misrepresented; you must not claim 14 * that you wrote the original software. If you use this software in a product, 15 * an acknowledgment in the product documentation would be appreciated but is 16 * not required. 17 * 18 * 2. Altered source versions must be plainly marked as such, and must not be 19 * misrepresented as being the original software. 20 * 21 * 3. This notice may not be removed or altered from any source distribution. 22 ******************************************************************************************* 23 */ 24 module Dgame.Graphic.Text; 25 26 private: 27 28 import Dgame.Graphic.Drawable; 29 import Dgame.Graphic.Transformable; 30 import Dgame.Graphic.Surface; 31 import Dgame.Graphic.Texture; 32 import Dgame.Graphic.Color; 33 34 import Dgame.Math.Vertex; 35 import Dgame.Math.Geometry; 36 37 import Dgame.System.Font; 38 39 public: 40 41 /** 42 * Text defines a graphical 2D text, that can be drawn on screen. 43 * 44 * Author: Randy Schuett (rswhite4@googlemail.com) 45 */ 46 class Text : Transformable, Drawable { 47 private: 48 Vertex[4] _vertices; 49 50 Texture _texture; 51 Font* _font; 52 53 string _text; 54 55 bool _redraw = true; 56 57 protected: 58 @nogc 59 override void draw(ref const Window wnd) nothrow { 60 this.update(); 61 62 if (_text.length != 0) 63 wnd.draw(Geometry.TriangleStrip, super.getMatrix(), &_texture, _vertices[]); 64 } 65 66 @nogc 67 final void _init() pure nothrow { 68 // #2 69 _vertices[1].texCoord.x = 1; 70 // #3 71 _vertices[2].texCoord.y = 1; 72 // #4 73 _vertices[3].texCoord.x = 1; 74 _vertices[3].texCoord.y = 1; 75 76 foreach (ref Vertex v; _vertices) { 77 v.color = Color4f.White; 78 } 79 } 80 81 public: 82 /** 83 * The foreground color. Default is Color4b.Black. 84 */ 85 Color4b foreground = Color4b.Black; 86 /** 87 * The background color. Default is Color4b.White. 88 * 89 * Note: The background color is ignored if your mode is not Font.Mode.Shaded 90 */ 91 Color4b background = Color4b.White; 92 /** 93 * The Font mode which is default Font.Mode.Solid. 94 */ 95 Font.Mode mode = Font.Mode.Solid; 96 97 final: 98 /** 99 * CTor 100 */ 101 @nogc 102 this(ref Font fnt, string str = null) pure nothrow { 103 _font = &fnt; 104 _text = str; 105 106 _init(); 107 } 108 109 /** 110 * Update the Texture and redraw the text, if necessary. 111 * This method is called automatically if the Text is drawn onto the Window. 112 * But if you need specific informations (e.g. width/height) before the draw call, 113 * you can call the method by yourself. 114 */ 115 @nogc 116 void update() nothrow { 117 if (_text.length != 0 && _redraw) { 118 assert(_font, "No font given"); 119 120 _redraw = false; 121 122 Surface srfc = _font.render(_text, this.foreground, this.background, this.mode); 123 _texture.loadFrom(srfc); 124 125 // Update Vertices 126 immutable uint tw = _texture.width; 127 immutable uint th = _texture.height; 128 129 // #2 130 _vertices[1].position.x = tw; 131 // #3 132 _vertices[2].position.y = th; 133 // #4 134 _vertices[3].position.x = tw; 135 _vertices[3].position.y = th; 136 } 137 } 138 139 /** 140 * Returns the width 141 */ 142 @property 143 @nogc 144 uint width() const pure nothrow { 145 return _texture.width; 146 } 147 148 /** 149 * Returns the height 150 */ 151 @property 152 @nogc 153 uint height() const pure nothrow { 154 return _texture.height; 155 } 156 157 /** 158 * Returns the used Texture which contains the last rendered Text 159 */ 160 @nogc 161 inout(Texture*) getTexture() inout pure nothrow { 162 return &_texture; 163 } 164 165 /** 166 * Format a given string by using std.string.format. 167 * Therefore the formating pattern is identical. 168 */ 169 void format(Args...)(string text, Args args) pure { 170 import std..string : format; 171 172 immutable string formated = text.length != 0 ? format(text, args) : null; 173 if (formated != _text) { 174 _text = formated; 175 _redraw = true; 176 } 177 } 178 179 /** 180 * Set or reset the current text by using std.conv.to!(string) if the data is not a string 181 */ 182 void setData(T)(T data) pure nothrow { 183 static if (is(T == string)) 184 immutable string text = data; 185 else static if (is(T == typeof(null))) 186 immutable string text = null; 187 else { 188 import std.conv : to; 189 190 immutable string text = to!string(data); 191 } 192 193 if (text != _text) { 194 _text = text; 195 _redraw = true; 196 } 197 } 198 199 /** 200 * Concatenate the current string with another. 201 * 202 * Examples: 203 * --- 204 * Font fnt = new Font("samples/font/arial.ttf", 12); 205 * Text t = new Text(font); 206 * t.setData("My new string"); 207 * t ~= "is great!"; // t draws now 'My new string is great' on screen. 208 * --- 209 * The example above is the same as if you do: 210 * --- 211 * t += "is great!"; 212 * --- 213 * Both operators (~ and +) are allowed. 214 */ 215 Text opBinary(string op)(string text) pure nothrow 216 if (op == "~" || op == "+") 217 { 218 _text ~= text; 219 _redraw = true; 220 221 return this; 222 } 223 224 /** 225 * Returns the current text 226 */ 227 @nogc 228 string getText() const pure nothrow { 229 return _text; 230 } 231 232 /** 233 * Set or reset the current Font 234 */ 235 @nogc 236 void setFont(ref Font fnt) pure nothrow { 237 _font = &fnt; 238 _redraw = true; 239 } 240 241 /** 242 * Returns a pointer to the current Font 243 */ 244 @nogc 245 inout(Font*) getFont() inout pure nothrow { 246 return _font; 247 } 248 }