1 module evael.graphics.gui.controls.Button;
2 
3 import evael.graphics.gui.controls.Control;
4 import evael.graphics.Font;
5 
6 import evael.utils.Math;
7 
8 import evael.utils.Size;
9 
10 class Button : Control
11 {
12 	public enum Type
13 	{
14 		Text = (1u << 0),
15 		Icon = (1u << 1)
16 	}
17 
18 	/// Button text
19 	private wstring m_text;
20 
21 	/// Text position
22 	private vec2 m_textPosition;
23 
24 	/// Icon position
25 	private vec2 m_iconPosition;
26 
27 	/// Button type
28 	private Type m_type;
29 
30 	/// Button icon
31 	private Icon m_icon;
32 
33 	public this(in float x, in float y, in int width = 0, in int height = 0)
34 	{
35 		this("", x, y, width, height);
36 	}
37 	
38 	public this(in wstring text, in float x = 0, in float y = 0, in int width = 0, in int height = 0)
39 	{
40 		this(text, vec2(x, y), Size!int(width, height));
41 	}
42 
43 	public this(in wstring text, in vec2 position)
44 	{
45 		this(text, position, Size!int(0, 0));
46 	}
47 
48 	public this(in wstring text, in vec2 position, in Size!int size)
49 	{
50 		super(position, size);
51 
52 		this.m_name = "button";
53 		this.m_text = text;
54 		this.m_textPosition = vec2(0.0f, 0.0f);
55 		this.m_iconPosition = this.m_textPosition;
56 		this.m_type = Type.Text;
57 	}
58 
59 	/**
60 	 * Renders the button
61 	 */
62 	public override void draw(in float deltaTime)
63 	{
64 		if(!this.m_isVisible)
65 			return;
66 
67 		super.draw(deltaTime);
68 
69 		if(this.m_type & Type.Text)
70 		{
71 			this.m_theme.font.draw(this.m_text, vec2(this.m_realPosition.x, this.m_realPosition.y) + this.m_textPosition, 
72 				this.m_theme.fontColor, this.m_theme.fontSize, this.m_theme.drawTextShadow);
73 		}
74 
75 		if(this.m_type & Type.Icon)
76 		{
77 			this.m_theme.iconFont.draw(cpToUtf(this.m_icon), vec2(this.m_realPosition.x, this.m_realPosition.y) + this.m_iconPosition, 
78 				this.m_theme.fontColor, this.m_theme.fontSize);
79 		}
80 	}
81 
82 	/**
83 	 * Event called on mouse button click
84 	 * Params:
85 	 *		mouseButton : mouse button	 
86 	 *		mousePosition : mouse position
87 	 */
88 	public override void onMouseClick(in MouseButton mouseButton, in ref vec2 mousePosition)
89 	{
90 		super.onMouseClick(mouseButton, mousePosition);
91 
92 		if(this.m_isEnabled)
93 		{
94 			this.switchState!(State.Clicked);
95 		}
96 	}
97 
98 	/**
99 	 * Event called on mouse button release
100 	 * Params:
101 	 *		mouseButton : mouse button
102 	 */
103 	public override void onMouseUp(in MouseButton mouseButton)
104 	{
105 		super.onMouseUp(mouseButton);
106 
107 		if(this.m_isEnabled)
108 		{
109 			this.switchState!(State.Hovered);
110 		}
111 	}
112 
113 	/**
114 	 * Event called when mouse enters in control's rect
115 	 * Params:
116 	 * 		 mousePosition : mouse position
117 	 */
118 	public override void onMouseMove(in ref vec2 mousePosition)
119 	{
120 		super.onMouseMove(mousePosition);
121 
122 		if(this.m_isEnabled)
123 		{
124 			if(this.isClicked)
125 			{
126 				this.switchState!(State.Clicked);
127 			}
128 			else
129 			{
130 				this.switchState!(State.Hovered);
131 			}
132 		}
133 	}
134 
135 	/**
136 	 * Event called when mouse leaves control's rect
137 	 */
138 	public override void onMouseLeave()
139 	{
140 		super.onMouseLeave();
141 
142 		if(this.m_isEnabled)
143 		{
144 			this.switchState!(State.Normal);
145 		}
146 	}
147 
148 	/**
149 	 * Initializes control
150 	 */
151 	public override void initialize()
152 	{
153 		float width = 0.0f, height = 0.0f;
154 
155 		if(this.m_type & Type.Text && this.m_text.length)
156 		{
157 			immutable bounds = this.m_theme.font.getTextBounds(this.m_text, 0, this.m_theme.fontSize);
158 
159 			width = bounds[2] - bounds[0];
160 			height = bounds[3] - bounds[1];
161 		}
162 
163 		if (this.m_type & Type.Icon)
164 		{
165 			immutable bounds = this.m_theme.iconFont.getTextBounds(cpToUtf(this.m_icon), 0, this.m_theme.fontSize);
166 
167 			width += bounds[2] - bounds[0];
168 			
169 			// We don't need to add heights together, we just take the highest value
170 			immutable iconHeight = bounds[3] - bounds[1];
171 
172 			if(iconHeight > height)
173 			{
174 				height = iconHeight;
175 			}
176 		}
177 
178 		if(width > this.m_size.width)
179 		{
180 			this.m_size.width = cast(int)width + 10;
181 		}
182 
183 		if(height > this.m_size.height)
184 		{
185 			this.m_size.height = cast(int)height + 5;
186 		}
187 
188 		import std.math : round;
189 		
190 		this.m_textPosition.x = round(this.m_size.halfWidth - (width / 2));
191 		this.m_textPosition.y = round(this.m_size.halfHeight - (height / 2));
192 
193 		this.m_iconPosition = this.m_textPosition;
194 		
195 		super.initialize();
196 	}
197 
198 	@property
199 	{
200 		public void type(in Type value) nothrow @nogc
201 		{
202 			this.m_type = value;
203 		}
204 
205 		public void icon(in Icon value) nothrow @nogc
206 		{
207 			this.m_icon = value;
208 		}
209 	}
210 
211 
212 }