2
0
mirror of https://github.com/9ParsonsB/Pulsar.git synced 2025-04-05 17:39:39 -04:00
pulsar/ObservatoryCore/UI/SettingsForm.cs
F K 666f91cfd3 [Core] Fix: Convert Decimal control values to int32 for Int settings (#134)
Attempting to set decimal values to int properties tends to throw errors. ;-)
2024-01-25 23:19:20 -03:30

378 lines
14 KiB
C#

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using Observatory.Assets;
using Observatory.Framework;
using Observatory.Framework.Interfaces;
namespace Observatory.UI
{
public partial class SettingsForm : Form
{
private readonly IObservatoryPlugin _plugin;
private readonly List<int> _colHeight = new List<int>();
private int _colWidth = 400;
public SettingsForm(IObservatoryPlugin plugin)
{
InitializeComponent();
_plugin = plugin;
// Filtered to only settings without SettingIgnore attribute
var settings = PluginManagement.PluginManager.GetSettingDisplayNames(plugin.Settings).Where(s => !Attribute.IsDefined(s.Key, typeof(SettingIgnore)));
CreateControls(settings);
Text = plugin.Name + " Settings";
Icon = Resources.EOCIcon_Presized;
ThemeManager.GetInstance.RegisterControl(this);
}
private void CreateControls(IEnumerable<KeyValuePair<PropertyInfo, string>> settings)
{
bool recentHalfCol = false;
int settingsHeight = 0;
var trackBottomEdge = (Control control) =>
{
var controlBottom = control.Location.Y + control.Height;
if (controlBottom > settingsHeight)
settingsHeight = controlBottom;
};
foreach (var setting in settings)
{
// Reset the column tracking for checkboxes if this isn't a checkbox
int addedHeight = 35;
if (setting.Key.PropertyType.Name != "Boolean")
{
if (recentHalfCol) _colHeight.Add(addedHeight);
recentHalfCol = false;
}
switch (setting.Key.GetValue(_plugin.Settings))
{
case bool:
var checkBox = CreateBoolSetting(setting);
addedHeight = recentHalfCol ? addedHeight : 0;
checkBox.Location = GetSettingPosition(recentHalfCol);
recentHalfCol = !recentHalfCol;
Controls.Add(checkBox);
trackBottomEdge(checkBox);
break;
case string:
var stringLabel = CreateSettingLabel(setting.Value);
var textBox = CreateStringSetting(setting.Key);
stringLabel.Location = GetSettingPosition();
textBox.Location = GetSettingPosition(true);
Controls.Add(stringLabel);
Controls.Add(textBox);
trackBottomEdge(textBox);
break;
case FileInfo:
var fileLabel = CreateSettingLabel(setting.Value);
var pathTextBox = CreateFilePathSetting(setting.Key);
var pathButton = CreateFileBrowseSetting(setting.Key, pathTextBox);
fileLabel.Location = GetSettingPosition();
pathTextBox.Location = GetSettingPosition(true);
_colHeight.Add(addedHeight);
pathButton.Location = GetSettingPosition(true);
Controls.Add(fileLabel);
Controls.Add(pathTextBox);
Controls.Add(pathButton);
trackBottomEdge(pathButton);
break;
case int:
// We have two options for integer values:
// 1) A slider (explicit by way of the SettingIntegerUseSlider attribute and bounded to 0..100 by default)
// 2) A numeric up/down (default otherwise, and is unbounded by default).
// Bounds for both can be set via the SettingNumericBounds attribute, only the up/down uses Increment.
var intLabel = CreateSettingLabel(setting.Value);
Control intControl;
if (Attribute.IsDefined(setting.Key, typeof(SettingNumericUseSlider)))
{
intControl = CreateSettingTrackbar(setting.Key);
}
else
{
intControl = CreateSettingNumericUpDown(setting.Key);
}
intLabel.Location = GetSettingPosition();
intControl.Location = GetSettingPosition(true);
addedHeight = intControl.Height + 2;
intLabel.Height = intControl.Height;
intLabel.TextAlign = ContentAlignment.MiddleRight;
Controls.Add(intLabel);
Controls.Add(intControl);
trackBottomEdge(intControl);
break;
case Action action:
var button = CreateSettingButton(setting.Value, action);
button.Location = GetSettingPosition();
Controls.Add(button);
addedHeight = button.Height;
trackBottomEdge(button);
break;
case Dictionary<string, object> dictSetting:
var dictLabel = CreateSettingLabel(setting.Value);
var dropdown = CreateSettingDropdown(setting.Key, dictSetting);
dictLabel.Location = GetSettingPosition();
dropdown.Location = GetSettingPosition(true);
Controls.Add(dictLabel);
Controls.Add(dropdown);
trackBottomEdge(dropdown);
break;
default:
break;
}
_colHeight.Add(addedHeight);
}
Height = settingsHeight + 160;
Width = _colWidth * 2 + 80;
}
private Point GetSettingPosition(bool secondCol = false)
{
//return new Point(10 + (secondCol ? 200 : 0), -26 + _colHeight.Sum());
return new Point(10 + (secondCol ? _colWidth : 0), 15 + _colHeight.Sum());
}
private Label CreateSettingLabel(string settingName)
{
Label label = new()
{
Text = settingName + ": ",
TextAlign = System.Drawing.ContentAlignment.MiddleRight,
Width = _colWidth,
ForeColor = Color.LightGray
};
return label;
}
private ComboBox CreateSettingDropdown(PropertyInfo setting, Dictionary<string, object> dropdownItems)
{
var backingValueName = (SettingBackingValue?)Attribute.GetCustomAttribute(setting, typeof(SettingBackingValue));
var backingValue = from s in PluginManagement.PluginManager.GetSettingDisplayNames(_plugin.Settings)
where s.Value == backingValueName?.BackingProperty
select s.Key;
if (backingValue.Count() != 1)
throw new($"{_plugin.ShortName}: Dictionary settings must have exactly one backing value.");
ComboBox comboBox = new()
{
Width = _colWidth,
DropDownStyle = ComboBoxStyle.DropDownList
};
comboBox.Items.AddRange(dropdownItems.OrderBy(s => s.Key).Select(s => s.Key).ToArray());
string? currentSelection = backingValue.First().GetValue(_plugin.Settings)?.ToString();
if (currentSelection?.Length > 0)
{
comboBox.SelectedItem = currentSelection;
}
comboBox.SelectedValueChanged += (sender, e) =>
{
backingValue.First().SetValue(_plugin.Settings, comboBox.SelectedItem.ToString());
SaveSettings();
};
return comboBox;
}
private Button CreateSettingButton(string settingName, Action action)
{
Button button = new()
{
Text = settingName,
Width = Convert.ToInt32(_colWidth * 0.8),
Height = 35,
};
button.Click += (sender, e) =>
{
action.Invoke();
SaveSettings();
};
return button;
}
private TrackBar CreateSettingTrackbar(PropertyInfo setting)
{
SettingNumericBounds? bounds = (SettingNumericBounds?)System.Attribute.GetCustomAttribute(setting, typeof(SettingNumericBounds));
var minBound = Convert.ToInt32(bounds?.Minimum ?? 0);
var maxBound = Convert.ToInt32(bounds?.Maximum ?? 100);
var tickFrequency = maxBound - minBound >= 20 ? (maxBound - minBound) / 10 : 1;
TrackBar trackBar = new()
{
Orientation = Orientation.Horizontal,
TickStyle = TickStyle.Both,
TickFrequency = tickFrequency,
Width = _colWidth,
Minimum = minBound,
Maximum = maxBound,
};
trackBar.Value = (int?)setting.GetValue(_plugin.Settings) ?? 0;
trackBar.ValueChanged += (sender, e) =>
{
setting.SetValue(_plugin.Settings, Convert.ToInt32(trackBar.Value));
SaveSettings();
};
return trackBar;
}
private NumericUpDown CreateSettingNumericUpDown(PropertyInfo setting)
{
SettingNumericBounds? bounds = (SettingNumericBounds?)System.Attribute.GetCustomAttribute(setting, typeof(SettingNumericBounds));
NumericUpDown numericUpDown = new()
{
Width = _colWidth,
Minimum = Convert.ToInt32(bounds?.Minimum ?? Int32.MinValue),
Maximum = Convert.ToInt32(bounds?.Maximum ?? Int32.MaxValue),
Increment = Convert.ToInt32(bounds?.Increment ?? 1)
};
numericUpDown.Value = (int?)setting.GetValue(_plugin.Settings) ?? 0;
numericUpDown.ValueChanged += (sender, e) =>
{
setting.SetValue(_plugin.Settings, Convert.ToInt32(numericUpDown.Value));
SaveSettings();
};
return numericUpDown;
}
private CheckBox CreateBoolSetting(KeyValuePair<PropertyInfo, string> setting)
{
CheckBox checkBox = new()
{
Text = setting.Value,
TextAlign = System.Drawing.ContentAlignment.MiddleLeft,
Checked = (bool?)setting.Key.GetValue(_plugin.Settings) ?? false,
Height = 30,
Width = _colWidth,
ForeColor = Color.LightGray
};
checkBox.CheckedChanged += (sender, e) =>
{
setting.Key.SetValue(_plugin.Settings, checkBox.Checked);
SaveSettings();
};
return checkBox;
}
private TextBox CreateStringSetting(PropertyInfo setting)
{
TextBox textBox = new()
{
Text = (setting.GetValue(_plugin.Settings) ?? String.Empty).ToString(),
Width = _colWidth,
};
textBox.TextChanged += (object? sender, EventArgs e) =>
{
setting.SetValue(_plugin.Settings, textBox.Text);
SaveSettings();
};
return textBox;
}
private TextBox CreateFilePathSetting(PropertyInfo setting)
{
var fileInfo = (FileInfo?)setting.GetValue(_plugin.Settings);
TextBox textBox = new()
{
Text = fileInfo?.FullName ?? string.Empty,
Width = _colWidth,
};
textBox.TextChanged += (object? sender, EventArgs e) =>
{
setting.SetValue(_plugin.Settings, new FileInfo(textBox.Text));
SaveSettings();
};
return textBox;
}
private Button CreateFileBrowseSetting(PropertyInfo setting, TextBox textBox)
{
Button button = new()
{
Text = "Browse",
Height = 35,
Width = _colWidth / 2,
};
button.Click += (object? sender, EventArgs e) =>
{
var currentDir = ((FileInfo?)setting.GetValue(_plugin.Settings))?.DirectoryName;
OpenFileDialog ofd = new OpenFileDialog()
{
Title = "Select File...",
Filter = "Lua files (*.lua)|*.lua|All files (*.*)|*.*",
FilterIndex = 0,
InitialDirectory = currentDir ?? Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments)
};
var browseResult = ofd.ShowDialog();
if (browseResult == DialogResult.OK)
{
textBox.Text = ofd.FileName;
}
};
return button;
}
private void SaveSettings()
{
PluginManagement.PluginManager.GetInstance.SaveSettings(_plugin, _plugin.Settings);
}
private void PluginSettingsCloseButton_Click(object sender, EventArgs e)
{
Close();
}
}
}