-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathAdvancedSlider.cs
304 lines (268 loc) · 11.4 KB
/
AdvancedSlider.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
using Microsoft.SqlServer.Server;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Globalization;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.Xml.Linq;
namespace UserControlTesterProject
{
public partial class AdvancedSlider : UserControl
{
private double ActualValue;
/// <summary>
/// Use the required format specifier string. The default is "G":
/// https://learn.microsoft.com/en-us/dotnet/standard/base-types/standard-numeric-format-strings#GFormatString.
/// Use Precision specifier if required, for example scientific notation "E" has a default of 6 precision.
/// If you need less or more, you can change this like "E3" for example (in this case the 3rd digit will be rounded).
/// </summary>
[Description("Use the required format specifier string. The default is \"G\"")]
public string NumberFormatSpecifier { get; set; } = "G";
public double MinimumValue { get; private set; }
public double MaximumValue { get; private set; }
/// <summary>
/// If false, out of range values will be ignored. If true, value will be coerced to actual min or max limit.
/// Default is false.
/// </summary>
[Description("If false, out of range values will be ignored. If true, value will be coerced to actual MinimumValue or MaximumValue limit.")]
public bool CoerceOutOfRange { get; set; } = false;
/// <summary>
/// Label text.
/// </summary>
[Description("Control label text")]
public string Label
{
get => parameterLabel.Text;
set => parameterLabel.Text = value;
}
/// <summary>
/// Sets the small steps for the trackBar integer range between 0-1000
/// </summary>
public int SmallChange
{
get => trackBar.SmallChange;
set => trackBar.SmallChange = value;
}
/// <summary>
/// Sets the large steps for the trackBar integer range between 0-1000
/// </summary>
public int LargeChange
{
get => trackBar.LargeChange;
set => trackBar.LargeChange = value;
}
[Description("Sets the trackBar/slider steps. The slider resolution will be (MaximumValue-MinimumValue)/sliderResolution. Default is 1000.")]
public int SliderResolution { get; private set; } = 1000;
/// <summary>
/// Sets the trackBar/slider steps.
/// The slider resolution will be (MaximumValue-MinimumValue)/sliderResolution. Default is 1000.
/// </summary>
public void SetSliderResolution(int sliderResolution)
{
SliderResolution = sliderResolution;
trackBar.Maximum = SliderResolution;
//recalc slider position
trackBar.Value = (int)Math.Floor(CalcPercent(ActualValue) / 100 * SliderResolution);
}
/// <summary>
/// Color used to indicate edit mode of the control. Default is Color.LightBlue.
/// </summary>
public Color ValidatingColor { get; set; } = Color.LightBlue;
[Browsable(true)]
[Category("Action")]
[Description("Invoked each time when the value changes. Slider scrolling changes are included")]
public event EventHandler ValueChanged;
[Browsable(true)]
[Category("Action")]
[Description("Invoked each time when the value changes. Slider scrolling not included!")]
public event EventHandler ValueChangedFinal;
[Browsable(true)]
[Category("Action")]
[Description("Invoked when Enter key is released")]
public event EventHandler EnterKeyUpCustom;
[Browsable(true)]
[Category("Action")]
[Description("Invoked when the focus is lost")]
public event EventHandler FocusLostCustom;
[Browsable(true)]
[Category("Action")]
[Description("Invoked when input was not parsable as a number")]
public event EventHandler InvalidInput;
[Browsable(true)]
[Category("Action")]
[Description("Invoked when input is out of range")]
public event EventHandler OutOfRange;
public AdvancedSlider()
{
InitializeComponent();
textBox.BackColor = SystemColors.Window;
trackBar.Minimum = 0;
trackBar.Maximum = SliderResolution;
MinimumValue = 0;
MaximumValue = SliderResolution;
}
/// <summary>
/// Sets the minimum limit of the accepted input range. If actual value is below the new limit, we set it to the new limit.
/// </summary>
/// <param name="minLimit">Requested new minimum limit.</param>
public void SetMinimum(double minLimit)
{
MinimumValue = minLimit;
if (ActualValue < minLimit)
{
ActualValue = minLimit;
ValueChanged?.Invoke(this, null);
ValueChangedFinal?.Invoke(this, null);
textBox.Text = ActualValue.ToString(NumberFormatSpecifier, CultureInfo.InvariantCulture);
textBox.BackColor = SystemColors.Window;
trackBar.Value = (int)Math.Floor(CalcPercent(ActualValue) / 100 * SliderResolution);
}
}
/// <summary>
/// Sets the maximum limit of the accepted input range. If actual value is above the new limit, we set it to the new limit.
/// </summary>
/// <param name="maxLimit">Requested new minimum limit.</param>
public void SetMaximum(double maxLimit)
{
MaximumValue = maxLimit;
if (ActualValue > maxLimit)
{
ActualValue = maxLimit;
ValueChanged?.Invoke(this, null);
ValueChangedFinal?.Invoke(this, null);
textBox.Text = ActualValue.ToString(NumberFormatSpecifier, CultureInfo.InvariantCulture);
textBox.BackColor = SystemColors.Window;
trackBar.Value = (int)Math.Floor(CalcPercent(ActualValue) / 100 * SliderResolution);
}
}
private void HandleOutOfRange(double newVal)
{
if (newVal > MaximumValue)
{
if (CoerceOutOfRange)
{
ActualValue = MaximumValue;
ValueChanged?.Invoke(this, null);
ValueChangedFinal?.Invoke(this, null);
}
OutOfRange?.Invoke(this, null);
}
else if (newVal < MinimumValue)
{
if (CoerceOutOfRange)
{
ActualValue = MinimumValue;
ValueChanged?.Invoke(this, null);
ValueChangedFinal?.Invoke(this, null);
}
OutOfRange?.Invoke(this, null);
}
else
{
ActualValue = newVal;
ValueChanged?.Invoke(this, null);
ValueChangedFinal?.Invoke(this, null);
}
}
/// <summary>
/// Use this to programmatically set the value of the user control.
/// </summary>
/// <param name="newVal"></param>
public void SetValue(double newVal)
{
HandleOutOfRange(newVal);
textBox.Text = ActualValue.ToString(NumberFormatSpecifier, CultureInfo.InvariantCulture);
textBox.BackColor = SystemColors.Window;
trackBar.Value = (int)Math.Floor(CalcPercent(ActualValue) / 100 * SliderResolution);
}
private double CalcPercent(double value)
{
return (value - MinimumValue) / (MaximumValue - MinimumValue) * 100;
}
private double CalcValueFromPercent(double percent)
{
return percent / 100 * (MaximumValue - MinimumValue) + MinimumValue;
}
/// <summary>
/// Get the double value the user control currently holds.
/// </summary>
/// <returns></returns>
public double GetValue()
{
return ActualValue;
}
public void EnableToolTip(string text)
{
toolTip1.SetToolTip(textBox, text);
}
public void DisableToolTip()
{
toolTip1.RemoveAll();
}
private void textBox_KeyUp(object sender, KeyEventArgs e)
{
if (e.KeyCode == Keys.Enter)
{
if (double.TryParse(textBox.Text, NumberStyles.Any, CultureInfo.InvariantCulture, out double newVal))
{
HandleOutOfRange(newVal);
}
else InvalidInput?.Invoke(this, e);
EnterKeyUpCustom?.Invoke(this, e);
textBox.Text = ActualValue.ToString(NumberFormatSpecifier, CultureInfo.InvariantCulture);
textBox.BackColor = SystemColors.Window;
trackBar.Value = (int)Math.Floor(CalcPercent(ActualValue) / 100 * SliderResolution);
}
}
private void textBox_Leave(object sender, EventArgs e)
{
if (double.TryParse(textBox.Text, NumberStyles.Any, CultureInfo.InvariantCulture, out double newVal))
{
HandleOutOfRange(newVal);
}
else InvalidInput?.Invoke(this, e);
FocusLostCustom?.Invoke(this, e);
textBox.Text = ActualValue.ToString(NumberFormatSpecifier, CultureInfo.InvariantCulture);
trackBar.Value = (int)Math.Floor(CalcPercent(ActualValue) / 100 * SliderResolution);
textBox.BackColor = SystemColors.Window;
}
private void textBox_Enter(object sender, EventArgs e)
{
textBox.BackColor = ValidatingColor;
}
private void textBox_TextChanged(object sender, EventArgs e)
{
textBox.BackColor = ValidatingColor;
}
private void trackBar_Scroll(object sender, EventArgs e)
{
double percent = ((double)trackBar.Value / SliderResolution) * 100;
ActualValue = CalcValueFromPercent(percent);
ValueChanged?.Invoke(this, null);
textBox.Text = ActualValue.ToString(NumberFormatSpecifier, CultureInfo.InvariantCulture);
}
private void trackBar_MouseUp(object sender, MouseEventArgs e)
{
double percent = ((double)trackBar.Value / SliderResolution) * 100;
ActualValue = CalcValueFromPercent(percent);
ValueChanged?.Invoke(this, null);
ValueChangedFinal?.Invoke(this, null);
textBox.Text = ActualValue.ToString(NumberFormatSpecifier, CultureInfo.InvariantCulture);
textBox.BackColor = SystemColors.Window;
}
private void trackBar_KeyUp(object sender, KeyEventArgs e)
{
double percent = ((double)trackBar.Value / SliderResolution) * 100;
ActualValue = CalcValueFromPercent(percent);
ValueChanged?.Invoke(this, null);
ValueChangedFinal?.Invoke(this, null);
textBox.Text = ActualValue.ToString(NumberFormatSpecifier, CultureInfo.InvariantCulture);
textBox.BackColor = SystemColors.Window;
}
}
}