diff --git a/BizHawk.Client.EmuHawk/ArchiveChooser.Designer.cs b/BizHawk.Client.EmuHawk/ArchiveChooser.Designer.cs index c10df806b8..b6e9a894dd 100644 --- a/BizHawk.Client.EmuHawk/ArchiveChooser.Designer.cs +++ b/BizHawk.Client.EmuHawk/ArchiveChooser.Designer.cs @@ -31,10 +31,21 @@ this.flowLayoutPanel1 = new System.Windows.Forms.FlowLayoutPanel(); this.btnCancel = new System.Windows.Forms.Button(); this.btnOK = new System.Windows.Forms.Button(); + this.tableLayoutPanel1 = new System.Windows.Forms.TableLayoutPanel(); this.lvMembers = new System.Windows.Forms.ListView(); this.colName = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader())); this.colSize = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader())); + this.panel1 = new System.Windows.Forms.Panel(); + this.cbInstantFilter = new System.Windows.Forms.CheckBox(); + this.radRegEx = new System.Windows.Forms.RadioButton(); + this.radSimple = new System.Windows.Forms.RadioButton(); + this.btnFilter = new System.Windows.Forms.Button(); + this.btnSearch = new System.Windows.Forms.Button(); + this.tbFilter = new System.Windows.Forms.TextBox(); + this.tbSearch = new System.Windows.Forms.TextBox(); this.flowLayoutPanel1.SuspendLayout(); + this.tableLayoutPanel1.SuspendLayout(); + this.panel1.SuspendLayout(); this.SuspendLayout(); // // flowLayoutPanel1 @@ -70,6 +81,21 @@ this.btnOK.UseVisualStyleBackColor = true; this.btnOK.Click += new System.EventHandler(this.btnOK_Click); // + // tableLayoutPanel1 + // + this.tableLayoutPanel1.ColumnCount = 1; + this.tableLayoutPanel1.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 100F)); + this.tableLayoutPanel1.Controls.Add(this.lvMembers, 0, 0); + this.tableLayoutPanel1.Controls.Add(this.panel1, 0, 1); + this.tableLayoutPanel1.Dock = System.Windows.Forms.DockStyle.Fill; + this.tableLayoutPanel1.Location = new System.Drawing.Point(0, 0); + this.tableLayoutPanel1.Name = "tableLayoutPanel1"; + this.tableLayoutPanel1.RowCount = 2; + this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 100F)); + this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle()); + this.tableLayoutPanel1.Size = new System.Drawing.Size(472, 276); + this.tableLayoutPanel1.TabIndex = 1; + // // lvMembers // this.lvMembers.Columns.AddRange(new System.Windows.Forms.ColumnHeader[] { @@ -78,13 +104,13 @@ this.lvMembers.Dock = System.Windows.Forms.DockStyle.Fill; this.lvMembers.FullRowSelect = true; this.lvMembers.GridLines = true; - this.lvMembers.Location = new System.Drawing.Point(0, 0); + this.lvMembers.Location = new System.Drawing.Point(3, 3); + this.lvMembers.MultiSelect = false; this.lvMembers.Name = "lvMembers"; - this.lvMembers.Size = new System.Drawing.Size(472, 276); - this.lvMembers.TabIndex = 0; + this.lvMembers.Size = new System.Drawing.Size(466, 164); + this.lvMembers.TabIndex = 3; this.lvMembers.UseCompatibleStateImageBehavior = false; this.lvMembers.View = System.Windows.Forms.View.Details; - this.lvMembers.ItemActivate += new System.EventHandler(this.lvMembers_ItemActivate); // // colName // @@ -97,6 +123,92 @@ this.colSize.DisplayIndex = 0; this.colSize.Text = "Size"; // + // panel1 + // + this.panel1.Controls.Add(this.cbInstantFilter); + this.panel1.Controls.Add(this.radRegEx); + this.panel1.Controls.Add(this.radSimple); + this.panel1.Controls.Add(this.btnFilter); + this.panel1.Controls.Add(this.btnSearch); + this.panel1.Controls.Add(this.tbFilter); + this.panel1.Controls.Add(this.tbSearch); + this.panel1.Dock = System.Windows.Forms.DockStyle.Fill; + this.panel1.Location = new System.Drawing.Point(3, 173); + this.panel1.Name = "panel1"; + this.panel1.Size = new System.Drawing.Size(466, 100); + this.panel1.TabIndex = 4; + // + // cbInstantFilter + // + this.cbInstantFilter.AutoSize = true; + this.cbInstantFilter.Checked = true; + this.cbInstantFilter.CheckState = System.Windows.Forms.CheckState.Checked; + this.cbInstantFilter.Location = new System.Drawing.Point(258, 33); + this.cbInstantFilter.Name = "cbInstantFilter"; + this.cbInstantFilter.Size = new System.Drawing.Size(106, 17); + this.cbInstantFilter.TabIndex = 6; + this.cbInstantFilter.Text = "Filter while typing"; + this.cbInstantFilter.UseVisualStyleBackColor = true; + this.cbInstantFilter.CheckedChanged += new System.EventHandler(this.cbInstantFilter_CheckedChanged); + // + // radRegEx + // + this.radRegEx.AutoSize = true; + this.radRegEx.Location = new System.Drawing.Point(71, 58); + this.radRegEx.Name = "radRegEx"; + this.radRegEx.Size = new System.Drawing.Size(116, 17); + this.radRegEx.TabIndex = 5; + this.radRegEx.Text = "Regular Expression"; + this.radRegEx.UseVisualStyleBackColor = true; + this.radRegEx.CheckedChanged += new System.EventHandler(this.radRegEx_CheckedChanged); + // + // radSimple + // + this.radSimple.AutoSize = true; + this.radSimple.Checked = true; + this.radSimple.Location = new System.Drawing.Point(9, 57); + this.radSimple.Name = "radSimple"; + this.radSimple.Size = new System.Drawing.Size(56, 17); + this.radSimple.TabIndex = 4; + this.radSimple.TabStop = true; + this.radSimple.Text = "Simple"; + this.radSimple.UseVisualStyleBackColor = true; + // + // btnFilter + // + this.btnFilter.Location = new System.Drawing.Point(177, 29); + this.btnFilter.Name = "btnFilter"; + this.btnFilter.Size = new System.Drawing.Size(75, 23); + this.btnFilter.TabIndex = 3; + this.btnFilter.Text = "Filter"; + this.btnFilter.UseVisualStyleBackColor = true; + this.btnFilter.Click += new System.EventHandler(this.btnFilter_Click); + // + // btnSearch + // + this.btnSearch.Location = new System.Drawing.Point(177, 3); + this.btnSearch.Name = "btnSearch"; + this.btnSearch.Size = new System.Drawing.Size(75, 23); + this.btnSearch.TabIndex = 2; + this.btnSearch.Text = "Find"; + this.btnSearch.UseVisualStyleBackColor = true; + this.btnSearch.Click += new System.EventHandler(this.btnSearch_Click); + // + // tbFilter + // + this.tbFilter.Location = new System.Drawing.Point(4, 31); + this.tbFilter.Name = "tbFilter"; + this.tbFilter.Size = new System.Drawing.Size(167, 20); + this.tbFilter.TabIndex = 1; + this.tbFilter.TextChanged += new System.EventHandler(this.tbFilter_TextChanged); + // + // tbSearch + // + this.tbSearch.Location = new System.Drawing.Point(4, 4); + this.tbSearch.Name = "tbSearch"; + this.tbSearch.Size = new System.Drawing.Size(167, 20); + this.tbSearch.TabIndex = 0; + // // ArchiveChooser // this.AcceptButton = this.btnOK; @@ -104,7 +216,7 @@ this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; this.CancelButton = this.btnCancel; this.ClientSize = new System.Drawing.Size(472, 305); - this.Controls.Add(this.lvMembers); + this.Controls.Add(this.tableLayoutPanel1); this.Controls.Add(this.flowLayoutPanel1); this.MaximizeBox = false; this.MinimizeBox = false; @@ -115,6 +227,9 @@ this.Text = "Choose File From Archive"; this.Load += new System.EventHandler(this.ArchiveChooser_Load); this.flowLayoutPanel1.ResumeLayout(false); + this.tableLayoutPanel1.ResumeLayout(false); + this.panel1.ResumeLayout(false); + this.panel1.PerformLayout(); this.ResumeLayout(false); this.PerformLayout(); @@ -122,11 +237,20 @@ #endregion - private System.Windows.Forms.FlowLayoutPanel flowLayoutPanel1; - private System.Windows.Forms.ListView lvMembers; + private System.Windows.Forms.FlowLayoutPanel flowLayoutPanel1; private System.Windows.Forms.Button btnCancel; - private System.Windows.Forms.Button btnOK; - private System.Windows.Forms.ColumnHeader colSize; - private System.Windows.Forms.ColumnHeader colName; + private System.Windows.Forms.Button btnOK; + private System.Windows.Forms.TableLayoutPanel tableLayoutPanel1; + private System.Windows.Forms.ListView lvMembers; + private System.Windows.Forms.ColumnHeader colName; + private System.Windows.Forms.ColumnHeader colSize; + private System.Windows.Forms.Panel panel1; + private System.Windows.Forms.RadioButton radRegEx; + private System.Windows.Forms.RadioButton radSimple; + private System.Windows.Forms.Button btnFilter; + private System.Windows.Forms.Button btnSearch; + private System.Windows.Forms.TextBox tbFilter; + private System.Windows.Forms.TextBox tbSearch; + private System.Windows.Forms.CheckBox cbInstantFilter; } } \ No newline at end of file diff --git a/BizHawk.Client.EmuHawk/ArchiveChooser.cs b/BizHawk.Client.EmuHawk/ArchiveChooser.cs index 8db1fa1dac..5db5bfd63f 100644 --- a/BizHawk.Client.EmuHawk/ArchiveChooser.cs +++ b/BizHawk.Client.EmuHawk/ArchiveChooser.cs @@ -2,6 +2,7 @@ using System.IO; using System.Collections.Generic; using System.Linq; +using System.Text.RegularExpressions; using System.Windows.Forms; using BizHawk.Common; @@ -11,11 +12,26 @@ namespace BizHawk.Client.EmuHawk { public partial class ArchiveChooser : Form { + IList archiveItems = new List(); + ToolTip errorBalloon = new ToolTip(); + + static bool useRegEx = false; + static bool matchWhileTyping = true; + public ArchiveChooser(HawkFile hawkfile) { InitializeComponent(); + + errorBalloon.IsBalloon = true; + errorBalloon.InitialDelay = 0; + if (useRegEx) + radRegEx.Checked = true; + else + radSimple.Checked = true; + cbInstantFilter.Checked = matchWhileTyping; + var items = hawkfile.ArchiveItems; - for(int i=0;i func) + { + try + { + var searchMatcher = CreateMatcher(tb.Text); + if (searchMatcher != null) + { + func(searchMatcher); + } + } + catch (ArgumentException ex) + { + string errMsg = ex.Message; + errMsg = errMsg.Substring(errMsg.IndexOf('-') + 2); + // Balloon is bugged on first invocation + errorBalloon.Show("Error parsing RegEx: " + errMsg, tb); + errorBalloon.Show("Error parsing RegEx: " + errMsg, tb); + } + } + + private void DoSearch(IMatcher searchMatcher) + { + errorBalloon.Hide(tbSearch); + int count = lvMembers.Items.Count; + int searchStartIdx = 0; + if (lvMembers.SelectedItems.Count > 0) + { + searchStartIdx = (lvMembers.SelectedIndices[0] + 1) % count; + } + int? searchResultIdx = null; + + for (int i = 0; i < count; ++i) + { + int curIdx = (searchStartIdx + i) % count; + if (searchMatcher.Matches(lvMembers.Items[curIdx])) + { + searchResultIdx = curIdx; + break; + } + } + if (searchResultIdx != null) + { + lvMembers.Focus(); + lvMembers.Items[searchResultIdx.Value].Selected = true; + } + else + { + // Balloon is bugged on first invocation + errorBalloon.Show("Could not find search text", tbSearch); + errorBalloon.Show("Could not find search text", tbSearch); + } + } + + private void DoFilter(IMatcher searchMatcher) + { + lvMembers.Items.Clear(); + foreach (ListViewItem item in archiveItems) + { + if (searchMatcher.Matches(item)) + { + lvMembers.Items.Add(item); + } + } + } + + private interface IMatcher + { + bool Matches(ListViewItem value); + }; + + private class SimpleMatcher : IMatcher + { + public string[] Keys { get; set; } + public bool Matches(ListViewItem value) + { + string searchedStr = value.Text.ToLower(); + foreach (string key in Keys) + { + if (!searchedStr.Contains(key)) + { + return false; + } + } + return true; + } + }; + + private class RegExMatcher : IMatcher + { + public Regex Matcher { get; set; } + public bool Matches(ListViewItem value) + { + return Matcher.IsMatch(value.Text); + } + }; + + private IMatcher CreateMatcher(string searchKey) + { + if (radSimple.Checked) + { + return new SimpleMatcher { + Keys = searchKey.ToLower().Split(new char[0], + StringSplitOptions.RemoveEmptyEntries)}; + } + else + { + return new RegExMatcher { Matcher = new Regex(searchKey, RegexOptions.IgnoreCase) }; + } + } } }