1 module evael.graphics.gui.controls.TextBlock;
2 
3 import evael.graphics.gui.controls.Control;
4 import evael.graphics.Font;
5 
6 import evael.utils.Math;
7 import evael.utils.Size;
8 import evael.utils.Color;
9 
10 class TextBlock : Control
11 {
12 	enum Type
13 	{
14 		FixedSize,
15 		DynamicSize
16 	}
17 
18 	enum TextAlignement
19 	{
20 		Center = (1u << 0),		// Vertical align
21 		Middle = (1u << 1),		// Horizontal align
22 		Top =    (1u << 2),
23 		Left =   (1u << 3),
24 		Bottom = (1u << 4),
25 		Right  = (1u << 5)
26 	}
27 
28 	/// Textblock text
29 	private wstring m_text;
30 
31 	/// Text position
32 	private vec2 m_textPosition;
33 
34 	/// Text color
35 	private Color m_color;
36 
37 	/// Text alignement
38 	private TextAlignement m_textAlignement;
39 
40 	private int m_nvgTextAlignement;
41 
42 	/// Type
43 	private Type m_type;
44 
45 	/// Indicates if textblock use theme color or custom color
46 	private bool m_useThemeColor;
47 
48 	public this()(in auto ref vec2 position, in auto ref Size!int size)
49 	{
50 		super(position, size);
51 
52 		this.m_name = "textBlock";
53 		this.m_color = Color.Black;
54 
55 		this.m_textAlignement = TextAlignement.Center | TextAlignement.Middle;
56 		this.m_type = Type.DynamicSize;
57 
58 		this.m_useThemeColor = true;
59 	}
60 
61 	public this(in float x = 0, in float y = 0)
62 	{
63 		this(vec2(x, y), Size!int(0, 0));
64 	}
65 
66 	public this(in float x, in float y, in int width, in int height)
67 	{
68 		this(vec2(x, y), Size!int(width, height));
69 
70 		this.m_type = Type.FixedSize;
71 	}
72 
73 	public override void draw(in float deltaTime)
74 	{
75 		if (!this.m_isVisible)
76 			return;
77 
78 		super.draw(deltaTime);
79 
80 		auto color = this.m_useThemeColor ? this.m_theme.fontColor : this.m_color;
81 
82 		this.m_theme.font.draw(this.m_text, vec2(this.m_realPosition.x, this.m_realPosition.y) + this.m_textPosition,
83 			color, this.m_theme.fontSize,  this.m_theme.drawTextShadow, this.m_nvgTextAlignement );
84 	}
85 
86 	/**
87 	 */
88 	public override void initialize()
89 	{
90 		super.initialize();
91 		
92 		if(this.m_text.length)
93 		{
94 			this.text = this.m_text;
95 		}
96 	}
97 
98 	@property
99 		public override void opacity(in ubyte value)   @nogc
100 		{
101 		super.opacity = value;
102 
103 		if(!this.m_useThemeColor)
104 		{
105 			this.m_color.a = value;
106 		}
107 		}
108 
109 	@property
110 	{
111 		public wstring text() const nothrow @nogc
112 		{
113 			return this.m_text;
114 		}
115 
116 
117 		public void text(in string value)
118 		{
119 			import std.conv;
120 
121 			this.text = value.to!wstring();
122 		}
123 
124 		public void text(in wstring value)
125 		{
126 			this.m_text = value;
127 
128 			if(this.m_theme !is null && this.m_theme.font !is null)
129 			{
130 				if(this.m_type == Type.DynamicSize)
131 				{
132 					float[4] bounds = this.m_theme.font.getTextBounds(this.m_text, 0, this.m_theme.fontSize);
133 
134 					immutable float w = bounds[2] - bounds[0];
135 					immutable float h = bounds[3] - bounds[1];
136 					
137 					this.m_size.width = cast(int)w + 10;
138 					this.m_size.height = cast(int)h + 5;
139 
140 					this.m_textPosition.x = this.m_size.halfWidth;
141 					this.m_textPosition.y = this.m_size.halfHeight;
142 					this.m_nvgTextAlignement = NVGalign.NVG_ALIGN_CENTER | NVGalign.NVG_ALIGN_MIDDLE;
143 				}
144 				else if(this.m_type == Type.FixedSize)
145 				{
146 					this.m_nvgTextAlignement = 0;
147 					
148 					/**
149 					 * Vertical alignement
150 					 */
151 					if(this.m_textAlignement & TextAlignement.Center)
152 					{
153 						this.m_textPosition.y = this.m_size.halfHeight;
154 						this.m_nvgTextAlignement = NVGalign.NVG_ALIGN_CENTER;
155 					}
156 
157 					if(this.m_textAlignement & TextAlignement.Bottom)
158 					{
159 						this.m_textPosition.y = this.m_size.height;
160 						this.m_nvgTextAlignement += NVGalign.NVG_ALIGN_BOTTOM;
161 					}
162 
163 					if(this.m_textAlignement & TextAlignement.Top)
164 					{
165 						this.m_textPosition.y = 0;
166 						this.m_nvgTextAlignement += NVGalign.NVG_ALIGN_TOP;
167 					}
168 
169 					/**
170 					 * Horizontal alignement
171 					 */
172 					if(this.m_textAlignement & TextAlignement.Middle)
173 					{
174 						this.m_textPosition.x = this.m_size.halfWidth;
175 						this.m_nvgTextAlignement += NVGalign.NVG_ALIGN_MIDDLE;
176 					}
177 
178 					if(this.m_textAlignement & TextAlignement.Left)
179 					{
180 						this.m_textPosition.x = 0;
181 						this.m_nvgTextAlignement += NVGalign.NVG_ALIGN_LEFT;
182 					}
183 
184 					if(this.m_textAlignement & TextAlignement.Right)
185 					{
186 						this.m_textPosition.x = this.m_size.width;
187 						this.m_nvgTextAlignement += NVGalign.NVG_ALIGN_RIGHT;
188 					}
189 				}
190 				else
191 				{
192 					/*wstring realText;
193 
194 					int i, j;
195 
196 					// We try to cut the text in multiple lines
197 					if(this.m_theme.font.getTextWidth(value) > this.m_size.width - this.m_position.x)
198 					{
199 						while(j < value.length)
200 						{
201 							j++;
202 
203 							if(this.m_theme.font.getTextWidth(value[i..j]) >= (this.m_size.width - this.m_position.x - 3))
204 							{
205 								realText = realText ~ value[i..j] ~ '\n';
206 								i = j;
207 							}
208 						}
209 
210 						realText ~= value[i..j];
211 					}
212 					else realText = value;
213 
214 					this.m_text = realText;*/
215 				}
216 			}
217 		}
218 
219 		public void color(in Color value) nothrow @nogc
220 		{
221 			this.m_color = value;
222 			this.m_useThemeColor = false;
223 		}
224 
225 		public void textAlignement(in TextAlignement value) nothrow  @nogc
226 		{
227 			this.m_textAlignement = value;
228 		}
229 	}
230 }