mirror of
https://github.com/9ParsonsB/Pulsar.git
synced 2025-07-01 08:23:42 -04:00
WIP: observatory UI overhaul
This commit is contained in:
2
ObservatoryCore/UI/CoreForm.Designer.cs
generated
2
ObservatoryCore/UI/CoreForm.Designer.cs
generated
@ -360,6 +360,7 @@
|
||||
this.TestButton.TabIndex = 12;
|
||||
this.TestButton.Text = "Test";
|
||||
this.TestButton.UseVisualStyleBackColor = false;
|
||||
this.TestButton.Click += new System.EventHandler(this.TestButton_Click);
|
||||
//
|
||||
// ColourButton
|
||||
//
|
||||
@ -569,6 +570,7 @@
|
||||
this.ToggleMonitorButton.TabIndex = 3;
|
||||
this.ToggleMonitorButton.Text = "Start Monitor";
|
||||
this.ToggleMonitorButton.UseVisualStyleBackColor = false;
|
||||
this.ToggleMonitorButton.Click += new System.EventHandler(this.ToggleMonitorButton_Click);
|
||||
//
|
||||
// ClearButton
|
||||
//
|
||||
|
109
ObservatoryCore/UI/CoreForm.Plugins.cs
Normal file
109
ObservatoryCore/UI/CoreForm.Plugins.cs
Normal file
@ -0,0 +1,109 @@
|
||||
using Observatory.PluginManagement;
|
||||
using Observatory.Framework.Interfaces;
|
||||
|
||||
namespace Observatory.UI
|
||||
{
|
||||
partial class CoreForm
|
||||
{
|
||||
|
||||
private void PopulatePluginList()
|
||||
{
|
||||
List<IObservatoryPlugin> uniquePlugins = new();
|
||||
|
||||
foreach (var (plugin, signed) in PluginManager.GetInstance.workerPlugins)
|
||||
{
|
||||
if (!uniquePlugins.Contains(plugin))
|
||||
{
|
||||
uniquePlugins.Add(plugin);
|
||||
ListViewItem item = new ListViewItem(new[] { plugin.Name, "Worker", plugin.Version, PluginStatusString(signed) });
|
||||
PluginList.Items.Add(item);
|
||||
}
|
||||
}
|
||||
|
||||
foreach (var (plugin, signed) in PluginManager.GetInstance.notifyPlugins)
|
||||
{
|
||||
if (!uniquePlugins.Contains(plugin))
|
||||
{
|
||||
uniquePlugins.Add(plugin);
|
||||
ListViewItem item = new ListViewItem(new[] { plugin.Name, "Notifier", plugin.Version, PluginStatusString(signed) });
|
||||
PluginList.Items.Add(item);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static string PluginStatusString(PluginManager.PluginStatus status)
|
||||
{
|
||||
switch (status)
|
||||
{
|
||||
case PluginManager.PluginStatus.Signed:
|
||||
return "Signed";
|
||||
|
||||
case PluginManager.PluginStatus.Unsigned:
|
||||
return "Unsigned";
|
||||
|
||||
case PluginManager.PluginStatus.InvalidSignature:
|
||||
return "Invalid Signature";
|
||||
|
||||
case PluginManager.PluginStatus.InvalidPlugin:
|
||||
return "Invalid Plugin";
|
||||
|
||||
case PluginManager.PluginStatus.InvalidLibrary:
|
||||
return "Invalid File";
|
||||
|
||||
case PluginManager.PluginStatus.NoCert:
|
||||
return "Unsigned Observatory (Debug build)";
|
||||
|
||||
case PluginManager.PluginStatus.SigCheckDisabled:
|
||||
return "Signature Checks Disabled";
|
||||
|
||||
default:
|
||||
return string.Empty;
|
||||
}
|
||||
}
|
||||
|
||||
private void CreatePluginTabs()
|
||||
{
|
||||
var uiPlugins = PluginManager.GetInstance.workerPlugins.Where(p => p.plugin.PluginUI.PluginUIType != Framework.PluginUI.UIType.None);
|
||||
|
||||
PluginHelper.CreatePluginTabs(CoreMenu, uiPlugins, uiPanels);
|
||||
|
||||
foreach(ToolStripMenuItem item in CoreMenu.Items)
|
||||
{
|
||||
pluginList.Add(item.Text, item);
|
||||
}
|
||||
}
|
||||
|
||||
private void CreatePluginSettings()
|
||||
{
|
||||
foreach (var plugin in PluginManager.GetInstance.workerPlugins)
|
||||
{
|
||||
var pluginSettingsPanel = new SettingsPanel(plugin.plugin, AdjustPanelsBelow);
|
||||
AddSettingsPanel(pluginSettingsPanel);
|
||||
}
|
||||
foreach (var plugin in PluginManager.GetInstance.notifyPlugins)
|
||||
{
|
||||
var pluginSettingsPanel = new SettingsPanel(plugin.plugin, AdjustPanelsBelow);
|
||||
AddSettingsPanel(pluginSettingsPanel);
|
||||
}
|
||||
}
|
||||
|
||||
private void AddSettingsPanel(SettingsPanel panel)
|
||||
{
|
||||
int lowestPoint = 0;
|
||||
foreach (Control control in CorePanel.Controls)
|
||||
{
|
||||
if (control.Location.Y + control.Height > lowestPoint)
|
||||
lowestPoint = control.Location.Y + control.Height;
|
||||
}
|
||||
DuplicateControlVisuals(PopupNotificationLabel, panel.Header);
|
||||
panel.Header.TextAlign = PopupNotificationLabel.TextAlign;
|
||||
panel.Header.Location = new Point(PopupNotificationLabel.Location.X, lowestPoint);
|
||||
|
||||
DuplicateControlVisuals(PopupSettingsPanel, panel, false);
|
||||
panel.Location = new Point(PopupSettingsPanel.Location.X, lowestPoint + panel.Header.Height);
|
||||
panel.Visible = false;
|
||||
CorePanel.Controls.Add(panel.Header);
|
||||
CorePanel.Controls.Add(panel);
|
||||
}
|
||||
}
|
||||
}
|
111
ObservatoryCore/UI/CoreForm.Settings.cs
Normal file
111
ObservatoryCore/UI/CoreForm.Settings.cs
Normal file
@ -0,0 +1,111 @@
|
||||
using Observatory.Utils;
|
||||
|
||||
namespace Observatory.UI
|
||||
{
|
||||
partial class CoreForm
|
||||
{
|
||||
private void ColourButton_Click(object _, EventArgs e)
|
||||
{
|
||||
var selectionResult = PopupColour.ShowDialog();
|
||||
if (selectionResult == DialogResult.OK)
|
||||
{
|
||||
ColourButton.BackColor = PopupColour.Color;
|
||||
Properties.Core.Default.NativeNotifyColour = (uint)PopupColour.Color.ToArgb();
|
||||
SettingsManager.Save();
|
||||
}
|
||||
}
|
||||
|
||||
private void PopupCheckbox_CheckedChanged(object _, EventArgs e)
|
||||
{
|
||||
Properties.Core.Default.NativeNotify = PopupCheckbox.Checked;
|
||||
SettingsManager.Save();
|
||||
}
|
||||
|
||||
private void DurationSpinner_ValueChanged(object _, EventArgs e)
|
||||
{
|
||||
Properties.Core.Default.NativeNotifyTimeout = (int)DurationSpinner.Value;
|
||||
SettingsManager.Save();
|
||||
}
|
||||
|
||||
private void ScaleSpinner_ValueChanged(object _, EventArgs e)
|
||||
{
|
||||
Properties.Core.Default.NativeNotifyScale = (int)ScaleSpinner.Value;
|
||||
SettingsManager.Save();
|
||||
}
|
||||
|
||||
private void FontDropdown_SelectedIndexChanged(object _, EventArgs e)
|
||||
{
|
||||
Properties.Core.Default.NativeNotifyFont = FontDropdown.SelectedItem.ToString();
|
||||
SettingsManager.Save();
|
||||
}
|
||||
|
||||
private void CornerDropdown_SelectedIndexChanged(object _, EventArgs e)
|
||||
{
|
||||
Properties.Core.Default.NativeNotifyCorner = CornerDropdown.SelectedIndex;
|
||||
SettingsManager.Save();
|
||||
}
|
||||
|
||||
private void DisplayDropdown_SelectedIndexChanged(object _, EventArgs e)
|
||||
{
|
||||
Properties.Core.Default.NativeNotifyScreen = DisplayDropdown.SelectedIndex - 1;
|
||||
SettingsManager.Save();
|
||||
}
|
||||
|
||||
private void VoiceVolumeSlider_Scroll(object _, EventArgs e)
|
||||
{
|
||||
Properties.Core.Default.VoiceVolume = VoiceVolumeSlider.Value;
|
||||
SettingsManager.Save();
|
||||
}
|
||||
|
||||
private void VoiceSpeedSlider_Scroll(object _, EventArgs e)
|
||||
{
|
||||
Properties.Core.Default.VoiceRate = VoiceSpeedSlider.Value;
|
||||
SettingsManager.Save();
|
||||
}
|
||||
|
||||
private void VoiceCheckbox_CheckedChanged(object _, EventArgs e)
|
||||
{
|
||||
Properties.Core.Default.VoiceNotify = VoiceCheckbox.Checked;
|
||||
SettingsManager.Save();
|
||||
}
|
||||
|
||||
private void VoiceDropdown_SelectedIndexChanged(object _, EventArgs e)
|
||||
{
|
||||
Properties.Core.Default.VoiceSelected = VoiceDropdown.SelectedItem.ToString();
|
||||
SettingsManager.Save();
|
||||
}
|
||||
|
||||
private void PopulateDropdownOptions()
|
||||
{
|
||||
var fonts = new System.Drawing.Text.InstalledFontCollection().Families;
|
||||
FontDropdown.Items.AddRange(fonts.Select(f => f.Name).ToArray());
|
||||
|
||||
DisplayDropdown.Items.Add("Primary");
|
||||
if (Screen.AllScreens.Length > 1)
|
||||
for (int i = 0; i < Screen.AllScreens.Length; i++)
|
||||
DisplayDropdown.Items.Add((i + 1).ToString());
|
||||
|
||||
var voices = new System.Speech.Synthesis.SpeechSynthesizer().GetInstalledVoices();
|
||||
foreach (var voice in voices.Select(v => v.VoiceInfo.Name))
|
||||
VoiceDropdown.Items.Add(voice);
|
||||
|
||||
}
|
||||
|
||||
private void PopulateNativeSettings()
|
||||
{
|
||||
var settings = Properties.Core.Default;
|
||||
|
||||
DisplayDropdown.SelectedIndex = settings.NativeNotifyScreen + 1;
|
||||
CornerDropdown.SelectedIndex = settings.NativeNotifyCorner;
|
||||
FontDropdown.SelectedItem = settings.NativeNotifyFont;
|
||||
ScaleSpinner.Value = settings.NativeNotifyScale;
|
||||
DurationSpinner.Value = settings.NativeNotifyTimeout;
|
||||
ColourButton.BackColor = Color.FromArgb((int)settings.NativeNotifyColour);
|
||||
PopupCheckbox.Checked = settings.NativeNotify;
|
||||
VoiceVolumeSlider.Value = settings.VoiceVolume;
|
||||
VoiceSpeedSlider.Value = settings.VoiceRate;
|
||||
VoiceDropdown.SelectedItem = settings.VoiceSelected;
|
||||
VoiceCheckbox.Checked = settings.VoiceNotify;
|
||||
}
|
||||
}
|
||||
}
|
@ -1,6 +1,9 @@
|
||||
using Observatory.Framework.Interfaces;
|
||||
using Observatory.Framework;
|
||||
using Observatory.Framework.Interfaces;
|
||||
using Observatory.PluginManagement;
|
||||
using Observatory.Utils;
|
||||
using System.Text;
|
||||
using System.Windows.Forms;
|
||||
|
||||
namespace Observatory.UI
|
||||
{
|
||||
@ -37,40 +40,6 @@ namespace Observatory.UI
|
||||
AdjustPanelsBelow(PopupSettingsPanel, AdjustmentDirection.Up);
|
||||
}
|
||||
|
||||
private void PopulateDropdownOptions()
|
||||
{
|
||||
var fonts = new System.Drawing.Text.InstalledFontCollection().Families;
|
||||
FontDropdown.Items.AddRange(fonts.Select(f => f.Name).ToArray());
|
||||
|
||||
DisplayDropdown.Items.Add("Primary");
|
||||
if (Screen.AllScreens.Length > 1)
|
||||
for (int i = 0; i < Screen.AllScreens.Length; i++)
|
||||
DisplayDropdown.Items.Add((i + 1).ToString());
|
||||
|
||||
var voices = new System.Speech.Synthesis.SpeechSynthesizer().GetInstalledVoices();
|
||||
foreach (var voice in voices.Select(v => v.VoiceInfo.Name))
|
||||
VoiceDropdown.Items.Add(voice);
|
||||
|
||||
}
|
||||
|
||||
private void PopulateNativeSettings()
|
||||
{
|
||||
var settings = Properties.Core.Default;
|
||||
|
||||
DisplayDropdown.SelectedIndex = settings.NativeNotifyScreen + 1;
|
||||
CornerDropdown.SelectedIndex = settings.NativeNotifyCorner;
|
||||
FontDropdown.SelectedItem = settings.NativeNotifyFont;
|
||||
ScaleSpinner.Value = settings.NativeNotifyScale;
|
||||
DurationSpinner.Value = settings.NativeNotifyTimeout;
|
||||
ColourButton.BackColor = Color.FromArgb((int)settings.NativeNotifyColour);
|
||||
PopupCheckbox.Checked = settings.NativeNotify;
|
||||
VoiceVolumeSlider.Value = settings.VoiceVolume;
|
||||
VoiceSpeedSlider.Value = settings.VoiceRate;
|
||||
VoiceDropdown.SelectedItem = settings.VoiceSelected;
|
||||
VoiceCheckbox.Checked = settings.VoiceNotify;
|
||||
}
|
||||
|
||||
|
||||
private void CoreMenu_SizeChanged(object? sender, EventArgs e)
|
||||
{
|
||||
CorePanel.Location = new Point(12 + CoreMenu.Width, 12);
|
||||
@ -80,95 +49,27 @@ namespace Observatory.UI
|
||||
|
||||
private Dictionary<string, ToolStripMenuItem> pluginList;
|
||||
|
||||
private void CreatePluginTabs()
|
||||
private static void DuplicateControlVisuals(Control source, Control target, bool applyHeight = true)
|
||||
{
|
||||
var uiPlugins = PluginManager.GetInstance.workerPlugins.Where(p => p.plugin.PluginUI.PluginUIType != Framework.PluginUI.UIType.None);
|
||||
|
||||
PluginHelper.CreatePluginTabs(CoreMenu, uiPlugins, uiPanels);
|
||||
|
||||
foreach(ToolStripMenuItem item in CoreMenu.Items)
|
||||
{
|
||||
pluginList.Add(item.Text, item);
|
||||
}
|
||||
if (applyHeight) target.Height = source.Height;
|
||||
target.Width = source.Width;
|
||||
target.Font = source.Font;
|
||||
target.ForeColor = source.ForeColor;
|
||||
target.BackColor = source.BackColor;
|
||||
target.Anchor = source.Anchor;
|
||||
}
|
||||
|
||||
private void CreatePluginSettings()
|
||||
private void ToggleMonitorButton_Click(object sender, EventArgs e)
|
||||
{
|
||||
foreach (var plugin in PluginManager.GetInstance.workerPlugins)
|
||||
if ((LogMonitor.GetInstance.CurrentState & Framework.LogMonitorState.Realtime) == Framework.LogMonitorState.Realtime)
|
||||
{
|
||||
var pluginSettingsPanel = new SettingsPanel(plugin.plugin, AdjustPanelsBelow);
|
||||
AddSettingsPanel(pluginSettingsPanel);
|
||||
LogMonitor.GetInstance.Stop();
|
||||
ToggleMonitorButton.Text = "Start Monitor";
|
||||
}
|
||||
foreach (var plugin in PluginManager.GetInstance.notifyPlugins)
|
||||
else
|
||||
{
|
||||
var pluginSettingsPanel = new SettingsPanel(plugin.plugin, AdjustPanelsBelow);
|
||||
AddSettingsPanel(pluginSettingsPanel);
|
||||
}
|
||||
}
|
||||
|
||||
private void AddSettingsPanel(SettingsPanel panel)
|
||||
{
|
||||
int lowestPoint = 0;
|
||||
foreach (Control control in CorePanel.Controls)
|
||||
{
|
||||
if (control.Location.Y + control.Height > lowestPoint)
|
||||
lowestPoint = control.Location.Y + control.Height;
|
||||
}
|
||||
panel.Header.Location = new Point(PopupNotificationLabel.Location.X, lowestPoint);
|
||||
panel.Header.Width = PopupNotificationLabel.Width;
|
||||
panel.Header.Font = PopupNotificationLabel.Font;
|
||||
panel.Header.ForeColor = PopupNotificationLabel.ForeColor;
|
||||
panel.Header.BackColor = PopupNotificationLabel.BackColor;
|
||||
panel.Header.TextAlign = PopupNotificationLabel.TextAlign;
|
||||
panel.Location = new Point(PopupNotificationLabel.Location.X, lowestPoint + panel.Header.Height);
|
||||
panel.Width = PopupSettingsPanel.Width;
|
||||
CorePanel.Controls.Add(panel.Header);
|
||||
CorePanel.Controls.Add(panel);
|
||||
}
|
||||
|
||||
private void PopulatePluginList()
|
||||
{
|
||||
List<IObservatoryPlugin> uniquePlugins = new();
|
||||
|
||||
|
||||
foreach (var (plugin, signed) in PluginManager.GetInstance.workerPlugins)
|
||||
{
|
||||
if (!uniquePlugins.Contains(plugin))
|
||||
{
|
||||
uniquePlugins.Add(plugin);
|
||||
ListViewItem item = new ListViewItem(new[] { plugin.Name, "Worker", plugin.Version, PluginStatusString(signed) });
|
||||
PluginList.Items.Add(item);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static string PluginStatusString(PluginManager.PluginStatus status)
|
||||
{
|
||||
switch (status)
|
||||
{
|
||||
case PluginManager.PluginStatus.Signed:
|
||||
return "Signed";
|
||||
|
||||
case PluginManager.PluginStatus.Unsigned:
|
||||
return "Unsigned";
|
||||
|
||||
case PluginManager.PluginStatus.InvalidSignature:
|
||||
return "Invalid Signature";
|
||||
|
||||
case PluginManager.PluginStatus.InvalidPlugin:
|
||||
return "Invalid Plugin";
|
||||
|
||||
case PluginManager.PluginStatus.InvalidLibrary:
|
||||
return "Invalid File";
|
||||
|
||||
case PluginManager.PluginStatus.NoCert:
|
||||
return "Unsigned Observatory (Debug build)";
|
||||
|
||||
case PluginManager.PluginStatus.SigCheckDisabled:
|
||||
return "Signature Checks Disabled";
|
||||
|
||||
default:
|
||||
return string.Empty;
|
||||
LogMonitor.GetInstance.Start();
|
||||
ToggleMonitorButton.Text = "Stop Monitor";
|
||||
}
|
||||
}
|
||||
|
||||
@ -337,82 +238,16 @@ namespace Observatory.UI
|
||||
Up, Down
|
||||
}
|
||||
|
||||
#region Settings Changes
|
||||
|
||||
private void ColourButton_Click(object _, EventArgs e)
|
||||
private void TestButton_Click(object sender, EventArgs e)
|
||||
{
|
||||
var selectionResult = PopupColour.ShowDialog();
|
||||
if (selectionResult == DialogResult.OK)
|
||||
NotificationArgs args = new()
|
||||
{
|
||||
ColourButton.BackColor = PopupColour.Color;
|
||||
Properties.Core.Default.NativeNotifyColour = (uint)PopupColour.Color.ToArgb();
|
||||
Properties.Core.Default.Save();
|
||||
}
|
||||
Title = "Test Notification",
|
||||
Detail = "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Donec at elit maximus, ornare dui nec, accumsan velit. Vestibulum fringilla elit."
|
||||
};
|
||||
var testNotify = new NotificationForm(new Guid(), args);
|
||||
testNotify.Show();
|
||||
|
||||
}
|
||||
|
||||
private void PopupCheckbox_CheckedChanged(object _, EventArgs e)
|
||||
{
|
||||
Properties.Core.Default.NativeNotify = PopupCheckbox.Checked;
|
||||
Properties.Core.Default.Save();
|
||||
}
|
||||
|
||||
private void DurationSpinner_ValueChanged(object _, EventArgs e)
|
||||
{
|
||||
Properties.Core.Default.NativeNotifyTimeout = (int)DurationSpinner.Value;
|
||||
Properties.Core.Default.Save();
|
||||
}
|
||||
|
||||
private void ScaleSpinner_ValueChanged(object _, EventArgs e)
|
||||
{
|
||||
Properties.Core.Default.NativeNotifyScale = (int)ScaleSpinner.Value;
|
||||
Properties.Core.Default.Save();
|
||||
}
|
||||
|
||||
private void FontDropdown_SelectedIndexChanged(object _, EventArgs e)
|
||||
{
|
||||
Properties.Core.Default.NativeNotifyFont = FontDropdown.SelectedItem.ToString();
|
||||
Properties.Core.Default.Save();
|
||||
}
|
||||
|
||||
private void CornerDropdown_SelectedIndexChanged(object _, EventArgs e)
|
||||
{
|
||||
Properties.Core.Default.NativeNotifyCorner = CornerDropdown.SelectedIndex;
|
||||
Properties.Core.Default.Save();
|
||||
}
|
||||
|
||||
private void DisplayDropdown_SelectedIndexChanged(object _, EventArgs e)
|
||||
{
|
||||
Properties.Core.Default.NativeNotifyScreen = DisplayDropdown.SelectedIndex - 1;
|
||||
Properties.Core.Default.Save();
|
||||
}
|
||||
|
||||
private void VoiceVolumeSlider_Scroll(object _, EventArgs e)
|
||||
{
|
||||
Properties.Core.Default.VoiceVolume = VoiceVolumeSlider.Value;
|
||||
Properties.Core.Default.Save();
|
||||
}
|
||||
|
||||
private void VoiceSpeedSlider_Scroll(object _, EventArgs e)
|
||||
{
|
||||
Properties.Core.Default.VoiceRate = VoiceSpeedSlider.Value;
|
||||
Properties.Core.Default.Save();
|
||||
}
|
||||
|
||||
private void VoiceCheckbox_CheckedChanged(object _, EventArgs e)
|
||||
{
|
||||
Properties.Core.Default.VoiceNotify = VoiceCheckbox.Checked;
|
||||
Properties.Core.Default.Save();
|
||||
}
|
||||
|
||||
private void VoiceDropdown_SelectedIndexChanged(object _, EventArgs e)
|
||||
{
|
||||
Properties.Core.Default.VoiceSelected = VoiceDropdown.SelectedItem.ToString();
|
||||
Properties.Core.Default.Save();
|
||||
}
|
||||
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
}
|
||||
}
|
@ -3,10 +3,11 @@ using System.Collections;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using Observatory.Framework.Interfaces;
|
||||
|
||||
namespace Observatory.UI
|
||||
{
|
||||
internal class DefaultSorter : IComparer
|
||||
internal class DefaultSorter : IObservatoryComparer
|
||||
{
|
||||
/// <summary>
|
||||
/// Specifies the column to be sorted
|
||||
@ -15,7 +16,7 @@ namespace Observatory.UI
|
||||
/// <summary>
|
||||
/// Specifies the order in which to sort (i.e. 'Ascending').
|
||||
/// </summary>
|
||||
private SortOrder OrderOfSort;
|
||||
private int OrderOfSort;
|
||||
/// <summary>
|
||||
/// Case insensitive comparer object
|
||||
/// </summary>
|
||||
@ -30,7 +31,7 @@ namespace Observatory.UI
|
||||
ColumnToSort = 0;
|
||||
|
||||
// Initialize the sort order to 'none'
|
||||
OrderOfSort = SortOrder.None;
|
||||
OrderOfSort = 0;
|
||||
|
||||
// Initialize the CaseInsensitiveComparer object
|
||||
ObjectCompare = new CaseInsensitiveComparer();
|
||||
@ -49,25 +50,68 @@ namespace Observatory.UI
|
||||
ListViewItem? listviewX = (ListViewItem?)x;
|
||||
ListViewItem? listviewY = (ListViewItem?)y;
|
||||
|
||||
if (OrderOfSort == 0)
|
||||
return 0;
|
||||
|
||||
// Compare the two items
|
||||
compareResult = ObjectCompare.Compare(listviewX?.SubItems[ColumnToSort].Text, listviewY?.SubItems[ColumnToSort].Text);
|
||||
compareResult = NaturalCompare(listviewX?.SubItems[ColumnToSort].Text, listviewY?.SubItems[ColumnToSort].Text);
|
||||
|
||||
// Calculate correct return value based on object comparison
|
||||
if (OrderOfSort == SortOrder.Ascending)
|
||||
if (OrderOfSort == 1)
|
||||
{
|
||||
// Ascending sort is selected, return normal result of compare operation
|
||||
return compareResult;
|
||||
}
|
||||
else if (OrderOfSort == SortOrder.Descending)
|
||||
else
|
||||
{
|
||||
// Descending sort is selected, return negative result of compare operation
|
||||
return (-compareResult);
|
||||
}
|
||||
else
|
||||
}
|
||||
|
||||
private static int NaturalCompare(string? x, string? y)
|
||||
{
|
||||
for (int i = 0; i <= x?.Length && i <= y?.Length; i++)
|
||||
{
|
||||
// Return '0' to indicate they are equal
|
||||
return 0;
|
||||
// If we've reached the end of the string without finding a difference
|
||||
// the longer string is "greater".
|
||||
if (i == x.Length || i == y.Length)
|
||||
return x.Length > y.Length ? 1 : y.Length > x.Length ? -1 : 0;
|
||||
|
||||
// We've found a number in the same place in both strings.
|
||||
if (Char.IsDigit(x[i]) && Char.IsDigit(y[i]))
|
||||
{
|
||||
// Walk ahead and get the full numbers.
|
||||
string xNum = new(x[i..].TakeWhile(c => Char.IsDigit(c)).ToArray());
|
||||
string yNum = new(y[i..].TakeWhile(c => Char.IsDigit(c)).ToArray());
|
||||
|
||||
// Pad with zeroes to equal lengths.
|
||||
int numLength = Math.Max(xNum.Length, yNum.Length);
|
||||
string xNumPadded = xNum.PadLeft(numLength, '0');
|
||||
string yNumPadded = yNum.PadLeft(numLength, '0');
|
||||
|
||||
// Now that they're the same length a direct compare works.
|
||||
int result = xNumPadded.CompareTo(yNumPadded);
|
||||
if (result != 0)
|
||||
{
|
||||
return result;
|
||||
}
|
||||
else
|
||||
{
|
||||
// The numbers are identical, skip them and keep moving.
|
||||
i += numLength - 1;
|
||||
}
|
||||
}
|
||||
// Check if we have unequal letters.
|
||||
else if (x[i] != y[i])
|
||||
{
|
||||
// Straight compare and return.
|
||||
return x[i] > y[i] ? 1 : -1;
|
||||
}
|
||||
}
|
||||
|
||||
// If we somehow make it here, return equal result.
|
||||
return 0;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@ -88,7 +132,7 @@ namespace Observatory.UI
|
||||
/// <summary>
|
||||
/// Gets or sets the order of sorting to apply (for example, 'Ascending' or 'Descending').
|
||||
/// </summary>
|
||||
public SortOrder Order
|
||||
public int Order
|
||||
{
|
||||
set
|
||||
{
|
||||
|
310
ObservatoryCore/UI/DwmHelper.cs
Normal file
310
ObservatoryCore/UI/DwmHelper.cs
Normal file
@ -0,0 +1,310 @@
|
||||
// Source: https://stackoverflow.com/questions/51578104/how-to-create-a-semi-transparent-or-blurred-backcolor-in-a-windows-form
|
||||
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Security;
|
||||
|
||||
[SuppressUnmanagedCodeSecurity]
|
||||
public class DwmHelper
|
||||
{
|
||||
public const int WM_DWMCOMPOSITIONCHANGED = 0x031E;
|
||||
|
||||
public struct MARGINS
|
||||
{
|
||||
public int leftWidth;
|
||||
public int rightWidth;
|
||||
public int topHeight;
|
||||
public int bottomHeight;
|
||||
|
||||
public MARGINS(int LeftWidth, int RightWidth, int TopHeight, int BottomHeight)
|
||||
{
|
||||
leftWidth = LeftWidth;
|
||||
rightWidth = RightWidth;
|
||||
topHeight = TopHeight;
|
||||
bottomHeight = BottomHeight;
|
||||
}
|
||||
|
||||
public void NoMargins()
|
||||
{
|
||||
leftWidth = 0;
|
||||
rightWidth = 0;
|
||||
topHeight = 0;
|
||||
bottomHeight = 0;
|
||||
}
|
||||
|
||||
public void SheetOfGlass()
|
||||
{
|
||||
leftWidth = -1;
|
||||
rightWidth = -1;
|
||||
topHeight = -1;
|
||||
bottomHeight = -1;
|
||||
}
|
||||
}
|
||||
|
||||
[Flags]
|
||||
public enum DWM_BB
|
||||
{
|
||||
Enable = 1,
|
||||
BlurRegion = 2,
|
||||
TransitionOnMaximized = 4
|
||||
}
|
||||
|
||||
// https://learn.microsoft.com/en-us/windows/win32/api/dwmapi/ne-dwmapi-dwmwindowattribute
|
||||
public enum DWMWINDOWATTRIBUTE : uint
|
||||
{
|
||||
NCRenderingEnabled = 1, //Get atttribute
|
||||
NCRenderingPolicy, //Enable or disable non-client rendering
|
||||
TransitionsForceDisabled,
|
||||
AllowNCPaint,
|
||||
CaptionButtonBounds, //Get atttribute
|
||||
NonClientRtlLayout,
|
||||
ForceIconicRepresentation,
|
||||
Flip3DPolicy,
|
||||
ExtendedFrameBounds, //Get atttribute
|
||||
HasIconicBitmap,
|
||||
DisallowPeek,
|
||||
ExcludedFromPeek,
|
||||
Cloak,
|
||||
Cloaked, //Get atttribute. Returns a DWMCLOACKEDREASON
|
||||
FreezeRepresentation,
|
||||
PassiveUpdateMode,
|
||||
UseHostBackDropBrush,
|
||||
AccentPolicy = 19, // Win 10 (undocumented)
|
||||
ImmersiveDarkMode = 20, // Win 11 22000
|
||||
WindowCornerPreference = 33, // Win 11 22000
|
||||
BorderColor, // Win 11 22000
|
||||
CaptionColor, // Win 11 22000
|
||||
TextColor, // Win 11 22000
|
||||
VisibleFrameBorderThickness, // Win 11 22000
|
||||
SystemBackdropType // Win 11 22621
|
||||
}
|
||||
|
||||
public enum DWMCLOACKEDREASON : uint
|
||||
{
|
||||
DWM_CLOAKED_APP = 0x0000001, //cloaked by its owner application.
|
||||
DWM_CLOAKED_SHELL = 0x0000002, //cloaked by the Shell.
|
||||
DWM_CLOAKED_INHERITED = 0x0000004 //inherited from its owner window.
|
||||
}
|
||||
|
||||
public enum DWMNCRENDERINGPOLICY : uint
|
||||
{
|
||||
UseWindowStyle, // Enable/disable non-client rendering based on window style
|
||||
Disabled, // Disabled non-client rendering; window style is ignored
|
||||
Enabled, // Enabled non-client rendering; window style is ignored
|
||||
};
|
||||
|
||||
public enum DWMACCENTSTATE
|
||||
{
|
||||
ACCENT_DISABLED = 0,
|
||||
ACCENT_ENABLE_GRADIENT = 1,
|
||||
ACCENT_ENABLE_TRANSPARENTGRADIENT = 2,
|
||||
ACCENT_ENABLE_BLURBEHIND = 3,
|
||||
ACCENT_INVALID_STATE = 4
|
||||
}
|
||||
|
||||
[Flags]
|
||||
public enum CompositionAction : uint
|
||||
{
|
||||
DWM_EC_DISABLECOMPOSITION = 0,
|
||||
DWM_EC_ENABLECOMPOSITION = 1
|
||||
}
|
||||
|
||||
// Values designating how Flip3D treats a given window.
|
||||
enum DWMFLIP3DWINDOWPOLICY : uint
|
||||
{
|
||||
Default, // Hide or include the window in Flip3D based on window style and visibility.
|
||||
ExcludeBelow, // Display the window under Flip3D and disabled.
|
||||
ExcludeAbove, // Display the window above Flip3D and enabled.
|
||||
};
|
||||
|
||||
public enum ThumbProperties_dwFlags : uint
|
||||
{
|
||||
RectDestination = 0x00000001,
|
||||
RectSource = 0x00000002,
|
||||
Opacity = 0x00000004,
|
||||
Visible = 0x00000008,
|
||||
SourceClientAreaOnly = 0x00000010
|
||||
}
|
||||
|
||||
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
public struct AccentPolicy
|
||||
{
|
||||
public DWMACCENTSTATE AccentState;
|
||||
public int AccentFlags;
|
||||
public int GradientColor;
|
||||
public int AnimationId;
|
||||
|
||||
public AccentPolicy(DWMACCENTSTATE accentState, int accentFlags, int gradientColor, int animationId)
|
||||
{
|
||||
AccentState = accentState;
|
||||
AccentFlags = accentFlags;
|
||||
GradientColor = gradientColor;
|
||||
AnimationId = animationId;
|
||||
}
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
public struct DWM_BLURBEHIND
|
||||
{
|
||||
public DWM_BB dwFlags;
|
||||
public int fEnable;
|
||||
public IntPtr hRgnBlur;
|
||||
public int fTransitionOnMaximized;
|
||||
|
||||
public DWM_BLURBEHIND(bool enabled)
|
||||
{
|
||||
dwFlags = DWM_BB.Enable;
|
||||
fEnable = (enabled) ? 1 : 0;
|
||||
hRgnBlur = IntPtr.Zero;
|
||||
fTransitionOnMaximized = 0;
|
||||
}
|
||||
|
||||
public Region Region => Region.FromHrgn(hRgnBlur);
|
||||
|
||||
public bool TransitionOnMaximized
|
||||
{
|
||||
get => fTransitionOnMaximized > 0;
|
||||
set
|
||||
{
|
||||
fTransitionOnMaximized = (value) ? 1 : 0;
|
||||
dwFlags |= DWM_BB.TransitionOnMaximized;
|
||||
}
|
||||
}
|
||||
|
||||
public void SetRegion(Graphics graphics, Region region)
|
||||
{
|
||||
hRgnBlur = region.GetHrgn(graphics);
|
||||
dwFlags |= DWM_BB.BlurRegion;
|
||||
}
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
public struct WinCompositionAttrData
|
||||
{
|
||||
public DWMWINDOWATTRIBUTE Attribute;
|
||||
public IntPtr Data; //Will point to an AccentPolicy struct, where Attribute will be DWMWINDOWATTRIBUTE.AccentPolicy
|
||||
public int SizeOfData;
|
||||
|
||||
public WinCompositionAttrData(DWMWINDOWATTRIBUTE attribute, IntPtr data, int sizeOfData)
|
||||
{
|
||||
Attribute = attribute;
|
||||
Data = data;
|
||||
SizeOfData = sizeOfData;
|
||||
}
|
||||
}
|
||||
|
||||
private static int GetBlurBehindPolicyAccentFlags()
|
||||
{
|
||||
int drawLeftBorder = 20;
|
||||
int drawTopBorder = 40;
|
||||
int drawRightBorder = 80;
|
||||
int drawBottomBorder = 100;
|
||||
return (drawLeftBorder | drawTopBorder | drawRightBorder | drawBottomBorder);
|
||||
}
|
||||
|
||||
//https://msdn.microsoft.com/en-us/library/windows/desktop/aa969508(v=vs.85).aspx
|
||||
[DllImport("dwmapi.dll")]
|
||||
internal static extern int DwmEnableBlurBehindWindow(IntPtr hwnd, ref DWM_BLURBEHIND blurBehind);
|
||||
|
||||
[DllImport("dwmapi.dll", PreserveSig = false)]
|
||||
public static extern void DwmEnableComposition(CompositionAction uCompositionAction);
|
||||
|
||||
//https://msdn.microsoft.com/it-it/library/windows/desktop/aa969512(v=vs.85).aspx
|
||||
[DllImport("dwmapi.dll")]
|
||||
internal static extern int DwmExtendFrameIntoClientArea(IntPtr hWnd, ref MARGINS pMarInset);
|
||||
|
||||
//https://msdn.microsoft.com/en-us/library/windows/desktop/aa969515(v=vs.85).aspx
|
||||
[DllImport("dwmapi.dll")]
|
||||
internal static extern int DwmGetWindowAttribute(IntPtr hwnd, DWMWINDOWATTRIBUTE attr, ref int attrValue, int attrSize);
|
||||
|
||||
//https://msdn.microsoft.com/en-us/library/windows/desktop/aa969524(v=vs.85).aspx
|
||||
[DllImport("dwmapi.dll")]
|
||||
internal static extern int DwmSetWindowAttribute(IntPtr hwnd, DWMWINDOWATTRIBUTE attr, ref int attrValue, int attrSize);
|
||||
|
||||
[DllImport("User32.dll", SetLastError = true)]
|
||||
internal static extern int SetWindowCompositionAttribute(IntPtr hwnd, ref WinCompositionAttrData data);
|
||||
|
||||
[DllImport("dwmapi.dll")]
|
||||
internal static extern int DwmIsCompositionEnabled(ref int pfEnabled);
|
||||
|
||||
public static bool IsCompositionEnabled()
|
||||
{
|
||||
int pfEnabled = 0;
|
||||
int result = DwmIsCompositionEnabled(ref pfEnabled);
|
||||
return (pfEnabled == 1) ? true : false;
|
||||
}
|
||||
|
||||
public static bool IsNonClientRenderingEnabled(IntPtr hWnd)
|
||||
{
|
||||
int gwaEnabled = 0;
|
||||
int result = DwmGetWindowAttribute(hWnd, DWMWINDOWATTRIBUTE.NCRenderingEnabled, ref gwaEnabled, sizeof(int));
|
||||
return gwaEnabled == 1;
|
||||
}
|
||||
|
||||
public static bool WindowSetAttribute(IntPtr hWnd, DWMWINDOWATTRIBUTE attribute, int attributeValue)
|
||||
{
|
||||
int result = DwmSetWindowAttribute(hWnd, attribute, ref attributeValue, sizeof(int));
|
||||
return (result == 0);
|
||||
}
|
||||
|
||||
public static void Windows10EnableBlurBehind(IntPtr hWnd)
|
||||
{
|
||||
DWMNCRENDERINGPOLICY policy = DWMNCRENDERINGPOLICY.Enabled;
|
||||
WindowSetAttribute(hWnd, DWMWINDOWATTRIBUTE.NCRenderingPolicy, (int)policy);
|
||||
|
||||
AccentPolicy accPolicy = new AccentPolicy()
|
||||
{
|
||||
AccentState = DWMACCENTSTATE.ACCENT_ENABLE_BLURBEHIND,
|
||||
};
|
||||
|
||||
int accentSize = Marshal.SizeOf(accPolicy);
|
||||
IntPtr accentPtr = Marshal.AllocHGlobal(accentSize);
|
||||
Marshal.StructureToPtr(accPolicy, accentPtr, false);
|
||||
var data = new WinCompositionAttrData(DWMWINDOWATTRIBUTE.AccentPolicy, accentPtr, accentSize);
|
||||
|
||||
SetWindowCompositionAttribute(hWnd, ref data);
|
||||
Marshal.FreeHGlobal(accentPtr);
|
||||
}
|
||||
|
||||
public static bool WindowEnableBlurBehind(IntPtr hWnd)
|
||||
{
|
||||
DWMNCRENDERINGPOLICY policy = DWMNCRENDERINGPOLICY.Enabled;
|
||||
WindowSetAttribute(hWnd, DWMWINDOWATTRIBUTE.NCRenderingPolicy, (int)policy);
|
||||
|
||||
DWM_BLURBEHIND dwm_BB = new DWM_BLURBEHIND(true);
|
||||
int result = DwmEnableBlurBehindWindow(hWnd, ref dwm_BB);
|
||||
return result == 0;
|
||||
}
|
||||
|
||||
public static bool WindowExtendIntoClientArea(IntPtr hWnd, MARGINS margins)
|
||||
{
|
||||
// Extend frame on the bottom of client area
|
||||
int result = DwmExtendFrameIntoClientArea(hWnd, ref margins);
|
||||
return result == 0;
|
||||
}
|
||||
|
||||
public static bool WindowBorderlessDropShadow(IntPtr hWnd, int shadowSize)
|
||||
{
|
||||
MARGINS margins = new MARGINS(0, shadowSize, 0, shadowSize);
|
||||
int result = DwmExtendFrameIntoClientArea(hWnd, ref margins);
|
||||
return result == 0;
|
||||
}
|
||||
|
||||
public static bool WindowSheetOfGlass(IntPtr hWnd)
|
||||
{
|
||||
MARGINS margins = new MARGINS();
|
||||
|
||||
//Margins set to All:-1 - Sheet Of Glass effect
|
||||
margins.SheetOfGlass();
|
||||
int result = DwmExtendFrameIntoClientArea(hWnd, ref margins);
|
||||
return result == 0;
|
||||
}
|
||||
|
||||
public static bool WindowDisableRendering(IntPtr hWnd)
|
||||
{
|
||||
int ncrp = (int)DWMNCRENDERINGPOLICY.Disabled;
|
||||
// Disable non-client area rendering on the window.
|
||||
int result = DwmSetWindowAttribute(hWnd, DWMWINDOWATTRIBUTE.NCRenderingPolicy, ref ncrp, sizeof(int));
|
||||
return result == 0;
|
||||
}
|
||||
}
|
52
ObservatoryCore/UI/NotificationForm.Designer.cs
generated
52
ObservatoryCore/UI/NotificationForm.Designer.cs
generated
@ -28,12 +28,60 @@
|
||||
/// </summary>
|
||||
private void InitializeComponent()
|
||||
{
|
||||
this.components = new System.ComponentModel.Container();
|
||||
this.Title = new System.Windows.Forms.Label();
|
||||
this.Body = new System.Windows.Forms.Label();
|
||||
this.SuspendLayout();
|
||||
//
|
||||
// Title
|
||||
//
|
||||
this.Title.Font = new System.Drawing.Font("Segoe UI", 24F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point);
|
||||
this.Title.ForeColor = System.Drawing.Color.OrangeRed;
|
||||
this.Title.Location = new System.Drawing.Point(5, 5);
|
||||
this.Title.MaximumSize = new System.Drawing.Size(355, 0);
|
||||
this.Title.Name = "Title";
|
||||
this.Title.Size = new System.Drawing.Size(338, 45);
|
||||
this.Title.TabIndex = 0;
|
||||
this.Title.Text = "Title";
|
||||
//
|
||||
// Body
|
||||
//
|
||||
this.Body.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left)
|
||||
| System.Windows.Forms.AnchorStyles.Right)));
|
||||
this.Body.AutoSize = true;
|
||||
this.Body.Font = new System.Drawing.Font("Segoe UI", 14.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point);
|
||||
this.Body.ForeColor = System.Drawing.Color.OrangeRed;
|
||||
this.Body.Location = new System.Drawing.Point(12, 45);
|
||||
this.Body.MaximumSize = new System.Drawing.Size(320, 85);
|
||||
this.Body.Name = "Body";
|
||||
this.Body.Size = new System.Drawing.Size(51, 31);
|
||||
this.Body.TabIndex = 1;
|
||||
this.Body.Text = "Body";
|
||||
this.Body.UseCompatibleTextRendering = true;
|
||||
//
|
||||
// NotificationForm
|
||||
//
|
||||
this.AutoScaleDimensions = new System.Drawing.SizeF(7F, 15F);
|
||||
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
|
||||
this.ClientSize = new System.Drawing.Size(800, 450);
|
||||
this.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(64)))), ((int)(((byte)(64)))), ((int)(((byte)(64)))));
|
||||
this.ClientSize = new System.Drawing.Size(355, 145);
|
||||
this.ControlBox = false;
|
||||
this.Controls.Add(this.Body);
|
||||
this.Controls.Add(this.Title);
|
||||
this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.None;
|
||||
this.MaximizeBox = false;
|
||||
this.MinimizeBox = false;
|
||||
this.Name = "NotificationForm";
|
||||
this.ShowIcon = false;
|
||||
this.ShowInTaskbar = false;
|
||||
this.Text = "NotificationForm";
|
||||
this.ResumeLayout(false);
|
||||
this.PerformLayout();
|
||||
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
private Label Title;
|
||||
private Label Body;
|
||||
}
|
||||
}
|
@ -1,9 +1,12 @@
|
||||
using System;
|
||||
using Observatory.Framework;
|
||||
using Observatory.Framework.Files.Journal;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using System.Data;
|
||||
using System.Drawing;
|
||||
using System.Linq;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows.Forms;
|
||||
@ -12,11 +15,206 @@ namespace Observatory.UI
|
||||
{
|
||||
public partial class NotificationForm : Form
|
||||
{
|
||||
public NotificationForm()
|
||||
private Color _color;
|
||||
private readonly Guid _guid;
|
||||
private readonly System.Timers.Timer _timer;
|
||||
private bool _defaultPosition = true;
|
||||
private Point _originalLocation;
|
||||
|
||||
protected override bool ShowWithoutActivation => true;
|
||||
protected override CreateParams CreateParams
|
||||
{
|
||||
get
|
||||
{
|
||||
CreateParams cp = base.CreateParams;
|
||||
cp.ExStyle |= 0x00000008; // WS_EX_TOPMOST
|
||||
return cp;
|
||||
}
|
||||
}
|
||||
|
||||
public NotificationForm(Guid guid, NotificationArgs args)
|
||||
{
|
||||
_guid = guid;
|
||||
_color = Color.FromArgb((int)Properties.Core.Default.NativeNotifyColour);
|
||||
InitializeComponent();
|
||||
|
||||
Title.Paint += DrawText;
|
||||
Body.Paint += DrawText;
|
||||
|
||||
if (System.Environment.OSVersion.Version.Major >= 6 && DwmHelper.IsCompositionEnabled())
|
||||
{
|
||||
if (Environment.OSVersion.Version.Major > 6)
|
||||
{
|
||||
DwmHelper.Windows10EnableBlurBehind(Handle);
|
||||
}
|
||||
else
|
||||
{
|
||||
DwmHelper.WindowEnableBlurBehind(Handle);
|
||||
}
|
||||
|
||||
// For some reason this causes the window to become all white on my own
|
||||
// PC. Looks very similar to strange system-specific all-white behaviour
|
||||
// of Avalonia.
|
||||
// DwmHelper.WindowBorderlessDropShadow(Handle, 2);
|
||||
}
|
||||
|
||||
|
||||
Title.ForeColor = _color;
|
||||
Title.Text = args.Title;
|
||||
Title.Font = new Font(Properties.Core.Default.NativeNotifyFont, 24);
|
||||
Body.ForeColor = _color;
|
||||
Body.Text = args.Detail;
|
||||
Body.Font = new Font(Properties.Core.Default.NativeNotifyFont, 14);
|
||||
this.Paint += DrawBorder;
|
||||
|
||||
AdjustPosition(args.XPos / 100, args.YPos / 100);
|
||||
|
||||
_timer = new();
|
||||
_timer.Elapsed += CloseNotification;
|
||||
if (args.Timeout != 0)
|
||||
{
|
||||
_timer.Interval = args.Timeout == -1 ? Properties.Core.Default.NativeNotifyTimeout : args.Timeout;
|
||||
_timer.Start();
|
||||
}
|
||||
}
|
||||
|
||||
public Guid Guid;
|
||||
public void Update(NotificationArgs notificationArgs)
|
||||
{
|
||||
Title.Text = notificationArgs.Title;
|
||||
Body.Text = notificationArgs.Detail;
|
||||
}
|
||||
|
||||
private void AdjustPosition(double x = -1.0, double y = -1.0)
|
||||
{
|
||||
int screen = Properties.Core.Default.NativeNotifyScreen;
|
||||
int corner = Properties.Core.Default.NativeNotifyCorner;
|
||||
Rectangle screenBounds;
|
||||
|
||||
|
||||
if (screen == -1 || screen > Screen.AllScreens.Length)
|
||||
if (Screen.AllScreens.Length == 1)
|
||||
screenBounds = Screen.GetBounds(this);
|
||||
else
|
||||
screenBounds = Screen.PrimaryScreen.Bounds;
|
||||
else
|
||||
screenBounds = Screen.AllScreens[screen - 1].Bounds;
|
||||
|
||||
if (x >= 0 && y >= 0)
|
||||
{
|
||||
_defaultPosition = false;
|
||||
int xLocation = Convert.ToInt32(screenBounds.Width * x);
|
||||
int yLocation = Convert.ToInt32(screenBounds.Height * x);
|
||||
Location = Point.Add(screenBounds.Location, new Size(xLocation, yLocation));
|
||||
}
|
||||
else
|
||||
{
|
||||
_defaultPosition = true;
|
||||
switch (corner)
|
||||
{
|
||||
default:
|
||||
case 0:
|
||||
Location = Point.Add(
|
||||
new Point(screenBounds.Right, screenBounds.Bottom),
|
||||
new Size(-(Width+50), -(Height+50)));
|
||||
break;
|
||||
case 1:
|
||||
Location = Point.Add(
|
||||
new Point(screenBounds.Left, screenBounds.Bottom),
|
||||
new Size(50, -(Height + 50)));
|
||||
break;
|
||||
case 2:
|
||||
Location = Point.Add(
|
||||
new Point(screenBounds.Right, screenBounds.Top),
|
||||
new Size(-(Width + 50), 50));
|
||||
break;
|
||||
case 3:
|
||||
Location = Point.Add(
|
||||
new Point(screenBounds.Left, screenBounds.Top),
|
||||
new Size(50, 00));
|
||||
break;
|
||||
}
|
||||
_originalLocation = new Point(Location.X, Location.Y);
|
||||
}
|
||||
}
|
||||
|
||||
private void DrawBorder(object? sender, PaintEventArgs e)
|
||||
{
|
||||
using (Pen pen = new Pen(_color))
|
||||
{
|
||||
pen.Width = 6;
|
||||
e.Graphics.DrawLine(pen, 0, 0, Width, 0);
|
||||
e.Graphics.DrawLine(pen, 0, 0, 0, Height);
|
||||
e.Graphics.DrawLine(pen, 0, Height, Width, Height);
|
||||
e.Graphics.DrawLine(pen, Width, 0, Width, Height);
|
||||
}
|
||||
}
|
||||
|
||||
protected override void WndProc(ref Message m)
|
||||
{
|
||||
|
||||
switch (m.Msg)
|
||||
{
|
||||
case DwmHelper.WM_DWMCOMPOSITIONCHANGED:
|
||||
if (System.Environment.OSVersion.Version.Major >= 6 && DwmHelper.IsCompositionEnabled())
|
||||
{
|
||||
var policy = DwmHelper.DWMNCRENDERINGPOLICY.Enabled;
|
||||
DwmHelper.WindowSetAttribute(Handle, DwmHelper.DWMWINDOWATTRIBUTE.NCRenderingPolicy, (int)policy);
|
||||
DwmHelper.WindowBorderlessDropShadow(Handle, 2);
|
||||
m.Result = IntPtr.Zero;
|
||||
}
|
||||
break;
|
||||
case 0x0084:
|
||||
m.Result = (IntPtr)(-1);
|
||||
return;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
base.WndProc(ref m);
|
||||
}
|
||||
|
||||
private void DrawText(object? sender, PaintEventArgs e)
|
||||
{
|
||||
if (sender != null)
|
||||
{
|
||||
var label = (Label)sender;
|
||||
e.Graphics.Clear(Color.Transparent);
|
||||
using (var sf = new StringFormat())
|
||||
using (var brush = new SolidBrush(label.ForeColor))
|
||||
{
|
||||
sf.Alignment = sf.LineAlignment = StringAlignment.Near;
|
||||
e.Graphics.TextRenderingHint = System.Drawing.Text.TextRenderingHint.AntiAliasGridFit;
|
||||
e.Graphics.DrawString(label.Text, label.Font, brush, label.ClientRectangle, sf);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public Guid Guid { get => _guid; }
|
||||
|
||||
private void AdjustText()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
private void CloseNotification(object? sender, System.Timers.ElapsedEventArgs e)
|
||||
{
|
||||
try
|
||||
{
|
||||
Close();
|
||||
}
|
||||
catch
|
||||
{
|
||||
try
|
||||
{
|
||||
this.Invoke(() => Close());
|
||||
}
|
||||
catch
|
||||
{
|
||||
throw new Exception("blah");
|
||||
}
|
||||
}
|
||||
|
||||
_timer.Stop();
|
||||
_timer.Dispose();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,64 +1,4 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<root>
|
||||
<!--
|
||||
Microsoft ResX Schema
|
||||
|
||||
Version 2.0
|
||||
|
||||
The primary goals of this format is to allow a simple XML format
|
||||
that is mostly human readable. The generation and parsing of the
|
||||
various data types are done through the TypeConverter classes
|
||||
associated with the data types.
|
||||
|
||||
Example:
|
||||
|
||||
... ado.net/XML headers & schema ...
|
||||
<resheader name="resmimetype">text/microsoft-resx</resheader>
|
||||
<resheader name="version">2.0</resheader>
|
||||
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
|
||||
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
|
||||
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
|
||||
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
|
||||
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
|
||||
<value>[base64 mime encoded serialized .NET Framework object]</value>
|
||||
</data>
|
||||
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
|
||||
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
|
||||
<comment>This is a comment</comment>
|
||||
</data>
|
||||
|
||||
There are any number of "resheader" rows that contain simple
|
||||
name/value pairs.
|
||||
|
||||
Each data row contains a name, and value. The row also contains a
|
||||
type or mimetype. Type corresponds to a .NET class that support
|
||||
text/value conversion through the TypeConverter architecture.
|
||||
Classes that don't support this are serialized and stored with the
|
||||
mimetype set.
|
||||
|
||||
The mimetype is used for serialized objects, and tells the
|
||||
ResXResourceReader how to depersist the object. This is currently not
|
||||
extensible. For a given mimetype the value must be set accordingly:
|
||||
|
||||
Note - application/x-microsoft.net.object.binary.base64 is the format
|
||||
that the ResXResourceWriter will generate, however the reader can
|
||||
read any of the formats listed below.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.binary.base64
|
||||
value : The object must be serialized with
|
||||
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.soap.base64
|
||||
value : The object must be serialized with
|
||||
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.bytearray.base64
|
||||
value : The object must be serialized into a byte array
|
||||
: using a System.ComponentModel.TypeConverter
|
||||
: and then encoded with base64 encoding.
|
||||
-->
|
||||
<root>
|
||||
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
|
||||
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
|
||||
<xsd:element name="root" msdata:IsDataSet="true">
|
||||
|
@ -1,11 +1,7 @@
|
||||
using Observatory.Framework.Interfaces;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Security.Cryptography.X509Certificates;
|
||||
using System.Speech.Synthesis;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Collections;
|
||||
using Observatory.PluginManagement;
|
||||
using Observatory.Utils;
|
||||
|
||||
namespace Observatory.UI
|
||||
{
|
||||
@ -47,12 +43,20 @@ namespace Observatory.UI
|
||||
|
||||
if (plugin.PluginUI.PluginUIType == Framework.PluginUI.UIType.Basic)
|
||||
uiPanels.Add(newItem, CreateBasicUI(plugin));
|
||||
else if (plugin.PluginUI.PluginUIType == Framework.PluginUI.UIType.Panel)
|
||||
uiPanels.Add(newItem, (Panel)plugin.PluginUI.UI);
|
||||
}
|
||||
|
||||
private static Panel CreateBasicUI(IObservatoryPlugin plugin)
|
||||
{
|
||||
Panel panel = new();
|
||||
var columnSorter = new DefaultSorter();
|
||||
|
||||
IObservatoryComparer columnSorter;
|
||||
if (plugin.ColumnSorter != null)
|
||||
columnSorter = plugin.ColumnSorter;
|
||||
else
|
||||
columnSorter = new DefaultSorter();
|
||||
|
||||
ListView listView = new()
|
||||
{
|
||||
View = View.Details,
|
||||
@ -62,7 +66,8 @@ namespace Observatory.UI
|
||||
BackColor = Color.FromArgb(64, 64, 64),
|
||||
ForeColor = Color.LightGray,
|
||||
GridLines = true,
|
||||
ListViewItemSorter = columnSorter
|
||||
ListViewItemSorter = columnSorter,
|
||||
Font = new Font(new FontFamily("Segoe UI"), 10, FontStyle.Regular)
|
||||
};
|
||||
|
||||
foreach (var property in plugin.PluginUI.DataGrid.First().GetType().GetProperties())
|
||||
@ -75,20 +80,20 @@ namespace Observatory.UI
|
||||
if (e.Column == columnSorter.SortColumn)
|
||||
{
|
||||
// Reverse the current sort direction for this column.
|
||||
if (columnSorter.Order == SortOrder.Ascending)
|
||||
if (columnSorter.Order == 1)
|
||||
{
|
||||
columnSorter.Order = SortOrder.Descending;
|
||||
columnSorter.Order = -1;
|
||||
}
|
||||
else
|
||||
{
|
||||
columnSorter.Order = SortOrder.Ascending;
|
||||
columnSorter.Order = 1;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Set the column number that is to be sorted; default to ascending.
|
||||
columnSorter.SortColumn = e.Column;
|
||||
columnSorter.Order = SortOrder.Ascending;
|
||||
columnSorter.Order = 1;
|
||||
}
|
||||
listView.Sort();
|
||||
};
|
||||
@ -97,20 +102,58 @@ namespace Observatory.UI
|
||||
|
||||
plugin.PluginUI.DataGrid.CollectionChanged += (sender, e) =>
|
||||
{
|
||||
if (e.Action == System.Collections.Specialized.NotifyCollectionChangedAction.Add &&
|
||||
e.NewItems != null)
|
||||
listView.Invoke(() =>
|
||||
{
|
||||
foreach (var newItem in e.NewItems)
|
||||
if (e.Action == System.Collections.Specialized.NotifyCollectionChangedAction.Add &&
|
||||
e.NewItems != null)
|
||||
{
|
||||
ListViewItem newListItem = new();
|
||||
foreach (var property in newItem.GetType().GetProperties())
|
||||
foreach (var newItem in e.NewItems)
|
||||
{
|
||||
newListItem.SubItems.Add(property.GetValue(newItem)?.ToString());
|
||||
ListViewItem newListItem = new();
|
||||
foreach (var property in newItem.GetType().GetProperties())
|
||||
{
|
||||
newListItem.SubItems.Add(property.GetValue(newItem)?.ToString());
|
||||
}
|
||||
newListItem.SubItems.RemoveAt(0);
|
||||
listView.Items.Add(newListItem);
|
||||
}
|
||||
newListItem.SubItems.RemoveAt(0);
|
||||
listView.Items.Add(newListItem);
|
||||
}
|
||||
}
|
||||
|
||||
if (e.Action == System.Collections.Specialized.NotifyCollectionChangedAction.Remove &&
|
||||
e.OldItems != null)
|
||||
{
|
||||
foreach (var oldItem in e.OldItems)
|
||||
{
|
||||
ListViewItem oldListItem = new();
|
||||
foreach (var property in oldItem.GetType().GetProperties())
|
||||
{
|
||||
oldListItem.SubItems.Add(property.GetValue(oldItem)?.ToString());
|
||||
}
|
||||
oldListItem.SubItems.RemoveAt(0);
|
||||
|
||||
var itemToRemove = listView.Items.Cast<ListViewItem>().Where(i => i.SubItems.Cast<string>().SequenceEqual(oldListItem.SubItems.Cast<string>())).First();
|
||||
if (itemToRemove != null)
|
||||
{
|
||||
listView.Items.Remove(itemToRemove);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (e.Action == System.Collections.Specialized.NotifyCollectionChangedAction.Reset)
|
||||
{
|
||||
listView.Items.Clear();
|
||||
foreach (var item in plugin.PluginUI.DataGrid)
|
||||
{
|
||||
ListViewItem listItem = new();
|
||||
foreach (var property in item.GetType().GetProperties())
|
||||
{
|
||||
listItem.SubItems.Add(property.GetValue(item)?.ToString());
|
||||
}
|
||||
listItem.SubItems.RemoveAt(0);
|
||||
listView.Items.Add(listItem);
|
||||
}
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
return panel;
|
||||
|
@ -2,10 +2,12 @@
|
||||
using Observatory.Framework.Interfaces;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Data.Common;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows.Forms.VisualStyles;
|
||||
|
||||
namespace Observatory.UI
|
||||
{
|
||||
@ -22,7 +24,7 @@ namespace Observatory.UI
|
||||
_adjustPanelsBelow = adjustPanelsBelow;
|
||||
|
||||
// Filtered to only settings without SettingIgnore attribute
|
||||
var settings = PluginManagement.PluginManager.GetSettingDisplayNames(plugin).Where(s => !Attribute.IsDefined(s.Key, typeof (SettingIgnore)));
|
||||
var settings = PluginManagement.PluginManager.GetSettingDisplayNames(plugin.Settings).Where(s => !Attribute.IsDefined(s.Key, typeof (SettingIgnore)));
|
||||
CreateControls(settings);
|
||||
|
||||
}
|
||||
@ -30,35 +32,300 @@ namespace Observatory.UI
|
||||
private void CreateControls(IEnumerable<KeyValuePair<PropertyInfo, string>> settings)
|
||||
{
|
||||
int controlRow = 0;
|
||||
bool nextColumn = true;
|
||||
bool recentHalfCol = false;
|
||||
|
||||
// Handle bool (checkbox) settings first and keep them grouped together
|
||||
foreach (var setting in settings.Where(s => s.Key.PropertyType == typeof(bool)))
|
||||
foreach (var setting in settings)
|
||||
{
|
||||
CheckBox checkBox = new()
|
||||
// Reset the column tracking for checkboxes if this isn't a checkbox
|
||||
if (setting.Key.PropertyType.Name != "Boolean" && setting.Key.PropertyType.Name != "Button")
|
||||
recentHalfCol = false;
|
||||
|
||||
switch (setting.Key.GetValue(_plugin.Settings))
|
||||
{
|
||||
Text = setting.Value,
|
||||
Checked = (bool?)setting.Key.GetValue(_plugin.Settings) ?? false
|
||||
};
|
||||
case bool:
|
||||
var checkBox = CreateBoolSetting(setting);
|
||||
controlRow += recentHalfCol ? 0 : 1;
|
||||
checkBox.Location = GetSettingPosition(controlRow, recentHalfCol);
|
||||
|
||||
checkBox.CheckedChanged += (object? _, EventArgs _) =>
|
||||
{
|
||||
setting.Key.SetValue(_plugin.Settings, checkBox.Checked);
|
||||
PluginManagement.PluginManager.GetInstance.SaveSettings(_plugin, _plugin.Settings);
|
||||
};
|
||||
recentHalfCol = !recentHalfCol;
|
||||
|
||||
checkBox.Location = new Point(nextColumn ? 10 : 130, 3 + controlRow * 29);
|
||||
controlRow += nextColumn ? 0 : 1;
|
||||
nextColumn = !nextColumn;
|
||||
Controls.Add(checkBox);
|
||||
break;
|
||||
case string:
|
||||
var stringLabel = CreateSettingLabel(setting.Value);
|
||||
var textBox = CreateStringSetting(setting.Key);
|
||||
controlRow++;
|
||||
stringLabel.Location = GetSettingPosition(controlRow);
|
||||
textBox.Location = GetSettingPosition(controlRow, true);
|
||||
|
||||
Controls.Add(stringLabel);
|
||||
Controls.Add(textBox);
|
||||
|
||||
Controls.Add(checkBox);
|
||||
break;
|
||||
case FileInfo:
|
||||
var fileLabel = CreateSettingLabel(setting.Value);
|
||||
var pathTextBox = CreateFilePathSetting(setting.Key);
|
||||
var pathButton = CreateFileBrowseSetting(setting.Key, pathTextBox);
|
||||
|
||||
controlRow++;
|
||||
|
||||
fileLabel.Location = GetSettingPosition(controlRow);
|
||||
pathTextBox.Location = GetSettingPosition(controlRow, true);
|
||||
pathButton.Location = GetSettingPosition(++controlRow, true);
|
||||
|
||||
Controls.Add(fileLabel);
|
||||
Controls.Add(pathTextBox);
|
||||
Controls.Add(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;
|
||||
controlRow++;
|
||||
if (System.Attribute.IsDefined(setting.Key, typeof(SettingNumericUseSlider)))
|
||||
{
|
||||
intControl = CreateSettingTrackbar(setting.Key);
|
||||
}
|
||||
else
|
||||
{
|
||||
intControl = CreateSettingNumericUpDown(setting.Key);
|
||||
}
|
||||
intLabel.Location = GetSettingPosition(controlRow);
|
||||
intControl.Location = GetSettingPosition(controlRow, true);
|
||||
|
||||
Controls.Add(intLabel);
|
||||
Controls.Add(intControl);
|
||||
break;
|
||||
case Action action:
|
||||
var button = CreateSettingButton(setting.Value, action);
|
||||
|
||||
controlRow += recentHalfCol ? 0 : 1;
|
||||
button.Location = GetSettingPosition(controlRow, recentHalfCol);
|
||||
recentHalfCol = !recentHalfCol;
|
||||
|
||||
Controls.Add(button);
|
||||
break;
|
||||
case Dictionary<string, object> dictSetting:
|
||||
var dictLabel = CreateSettingLabel(setting.Value);
|
||||
var dropdown = CreateSettingDropdown(setting.Key, dictSetting);
|
||||
controlRow++;
|
||||
|
||||
dictLabel.Location = GetSettingPosition(controlRow);
|
||||
dropdown.Location = GetSettingPosition(controlRow, true);
|
||||
Controls.Add(dictLabel);
|
||||
Controls.Add(dropdown);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
Height = 3 + controlRow * 29;
|
||||
}
|
||||
|
||||
private static Point GetSettingPosition(int rowNum, bool secondCol = false)
|
||||
{
|
||||
return new Point(10 + (secondCol ? 200 : 0), -26 + rowNum * 29);
|
||||
}
|
||||
|
||||
|
||||
private Label CreateSettingLabel(string settingName)
|
||||
{
|
||||
Label label = new()
|
||||
{
|
||||
Text = settingName + ": ",
|
||||
TextAlign = System.Drawing.ContentAlignment.MiddleRight,
|
||||
Width = 200,
|
||||
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 = 200,
|
||||
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;
|
||||
}
|
||||
|
||||
// Then the rest
|
||||
foreach (var setting in settings.Where(s => s.Key.PropertyType != typeof(bool)))
|
||||
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
|
||||
};
|
||||
|
||||
button.Click += (sender, e) =>
|
||||
{
|
||||
action.Invoke();
|
||||
SaveSettings();
|
||||
};
|
||||
|
||||
return button;
|
||||
}
|
||||
|
||||
private TrackBar CreateSettingTrackbar(PropertyInfo setting)
|
||||
{
|
||||
SettingNumericBounds? bounds = (SettingNumericBounds?)System.Attribute.GetCustomAttribute(setting, typeof(SettingNumericBounds));
|
||||
TrackBar trackBar = new ()
|
||||
{
|
||||
Orientation = Orientation.Horizontal,
|
||||
TickStyle = TickStyle.Both,
|
||||
Width = 200,
|
||||
Minimum = Convert.ToInt32(bounds?.Minimum ?? 0),
|
||||
Maximum = Convert.ToInt32(bounds?.Maximum ?? 100)
|
||||
};
|
||||
|
||||
trackBar.Value = (int?)setting.GetValue(_plugin.Settings) ?? 0;
|
||||
|
||||
trackBar.ValueChanged += (sender, e) =>
|
||||
{
|
||||
setting.SetValue(_plugin.Settings, trackBar.Value);
|
||||
SaveSettings();
|
||||
};
|
||||
|
||||
return trackBar;
|
||||
}
|
||||
|
||||
private NumericUpDown CreateSettingNumericUpDown(PropertyInfo setting)
|
||||
{
|
||||
SettingNumericBounds? bounds = (SettingNumericBounds?)System.Attribute.GetCustomAttribute(setting, typeof(SettingNumericBounds));
|
||||
NumericUpDown numericUpDown = new()
|
||||
{
|
||||
|
||||
}
|
||||
Width = 200,
|
||||
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, 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,
|
||||
Width = 200,
|
||||
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 = 200
|
||||
};
|
||||
|
||||
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 = 200
|
||||
};
|
||||
|
||||
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"
|
||||
};
|
||||
|
||||
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 Label CreateHeader(string pluginName)
|
||||
@ -92,5 +359,10 @@ namespace Observatory.UI
|
||||
}
|
||||
this.Parent?.ResumeLayout();
|
||||
}
|
||||
|
||||
private void SaveSettings()
|
||||
{
|
||||
PluginManagement.PluginManager.GetInstance.SaveSettings(_plugin, _plugin.Settings);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user