diff --git a/InfoBox.sln b/InfoBox.sln
index dd07fa1..3b0c972 100644
--- a/InfoBox.sln
+++ b/InfoBox.sln
@@ -1,6 +1,6 @@
Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 18
-VisualStudioVersion = 18.2.11408.102 d18.0
+VisualStudioVersion = 18.2.11408.102
MinimumVisualStudioVersion = 10.0.40219.1
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{11BF73EF-1C37-4B34-BB1B-E378D733E8DC}"
EndProject
@@ -14,6 +14,10 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "InfoBoxCore.Designer", "Inf
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "InfoBoxCore.Designer.Tests", "InfoBoxCore.Designer.Tests\InfoBoxCore.Designer.Tests.csproj", "{A597A632-9151-4FB3-8696-8830D4B32170}"
EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "InfoBoxCore.Tests", "InfoBoxCore.Tests\InfoBoxCore.Tests.csproj", "{B8F3C21D-7A42-4E91-9C5A-1F2D4E5B6C7D}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "InfoBoxCore.ManualTests", "InfoBoxCore.ManualTests\InfoBoxCore.ManualTests.csproj", "{C3CC7542-1BA9-4BC4-9D3E-18B0A2DCE537}"
+EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@@ -40,6 +44,14 @@ Global
{A597A632-9151-4FB3-8696-8830D4B32170}.Debug|Any CPU.Build.0 = Debug|Any CPU
{A597A632-9151-4FB3-8696-8830D4B32170}.Release|Any CPU.ActiveCfg = Release|Any CPU
{A597A632-9151-4FB3-8696-8830D4B32170}.Release|Any CPU.Build.0 = Release|Any CPU
+ {B8F3C21D-7A42-4E91-9C5A-1F2D4E5B6C7D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {B8F3C21D-7A42-4E91-9C5A-1F2D4E5B6C7D}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {B8F3C21D-7A42-4E91-9C5A-1F2D4E5B6C7D}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {B8F3C21D-7A42-4E91-9C5A-1F2D4E5B6C7D}.Release|Any CPU.Build.0 = Release|Any CPU
+ {C3CC7542-1BA9-4BC4-9D3E-18B0A2DCE537}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {C3CC7542-1BA9-4BC4-9D3E-18B0A2DCE537}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {C3CC7542-1BA9-4BC4-9D3E-18B0A2DCE537}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {C3CC7542-1BA9-4BC4-9D3E-18B0A2DCE537}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
diff --git a/InfoBox/Form/InformationBoxForm.cs b/InfoBox/Form/InformationBoxForm.cs
index 5c0593e..8d3ed19 100644
--- a/InfoBox/Form/InformationBoxForm.cs
+++ b/InfoBox/Form/InformationBoxForm.cs
@@ -33,7 +33,7 @@ internal partial class InformationBoxForm : Form
///
/// Padding for the borders
///
- private const int BorderPadding = 20;
+ private const int BorderPadding = 10;
#endregion Consts
@@ -169,11 +169,6 @@ internal partial class InformationBoxForm : Form
///
private IconType iconType = IconType.Internal;
- ///
- /// Contains the text
- ///
- private StringBuilder internalText;
-
///
/// Contains if the help button should be displayed
///
@@ -1253,36 +1248,37 @@ private void SetText()
Screen currentScreen = Screen.FromControl(this);
int screenWidth = currentScreen.WorkingArea.Width;
- this.messageText.Text = this.messageText.Text.Replace("\r\n", "\n");
- this.messageText.Text = this.messageText.Text.Replace("\n", Environment.NewLine);
+ var internalText = String.Empty;
+ internalText = TextHelper.NormalizeLineBreaks(this.messageText.Text);
if (this.autoSizeMode == InformationBoxAutoSizeMode.FitToText)
{
this.messageText.WordWrap = false;
- this.messageText.Size = TextRenderer.MeasureText(this.messageText.Text, this.messageText.Font, currentScreen.WorkingArea.Size, TextFormatFlags.TextBoxControl) + new Size(1, 1);
+ this.messageText.Text = internalText.ToString();
+ this.messageText.Size = TextRenderer.MeasureText(internalText, this.messageText.Font, Size.Empty, TextFormatFlags.NoPadding);
}
else
{
if (this.autoSizeMode == InformationBoxAutoSizeMode.None)
{
this.messageText.WordWrap = true;
- this.messageText.Size = TextRenderer.MeasureText(this.messageText.Text, this.messageText.Font, new Size(screenWidth / 2, 0), TextFormatFlags.TextBoxControl | TextFormatFlags.WordBreak);
+ this.messageText.Text = internalText.ToString();
+ this.messageText.Size = TextRenderer.MeasureText(internalText, this.messageText.Font, new Size(screenWidth / 2, 0), TextFormatFlags.TextBoxControl | TextFormatFlags.WordBreak);
}
else
{
- this.internalText = new StringBuilder(this.messageText.Text);
-
if (this.autoSizeMode == InformationBoxAutoSizeMode.MinimumHeight)
{
// Remove line breaks.
- this.internalText = this.internalText.Replace(Environment.NewLine, " ");
- Regex splitter = new Regex(@"(?.+?(\. |$))", RegexOptions.Compiled);
- MatchCollection sentences = splitter.Matches(this.internalText.ToString());
+ internalText = TextHelper.ReplaceLineBreaksWithSpaces(internalText);
+ var sentences = TextHelper.SplitTextIntoSentences(internalText);
+
StringBuilder formattedText = new StringBuilder();
int currentWidth = 0;
foreach (Match sentence in sentences)
{
+ // FIX: In case an icon is configured, the maximum width of the text should be reduced to accomodate the icon width and avoid the horizontal scrollbar.
int sentenceLength = TextRenderer.MeasureText(sentence.Value, this.messageText.Font, Size.Empty, TextFormatFlags.TextBoxControl | TextFormatFlags.NoPadding).Width;
if (currentWidth != 0 && (sentenceLength + currentWidth) > (screenWidth - 50))
{
@@ -1294,20 +1290,14 @@ private void SetText()
formattedText.Append(sentence.Value);
}
- this.internalText = formattedText;
+ internalText = formattedText.ToString();
}
else if (this.autoSizeMode == InformationBoxAutoSizeMode.MinimumWidth)
{
- this.internalText.Replace(". ", "." + Environment.NewLine);
- this.internalText.Replace("? ", "?" + Environment.NewLine);
- this.internalText.Replace("! ", "!" + Environment.NewLine);
- this.internalText.Replace(": ", ":" + Environment.NewLine);
- this.internalText.Replace(") ", ")" + Environment.NewLine);
- this.internalText.Replace(", ", "," + Environment.NewLine);
+ internalText = TextHelper.AddLineBreaksAfterPunctuation(internalText);
}
- this.messageText.Text = this.internalText.ToString();
-
+ this.messageText.Text = internalText.ToString();
this.messageText.Size = TextRenderer.MeasureText(this.messageText.Text, this.messageText.Font, Size.Empty, TextFormatFlags.TextBoxControl);
}
}
diff --git a/InfoBox/InfoBox.csproj b/InfoBox/InfoBox.csproj
index d019647..aefd3d7 100644
--- a/InfoBox/InfoBox.csproj
+++ b/InfoBox/InfoBox.csproj
@@ -160,6 +160,7 @@
+
diff --git a/InfoBox/InformationBox.cs b/InfoBox/InformationBox.cs
index 25aba64..bc3d2ef 100644
--- a/InfoBox/InformationBox.cs
+++ b/InfoBox/InformationBox.cs
@@ -7,14 +7,13 @@
namespace InfoBox
{
using System.Drawing;
- using System.Security.Permissions;
using System.Windows.Forms;
///
/// Displays a message box that can contain text, buttons, and symbols that inform and instruct the user.
///
#if !NET5_0_OR_GREATER
- [UIPermission(SecurityAction.Demand)]
+ [System.Security.Permissions.UIPermission(System.Security.Permissions.SecurityAction.Demand)]
#endif
public static class InformationBox
{
diff --git a/InfoBox/Internals/TextHelper.cs b/InfoBox/Internals/TextHelper.cs
new file mode 100644
index 0000000..b2b553f
--- /dev/null
+++ b/InfoBox/Internals/TextHelper.cs
@@ -0,0 +1,76 @@
+using System;
+using System.Text;
+using System.Text.RegularExpressions;
+
+namespace InfoBox.Internals
+{
+ ///
+ /// Contains methods to process the content of the InformationBox
+ ///
+ internal static class TextHelper
+ {
+ private static readonly Regex _regex;
+
+ ///
+ /// Initialises the static members of the class.
+ ///
+ static TextHelper()
+ {
+ _regex = new Regex(@"(?.+?(\. |$))", RegexOptions.Compiled, TimeSpan.FromSeconds(10));
+ }
+
+ ///
+ /// Returns a string containing the same content with all line breaks normalized as
+ ///
+ /// The text to normalize
+ /// a string containing the same content with all line breaks normalized as
+ public static string NormalizeLineBreaks(string text)
+ {
+ var builder = new StringBuilder(text);
+ builder.Replace("\r\n", "\n");
+ builder.Replace("\n", Environment.NewLine);
+ return builder.ToString();
+ }
+
+ ///
+ /// Returns a string containing the same content with all line breaks replaced with a single space per line break.
+ ///
+ /// The text to normalize
+ /// a string containing the same content with all line breaks replaced with spaces.
+ public static string ReplaceLineBreaksWithSpaces(string text)
+ {
+ var builder = new StringBuilder(text);
+ builder.Replace(Environment.NewLine, " ");
+ return builder.ToString();
+ }
+
+ ///
+ /// Transform a text into a list of sentences.
+ ///
+ /// The text to split into sentences
+ /// a containing the list of sentences
+ public static MatchCollection SplitTextIntoSentences(string text)
+ {
+ return _regex.Matches(text);
+ }
+
+ ///
+ /// Adds a line break after most punctuation symbols
+ ///
+ /// the text to update
+ /// a string containing the content with the additional line breaks.
+ public static string AddLineBreaksAfterPunctuation(string text)
+ {
+ var builder = new StringBuilder(text);
+
+ builder.Replace(". ", "." + Environment.NewLine);
+ builder.Replace("? ", "?" + Environment.NewLine);
+ builder.Replace("! ", "!" + Environment.NewLine);
+ builder.Replace(": ", ":" + Environment.NewLine);
+ builder.Replace(") ", ")" + Environment.NewLine);
+ builder.Replace(", ", "," + Environment.NewLine);
+
+ return builder.ToString();
+ }
+ }
+}
diff --git a/InfoBox/Properties/AssemblyInfo.cs b/InfoBox/Properties/AssemblyInfo.cs
index ab7ac56..527c397 100644
--- a/InfoBox/Properties/AssemblyInfo.cs
+++ b/InfoBox/Properties/AssemblyInfo.cs
@@ -7,6 +7,7 @@
using System;
using System.Reflection;
using System.Resources;
+using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
#if NET6_0_OR_GREATER
@@ -36,6 +37,9 @@
// Assembly is CLS compliant
[assembly: CLSCompliant(true)]
+// Make internal types visible to test assemblies
+[assembly: InternalsVisibleTo("InfoBoxCore.Tests, PublicKey=00240000048000009400000006020000002400005253413100040000010001000d083a79d3b652c8e75ecc5b0eaf93f8160a1de04d6f967a87d4a7f6e2b5916017afef3cb81a9a6789079138170385c6e30dfdbb8b9999e08e29436e87bb10044b637e6c9cf0f6e52b64ba19001b5181839a5471dff368d415d29cbaae2189f89d7b5f736ef3e7692e257a35c0836ec97e5a2a950864617b8642590517bf8c9a")]
+
// The following GUID is for the ID of the typelib if this project is exposed to COM
[assembly: Guid("e14a6ac1-494d-481d-8510-d652082e43ba")]
diff --git a/InfoBoxCore.ManualTests/InfoBoxCore.ManualTests.csproj b/InfoBoxCore.ManualTests/InfoBoxCore.ManualTests.csproj
new file mode 100644
index 0000000..c09c976
--- /dev/null
+++ b/InfoBoxCore.ManualTests/InfoBoxCore.ManualTests.csproj
@@ -0,0 +1,15 @@
+
+
+
+ WinExe
+ net10.0-windows
+ enable
+ true
+ enable
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/InfoBoxCore.ManualTests/ManualTestsForm.Designer.cs b/InfoBoxCore.ManualTests/ManualTestsForm.Designer.cs
new file mode 100644
index 0000000..5898d7c
--- /dev/null
+++ b/InfoBoxCore.ManualTests/ManualTestsForm.Designer.cs
@@ -0,0 +1,98 @@
+namespace InfoBoxCore.ManualTests
+{
+ partial class ManualTestsForm
+ {
+ ///
+ /// Required designer variable.
+ ///
+ private System.ComponentModel.IContainer components = null;
+
+ ///
+ /// Clean up any resources being used.
+ ///
+ /// true if managed resources should be disposed; otherwise, false.
+ protected override void Dispose(bool disposing)
+ {
+ if (disposing && (components != null))
+ {
+ components.Dispose();
+ }
+ base.Dispose(disposing);
+ }
+
+ #region Windows Form Designer generated code
+
+ ///
+ /// Required method for Designer support - do not modify
+ /// the contents of this method with the code editor.
+ ///
+ private void InitializeComponent()
+ {
+ btnTestFixedWidthEightPoints = new Button();
+ btnTestFixedWidthFourPoints = new Button();
+ btnTestFixedWidthTwelvePoints = new Button();
+ btnTestLongLinesFixedFont = new Button();
+ SuspendLayout();
+ //
+ // btnTestFixedWidthEightPoints
+ //
+ btnTestFixedWidthEightPoints.Location = new Point(12, 12);
+ btnTestFixedWidthEightPoints.Name = "btnTestFixedWidthEightPoints";
+ btnTestFixedWidthEightPoints.Size = new Size(182, 23);
+ btnTestFixedWidthEightPoints.TabIndex = 0;
+ btnTestFixedWidthEightPoints.Text = "Fixed width font 8.25F";
+ btnTestFixedWidthEightPoints.UseVisualStyleBackColor = true;
+ btnTestFixedWidthEightPoints.Click += btnTestFixedWidthEightPoints_Click;
+ //
+ // btnTestFixedWidthFourPoints
+ //
+ btnTestFixedWidthFourPoints.Location = new Point(12, 41);
+ btnTestFixedWidthFourPoints.Name = "btnTestFixedWidthFourPoints";
+ btnTestFixedWidthFourPoints.Size = new Size(182, 23);
+ btnTestFixedWidthFourPoints.TabIndex = 1;
+ btnTestFixedWidthFourPoints.Text = "Fixed width font 4.25F";
+ btnTestFixedWidthFourPoints.UseVisualStyleBackColor = true;
+ btnTestFixedWidthFourPoints.Click += btnTestFixedWidthFourPoints_Click;
+ //
+ // btnTestFixedWidthTwelvePoints
+ //
+ btnTestFixedWidthTwelvePoints.Location = new Point(12, 70);
+ btnTestFixedWidthTwelvePoints.Name = "btnTestFixedWidthTwelvePoints";
+ btnTestFixedWidthTwelvePoints.Size = new Size(182, 23);
+ btnTestFixedWidthTwelvePoints.TabIndex = 2;
+ btnTestFixedWidthTwelvePoints.Text = "Fixed width font 12.25F";
+ btnTestFixedWidthTwelvePoints.UseVisualStyleBackColor = true;
+ btnTestFixedWidthTwelvePoints.Click += btnTestFixedWidthTwelvePoints_Click;
+ //
+ // btnTestLongLinesFixedFont
+ //
+ btnTestLongLinesFixedFont.Location = new Point(12, 99);
+ btnTestLongLinesFixedFont.Name = "btnTestLongLinesFixedFont";
+ btnTestLongLinesFixedFont.Size = new Size(182, 23);
+ btnTestLongLinesFixedFont.TabIndex = 3;
+ btnTestLongLinesFixedFont.Text = "Fixed width font long lines";
+ btnTestLongLinesFixedFont.UseVisualStyleBackColor = true;
+ btnTestLongLinesFixedFont.Click += btnTestLongLinesFixedFont_Click;
+ //
+ // ManualTestsForm
+ //
+ AutoScaleDimensions = new SizeF(7F, 15F);
+ AutoScaleMode = AutoScaleMode.Font;
+ ClientSize = new Size(800, 450);
+ Controls.Add(btnTestLongLinesFixedFont);
+ Controls.Add(btnTestFixedWidthTwelvePoints);
+ Controls.Add(btnTestFixedWidthFourPoints);
+ Controls.Add(btnTestFixedWidthEightPoints);
+ Name = "ManualTestsForm";
+ Text = "Manual tests";
+ ResumeLayout(false);
+ }
+
+ #endregion
+
+ private Button btnTestFixedWidthEightPoints;
+ private Button btnTestFixedWidthFourPoints;
+ private Button btnTestFixedWidthTwelvePoints;
+ private Button btnTestLongLinesFixedFont;
+ }
+}
diff --git a/InfoBoxCore.ManualTests/ManualTestsForm.cs b/InfoBoxCore.ManualTests/ManualTestsForm.cs
new file mode 100644
index 0000000..25129be
--- /dev/null
+++ b/InfoBoxCore.ManualTests/ManualTestsForm.cs
@@ -0,0 +1,102 @@
+using InfoBox;
+
+namespace InfoBoxCore.ManualTests
+{
+ public partial class ManualTestsForm : Form
+ {
+ public ManualTestsForm()
+ {
+ InitializeComponent();
+ }
+
+ private void btnTestFixedWidthEightPoints_Click(object sender, EventArgs e)
+ {
+ var testString = " My Program's Help Window" + Environment.NewLine;
+ testString += "" + Environment.NewLine;
+ testString += "Command Line Arguments What the argument does" + Environment.NewLine;
+ testString += "" + Environment.NewLine;
+ testString += "-h, --help Display this help window" + Environment.NewLine;
+ testString += "-v, --version Display version information" + Environment.NewLine;
+ testString += "-l, --log Display log file" + Environment.NewLine;
+ testString += "-d, --display Display variables" + Environment.NewLine;
+ testString += "-a, --arguments Display command line arguments" + Environment.NewLine;
+ testString += "" + Environment.NewLine;
+ testString += "Line 11\nLine 12\nLine 13\nLine 14\nLine 15\nLine 16\nLine 17\nLine 18\nLine 19\nLine 20\n";
+ testString += "Line 21\nLine 22\nLine 23\nLine 24\nLine 25\nLine 26\nLine 27\nLine 28\nLine 29\nLine 30\n";
+ testString += "Line 31\nLine 32\nLine 33\nLine 34\nLine 35\nLine 36\nLine 37\nLine 38\nLine 39\nLine 40\n";
+ testString += "Line 41\nLine 42\nLine 43\nLine 44\nLine 45\nLine 46\nLine 47\nLine 48\nLine 49\nLine 50\n";
+ testString += "Line 51\nLine 52\nLine 53\nLine 54\nLine 55\nLine 56\nLine 57\nLine 58\nLine 59\nLine 60";
+
+ InformationBox.Show(testString,
+ title: "My Program's Help Window Command Line Help",
+ icon: InformationBoxIcon.Information,
+ titleStyle: InformationBoxTitleIconStyle.SameAsBox,
+ autoSizeMode: InformationBoxAutoSizeMode.FitToText,
+ fontParameters: new FontParameters(new System.Drawing.Font("Courier New", 8.25F))
+ );
+ }
+
+ private void btnTestFixedWidthFourPoints_Click(object sender, EventArgs e)
+ {
+ var testString = " My Program's Help Window" + Environment.NewLine;
+ testString += "" + Environment.NewLine;
+ testString += "Command Line Arguments What the argument does" + Environment.NewLine;
+ testString += "" + Environment.NewLine;
+ testString += "-h, --help Display this help window" + Environment.NewLine;
+ testString += "-v, --version Display version information" + Environment.NewLine;
+ testString += "-l, --log Display log file" + Environment.NewLine;
+ testString += "-d, --display Display variables" + Environment.NewLine;
+ testString += "-a, --arguments Display command line arguments" + Environment.NewLine;
+ testString += "" + Environment.NewLine;
+ testString += "Line 11\nLine 12\nLine 13\nLine 14\nLine 15\nLine 16\nLine 17\nLine 18\nLine 19\nLine 20\n";
+ testString += "Line 21\nLine 22\nLine 23\nLine 24\nLine 25\nLine 26\nLine 27\nLine 28\nLine 29\nLine 30\n";
+ testString += "Line 31\nLine 32\nLine 33\nLine 34\nLine 35\nLine 36\nLine 37\nLine 38\nLine 39\nLine 40\n";
+ testString += "Line 41\nLine 42\nLine 43\nLine 44\nLine 45\nLine 46\nLine 47\nLine 48\nLine 49\nLine 50\n";
+ testString += "Line 51\nLine 52\nLine 53\nLine 54\nLine 55\nLine 56\nLine 57\nLine 58\nLine 59\nLine 60";
+
+ InformationBox.Show(testString,
+ title: "My Program's Help Window Command Line Help",
+ icon: InformationBoxIcon.Information,
+ titleStyle: InformationBoxTitleIconStyle.SameAsBox,
+ autoSizeMode: InformationBoxAutoSizeMode.FitToText,
+ fontParameters: new FontParameters(new System.Drawing.Font("Courier New", 4.25F))
+ );
+ }
+
+ private void btnTestFixedWidthTwelvePoints_Click(object sender, EventArgs e)
+ {
+ var testString = " My Program's Help Window" + Environment.NewLine;
+ testString += "" + Environment.NewLine;
+ testString += "Command Line Arguments What the argument does" + Environment.NewLine;
+ testString += "" + Environment.NewLine;
+ testString += "-h, --help Display this help window" + Environment.NewLine;
+ testString += "-v, --version Display version information" + Environment.NewLine;
+ testString += "-l, --log Display log file" + Environment.NewLine;
+ testString += "-d, --display Display variables" + Environment.NewLine;
+ testString += "-a, --arguments Display command line arguments" + Environment.NewLine;
+ testString += "" + Environment.NewLine;
+ testString += "Line 11\nLine 12\nLine 13\nLine 14\nLine 15\nLine 16\nLine 17\nLine 18\nLine 19\nLine 20\n";
+ testString += "Line 21\nLine 22\nLine 23\nLine 24\nLine 25\nLine 26\nLine 27\nLine 28\nLine 29\nLine 30\n";
+ testString += "Line 31\nLine 32\nLine 33\nLine 34\nLine 35\nLine 36\nLine 37\nLine 38\nLine 39\nLine 40\n";
+ testString += "Line 41\nLine 42\nLine 43\nLine 44\nLine 45\nLine 46\nLine 47\nLine 48\nLine 49\nLine 50\n";
+ testString += "Line 51\nLine 52\nLine 53\nLine 54\nLine 55\nLine 56\nLine 57\nLine 58\nLine 59\nLine 60";
+
+ InformationBox.Show(testString,
+ title: "My Program's Help Window Command Line Help",
+ icon: InformationBoxIcon.Information,
+ titleStyle: InformationBoxTitleIconStyle.SameAsBox,
+ autoSizeMode: InformationBoxAutoSizeMode.FitToText,
+ fontParameters: new FontParameters(new System.Drawing.Font("Courier New", 12.25F))
+ );
+ }
+
+ private void btnTestLongLinesFixedFont_Click(object sender, EventArgs e)
+ {
+ InformationBox.Show("Lorem ipsum dolor sit amet, consectetur adipiscing elit. Maecenas porttitor ante et lacinia tristique. Suspendisse massa felis, dapibus nec tristique a, malesuada ut mi. In fermentum augue vel odio rhoncus dignissim. Sed cursus ipsum lacinia efficitur consequat. Integer sit amet dui nunc. Curabitur aliquet, urna non condimentum viverra, nunc leo fermentum orci, quis faucibus sem erat ut nibh. Duis viverra in nisl a interdum. Praesent porta lectus et scelerisque porttitor. Nam a lectus a neque interdum faucibus non sit amet lacus. Aenean vehicula auctor neque. Nam vitae metus sed est laoreet dapibus. Fusce pulvinar tincidunt diam eu iaculis. Nulla blandit egestas arcu vitae malesuada. Aliquam erat volutpat.\n\nAenean iaculis cursus nisl quis sodales. Fusce id nisl id dolor tempor laoreet. Donec ac condimentum enim. Maecenas at pulvinar odio, a vestibulum turpis. Cras ex odio, dictum feugiat sem eget, tristique elementum quam. Vivamus facilisis quam sed hendrerit vestibulum. Sed ac ullamcorper nunc. Praesent maximus ante arcu, id dapibus nulla hendrerit at. Nullam molestie laoreet sem non finibus.\n\nEtiam imperdiet a purus id dignissim. Curabitur vulputate efficitur risus quis dictum. Aliquam iaculis accumsan diam, in sodales lacus bibendum et. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Nunc eget porttitor ex. Quisque vitae leo auctor, auctor augue in, eleifend quam. Nullam a neque nisi. Nunc imperdiet nunc enim, at congue magna sodales ac. Nam risus enim, laoreet eget pulvinar quis, semper ac lacus. Ut elementum nisl metus, sed porttitor urna feugiat malesuada. Etiam euismod, lorem vel dignissim malesuada, nunc arcu interdum diam, vel placerat lorem turpis sed nibh.\n\nDuis aliquam pulvinar libero sit amet volutpat. Curabitur vel orci nec nisl convallis lobortis. Ut eget condimentum dolor. Aenean iaculis nunc non magna euismod imperdiet. Suspendisse tempus lectus nec nulla lobortis blandit. Duis id lorem tempus, aliquam nibh vel, ornare nunc. Sed at ipsum turpis. Duis vel nulla non nibh volutpat dictum. Suspendisse tristique facilisis purus, nec rhoncus turpis tempus at. Donec leo dui, ullamcorper et est in, rhoncus dapibus risus. In finibus sollicitudin felis non facilisis. Nulla cursus mauris quis venenatis elementum. Morbi semper eros nunc, vitae rhoncus lacus vestibulum non. Duis congue maximus ornare.\n\nNam et mauris elementum, aliquam nulla non, venenatis est. Aliquam vitae dui consequat, ornare velit vitae, rutrum dui. Nulla porttitor euismod egestas. Quisque lacinia dignissim sapien nec tempus. Etiam porta malesuada ligula. Mauris non metus lacus. Vivamus sit amet congue risus, at ultricies ante. Sed vulputate auctor suscipit. Orci varius natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Ut nec turpis eu purus efficitur iaculis. Donec a quam sed turpis porta tempus id nec lectus. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia curae; Vivamus venenatis ac nulla ac condimentum. Praesent sapien lorem, dignissim in ultricies sit amet, mollis et nunc. Praesent commodo nibh quis erat bibendum, non porta tellus volutpat. Praesent bibendum elit at mauris aliquam mollis. ",
+ title: "Long lines of text",
+ icon: InformationBoxIcon.Asterisk,
+ fontParameters: new FontParameters(new System.Drawing.Font("Courier New", 12F)),
+ titleStyle: InformationBoxTitleIconStyle.SameAsBox);
+ }
+ }
+}
diff --git a/InfoBoxCore.ManualTests/ManualTestsForm.resx b/InfoBoxCore.ManualTests/ManualTestsForm.resx
new file mode 100644
index 0000000..8b2ff64
--- /dev/null
+++ b/InfoBoxCore.ManualTests/ManualTestsForm.resx
@@ -0,0 +1,120 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ text/microsoft-resx
+
+
+ 2.0
+
+
+ System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+
+ System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+
\ No newline at end of file
diff --git a/InfoBoxCore.ManualTests/Program.cs b/InfoBoxCore.ManualTests/Program.cs
new file mode 100644
index 0000000..a315c61
--- /dev/null
+++ b/InfoBoxCore.ManualTests/Program.cs
@@ -0,0 +1,17 @@
+namespace InfoBoxCore.ManualTests
+{
+ internal static class Program
+ {
+ ///
+ /// The main entry point for the application.
+ ///
+ [STAThread]
+ static void Main()
+ {
+ // To customize application configuration such as set high DPI settings or default font,
+ // see https://aka.ms/applicationconfiguration.
+ ApplicationConfiguration.Initialize();
+ Application.Run(new ManualTestsForm());
+ }
+ }
+}
\ No newline at end of file
diff --git a/InfoBoxCore.Tests/InfoBoxCore.Tests.csproj b/InfoBoxCore.Tests/InfoBoxCore.Tests.csproj
new file mode 100644
index 0000000..cf33bdd
--- /dev/null
+++ b/InfoBoxCore.Tests/InfoBoxCore.Tests.csproj
@@ -0,0 +1,32 @@
+
+
+
+ net10.0-windows7.0
+ false
+ Johann Blais
+ Johann Blais
+ InformationBox Core Tests
+ Copyright © Johann Blais 2007-2026
+ True
+ ..\InfoBox\Properties\key.snk
+
+
+
+ False
+
+
+
+ False
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/InfoBoxCore.Tests/TextHelperTests.cs b/InfoBoxCore.Tests/TextHelperTests.cs
new file mode 100644
index 0000000..cff8510
--- /dev/null
+++ b/InfoBoxCore.Tests/TextHelperTests.cs
@@ -0,0 +1,483 @@
+using System;
+using System.Text.RegularExpressions;
+using InfoBox.Internals;
+using NUnit.Framework;
+
+namespace InfoBoxCore.Tests
+{
+ ///
+ /// Unit tests for the class.
+ ///
+ [TestFixture]
+ public class TextHelperTests
+ {
+ #region NormalizeLineBreaks Tests
+
+ [Test]
+ public void NormalizeLineBreaks_WithCrLf_ReturnsNormalizedText()
+ {
+ // Arrange
+ string input = "Line1\r\nLine2\r\nLine3";
+ string expected = $"Line1{Environment.NewLine}Line2{Environment.NewLine}Line3";
+
+ // Act
+ string result = TextHelper.NormalizeLineBreaks(input);
+
+ // Assert
+ Assert.That(result, Is.EqualTo(expected));
+ }
+
+ [Test]
+ public void NormalizeLineBreaks_WithLfOnly_ReturnsNormalizedText()
+ {
+ // Arrange
+ string input = "Line1\nLine2\nLine3";
+ string expected = $"Line1{Environment.NewLine}Line2{Environment.NewLine}Line3";
+
+ // Act
+ string result = TextHelper.NormalizeLineBreaks(input);
+
+ // Assert
+ Assert.That(result, Is.EqualTo(expected));
+ }
+
+ [Test]
+ public void NormalizeLineBreaks_WithMixedLineEndings_ReturnsNormalizedText()
+ {
+ // Arrange
+ string input = "Line1\r\nLine2\nLine3\r\nLine4";
+ string expected = $"Line1{Environment.NewLine}Line2{Environment.NewLine}Line3{Environment.NewLine}Line4";
+
+ // Act
+ string result = TextHelper.NormalizeLineBreaks(input);
+
+ // Assert
+ Assert.That(result, Is.EqualTo(expected));
+ }
+
+ [Test]
+ public void NormalizeLineBreaks_WithEmptyString_ReturnsEmptyString()
+ {
+ // Arrange
+ string input = string.Empty;
+
+ // Act
+ string result = TextHelper.NormalizeLineBreaks(input);
+
+ // Assert
+ Assert.That(result, Is.Empty);
+ }
+
+ [Test]
+ public void NormalizeLineBreaks_WithNoLineBreaks_ReturnsSameText()
+ {
+ // Arrange
+ string input = "Single line text without breaks";
+
+ // Act
+ string result = TextHelper.NormalizeLineBreaks(input);
+
+ // Assert
+ Assert.That(result, Is.EqualTo(input));
+ }
+
+ [Test]
+ public void NormalizeLineBreaks_WithMultipleConsecutiveLineBreaks_ReturnsNormalizedText()
+ {
+ // Arrange
+ string input = "Line1\r\n\r\nLine2\n\nLine3";
+ string expected = $"Line1{Environment.NewLine}{Environment.NewLine}Line2{Environment.NewLine}{Environment.NewLine}Line3";
+
+ // Act
+ string result = TextHelper.NormalizeLineBreaks(input);
+
+ // Assert
+ Assert.That(result, Is.EqualTo(expected));
+ }
+
+ #endregion
+
+ #region ReplaceLineBreaksWithSpaces Tests
+
+ [Test]
+ public void ReplaceLineBreaksWithSpaces_WithSingleLineBreak_ReturnsTextWithSpace()
+ {
+ // Arrange
+ string input = $"Line1{Environment.NewLine}Line2";
+ string expected = "Line1 Line2";
+
+ // Act
+ string result = TextHelper.ReplaceLineBreaksWithSpaces(input);
+
+ // Assert
+ Assert.That(result, Is.EqualTo(expected));
+ }
+
+ [Test]
+ public void ReplaceLineBreaksWithSpaces_WithMultipleLineBreaks_ReturnsTextWithSpaces()
+ {
+ // Arrange
+ string input = $"Line1{Environment.NewLine}Line2{Environment.NewLine}Line3{Environment.NewLine}Line4";
+ string expected = "Line1 Line2 Line3 Line4";
+
+ // Act
+ string result = TextHelper.ReplaceLineBreaksWithSpaces(input);
+
+ // Assert
+ Assert.That(result, Is.EqualTo(expected));
+ }
+
+ [Test]
+ public void ReplaceLineBreaksWithSpaces_WithEmptyString_ReturnsEmptyString()
+ {
+ // Arrange
+ string input = string.Empty;
+
+ // Act
+ string result = TextHelper.ReplaceLineBreaksWithSpaces(input);
+
+ // Assert
+ Assert.That(result, Is.Empty);
+ }
+
+ [Test]
+ public void ReplaceLineBreaksWithSpaces_WithNoLineBreaks_ReturnsSameText()
+ {
+ // Arrange
+ string input = "Single line text without breaks";
+
+ // Act
+ string result = TextHelper.ReplaceLineBreaksWithSpaces(input);
+
+ // Assert
+ Assert.That(result, Is.EqualTo(input));
+ }
+
+ [Test]
+ public void ReplaceLineBreaksWithSpaces_WithConsecutiveLineBreaks_ReturnsTextWithMultipleSpaces()
+ {
+ // Arrange
+ string input = $"Line1{Environment.NewLine}{Environment.NewLine}Line2";
+ string expected = "Line1 Line2";
+
+ // Act
+ string result = TextHelper.ReplaceLineBreaksWithSpaces(input);
+
+ // Assert
+ Assert.That(result, Is.EqualTo(expected));
+ }
+
+ #endregion
+
+ #region SplitTextIntoSentences Tests
+
+ [Test]
+ public void SplitTextIntoSentences_WithSingleSentence_ReturnsSingleMatch()
+ {
+ // Arrange
+ string input = "This is a sentence.";
+
+ // Act
+ MatchCollection result = TextHelper.SplitTextIntoSentences(input);
+
+ // Assert
+ Assert.That(result.Count, Is.EqualTo(1));
+ Assert.That(result[0].Value, Is.EqualTo("This is a sentence."));
+ }
+
+ [Test]
+ public void SplitTextIntoSentences_WithMultipleSentences_ReturnsMultipleMatches()
+ {
+ // Arrange
+ string input = "First sentence. Second sentence. Third sentence.";
+
+ // Act
+ MatchCollection result = TextHelper.SplitTextIntoSentences(input);
+
+ // Assert
+ Assert.That(result.Count, Is.EqualTo(3));
+ Assert.That(result[0].Value, Is.EqualTo("First sentence. "));
+ Assert.That(result[1].Value, Is.EqualTo("Second sentence. "));
+ Assert.That(result[2].Value, Is.EqualTo("Third sentence."));
+ }
+
+ [Test]
+ public void SplitTextIntoSentences_WithSentenceEndingWithoutSpace_IncludesInMatch()
+ {
+ // Arrange
+ string input = "First sentence.Second sentence.";
+
+ // Act
+ MatchCollection result = TextHelper.SplitTextIntoSentences(input);
+
+ // Assert
+ Assert.That(result.Count, Is.EqualTo(1));
+ Assert.That(result[0].Value, Is.EqualTo("First sentence.Second sentence."));
+ }
+
+ [Test]
+ public void SplitTextIntoSentences_WithEmptyString_ReturnsEmptyCollection()
+ {
+ // Arrange
+ string input = string.Empty;
+
+ // Act
+ MatchCollection result = TextHelper.SplitTextIntoSentences(input);
+
+ // Assert
+ Assert.That(result.Count, Is.EqualTo(0));
+ }
+
+ [Test]
+ public void SplitTextIntoSentences_WithTextWithoutPeriod_ReturnsEntireText()
+ {
+ // Arrange
+ string input = "This is text without ending period";
+
+ // Act
+ MatchCollection result = TextHelper.SplitTextIntoSentences(input);
+
+ // Assert
+ Assert.That(result.Count, Is.EqualTo(1));
+ Assert.That(result[0].Value, Is.EqualTo(input));
+ }
+
+ [Test]
+ public void SplitTextIntoSentences_WithMixedContent_SplitsCorrectly()
+ {
+ // Arrange
+ string input = "First. Second. Third";
+
+ // Act
+ MatchCollection result = TextHelper.SplitTextIntoSentences(input);
+
+ // Assert
+ Assert.That(result.Count, Is.EqualTo(3));
+ Assert.That(result[0].Value, Is.EqualTo("First. "));
+ Assert.That(result[1].Value, Is.EqualTo("Second. "));
+ Assert.That(result[2].Value, Is.EqualTo("Third"));
+ }
+
+ [Test]
+ public void SplitTextIntoSentences_WithNumbersAndPeriods_SplitsOnPeriodWithSpace()
+ {
+ // Arrange
+ string input = "Version 1.0 is ready. Version 2.0 will follow.";
+
+ // Act
+ MatchCollection result = TextHelper.SplitTextIntoSentences(input);
+
+ // Assert
+ Assert.That(result.Count, Is.EqualTo(2));
+ Assert.That(result[0].Value, Is.EqualTo("Version 1.0 is ready. "));
+ Assert.That(result[1].Value, Is.EqualTo("Version 2.0 will follow."));
+ }
+
+ #endregion
+
+ #region AddLineBreaksAfterPunctuation Tests
+
+ [Test]
+ public void AddLineBreaksAfterPunctuation_WithPeriod_AddsLineBreak()
+ {
+ // Arrange
+ string input = "First sentence. Second sentence.";
+ string expected = $"First sentence.{Environment.NewLine}Second sentence.";
+
+ // Act
+ string result = TextHelper.AddLineBreaksAfterPunctuation(input);
+
+ // Assert
+ Assert.That(result, Is.EqualTo(expected));
+ }
+
+ [Test]
+ public void AddLineBreaksAfterPunctuation_WithQuestionMark_AddsLineBreak()
+ {
+ // Arrange
+ string input = "First question? Second question?";
+ string expected = $"First question?{Environment.NewLine}Second question?";
+
+ // Act
+ string result = TextHelper.AddLineBreaksAfterPunctuation(input);
+
+ // Assert
+ Assert.That(result, Is.EqualTo(expected));
+ }
+
+ [Test]
+ public void AddLineBreaksAfterPunctuation_WithExclamationMark_AddsLineBreak()
+ {
+ // Arrange
+ string input = "First exclamation! Second exclamation!";
+ string expected = $"First exclamation!{Environment.NewLine}Second exclamation!";
+
+ // Act
+ string result = TextHelper.AddLineBreaksAfterPunctuation(input);
+
+ // Assert
+ Assert.That(result, Is.EqualTo(expected));
+ }
+
+ [Test]
+ public void AddLineBreaksAfterPunctuation_WithColon_AddsLineBreak()
+ {
+ // Arrange
+ string input = "First part: Second part: Third part";
+ string expected = $"First part:{Environment.NewLine}Second part:{Environment.NewLine}Third part";
+
+ // Act
+ string result = TextHelper.AddLineBreaksAfterPunctuation(input);
+
+ // Assert
+ Assert.That(result, Is.EqualTo(expected));
+ }
+
+ [Test]
+ public void AddLineBreaksAfterPunctuation_WithClosingParenthesis_AddsLineBreak()
+ {
+ // Arrange
+ string input = "First (note) Second (another)";
+ string expected = $"First (note){Environment.NewLine}Second (another)";
+
+ // Act
+ string result = TextHelper.AddLineBreaksAfterPunctuation(input);
+
+ // Assert
+ Assert.That(result, Is.EqualTo(expected));
+ }
+
+ [Test]
+ public void AddLineBreaksAfterPunctuation_WithComma_AddsLineBreak()
+ {
+ // Arrange
+ string input = "First, second, third";
+ string expected = $"First,{Environment.NewLine}second,{Environment.NewLine}third";
+
+ // Act
+ string result = TextHelper.AddLineBreaksAfterPunctuation(input);
+
+ // Assert
+ Assert.That(result, Is.EqualTo(expected));
+ }
+
+ [Test]
+ public void AddLineBreaksAfterPunctuation_WithMixedPunctuation_AddsLineBreaksAfterAll()
+ {
+ // Arrange
+ string input = "Hello! How are you? I am fine, thank you. Great: yes indeed (really) cool!";
+ string expected = $"Hello!{Environment.NewLine}How are you?{Environment.NewLine}I am fine,{Environment.NewLine}thank you.{Environment.NewLine}Great:{Environment.NewLine}yes indeed (really){Environment.NewLine}cool!";
+
+ // Act
+ string result = TextHelper.AddLineBreaksAfterPunctuation(input);
+
+ // Assert
+ Assert.That(result, Is.EqualTo(expected));
+ }
+
+ [Test]
+ public void AddLineBreaksAfterPunctuation_WithEmptyString_ReturnsEmptyString()
+ {
+ // Arrange
+ string input = string.Empty;
+
+ // Act
+ string result = TextHelper.AddLineBreaksAfterPunctuation(input);
+
+ // Assert
+ Assert.That(result, Is.Empty);
+ }
+
+ [Test]
+ public void AddLineBreaksAfterPunctuation_WithNoPunctuation_ReturnsSameText()
+ {
+ // Arrange
+ string input = "Text without punctuation";
+
+ // Act
+ string result = TextHelper.AddLineBreaksAfterPunctuation(input);
+
+ // Assert
+ Assert.That(result, Is.EqualTo(input));
+ }
+
+ [Test]
+ public void AddLineBreaksAfterPunctuation_WithPunctuationAtEnd_DoesNotAddSpaceAfter()
+ {
+ // Arrange
+ string input = "End with period.";
+ string expected = "End with period.";
+
+ // Act
+ string result = TextHelper.AddLineBreaksAfterPunctuation(input);
+
+ // Assert
+ Assert.That(result, Is.EqualTo(expected));
+ }
+
+ [Test]
+ public void AddLineBreaksAfterPunctuation_WithDecimalNumbers_DoesNotAddLineBreak()
+ {
+ // Arrange
+ string input = "The price is 9.99 dollars.";
+ string expected = $"The price is 9.99 dollars.";
+
+ // Act
+ string result = TextHelper.AddLineBreaksAfterPunctuation(input);
+
+ // Assert
+ Assert.That(result, Is.EqualTo(expected));
+ }
+
+ #endregion
+
+ #region Integration Tests
+
+ [Test]
+ public void Integration_NormalizeAndReplace_WorksCorrectly()
+ {
+ // Arrange
+ string input = "Line1\r\nLine2\nLine3";
+
+ // Act
+ string normalized = TextHelper.NormalizeLineBreaks(input);
+ string result = TextHelper.ReplaceLineBreaksWithSpaces(normalized);
+
+ // Assert
+ Assert.That(result, Is.EqualTo("Line1 Line2 Line3"));
+ }
+
+ [Test]
+ public void Integration_ReplaceAndSplit_WorksCorrectly()
+ {
+ // Arrange
+ string input = $"First sentence.{Environment.NewLine}Second sentence.";
+
+ // Act
+ string replaced = TextHelper.ReplaceLineBreaksWithSpaces(input);
+ MatchCollection result = TextHelper.SplitTextIntoSentences(replaced);
+
+ // Assert
+ Assert.That(result.Count, Is.EqualTo(2));
+ Assert.That(result[0].Value, Is.EqualTo("First sentence. "));
+ Assert.That(result[1].Value, Is.EqualTo("Second sentence."));
+ }
+
+ [Test]
+ public void Integration_AddLineBreaksAndNormalize_WorksCorrectly()
+ {
+ // Arrange
+ string input = "First. Second. Third.";
+
+ // Act
+ string withBreaks = TextHelper.AddLineBreaksAfterPunctuation(input);
+ string result = TextHelper.NormalizeLineBreaks(withBreaks);
+
+ // Assert
+ string expected = $"First.{Environment.NewLine}Second.{Environment.NewLine}Third.";
+ Assert.That(result, Is.EqualTo(expected));
+ }
+
+ #endregion
+ }
+}