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

MorganKryze / ConsoleAppVisuals / 8114215569

01 Mar 2024 04:29PM UTC coverage: 85.767% (-9.3%) from 95.093%
8114215569

push

github

MorganKryze
🤖 moved to publish

865 of 1072 branches covered (80.69%)

Branch coverage included in aggregate %.

1708 of 1928 relevant lines covered (88.59%)

273.5 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;
21✔
34

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

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

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

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

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

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

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

74
    /// <summary>
75
    /// Whether the corners of the selector are rounded.
76
    /// </summary>
77
    public bool RoundedCorners => _roundedCorners;
3✔
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(
45✔
99
        string question,
45✔
100
        float min,
45✔
101
        float max,
45✔
102
        float start = 0,
45✔
103
        float step = 100,
45✔
104
        Placement placement = Placement.TopCenter,
45✔
105
        bool roundedCorners = false
45✔
106
    )
45✔
107
    {
108
        _question = question;
45✔
109
        CheckMinNotHigherThanMax(min, max);
45✔
110
        _minimumValue = min;
39✔
111
        _maximumValue = max;
39✔
112
        _startValue = CheckStart(start, _minimumValue, _maximumValue);
39✔
113
        _step = CheckStep(step, _minimumValue, _maximumValue);
30✔
114
        _placement = placement;
24✔
115
        _roundedCorners = roundedCorners;
24✔
116
    }
24✔
117

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

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

137
    private static float CheckStep(float step, float min, float max)
138
    {
139
        if (step > max - min)
30✔
140
            throw new ArgumentException(
3✔
141
                "The step cannot be greater than the difference between the minimum and maximum values."
3✔
142
            );
3✔
143
        if (step <= 0f)
27✔
144
            throw new ArgumentException("The step cannot be less than 0.");
3✔
145
        return step;
24✔
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
        while (true)
279
        {
280
            DisplayChoices(lineSelector, currentNumber);
281

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

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

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

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

380
    string BuildNumber(float number)
381
    {
382
        StringBuilder numberStr = new();
3✔
383
        numberStr.Append("│ ");
3✔
384
        numberStr.Append(
3✔
385
            number.ToString().ResizeString(_maximumValue.ToString().Length, TextAlignment.Center)
3✔
386
        );
3✔
387
        numberStr.Append(" │");
3✔
388
        return numberStr.ToString();
3✔
389
    }
390
    #endregion
391
}
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