• 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

97.41
/src/ConsoleAppVisuals/elements/static_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.Elements;
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 Placement _placement;
17
    #endregion
18

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

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

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

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

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

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

47
    #endregion
48

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

80
    private bool CompatibilityCheck()
81
    {
82
        if (_lines.Count == 0)
30✔
83
        {
84
            throw new ArgumentException("The matrix is empty.");
2✔
85
        }
86
        int firstRowLength = _lines[0].Count;
28✔
87
        for (int i = 1; i < _lines.Count; i++)
108✔
88
        {
89
            if (_lines[i].Count != firstRowLength)
28✔
90
            {
91
                throw new ArgumentException("The matrix is not compatible.");
2✔
92
            }
93
        }
94
        return true;
26✔
95
    }
96

97
    #endregion
98

99
    #region Build Methods
100
    private void BuildMatrix()
101
    {
102
        var stringList = new List<string>();
78✔
103
        var localMax = new int[_lines[0].Count];
78✔
104

105
        CalculateLocalMax(localMax);
78✔
106
        string border = CreateBorder(localMax);
78✔
107
        stringList.Add(border);
78✔
108

109
        var separator = CreateSeparator(localMax);
78✔
110
        for (int i = 0; i < _lines.Count; i++)
428✔
111
        {
112
            StringBuilder lineBuilder = new StringBuilder("│ ");
136✔
113
            BuildLine(lineBuilder, localMax, i);
136✔
114
            stringList.Add(lineBuilder.ToString());
136✔
115
            if (i != _lines.Count - 1)
136✔
116
                stringList.Add(separator);
58✔
117
        }
118

119
        border = CreateFooter(localMax);
78✔
120
        stringList.Add(border);
78✔
121

122
        _displayArray = stringList.ToArray();
78✔
123
    }
78✔
124

125
    private void CalculateLocalMax(int[] localMax)
126
    {
127
        for (int i = 0; i < _lines.Count; i++)
428✔
128
        {
129
            for (int j = 0; j < _lines[i].Count; j++)
1,088✔
130
            {
131
                if (_lines[i][j]?.ToString()?.Length > localMax[j])
408!
132
                {
133
                    localMax[j] = _lines[i][j]?.ToString()?.Length ?? 0;
234!
134
                }
135
            }
136
        }
137
    }
78✔
138

139
    private string CreateBorder(int[] localMax)
140
    {
141
        string border = GetCorners[0].ToString();
78✔
142
        StringBuilder headerBuilder = new StringBuilder(border);
78✔
143
        for (int i = 0; i < _lines[0].Count; i++)
624✔
144
        {
145
            headerBuilder.Append(new string('─', localMax[i] + 2));
234✔
146
            headerBuilder.Append((i != _lines[0].Count - 1) ? "┬" : GetCorners[1].ToString());
234✔
147
        }
148
        return headerBuilder.ToString();
78✔
149
    }
150

151
    private string CreateSeparator(int[] localMax)
152
    {
153
        var separator = "├";
78✔
154
        StringBuilder separatorBuilder = new StringBuilder(separator);
78✔
155
        for (int i = 0; i < _lines[0].Count; i++)
624✔
156
        {
157
            separatorBuilder.Append(new string('─', localMax[i] + 2));
234✔
158
            separatorBuilder.Append((i != _lines[0].Count - 1) ? "┼" : "┤");
234✔
159
        }
160
        return separatorBuilder.ToString();
78✔
161
    }
162

163
    private void BuildLine(StringBuilder lineBuilder, int[] localMax, int i)
164
    {
165
        for (int j = 0; j < _lines[i].Count; j++)
1,088✔
166
        {
167
            lineBuilder.Append(
408!
168
                _lines[i][j]?.ToString()?.PadRight(localMax[j]) ?? " ".PadRight(localMax[j])
408✔
169
            );
408✔
170
            if (j != _lines[i].Count - 1)
408✔
171
                lineBuilder.Append(" │ ");
272✔
172
            else
173
                lineBuilder.Append(" │");
136✔
174
        }
175
    }
136✔
176

177
    private string CreateFooter(int[] localMax)
178
    {
179
        string border = GetCorners[2].ToString();
78✔
180
        StringBuilder footerBuilder = new StringBuilder(border);
78✔
181
        for (int i = 0; i < _lines[0].Count; i++)
624✔
182
        {
183
            footerBuilder.Append(new string('─', localMax[i] + 2));
234✔
184
            footerBuilder.Append((i != _lines[0].Count - 1) ? "┴" : GetCorners[3].ToString());
234✔
185
        }
186
        return footerBuilder.ToString();
78✔
187
    }
188
    #endregion
189

190
    #region Methods
191
    /// <summary>
192
    /// Toggles the rounded corners of the table.
193
    /// </summary>
194
    /// <remarks>
195
    /// For more information, refer to the following resources:
196
    /// <list type="bullet">
197
    /// <item><description><a href="https://morgankryze.github.io/ConsoleAppVisuals/">Documentation</a></description></item>
198
    /// <item><description><a href="https://github.com/MorganKryze/ConsoleAppVisuals/blob/main/example/">Example Project</a></description></item>
199
    /// </list>
200
    /// </remarks>
201
    public void SetRoundedCorners(bool value = true)
202
    {
203
        _roundedCorners = value;
2✔
204
        if (CompatibilityCheck())
2✔
205
        {
206
            BuildMatrix();
2✔
207
        }
208
    }
2✔
209

210
    /// <summary>
211
    /// This method is used to update the placement of the matrix.
212
    /// </summary>
213
    /// <param name="placement">The new placement of the matrix.</param>
214
    /// <remarks>
215
    /// For more information, refer to the following resources:
216
    /// <list type="bullet">
217
    /// <item><description><a href="https://morgankryze.github.io/ConsoleAppVisuals/">Documentation</a></description></item>
218
    /// <item><description><a href="https://github.com/MorganKryze/ConsoleAppVisuals/blob/main/example/">Example Project</a></description></item>
219
    /// </list>
220
    /// </remarks>
221
    public void UpdatePlacement(Placement placement)
222
    {
223
        _placement = placement;
×
224
    }
×
225

226
    /// <summary>
227
    /// Gets the element at the specified position.
228
    /// </summary>
229
    /// <param name="position">The position of the element.</param>
230
    /// <returns>The element at the specified position.</returns>
231
    /// <exception cref="ArgumentOutOfRangeException">Thrown when the position is out of range.</exception>
232
    /// <remarks>
233
    /// For more information, refer to the following resources:
234
    /// <list type="bullet">
235
    /// <item><description><a href="https://morgankryze.github.io/ConsoleAppVisuals/">Documentation</a></description></item>
236
    /// <item><description><a href="https://github.com/MorganKryze/ConsoleAppVisuals/blob/main/example/">Example Project</a></description></item>
237
    /// </list>
238
    /// </remarks>
239
    public T? GetItem(Position position)
240
    {
241
        if (position.X >= _lines.Count || position.Y >= _lines[position.X].Count)
10✔
242
        {
243
            throw new ArgumentOutOfRangeException(nameof(position), "Position is out of range.");
2✔
244
        }
245
        return _lines[position.X][position.Y];
8✔
246
    }
247

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

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

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

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

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

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

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