mirror of
https://github.com/batfasturd/BetterNPCEditor.git
synced 2025-04-19 10:51:18 +00:00
Added search function, fixed some variable typing
This commit is contained in:
parent
8dc217116f
commit
61919ba9a3
@ -3,6 +3,7 @@ using System.Collections.Generic;
|
||||
using System.Drawing;
|
||||
using System.Linq;
|
||||
using System.Windows.Forms;
|
||||
using System.Globalization;
|
||||
|
||||
namespace Better_NCP_Editor
|
||||
{
|
||||
@ -188,21 +189,14 @@ namespace Better_NCP_Editor
|
||||
|
||||
private void BtnOk_Click(object sender, EventArgs e)
|
||||
{
|
||||
// Determine the new value based on the type of the input control.
|
||||
if (inputControl is ComboBox combo)
|
||||
{
|
||||
if (valueType == typeof(bool))
|
||||
{
|
||||
// Parse the selected string to a boolean.
|
||||
if (bool.TryParse(combo.SelectedItem?.ToString(), out bool boolVal))
|
||||
{
|
||||
NewValue = boolVal;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Handle parsing error as needed.
|
||||
NewValue = false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -212,11 +206,32 @@ namespace Better_NCP_Editor
|
||||
}
|
||||
else if (inputControl is TextBox txt)
|
||||
{
|
||||
// If possible, parse to int; otherwise, leave as string.
|
||||
if (int.TryParse(txt.Text, out int intValue))
|
||||
// Parse the value based on the expected type using invariant culture.
|
||||
if (valueType == typeof(int) &&
|
||||
int.TryParse(txt.Text, NumberStyles.Integer, CultureInfo.InvariantCulture, out int intValue))
|
||||
{
|
||||
NewValue = intValue;
|
||||
}
|
||||
else if (valueType == typeof(double) &&
|
||||
double.TryParse(txt.Text, NumberStyles.Float | NumberStyles.AllowThousands, CultureInfo.InvariantCulture, out double doubleValue))
|
||||
{
|
||||
NewValue = doubleValue;
|
||||
}
|
||||
else if (valueType == typeof(float) &&
|
||||
float.TryParse(txt.Text, NumberStyles.Float | NumberStyles.AllowThousands, CultureInfo.InvariantCulture, out float floatValue))
|
||||
{
|
||||
NewValue = floatValue;
|
||||
}
|
||||
else if (valueType == typeof(bool) &&
|
||||
bool.TryParse(txt.Text, out bool boolValue))
|
||||
{
|
||||
NewValue = boolValue;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Default to string if parsing fails.
|
||||
NewValue = txt.Text;
|
||||
}
|
||||
}
|
||||
this.DialogResult = DialogResult.OK;
|
||||
this.Close();
|
||||
|
58
Better NCP Editor/Form1.Designer.cs
generated
58
Better NCP Editor/Form1.Designer.cs
generated
@ -39,6 +39,9 @@
|
||||
btn_import_entityData = new Button();
|
||||
btn_export_entityData = new Button();
|
||||
statusTextbox = new TextBox();
|
||||
searchTextBox = new TextBox();
|
||||
btn_Search = new Button();
|
||||
btn_Search_Clear = new Button();
|
||||
SuspendLayout();
|
||||
//
|
||||
// btn_load
|
||||
@ -69,7 +72,7 @@
|
||||
dirTreeView.Location = new Point(15, 40);
|
||||
dirTreeView.Margin = new Padding(3, 2, 3, 2);
|
||||
dirTreeView.Name = "dirTreeView";
|
||||
dirTreeView.Size = new Size(254, 610);
|
||||
dirTreeView.Size = new Size(254, 623);
|
||||
dirTreeView.TabIndex = 2;
|
||||
//
|
||||
// entityTreeView
|
||||
@ -77,7 +80,7 @@
|
||||
entityTreeView.Location = new Point(274, 40);
|
||||
entityTreeView.Margin = new Padding(3, 2, 3, 2);
|
||||
entityTreeView.Name = "entityTreeView";
|
||||
entityTreeView.Size = new Size(738, 610);
|
||||
entityTreeView.Size = new Size(738, 623);
|
||||
entityTreeView.TabIndex = 3;
|
||||
//
|
||||
// btn_entity_del
|
||||
@ -107,10 +110,10 @@
|
||||
// btn_import_entityData
|
||||
//
|
||||
btn_import_entityData.Enabled = false;
|
||||
btn_import_entityData.Location = new Point(431, 9);
|
||||
btn_import_entityData.Location = new Point(366, 9);
|
||||
btn_import_entityData.Margin = new Padding(3, 2, 3, 2);
|
||||
btn_import_entityData.Name = "btn_import_entityData";
|
||||
btn_import_entityData.Size = new Size(61, 22);
|
||||
btn_import_entityData.Size = new Size(68, 22);
|
||||
btn_import_entityData.TabIndex = 9;
|
||||
btn_import_entityData.Text = "Import";
|
||||
btn_import_entityData.UseVisualStyleBackColor = true;
|
||||
@ -119,10 +122,10 @@
|
||||
// btn_export_entityData
|
||||
//
|
||||
btn_export_entityData.Enabled = false;
|
||||
btn_export_entityData.Location = new Point(498, 9);
|
||||
btn_export_entityData.Location = new Point(440, 9);
|
||||
btn_export_entityData.Margin = new Padding(3, 2, 3, 2);
|
||||
btn_export_entityData.Name = "btn_export_entityData";
|
||||
btn_export_entityData.Size = new Size(58, 22);
|
||||
btn_export_entityData.Size = new Size(65, 22);
|
||||
btn_export_entityData.TabIndex = 10;
|
||||
btn_export_entityData.Text = "Export";
|
||||
btn_export_entityData.UseVisualStyleBackColor = true;
|
||||
@ -132,18 +135,50 @@
|
||||
//
|
||||
statusTextbox.BorderStyle = BorderStyle.FixedSingle;
|
||||
statusTextbox.ImeMode = ImeMode.NoControl;
|
||||
statusTextbox.Location = new Point(578, 10);
|
||||
statusTextbox.Location = new Point(15, 667);
|
||||
statusTextbox.Margin = new Padding(3, 2, 3, 2);
|
||||
statusTextbox.Name = "statusTextbox";
|
||||
statusTextbox.ReadOnly = true;
|
||||
statusTextbox.Size = new Size(434, 23);
|
||||
statusTextbox.Size = new Size(997, 23);
|
||||
statusTextbox.TabIndex = 11;
|
||||
//
|
||||
// searchTextBox
|
||||
//
|
||||
searchTextBox.Location = new Point(725, 8);
|
||||
searchTextBox.Name = "searchTextBox";
|
||||
searchTextBox.Size = new Size(287, 23);
|
||||
searchTextBox.TabIndex = 12;
|
||||
//
|
||||
// btn_Search
|
||||
//
|
||||
btn_Search.Location = new Point(605, 7);
|
||||
btn_Search.Margin = new Padding(3, 2, 3, 2);
|
||||
btn_Search.Name = "btn_Search";
|
||||
btn_Search.Size = new Size(65, 22);
|
||||
btn_Search.TabIndex = 13;
|
||||
btn_Search.Text = "Search";
|
||||
btn_Search.UseVisualStyleBackColor = true;
|
||||
btn_Search.Click += btn_Search_Click;
|
||||
//
|
||||
// btn_Search_Clear
|
||||
//
|
||||
btn_Search_Clear.Location = new Point(676, 7);
|
||||
btn_Search_Clear.Margin = new Padding(3, 2, 3, 2);
|
||||
btn_Search_Clear.Name = "btn_Search_Clear";
|
||||
btn_Search_Clear.Size = new Size(43, 22);
|
||||
btn_Search_Clear.TabIndex = 14;
|
||||
btn_Search_Clear.Text = "Clear";
|
||||
btn_Search_Clear.UseVisualStyleBackColor = true;
|
||||
btn_Search_Clear.Click += btn_Search_Clear_Click;
|
||||
//
|
||||
// Form1
|
||||
//
|
||||
AutoScaleDimensions = new SizeF(7F, 15F);
|
||||
AutoScaleMode = AutoScaleMode.Font;
|
||||
ClientSize = new Size(1028, 661);
|
||||
ClientSize = new Size(1028, 696);
|
||||
Controls.Add(btn_Search_Clear);
|
||||
Controls.Add(btn_Search);
|
||||
Controls.Add(searchTextBox);
|
||||
Controls.Add(statusTextbox);
|
||||
Controls.Add(btn_export_entityData);
|
||||
Controls.Add(btn_import_entityData);
|
||||
@ -155,7 +190,7 @@
|
||||
Controls.Add(btn_load);
|
||||
Margin = new Padding(3, 2, 3, 2);
|
||||
Name = "Form1";
|
||||
Text = "BetterNPC Editor V1.0";
|
||||
Text = "BetterNPC";
|
||||
Load += Form1_Load;
|
||||
ResumeLayout(false);
|
||||
PerformLayout();
|
||||
@ -172,5 +207,8 @@
|
||||
private Button btn_import_entityData;
|
||||
private Button btn_export_entityData;
|
||||
private TextBox statusTextbox;
|
||||
private TextBox searchTextBox;
|
||||
private Button btn_Search;
|
||||
private Button btn_Search_Clear;
|
||||
}
|
||||
}
|
||||
|
@ -5,11 +5,14 @@ using System.Text.Json;
|
||||
using System.Text.Json.Nodes;
|
||||
using System.Text.Json.Serialization.Metadata;
|
||||
using System.Windows.Forms;
|
||||
using System.Globalization;
|
||||
|
||||
namespace Better_NCP_Editor
|
||||
{
|
||||
public partial class Form1 : Form
|
||||
{
|
||||
private const string formTitle = "Better NCP Editor";
|
||||
private const string version = "0.0.2-alpha";
|
||||
private string currentJsonFilePath;
|
||||
private JsonNode currentJson;
|
||||
private bool fileModified = false;
|
||||
@ -23,7 +26,7 @@ namespace Better_NCP_Editor
|
||||
private List<String> _beltItems;
|
||||
private List<String> _weaponModItems;
|
||||
|
||||
private Dictionary<String, Dictionary<String,UInt64>> _itemShortnameToSkinName;
|
||||
private Dictionary<String, Dictionary<String, UInt64>> _itemShortnameToSkinName;
|
||||
|
||||
// All items dictionary.
|
||||
private Dictionary<String, String> _allItems;
|
||||
@ -31,13 +34,16 @@ namespace Better_NCP_Editor
|
||||
public Form1()
|
||||
{
|
||||
InitializeComponent();
|
||||
this.Text = $"{formTitle} v{version}";
|
||||
this.AutoScaleMode = AutoScaleMode.None;
|
||||
dirTreeView.AfterSelect += DirTreeView_AfterSelect;
|
||||
entityTreeView.NodeMouseDoubleClick += entityTreeView_NodeMouseDoubleClick;
|
||||
entityTreeView.AfterSelect += entityTreeView_AfterSelect;
|
||||
|
||||
searchTextBox.KeyDown += SearchTextBox_KeyDown;
|
||||
|
||||
// Prevent the form from shrinking below its current size.
|
||||
this.MinimumSize = new Size(1044, 700); // Set minimum allowed size
|
||||
this.MinimumSize = new Size(1044, 735); // Set minimum allowed size
|
||||
this.FormBorderStyle = FormBorderStyle.Sizable;
|
||||
|
||||
// Example layout using docking:
|
||||
@ -50,6 +56,7 @@ namespace Better_NCP_Editor
|
||||
// In the designer or constructor:
|
||||
dirTreeView.Anchor = AnchorStyles.Top | AnchorStyles.Bottom | AnchorStyles.Left;
|
||||
entityTreeView.Anchor = AnchorStyles.Top | AnchorStyles.Bottom | AnchorStyles.Left | AnchorStyles.Right;
|
||||
statusTextbox.Anchor = AnchorStyles.Bottom | AnchorStyles.Left | AnchorStyles.Right;
|
||||
entityTreeView.ShowNodeToolTips = false;
|
||||
|
||||
// Configure the custom tooltip.
|
||||
@ -87,7 +94,7 @@ namespace Better_NCP_Editor
|
||||
}
|
||||
}
|
||||
|
||||
private Dictionary<String,String> LoadItemDatabase(String filepath)
|
||||
private Dictionary<String, String> LoadItemDatabase(String filepath)
|
||||
{
|
||||
try
|
||||
{
|
||||
@ -101,7 +108,7 @@ namespace Better_NCP_Editor
|
||||
}
|
||||
}
|
||||
|
||||
private Dictionary<String,Dictionary<String, UInt64>> LoadSkinDict(String filepath)
|
||||
private Dictionary<String, Dictionary<String, UInt64>> LoadSkinDict(String filepath)
|
||||
{
|
||||
try
|
||||
{
|
||||
@ -265,9 +272,11 @@ namespace Better_NCP_Editor
|
||||
foreach (var kvp in obj)
|
||||
{
|
||||
TreeNode child;
|
||||
if (kvp.Value is JsonValue)
|
||||
if (kvp.Value is JsonValue jsonValue)
|
||||
{
|
||||
child = new TreeNode($"{kvp.Key}: {kvp.Value}");
|
||||
// Format the value properly based on its type
|
||||
string displayValue = FormatJsonValueForDisplay(jsonValue);
|
||||
child = new TreeNode($"{kvp.Key}: {displayValue}");
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -309,9 +318,11 @@ namespace Better_NCP_Editor
|
||||
{
|
||||
JsonNode item = arr[i];
|
||||
TreeNode child;
|
||||
if (item is JsonValue)
|
||||
if (item is JsonValue jsonValue)
|
||||
{
|
||||
child = new TreeNode($"[{i}]: {item}");
|
||||
// Format the value properly based on its type
|
||||
string displayValue = FormatJsonValueForDisplay(jsonValue);
|
||||
child = new TreeNode($"[{i}]: {displayValue}");
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -324,6 +335,31 @@ namespace Better_NCP_Editor
|
||||
}
|
||||
}
|
||||
|
||||
// Helper method to properly format JSON values for display
|
||||
private string FormatJsonValueForDisplay(JsonValue jsonValue)
|
||||
{
|
||||
try
|
||||
{
|
||||
// Get the underlying value
|
||||
object value = jsonValue.GetValue<object>();
|
||||
|
||||
if (value is double doubleVal)
|
||||
return doubleVal.ToString(CultureInfo.InvariantCulture);
|
||||
else if (value is float floatVal)
|
||||
return floatVal.ToString(CultureInfo.InvariantCulture);
|
||||
else if (value is bool boolVal)
|
||||
return boolVal.ToString().ToLowerInvariant(); // Display as lowercase true/false
|
||||
else if (value is string str)
|
||||
return str; // Return the raw string without quotes.
|
||||
else
|
||||
return jsonValue.ToString(); // Default fallback.
|
||||
}
|
||||
catch
|
||||
{
|
||||
return jsonValue.ToString();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private void entityTreeView_AfterSelect(object sender, TreeViewEventArgs e)
|
||||
{
|
||||
@ -429,8 +465,12 @@ namespace Better_NCP_Editor
|
||||
{
|
||||
if (bool.TryParse(currentVal, out _))
|
||||
return typeof(bool);
|
||||
if (int.TryParse(currentVal, out _))
|
||||
if (int.TryParse(currentVal, NumberStyles.Integer, CultureInfo.InvariantCulture, out _))
|
||||
return typeof(int);
|
||||
if (float.TryParse(currentVal, NumberStyles.Float | NumberStyles.AllowThousands, CultureInfo.InvariantCulture, out _))
|
||||
return typeof(float);
|
||||
if (double.TryParse(currentVal, NumberStyles.Float | NumberStyles.AllowThousands, CultureInfo.InvariantCulture, out _))
|
||||
return typeof(double);
|
||||
return typeof(string);
|
||||
}
|
||||
|
||||
@ -589,7 +629,8 @@ namespace Better_NCP_Editor
|
||||
obj["Mods"] = new JsonArray(); // Empty array
|
||||
obj["Ammo"] = "";
|
||||
newNode = obj;
|
||||
} else if (arrayName.Equals("List of prefabs", StringComparison.OrdinalIgnoreCase))
|
||||
}
|
||||
else if (arrayName.Equals("List of prefabs", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
var obj = new JsonObject();
|
||||
obj["Chance [0.0-100.0]"] = 100.0;
|
||||
@ -945,5 +986,155 @@ namespace Better_NCP_Editor
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void btn_Search_Click(object sender, EventArgs e)
|
||||
{
|
||||
string searchText = searchTextBox.Text.Trim().ToLowerInvariant();
|
||||
|
||||
if (string.IsNullOrEmpty(searchText))
|
||||
{
|
||||
// If search text is empty, restore the full tree view
|
||||
if (currentJson != null)
|
||||
{
|
||||
PopulateEntityTree(currentJson);
|
||||
statusTextbox.Text = "Search cleared. Displaying all nodes.";
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (currentJson == null)
|
||||
{
|
||||
statusTextbox.Text = "No JSON file loaded to search.";
|
||||
return;
|
||||
}
|
||||
|
||||
// Clear the tree view before repopulating with filtered results
|
||||
entityTreeView.Nodes.Clear();
|
||||
|
||||
// Get the filename for the root node
|
||||
string fileName = string.IsNullOrEmpty(currentJsonFilePath) ? "JSON" : Path.GetFileName(currentJsonFilePath);
|
||||
TreeNode rootNode = new TreeNode(fileName)
|
||||
{
|
||||
Tag = currentJson
|
||||
};
|
||||
entityTreeView.Nodes.Add(rootNode);
|
||||
|
||||
// Use a flag to track if any matches were found
|
||||
bool foundMatches = SearchAndPopulateTree(currentJson, rootNode, searchText);
|
||||
|
||||
if (foundMatches)
|
||||
{
|
||||
rootNode.ExpandAll();
|
||||
statusTextbox.Text = $"Search complete. Showing results for: '{searchText}'";
|
||||
}
|
||||
else
|
||||
{
|
||||
// No matches found
|
||||
PopulateEntityTree(currentJson); // Restore the full tree
|
||||
statusTextbox.Text = $"No matches found for: '{searchText}'";
|
||||
}
|
||||
}
|
||||
|
||||
private bool SearchAndPopulateTree(JsonNode node, TreeNode treeNode, string searchText)
|
||||
{
|
||||
bool foundMatch = false;
|
||||
|
||||
if (node is JsonObject obj)
|
||||
{
|
||||
foreach (var kvp in obj)
|
||||
{
|
||||
bool keyMatch = kvp.Key.ToLowerInvariant().Contains(searchText);
|
||||
bool valueMatch = false;
|
||||
TreeNode child;
|
||||
|
||||
if (kvp.Value is JsonValue jsonValue)
|
||||
{
|
||||
string displayValue = FormatJsonValueForDisplay(jsonValue);
|
||||
string valueStr = jsonValue.ToString().ToLowerInvariant();
|
||||
valueMatch = valueStr.Contains(searchText);
|
||||
child = new TreeNode($"{kvp.Key}: {displayValue}");
|
||||
}
|
||||
else
|
||||
{
|
||||
child = new TreeNode(kvp.Key);
|
||||
}
|
||||
|
||||
child.ToolTipText = toolTips.tips.ContainsKey(kvp.Key) ? toolTips.tips[kvp.Key] : "";
|
||||
child.Tag = kvp.Value;
|
||||
|
||||
if (keyMatch || valueMatch)
|
||||
{
|
||||
// Direct match found:
|
||||
// Add the full subtree without filtering.
|
||||
PopulateTreeRecursive(kvp.Value, child);
|
||||
treeNode.Nodes.Add(child);
|
||||
foundMatch = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
// No direct match: continue filtering the children.
|
||||
bool childrenMatch = SearchAndPopulateTree(kvp.Value, child, searchText);
|
||||
if (childrenMatch)
|
||||
{
|
||||
treeNode.Nodes.Add(child);
|
||||
foundMatch = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (node is JsonArray arr)
|
||||
{
|
||||
for (int i = 0; i < arr.Count; i++)
|
||||
{
|
||||
JsonNode item = arr[i];
|
||||
TreeNode child;
|
||||
|
||||
if (item is JsonValue jsonValue)
|
||||
{
|
||||
string displayValue = FormatJsonValueForDisplay(jsonValue);
|
||||
string valueStr = jsonValue.ToString().ToLowerInvariant();
|
||||
bool valueMatch = valueStr.Contains(searchText);
|
||||
child = new TreeNode($"[{i}]: {displayValue}");
|
||||
|
||||
if (valueMatch)
|
||||
{
|
||||
child.BackColor = Color.LightYellow;
|
||||
treeNode.Nodes.Add(child);
|
||||
foundMatch = true;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
child = new TreeNode($"[{i}]");
|
||||
child.Tag = item;
|
||||
bool childrenMatch = SearchAndPopulateTree(item, child, searchText);
|
||||
if (childrenMatch)
|
||||
{
|
||||
treeNode.Nodes.Add(child);
|
||||
foundMatch = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return foundMatch;
|
||||
}
|
||||
|
||||
private void btn_Search_Clear_Click(object sender, EventArgs e)
|
||||
{
|
||||
searchTextBox.Clear();
|
||||
btn_Search_Click(sender, e);
|
||||
}
|
||||
|
||||
private void SearchTextBox_KeyDown(object sender, KeyEventArgs e)
|
||||
{
|
||||
if (e.KeyCode == Keys.Enter)
|
||||
{
|
||||
// Prevent the beep sound
|
||||
e.SuppressKeyPress = true;
|
||||
|
||||
// Trigger the search button click
|
||||
btn_Search_Click(sender, EventArgs.Empty);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user