1 module evael.graphics.gui.controls.ContextMenuStrip;
2 
3 import std.conv;
4 
5 import evael.graphics.gui.controls.Container;
6 
7 import evael.utils.Math;
8 
9 import evael.utils.Size;
10 import evael.utils.Color;
11 
12 class ContextMenuStrip : Container
13 {
14 	/// Item size
15 	private Size!int m_itemSize;
16 
17 	/// Position for the next item
18 	private vec2 m_nextItemPosition;
19 
20 	public this(in float x, in float y, in int width = 0)
21 	{
22 		this(vec2(x, y), Size!int(width, 0));
23 	}
24 
25 	public this(in vec2 position, in Size!int size)
26 	{
27 		super(position, size);
28 
29 		this.m_name = "contextMenuStrip";
30 
31 		this.m_itemSize = Size!int(this.m_size.width, 0);
32 
33 		this.m_movable = false;
34 	}
35 
36 	public override void draw(in float deltaTime)
37 	{
38 		super.draw(deltaTime);
39 	}
40 
41 
42 	/**
43 	 * Adds item
44 	 * Params:
45 	 *		 itemText : item text
46 	 */
47 	public void addItem(in string itemText, OnClickEvent onClick)
48 	{
49 		this.addItem(itemText.to!wstring, onClick);
50 	}
51 
52 	public void addItem(in wstring itemText, OnClickEvent onClick)
53 	{/*
54 		this.m_size.height = this.m_size.height + 20;
55 
56 		// 1.0f = Border pixel
57 		this.m_nextItemPosition = vec2(1.0f, this.m_size.height - 19.0f);
58 */
59 		auto item = new ContextMenuStripItem(this.m_controls.length, itemText, vec2(0), this.m_itemSize);
60 		item.onClickEvent = onClick;
61 
62 		this.addChild(item);
63 	}
64 
65 	/**
66 	 * Initializes control
67 	 */
68 	public override void initialize()
69 	{
70 		super.initialize();
71 
72 		// Now that child controls have been correctly sized, we can defines ContextMenuStrip's height
73 
74 		int y = 0;
75 		int height = 0;
76 
77 		foreach(control; this.m_controls)
78 		{
79 			height += control.size.height;
80 			control.position = vec2(0, y);
81 			control.realPosition = control.position + this.m_realPosition;
82 			y += height;
83 		}
84 
85 		this.m_size.height = height;
86 	}
87 }
88 
89 
90 class ContextMenuStripItem : Control
91 {
92 	/// Item text
93 	private wstring m_text;
94 
95 	/// Item text position
96 	private vec2 m_textPosition;
97 
98 	/// Item index
99 	private int m_index;
100 
101 	public this(in int index, in wstring text, in vec2 position, in Size!int size)
102 	{
103 		super(position, size);
104 
105 		this.m_name = "contextMenuStripItem";
106 		this.m_index = index;
107 		this.m_text = text;
108 	}
109 
110 
111 	/**
112 	 * Renders the item
113 	 */
114 	public override void draw(in float deltaTime)
115 	{
116 		if(!this.m_isVisible)
117 			return;
118 
119 		super.draw(deltaTime);
120 
121 		this.m_theme.font.draw(this.m_text, vec2(this.m_realPosition.x, this.m_realPosition.y) + this.m_textPosition, 
122 			this.m_theme.fontColor, this.m_theme.fontSize);
123 	}
124 
125 	/**
126 	 * Initializes control
127 	 */
128 	public override void initialize()
129 	{
130 		if(this.m_text.length)
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 			if(w > this.m_size.width)
138 			{
139 				this.m_size.width = cast(int)w + 10;
140 			}
141 
142 			if(h > this.m_size.height)
143 			{
144 				this.m_size.height = cast(int)h + 5;
145 			}
146 
147 			import std.math : round;
148 			
149 			this.m_textPosition.x = 2.0f;
150 			this.m_textPosition.y = round(this.m_size.halfHeight - (h / 2));
151 		}
152 
153 		super.initialize();
154 	}
155 
156 	/**
157 	 * Event called on mouse button click
158 	 * Params:
159 	 *		mouseButton : mouse button	 
160 	 *		mousePosition : mouse position
161 	 */
162 	public override void onMouseClick(in MouseButton mouseButton, in ref vec2 mousePosition)
163 	{
164 		super.onMouseClick(mouseButton, mousePosition);
165 		this.switchState!(State.Clicked);
166 	}
167 
168 	/**
169 	 * Event called on mouse button release
170 	 * Params:
171 	 *		mouseButton : mouse button
172 	 */
173 	public override void onMouseUp(in MouseButton mouseButton)
174 	{
175 		super.onMouseUp(mouseButton);
176 		this.switchState!(State.Hovered);
177 	}
178 
179 	/**
180 	 * Event called when mouse enters in control's rect
181 	 * Params:
182 	 * 		 mousePosition : mouse position
183 	 */
184 	public override void onMouseMove(in ref vec2 mousePosition)
185 	{
186 		if(this.hasFocus)
187 		{
188 			return;
189 		}
190 
191 		super.onMouseMove(mousePosition);
192 
193 		if(this.isClicked)
194 		{
195 			this.switchState!(State.Clicked);
196 		}
197 		else
198 		{
199 			this.switchState!(State.Hovered);
200 		}
201 	}
202 
203 	/**
204 	 * Event called when mouse leaves in control's rect
205 	 */
206 	public override void onMouseLeave()
207 	{
208 		super.onMouseLeave();
209 
210 		this.switchState!(State.Normal);
211 	}
212 
213 	/**
214 	 * Properties
215 	 */
216 	@property
217 	public int index() const nothrow @nogc
218 	{
219 		return this.m_index;
220 	}
221 
222 }