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

MorganKryze / ConsoleAppVisuals / 7993638304

pending completion
7993638304

push

github

MorganKryze
📖 add files and contributing recommendation

827 of 916 branches covered (90.28%)

Branch coverage included in aggregate %.

1676 of 1694 relevant lines covered (98.94%)

104.0 hits per line

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

97.87
/src/ConsoleAppVisuals/elements/Matrix.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;
6

7
/// <summary>
8
/// A matrix class for the console.
9
/// </summary>
10
public class Matrix<T> : Element
11
{
12
    #region Fields: Lines, display array, rounded corners, placement, line
13
    private readonly List<List<T?>> _lines;
14
    private string[]? _displayArray;
15
    private bool _roundedCorners;
16
    private readonly Placement _placement;
17
    private readonly int _line;
18
    #endregion
19

20
    #region Properties: GetCorners, Count, Placement, Height, Width, Line
21
    private string GetCorners => _roundedCorners ? "╭╮╰╯" : "┌┐└┘";
468✔
22

23
    /// <summary>
24
    /// Gets the rounded corners boolean value of the matrix.
25
    /// </summary>
26
    public bool RoundedCorners => _roundedCorners;
3✔
27

28
    /// <summary>
29
    /// Gets the number of lines in the matrix.
30
    /// </summary>
31
    public int Count => _lines.Count;
15✔
32

33
    /// <summary>
34
    /// Gets the placement of the matrix.
35
    /// </summary>
36
    public override Placement Placement => _placement;
3✔
37

38
    /// <summary>
39
    /// Gets the height of the matrix.
40
    /// </summary>
41
    public override int Height => _displayArray?.Length ?? 0;
6✔
42

43
    /// <summary>
44
    /// Gets the width of the matrix.
45
    /// </summary>
46
    public override int Width => _displayArray?.Max(x => x.Length) ?? 0;
21✔
47

48
    /// <summary>
49
    /// Gets the line of the matrix.
50
    /// </summary>
51
    public override int Line => _line;
3✔
52
    #endregion
53

54
    #region Constructor
55
    /// <summary>
56
    /// The natural constructor of the <see cref="Matrix{T}"/> class.
57
    /// </summary>
58
    /// <param name="rawLines">The matrix to be used.</param>
59
    /// <param name="roundedCorners">Whether the matrix should have rounded corners or not.</param>
60
    /// <param name="placement">The placement of the matrix.</param>
61
    /// <param name="line">The line of the matrix.</param>
62
    /// <exception cref="ArgumentException">Thrown when the matrix is empty or not compatible (lines are not of the same length).</exception>
63
    /// <remarks>Refer to the example project to understand how to implement it available at https://github.com/MorganKryze/ConsoleAppVisuals/blob/main/example/Program.cs </remarks>
64
    public Matrix(
84✔
65
        List<List<T?>>? rawLines = null,
84✔
66
        bool roundedCorners = false,
84✔
67
        Placement placement = Placement.TopCenter,
84✔
68
        int? line = null
84✔
69
    )
84✔
70
    {
71
        _roundedCorners = roundedCorners;
84✔
72
        _placement = placement;
84✔
73
        _line = Window.CheckLine(line) ?? Window.GetLineAvailable(placement);
84!
74
        if (rawLines is not null)
84✔
75
        {
76
            _lines = rawLines;
42✔
77
            if (CompatibilityCheck())
42✔
78
            {
79
                BuildMatrix();
36✔
80
            }
81
        }
82
        else
83
        {
84
            _lines = new List<List<T?>>();
42✔
85
        }
86
    }
42✔
87

88
    private bool CompatibilityCheck()
89
    {
90
        if (_lines.Count == 0)
45✔
91
        {
92
            throw new ArgumentException("The matrix is empty.");
3✔
93
        }
94
        int firstRowLength = _lines[0].Count;
42✔
95
        for (int i = 1; i < _lines.Count; i++)
162✔
96
        {
97
            if (_lines[i].Count != firstRowLength)
42✔
98
            {
99
                throw new ArgumentException("The matrix is not compatible.");
3✔
100
            }
101
        }
102
        return true;
39✔
103
    }
104

105
    #endregion
106

107
    #region Build Methods
108
    private void BuildMatrix()
109
    {
110
        var stringList = new List<string>();
117✔
111
        var localMax = new int[_lines[0].Count];
117✔
112

113
        CalculateLocalMax(localMax);
117✔
114
        string border = CreateBorder(localMax);
117✔
115
        stringList.Add(border);
117✔
116

117
        var separator = CreateSeparator(localMax);
117✔
118
        for (int i = 0; i < _lines.Count; i++)
642✔
119
        {
120
            StringBuilder lineBuilder = new StringBuilder("│ ");
204✔
121
            BuildLine(lineBuilder, localMax, i);
204✔
122
            stringList.Add(lineBuilder.ToString());
204✔
123
            if (i != _lines.Count - 1)
204✔
124
                stringList.Add(separator);
87✔
125
        }
126

127
        border = CreateFooter(localMax);
117✔
128
        stringList.Add(border);
117✔
129

130
        _displayArray = stringList.ToArray();
117✔
131
    }
117✔
132

133
    private void CalculateLocalMax(int[] localMax)
134
    {
135
        for (int i = 0; i < _lines.Count; i++)
642✔
136
        {
137
            for (int j = 0; j < _lines[i].Count; j++)
1,632✔
138
            {
139
                if (_lines[i][j]?.ToString()?.Length > localMax[j])
612!
140
                {
141
                    localMax[j] = _lines[i][j]?.ToString()?.Length ?? 0;
351!
142
                }
143
            }
144
        }
145
    }
117✔
146

147
    private string CreateBorder(int[] localMax)
148
    {
149
        string border = GetCorners[0].ToString();
117✔
150
        StringBuilder headerBuilder = new StringBuilder(border);
117✔
151
        for (int i = 0; i < _lines[0].Count; i++)
936✔
152
        {
153
            headerBuilder.Append(new string('─', localMax[i] + 2));
351✔
154
            headerBuilder.Append((i != _lines[0].Count - 1) ? "┬" : GetCorners[1].ToString());
351✔
155
        }
156
        return headerBuilder.ToString();
117✔
157
    }
158

159
    private string CreateSeparator(int[] localMax)
160
    {
161
        var separator = "├";
117✔
162
        StringBuilder separatorBuilder = new StringBuilder(separator);
117✔
163
        for (int i = 0; i < _lines[0].Count; i++)
936✔
164
        {
165
            separatorBuilder.Append(new string('─', localMax[i] + 2));
351✔
166
            separatorBuilder.Append((i != _lines[0].Count - 1) ? "┼" : "┤");
351✔
167
        }
168
        return separatorBuilder.ToString();
117✔
169
    }
170

171
    private void BuildLine(StringBuilder lineBuilder, int[] localMax, int i)
172
    {
173
        for (int j = 0; j < _lines[i].Count; j++)
1,632✔
174
        {
175
            lineBuilder.Append(
612!
176
                _lines[i][j]?.ToString()?.PadRight(localMax[j]) ?? " ".PadRight(localMax[j])
612✔
177
            );
612✔
178
            if (j != _lines[i].Count - 1)
612✔
179
                lineBuilder.Append(" │ ");
408✔
180
            else
181
                lineBuilder.Append(" │");
204✔
182
        }
183
    }
204✔
184

185
    private string CreateFooter(int[] localMax)
186
    {
187
        string border = GetCorners[2].ToString();
117✔
188
        StringBuilder footerBuilder = new StringBuilder(border);
117✔
189
        for (int i = 0; i < _lines[0].Count; i++)
936✔
190
        {
191
            footerBuilder.Append(new string('─', localMax[i] + 2));
351✔
192
            footerBuilder.Append((i != _lines[0].Count - 1) ? "┴" : GetCorners[3].ToString());
351✔
193
        }
194
        return footerBuilder.ToString();
117✔
195
    }
196
    #endregion
197

198
    #region Methods
199
    /// <summary>
200
    /// Toggles the rounded corners of the table.
201
    /// </summary>
202
    /// <remarks>
203
    /// For more information, refer to the following resources:
204
    /// <list type="bullet">
205
    /// <item><description><a href="https://morgankryze.github.io/ConsoleAppVisuals/">Documentation</a></description></item>
206
    /// <item><description><a href="https://github.com/MorganKryze/ConsoleAppVisuals/blob/main/example/Program.cs">Example Project</a></description></item>
207
    /// </list>
208
    /// </remarks>
209
    public void SetRoundedCorners(bool value = true)
210
    {
211
        _roundedCorners = value;
3✔
212
        if (CompatibilityCheck())
3✔
213
        {
214
            BuildMatrix();
3✔
215
        }
216
    }
3✔
217

218
    /// <summary>
219
    /// Gets the element at the specified position.
220
    /// </summary>
221
    /// <param name="position">The position of the element.</param>
222
    /// <returns>The element at the specified position.</returns>
223
    /// <exception cref="ArgumentOutOfRangeException">Thrown when the position is out of range.</exception>
224
    /// <remarks>
225
    /// For more information, refer to the following resources:
226
    /// <list type="bullet">
227
    /// <item><description><a href="https://morgankryze.github.io/ConsoleAppVisuals/">Documentation</a></description></item>
228
    /// <item><description><a href="https://github.com/MorganKryze/ConsoleAppVisuals/blob/main/example/Program.cs">Example Project</a></description></item>
229
    /// </list>
230
    /// </remarks>
231
    public T? GetItem(Position position)
232
    {
233
        if (position.X >= _lines.Count || position.Y >= _lines[position.X].Count)
15✔
234
        {
235
            throw new ArgumentOutOfRangeException(nameof(position), "Position is out of range.");
3✔
236
        }
237
        return _lines[position.X][position.Y];
12✔
238
    }
239

240
    /// <summary>
241
    /// Adds a line to the matrix.
242
    /// </summary>
243
    /// <param name="line">The line to add.</param>
244
    /// <returns>True if the line has been added successfully, false otherwise.</returns>
245
    /// <exception cref="ArgumentException">Thrown when the line is not of the same length as the other lines.</exception>
246
    /// <remarks>
247
    /// For more information, refer to the following resources:
248
    /// <list type="bullet">
249
    /// <item><description><a href="https://morgankryze.github.io/ConsoleAppVisuals/">Documentation</a></description></item>
250
    /// <item><description><a href="https://github.com/MorganKryze/ConsoleAppVisuals/blob/main/example/Program.cs">Example Project</a></description></item>
251
    /// </list>
252
    /// </remarks>
253
    public bool AddLine(List<T?> line)
254
    {
255
        if (_lines.Count == 0)
66✔
256
        {
257
            _lines.Add(line);
33✔
258
        }
259
        else if (line.Count != _lines[0].Count)
33✔
260
        {
261
            throw new ArgumentException(
3✔
262
                "Line has a different number of elements than the existing lines."
3✔
263
            );
3✔
264
        }
265
        else
266
        {
267
            _lines.Add(line);
30✔
268
        }
269
        BuildMatrix();
63✔
270
        return true;
63✔
271
    }
272

273
    /// <summary>
274
    /// Inserts a line at the specified index.
275
    /// </summary>
276
    /// <param name="index">The index of the line to insert.</param>
277
    /// <param name="line">The line to insert.</param>
278
    /// <returns>True if the line has been inserted successfully, false otherwise.</returns>
279
    /// <exception cref="ArgumentOutOfRangeException">Thrown when the index is out of range.</exception>
280
    /// <exception cref="ArgumentException">Thrown when the line is not of the same length as the other lines.</exception>
281
    /// <remarks>
282
    /// For more information, refer to the following resources:
283
    /// <list type="bullet">
284
    /// <item><description><a href="https://morgankryze.github.io/ConsoleAppVisuals/">Documentation</a></description></item>
285
    /// <item><description><a href="https://github.com/MorganKryze/ConsoleAppVisuals/blob/main/example/Program.cs">Example Project</a></description></item>
286
    /// </list>
287
    /// </remarks>
288
    public bool InsertLine(int index, List<T?> line)
289
    {
290
        if (index < 0 || index >= _lines.Count)
9✔
291
        {
292
            throw new ArgumentOutOfRangeException(nameof(index), "Index is out of range.");
3✔
293
        }
294
        else if (line.Count != _lines[0].Count)
6✔
295
        {
296
            throw new ArgumentException(
3✔
297
                "Line has a different number of elements than the existing lines."
3✔
298
            );
3✔
299
        }
300
        _lines.Insert(index, line);
3✔
301
        BuildMatrix();
3✔
302
        return true;
3✔
303
    }
304

305
    /// <summary>
306
    /// Updates a line in the matrix.
307
    /// </summary>
308
    /// <param name="index">The index of the line to update.</param>
309
    /// <param name="line">The new line.</param>
310
    /// <returns>True if the line has been updated successfully, false otherwise.</returns>
311
    /// <exception cref="ArgumentOutOfRangeException">Thrown when the index is out of range.</exception>
312
    /// <exception cref="ArgumentException">Thrown when the line is not of the same length as the other lines.</exception>
313
    /// <remarks>
314
    /// For more information, refer to the following resources:
315
    /// <list type="bullet">
316
    /// <item><description><a href="https://morgankryze.github.io/ConsoleAppVisuals/">Documentation</a></description></item>
317
    /// <item><description><a href="https://github.com/MorganKryze/ConsoleAppVisuals/blob/main/example/Program.cs">Example Project</a></description></item>
318
    /// </list>
319
    /// </remarks>
320
    public bool UpdateLine(int index, List<T?> line)
321
    {
322
        if (index < 0 || index >= _lines.Count)
9✔
323
        {
324
            throw new ArgumentOutOfRangeException(nameof(index), "Index is out of range.");
3✔
325
        }
326
        else if (line.Count != _lines[0].Count)
6✔
327
        {
328
            throw new ArgumentException(
3✔
329
                "Line has a different number of elements than the existing lines."
3✔
330
            );
3✔
331
        }
332
        _lines[index] = line;
3✔
333
        BuildMatrix();
3✔
334
        return true;
3✔
335
    }
336

337
    /// <summary>
338
    /// Updates an element in the matrix.
339
    /// </summary>
340
    /// <param name="position">The position of the element to update.</param>
341
    /// <param name="item">The new element.</param>
342
    /// <returns>True if the element has been updated successfully, false otherwise.</returns>
343
    /// <exception cref="ArgumentOutOfRangeException">Thrown when the position is out of range.</exception>
344
    /// <remarks>
345
    /// For more information, refer to the following resources:
346
    /// <list type="bullet">
347
    /// <item><description><a href="https://morgankryze.github.io/ConsoleAppVisuals/">Documentation</a></description></item>
348
    /// <item><description><a href="https://github.com/MorganKryze/ConsoleAppVisuals/blob/main/example/Program.cs">Example Project</a></description></item>
349
    /// </list>
350
    /// </remarks>
351
    public bool UpdateItem(Position position, T item)
352
    {
353
        if (position.X >= _lines.Count || position.Y >= _lines[position.X].Count)
9✔
354
        {
355
            throw new ArgumentOutOfRangeException(nameof(position), "Position is out of range.");
6✔
356
        }
357
        _lines[position.X][position.Y] = item;
3✔
358
        BuildMatrix();
3✔
359
        return true;
3✔
360
    }
361

362
    /// <summary>
363
    /// Removes a line from the matrix.
364
    /// </summary>
365
    /// <param name="index">The index of the line to remove.</param>
366
    /// <returns>True if the line has been removed successfully, false otherwise.</returns>
367
    /// <exception cref="ArgumentOutOfRangeException">Thrown when the index is out of range.</exception>
368
    /// <remarks>
369
    /// For more information, refer to the following resources:
370
    /// <list type="bullet">
371
    /// <item><description><a href="https://morgankryze.github.io/ConsoleAppVisuals/">Documentation</a></description></item>
372
    /// <item><description><a href="https://github.com/MorganKryze/ConsoleAppVisuals/blob/main/example/Program.cs">Example Project</a></description></item>
373
    /// </list>
374
    /// </remarks>
375
    public bool RemoveLine(int index)
376
    {
377
        if (index < 0 || index >= _lines.Count)
6✔
378
        {
379
            throw new ArgumentOutOfRangeException(nameof(index), "Index is out of range.");
3✔
380
        }
381
        _lines.RemoveAt(index);
3✔
382
        BuildMatrix();
3✔
383
        return true;
3✔
384
    }
385

386
    /// <summary>
387
    /// Removes an element from the matrix.
388
    /// </summary>
389
    /// <param name="position">The position of the element to remove.</param>
390
    /// <returns>True if the element has been removed successfully, false otherwise.</returns>
391
    /// <exception cref="ArgumentOutOfRangeException">Thrown when the position is out of range.</exception>
392
    /// <remarks>
393
    /// For more information, refer to the following resources:
394
    /// <list type="bullet">
395
    /// <item><description><a href="https://morgankryze.github.io/ConsoleAppVisuals/">Documentation</a></description></item>
396
    /// <item><description><a href="https://github.com/MorganKryze/ConsoleAppVisuals/blob/main/example/Program.cs">Example Project</a></description></item>
397
    /// </list>
398
    /// </remarks>
399
    public bool RemoveItem(Position position)
400
    {
401
        if (position.X >= _lines.Count || position.Y >= _lines[position.X].Count)
6✔
402
        {
403
            throw new ArgumentOutOfRangeException(nameof(position), "Position is out of range.");
3✔
404
        }
405
        _lines[position.X][position.Y] = default(T);
3✔
406
        BuildMatrix();
3✔
407
        return true;
3✔
408
    }
409
    #endregion
410

411
    #region Render Methods
412
    /// <summary>
413
    /// Writes the matrix instance to the console.
414
    /// </summary>
415
    /// <remarks>
416
    /// For more information, refer to the following resources:
417
    /// <list type="bullet">
418
    /// <item><description><a href="https://morgankryze.github.io/ConsoleAppVisuals/">Documentation</a></description></item>
419
    /// <item><description><a href="https://github.com/MorganKryze/ConsoleAppVisuals/blob/main/example/Program.cs">Example Project</a></description></item>
420
    /// </list>
421
    /// </remarks>
422
    protected override void RenderElementActions()
423
    {
424
        if (_displayArray is null || _displayArray.Length == 0)
6✔
425
            throw new InvalidOperationException(
3✔
426
                "The matrix has not been built yet. The matrix cannot be displayed"
3✔
427
            );
3✔
428
        Core.WriteMultiplePositionedLines(
3✔
429
            true,
3✔
430
            _placement.ToTextAlignment(),
3✔
431
            false,
3✔
432
            _line,
3✔
433
            _displayArray
3✔
434
        );
3✔
435
    }
3✔
436
    #endregion
437
}
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

© 2025 Coveralls, Inc