diff --git a/docs/documentation/specific.md b/docs/documentation/specific.md index 40803876..7092a4a8 100644 --- a/docs/documentation/specific.md +++ b/docs/documentation/specific.md @@ -87,7 +87,50 @@ students.UpdateLine(3, new () {"04", "Charles", "Computer Science", "55"}); You may also use the `SetRoundedCorners` method to set the rounded corners to true or false for the tables. ```csharp -Table.SetRoundedCorners(true); +students.SetRoundedCorners(true); +``` + +## Matrix display + +First, you need to create a `Matrix` object giving the data just as in the example below. + +```csharp +List firstRow = new() { 1, null, 2, 7, 9, 3 }; +List secondRow = new() { 4, 5, 6, 8, null, 2 }; +List thirdRow = new() { 7, 8, null, 3, 4, 5 }; +List fourthRow = new() { null, 2, 3, 4, 5, 6 }; +List> data = new() { firstRow, secondRow, thirdRow, fourthRow }; +Matrix matrix = new(data); +``` + +The `WriteMatrix` is a special block that allows you to display the matrix. This is only visual, you can't select any element. + +```csharp +matrix.WriteMatrix(Placement.Center); + +Console.ReadKey(); +``` + +![matrix](../images/matrix.png) + +> [!NOTE] +> Once you created the matrix, you can add, remove or update the lines using the methods provided by the `Matrix` class (`AddLine`, `RemoveLine`, `UpdateLine`) but also the elements using the `RemoveElement` and `UpdateElement` methods. + +Here is an example of a matrix of how to use them: + +```csharp + +matrix.AddLine(new () {2, 5, 7, 9, 3, 6}); +matrix.RemoveLine(3); +matrix.UpdateLine(2, new () {3, 6, 8, 9, null, 2}); +matrix.RemoveElement(new Position(2, 2)); +matrix.UpdateElement(new Position(3,1), 7); +``` + +You may also use the `SetRoundedCorners` method to set the rounded corners to true or false for the matrix. + +```csharp +matrix.SetRoundedCorners(true); ``` ## Loading bar diff --git a/docs/documentation/started.md b/docs/documentation/started.md index f739aab6..a730689f 100644 --- a/docs/documentation/started.md +++ b/docs/documentation/started.md @@ -33,6 +33,7 @@ ConsoleAppVisuals │ └───FontYamlFile.cs ├───Core.cs ├───Extensions.cs +├───Matrix.cs ├───Table.cs ├───TextStyler.cs └───Usings.cs @@ -60,6 +61,10 @@ This class is used to style the text. It contains the methods to apply a specifi This class is used to create a table. It may be useful to display data in a table on the screen. +### Matrix.cs + +This class is used to create a matrix. It may be useful to display data in a matrix on the screen. + ### Position.cs This class is used to define any position defined by an X and Y coordinate. It may be used in cases like matrix selectors for example. diff --git a/docs/images/matrix.png b/docs/images/matrix.png new file mode 100644 index 00000000..4cbf2eb7 Binary files /dev/null and b/docs/images/matrix.png differ diff --git a/example/Program.cs b/example/Program.cs index abe56336..7aa24644 100644 --- a/example/Program.cs +++ b/example/Program.cs @@ -9,12 +9,12 @@ static void Main() Console.Clear(); Console.CursorVisible = false; - Test(); + Debugging(); Core.SetTitle("Example"); Core.WriteTitle(); - Core.WriteHeader(true); - Core.WriteFooter(true); + Core.WriteHeader(false); + Core.WriteFooter(false); Core.ClearContent(); Core.LoadingBar("[ Some example loading... ]"); Core.UpdateScreen(); @@ -22,46 +22,22 @@ static void Main() Menu: - var index = Core.ScrollingMenuSelector("What do you want to do?", default, default, "Select a number", "Answer some prompt","Display trivia", "Display table", "Change color", "Quit the app"); - switch (index.Item1){ + var index = Core.ScrollingMenuSelector("What will be your next action?", default, default, + "Change Console color", + "Display paragraph", + "Display a styled text", + "Display a matrix", + "Answer some prompt", + "Select a number", + "Display table", + "Quit the app"); + Core.ClearContent(); + switch (index.Item1) + { case Output.Select: - switch (index.Item2){ + switch (index.Item2) + { case 0: - Core.ClearContent(); - Core.UpdateScreen(); - var answerNumber = Core.ScrollingNumberSelector("Select a number", 10, 50, 25, 5); - float number = answerNumber.Item2; - Core.ClearContent(); - break; - case 1: - Core.ClearContent(); - Core.UpdateScreen(); - var answerPrompt = Core.WritePrompt("Hey! What is your name?"); - string name = answerPrompt.Item2; - Core.ClearContent(); - break; - case 2: - Core.ClearContent(); - Core.UpdateScreen(); - Core.WriteParagraph(default, default, "C# is a general-purpose, multi-paradigm programming language encompassing strong typing,","lexically scoped, imperative, declarative, functional, generic, object-oriented (class-based),"," and component-oriented programming disciplines.", "", "Press [Enter] to continue..."); - Console.ReadKey(); - Core.ClearContent(); - break; - case 3: - Core.ClearContent(); - Core.UpdateScreen(); - List headers = new () {"id", "name", "major", "grades"}; - List student1 = new () {"01", "Theo", "Technology", "97"}; - List student2 = new () {"02", "Paul", "Mathematics", "86"}; - List student3 = new () {"03", "Maxime", "Physics", "92"}; - List student4 = new () {"04", "Charles", "Computer Science", "100"}; - Table students = new (headers, new () {student1, student2, student3, student4}); - students.SetRoundedCorners(true); - students.ScrollingTableSelector(true, false, "Add student"); - Core.ClearContent(); - break; - case 4: - Core.ClearContent(); Core.UpdateScreen(); var indexColor = Core.ScrollingMenuSelector("What color do you want to change?", default, default, "White", "Gray", "Red", "Green", "Blue", "Yellow", "Magenta", "Cyan"); switch(indexColor.Item2){ @@ -92,38 +68,133 @@ static void Main() default: break; } + Core.ClearContent(); + break; + + case 1: Core.UpdateScreen(); + + Core.WriteMultiplePositionedLines(default, default, default, "C# is a general-purpose, multi-paradigm programming language encompassing strong typing,","lexically scoped, imperative, declarative, functional, generic, object-oriented (class-based),"," and component-oriented programming disciplines.", "", "Press [Enter] to continue..."); + + Console.ReadKey(); + Core.ClearContent(); break; - default: + + case 2: + Core.UpdateScreen(); + + Core.WritePositionedStyledText(Core.StyleText("Hello World!")); + + Console.ReadKey(); + Core.ClearContent(); + + Core.WritePositionedStyledText(Core.StyleText("Welcome Aboard!")); + + Console.ReadKey(); Core.ClearContent(); + break; + + case 3: Core.UpdateScreen(); - Core.WriteParagraph(true, default, "You have selected to quit the app. Press [Enter] to continue..."); + + List firstRow = new() { 1, null, 2, 7, 9, 3 }; + List secondRow = new() { 4, 5, 6, 8, null, 2 }; + List thirdRow = new() { 7, 8, null, 3, 4, 5 }; + List fourthRow = new() { null, 2, 3, 4, 5, 6 }; + List> data = new() { firstRow, secondRow, thirdRow, fourthRow }; + Matrix matrix = new(data); + matrix.SetRoundedCorners(false); + matrix.WriteMatrix(Placement.Center); + + Console.ReadKey(); + Core.ClearContent(); + + matrix.Remove(new Position(0, 0)); + matrix.Remove(new Position(3, 5)); + matrix.WriteMatrix(Placement.Center); + + Console.ReadKey(); + Core.ClearContent(); + + matrix.UpdateElement(new Position(0, 0), 1); + matrix.UpdateElement(new Position(3, 5), 6); + matrix.WriteMatrix(Placement.Center); + Console.ReadKey(); + Core.ClearContent(); + break; + + case 4: + Core.UpdateScreen(); + + var answerPrompt = Core.WritePrompt("Hey! What is your name?", "Theo"); + string name = answerPrompt.Item2; + + Core.ClearContent(); + break; + case 5: + Core.UpdateScreen(); + + var answerNumber = Core.ScrollingNumberSelector("Select a number", 10, 50, 25, 5); + float number = answerNumber.Item2; + + Core.ClearContent(); + break; + case 6: + Core.UpdateScreen(); + + List headers = new () {"id", "name", "major", "grades"}; + List student1 = new () {"01", "Theo", "Technology", "97"}; + List student2 = new () {"02", "Paul", "Mathematics", "86"}; + List student3 = new () {"03", "Maxime", "Physics", "92"}; + List student4 = new () {"04", "Charles", "Computer Science", "100"}; + Table students = new (headers, new () {student1, student2, student3, student4}); + students.SetRoundedCorners(false); + students.ScrollingTableSelector(true, false, "Add student"); + + students.UpdateLine(0, new () {"01", "Theo", "Biology", "100"}); + students.RemoveLine(3); + students.ScrollingTableSelector(true, true); + + Core.ClearContent(); + break; + + default: + Core.ClearContent(); + Core.UpdateScreen(); + Core.ExitProgram(); break; } break; + case Output.Exit: Core.ClearContent(); Core.UpdateScreen(); - Core.WriteParagraph(true, default, "You have selected to quit the app. Press [Enter] to continue..."); + + Core.WriteMultiplePositionedLines(default, true, default, "You have selected to quit the app. Press [Enter] to continue..."); + Console.ReadKey(); Core.ExitProgram(); break; + case Output.Delete: Core.ClearContent(); Core.UpdateScreen(); - Core.WriteParagraph(true, default, "You have selected the backspace tile. Press [Enter] to continue..."); + + Core.WriteMultiplePositionedLines(default, true, default, "You have selected the backspace tile. Press [Enter] to continue..."); + Console.ReadKey(); break; + default: break; } goto Menu; } - public static void Test() + public static void Debugging() { - // Test code placeholder + // Debug code placeholder } } } \ No newline at end of file diff --git a/src/ConsoleAppVisuals/Core.cs b/src/ConsoleAppVisuals/Core.cs index 1df88d44..412ed954 100644 --- a/src/ConsoleAppVisuals/Core.cs +++ b/src/ConsoleAppVisuals/Core.cs @@ -339,6 +339,7 @@ public static void WriteFooter(bool continuous = true, (string, string, string)? /// If true, the paragraph is printed in the negative colors. /// The height of the paragraph. /// The lines of the paragraph. + [Obsolete("This method is deprecated. Use WriteParagraph with the placement attribute instead. This method will be removed in a future release.", true)] public static void WriteParagraph(bool negative = false, int? line = null, params string[] text) { line ??= ContentHeight; @@ -352,6 +353,26 @@ public static void WriteParagraph(bool negative = false, int? line = null, param } ApplyNegative(default); } + /// + /// This method prints a paragraph in the console. + /// + /// The placement of the paragraph. + /// If true, the paragraph is printed in the negative colors. + /// The height of the paragraph. + /// The lines of the paragraph. + public static void WriteMultiplePositionedLines(Placement placement = Placement.Center , bool negative = false, int? line = null, params string[] text) + { + line ??= ContentHeight; + ApplyNegative(negative); + int maxLength = text.Length > 0 ? text.Max(s => s.Length) : 0; + foreach (string str in text) + { + WritePositionedString(str.ResizeString(maxLength, placement), placement, negative, line++); + if (line >= Console.WindowHeight - 1) + break; + } + ApplyNegative(default); + } /// /// This method prints a message in the console and gets a string written by the user. /// diff --git a/src/ConsoleAppVisuals/Matrix.cs b/src/ConsoleAppVisuals/Matrix.cs new file mode 100644 index 00000000..3acf77c8 --- /dev/null +++ b/src/ConsoleAppVisuals/Matrix.cs @@ -0,0 +1,206 @@ +namespace ConsoleAppVisuals; +/// +/// A maxtrix class for the console. +/// +public class Matrix +{ + + private List> lines = new(); + private string[]? displayArray; + private bool roundedCorners = true; + /// + /// The natural constructor of the matrix. + /// + /// The matrix to be used. + /// Thrown when the matrix is empty or not compatible (lines are not of the same length). + public Matrix(List>? rawLines = null) + { + if (rawLines is not null) + { + lines = rawLines; + if (CompatibilityCheck()) + { + BuildMatrix(); + } + } + } + private bool CompatibilityCheck() + { + if (lines.Count == 0) + { + return false; + throw new ArgumentException("The matrix is empty."); + } + int firstRowLength = lines[0].Count; + for (int i = 1; i < lines.Count; i++) + { + if (lines[i].Count != firstRowLength) + { + return false; + throw new ArgumentException("The matrix is not compatible."); + } + } + return true; + } + private void BuildMatrix() + { + var stringList = new List(); + var localMax = new int[lines[0].Count]; // Assuming rawLines is a List> containing the grid data + + for (int i = 0; i < lines.Count; i++) + { + for (int j = 0; j < lines[i].Count; j++) + { + if (lines[i][j]?.ToString()?.Length > localMax[j]) + { + localMax[j] = lines[i][j]?.ToString()?.Length ?? 0; + } + } + } + + string border = Corners[0].ToString(); + for (int i = 0; i < lines[0].Count; i++) + { + border += new string('─', localMax[i] + 2); + border += (i != lines[0].Count - 1) ? "┬" : Corners[1].ToString(); + } + stringList.Add(border); + + var separator = "├"; + for (int i = 0; i < lines[0].Count; i++) + { + separator += new string('─', localMax[i] + 2); + separator += (i != lines[0].Count - 1) ? "┼" : "┤"; + } + + + for (int i = 0; i < lines.Count; i++) + { + string line = "│ "; + for (int j = 0; j < lines[i].Count; j++) + { + line += lines[i][j]?.ToString()?.PadRight(localMax[j]) ?? " ".PadRight(localMax[j]); + if (j != lines[i].Count - 1) + line += " │ "; + else + line += " │"; + } + stringList.Add(line); + if (i != lines.Count - 1) + stringList.Add(separator); + } + + border = Corners[2].ToString(); + for (int i = 0; i < lines[0].Count; i++) + { + border += new string('─', localMax[i] + 2); + border += (i != lines[0].Count - 1) ? "┴" : Corners[3].ToString(); + } + stringList.Add(border); + + displayArray = stringList.ToArray(); + } + private string Corners => roundedCorners ? "╭╮╰╯" : "┌┐└┘"; + /// + /// Toggles the rounded corners of the table. + /// + public void SetRoundedCorners(bool value = true) + { + roundedCorners = value; + BuildMatrix(); + } + + /// + /// Adds a line to the matrix. + /// + /// The line to add. + /// Thrown when the line is not of the same length as the other lines. + public void AddLine(List line) + { + if (lines.Count == 0) + { + lines.Add(line); + } + else if (line.Count != lines[0].Count) + { + throw new ArgumentException("Line has a different number of elements than the existing lines."); + } + else + { + lines.Add(line); + BuildMatrix(); + } + } + /// + /// Removes a line from the matrix. + /// + /// The index of the line to remove. + /// Thrown when the index is out of range. + public void RemoveLine(int index) + { + if (index < 0 || index >= lines.Count) + { + throw new IndexOutOfRangeException("Index is out of range."); + } + lines.RemoveAt(index); + BuildMatrix(); + } + /// + /// Updates a line in the matrix. + /// + /// The index of the line to update. + /// The new line. + /// Thrown when the index is out of range. + /// Thrown when the line is not of the same length as the other lines. + public void UpdateLine(int index, List line) + { + if (index < 0 || index >= lines.Count) + { + throw new IndexOutOfRangeException("Index is out of range."); + } + else if (line.Count != lines[0].Count) + { + throw new ArgumentException("Line has a different number of elements than the existing lines."); + } + lines[index] = line; + BuildMatrix(); + } + /// + /// Removes an element from the matrix. + /// + /// The position of the element to remove. + /// Thrown when the position is out of range. + public void Remove(Position position) + { + if (position.X >= lines.Count || position.Y >= lines[position.X].Count) + { + throw new IndexOutOfRangeException("Position is out of range."); + } + lines[position.X][position.Y] = default(T); + BuildMatrix(); + } + /// + /// Updates an element in the matrix. + /// + /// The position of the element to update. + /// The new element. + /// Thrown when the position is out of range. + public void UpdateElement(Position position, T newElement) + { + if (position.X >= lines.Count || position.Y >= lines[position.X].Count) + { + throw new IndexOutOfRangeException("Position is out of range."); + } + lines[position.X][position.Y] = newElement; + BuildMatrix(); + } + /// + /// Writes the matrix instance to the console. + /// + public void WriteMatrix(Placement placement = Placement.Center, bool negative = false, int? line = null) + { + if (displayArray is null) + throw new NullReferenceException("The matrix has not been built yet. The matrix cannot be displayed"); + Core.WriteMultiplePositionedLines(placement, negative, line, displayArray); + } +} \ No newline at end of file diff --git a/src/ConsoleAppVisuals/Table.cs b/src/ConsoleAppVisuals/Table.cs index 99bd1051..7d19bf86 100644 --- a/src/ConsoleAppVisuals/Table.cs +++ b/src/ConsoleAppVisuals/Table.cs @@ -77,8 +77,8 @@ private void BuildTable() } stringList.Add(line); } - stringList.Insert(0, corners[0].ToString().PadRight(stringList[0].Length - 1, '─') + corners[1]); - stringList.Add(corners[2].ToString().PadRight(stringList[0].Length - 1, '─') + corners[3]); + stringList.Insert(0, Corners[0].ToString().PadRight(stringList[0].Length - 1, '─') + Corners[1]); + stringList.Add(Corners[2].ToString().PadRight(stringList[0].Length - 1, '─') + Corners[3]); displayArray = stringList.ToArray(); } @@ -105,11 +105,11 @@ private void BuildTable() } stringList.Add(header); - string border = corners[0].ToString(); + string border = Corners[0].ToString(); for (int i = 0; i < rawHeaders.Count; i++) { border += new string('─', localMax[i] + 2); - border += (i != rawHeaders.Count - 1) ? "┬" : corners[1].ToString(); + border += (i != rawHeaders.Count - 1) ? "┬" : Corners[1].ToString(); } stringList.Insert(0, border); @@ -135,11 +135,11 @@ private void BuildTable() stringList.Add(line); } - border = corners[2].ToString(); + border = Corners[2].ToString(); for (int i = 0; i < rawHeaders.Count; i++) { border += new string('─', localMax[i] + 2); - border += (i != rawHeaders.Count - 1) ? "┴" : corners[3].ToString(); + border += (i != rawHeaders.Count - 1) ? "┴" : Corners[3].ToString(); } stringList.Add(border); @@ -149,7 +149,7 @@ private void BuildTable() #endregion #region Properties - private string corners => roundedCorners ? "╭╮╰╯" : "┌┐└┘"; + private string Corners => roundedCorners ? "╭╮╰╯" : "┌┐└┘"; /// /// Toggles the rounded corners of the table. /// diff --git a/src/ConsoleAppVisuals/models/Placement.cs b/src/ConsoleAppVisuals/models/Placement.cs index ee1114ef..bb3b1934 100644 --- a/src/ConsoleAppVisuals/models/Placement.cs +++ b/src/ConsoleAppVisuals/models/Placement.cs @@ -9,15 +9,15 @@ namespace ConsoleAppVisuals; /// public enum Placement { - /// - /// The string is placed at the left of the console. - /// - Left, /// /// The string is placed at the center of the console. /// Center, /// + /// The string is placed at the left of the console. + /// + Left, + /// /// The string is placed at the right of the console. /// Right