diff --git a/CutToLength/ArchUnits.cs b/CutToLength/ArchUnits.cs new file mode 100644 index 0000000..9321d29 --- /dev/null +++ b/CutToLength/ArchUnits.cs @@ -0,0 +1,75 @@ +using System; +using System.Text.RegularExpressions; +using System.Text; + +namespace CutToLength +{ + public static class ArchUnits + { + public static double ParseToInches(string input) + { + if (string.IsNullOrWhiteSpace(input)) + return 0; + + var sb = new StringBuilder(input.Trim().ToLower()); + + // replace all units with their equivelant symbols + sb.Replace("ft", "'"); + sb.Replace("feet", "'"); + sb.Replace("foot", "'"); + sb.Replace("inches", "\""); + sb.Replace("inch", "\""); + sb.Replace("in", "\""); + + var regex = new Regex("^(?\\d+\\.?\\d*\\s*')?\\s*(?\\d+\\.?\\d*\\s*\")?$"); + + // input manipulation is done, put the value back + input = Fraction.ReplaceFractionsWithDecimals(sb.ToString()); + + var match2 = regex.Match(input); + + if (!match2.Success) + throw new Exception("Input is not in a valid format."); + + var feet = match2.Groups["Feet"]; + var inches = match2.Groups["Inches"]; + + var totalInches = 0.0; + + if (feet.Success) + { + var x = double.Parse(feet.Value.Remove(feet.Length - 1)); + totalInches += x * 12; + } + + if (inches.Success) + { + var x = double.Parse(inches.Value.Remove(inches.Length - 1)); + totalInches += x; + } + + return Math.Round(totalInches, 8); + } + + public static double ParseToFeet(string input) + { + var inches = ParseToInches(input); + return Math.Round(inches / 12.0, 8); + } + + public static string FormatFromInches(double totalInches) + { + var feet = Math.Floor(totalInches / 12.0); + var inches = totalInches - (feet * 12.0); + + if (feet > 0) + { + return $"{feet}' {inches}\""; + } + else + { + return $"{inches}\""; + } + } + } +} diff --git a/CutToLength/CutToLength.csproj b/CutToLength/CutToLength.csproj index 00a9d59..313a8df 100644 --- a/CutToLength/CutToLength.csproj +++ b/CutToLength/CutToLength.csproj @@ -52,12 +52,14 @@ + Component + Form diff --git a/CutToLength/Fraction.cs b/CutToLength/Fraction.cs new file mode 100644 index 0000000..2872e00 --- /dev/null +++ b/CutToLength/Fraction.cs @@ -0,0 +1,85 @@ +using System; +using System.Text.RegularExpressions; +using System.Text; +using System.Linq; + +namespace CutToLength +{ + public static class Fraction + { + public static readonly Regex FractionRegex = new Regex(@"((?\d+)(\ |-))?(?\d+\/\d+)"); + + public static bool IsValid(string s) + { + return FractionRegex.IsMatch(s); + } + + public static double Parse(string s) + { + var match = FractionRegex.Match(s); + + if (!match.Success) + throw new Exception("Invalid format."); + + var value = 0.0; + + var wholeNumGroup = match.Groups["WholeNum"]; + var fractionGroup = match.Groups["Fraction"]; + + if (wholeNumGroup.Success) + { + value = double.Parse(wholeNumGroup.Value); + } + + if (fractionGroup.Success) + { + var parts = fractionGroup.Value.Split('/'); + var numerator = double.Parse(parts[0]); + var denominator = double.Parse(parts[1]); + + value += Math.Round(numerator / denominator, 8); + } + + return value; + } + + public static string ReplaceFractionsWithDecimals(string input) + { + var sb = new StringBuilder(input); + + // find all matches and sort by descending index number to avoid + // changing all previous index numbers when the fraction is replaced + // with the decimal equivalent. + var fractionMatches = FractionRegex.Matches(sb.ToString()) + .Cast() + .OrderByDescending(m => m.Index); + + foreach (var fractionMatch in fractionMatches) + { + // convert the fraction to a decimal value + var decimalValue = Parse(fractionMatch.Value); + + // remove the fraction and insert the decimal value in its place. + sb.Remove(fractionMatch.Index, fractionMatch.Length); + sb.Insert(fractionMatch.Index, decimalValue); + } + + return sb.ToString(); + } + + public static bool TryParse(string s, out double fraction) + { + try + { + fraction = Parse(s); + } + catch + { + fraction = 0; + return false; + } + + return true; + } + } +} diff --git a/CutToLength/MainForm.Designer.cs b/CutToLength/MainForm.Designer.cs index 44c26dc..f6b1f64 100644 --- a/CutToLength/MainForm.Designer.cs +++ b/CutToLength/MainForm.Designer.cs @@ -29,11 +29,15 @@ private void InitializeComponent() { this.components = new System.ComponentModel.Container(); - System.Windows.Forms.DataGridViewCellStyle dataGridViewCellStyle4 = new System.Windows.Forms.DataGridViewCellStyle(); - System.Windows.Forms.DataGridViewCellStyle dataGridViewCellStyle5 = new System.Windows.Forms.DataGridViewCellStyle(); - System.Windows.Forms.DataGridViewCellStyle dataGridViewCellStyle6 = new System.Windows.Forms.DataGridViewCellStyle(); + System.Windows.Forms.DataGridViewCellStyle dataGridViewCellStyle1 = new System.Windows.Forms.DataGridViewCellStyle(); + System.Windows.Forms.DataGridViewCellStyle dataGridViewCellStyle2 = new System.Windows.Forms.DataGridViewCellStyle(); + System.Windows.Forms.DataGridViewCellStyle dataGridViewCellStyle3 = new System.Windows.Forms.DataGridViewCellStyle(); this.dataGridView1 = new System.Windows.Forms.DataGridView(); + this.nameDataGridViewTextBoxColumn = new System.Windows.Forms.DataGridViewTextBoxColumn(); + this.lengthDataGridViewTextBoxColumn = new System.Windows.Forms.DataGridViewTextBoxColumn(); + this.quantityDataGridViewTextBoxColumn = new System.Windows.Forms.DataGridViewTextBoxColumn(); this.TotalLength = new System.Windows.Forms.DataGridViewTextBoxColumn(); + this.itemBindingSource = new System.Windows.Forms.BindingSource(this.components); this.label1 = new System.Windows.Forms.Label(); this.label2 = new System.Windows.Forms.Label(); this.toolStrip1 = new System.Windows.Forms.ToolStrip(); @@ -45,17 +49,10 @@ this.textBox1 = new System.Windows.Forms.TextBox(); this.label3 = new System.Windows.Forms.Label(); this.label4 = new System.Windows.Forms.Label(); - this.feetBox = new System.Windows.Forms.TextBox(); - this.label5 = new System.Windows.Forms.Label(); - this.label6 = new System.Windows.Forms.Label(); - this.inchesBox = new System.Windows.Forms.TextBox(); - this.nameDataGridViewTextBoxColumn = new System.Windows.Forms.DataGridViewTextBoxColumn(); - this.lengthDataGridViewTextBoxColumn = new System.Windows.Forms.DataGridViewTextBoxColumn(); - this.quantityDataGridViewTextBoxColumn = new System.Windows.Forms.DataGridViewTextBoxColumn(); - this.itemBindingSource = new System.Windows.Forms.BindingSource(this.components); + this.stockLengthBox = new System.Windows.Forms.TextBox(); ((System.ComponentModel.ISupportInitialize)(this.dataGridView1)).BeginInit(); - this.toolStrip1.SuspendLayout(); ((System.ComponentModel.ISupportInitialize)(this.itemBindingSource)).BeginInit(); + this.toolStrip1.SuspendLayout(); this.SuspendLayout(); // // dataGridView1 @@ -84,18 +81,50 @@ this.dataGridView1.RowTemplate.Height = 26; this.dataGridView1.Size = new System.Drawing.Size(822, 349); this.dataGridView1.TabIndex = 11; + this.dataGridView1.CellEndEdit += new System.Windows.Forms.DataGridViewCellEventHandler(this.dataGridView1_CellEndEdit); this.dataGridView1.CellValidated += new System.Windows.Forms.DataGridViewCellEventHandler(this.DataGridView1_CellValidated); + this.dataGridView1.DataError += new System.Windows.Forms.DataGridViewDataErrorEventHandler(this.dataGridView1_DataError); + // + // nameDataGridViewTextBoxColumn + // + this.nameDataGridViewTextBoxColumn.DataPropertyName = "Name"; + this.nameDataGridViewTextBoxColumn.HeaderText = "Name"; + this.nameDataGridViewTextBoxColumn.Name = "nameDataGridViewTextBoxColumn"; + this.nameDataGridViewTextBoxColumn.Width = 200; + // + // lengthDataGridViewTextBoxColumn + // + this.lengthDataGridViewTextBoxColumn.DataPropertyName = "LengthInputValue"; + dataGridViewCellStyle1.Alignment = System.Windows.Forms.DataGridViewContentAlignment.MiddleRight; + this.lengthDataGridViewTextBoxColumn.DefaultCellStyle = dataGridViewCellStyle1; + this.lengthDataGridViewTextBoxColumn.HeaderText = "Length"; + this.lengthDataGridViewTextBoxColumn.Name = "lengthDataGridViewTextBoxColumn"; + this.lengthDataGridViewTextBoxColumn.Width = 120; + // + // quantityDataGridViewTextBoxColumn + // + this.quantityDataGridViewTextBoxColumn.DataPropertyName = "Quantity"; + dataGridViewCellStyle2.Alignment = System.Windows.Forms.DataGridViewContentAlignment.MiddleRight; + this.quantityDataGridViewTextBoxColumn.DefaultCellStyle = dataGridViewCellStyle2; + this.quantityDataGridViewTextBoxColumn.HeaderText = "Qty"; + this.quantityDataGridViewTextBoxColumn.Name = "quantityDataGridViewTextBoxColumn"; + this.quantityDataGridViewTextBoxColumn.Width = 50; // // TotalLength // this.TotalLength.DataPropertyName = "TotalLength"; - dataGridViewCellStyle4.Alignment = System.Windows.Forms.DataGridViewContentAlignment.MiddleRight; - dataGridViewCellStyle4.BackColor = System.Drawing.SystemColors.Info; - dataGridViewCellStyle4.Format = "N3"; - this.TotalLength.DefaultCellStyle = dataGridViewCellStyle4; - this.TotalLength.HeaderText = "Total Length"; + dataGridViewCellStyle3.Alignment = System.Windows.Forms.DataGridViewContentAlignment.MiddleRight; + dataGridViewCellStyle3.BackColor = System.Drawing.SystemColors.Info; + dataGridViewCellStyle3.Format = "N3"; + this.TotalLength.DefaultCellStyle = dataGridViewCellStyle3; + this.TotalLength.HeaderText = "Total Length (in)"; this.TotalLength.Name = "TotalLength"; this.TotalLength.ReadOnly = true; + this.TotalLength.Width = 150; + // + // itemBindingSource + // + this.itemBindingSource.DataSource = typeof(CutToLength.UIItem); // // label1 // @@ -213,94 +242,25 @@ this.label4.TabIndex = 8; this.label4.Text = "Cut width"; // - // feetBox + // stockLengthBox // - this.feetBox.Location = new System.Drawing.Point(110, 42); - this.feetBox.Name = "feetBox"; - this.feetBox.Size = new System.Drawing.Size(53, 25); - this.feetBox.TabIndex = 2; - this.feetBox.Text = "12"; - this.feetBox.TextChanged += new System.EventHandler(this.FeetBox_TextChanged); - this.feetBox.KeyPress += new System.Windows.Forms.KeyPressEventHandler(this.TextBox2_KeyPress); - this.feetBox.Validating += new System.ComponentModel.CancelEventHandler(this.TextBox2_Validating); - // - // label5 - // - this.label5.AutoSize = true; - this.label5.Font = new System.Drawing.Font("Segoe UI Semibold", 9.75F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(0))); - this.label5.ForeColor = System.Drawing.Color.Gray; - this.label5.Location = new System.Drawing.Point(166, 45); - this.label5.Margin = new System.Windows.Forms.Padding(0, 0, 3, 0); - this.label5.Name = "label5"; - this.label5.Size = new System.Drawing.Size(17, 17); - this.label5.TabIndex = 3; - this.label5.Text = "ft"; - // - // label6 - // - this.label6.AutoSize = true; - this.label6.Font = new System.Drawing.Font("Segoe UI Semibold", 9.75F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(0))); - this.label6.ForeColor = System.Drawing.Color.Gray; - this.label6.Location = new System.Drawing.Point(245, 45); - this.label6.Margin = new System.Windows.Forms.Padding(0, 0, 3, 0); - this.label6.Name = "label6"; - this.label6.Size = new System.Drawing.Size(19, 17); - this.label6.TabIndex = 5; - this.label6.Text = "in"; - // - // inchesBox - // - this.inchesBox.Location = new System.Drawing.Point(189, 42); - this.inchesBox.Name = "inchesBox"; - this.inchesBox.Size = new System.Drawing.Size(53, 25); - this.inchesBox.TabIndex = 4; - this.inchesBox.Text = "0"; - this.inchesBox.TextChanged += new System.EventHandler(this.InchesBox_TextChanged); - this.inchesBox.KeyPress += new System.Windows.Forms.KeyPressEventHandler(this.TextBox2_KeyPress); - this.inchesBox.Validating += new System.ComponentModel.CancelEventHandler(this.TextBox2_Validating); - // - // nameDataGridViewTextBoxColumn - // - this.nameDataGridViewTextBoxColumn.DataPropertyName = "Name"; - this.nameDataGridViewTextBoxColumn.HeaderText = "Name"; - this.nameDataGridViewTextBoxColumn.Name = "nameDataGridViewTextBoxColumn"; - this.nameDataGridViewTextBoxColumn.Width = 200; - // - // lengthDataGridViewTextBoxColumn - // - this.lengthDataGridViewTextBoxColumn.DataPropertyName = "Length"; - dataGridViewCellStyle5.Alignment = System.Windows.Forms.DataGridViewContentAlignment.MiddleRight; - this.lengthDataGridViewTextBoxColumn.DefaultCellStyle = dataGridViewCellStyle5; - this.lengthDataGridViewTextBoxColumn.HeaderText = "Length"; - this.lengthDataGridViewTextBoxColumn.Name = "lengthDataGridViewTextBoxColumn"; - this.lengthDataGridViewTextBoxColumn.Width = 120; - // - // quantityDataGridViewTextBoxColumn - // - this.quantityDataGridViewTextBoxColumn.DataPropertyName = "Quantity"; - dataGridViewCellStyle6.Alignment = System.Windows.Forms.DataGridViewContentAlignment.MiddleRight; - this.quantityDataGridViewTextBoxColumn.DefaultCellStyle = dataGridViewCellStyle6; - this.quantityDataGridViewTextBoxColumn.HeaderText = "Qty"; - this.quantityDataGridViewTextBoxColumn.Name = "quantityDataGridViewTextBoxColumn"; - this.quantityDataGridViewTextBoxColumn.Width = 50; - // - // itemBindingSource - // - this.itemBindingSource.DataSource = typeof(CutToLength.UIItem); + this.stockLengthBox.Location = new System.Drawing.Point(110, 42); + this.stockLengthBox.Name = "stockLengthBox"; + this.stockLengthBox.Size = new System.Drawing.Size(142, 25); + this.stockLengthBox.TabIndex = 2; + this.stockLengthBox.Text = "12ft 0in"; + this.stockLengthBox.TextChanged += new System.EventHandler(this.StockLengthBox_TextChanged); // // MainForm // this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.None; this.ClientSize = new System.Drawing.Size(846, 484); - this.Controls.Add(this.inchesBox); - this.Controls.Add(this.feetBox); + this.Controls.Add(this.stockLengthBox); this.Controls.Add(this.textBox1); this.Controls.Add(this.comboBox1); this.Controls.Add(this.toolStrip1); this.Controls.Add(this.label4); - this.Controls.Add(this.label6); this.Controls.Add(this.label3); - this.Controls.Add(this.label5); this.Controls.Add(this.label2); this.Controls.Add(this.label1); this.Controls.Add(this.dataGridView1); @@ -311,9 +271,9 @@ this.StartPosition = System.Windows.Forms.FormStartPosition.CenterScreen; this.Text = "Cut To Length"; ((System.ComponentModel.ISupportInitialize)(this.dataGridView1)).EndInit(); + ((System.ComponentModel.ISupportInitialize)(this.itemBindingSource)).EndInit(); this.toolStrip1.ResumeLayout(false); this.toolStrip1.PerformLayout(); - ((System.ComponentModel.ISupportInitialize)(this.itemBindingSource)).EndInit(); this.ResumeLayout(false); this.PerformLayout(); @@ -329,18 +289,15 @@ private System.Windows.Forms.ToolStripButton saveButton; private System.Windows.Forms.ToolStripButton runButton; private System.Windows.Forms.ToolStripSeparator toolStripSeparator1; - private System.Windows.Forms.DataGridViewTextBoxColumn nameDataGridViewTextBoxColumn; - private System.Windows.Forms.DataGridViewTextBoxColumn lengthDataGridViewTextBoxColumn; - private System.Windows.Forms.DataGridViewTextBoxColumn quantityDataGridViewTextBoxColumn; - private System.Windows.Forms.DataGridViewTextBoxColumn TotalLength; private System.Windows.Forms.ComboBox comboBox1; private System.Windows.Forms.TextBox textBox1; private System.Windows.Forms.Label label3; private System.Windows.Forms.Label label4; - private System.Windows.Forms.TextBox feetBox; - private System.Windows.Forms.Label label5; - private System.Windows.Forms.Label label6; - private System.Windows.Forms.TextBox inchesBox; + private System.Windows.Forms.TextBox stockLengthBox; + private System.Windows.Forms.DataGridViewTextBoxColumn nameDataGridViewTextBoxColumn; + private System.Windows.Forms.DataGridViewTextBoxColumn lengthDataGridViewTextBoxColumn; + private System.Windows.Forms.DataGridViewTextBoxColumn quantityDataGridViewTextBoxColumn; + private System.Windows.Forms.DataGridViewTextBoxColumn TotalLength; } } diff --git a/CutToLength/MainForm.cs b/CutToLength/MainForm.cs index 7ec367e..9cfc839 100644 --- a/CutToLength/MainForm.cs +++ b/CutToLength/MainForm.cs @@ -60,11 +60,31 @@ namespace CutToLength private void UpdateRunButtonState() { - var hasItems = items.Any(i => i.Length > 0 && i.Quantity > 0); - var validStockLength = !Double.IsNaN(StockLengthInches); + var isValid = IsValid(); - runButton.Enabled = hasItems && validStockLength; - saveButton.Enabled = hasItems; + runButton.Enabled = isValid; + saveButton.Enabled = isValid; + } + + private bool IsValid() + { + if (!items.Any(i => i.Length > 0 && i.Quantity > 0)) + return false; + + if (Double.IsNaN(StockLengthInches)) + return false; + + for (int rowIndex = 0; rowIndex < dataGridView1.Rows.Count; rowIndex++) + { + var row = dataGridView1.Rows[rowIndex]; + + if (!string.IsNullOrWhiteSpace(row.ErrorText)) + { + return false; + } + } + + return true; } private void Open() @@ -103,18 +123,22 @@ namespace CutToLength { get { - var feet = GetDouble(feetBox); - var inches = GetDouble(inchesBox); - - return feet * 12 + inches; + return GetLengthInches(stockLengthBox); } } - private double GetDouble(TextBox tb) + private double GetLengthInches(TextBox tb) { try { - var x = double.Parse(tb.Text); + double d; + + if (double.TryParse(tb.Text, out d)) + { + return d; + } + + var x = ArchUnits.ParseToInches(tb.Text); tb.ForeColor = SystemColors.WindowText; return x; @@ -156,7 +180,7 @@ namespace CutToLength foreach (var item in items) { - if (item.Length == 0) + if (item.Length == null || item.Length == 0) continue; for (int i = 0; i < item.Quantity; i++) @@ -164,7 +188,7 @@ namespace CutToLength items2.Add(new BinItem { Name = item.Name, - Length = item.Length + Length = item.Length.Value }); } } @@ -285,42 +309,43 @@ namespace CutToLength } } - private void TextBox2_Validating(object sender, System.ComponentModel.CancelEventArgs e) - { - try - { - var ee = new ExpressionEvaluator(); - var x = ee.Evaluate(feetBox.Text); - feetBox.Text = x.ToString(); - feetBox.ForeColor = SystemColors.WindowText; - } - catch - { - feetBox.ForeColor = Color.Red; - } - } - - private void TextBox2_KeyPress(object sender, KeyPressEventArgs e) - { - - } - private void DataGridView1_CellValidated(object sender, DataGridViewCellEventArgs e) { - UpdateRunButtonState(); + if (e.ColumnIndex == lengthDataGridViewTextBoxColumn.Index) + { + var item = dataGridView1.Rows[e.RowIndex].DataBoundItem as UIItem; + if (item == null) + return; + + var errorText = string.Empty; + + if (item.Length == null) + { + errorText = "Length is not in a valid format."; + } + + dataGridView1.Rows[e.RowIndex].ErrorText = errorText; + } + + UpdateRunButtonState(); } - private void FeetBox_TextChanged(object sender, EventArgs e) + private void StockLengthBox_TextChanged(object sender, EventArgs e) { UpdateRunButtonState(); - } - private void InchesBox_TextChanged(object sender, EventArgs e) + private void dataGridView1_CellEndEdit(object sender, DataGridViewCellEventArgs e) { - UpdateRunButtonState(); + if (e.ColumnIndex == lengthDataGridViewTextBoxColumn.Index) + dataGridView1.Refresh(); + } + private void dataGridView1_DataError(object sender, DataGridViewDataErrorEventArgs e) + { + dataGridView1.Rows[e.RowIndex].ErrorText = e.Exception.InnerException?.Message; + e.ThrowException = false; } } } diff --git a/CutToLength/MainForm.resx b/CutToLength/MainForm.resx index 4353a46..2ae7c58 100644 --- a/CutToLength/MainForm.resx +++ b/CutToLength/MainForm.resx @@ -123,13 +123,7 @@ 17, 17 - - True - 172, 17 - - 17, 17 - \ No newline at end of file diff --git a/CutToLength/UIItem.cs b/CutToLength/UIItem.cs index cb6e83f..ffd5d7e 100644 --- a/CutToLength/UIItem.cs +++ b/CutToLength/UIItem.cs @@ -11,12 +11,43 @@ namespace CutToLength public string Name { get; set; } - public double Length { get; set; } + public string LengthInputValue { get; set; } + + public double? Length + { + get + { + try + { + double d; + + if (double.TryParse(LengthInputValue, out d)) + { + LengthInputValue += "\""; + return d; + } + + return ArchUnits.ParseToInches(LengthInputValue); + } + catch + { + return null; + } + } + } [JsonIgnore] - public double TotalLength + public double? TotalLength { - get { return Math.Round(Length * Quantity, 8); } + get + { + var length = Length; + + if (length == null) + return null; + + return Math.Round(length.Value * Quantity, 8); + } } public int Quantity { get; set; } = 1;