Files
bluflame/evoke-64k/trunk/Tweaky/Backup/Tweaky/TweakyCore.cs
2026-04-18 22:31:51 +02:00

454 lines
16 KiB
C#

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using System.Windows.Forms;
using System.IO;
using System.Globalization;
using System.Data;
namespace Tweaky
{
public class TweakyCore
{
private Regex EntryPattern = new Regex(@"((?<type>ANY\(.*\))|(?<type>RANGE\(.*\))|(?<type>COMBO\(.*\)))\s*\=\s*(?<value>.*)\s*;");
private Regex AnyPattern = new Regex(@"ANY\((?<type>\w*),\s*(?<name>.*)\)");
private Regex ComboPattern = new Regex(@"COMBO\((?<type>\w*)\s*,\s*(?<options>.*),\s*(?<name>.*)\)");
private Regex RangePattern = new Regex(@"RANGE\((?<type>\w*)\s*,\s*(?<from>.*)\s*,\s*(?<to>.*),\s*(?<name>.*)\)");
private List<VarEntryBase> varEntries = new List<VarEntryBase>();
private Timer saveTimer;
public string FilePath {get; protected set; }
public bool HasWatchableVarEntries { get; protected set; }
public TweakyCore(string filePath)
{
this.FilePath = filePath;
this.ReadFileContent();
}
public void BuildUiElements(Control rootControl)
{
var table = new TableLayoutPanel();
table.AutoSize = true;
table.ColumnCount = 3;
table.RowCount = varEntries.Count;
foreach (RowStyle style in table.RowStyles)
style.SizeType = SizeType.AutoSize;
var currentRowIndex = 0;
foreach (var entry in varEntries)
{
var localEntry = entry;
Control editControl = entry.CreateUi();
if (editControl != null)
{
var nameLabel = new Label();
nameLabel.Text = entry.Name;
nameLabel.Dock = DockStyle.Fill;
nameLabel.AutoSize = true;
nameLabel.TextAlign = System.Drawing.ContentAlignment.MiddleLeft;
var resetControl = new Button();
resetControl.Text = "Reset";
resetControl.Dock = DockStyle.Fill;
resetControl.AutoSize = true;
resetControl.Click += (s, e) => localEntry.Reset();
resetControl.Enabled = false;
table.Controls.Add(nameLabel, 0, currentRowIndex);
table.Controls.Add(editControl, 1, currentRowIndex);
table.Controls.Add(resetControl, 2, currentRowIndex);
localEntry.OnValueChanged += () =>
{
resetControl.Enabled = !localEntry.HasDefaultValue;
};
currentRowIndex++;
}
}
rootControl.Controls.Add(table);
}
protected void ReadFileContent()
{
using (var stringReader = new StreamReader(FilePath))
{
string line;
while ((line = stringReader.ReadLine()) != null)
{
var entryMatch = EntryPattern.Match(line.Trim());
if (!entryMatch.Success)
{
varEntries.Add(new VarEntryBase()
{
Name = line,
});
continue;
}
var maintype = entryMatch.Groups["type"].Value;
var anyMatch = AnyPattern.Match(maintype);
var rangeMatch = RangePattern.Match(maintype);
var comboMatch = ComboPattern.Match(maintype);
VarEntryBase newEntry = null;
if (anyMatch.Success)
{
var type = anyMatch.Groups["type"].Value;
newEntry = VarEntryUtility.CreateType(typeof(VarEntryT<>), type,
VarEntryUtility.ConvertToObject(type, entryMatch.Groups["value"].Value));
newEntry.Name = anyMatch.Groups["name"].Value;
this.HasWatchableVarEntries = true;
}
else if (rangeMatch.Success)
{
var type = rangeMatch.Groups["type"].Value;
newEntry = VarEntryUtility.CreateType(typeof(RangeEntryT<>), type,
VarEntryUtility.ConvertToObject(type, entryMatch.Groups["value"].Value),
VarEntryUtility.ConvertToObject(type, rangeMatch.Groups["from"].Value),
VarEntryUtility.ConvertToObject(type, rangeMatch.Groups["to"].Value));
newEntry.Name = rangeMatch.Groups["name"].Value;
this.HasWatchableVarEntries = true;
}
else if (comboMatch.Success)
{
var type = comboMatch.Groups["type"].Value;
var options = comboMatch.Groups["options"].Value
.Trim('\"').Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries)
.Select(o => VarEntryUtility.ConvertToObject(type, o.Trim()))
.ToList();
newEntry = VarEntryUtility.CreateType(typeof(ComboEntryT<>), type,
VarEntryUtility.ConvertToObject(type, entryMatch.Groups["value"].Value),
options);
newEntry.Name = comboMatch.Groups["name"].Value;
this.HasWatchableVarEntries = true;
}
newEntry.OnValueChanged += () => OnValueChanged();
varEntries.Add(newEntry);
}
}
}
protected void OnValueChanged()
{
if (saveTimer != null)
return; // save is already pending
saveTimer = new Timer();
saveTimer.Interval = 1200; // > one second till the save call is progressed
saveTimer.Tick += (s, e) => WriteFileContent();
saveTimer.Start();
}
public void WriteFileContent()
{
if (saveTimer != null)
{
saveTimer.Stop();
saveTimer.Dispose();
saveTimer = null;
}
using (var streamWriter = new StreamWriter(FilePath, false))
{
foreach (var entry in varEntries)
streamWriter.Write(entry.ToString() + "\r\n");
}
}
}
public static class VarEntryUtility
{
public static string GetTypeName<T>()
{
if (typeof(T) == typeof(bool))
return "bool";
else if (typeof(T) == typeof(int))
return "int";
else if (typeof(T) == typeof(float))
return "float";
return string.Empty;
}
private static Type GetType(Type baseType, string type)
{
switch (type)
{
case "int":
return baseType.MakeGenericType(typeof(int));
case "float":
return baseType.MakeGenericType(typeof(float));
case "bool":
return baseType.MakeGenericType(typeof(bool));
default:
throw new ArgumentException(type);
}
}
public static VarEntryBase CreateType(Type baseType, string type, params object[] args)
{
return Activator.CreateInstance(GetType(baseType, type), args) as VarEntryBase;
}
public static object ConvertToObject(string type, string rawValue)
{
switch (type)
{
case "bool":
return bool.Parse(rawValue);
case "int":
return int.Parse(rawValue);
case "float":
return float.Parse(rawValue.TrimEnd('f'), CultureInfo.InvariantCulture);
default:
return null;
}
}
public static string ConvertToString<T>(object rawValue)
{
if (typeof(T) == typeof(bool))
return (bool)rawValue == true ? "true" : "false";
if (typeof(T) == typeof(int))
return ((int)rawValue).ToString(CultureInfo.InvariantCulture);
if (typeof(T) == typeof(float))
return ((float)rawValue).ToString(CultureInfo.InvariantCulture);
return null;
}
}
public class VarEntryBase
{
public string Name;
public Action OnValueChanged;
public virtual Control CreateUi() { return null; }
public virtual void Reset() {}
public override string ToString()
{
return this.Name;
}
public virtual bool HasDefaultValue { get { return false; } }
}
public class VarEntryT<T> : VarEntryBase
{
public VarEntryT(T defaultValue)
{
this.CurrentValue = this.DefaultValue = defaultValue;
}
public T CurrentValue;
public T DefaultValue;
public override string ToString()
{
return string.Format("ANY({0}, {1}) = {2};",
VarEntryUtility.GetTypeName<T>(),
this.Name,
VarEntryUtility.ConvertToString<T>(this.CurrentValue));
}
protected float ToFloat(object value)
{
if (value.GetType() == typeof(int))
return (float)(int)value;
else
return (float)value;
}
protected T FromFloat(float value)
{
if (typeof(T) == typeof(int))
return (T)(object)(int)value;
else
return (T)(object)value; ;
}
private CheckBox checkBox;
private NumericUpDown numBox;
public override Control CreateUi()
{
if (typeof(T) == typeof(bool))
{
checkBox = new CheckBox();
checkBox.Dock = DockStyle.Left;
checkBox.Checked = (bool)(object)this.CurrentValue;
checkBox.CheckedChanged += (s, e) =>
{
this.CurrentValue = (T)(object)checkBox.Checked;
if (this.OnValueChanged != null)
this.OnValueChanged();
};
return checkBox;
}
else
{
numBox = new NumericUpDown();
numBox.DecimalPlaces = 6;
numBox.Dock = DockStyle.Fill;
numBox.Value = (decimal)ToFloat(this.CurrentValue);
numBox.ValueChanged += (s, e) =>
{
var oldValue = this.CurrentValue;
this.CurrentValue = FromFloat((float)numBox.Value);
if (this.OnValueChanged != null && !oldValue.Equals(this.CurrentValue))
this.OnValueChanged();
};
return numBox;
}
}
public override void Reset()
{
this.CurrentValue = this.DefaultValue;
if (typeof(T) == typeof(bool))
checkBox.Checked = (bool)(object)this.CurrentValue;
else
numBox.Value = (decimal)ToFloat(this.CurrentValue);
this.OnValueChanged();
}
public override bool HasDefaultValue { get { return this.CurrentValue.Equals(this.DefaultValue); } }
}
public class ComboEntryT<T> : VarEntryT<T>
{
public IEnumerable<T> Values;
public ComboEntryT(T defaultValue, IEnumerable<object> values)
: base(defaultValue)
{
this.Values = values.Select(o => (T)o);
}
public override string ToString()
{
var options = string.Join(", ", this.Values
.Select(o => VarEntryUtility.ConvertToString<T>(o))
.ToArray());
return string.Format("COMBO({0}, \"{1}\", {2}) = {3};",
VarEntryUtility.GetTypeName<T>(),
options,
this.Name,
VarEntryUtility.ConvertToString<T>(this.CurrentValue));
}
private ComboBox comboBox;
public override Control CreateUi()
{
comboBox = new ComboBox();
comboBox.DropDownStyle = ComboBoxStyle.DropDownList;
foreach (var option in Values)
comboBox.Items.Add(option);
comboBox.SelectedItem = Values.FirstOrDefault(o => o.Equals(this.CurrentValue));
comboBox.Dock = DockStyle.Fill;
comboBox.SelectedValueChanged += (s, e) =>
{
var oldValue = this.CurrentValue;
this.CurrentValue = (T)comboBox.SelectedItem;
if (OnValueChanged != null && !oldValue.Equals(this.CurrentValue))
OnValueChanged();
};
return comboBox;
}
public override void Reset()
{
this.CurrentValue = this.DefaultValue;
comboBox.SelectedItem = Values.FirstOrDefault(o => o.Equals(this.CurrentValue));
this.OnValueChanged();
}
}
public class RangeEntryT<T> : VarEntryT<T>
{
public T From;
public T To;
public RangeEntryT(T defaultValue, T from, T to)
: base(defaultValue)
{
this.From = from;
this.To = to;
}
public override string ToString()
{
return string.Format("RANGE({0}, {1}, {2}, {3}) = {4};",
VarEntryUtility.GetTypeName<T>(),
VarEntryUtility.ConvertToString<T>(this.From),
VarEntryUtility.ConvertToString<T>(this.To),
this.Name,
VarEntryUtility.ConvertToString<T>(this.CurrentValue));
}
private TrackBar trackBar;
public override Control CreateUi()
{
var panel = new Panel();
panel.Dock = DockStyle.Fill;
panel.Height = 24;
var textBox = new TextBox();
textBox.MaximumSize = new System.Drawing.Size(50, 24);
textBox.Enabled = false;
textBox.Text = VarEntryUtility.ConvertToString<T>(this.CurrentValue);
textBox.Dock = DockStyle.Left;
trackBar = new TrackBar();
trackBar.TickStyle = TickStyle.None;
int Multiplicator = 100;
trackBar.Minimum = (int)(ToFloat(this.From) * Multiplicator);
trackBar.Maximum = (int)(ToFloat(this.To) * Multiplicator);
trackBar.Value = (int)(ToFloat(this.CurrentValue) * Multiplicator);
trackBar.Dock = DockStyle.Fill;
trackBar.ValueChanged += (s, e) =>
{
var oldValue = ToFloat(this.CurrentValue);
this.CurrentValue = FromFloat(trackBar.Value / (float)Multiplicator);
if (this.OnValueChanged != null && !oldValue.Equals(this.CurrentValue))
this.OnValueChanged();
textBox.Text = VarEntryUtility.ConvertToString<T>(this.CurrentValue);
};
panel.Controls.Add(trackBar);
panel.Controls.Add(textBox);
return panel;
}
public override void Reset()
{
this.CurrentValue = this.DefaultValue;
int Multiplicator = 100;
trackBar.Value = (int)(ToFloat(this.CurrentValue) * Multiplicator);
this.OnValueChanged();
}
}
}