mirror of
https://github.com/batfasturd/BetterNPCEditor.git
synced 2025-04-19 10:51:18 +00:00
not sure
This commit is contained in:
parent
33f0e5b1c7
commit
8dc217116f
@ -1,6 +1,7 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Drawing;
|
||||
using System.Linq;
|
||||
using System.Windows.Forms;
|
||||
|
||||
namespace Better_NCP_Editor
|
||||
@ -9,49 +10,58 @@ namespace Better_NCP_Editor
|
||||
{
|
||||
public object NewValue { get; private set; }
|
||||
private Control inputControl;
|
||||
private readonly Type valueType;
|
||||
|
||||
// Constructor now takes an extra parameter: parentNodeName.
|
||||
public EditValueForm(string propertyName, string currentValue, Type valueType, List<string>? comboItems,Dictionary<String,String> allItems)
|
||||
public EditValueForm(string propertyName, string currentValue, Type valueType, List<string>? comboItems, Dictionary<string, string> allItems, Dictionary<string, UInt64> skinIDs)
|
||||
{
|
||||
// Validate required parameters.
|
||||
if (string.IsNullOrWhiteSpace(propertyName))
|
||||
throw new ArgumentException("Property name cannot be null or empty.", nameof(propertyName));
|
||||
if (currentValue == null)
|
||||
throw new ArgumentNullException(nameof(currentValue));
|
||||
if (valueType == null)
|
||||
throw new ArgumentNullException(nameof(valueType));
|
||||
|
||||
this.valueType = valueType;
|
||||
|
||||
// Set up the form's basic properties and size.
|
||||
InitializeForm(propertyName, currentValue, comboItems);
|
||||
// Create and add the input control.
|
||||
CreateInputControl(propertyName, currentValue, comboItems, allItems, skinIDs);
|
||||
// Create and add OK/Cancel buttons.
|
||||
CreateButtons();
|
||||
}
|
||||
|
||||
private void InitializeForm(string propertyName, string currentValue, List<string>? comboItems)
|
||||
{
|
||||
// Set the minimum and default size.
|
||||
this.MinimumSize = new Size(210, 120);
|
||||
//this.AutoScaleDimensions = new SizeF(96F, 96F); // or your base DPI
|
||||
this.AutoScaleMode = AutoScaleMode.None;
|
||||
this.FormBorderStyle = FormBorderStyle.FixedDialog;
|
||||
this.MaximizeBox = false;
|
||||
this.StartPosition = FormStartPosition.CenterParent;
|
||||
this.Text = $"Edit {propertyName}";
|
||||
|
||||
// Measure the width of the property name.
|
||||
// Measure text widths for layout.
|
||||
int propertyNameWidth = TextRenderer.MeasureText(propertyName, this.Font).Width;
|
||||
|
||||
// For non-bool types, measure the current value width.
|
||||
int currentValueWidth = valueType == typeof(bool)
|
||||
? TextRenderer.MeasureText("false", this.Font).Width + 30
|
||||
: TextRenderer.MeasureText(currentValue, this.Font).Width + 40;
|
||||
|
||||
// If combo items are provided, determine the maximum width needed for them.
|
||||
int comboItemsWidth = 0;
|
||||
if (comboItems != null)
|
||||
{
|
||||
foreach (var item in comboItems)
|
||||
{
|
||||
int itemWidth = TextRenderer.MeasureText(item, this.Font).Width;
|
||||
if (itemWidth > comboItemsWidth)
|
||||
comboItemsWidth = itemWidth;
|
||||
comboItemsWidth = Math.Max(comboItemsWidth, itemWidth);
|
||||
}
|
||||
// Add padding for the dropdown arrow and some extra margin.
|
||||
comboItemsWidth += 20;
|
||||
comboItemsWidth += 20; // extra padding for dropdown arrow and margin.
|
||||
}
|
||||
|
||||
// Determine the desired width by taking the maximum of the measured values and adding extra margins.
|
||||
int desiredWidth = Math.Max(propertyNameWidth, Math.Max(currentValueWidth, comboItemsWidth)) + 40;
|
||||
|
||||
// Set the client size based on the desired width.
|
||||
this.ClientSize = new Size(desiredWidth, 120);
|
||||
|
||||
this.Text = $"Edit {propertyName}";
|
||||
this.StartPosition = FormStartPosition.CenterParent;
|
||||
|
||||
// Create the property label.
|
||||
// Create and add the property label.
|
||||
Label lblProperty = new Label()
|
||||
{
|
||||
Text = propertyName,
|
||||
@ -59,59 +69,60 @@ namespace Better_NCP_Editor
|
||||
AutoSize = true
|
||||
};
|
||||
this.Controls.Add(lblProperty);
|
||||
}
|
||||
|
||||
int controlWidth = desiredWidth - 20;
|
||||
private void CreateInputControl(string propertyName, string currentValue, List<string>? comboItems, Dictionary<string, string> allItems, Dictionary<string, UInt64> skinIDs)
|
||||
{
|
||||
int controlWidth = this.ClientSize.Width - 20;
|
||||
|
||||
// Check if we need to use a special ComboBox (for "ShortName" in "Wear items").
|
||||
if (comboItems != null)
|
||||
{
|
||||
ComboBox combo = new ComboBox()
|
||||
// Create a ComboBox when comboItems are provided.
|
||||
ComboBox combo = new ComboBox
|
||||
{
|
||||
Location = new Point(10, 40),
|
||||
Width = controlWidth, // initial width based on desiredWidth minus margins
|
||||
Width = controlWidth,
|
||||
DropDownStyle = ComboBoxStyle.DropDownList
|
||||
};
|
||||
|
||||
int maxWidth = 0;
|
||||
foreach (var key in comboItems)
|
||||
{
|
||||
combo.Items.Add(key);
|
||||
// Measure each item's width using the ComboBox's font.
|
||||
Size itemSize = TextRenderer.MeasureText(key, combo.Font);
|
||||
if (itemSize.Width > maxWidth)
|
||||
maxWidth = itemSize.Width;
|
||||
}
|
||||
|
||||
// Optionally add some extra padding.
|
||||
int paddedWidth = maxWidth + 20;
|
||||
|
||||
// Set the DropDownWidth to ensure items are fully visible.
|
||||
// Add items and adjust the dropdown width to fit the widest item.
|
||||
int maxItemWidth = comboItems.Select(item => TextRenderer.MeasureText(item, combo.Font).Width).Max();
|
||||
int paddedWidth = maxItemWidth + 20;
|
||||
combo.DropDownWidth = paddedWidth;
|
||||
|
||||
// Optionally, you can also adjust the combo's Width if you want it to match the dropdown width.
|
||||
if (combo.Width < paddedWidth)
|
||||
combo.Width = paddedWidth;
|
||||
|
||||
// Set selected item to currentValue if found, otherwise select the first item.
|
||||
var matchingPair = allItems.FirstOrDefault(x => x.Value == currentValue);
|
||||
if (matchingPair.Key != null)
|
||||
foreach (var item in comboItems)
|
||||
{
|
||||
combo.SelectedItem = matchingPair.Key;
|
||||
combo.Items.Add(item);
|
||||
}
|
||||
|
||||
// Attempt to set the selected item using the provided dictionaries.
|
||||
string? selectedKey = allItems.FirstOrDefault(x => x.Value == currentValue).Key;
|
||||
|
||||
// If not found, try using skinIDs (with safe parsing).
|
||||
if (string.IsNullOrEmpty(selectedKey) && skinIDs != null && UInt64.TryParse(currentValue, out UInt64 parsedValue))
|
||||
{
|
||||
selectedKey = skinIDs.FirstOrDefault(x => x.Value == parsedValue).Key;
|
||||
}
|
||||
|
||||
if (!string.IsNullOrEmpty(selectedKey) && combo.Items.Contains(selectedKey))
|
||||
{
|
||||
combo.SelectedItem = selectedKey;
|
||||
}
|
||||
else if (combo.Items.Count > 0)
|
||||
{
|
||||
combo.SelectedIndex = 0;
|
||||
}
|
||||
|
||||
inputControl = combo;
|
||||
this.Controls.Add(combo);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Create the input control normally.
|
||||
// For bool types, use a ComboBox to choose true/false.
|
||||
if (valueType == typeof(bool))
|
||||
{
|
||||
ComboBox combo = new ComboBox()
|
||||
ComboBox combo = new ComboBox
|
||||
{
|
||||
Location = new Point(10, 40),
|
||||
Width = controlWidth,
|
||||
@ -119,13 +130,22 @@ namespace Better_NCP_Editor
|
||||
};
|
||||
combo.Items.Add("true");
|
||||
combo.Items.Add("false");
|
||||
combo.SelectedItem = currentValue;
|
||||
// Parse the current value safely.
|
||||
if (bool.TryParse(currentValue, out bool boolVal))
|
||||
{
|
||||
combo.SelectedItem = boolVal.ToString().ToLower();
|
||||
}
|
||||
else
|
||||
{
|
||||
combo.SelectedIndex = 0;
|
||||
}
|
||||
inputControl = combo;
|
||||
this.Controls.Add(combo);
|
||||
}
|
||||
else
|
||||
{
|
||||
TextBox txtBox = new TextBox()
|
||||
// Default to a TextBox for other types.
|
||||
TextBox txtBox = new TextBox
|
||||
{
|
||||
Location = new Point(10, 40),
|
||||
Width = controlWidth,
|
||||
@ -135,9 +155,12 @@ namespace Better_NCP_Editor
|
||||
this.Controls.Add(txtBox);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void CreateButtons()
|
||||
{
|
||||
// OK button.
|
||||
Button btnOk = new Button()
|
||||
Button btnOk = new Button
|
||||
{
|
||||
Text = "OK",
|
||||
Location = new Point(10, 80),
|
||||
@ -149,7 +172,7 @@ namespace Better_NCP_Editor
|
||||
this.Controls.Add(btnOk);
|
||||
|
||||
// Cancel button.
|
||||
Button btnCancel = new Button()
|
||||
Button btnCancel = new Button
|
||||
{
|
||||
Text = "Cancel",
|
||||
Location = new Point(100, 80),
|
||||
@ -165,18 +188,31 @@ namespace Better_NCP_Editor
|
||||
|
||||
private void BtnOk_Click(object sender, EventArgs e)
|
||||
{
|
||||
// If the input control is the special ComboBox, return the dictionary value.
|
||||
if (inputControl is ComboBox combo && combo.DropDownStyle == ComboBoxStyle.DropDownList &&
|
||||
combo.Items.Count > 0)
|
||||
// Determine the new value based on the type of the input control.
|
||||
if (inputControl is ComboBox combo)
|
||||
{
|
||||
NewValue = combo.SelectedItem.ToString();
|
||||
}
|
||||
else if (inputControl is ComboBox comboBool)
|
||||
{
|
||||
NewValue = comboBool.SelectedItem.ToString() == "true";
|
||||
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
|
||||
{
|
||||
// For non-boolean values, return the selected string.
|
||||
NewValue = combo.SelectedItem?.ToString() ?? string.Empty;
|
||||
}
|
||||
}
|
||||
else if (inputControl is TextBox txt)
|
||||
{
|
||||
// If possible, parse to int; otherwise, leave as string.
|
||||
if (int.TryParse(txt.Text, out int intValue))
|
||||
NewValue = intValue;
|
||||
else
|
||||
|
@ -273,7 +273,31 @@ namespace Better_NCP_Editor
|
||||
{
|
||||
child = new TreeNode(kvp.Key);
|
||||
}
|
||||
// Set the tooltip using your existing tooltips dictionary.
|
||||
child.ToolTipText = toolTips.tips.ContainsKey(kvp.Key) ? toolTips.tips[kvp.Key] : "";
|
||||
|
||||
// *** New code: if this property is the SkinID property, try to update its tooltip ***
|
||||
if (kvp.Key.Equals("SkinID (0 - default)", StringComparison.OrdinalIgnoreCase) &&
|
||||
obj.ContainsKey("ShortName"))
|
||||
{
|
||||
string shortName = obj["ShortName"]?.ToString() ?? "";
|
||||
if (!string.IsNullOrEmpty(shortName) && _itemShortnameToSkinName != null &&
|
||||
_itemShortnameToSkinName.ContainsKey(shortName))
|
||||
{
|
||||
var skinMap = _itemShortnameToSkinName[shortName];
|
||||
if (UInt64.TryParse(kvp.Value?.ToString(), out UInt64 skinId))
|
||||
{
|
||||
// Reverse lookup: find the key (skin display name) whose value equals the skinId.
|
||||
string matchingDisplayName = skinMap.FirstOrDefault(pair => pair.Value == skinId).Key;
|
||||
if (!string.IsNullOrEmpty(matchingDisplayName))
|
||||
{
|
||||
child.ToolTipText = matchingDisplayName;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// *** End new code ***
|
||||
|
||||
child.Tag = kvp.Value;
|
||||
treeNode.Nodes.Add(child);
|
||||
PopulateTreeRecursive(kvp.Value, child);
|
||||
@ -300,6 +324,7 @@ namespace Better_NCP_Editor
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private void entityTreeView_AfterSelect(object sender, TreeViewEventArgs e)
|
||||
{
|
||||
if (e.Node != null)
|
||||
@ -324,11 +349,6 @@ namespace Better_NCP_Editor
|
||||
{
|
||||
enableAddDelButtons = false;
|
||||
}
|
||||
// You can also add additional conditions for a "preset" node, e.g. by checking text:
|
||||
// else if (e.Node.Text.StartsWith("Preset", StringComparison.OrdinalIgnoreCase))
|
||||
// {
|
||||
// enableButtons = true;
|
||||
// }
|
||||
|
||||
btn_entity_add.Enabled = enableAddDelButtons;
|
||||
btn_entity_del.Enabled = enableAddDelButtons;
|
||||
@ -357,91 +377,116 @@ namespace Better_NCP_Editor
|
||||
|
||||
string propName = parts[0].Trim();
|
||||
string currentVal = parts[1].Trim();
|
||||
string? skinToolTip = null;
|
||||
Type valueType = GetValueType(currentVal);
|
||||
|
||||
// Use simple heuristics to determine the type.
|
||||
Type valueType = typeof(string);
|
||||
if (bool.TryParse(currentVal, out bool b))
|
||||
valueType = typeof(bool);
|
||||
else if (int.TryParse(currentVal, out int i))
|
||||
valueType = typeof(int);
|
||||
|
||||
String parentNodeName = "Root";
|
||||
String grandParentNodeName = "Root";
|
||||
List<String> comboList = null;
|
||||
|
||||
if (e.Node.Parent != null)
|
||||
// Get any additional combo and skin lists based on the node hierarchy.
|
||||
var (comboList, skinList, itemCurrentVal) = GetComboAndSkinLists(e.Node, propName);
|
||||
|
||||
using (EditValueForm editForm = new EditValueForm(propName, currentVal, valueType, comboList, _allItems, skinList))
|
||||
{
|
||||
parentNodeName = e.Node.Parent.Text;
|
||||
|
||||
if (e.Node.Parent.Parent != null)
|
||||
if (editForm.ShowDialog() == DialogResult.OK)
|
||||
{
|
||||
grandParentNodeName = e.Node.Parent.Parent.Text;
|
||||
// Populate wear items list
|
||||
if (propName.Equals("ShortName", StringComparison.OrdinalIgnoreCase) && grandParentNodeName.Equals("Wear items"))
|
||||
object newVal = editForm.NewValue;
|
||||
string displayVal = newVal is bool ? newVal.ToString().ToLower() : newVal.ToString();
|
||||
|
||||
if (_allItems.ContainsKey(displayVal))
|
||||
{
|
||||
newVal = _allItems[displayVal];
|
||||
displayVal = _allItems[displayVal];
|
||||
}
|
||||
else if (!string.IsNullOrEmpty(itemCurrentVal) && _itemShortnameToSkinName.ContainsKey(itemCurrentVal))
|
||||
{
|
||||
skinToolTip = displayVal;
|
||||
newVal = _itemShortnameToSkinName[itemCurrentVal][displayVal];
|
||||
displayVal = _itemShortnameToSkinName[itemCurrentVal][displayVal].ToString();
|
||||
}
|
||||
|
||||
if (skinToolTip != null)
|
||||
{
|
||||
e.Node.ToolTipText = skinToolTip;
|
||||
}
|
||||
e.Node.Text = $"{propName}: {displayVal}";
|
||||
|
||||
if (e.Node.Tag is JsonNode node)
|
||||
{
|
||||
JsonNode newNode = JsonValue.Create(newVal);
|
||||
node.ReplaceWith(newNode);
|
||||
e.Node.Tag = newNode;
|
||||
}
|
||||
|
||||
// Mark the file as modified.
|
||||
fileModified = true;
|
||||
btn_save.Enabled = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Determines the type for the current value using simple heuristics.
|
||||
/// </summary>
|
||||
private Type GetValueType(string currentVal)
|
||||
{
|
||||
if (bool.TryParse(currentVal, out _))
|
||||
return typeof(bool);
|
||||
if (int.TryParse(currentVal, out _))
|
||||
return typeof(int);
|
||||
return typeof(string);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Retrieves combo list and skin dictionary based on the node's hierarchy and property name.
|
||||
/// Returns a tuple of (comboList, skinList, itemCurrentVal).
|
||||
/// </summary>
|
||||
private (List<string> comboList, Dictionary<string, UInt64> skinList, string itemCurrentVal) GetComboAndSkinLists(TreeNode node, string propName)
|
||||
{
|
||||
List<string> comboList = null;
|
||||
Dictionary<string, UInt64> skinList = null;
|
||||
string itemCurrentVal = string.Empty;
|
||||
|
||||
if (node.Parent == null)
|
||||
return (comboList, skinList, itemCurrentVal);
|
||||
|
||||
string parentNodeName = node.Parent.Text;
|
||||
string grandParentNodeName = node.Parent.Parent?.Text ?? "Root";
|
||||
|
||||
// Mods override.
|
||||
if (parentNodeName.Equals("Mods", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
comboList = _weaponModItems;
|
||||
}
|
||||
// Check deeper hierarchy.
|
||||
else if (node.Parent.Parent != null)
|
||||
{
|
||||
if (propName.Equals("ShortName", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
if (grandParentNodeName.Equals("Wear items", StringComparison.OrdinalIgnoreCase))
|
||||
comboList = _wearItems;
|
||||
}
|
||||
// Populate belt item list
|
||||
else if (propName.Equals("ShortName", StringComparison.OrdinalIgnoreCase) && grandParentNodeName.Equals("Belt items"))
|
||||
{
|
||||
else if (grandParentNodeName.Equals("Belt items", StringComparison.OrdinalIgnoreCase))
|
||||
comboList = _beltItems;
|
||||
}
|
||||
// Populate belt item list
|
||||
else if (propName.Equals("ShortName", StringComparison.OrdinalIgnoreCase) && grandParentNodeName.Equals("List of items"))
|
||||
{
|
||||
// Populate all items
|
||||
comboList = new List<String>(_allItems.Keys);
|
||||
}
|
||||
// Populate skin ids for wear items
|
||||
else if (propName.Equals("SkinID (0 - default)",StringComparison.OrdinalIgnoreCase) && grandParentNodeName.Equals("Wear items"))
|
||||
{
|
||||
// load the list here
|
||||
}
|
||||
// Populate skin ids for belt items
|
||||
else if (propName.Equals("SkinID (0 - default)", StringComparison.OrdinalIgnoreCase) && grandParentNodeName.Equals("Belt items"))
|
||||
{
|
||||
// load the list here
|
||||
}
|
||||
else if (grandParentNodeName.Equals("List of items", StringComparison.OrdinalIgnoreCase))
|
||||
comboList = new List<string>(_allItems.Keys);
|
||||
}
|
||||
|
||||
if (parentNodeName.Equals("Mods"))
|
||||
else if (propName.Equals("SkinID (0 - default)", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
comboList = _weaponModItems;
|
||||
// Expect node text in the form "Property: Value" from the first child.
|
||||
if (node.Parent.FirstNode != null)
|
||||
{
|
||||
string[] itemParts = node.Parent.FirstNode.Text.Split(new[] { ':' }, 2);
|
||||
if (itemParts.Length == 2)
|
||||
{
|
||||
itemCurrentVal = itemParts[1].Trim();
|
||||
if (_itemShortnameToSkinName.TryGetValue(itemCurrentVal, out var skinMap) && skinMap.Count > 0)
|
||||
{
|
||||
comboList = new List<string>(skinMap.Keys);
|
||||
skinList = skinMap;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
using (EditValueForm editForm = new EditValueForm(propName, currentVal, valueType, comboList, _allItems))
|
||||
{
|
||||
if (editForm.ShowDialog() == DialogResult.OK)
|
||||
{
|
||||
object newVal = editForm.NewValue;
|
||||
string displayVal = newVal is bool ? newVal.ToString().ToLower() : newVal.ToString();
|
||||
if (_allItems.ContainsKey(displayVal))
|
||||
{
|
||||
newVal = _allItems[displayVal];
|
||||
displayVal = _allItems[displayVal];
|
||||
}
|
||||
e.Node.Text = $"{propName}: {displayVal}";
|
||||
|
||||
if (e.Node.Tag is JsonNode node)
|
||||
{
|
||||
JsonNode newNode = JsonValue.Create(newVal);
|
||||
node.ReplaceWith(newNode);
|
||||
e.Node.Tag = newNode;
|
||||
}
|
||||
// Mark the file as modified.
|
||||
fileModified = true;
|
||||
btn_save.Enabled = true;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return (comboList, skinList, itemCurrentVal);
|
||||
}
|
||||
|
||||
|
||||
|
File diff suppressed because it is too large
Load Diff
Loading…
x
Reference in New Issue
Block a user