• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

MorganKryze / ConsoleAppVisuals / 8158191062

05 Mar 2024 02:47PM UTC coverage: 86.165% (+0.9%) from 85.231%
8158191062

push

github

MorganKryze
📖 (readme) update roadmap

931 of 1144 branches covered (81.38%)

Branch coverage included in aggregate %.

1803 of 2029 relevant lines covered (88.86%)

412.64 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

76.74
/src/ConsoleAppVisuals/elements/interactive_elements/FloatSelector.cs
1
/*
2
    GNU GPL License 2024 MorganKryze(Yann Vidamment)
3
    For full license information, please visit: https://github.com/MorganKryze/ConsoleAppVisuals/blob/main/LICENSE
4
*/
5
namespace ConsoleAppVisuals.Elements;
6

7
/// <summary>
8
/// Defines the number selector of the console window.
9
/// </summary>
10
/// <remarks>
11
/// For more information, refer to the following resources:
12
/// <list type="bullet">
13
/// <item><description><a href="https://morgankryze.github.io/ConsoleAppVisuals/">Documentation</a></description></item>
14
/// <item><description><a href="https://github.com/MorganKryze/ConsoleAppVisuals/blob/main/example/">Example Project</a></description></item>
15
/// </list>
16
/// </remarks>
17
public class FloatSelector : InteractiveElement<float>
18
{
19
    #region Fields
20
    private string _question;
21
    private float _minimumValue;
22
    private float _maximumValue;
23
    private float _startValue;
24
    private float _step;
25
    private bool _roundedCorners;
26
    private Placement _placement;
27
    #endregion
28

29
    #region Properties
30
    /// <summary>
31
    /// The placement of the selector on the console.
32
    /// </summary>
33
    public override Placement Placement => _placement;
14✔
34

35
    /// <summary>
36
    /// The height of the selector.
37
    /// </summary>
38
    public override int Height => 7;
2✔
39

40
    /// <summary>
41
    /// The width of the selector.
42
    /// </summary>
43
    public override int Width =>
44
        Math.Max(
2✔
45
            _question.Length,
2✔
46
            $" {Core.GetSelector.Item1} {BuildNumber((float)Math.Round(_maximumValue, 1))} {Core.GetSelector.Item2} ".Length
2✔
47
        );
2✔
48

49
    /// <summary>
50
    /// The question to ask the user.
51
    /// </summary>
52
    public string Question => _question;
2✔
53

54
    /// <summary>
55
    /// The minimum value of the selector.
56
    /// </summary>
57
    public float Min => _minimumValue;
2✔
58

59
    /// <summary>
60
    /// The maximum value of the selector.
61
    /// </summary>
62
    public float Max => _maximumValue;
2✔
63

64
    /// <summary>
65
    /// The start value of the selector.
66
    /// </summary>
67
    public float Start => _startValue;
2✔
68

69
    /// <summary>
70
    /// The step of the selector.
71
    /// </summary>
72
    public float Step => _step;
2✔
73

74
    /// <summary>
75
    /// Whether the corners of the selector are rounded.
76
    /// </summary>
77
    public bool RoundedCorners => _roundedCorners;
2✔
78
    #endregion
79

80
    #region Constructor
81
    /// <summary>
82
    /// The constructor of the FloatSelector class.
83
    /// </summary>
84
    /// <param name="question">The question to ask the user.</param>
85
    /// <param name="min">The minimum value of the selector.</param>
86
    /// <param name="max">The maximum value of the selector.</param>
87
    /// <param name="start">The start value of the selector.</param>
88
    /// <param name="step">The step of the selector.</param>
89
    /// <param name="placement">The placement of the selector on the console.</param>
90
    /// <param name="roundedCorners">Whether the corners of the selector are rounded.</param>
91
    /// <remarks>
92
    /// For more information, refer to the following resources:
93
    /// <list type="bullet">
94
    /// <item><description><a href="https://morgankryze.github.io/ConsoleAppVisuals/">Documentation</a></description></item>
95
    /// <item><description><a href="https://github.com/MorganKryze/ConsoleAppVisuals/blob/main/example/">Example Project</a></description></item>
96
    /// </list>
97
    /// </remarks>
98
    public FloatSelector(
30✔
99
        string question,
30✔
100
        float min,
30✔
101
        float max,
30✔
102
        float start = 0,
30✔
103
        float step = 100,
30✔
104
        Placement placement = Placement.TopCenter,
30✔
105
        bool roundedCorners = false
30✔
106
    )
30✔
107
    {
108
        _question = question;
30✔
109
        CheckMinNotHigherThanMax(min, max);
30✔
110
        _minimumValue = min;
26✔
111
        _maximumValue = max;
26✔
112
        _startValue = CheckStart(start, _minimumValue, _maximumValue);
26✔
113
        _step = CheckStep(step, _minimumValue, _maximumValue);
20✔
114
        _placement = placement;
16✔
115
        _roundedCorners = roundedCorners;
16✔
116
    }
16✔
117

118
    private static void CheckMinNotHigherThanMax(float min, float max)
119
    {
120
        if (min > max)
30✔
121
            throw new ArgumentException(
4✔
122
                "The minimum value cannot be greater than the maximum value."
4✔
123
            );
4✔
124
    }
26✔
125

126
    private static float CheckStart(float start, float min, float max)
127
    {
128
        if (start < min)
26✔
129
            throw new ArgumentException("The start value cannot be less than the minimum value.");
4✔
130
        if (start > max)
22✔
131
            throw new ArgumentException(
2✔
132
                "The start value cannot be greater than the maximum value."
2✔
133
            );
2✔
134
        return start;
20✔
135
    }
136

137
    private static float CheckStep(float step, float min, float max)
138
    {
139
        if (step > max - min)
20✔
140
            throw new ArgumentException(
2✔
141
                "The step cannot be greater than the difference between the minimum and maximum values."
2✔
142
            );
2✔
143
        if (step <= 0f)
18✔
144
            throw new ArgumentException("The step cannot be less than 0.");
2✔
145
        return step;
16✔
146
    }
147
    #endregion
148

149
    #region Methods
150

151
    /// <summary>
152
    /// This method is used to update the question of the selector.
153
    /// </summary>
154
    /// <param name="question">The question to ask the user.</param>
155
    /// <remarks>
156
    /// For more information, refer to the following resources:
157
    /// <list type="bullet">
158
    /// <item><description><a href="https://morgankryze.github.io/ConsoleAppVisuals/">Documentation</a></description></item>
159
    /// <item><description><a href="https://github.com/MorganKryze/ConsoleAppVisuals/blob/main/example/">Example Project</a></description></item>
160
    /// </list>
161
    /// </remarks>
162
    public void UpdateQuestion(string question)
163
    {
164
        _question = question;
×
165
    }
×
166

167
    /// <summary>
168
    /// This method is used to update the minimum value of the selector.
169
    /// </summary>
170
    /// <param name="min">The minimum value of the selector.</param>
171
    /// <remarks>
172
    /// For more information, refer to the following resources:
173
    /// <list type="bullet">
174
    /// <item><description><a href="https://morgankryze.github.io/ConsoleAppVisuals/">Documentation</a></description></item>
175
    /// <item><description><a href="https://github.com/MorganKryze/ConsoleAppVisuals/blob/main/example/">Example Project</a></description></item>
176
    /// </list>
177
    /// </remarks>
178
    public void UpdateMin(float min)
179
    {
180
        CheckMinNotHigherThanMax(min, _maximumValue);
×
181
        _minimumValue = min;
×
182
        _startValue = CheckStart(_startValue, _minimumValue, _maximumValue);
×
183
        _step = CheckStep(_step, _minimumValue, _maximumValue);
×
184
    }
×
185

186
    /// <summary>
187
    /// This method is used to update the maximum value of the selector.
188
    /// </summary>
189
    /// <param name="max">The maximum value of the selector.</param>
190
    /// <remarks>
191
    /// For more information, refer to the following resources:
192
    /// <list type="bullet">
193
    /// <item><description><a href="https://morgankryze.github.io/ConsoleAppVisuals/">Documentation</a></description></item>
194
    /// <item><description><a href="https://github.com/MorganKryze/ConsoleAppVisuals/blob/main/example/">Example Project</a></description></item>
195
    /// </list>
196
    /// </remarks>
197
    public void UpdateMax(float max)
198
    {
199
        CheckMinNotHigherThanMax(_minimumValue, max);
×
200
        _maximumValue = max;
×
201
        _startValue = CheckStart(_startValue, _minimumValue, _maximumValue);
×
202
        _step = CheckStep(_step, _minimumValue, _maximumValue);
×
203
    }
×
204

205
    /// <summary>
206
    /// This method is used to update the start value of the selector.
207
    /// </summary>
208
    /// <param name="start">The start value of the selector.</param>
209
    /// <remarks>
210
    /// For more information, refer to the following resources:
211
    /// <list type="bullet">
212
    /// <item><description><a href="https://morgankryze.github.io/ConsoleAppVisuals/">Documentation</a></description></item>
213
    /// <item><description><a href="https://github.com/MorganKryze/ConsoleAppVisuals/blob/main/example/">Example Project</a></description></item>
214
    /// </list>
215
    /// </remarks>
216
    public void UpdateStart(float start)
217
    {
218
        _startValue = CheckStart(start, _minimumValue, _maximumValue);
×
219
    }
×
220

221
    /// <summary>
222
    /// This method is used to update the step of the selector.
223
    /// </summary>
224
    /// <param name="step">The step of the selector.</param>
225
    /// <remarks>
226
    /// For more information, refer to the following resources:
227
    /// <list type="bullet">
228
    /// <item><description><a href="https://morgankryze.github.io/ConsoleAppVisuals/">Documentation</a></description></item>
229
    /// <item><description><a href="https://github.com/MorganKryze/ConsoleAppVisuals/blob/main/example/">Example Project</a></description></item>
230
    /// </list>
231
    /// </remarks>
232
    public void UpdateStep(float step)
233
    {
234
        _step = CheckStep(step, _minimumValue, _maximumValue);
×
235
    }
×
236

237
    /// <summary>
238
    /// This method is used to update the placement of the selector.
239
    /// </summary>
240
    /// <param name="placement">The placement of the selector on the console.</param>
241
    /// <remarks>
242
    /// For more information, refer to the following resources:
243
    /// <list type="bullet">
244
    /// <item><description><a href="https://morgankryze.github.io/ConsoleAppVisuals/">Documentation</a></description></item>
245
    /// <item><description><a href="https://github.com/MorganKryze/ConsoleAppVisuals/blob/main/example/">Example Project</a></description></item>
246
    /// </list>
247
    /// </remarks>
248
    public void UpdatePlacement(Placement placement)
249
    {
250
        _placement = placement;
×
251
    }
×
252

253
    /// <summary>
254
    /// This method is used to update the rounded corners of the selector.
255
    /// </summary>
256
    /// <param name="roundedCorners">Whether the corners of the selector are rounded.</param>
257
    /// <remarks>
258
    /// For more information, refer to the following resources:
259
    /// <list type="bullet">
260
    /// <item><description><a href="https://morgankryze.github.io/ConsoleAppVisuals/">Documentation</a></description></item>
261
    /// <item><description><a href="https://github.com/MorganKryze/ConsoleAppVisuals/blob/main/example/">Example Project</a></description></item>
262
    /// </list>
263
    /// </remarks>
264
    public void SetRoundedCorners(bool roundedCorners = true)
265
    {
266
        _roundedCorners = roundedCorners;
×
267
    }
×
268

269
    /// <summary>
270
    /// This method is used to draw the selector on the console.
271
    /// </summary>
272
    [Visual]
273
    protected override void RenderElementActions()
274
    {
275
        Core.WriteContinuousString(_question, Line, default, 1500, 50);
276
        float currentNumber = _startValue;
277
        int lineSelector = Line + 4;
278
        bool loop = true;
279
        while (loop)
280
        {
281
            DisplayChoices(lineSelector, currentNumber);
282

283
            switch (Console.ReadKey(true).Key)
284
            {
285
                case ConsoleKey.UpArrow:
286
                case ConsoleKey.Z:
287
                    currentNumber = NextNumber(Direction.Up, currentNumber);
288
                    break;
289
                case ConsoleKey.DownArrow:
290
                case ConsoleKey.S:
291
                    currentNumber = NextNumber(Direction.Down, currentNumber);
292
                    break;
293
                case ConsoleKey.Enter:
294
                    SendResponse(
295
                        this,
296
                        new InteractionEventArgs<float>(Output.Selected, currentNumber)
297
                    );
298
                    Window.DeactivateElement(this);
299
                    loop = false;
300
                    break;
301
                case ConsoleKey.Escape:
302
                    SendResponse(
303
                        this,
304
                        new InteractionEventArgs<float>(Output.Escaped, currentNumber)
305
                    );
306
                    loop = false;
307
                    break;
308
                default:
309
                    break;
310
            }
311
            Thread.Sleep(1);
312
        }
313
    }
314

315
    [Visual]
316
    void DisplayChoices(int lineSelector, float currentNumber)
317
    {
318
        Core.WritePositionedString(
319
            BuildLine(Direction.Up),
320
            TextAlignment.Center,
321
            false,
322
            lineSelector - 2
323
        );
324
        Core.WritePositionedString(
325
            BuildNumber((float)Math.Round(NextNumber(Direction.Up, currentNumber), 1)),
326
            TextAlignment.Center,
327
            false,
328
            lineSelector - 1
329
        );
330
        Core.WritePositionedString(
331
            $" {Core.GetSelector.Item1} {BuildNumber((float)Math.Round(currentNumber, 1))} {Core.GetSelector.Item2} ",
332
            TextAlignment.Center,
333
            true,
334
            lineSelector
335
        );
336
        Core.WritePositionedString(
337
            BuildNumber((float)Math.Round(NextNumber(Direction.Down, currentNumber), 1)),
338
            TextAlignment.Center,
339
            false,
340
            lineSelector + 1
341
        );
342
        Core.WritePositionedString(
343
            BuildLine(Direction.Down),
344
            TextAlignment.Center,
345
            false,
346
            lineSelector + 2
347
        );
348
    }
349

350
    [Visual]
351
    float NextNumber(Direction direction, float currentNumber)
352
    {
353
        if (direction == Direction.Up)
354
        {
355
            if (currentNumber + _step <= _maximumValue)
356
                return currentNumber + _step;
357
            else if (currentNumber + _step > _maximumValue)
358
                return _minimumValue;
359
        }
360
        else
361
        {
362
            if (currentNumber - _step >= _minimumValue)
363
                return currentNumber - _step;
364
            else if (currentNumber - _step < _minimumValue)
365
                return _maximumValue;
366
        }
367
        return currentNumber;
368
    }
369

370
    [Visual]
371
    string BuildLine(Direction direction)
372
    {
373
        string corners = _roundedCorners ? "╭╮╰╯" : "┌┐└┘";
374
        StringBuilder line = new();
375
        for (int i = 0; i < _maximumValue.ToString().Length + 2; i++)
376
            line.Append('─');
377
        if (direction == Direction.Up)
378
            line.Insert(0, corners[0].ToString(), 1).Append(corners[1], 1);
379
        else
380
            line.Insert(0, corners[2].ToString(), 1).Append(corners[3], 1);
381
        return line.ToString();
382
    }
383

384
    string BuildNumber(float number)
385
    {
386
        StringBuilder numberStr = new();
2✔
387
        numberStr.Append("│ ");
2✔
388
        numberStr.Append(
2✔
389
            number.ToString().ResizeString(_maximumValue.ToString().Length, TextAlignment.Center)
2✔
390
        );
2✔
391
        numberStr.Append(" │");
2✔
392
        return numberStr.ToString();
2✔
393
    }
394
    #endregion
395
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc