1 module evael.graphics.gui.controls.Slider;
2 
3 import std.algorithm : map;
4 import std.range : iota;
5 import std.array : array;
6 
7 import evael.graphics.gui.controls.Container;
8 import evael.graphics.gui.controls.Button;
9 import evael.graphics.gui.controls.Panel;
10 
11 import evael.utils.Math;
12 
13 import evael.utils.Size;
14 import evael.utils.Color;
15 
16 public class Slider : Container
17 {
18 	private alias void delegate(Control sender, int value) OnValueChangeEvent;
19 	private OnValueChangeEvent m_onValueChangeEvent;
20 
21 	/// Values
22 	private int m_minimumValue, m_maximumValue;
23 
24 	/// Possible values' position
25 	private int[] m_valuesPosition;
26 
27 	/// Current selected value
28 	private int m_currentValueIndex;
29 
30 	/// Incrementation, formula is : controlWidth / maximumValue
31 	private int m_incrementation;
32 
33 	private Button m_scrollButton;
34 
35 	public this(in float x, in float y, in int width)
36 	{
37 		this(vec2(x, y), Size!int(width + 20, 45));
38 	}
39 
40 	public this(in vec2 position, in Size!int size)
41 	{
42 		super(position, size);
43 
44 		this.m_opacity = 0;
45 
46 		Panel panel = new Panel(10, 20, size.width - 20, 5);
47 
48 		this.m_scrollButton = new Button(5, 16, 10, 16);
49 		this.m_scrollButton.type = Button.Type.Icon;
50 
51 		this.addChild(panel);
52 		this.addChild(this.m_scrollButton);
53 	}
54 
55 	/**
56 	 * Renders the slider
57 	 */
58 	public override void draw(in float deltaTime)
59 	{
60 		super.draw(deltaTime);
61 	}
62 
63 
64 
65 	/**
66 	 * Mouse enters in control's rect
67 	 * Params:
68 	 * 		 mousePosition : mouse's position
69 	 */
70 	public override void onMouseMove(in ref vec2 mousePosition)
71 	{	
72 		super.onMouseMove(mousePosition);
73 
74 		static vec2 lastMousePosition;
75 
76 		scope(exit) lastMousePosition =	mousePosition;
77 
78 		if(this.m_scrollButton.isClicked && mousePosition.x != lastMousePosition.x)
79 		{
80 			bool change = false;
81 
82 			vec2 buttonPosition = this.m_scrollButton.realPosition;
83 
84 			// Slide to right
85 			if(mousePosition.x > lastMousePosition.x && this.m_currentValueIndex < this.m_maximumValue + 1)
86 			{
87 				// We check if we reach half position for the next value
88 				if(mousePosition.x > buttonPosition.x + (this.m_incrementation / 2))
89 				{
90 					buttonPosition.x = (buttonPosition.x + this.m_incrementation);
91 					this.m_currentValueIndex++;
92 
93 					change = true;
94 				}
95 			}
96 			else if(mousePosition.x < lastMousePosition.x && this.m_currentValueIndex > 0)
97 			{
98 				if(mousePosition.x < buttonPosition.x - (this.m_incrementation / 2))
99 				{
100 					buttonPosition.x = (buttonPosition.x - this.m_incrementation);
101 					this.m_currentValueIndex--;
102 
103 					change = true;
104 				}
105 			}
106 
107 			// We update button's position and raise a new event if necessary
108 			if(change)
109 			{
110 				this.m_scrollButton.realPosition = buttonPosition;
111 
112 				if(this.m_onValueChangeEvent !is null)
113 					this.m_onValueChangeEvent(this, this.m_currentValueIndex);
114 			}
115 		}
116 	}
117 
118 	/**
119 	 * Properties
120 	 */
121 	@property 	
122 	public void onValueChangeEvent(OnValueChangeEvent callback) nothrow
123 	{
124 		this.m_onValueChangeEvent = callback;
125 	}
126 
127 	@property
128 	public void minimumValue(in int value) nothrow
129 	{
130 		this.m_minimumValue = value;
131 	}
132 
133 	@property
134 	public void maximumValue(in int value) nothrow
135 	{
136 		this.m_maximumValue = value;
137 
138 		this.m_incrementation = this.m_controls[0].size.width / value;
139 
140 		// this.m_values = iota(0, value + 1).map!(a => a * this.m_incrementation).array;
141 	}
142 
143 	@property
144 	public int value() const nothrow
145 	{
146 		return this.m_currentValueIndex;
147 	}
148 }