mirror of
https://github.com/9ParsonsB/Pulsar.git
synced 2025-04-05 17:39:39 -04:00
Winforms overhal in progress
This commit is contained in:
parent
4dba621d7c
commit
1d62a0ec1d
75
ObservatoryCore/App.config
Normal file
75
ObservatoryCore/App.config
Normal file
@ -0,0 +1,75 @@
|
||||
<?xml version="1.0" encoding="utf-8" ?>
|
||||
<configuration>
|
||||
<configSections>
|
||||
<sectionGroup name="userSettings" type="System.Configuration.UserSettingsGroup, System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" >
|
||||
<section name="Observatory.Properties.Core" type="System.Configuration.ClientSettingsSection, System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" allowExeDefinition="MachineToLocalUser" requirePermission="false" />
|
||||
</sectionGroup>
|
||||
</configSections>
|
||||
<userSettings>
|
||||
<Observatory.Properties.Core>
|
||||
<setting name="JournalFolder" serializeAs="String">
|
||||
<value />
|
||||
</setting>
|
||||
<setting name="AllowUnsigned" serializeAs="String">
|
||||
<value>False</value>
|
||||
</setting>
|
||||
<setting name="NativeNotify" serializeAs="String">
|
||||
<value>True</value>
|
||||
</setting>
|
||||
<setting name="NativeNotifyFont" serializeAs="String">
|
||||
<value />
|
||||
</setting>
|
||||
<setting name="NativeNotifyColour" serializeAs="String">
|
||||
<value>4294944000</value>
|
||||
</setting>
|
||||
<setting name="NativeNotifyCorner" serializeAs="String">
|
||||
<value>0</value>
|
||||
</setting>
|
||||
<setting name="NativeNotifyScreen" serializeAs="String">
|
||||
<value>-1</value>
|
||||
</setting>
|
||||
<setting name="TryPrimeSystemContextOnStartMonitor" serializeAs="String">
|
||||
<value>False</value>
|
||||
</setting>
|
||||
<setting name="CoreVersion" serializeAs="String">
|
||||
<value />
|
||||
</setting>
|
||||
<setting name="PluginSettings" serializeAs="String">
|
||||
<value />
|
||||
</setting>
|
||||
<setting name="VoiceNotify" serializeAs="String">
|
||||
<value>False</value>
|
||||
</setting>
|
||||
<setting name="VoiceSelected" serializeAs="String">
|
||||
<value />
|
||||
</setting>
|
||||
<setting name="VoiceVolume" serializeAs="String">
|
||||
<value>75</value>
|
||||
</setting>
|
||||
<setting name="VoiceRate" serializeAs="String">
|
||||
<value>0</value>
|
||||
</setting>
|
||||
<setting name="MainWindowSize" serializeAs="String">
|
||||
<value>800, 500</value>
|
||||
</setting>
|
||||
<setting name="MainWindowPosition" serializeAs="String">
|
||||
<value>100, 100</value>
|
||||
</setting>
|
||||
<setting name="NativeNotifyScale" serializeAs="String">
|
||||
<value>100</value>
|
||||
</setting>
|
||||
<setting name="NativeNotifyTimeout" serializeAs="String">
|
||||
<value>8000</value>
|
||||
</setting>
|
||||
<setting name="StartMonitor" serializeAs="String">
|
||||
<value>False</value>
|
||||
</setting>
|
||||
<setting name="ExportFolder" serializeAs="String">
|
||||
<value />
|
||||
</setting>
|
||||
<setting name="StartReadAll" serializeAs="String">
|
||||
<value>False</value>
|
||||
</setting>
|
||||
</Observatory.Properties.Core>
|
||||
</userSettings>
|
||||
</configuration>
|
@ -1,14 +1,11 @@
|
||||
using Observatory.Framework;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Observatory.UI.Views;
|
||||
using Observatory.UI.ViewModels;
|
||||
using Observatory.UI;
|
||||
|
||||
namespace Observatory.NativeNotification
|
||||
{
|
||||
public class NativePopup
|
||||
{
|
||||
private Dictionary<Guid, NotificationView> notifications;
|
||||
private Dictionary<Guid, NotificationForm> notifications;
|
||||
|
||||
public NativePopup()
|
||||
{
|
||||
@ -18,26 +15,21 @@ namespace Observatory.NativeNotification
|
||||
public Guid InvokeNativeNotification(NotificationArgs notificationArgs)
|
||||
{
|
||||
var notificationGuid = Guid.NewGuid();
|
||||
Avalonia.Threading.Dispatcher.UIThread.InvokeAsync(() =>
|
||||
var notification = new NotificationForm()
|
||||
{
|
||||
var notifyWindow = new NotificationView(notificationGuid) { DataContext = new NotificationViewModel(notificationArgs) };
|
||||
notifyWindow.Closed += NotifyWindow_Closed;
|
||||
|
||||
foreach (var notification in notifications)
|
||||
{
|
||||
notification.Value.AdjustOffset(true);
|
||||
}
|
||||
|
||||
notifications.Add(notificationGuid, notifyWindow);
|
||||
notifyWindow.Show();
|
||||
});
|
||||
Guid = notificationGuid
|
||||
};
|
||||
notification.Show();
|
||||
notifications.Add(notificationGuid, notification);
|
||||
|
||||
//TODO: Implement winform notification
|
||||
|
||||
return notificationGuid;
|
||||
}
|
||||
|
||||
private void NotifyWindow_Closed(object sender, EventArgs e)
|
||||
{
|
||||
var currentNotification = (NotificationView)sender;
|
||||
var currentNotification = (NotificationForm)sender;
|
||||
|
||||
if (notifications.ContainsKey(currentNotification.Guid))
|
||||
{
|
||||
@ -49,10 +41,7 @@ namespace Observatory.NativeNotification
|
||||
{
|
||||
if (notifications.ContainsKey(guid))
|
||||
{
|
||||
Avalonia.Threading.Dispatcher.UIThread.InvokeAsync(() =>
|
||||
{
|
||||
notifications[guid].Close();
|
||||
});
|
||||
notifications[guid].Close();
|
||||
}
|
||||
}
|
||||
|
||||
@ -60,10 +49,8 @@ namespace Observatory.NativeNotification
|
||||
{
|
||||
if (notifications.ContainsKey(guid))
|
||||
{
|
||||
Avalonia.Threading.Dispatcher.UIThread.InvokeAsync(() =>
|
||||
{
|
||||
notifications[guid].DataContext = new NotificationViewModel(notificationArgs);
|
||||
});
|
||||
//TODO: Update notification content
|
||||
// notifications[guid].DataContext = new NotificationViewModel(notificationArgs);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,24 +1,26 @@
|
||||
using System;
|
||||
using Avalonia;
|
||||
using Avalonia.ReactiveUI;
|
||||
using Observatory.PluginManagement;
|
||||
using System.Reflection.PortableExecutable;
|
||||
|
||||
namespace Observatory
|
||||
{
|
||||
class ObservatoryCore
|
||||
internal static class ObservatoryCore
|
||||
{
|
||||
/// <summary>
|
||||
/// The main entry point for the application.
|
||||
/// </summary>
|
||||
[STAThread]
|
||||
static void Main(string[] args)
|
||||
{
|
||||
if (args.Length > 0 && System.IO.File.Exists(args[0]))
|
||||
if (args.Length > 0 && File.Exists(args[0]))
|
||||
{
|
||||
var fileInfo = new System.IO.FileInfo(args[0]);
|
||||
var fileInfo = new FileInfo(args[0]);
|
||||
if (fileInfo.Extension == ".eop" || fileInfo.Extension == ".zip")
|
||||
System.IO.File.Copy(
|
||||
File.Copy(
|
||||
fileInfo.FullName,
|
||||
$"{AppDomain.CurrentDomain.BaseDirectory}{System.IO.Path.DirectorySeparatorChar}plugins{System.IO.Path.DirectorySeparatorChar}{fileInfo.Name}");
|
||||
$"{AppDomain.CurrentDomain.BaseDirectory}{Path.DirectorySeparatorChar}plugins{Path.DirectorySeparatorChar}{fileInfo.Name}");
|
||||
}
|
||||
|
||||
string version = System.Reflection.Assembly.GetEntryAssembly().GetName().Version.ToString();
|
||||
string version = System.Reflection.Assembly.GetEntryAssembly()?.GetName().Version?.ToString() ?? "0";
|
||||
try
|
||||
{
|
||||
if (Properties.Core.Default.CoreVersion != version)
|
||||
@ -34,7 +36,14 @@ namespace Observatory
|
||||
Properties.Core.Default.CoreVersion = version;
|
||||
Properties.Core.Default.Save();
|
||||
}
|
||||
BuildAvaloniaApp().StartWithClassicDesktopLifetime(args);
|
||||
|
||||
|
||||
|
||||
// To customize application configuration such as set high DPI settings or default font,
|
||||
// see https://aka.ms/applicationconfiguration.
|
||||
ApplicationConfiguration.Initialize();
|
||||
Application.Run(new UI.CoreForm());
|
||||
PluginManagement.PluginManager.GetInstance.Shutdown();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
@ -63,16 +72,7 @@ namespace Observatory
|
||||
.AppendLine(ex.StackTrace);
|
||||
if (ex.InnerException != null)
|
||||
errorMessage.AppendLine(FormatExceptionMessage(ex.InnerException, true));
|
||||
|
||||
return errorMessage.ToString();
|
||||
}
|
||||
|
||||
public static AppBuilder BuildAvaloniaApp()
|
||||
{
|
||||
return AppBuilder.Configure<UI.MainApplication>()
|
||||
.UsePlatformDetect()
|
||||
.LogToTrace()
|
||||
.UseReactiveUI();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -1,77 +1,68 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<OutputType>WinExe</OutputType>
|
||||
<TargetFramework>net6.0</TargetFramework>
|
||||
<PropertyGroup>
|
||||
<OutputType>WinExe</OutputType>
|
||||
<TargetFramework>net6.0-windows</TargetFramework>
|
||||
<Nullable>enable</Nullable>
|
||||
<UseWindowsForms>true</UseWindowsForms>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<RootNamespace>Observatory</RootNamespace>
|
||||
<SignAssembly>false</SignAssembly>
|
||||
<DelaySign>false</DelaySign>
|
||||
<AssemblyOriginatorKeyFile>ObservatoryKey.snk</AssemblyOriginatorKeyFile>
|
||||
<!--<PublishTrimmed>true</PublishTrimmed>-->
|
||||
<TrimMode>Link</TrimMode>
|
||||
<IncludeNativeLibrariesForSelfExtract>true</IncludeNativeLibrariesForSelfExtract>
|
||||
</PropertyGroup>
|
||||
<RootNamespace>Observatory</RootNamespace>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup>
|
||||
<VersionSuffix>0.2.$([System.DateTime]::UtcNow.Year.ToString().Substring(2))$([System.DateTime]::UtcNow.DayOfYear.ToString().PadLeft(3, "0")).$([System.DateTime]::UtcNow.ToString(HHmm))</VersionSuffix>
|
||||
<AssemblyVersion Condition=" '$(VersionSuffix)' == '' ">0.0.0.1</AssemblyVersion>
|
||||
<AssemblyVersion Condition=" '$(VersionSuffix)' != '' ">$(VersionSuffix)</AssemblyVersion>
|
||||
<Version Condition=" '$(VersionSuffix)' == '' ">0.0.1.0</Version>
|
||||
<Version Condition=" '$(VersionSuffix)' != '' ">$(VersionSuffix)</Version>
|
||||
<ApplicationIcon>Assets\EOCIcon-Presized.ico</ApplicationIcon>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Avalonia" Version="11.0.0-preview4" />
|
||||
<PackageReference Include="Avalonia.Controls.DataGrid" Version="11.0.0-preview4" />
|
||||
<PackageReference Include="Avalonia.Desktop" Version="11.0.0-preview4" />
|
||||
<PackageReference Include="Avalonia.Diagnostics" Version="11.0.0-preview4" />
|
||||
<PackageReference Include="Avalonia.ReactiveUI" Version="11.0.0-preview4" />
|
||||
<PackageReference Include="Avalonia.Themes.Fluent" Version="11.0.0-preview4" />
|
||||
<PackageReference Include="Avalonia.Themes.Simple" Version="11.0.0-preview4" />
|
||||
<PackageReference Include="Egorozh.ColorPicker.Avalonia.Dialog" Version="11.0.0-preview1" />
|
||||
<PackageReference Include="MessageBox.Avalonia" Version="2.3.1-prev2" />
|
||||
<PackageReference Include="System.Configuration.ConfigurationManager" Version="7.0.0" />
|
||||
<PackageReference Include="System.Speech" Version="7.0.0" />
|
||||
</ItemGroup>
|
||||
<PropertyGroup>
|
||||
<VersionSuffix>0.2.$([System.DateTime]::UtcNow.Year.ToString().Substring(2))$([System.DateTime]::UtcNow.DayOfYear.ToString().PadLeft(3, "0")).$([System.DateTime]::UtcNow.ToString(HHmm))</VersionSuffix>
|
||||
<AssemblyVersion Condition=" '$(VersionSuffix)' == '' ">0.0.0.1</AssemblyVersion>
|
||||
<AssemblyVersion Condition=" '$(VersionSuffix)' != '' ">$(VersionSuffix)</AssemblyVersion>
|
||||
<Version Condition=" '$(VersionSuffix)' == '' ">0.0.1.0</Version>
|
||||
<Version Condition=" '$(VersionSuffix)' != '' ">$(VersionSuffix)</Version>
|
||||
<ApplicationIcon>Assets\EOCIcon-Presized.ico</ApplicationIcon>
|
||||
<StartupObject>Observatory.ObservatoryCore</StartupObject>
|
||||
<SignAssembly>False</SignAssembly>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<AvaloniaResource Include="Assets\**" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Reference Include="ObservatoryFramework">
|
||||
<HintPath>..\ObservatoryFramework\bin\Release\net6.0\ObservatoryFramework.dll</HintPath>
|
||||
</Reference>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.Security.Extensions" Version="1.2.0" />
|
||||
<PackageReference Include="System.Speech" Version="7.0.0" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Reference Include="ObservatoryFramework">
|
||||
<HintPath>..\ObservatoryFramework\bin\Release\net6.0\ObservatoryFramework.dll</HintPath>
|
||||
</Reference>
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Compile Update="Properties\Core.Designer.cs">
|
||||
<DesignTimeSharedInput>True</DesignTimeSharedInput>
|
||||
<AutoGen>True</AutoGen>
|
||||
<DependentUpon>Core.settings</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Update="Properties\Resources.Designer.cs">
|
||||
<DesignTime>True</DesignTime>
|
||||
<AutoGen>True</AutoGen>
|
||||
<DependentUpon>Resources.resx</DependentUpon>
|
||||
</Compile>
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<EmbeddedResource Update="Properties\Resources.resx">
|
||||
<Generator>ResXFileCodeGenerator</Generator>
|
||||
<LastGenOutput>Resources.Designer.cs</LastGenOutput>
|
||||
</EmbeddedResource>
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<None Update="Properties\Core.settings">
|
||||
<Generator>SettingsSingleFileGenerator</Generator>
|
||||
<LastGenOutput>Core.Designer.cs</LastGenOutput>
|
||||
</None>
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Compile Update="Properties\Core.Designer.cs">
|
||||
<DesignTimeSharedInput>True</DesignTimeSharedInput>
|
||||
<AutoGen>True</AutoGen>
|
||||
<DependentUpon>Core.settings</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Update="UI\Views\CoreView.axaml.cs">
|
||||
<DependentUpon>CoreView.axaml</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Update="UI\Views\NotificationView.axaml.cs">
|
||||
<DependentUpon>NotificationView.axaml</DependentUpon>
|
||||
</Compile>
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<None Update="Properties\Core.settings">
|
||||
<Generator>SettingsSingleFileGenerator</Generator>
|
||||
<LastGenOutput>Core.Designer.cs</LastGenOutput>
|
||||
</None>
|
||||
</ItemGroup>
|
||||
|
||||
<Target Name="PreBuild" BeforeTargets="PreBuildEvent">
|
||||
<Exec Condition=" '$(OS)' == 'Windows_NT'" Command="if not exist "$(ProjectDir)..\ObservatoryFramework\bin\Release\net5.0\ObservatoryFramework.dll" dotnet build "$(ProjectDir)..\ObservatoryFramework\ObservatoryFramework.csproj" -c Release" />
|
||||
<Exec Condition=" '$(OS)' == 'Windows_NT'" Command="if not exist "$(OutDir)plugins\ObservatoryExplorer.dll" dotnet build "$(ProjectDir)..\ObservatoryExplorer\ObservatoryExplorer.csproj" -c $(ConfigurationName)" />
|
||||
<Exec Condition=" '$(OS)' != 'Windows_NT'" Command="[ ! -e "$(ProjectDir)../ObservatoryFramework/bin/Release/net5.0/ObservatoryFramework.dll" ] && dotnet build "$(ProjectDir)../ObservatoryFramework/ObservatoryFramework.csproj" -c Release || echo No build necessary" />
|
||||
<Exec Condition=" '$(OS)' != 'Windows_NT'" Command="[ ! -e "$(ProjectDir)$(OutDir)plugins/ObservatoryExplorer.dll" ] && dotnet build "$(ProjectDir)../ObservatoryExplorer/ObservatoryExplorer.csproj" -c $(ConfigurationName) || echo No build necessary" />
|
||||
</Target>
|
||||
|
||||
</Project>
|
||||
<Target Name="PreBuild" BeforeTargets="PreBuildEvent">
|
||||
<Exec Condition=" '$(OS)' == 'Windows_NT'" Command="if not exist "$(ProjectDir)..\ObservatoryFramework\bin\Release\net5.0\ObservatoryFramework.dll" dotnet build "$(ProjectDir)..\ObservatoryFramework\ObservatoryFramework.csproj" -c Release" />
|
||||
<Exec Condition=" '$(OS)' == 'Windows_NT'" Command="if not exist "$(OutDir)plugins\ObservatoryExplorer.dll" dotnet build "$(ProjectDir)..\ObservatoryExplorer\ObservatoryExplorer.csproj" -c $(ConfigurationName)" />
|
||||
<Exec Condition=" '$(OS)' != 'Windows_NT'" Command="[ ! -e "$(ProjectDir)../ObservatoryFramework/bin/Release/net5.0/ObservatoryFramework.dll" ] && dotnet build "$(ProjectDir)../ObservatoryFramework/ObservatoryFramework.csproj" -c Release || echo No build necessary" />
|
||||
<Exec Condition=" '$(OS)' != 'Windows_NT'" Command="[ ! -e "$(ProjectDir)$(OutDir)plugins/ObservatoryExplorer.dll" ] && dotnet build "$(ProjectDir)../ObservatoryExplorer/ObservatoryExplorer.csproj" -c $(ConfigurationName) || echo No build necessary" />
|
||||
</Target>
|
||||
|
||||
</Project>
|
@ -1,9 +1,9 @@
|
||||
|
||||
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||
# Visual Studio Version 16
|
||||
VisualStudioVersion = 16.0.30128.74
|
||||
# Visual Studio Version 17
|
||||
VisualStudioVersion = 17.3.32922.545
|
||||
MinimumVisualStudioVersion = 10.0.40219.1
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ObservatoryCore", "ObservatoryCore.csproj", "{0E1C4F16-858E-4E53-948A-77D81A8F3395}"
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ObservatoryCore", "ObservatoryCore.csproj", "{036A9A33-8C38-4A0C-BE2E-AC64B1B22090}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
@ -11,15 +11,15 @@ Global
|
||||
Release|Any CPU = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||
{0E1C4F16-858E-4E53-948A-77D81A8F3395}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{0E1C4F16-858E-4E53-948A-77D81A8F3395}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{0E1C4F16-858E-4E53-948A-77D81A8F3395}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{0E1C4F16-858E-4E53-948A-77D81A8F3395}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{036A9A33-8C38-4A0C-BE2E-AC64B1B22090}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{036A9A33-8C38-4A0C-BE2E-AC64B1B22090}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{036A9A33-8C38-4A0C-BE2E-AC64B1B22090}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{036A9A33-8C38-4A0C-BE2E-AC64B1B22090}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
EndGlobalSection
|
||||
GlobalSection(ExtensibilityGlobals) = postSolution
|
||||
SolutionGuid = {F41B8681-A5D9-4167-9938-56DE88024000}
|
||||
SolutionGuid = {53E6C705-9815-47F7-8ABF-92A7FA4E2F4B}
|
||||
EndGlobalSection
|
||||
EndGlobal
|
||||
|
@ -2,6 +2,7 @@
|
||||
using Observatory.Framework.Files;
|
||||
using Observatory.Framework.Interfaces;
|
||||
using Observatory.NativeNotification;
|
||||
using Observatory.Utils;
|
||||
using System;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.IO;
|
||||
@ -20,7 +21,7 @@ namespace Observatory.PluginManagement
|
||||
NativePopup = new();
|
||||
}
|
||||
|
||||
public string Version => System.Reflection.Assembly.GetEntryAssembly().GetName().Version.ToString();
|
||||
public string Version => System.Reflection.Assembly.GetEntryAssembly()?.GetName().Version?.ToString() ?? "0";
|
||||
|
||||
public Action<Exception, String> GetPluginErrorLogger(IObservatoryPlugin plugin)
|
||||
{
|
||||
@ -97,50 +98,29 @@ namespace Observatory.PluginManagement
|
||||
/// </summary>
|
||||
/// <param name="worker"></param>
|
||||
/// <param name="item"></param>
|
||||
public void AddGridItem(IObservatoryWorker worker, List<object> item)
|
||||
public void AddGridItem(IObservatoryWorker worker, object item)
|
||||
{
|
||||
Avalonia.Threading.Dispatcher.UIThread.InvokeAsync(() =>
|
||||
{
|
||||
ObservableCollection<object> newRow = new(item);
|
||||
worker.PluginUI.BasicGrid.Items.Add(newRow);
|
||||
|
||||
//Hacky removal of original empty object if one was used to populate columns
|
||||
if (worker.PluginUI.BasicGrid.Items.Count == 2)
|
||||
{
|
||||
bool allNull = true;
|
||||
|
||||
foreach (var cell in worker.PluginUI.BasicGrid.Items[0])
|
||||
{
|
||||
if (cell != null)
|
||||
{
|
||||
allNull = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (allNull)
|
||||
worker.PluginUI.BasicGrid.Items.RemoveAt(0);
|
||||
}
|
||||
|
||||
});
|
||||
worker.PluginUI.DataGrid.Add(item);
|
||||
}
|
||||
|
||||
public void ClearGrid(IObservatoryWorker worker)
|
||||
public void AddGridItems(IObservatoryWorker worker, IEnumerable<object> items)
|
||||
{
|
||||
Avalonia.Threading.Dispatcher.UIThread.InvokeAsync(() =>
|
||||
{
|
||||
worker.PluginUI.BasicGrid.Items.Clear();
|
||||
});
|
||||
//TODO: Add to winform list
|
||||
}
|
||||
|
||||
public void ClearGrid(IObservatoryWorker worker, object templateItem)
|
||||
{
|
||||
//TODO: Clear winform list
|
||||
}
|
||||
|
||||
public void ExecuteOnUIThread(Action action)
|
||||
{
|
||||
Avalonia.Threading.Dispatcher.UIThread.InvokeAsync(action);
|
||||
//TODO: Execute action
|
||||
}
|
||||
|
||||
public System.Net.Http.HttpClient HttpClient
|
||||
{
|
||||
get => Observatory.HttpClient.Client;
|
||||
get => Utils.HttpClient.Client;
|
||||
}
|
||||
|
||||
public LogMonitorState CurrentLogMonitorState
|
||||
@ -162,7 +142,7 @@ namespace Observatory.PluginManagement
|
||||
var context = new System.Diagnostics.StackFrame(1).GetMethod();
|
||||
|
||||
string folderLocation = Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData)
|
||||
+ $"{Path.DirectorySeparatorChar}ObservatoryCore{Path.DirectorySeparatorChar}{context.DeclaringType.Assembly.GetName().Name}{Path.DirectorySeparatorChar}";
|
||||
+ $"{Path.DirectorySeparatorChar}ObservatoryCore{Path.DirectorySeparatorChar}{context?.DeclaringType?.Assembly.GetName().Name}{Path.DirectorySeparatorChar}";
|
||||
|
||||
if (!Directory.Exists(folderLocation))
|
||||
Directory.CreateDirectory(folderLocation);
|
||||
|
@ -6,6 +6,7 @@ using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Observatory.Framework.Files.Journal;
|
||||
using System.Timers;
|
||||
using Observatory.Utils;
|
||||
|
||||
namespace Observatory.PluginManagement
|
||||
{
|
||||
|
@ -1,5 +1,4 @@
|
||||
using Avalonia.Controls;
|
||||
using System;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
@ -8,6 +7,8 @@ using Observatory.Framework.Interfaces;
|
||||
using System.IO;
|
||||
using Observatory.Framework;
|
||||
using System.Text.Json;
|
||||
using Observatory.Utils;
|
||||
using Microsoft.Security.Extensions;
|
||||
|
||||
namespace Observatory.PluginManagement
|
||||
{
|
||||
@ -191,54 +192,95 @@ namespace Observatory.PluginManagement
|
||||
|
||||
string pluginPath = $"{AppDomain.CurrentDomain.BaseDirectory}{Path.DirectorySeparatorChar}plugins";
|
||||
|
||||
string ownExe = System.Reflection.Assembly.GetExecutingAssembly().Location;
|
||||
FileSignatureInfo ownSig;
|
||||
|
||||
using (var stream = File.OpenRead(ownExe))
|
||||
ownSig = FileSignatureInfo.GetFromFileStream(stream);
|
||||
|
||||
|
||||
if (Directory.Exists(pluginPath))
|
||||
{
|
||||
ExtractPlugins(pluginPath);
|
||||
|
||||
//Temporarily skipping signature checks. Need to do this the right way later.
|
||||
var pluginLibraries = Directory.GetFiles($"{AppDomain.CurrentDomain.BaseDirectory}{Path.DirectorySeparatorChar}plugins", "*.dll");
|
||||
//var coreToken = Assembly.GetExecutingAssembly().GetName().GetPublicKeyToken();
|
||||
foreach (var dll in pluginLibraries)
|
||||
{
|
||||
try
|
||||
{
|
||||
//var pluginToken = AssemblyName.GetAssemblyName(dll).GetPublicKeyToken();
|
||||
//PluginStatus signed;
|
||||
PluginStatus pluginStatus = PluginStatus.SigCheckDisabled;
|
||||
bool loadOkay = true;
|
||||
|
||||
//if (pluginToken.Length == 0)
|
||||
//{
|
||||
// errorList.Add($"Warning: {dll} not signed.");
|
||||
// signed = PluginStatus.Unsigned;
|
||||
//}
|
||||
//else if (!coreToken.SequenceEqual(pluginToken))
|
||||
//{
|
||||
// errorList.Add($"Warning: {dll} signature does not match.");
|
||||
// signed = PluginStatus.InvalidSignature;
|
||||
//}
|
||||
//else
|
||||
//{
|
||||
// errorList.Add($"OK: {dll} signed.");
|
||||
// signed = PluginStatus.Signed;
|
||||
//}
|
||||
if (!Properties.Core.Default.AllowUnsigned)
|
||||
{
|
||||
if (ownSig.Kind == SignatureKind.Embedded)
|
||||
{
|
||||
FileSignatureInfo pluginSig;
|
||||
using (var stream = File.OpenRead(dll))
|
||||
pluginSig = FileSignatureInfo.GetFromFileStream(stream);
|
||||
|
||||
//if (signed == PluginStatus.Signed || Properties.Core.Default.AllowUnsigned)
|
||||
//{
|
||||
string error = LoadPluginAssembly(dll, observatoryWorkers, observatoryNotifiers);
|
||||
if (pluginSig.Kind == SignatureKind.Embedded)
|
||||
{
|
||||
if (pluginSig.SigningCertificate.Thumbprint == ownSig.SigningCertificate.Thumbprint)
|
||||
{
|
||||
pluginStatus = PluginStatus.Signed;
|
||||
}
|
||||
else
|
||||
{
|
||||
pluginStatus = PluginStatus.InvalidSignature;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
pluginStatus = PluginStatus.Unsigned;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
pluginStatus = PluginStatus.NoCert;
|
||||
}
|
||||
|
||||
if (pluginStatus != PluginStatus.Signed && pluginStatus != PluginStatus.NoCert)
|
||||
{
|
||||
string pluginHash = ComputeSha512Hash(dll);
|
||||
|
||||
if (Properties.Core.Default.UnsignedAllowed == null)
|
||||
Properties.Core.Default.UnsignedAllowed = new();
|
||||
|
||||
if (!Properties.Core.Default.UnsignedAllowed.Contains(pluginHash))
|
||||
{
|
||||
string warning;
|
||||
warning = $"Unable to confirm signature of plugin library {dll}.\r\n\r\n";
|
||||
warning += "Please ensure that you trust the source of this plugin before loading it.\r\n\r\n";
|
||||
warning += "Do you wish to continue loading the plugin? If you load this plugin you will not be asked again for this file.";
|
||||
|
||||
var response = MessageBox.Show(warning, "Plugin Signature Warning", MessageBoxButtons.OKCancel, MessageBoxIcon.Warning);
|
||||
|
||||
if (response == DialogResult.OK)
|
||||
{
|
||||
Properties.Core.Default.UnsignedAllowed.Add(pluginHash);
|
||||
Properties.Core.Default.Save();
|
||||
}
|
||||
else
|
||||
{
|
||||
loadOkay = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (loadOkay)
|
||||
{
|
||||
string error = LoadPluginAssembly(dll, observatoryWorkers, observatoryNotifiers, pluginStatus);
|
||||
if (!string.IsNullOrWhiteSpace(error))
|
||||
{
|
||||
errorList.Add((error, string.Empty));
|
||||
}
|
||||
//}
|
||||
//else
|
||||
//{
|
||||
// LoadPlaceholderPlugin(dll, signed, observatoryNotifiers);
|
||||
//}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
errorList.Add(($"ERROR: {new FileInfo(dll).Name}, {ex.Message}", ex.StackTrace));
|
||||
errorList.Add(($"ERROR: {new FileInfo(dll).Name}, {ex.Message}", ex.StackTrace ?? String.Empty));
|
||||
LoadPlaceholderPlugin(dll, PluginStatus.InvalidLibrary, observatoryNotifiers);
|
||||
}
|
||||
}
|
||||
@ -246,6 +288,15 @@ namespace Observatory.PluginManagement
|
||||
return errorList;
|
||||
}
|
||||
|
||||
private static string ComputeSha512Hash(string filePath)
|
||||
{
|
||||
using (var SHA512 = System.Security.Cryptography.SHA512.Create())
|
||||
{
|
||||
using (FileStream fileStream = File.OpenRead(filePath))
|
||||
return BitConverter.ToString(SHA512.ComputeHash(fileStream)).Replace("-", "").ToLowerInvariant();
|
||||
}
|
||||
}
|
||||
|
||||
private static void ExtractPlugins(string pluginFolder)
|
||||
{
|
||||
var files = Directory.GetFiles(pluginFolder, "*.zip")
|
||||
@ -265,9 +316,8 @@ namespace Observatory.PluginManagement
|
||||
}
|
||||
}
|
||||
|
||||
private static string LoadPluginAssembly(string dllPath, List<(IObservatoryWorker plugin, PluginStatus signed)> workers, List<(IObservatoryNotifier plugin, PluginStatus signed)> notifiers)
|
||||
private static string LoadPluginAssembly(string dllPath, List<(IObservatoryWorker plugin, PluginStatus signed)> workers, List<(IObservatoryNotifier plugin, PluginStatus signed)> notifiers, PluginStatus pluginStatus)
|
||||
{
|
||||
|
||||
string recursionGuard = string.Empty;
|
||||
|
||||
System.Runtime.Loader.AssemblyLoadContext.Default.Resolving += (context, name) => {
|
||||
@ -293,14 +343,12 @@ namespace Observatory.PluginManagement
|
||||
if (name.Name != recursionGuard)
|
||||
{
|
||||
recursionGuard = name.Name;
|
||||
|
||||
return context.LoadFromAssemblyName(name);
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new Exception("Unable to load assembly " + name.Name);
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
var pluginAssembly = System.Runtime.Loader.AssemblyLoadContext.Default.LoadFromAssemblyPath(new FileInfo(dllPath).FullName);
|
||||
@ -325,12 +373,12 @@ namespace Observatory.PluginManagement
|
||||
{
|
||||
ConstructorInfo constructor = worker.GetConstructor(Array.Empty<Type>());
|
||||
object instance = constructor.Invoke(Array.Empty<object>());
|
||||
workers.Add((instance as IObservatoryWorker, PluginStatus.Signed));
|
||||
workers.Add((instance as IObservatoryWorker, pluginStatus));
|
||||
if (instance is IObservatoryNotifier)
|
||||
{
|
||||
// This is also a notifier; add to the notifier list as well, so the work and notifier are
|
||||
// the same instance and can share state.
|
||||
notifiers.Add((instance as IObservatoryNotifier, PluginStatus.Signed));
|
||||
notifiers.Add((instance as IObservatoryNotifier, pluginStatus));
|
||||
}
|
||||
pluginCount++;
|
||||
}
|
||||
@ -366,13 +414,39 @@ namespace Observatory.PluginManagement
|
||||
notifiers.Add((placeholder, pluginStatus));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Possible plugin load results and signature statuses.
|
||||
/// </summary>
|
||||
public enum PluginStatus
|
||||
{
|
||||
/// <summary>
|
||||
/// Plugin valid and signed with matching certificate.
|
||||
/// </summary>
|
||||
Signed,
|
||||
/// <summary>
|
||||
/// Plugin valid but not signed with any certificate.
|
||||
/// </summary>
|
||||
Unsigned,
|
||||
/// <summary>
|
||||
/// Plugin valid but not signed with valid certificate.
|
||||
/// </summary>
|
||||
InvalidSignature,
|
||||
/// <summary>
|
||||
/// Plugin invalid and cannot be loaded. Possible version mismatch.
|
||||
/// </summary>
|
||||
InvalidPlugin,
|
||||
InvalidLibrary
|
||||
/// <summary>
|
||||
/// Plugin not a CLR library.
|
||||
/// </summary>
|
||||
InvalidLibrary,
|
||||
/// <summary>
|
||||
/// Plugin valid but executing assembly has no certificate to match against.
|
||||
/// </summary>
|
||||
NoCert,
|
||||
/// <summary>
|
||||
/// Plugin signature checks disabled.
|
||||
/// </summary>
|
||||
SigCheckDisabled
|
||||
}
|
||||
}
|
||||
}
|
||||
|
9
ObservatoryCore/Properties/Core.Designer.cs
generated
9
ObservatoryCore/Properties/Core.Designer.cs
generated
@ -12,7 +12,7 @@ namespace Observatory.Properties {
|
||||
|
||||
|
||||
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
|
||||
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "17.2.0.0")]
|
||||
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "17.3.0.0")]
|
||||
internal sealed partial class Core : global::System.Configuration.ApplicationSettingsBase {
|
||||
|
||||
private static Core defaultInstance = ((Core)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Core())));
|
||||
@ -277,13 +277,12 @@ namespace Observatory.Properties {
|
||||
|
||||
[global::System.Configuration.UserScopedSettingAttribute()]
|
||||
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
|
||||
[global::System.Configuration.DefaultSettingValueAttribute("Fixed width")]
|
||||
public string ExportStyle {
|
||||
public global::System.Collections.Specialized.StringCollection UnsignedAllowed {
|
||||
get {
|
||||
return ((string)(this["ExportStyle"]));
|
||||
return ((global::System.Collections.Specialized.StringCollection)(this["UnsignedAllowed"]));
|
||||
}
|
||||
set {
|
||||
this["ExportStyle"] = value;
|
||||
this["UnsignedAllowed"] = value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -65,8 +65,8 @@
|
||||
<Setting Name="StartReadAll" Type="System.Boolean" Scope="User">
|
||||
<Value Profile="(Default)">False</Value>
|
||||
</Setting>
|
||||
<Setting Name="ExportStyle" Type="System.String" Scope="User">
|
||||
<Value Profile="(Default)">Fixed width</Value>
|
||||
<Setting Name="UnsignedAllowed" Type="System.Collections.Specialized.StringCollection" Scope="User">
|
||||
<Value Profile="(Default)" />
|
||||
</Setting>
|
||||
</Settings>
|
||||
</SettingsFile>
|
63
ObservatoryCore/Properties/Resources.Designer.cs
generated
Normal file
63
ObservatoryCore/Properties/Resources.Designer.cs
generated
Normal file
@ -0,0 +1,63 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// <auto-generated>
|
||||
// This code was generated by a tool.
|
||||
// Runtime Version:4.0.30319.42000
|
||||
//
|
||||
// Changes to this file may cause incorrect behavior and will be lost if
|
||||
// the code is regenerated.
|
||||
// </auto-generated>
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
namespace Observatory.Properties {
|
||||
using System;
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// A strongly-typed resource class, for looking up localized strings, etc.
|
||||
/// </summary>
|
||||
// This class was auto-generated by the StronglyTypedResourceBuilder
|
||||
// class via a tool like ResGen or Visual Studio.
|
||||
// To add or remove a member, edit your .ResX file then rerun ResGen
|
||||
// with the /str option, or rebuild your VS project.
|
||||
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "17.0.0.0")]
|
||||
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
|
||||
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
|
||||
internal class Resources {
|
||||
|
||||
private static global::System.Resources.ResourceManager resourceMan;
|
||||
|
||||
private static global::System.Globalization.CultureInfo resourceCulture;
|
||||
|
||||
[global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
|
||||
internal Resources() {
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the cached ResourceManager instance used by this class.
|
||||
/// </summary>
|
||||
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
|
||||
internal static global::System.Resources.ResourceManager ResourceManager {
|
||||
get {
|
||||
if (object.ReferenceEquals(resourceMan, null)) {
|
||||
global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("Observatory.Properties.Resources", typeof(Resources).Assembly);
|
||||
resourceMan = temp;
|
||||
}
|
||||
return resourceMan;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Overrides the current thread's CurrentUICulture property for all
|
||||
/// resource lookups using this strongly typed resource class.
|
||||
/// </summary>
|
||||
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
|
||||
internal static global::System.Globalization.CultureInfo Culture {
|
||||
get {
|
||||
return resourceCulture;
|
||||
}
|
||||
set {
|
||||
resourceCulture = value;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
120
ObservatoryCore/Properties/Resources.resx
Normal file
120
ObservatoryCore/Properties/Resources.resx
Normal file
@ -0,0 +1,120 @@
|
||||
<?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.
|
||||
-->
|
||||
<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">
|
||||
<xsd:complexType>
|
||||
<xsd:choice maxOccurs="unbounded">
|
||||
<xsd:element name="metadata">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" use="required" type="xsd:string" />
|
||||
<xsd:attribute name="type" type="xsd:string" />
|
||||
<xsd:attribute name="mimetype" type="xsd:string" />
|
||||
<xsd:attribute ref="xml:space" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="assembly">
|
||||
<xsd:complexType>
|
||||
<xsd:attribute name="alias" type="xsd:string" />
|
||||
<xsd:attribute name="name" type="xsd:string" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="data">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
|
||||
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
|
||||
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
|
||||
<xsd:attribute ref="xml:space" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="resheader">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" use="required" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
</xsd:choice>
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
</xsd:schema>
|
||||
<resheader name="resmimetype">
|
||||
<value>text/microsoft-resx</value>
|
||||
</resheader>
|
||||
<resheader name="version">
|
||||
<value>2.0</value>
|
||||
</resheader>
|
||||
<resheader name="reader">
|
||||
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
<resheader name="writer">
|
||||
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
</root>
|
705
ObservatoryCore/UI/CoreForm.Designer.cs
generated
Normal file
705
ObservatoryCore/UI/CoreForm.Designer.cs
generated
Normal file
@ -0,0 +1,705 @@
|
||||
namespace Observatory.UI
|
||||
{
|
||||
partial class CoreForm
|
||||
{
|
||||
/// <summary>
|
||||
/// Required designer variable.
|
||||
/// </summary>
|
||||
private System.ComponentModel.IContainer components = null;
|
||||
|
||||
/// <summary>
|
||||
/// Clean up any resources being used.
|
||||
/// </summary>
|
||||
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
|
||||
protected override void Dispose(bool disposing)
|
||||
{
|
||||
if (disposing && (components != null))
|
||||
{
|
||||
components.Dispose();
|
||||
}
|
||||
base.Dispose(disposing);
|
||||
}
|
||||
|
||||
#region Windows Form Designer generated code
|
||||
|
||||
/// <summary>
|
||||
/// Required method for Designer support - do not modify
|
||||
/// the contents of this method with the code editor.
|
||||
/// </summary>
|
||||
private void InitializeComponent()
|
||||
{
|
||||
System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(CoreForm));
|
||||
this.CoreMenu = new System.Windows.Forms.MenuStrip();
|
||||
this.coreToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
|
||||
this.toolStripMenuItem1 = new System.Windows.Forms.ToolStripMenuItem();
|
||||
this.CorePanel = new System.Windows.Forms.Panel();
|
||||
this.VoiceSettingsPanel = new System.Windows.Forms.Panel();
|
||||
this.VoiceSpeedSlider = new System.Windows.Forms.TrackBar();
|
||||
this.VoiceVolumeSlider = new System.Windows.Forms.TrackBar();
|
||||
this.VoiceTestButton = new System.Windows.Forms.Button();
|
||||
this.VoiceCheckbox = new System.Windows.Forms.CheckBox();
|
||||
this.VoiceDropdown = new System.Windows.Forms.ComboBox();
|
||||
this.VoiceLabel = new System.Windows.Forms.Label();
|
||||
this.VoiceSpeedLabel = new System.Windows.Forms.Label();
|
||||
this.VoiceVolumeLabel = new System.Windows.Forms.Label();
|
||||
this.VoiceNotificationLabel = new System.Windows.Forms.Label();
|
||||
this.PopupSettingsPanel = new System.Windows.Forms.Panel();
|
||||
this.DurationSpinner = new System.Windows.Forms.NumericUpDown();
|
||||
this.ScaleSpinner = new System.Windows.Forms.NumericUpDown();
|
||||
this.LabelColour = new System.Windows.Forms.Label();
|
||||
this.TestButton = new System.Windows.Forms.Button();
|
||||
this.ColourButton = new System.Windows.Forms.Button();
|
||||
this.PopupCheckbox = new System.Windows.Forms.CheckBox();
|
||||
this.LabelDuration = new System.Windows.Forms.Label();
|
||||
this.LabelScale = new System.Windows.Forms.Label();
|
||||
this.FontDropdown = new System.Windows.Forms.ComboBox();
|
||||
this.LabelFont = new System.Windows.Forms.Label();
|
||||
this.CornerDropdown = new System.Windows.Forms.ComboBox();
|
||||
this.DisplayDropdown = new System.Windows.Forms.ComboBox();
|
||||
this.CornerLabel = new System.Windows.Forms.Label();
|
||||
this.DisplayLabel = new System.Windows.Forms.Label();
|
||||
this.PopupNotificationLabel = new System.Windows.Forms.Label();
|
||||
this.PluginFolderButton = new System.Windows.Forms.Button();
|
||||
this.PluginList = new System.Windows.Forms.ListView();
|
||||
this.NameColumn = new System.Windows.Forms.ColumnHeader();
|
||||
this.TypeColumn = new System.Windows.Forms.ColumnHeader();
|
||||
this.VersionColumn = new System.Windows.Forms.ColumnHeader();
|
||||
this.StatusColumn = new System.Windows.Forms.ColumnHeader();
|
||||
this.ReadAllButton = new System.Windows.Forms.Button();
|
||||
this.ToggleMonitorButton = new System.Windows.Forms.Button();
|
||||
this.ClearButton = new System.Windows.Forms.Button();
|
||||
this.ExportButton = new System.Windows.Forms.Button();
|
||||
this.GithubLink = new System.Windows.Forms.LinkLabel();
|
||||
this.DonateLink = new System.Windows.Forms.LinkLabel();
|
||||
this.PopupColour = new System.Windows.Forms.ColorDialog();
|
||||
this.CoreMenu.SuspendLayout();
|
||||
this.CorePanel.SuspendLayout();
|
||||
this.VoiceSettingsPanel.SuspendLayout();
|
||||
((System.ComponentModel.ISupportInitialize)(this.VoiceSpeedSlider)).BeginInit();
|
||||
((System.ComponentModel.ISupportInitialize)(this.VoiceVolumeSlider)).BeginInit();
|
||||
this.PopupSettingsPanel.SuspendLayout();
|
||||
((System.ComponentModel.ISupportInitialize)(this.DurationSpinner)).BeginInit();
|
||||
((System.ComponentModel.ISupportInitialize)(this.ScaleSpinner)).BeginInit();
|
||||
this.SuspendLayout();
|
||||
//
|
||||
// CoreMenu
|
||||
//
|
||||
this.CoreMenu.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom)
|
||||
| System.Windows.Forms.AnchorStyles.Left)));
|
||||
this.CoreMenu.AutoSize = false;
|
||||
this.CoreMenu.BackColor = System.Drawing.Color.Black;
|
||||
this.CoreMenu.Dock = System.Windows.Forms.DockStyle.None;
|
||||
this.CoreMenu.Items.AddRange(new System.Windows.Forms.ToolStripItem[] {
|
||||
this.coreToolStripMenuItem,
|
||||
this.toolStripMenuItem1});
|
||||
this.CoreMenu.LayoutStyle = System.Windows.Forms.ToolStripLayoutStyle.VerticalStackWithOverflow;
|
||||
this.CoreMenu.Location = new System.Drawing.Point(0, 0);
|
||||
this.CoreMenu.Name = "CoreMenu";
|
||||
this.CoreMenu.Size = new System.Drawing.Size(120, 691);
|
||||
this.CoreMenu.TabIndex = 0;
|
||||
//
|
||||
// coreToolStripMenuItem
|
||||
//
|
||||
this.coreToolStripMenuItem.Font = new System.Drawing.Font("Segoe UI", 18F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point);
|
||||
this.coreToolStripMenuItem.ForeColor = System.Drawing.Color.FromArgb(((int)(((byte)(224)))), ((int)(((byte)(224)))), ((int)(((byte)(224)))));
|
||||
this.coreToolStripMenuItem.Name = "coreToolStripMenuItem";
|
||||
this.coreToolStripMenuItem.Size = new System.Drawing.Size(113, 36);
|
||||
this.coreToolStripMenuItem.Text = "Core";
|
||||
this.coreToolStripMenuItem.TextAlign = System.Drawing.ContentAlignment.MiddleLeft;
|
||||
//
|
||||
// toolStripMenuItem1
|
||||
//
|
||||
this.toolStripMenuItem1.Alignment = System.Windows.Forms.ToolStripItemAlignment.Right;
|
||||
this.toolStripMenuItem1.Font = new System.Drawing.Font("Segoe UI", 18F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point);
|
||||
this.toolStripMenuItem1.ForeColor = System.Drawing.Color.Gainsboro;
|
||||
this.toolStripMenuItem1.Name = "toolStripMenuItem1";
|
||||
this.toolStripMenuItem1.Size = new System.Drawing.Size(113, 36);
|
||||
this.toolStripMenuItem1.Text = "<";
|
||||
this.toolStripMenuItem1.TextAlign = System.Drawing.ContentAlignment.MiddleLeft;
|
||||
//
|
||||
// CorePanel
|
||||
//
|
||||
this.CorePanel.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom)
|
||||
| System.Windows.Forms.AnchorStyles.Left)
|
||||
| System.Windows.Forms.AnchorStyles.Right)));
|
||||
this.CorePanel.AutoScroll = true;
|
||||
this.CorePanel.Controls.Add(this.VoiceSettingsPanel);
|
||||
this.CorePanel.Controls.Add(this.VoiceNotificationLabel);
|
||||
this.CorePanel.Controls.Add(this.PopupSettingsPanel);
|
||||
this.CorePanel.Controls.Add(this.PopupNotificationLabel);
|
||||
this.CorePanel.Controls.Add(this.PluginFolderButton);
|
||||
this.CorePanel.Controls.Add(this.PluginList);
|
||||
this.CorePanel.Location = new System.Drawing.Point(123, 12);
|
||||
this.CorePanel.Name = "CorePanel";
|
||||
this.CorePanel.Size = new System.Drawing.Size(665, 679);
|
||||
this.CorePanel.TabIndex = 1;
|
||||
//
|
||||
// VoiceSettingsPanel
|
||||
//
|
||||
this.VoiceSettingsPanel.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left)
|
||||
| System.Windows.Forms.AnchorStyles.Right)));
|
||||
this.VoiceSettingsPanel.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(64)))), ((int)(((byte)(64)))), ((int)(((byte)(64)))));
|
||||
this.VoiceSettingsPanel.Controls.Add(this.VoiceSpeedSlider);
|
||||
this.VoiceSettingsPanel.Controls.Add(this.VoiceVolumeSlider);
|
||||
this.VoiceSettingsPanel.Controls.Add(this.VoiceTestButton);
|
||||
this.VoiceSettingsPanel.Controls.Add(this.VoiceCheckbox);
|
||||
this.VoiceSettingsPanel.Controls.Add(this.VoiceDropdown);
|
||||
this.VoiceSettingsPanel.Controls.Add(this.VoiceLabel);
|
||||
this.VoiceSettingsPanel.Controls.Add(this.VoiceSpeedLabel);
|
||||
this.VoiceSettingsPanel.Controls.Add(this.VoiceVolumeLabel);
|
||||
this.VoiceSettingsPanel.Location = new System.Drawing.Point(3, 426);
|
||||
this.VoiceSettingsPanel.Name = "VoiceSettingsPanel";
|
||||
this.VoiceSettingsPanel.Size = new System.Drawing.Size(659, 177);
|
||||
this.VoiceSettingsPanel.TabIndex = 5;
|
||||
this.VoiceSettingsPanel.Visible = false;
|
||||
//
|
||||
// VoiceSpeedSlider
|
||||
//
|
||||
this.VoiceSpeedSlider.Location = new System.Drawing.Point(121, 51);
|
||||
this.VoiceSpeedSlider.Maximum = 100;
|
||||
this.VoiceSpeedSlider.Name = "VoiceSpeedSlider";
|
||||
this.VoiceSpeedSlider.Size = new System.Drawing.Size(120, 45);
|
||||
this.VoiceSpeedSlider.TabIndex = 15;
|
||||
this.VoiceSpeedSlider.TickFrequency = 10;
|
||||
this.VoiceSpeedSlider.TickStyle = System.Windows.Forms.TickStyle.Both;
|
||||
this.VoiceSpeedSlider.Value = 50;
|
||||
this.VoiceSpeedSlider.Scroll += new System.EventHandler(this.VoiceSpeedSlider_Scroll);
|
||||
//
|
||||
// VoiceVolumeSlider
|
||||
//
|
||||
this.VoiceVolumeSlider.LargeChange = 10;
|
||||
this.VoiceVolumeSlider.Location = new System.Drawing.Point(120, 0);
|
||||
this.VoiceVolumeSlider.Maximum = 100;
|
||||
this.VoiceVolumeSlider.Name = "VoiceVolumeSlider";
|
||||
this.VoiceVolumeSlider.Size = new System.Drawing.Size(121, 45);
|
||||
this.VoiceVolumeSlider.TabIndex = 14;
|
||||
this.VoiceVolumeSlider.TickFrequency = 10;
|
||||
this.VoiceVolumeSlider.TickStyle = System.Windows.Forms.TickStyle.Both;
|
||||
this.VoiceVolumeSlider.Value = 100;
|
||||
this.VoiceVolumeSlider.Scroll += new System.EventHandler(this.VoiceVolumeSlider_Scroll);
|
||||
//
|
||||
// VoiceTestButton
|
||||
//
|
||||
this.VoiceTestButton.BackColor = System.Drawing.Color.DimGray;
|
||||
this.VoiceTestButton.FlatStyle = System.Windows.Forms.FlatStyle.Flat;
|
||||
this.VoiceTestButton.ForeColor = System.Drawing.Color.WhiteSmoke;
|
||||
this.VoiceTestButton.Location = new System.Drawing.Point(190, 131);
|
||||
this.VoiceTestButton.Name = "VoiceTestButton";
|
||||
this.VoiceTestButton.Size = new System.Drawing.Size(51, 23);
|
||||
this.VoiceTestButton.TabIndex = 13;
|
||||
this.VoiceTestButton.Text = "Test";
|
||||
this.VoiceTestButton.UseVisualStyleBackColor = false;
|
||||
//
|
||||
// VoiceCheckbox
|
||||
//
|
||||
this.VoiceCheckbox.AutoSize = true;
|
||||
this.VoiceCheckbox.ForeColor = System.Drawing.Color.Gainsboro;
|
||||
this.VoiceCheckbox.Location = new System.Drawing.Point(120, 134);
|
||||
this.VoiceCheckbox.Name = "VoiceCheckbox";
|
||||
this.VoiceCheckbox.Size = new System.Drawing.Size(68, 19);
|
||||
this.VoiceCheckbox.TabIndex = 11;
|
||||
this.VoiceCheckbox.Text = "Enabled";
|
||||
this.VoiceCheckbox.UseVisualStyleBackColor = true;
|
||||
this.VoiceCheckbox.CheckedChanged += new System.EventHandler(this.VoiceCheckbox_CheckedChanged);
|
||||
//
|
||||
// VoiceDropdown
|
||||
//
|
||||
this.VoiceDropdown.FormattingEnabled = true;
|
||||
this.VoiceDropdown.Location = new System.Drawing.Point(121, 102);
|
||||
this.VoiceDropdown.Name = "VoiceDropdown";
|
||||
this.VoiceDropdown.Size = new System.Drawing.Size(121, 23);
|
||||
this.VoiceDropdown.TabIndex = 5;
|
||||
this.VoiceDropdown.SelectedIndexChanged += new System.EventHandler(this.VoiceDropdown_SelectedIndexChanged);
|
||||
//
|
||||
// VoiceLabel
|
||||
//
|
||||
this.VoiceLabel.AutoSize = true;
|
||||
this.VoiceLabel.ForeColor = System.Drawing.Color.Gainsboro;
|
||||
this.VoiceLabel.Location = new System.Drawing.Point(77, 105);
|
||||
this.VoiceLabel.Name = "VoiceLabel";
|
||||
this.VoiceLabel.Size = new System.Drawing.Size(38, 15);
|
||||
this.VoiceLabel.TabIndex = 4;
|
||||
this.VoiceLabel.Text = "Voice:";
|
||||
this.VoiceLabel.TextAlign = System.Drawing.ContentAlignment.MiddleRight;
|
||||
//
|
||||
// VoiceSpeedLabel
|
||||
//
|
||||
this.VoiceSpeedLabel.AutoSize = true;
|
||||
this.VoiceSpeedLabel.ForeColor = System.Drawing.Color.Gainsboro;
|
||||
this.VoiceSpeedLabel.Location = new System.Drawing.Point(73, 63);
|
||||
this.VoiceSpeedLabel.Name = "VoiceSpeedLabel";
|
||||
this.VoiceSpeedLabel.Size = new System.Drawing.Size(42, 15);
|
||||
this.VoiceSpeedLabel.TabIndex = 1;
|
||||
this.VoiceSpeedLabel.Text = "Speed:";
|
||||
this.VoiceSpeedLabel.TextAlign = System.Drawing.ContentAlignment.MiddleRight;
|
||||
//
|
||||
// VoiceVolumeLabel
|
||||
//
|
||||
this.VoiceVolumeLabel.AutoSize = true;
|
||||
this.VoiceVolumeLabel.ForeColor = System.Drawing.Color.Gainsboro;
|
||||
this.VoiceVolumeLabel.Location = new System.Drawing.Point(64, 12);
|
||||
this.VoiceVolumeLabel.Name = "VoiceVolumeLabel";
|
||||
this.VoiceVolumeLabel.Size = new System.Drawing.Size(50, 15);
|
||||
this.VoiceVolumeLabel.TabIndex = 0;
|
||||
this.VoiceVolumeLabel.Text = "Volume:";
|
||||
this.VoiceVolumeLabel.TextAlign = System.Drawing.ContentAlignment.MiddleRight;
|
||||
//
|
||||
// VoiceNotificationLabel
|
||||
//
|
||||
this.VoiceNotificationLabel.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left)
|
||||
| System.Windows.Forms.AnchorStyles.Right)));
|
||||
this.VoiceNotificationLabel.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle;
|
||||
this.VoiceNotificationLabel.ForeColor = System.Drawing.Color.LightGray;
|
||||
this.VoiceNotificationLabel.Location = new System.Drawing.Point(3, 403);
|
||||
this.VoiceNotificationLabel.Name = "VoiceNotificationLabel";
|
||||
this.VoiceNotificationLabel.Size = new System.Drawing.Size(659, 23);
|
||||
this.VoiceNotificationLabel.TabIndex = 4;
|
||||
this.VoiceNotificationLabel.Text = "❯ Voice Notifications";
|
||||
this.VoiceNotificationLabel.TextAlign = System.Drawing.ContentAlignment.MiddleLeft;
|
||||
this.VoiceNotificationLabel.Click += new System.EventHandler(this.VoiceNotificationLabel_Click);
|
||||
//
|
||||
// PopupSettingsPanel
|
||||
//
|
||||
this.PopupSettingsPanel.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left)
|
||||
| System.Windows.Forms.AnchorStyles.Right)));
|
||||
this.PopupSettingsPanel.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(64)))), ((int)(((byte)(64)))), ((int)(((byte)(64)))));
|
||||
this.PopupSettingsPanel.Controls.Add(this.DurationSpinner);
|
||||
this.PopupSettingsPanel.Controls.Add(this.ScaleSpinner);
|
||||
this.PopupSettingsPanel.Controls.Add(this.LabelColour);
|
||||
this.PopupSettingsPanel.Controls.Add(this.TestButton);
|
||||
this.PopupSettingsPanel.Controls.Add(this.ColourButton);
|
||||
this.PopupSettingsPanel.Controls.Add(this.PopupCheckbox);
|
||||
this.PopupSettingsPanel.Controls.Add(this.LabelDuration);
|
||||
this.PopupSettingsPanel.Controls.Add(this.LabelScale);
|
||||
this.PopupSettingsPanel.Controls.Add(this.FontDropdown);
|
||||
this.PopupSettingsPanel.Controls.Add(this.LabelFont);
|
||||
this.PopupSettingsPanel.Controls.Add(this.CornerDropdown);
|
||||
this.PopupSettingsPanel.Controls.Add(this.DisplayDropdown);
|
||||
this.PopupSettingsPanel.Controls.Add(this.CornerLabel);
|
||||
this.PopupSettingsPanel.Controls.Add(this.DisplayLabel);
|
||||
this.PopupSettingsPanel.Location = new System.Drawing.Point(3, 195);
|
||||
this.PopupSettingsPanel.Name = "PopupSettingsPanel";
|
||||
this.PopupSettingsPanel.Size = new System.Drawing.Size(659, 208);
|
||||
this.PopupSettingsPanel.TabIndex = 3;
|
||||
this.PopupSettingsPanel.Visible = false;
|
||||
//
|
||||
// DurationSpinner
|
||||
//
|
||||
this.DurationSpinner.BackColor = System.Drawing.Color.DimGray;
|
||||
this.DurationSpinner.ForeColor = System.Drawing.Color.Gainsboro;
|
||||
this.DurationSpinner.Increment = new decimal(new int[] {
|
||||
25,
|
||||
0,
|
||||
0,
|
||||
0});
|
||||
this.DurationSpinner.Location = new System.Drawing.Point(121, 119);
|
||||
this.DurationSpinner.Maximum = new decimal(new int[] {
|
||||
60000,
|
||||
0,
|
||||
0,
|
||||
0});
|
||||
this.DurationSpinner.Minimum = new decimal(new int[] {
|
||||
100,
|
||||
0,
|
||||
0,
|
||||
0});
|
||||
this.DurationSpinner.Name = "DurationSpinner";
|
||||
this.DurationSpinner.Size = new System.Drawing.Size(120, 23);
|
||||
this.DurationSpinner.TabIndex = 15;
|
||||
this.DurationSpinner.Value = new decimal(new int[] {
|
||||
8000,
|
||||
0,
|
||||
0,
|
||||
0});
|
||||
this.DurationSpinner.ValueChanged += new System.EventHandler(this.DurationSpinner_ValueChanged);
|
||||
//
|
||||
// ScaleSpinner
|
||||
//
|
||||
this.ScaleSpinner.BackColor = System.Drawing.Color.DimGray;
|
||||
this.ScaleSpinner.ForeColor = System.Drawing.Color.Gainsboro;
|
||||
this.ScaleSpinner.Location = new System.Drawing.Point(121, 90);
|
||||
this.ScaleSpinner.Maximum = new decimal(new int[] {
|
||||
500,
|
||||
0,
|
||||
0,
|
||||
0});
|
||||
this.ScaleSpinner.Minimum = new decimal(new int[] {
|
||||
1,
|
||||
0,
|
||||
0,
|
||||
0});
|
||||
this.ScaleSpinner.Name = "ScaleSpinner";
|
||||
this.ScaleSpinner.Size = new System.Drawing.Size(120, 23);
|
||||
this.ScaleSpinner.TabIndex = 14;
|
||||
this.ScaleSpinner.Value = new decimal(new int[] {
|
||||
100,
|
||||
0,
|
||||
0,
|
||||
0});
|
||||
this.ScaleSpinner.ValueChanged += new System.EventHandler(this.ScaleSpinner_ValueChanged);
|
||||
//
|
||||
// LabelColour
|
||||
//
|
||||
this.LabelColour.AutoSize = true;
|
||||
this.LabelColour.ForeColor = System.Drawing.Color.Gainsboro;
|
||||
this.LabelColour.Location = new System.Drawing.Point(68, 152);
|
||||
this.LabelColour.Name = "LabelColour";
|
||||
this.LabelColour.Size = new System.Drawing.Size(46, 15);
|
||||
this.LabelColour.TabIndex = 13;
|
||||
this.LabelColour.Text = "Colour:";
|
||||
this.LabelColour.TextAlign = System.Drawing.ContentAlignment.MiddleRight;
|
||||
//
|
||||
// TestButton
|
||||
//
|
||||
this.TestButton.BackColor = System.Drawing.Color.DimGray;
|
||||
this.TestButton.FlatStyle = System.Windows.Forms.FlatStyle.Flat;
|
||||
this.TestButton.ForeColor = System.Drawing.Color.WhiteSmoke;
|
||||
this.TestButton.Location = new System.Drawing.Point(190, 148);
|
||||
this.TestButton.Name = "TestButton";
|
||||
this.TestButton.Size = new System.Drawing.Size(51, 23);
|
||||
this.TestButton.TabIndex = 12;
|
||||
this.TestButton.Text = "Test";
|
||||
this.TestButton.UseVisualStyleBackColor = false;
|
||||
//
|
||||
// ColourButton
|
||||
//
|
||||
this.ColourButton.FlatStyle = System.Windows.Forms.FlatStyle.Flat;
|
||||
this.ColourButton.Location = new System.Drawing.Point(121, 148);
|
||||
this.ColourButton.Name = "ColourButton";
|
||||
this.ColourButton.Size = new System.Drawing.Size(51, 23);
|
||||
this.ColourButton.TabIndex = 11;
|
||||
this.ColourButton.UseVisualStyleBackColor = true;
|
||||
this.ColourButton.Click += new System.EventHandler(this.ColourButton_Click);
|
||||
//
|
||||
// PopupCheckbox
|
||||
//
|
||||
this.PopupCheckbox.AutoSize = true;
|
||||
this.PopupCheckbox.ForeColor = System.Drawing.Color.Gainsboro;
|
||||
this.PopupCheckbox.Location = new System.Drawing.Point(120, 177);
|
||||
this.PopupCheckbox.Name = "PopupCheckbox";
|
||||
this.PopupCheckbox.Size = new System.Drawing.Size(68, 19);
|
||||
this.PopupCheckbox.TabIndex = 10;
|
||||
this.PopupCheckbox.Text = "Enabled";
|
||||
this.PopupCheckbox.UseVisualStyleBackColor = true;
|
||||
this.PopupCheckbox.CheckedChanged += new System.EventHandler(this.PopupCheckbox_CheckedChanged);
|
||||
//
|
||||
// LabelDuration
|
||||
//
|
||||
this.LabelDuration.AutoSize = true;
|
||||
this.LabelDuration.ForeColor = System.Drawing.Color.Gainsboro;
|
||||
this.LabelDuration.Location = new System.Drawing.Point(32, 121);
|
||||
this.LabelDuration.Name = "LabelDuration";
|
||||
this.LabelDuration.Size = new System.Drawing.Size(83, 15);
|
||||
this.LabelDuration.TabIndex = 9;
|
||||
this.LabelDuration.Text = "Duration (ms):";
|
||||
this.LabelDuration.TextAlign = System.Drawing.ContentAlignment.MiddleRight;
|
||||
//
|
||||
// LabelScale
|
||||
//
|
||||
this.LabelScale.AutoSize = true;
|
||||
this.LabelScale.ForeColor = System.Drawing.Color.Gainsboro;
|
||||
this.LabelScale.Location = new System.Drawing.Point(57, 92);
|
||||
this.LabelScale.Name = "LabelScale";
|
||||
this.LabelScale.Size = new System.Drawing.Size(58, 15);
|
||||
this.LabelScale.TabIndex = 7;
|
||||
this.LabelScale.Text = "Scale (%):";
|
||||
this.LabelScale.TextAlign = System.Drawing.ContentAlignment.MiddleRight;
|
||||
//
|
||||
// FontDropdown
|
||||
//
|
||||
this.FontDropdown.FormattingEnabled = true;
|
||||
this.FontDropdown.Location = new System.Drawing.Point(120, 61);
|
||||
this.FontDropdown.Name = "FontDropdown";
|
||||
this.FontDropdown.Size = new System.Drawing.Size(121, 23);
|
||||
this.FontDropdown.TabIndex = 5;
|
||||
this.FontDropdown.SelectedIndexChanged += new System.EventHandler(this.FontDropdown_SelectedIndexChanged);
|
||||
//
|
||||
// LabelFont
|
||||
//
|
||||
this.LabelFont.AutoSize = true;
|
||||
this.LabelFont.ForeColor = System.Drawing.Color.Gainsboro;
|
||||
this.LabelFont.Location = new System.Drawing.Point(80, 64);
|
||||
this.LabelFont.Name = "LabelFont";
|
||||
this.LabelFont.Size = new System.Drawing.Size(34, 15);
|
||||
this.LabelFont.TabIndex = 4;
|
||||
this.LabelFont.Text = "Font:";
|
||||
this.LabelFont.TextAlign = System.Drawing.ContentAlignment.MiddleRight;
|
||||
//
|
||||
// CornerDropdown
|
||||
//
|
||||
this.CornerDropdown.FormattingEnabled = true;
|
||||
this.CornerDropdown.Items.AddRange(new object[] {
|
||||
"Bottom-Right",
|
||||
"Bottom-Left",
|
||||
"Top-Right",
|
||||
"Top-Left"});
|
||||
this.CornerDropdown.Location = new System.Drawing.Point(120, 32);
|
||||
this.CornerDropdown.Name = "CornerDropdown";
|
||||
this.CornerDropdown.Size = new System.Drawing.Size(121, 23);
|
||||
this.CornerDropdown.TabIndex = 3;
|
||||
this.CornerDropdown.SelectedIndexChanged += new System.EventHandler(this.CornerDropdown_SelectedIndexChanged);
|
||||
//
|
||||
// DisplayDropdown
|
||||
//
|
||||
this.DisplayDropdown.FormattingEnabled = true;
|
||||
this.DisplayDropdown.Location = new System.Drawing.Point(120, 3);
|
||||
this.DisplayDropdown.Name = "DisplayDropdown";
|
||||
this.DisplayDropdown.Size = new System.Drawing.Size(121, 23);
|
||||
this.DisplayDropdown.TabIndex = 2;
|
||||
this.DisplayDropdown.SelectedIndexChanged += new System.EventHandler(this.DisplayDropdown_SelectedIndexChanged);
|
||||
//
|
||||
// CornerLabel
|
||||
//
|
||||
this.CornerLabel.AutoSize = true;
|
||||
this.CornerLabel.ForeColor = System.Drawing.Color.Gainsboro;
|
||||
this.CornerLabel.Location = new System.Drawing.Point(68, 35);
|
||||
this.CornerLabel.Name = "CornerLabel";
|
||||
this.CornerLabel.Size = new System.Drawing.Size(46, 15);
|
||||
this.CornerLabel.TabIndex = 1;
|
||||
this.CornerLabel.Text = "Corner:";
|
||||
this.CornerLabel.TextAlign = System.Drawing.ContentAlignment.MiddleRight;
|
||||
//
|
||||
// DisplayLabel
|
||||
//
|
||||
this.DisplayLabel.AutoSize = true;
|
||||
this.DisplayLabel.ForeColor = System.Drawing.Color.Gainsboro;
|
||||
this.DisplayLabel.Location = new System.Drawing.Point(66, 6);
|
||||
this.DisplayLabel.Name = "DisplayLabel";
|
||||
this.DisplayLabel.Size = new System.Drawing.Size(48, 15);
|
||||
this.DisplayLabel.TabIndex = 0;
|
||||
this.DisplayLabel.Text = "Display:";
|
||||
this.DisplayLabel.TextAlign = System.Drawing.ContentAlignment.MiddleRight;
|
||||
//
|
||||
// PopupNotificationLabel
|
||||
//
|
||||
this.PopupNotificationLabel.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left)
|
||||
| System.Windows.Forms.AnchorStyles.Right)));
|
||||
this.PopupNotificationLabel.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle;
|
||||
this.PopupNotificationLabel.ForeColor = System.Drawing.Color.LightGray;
|
||||
this.PopupNotificationLabel.Location = new System.Drawing.Point(3, 172);
|
||||
this.PopupNotificationLabel.Name = "PopupNotificationLabel";
|
||||
this.PopupNotificationLabel.Size = new System.Drawing.Size(659, 23);
|
||||
this.PopupNotificationLabel.TabIndex = 2;
|
||||
this.PopupNotificationLabel.Text = "❯ Popup Notifications";
|
||||
this.PopupNotificationLabel.TextAlign = System.Drawing.ContentAlignment.MiddleLeft;
|
||||
this.PopupNotificationLabel.Click += new System.EventHandler(this.PopupNotificationLabel_Click);
|
||||
//
|
||||
// PluginFolderButton
|
||||
//
|
||||
this.PluginFolderButton.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right)));
|
||||
this.PluginFolderButton.BackColor = System.Drawing.Color.DimGray;
|
||||
this.PluginFolderButton.FlatAppearance.BorderSize = 0;
|
||||
this.PluginFolderButton.FlatStyle = System.Windows.Forms.FlatStyle.Flat;
|
||||
this.PluginFolderButton.ForeColor = System.Drawing.Color.FromArgb(((int)(((byte)(224)))), ((int)(((byte)(224)))), ((int)(((byte)(224)))));
|
||||
this.PluginFolderButton.Location = new System.Drawing.Point(532, 140);
|
||||
this.PluginFolderButton.Name = "PluginFolderButton";
|
||||
this.PluginFolderButton.Size = new System.Drawing.Size(130, 23);
|
||||
this.PluginFolderButton.TabIndex = 1;
|
||||
this.PluginFolderButton.Text = "Open Plugin Folder";
|
||||
this.PluginFolderButton.UseVisualStyleBackColor = false;
|
||||
//
|
||||
// PluginList
|
||||
//
|
||||
this.PluginList.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left)
|
||||
| System.Windows.Forms.AnchorStyles.Right)));
|
||||
this.PluginList.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(64)))), ((int)(((byte)(64)))), ((int)(((byte)(64)))));
|
||||
this.PluginList.BorderStyle = System.Windows.Forms.BorderStyle.None;
|
||||
this.PluginList.Columns.AddRange(new System.Windows.Forms.ColumnHeader[] {
|
||||
this.NameColumn,
|
||||
this.TypeColumn,
|
||||
this.VersionColumn,
|
||||
this.StatusColumn});
|
||||
this.PluginList.ForeColor = System.Drawing.Color.FromArgb(((int)(((byte)(224)))), ((int)(((byte)(224)))), ((int)(((byte)(224)))));
|
||||
this.PluginList.HeaderStyle = System.Windows.Forms.ColumnHeaderStyle.Nonclickable;
|
||||
this.PluginList.Location = new System.Drawing.Point(3, 3);
|
||||
this.PluginList.MultiSelect = false;
|
||||
this.PluginList.Name = "PluginList";
|
||||
this.PluginList.OwnerDraw = true;
|
||||
this.PluginList.Scrollable = false;
|
||||
this.PluginList.Size = new System.Drawing.Size(659, 137);
|
||||
this.PluginList.TabIndex = 0;
|
||||
this.PluginList.UseCompatibleStateImageBehavior = false;
|
||||
this.PluginList.View = System.Windows.Forms.View.Details;
|
||||
this.PluginList.Resize += new System.EventHandler(this.PluginList_Resize);
|
||||
//
|
||||
// NameColumn
|
||||
//
|
||||
this.NameColumn.Text = "Plugin";
|
||||
this.NameColumn.Width = 180;
|
||||
//
|
||||
// TypeColumn
|
||||
//
|
||||
this.TypeColumn.Text = "Type";
|
||||
this.TypeColumn.Width = 120;
|
||||
//
|
||||
// VersionColumn
|
||||
//
|
||||
this.VersionColumn.Text = "Version";
|
||||
this.VersionColumn.Width = 120;
|
||||
//
|
||||
// StatusColumn
|
||||
//
|
||||
this.StatusColumn.Text = "Status";
|
||||
//
|
||||
// ReadAllButton
|
||||
//
|
||||
this.ReadAllButton.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right)));
|
||||
this.ReadAllButton.BackColor = System.Drawing.Color.DimGray;
|
||||
this.ReadAllButton.FlatAppearance.BorderSize = 0;
|
||||
this.ReadAllButton.FlatStyle = System.Windows.Forms.FlatStyle.Flat;
|
||||
this.ReadAllButton.ForeColor = System.Drawing.Color.FromArgb(((int)(((byte)(224)))), ((int)(((byte)(224)))), ((int)(((byte)(224)))));
|
||||
this.ReadAllButton.Location = new System.Drawing.Point(713, 698);
|
||||
this.ReadAllButton.Name = "ReadAllButton";
|
||||
this.ReadAllButton.Size = new System.Drawing.Size(75, 23);
|
||||
this.ReadAllButton.TabIndex = 2;
|
||||
this.ReadAllButton.Text = "Read All";
|
||||
this.ReadAllButton.UseVisualStyleBackColor = false;
|
||||
this.ReadAllButton.Click += new System.EventHandler(this.ReadAllButton_Click);
|
||||
//
|
||||
// ToggleMonitorButton
|
||||
//
|
||||
this.ToggleMonitorButton.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right)));
|
||||
this.ToggleMonitorButton.BackColor = System.Drawing.Color.DimGray;
|
||||
this.ToggleMonitorButton.FlatAppearance.BorderSize = 0;
|
||||
this.ToggleMonitorButton.FlatStyle = System.Windows.Forms.FlatStyle.Flat;
|
||||
this.ToggleMonitorButton.ForeColor = System.Drawing.Color.FromArgb(((int)(((byte)(224)))), ((int)(((byte)(224)))), ((int)(((byte)(224)))));
|
||||
this.ToggleMonitorButton.Location = new System.Drawing.Point(610, 698);
|
||||
this.ToggleMonitorButton.Name = "ToggleMonitorButton";
|
||||
this.ToggleMonitorButton.Size = new System.Drawing.Size(97, 23);
|
||||
this.ToggleMonitorButton.TabIndex = 3;
|
||||
this.ToggleMonitorButton.Text = "Start Monitor";
|
||||
this.ToggleMonitorButton.UseVisualStyleBackColor = false;
|
||||
//
|
||||
// ClearButton
|
||||
//
|
||||
this.ClearButton.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right)));
|
||||
this.ClearButton.BackColor = System.Drawing.Color.DimGray;
|
||||
this.ClearButton.FlatAppearance.BorderSize = 0;
|
||||
this.ClearButton.FlatStyle = System.Windows.Forms.FlatStyle.Flat;
|
||||
this.ClearButton.ForeColor = System.Drawing.Color.FromArgb(((int)(((byte)(224)))), ((int)(((byte)(224)))), ((int)(((byte)(224)))));
|
||||
this.ClearButton.Location = new System.Drawing.Point(529, 698);
|
||||
this.ClearButton.Name = "ClearButton";
|
||||
this.ClearButton.Size = new System.Drawing.Size(75, 23);
|
||||
this.ClearButton.TabIndex = 4;
|
||||
this.ClearButton.Text = "Clear";
|
||||
this.ClearButton.UseVisualStyleBackColor = false;
|
||||
//
|
||||
// ExportButton
|
||||
//
|
||||
this.ExportButton.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right)));
|
||||
this.ExportButton.BackColor = System.Drawing.Color.DimGray;
|
||||
this.ExportButton.FlatAppearance.BorderSize = 0;
|
||||
this.ExportButton.FlatStyle = System.Windows.Forms.FlatStyle.Flat;
|
||||
this.ExportButton.ForeColor = System.Drawing.Color.FromArgb(((int)(((byte)(224)))), ((int)(((byte)(224)))), ((int)(((byte)(224)))));
|
||||
this.ExportButton.Location = new System.Drawing.Point(448, 698);
|
||||
this.ExportButton.Name = "ExportButton";
|
||||
this.ExportButton.Size = new System.Drawing.Size(75, 23);
|
||||
this.ExportButton.TabIndex = 5;
|
||||
this.ExportButton.Text = "Export";
|
||||
this.ExportButton.UseVisualStyleBackColor = false;
|
||||
//
|
||||
// GithubLink
|
||||
//
|
||||
this.GithubLink.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left)));
|
||||
this.GithubLink.AutoSize = true;
|
||||
this.GithubLink.LinkColor = System.Drawing.Color.White;
|
||||
this.GithubLink.Location = new System.Drawing.Point(12, 694);
|
||||
this.GithubLink.Name = "GithubLink";
|
||||
this.GithubLink.Size = new System.Drawing.Size(42, 15);
|
||||
this.GithubLink.TabIndex = 6;
|
||||
this.GithubLink.TabStop = true;
|
||||
this.GithubLink.Text = "github";
|
||||
//
|
||||
// DonateLink
|
||||
//
|
||||
this.DonateLink.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left)));
|
||||
this.DonateLink.AutoSize = true;
|
||||
this.DonateLink.LinkColor = System.Drawing.Color.White;
|
||||
this.DonateLink.Location = new System.Drawing.Point(12, 709);
|
||||
this.DonateLink.Name = "DonateLink";
|
||||
this.DonateLink.Size = new System.Drawing.Size(45, 15);
|
||||
this.DonateLink.TabIndex = 7;
|
||||
this.DonateLink.TabStop = true;
|
||||
this.DonateLink.Text = "Donate";
|
||||
//
|
||||
// CoreForm
|
||||
//
|
||||
this.AutoScaleDimensions = new System.Drawing.SizeF(7F, 15F);
|
||||
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
|
||||
this.BackColor = System.Drawing.Color.Black;
|
||||
this.ClientSize = new System.Drawing.Size(800, 733);
|
||||
this.Controls.Add(this.DonateLink);
|
||||
this.Controls.Add(this.GithubLink);
|
||||
this.Controls.Add(this.ExportButton);
|
||||
this.Controls.Add(this.ClearButton);
|
||||
this.Controls.Add(this.ToggleMonitorButton);
|
||||
this.Controls.Add(this.ReadAllButton);
|
||||
this.Controls.Add(this.CorePanel);
|
||||
this.Controls.Add(this.CoreMenu);
|
||||
this.Icon = ((System.Drawing.Icon)(resources.GetObject("$this.Icon")));
|
||||
this.MainMenuStrip = this.CoreMenu;
|
||||
this.Name = "CoreForm";
|
||||
this.Text = "Elite Observatory Core";
|
||||
this.CoreMenu.ResumeLayout(false);
|
||||
this.CoreMenu.PerformLayout();
|
||||
this.CorePanel.ResumeLayout(false);
|
||||
this.VoiceSettingsPanel.ResumeLayout(false);
|
||||
this.VoiceSettingsPanel.PerformLayout();
|
||||
((System.ComponentModel.ISupportInitialize)(this.VoiceSpeedSlider)).EndInit();
|
||||
((System.ComponentModel.ISupportInitialize)(this.VoiceVolumeSlider)).EndInit();
|
||||
this.PopupSettingsPanel.ResumeLayout(false);
|
||||
this.PopupSettingsPanel.PerformLayout();
|
||||
((System.ComponentModel.ISupportInitialize)(this.DurationSpinner)).EndInit();
|
||||
((System.ComponentModel.ISupportInitialize)(this.ScaleSpinner)).EndInit();
|
||||
this.ResumeLayout(false);
|
||||
this.PerformLayout();
|
||||
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
private MenuStrip CoreMenu;
|
||||
private ToolStripMenuItem coreToolStripMenuItem;
|
||||
private Panel CorePanel;
|
||||
private Button ReadAllButton;
|
||||
private Button ToggleMonitorButton;
|
||||
private Button ClearButton;
|
||||
private Button ExportButton;
|
||||
private LinkLabel GithubLink;
|
||||
private LinkLabel DonateLink;
|
||||
private ListView PluginList;
|
||||
private ColumnHeader NameColumn;
|
||||
private ColumnHeader TypeColumn;
|
||||
private ColumnHeader VersionColumn;
|
||||
private ColumnHeader StatusColumn;
|
||||
private Button PluginFolderButton;
|
||||
private Panel PopupSettingsPanel;
|
||||
private ComboBox CornerDropdown;
|
||||
private ComboBox DisplayDropdown;
|
||||
private Label CornerLabel;
|
||||
private Label DisplayLabel;
|
||||
private Label PopupNotificationLabel;
|
||||
private NumericUpDown DurationSpinner;
|
||||
private NumericUpDown ScaleSpinner;
|
||||
private Label LabelColour;
|
||||
private Button TestButton;
|
||||
private Button ColourButton;
|
||||
private CheckBox PopupCheckbox;
|
||||
private Label LabelDuration;
|
||||
private Label LabelScale;
|
||||
private ComboBox FontDropdown;
|
||||
private Label LabelFont;
|
||||
private ColorDialog PopupColour;
|
||||
private ToolStripMenuItem toolStripMenuItem1;
|
||||
private Panel VoiceSettingsPanel;
|
||||
private TrackBar VoiceSpeedSlider;
|
||||
private TrackBar VoiceVolumeSlider;
|
||||
private Button VoiceTestButton;
|
||||
private CheckBox VoiceCheckbox;
|
||||
private ComboBox VoiceDropdown;
|
||||
private Label VoiceLabel;
|
||||
private Label VoiceSpeedLabel;
|
||||
private Label VoiceVolumeLabel;
|
||||
private Label VoiceNotificationLabel;
|
||||
}
|
||||
}
|
418
ObservatoryCore/UI/CoreForm.cs
Normal file
418
ObservatoryCore/UI/CoreForm.cs
Normal file
@ -0,0 +1,418 @@
|
||||
using Observatory.Framework.Interfaces;
|
||||
using Observatory.PluginManagement;
|
||||
using Observatory.Utils;
|
||||
|
||||
namespace Observatory.UI
|
||||
{
|
||||
public partial class CoreForm : Form
|
||||
{
|
||||
private Dictionary<object, Panel> uiPanels;
|
||||
|
||||
public CoreForm()
|
||||
{
|
||||
InitializeComponent();
|
||||
|
||||
PopulateDropdownOptions();
|
||||
PopulateNativeSettings();
|
||||
|
||||
ColourListHeader(ref PluginList, Color.DarkSlateGray, Color.LightGray);
|
||||
PopulatePluginList();
|
||||
FitColumns();
|
||||
string version = System.Reflection.Assembly.GetEntryAssembly()?.GetName().Version?.ToString() ?? "0";
|
||||
Text += $" - v{version}";
|
||||
CoreMenu.SizeChanged += CoreMenu_SizeChanged;
|
||||
uiPanels = new();
|
||||
uiPanels.Add(coreToolStripMenuItem, CorePanel);
|
||||
pluginList = new Dictionary<string, ToolStripMenuItem>();
|
||||
CreatePluginTabs();
|
||||
CreatePluginSettings();
|
||||
CoreMenu.ItemClicked += CoreMenu_ItemClicked;
|
||||
|
||||
PreCollapsePanels();
|
||||
}
|
||||
|
||||
private void PreCollapsePanels()
|
||||
{
|
||||
AdjustPanelsBelow(VoiceSettingsPanel, AdjustmentDirection.Up);
|
||||
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);
|
||||
CorePanel.Width = Width - CoreMenu.Width - 40;
|
||||
|
||||
}
|
||||
|
||||
private Dictionary<string, ToolStripMenuItem> pluginList;
|
||||
|
||||
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;
|
||||
}
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
private void CoreMenu_ItemClicked(object? _, ToolStripItemClickedEventArgs e)
|
||||
{
|
||||
|
||||
if (e.ClickedItem.Text == "<")
|
||||
{
|
||||
foreach (KeyValuePair<string, ToolStripMenuItem> menuItem in pluginList)
|
||||
{
|
||||
if (menuItem.Value.Text == "<")
|
||||
menuItem.Value.Text = ">";
|
||||
else
|
||||
menuItem.Value.Text = menuItem.Key[..1];
|
||||
}
|
||||
CoreMenu.Width = 40;
|
||||
CorePanel.Location = new Point(43, 12);
|
||||
// CorePanel.Width += 40;
|
||||
}
|
||||
else if (e.ClickedItem.Text == ">")
|
||||
{
|
||||
foreach (KeyValuePair<string, ToolStripMenuItem> menuItem in pluginList)
|
||||
{
|
||||
if (menuItem.Value.Text == ">")
|
||||
menuItem.Value.Text = "<";
|
||||
else
|
||||
menuItem.Value.Text = menuItem.Key;
|
||||
}
|
||||
CoreMenu.Width = 120;
|
||||
CorePanel.Location = new Point(123, 12);
|
||||
// CorePanel.Width -= 40;
|
||||
}
|
||||
else
|
||||
{
|
||||
foreach (var panel in uiPanels.Where(p => p.Key != e.ClickedItem))
|
||||
{
|
||||
panel.Value.Visible = false;
|
||||
}
|
||||
|
||||
if (!Controls.Contains(uiPanels[e.ClickedItem]))
|
||||
{
|
||||
uiPanels[e.ClickedItem].Location = CorePanel.Location;
|
||||
uiPanels[e.ClickedItem].Size = CorePanel.Size;
|
||||
uiPanels[e.ClickedItem].BackColor = CorePanel.BackColor;
|
||||
Controls.Add(uiPanels[e.ClickedItem]);
|
||||
}
|
||||
uiPanels[e.ClickedItem].Visible = true;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private static void ColourListHeader(ref ListView list, Color backColor, Color foreColor)
|
||||
{
|
||||
list.OwnerDraw = true;
|
||||
|
||||
list.DrawColumnHeader +=
|
||||
new DrawListViewColumnHeaderEventHandler
|
||||
(
|
||||
(sender, e) => headerDraw(sender, e, backColor, foreColor)
|
||||
);
|
||||
list.DrawItem += new DrawListViewItemEventHandler(bodyDraw);
|
||||
}
|
||||
|
||||
private static void headerDraw(object? _, DrawListViewColumnHeaderEventArgs e, Color backColor, Color foreColor)
|
||||
{
|
||||
using (SolidBrush backBrush = new(backColor))
|
||||
{
|
||||
e.Graphics.FillRectangle(backBrush, e.Bounds);
|
||||
}
|
||||
|
||||
using (Pen borderBrush = new(Color.Black))
|
||||
{
|
||||
e.Graphics.DrawLine(borderBrush, e.Bounds.Left, e.Bounds.Top, e.Bounds.Left, e.Bounds.Bottom);
|
||||
e.Graphics.DrawLine(borderBrush, e.Bounds.Right, e.Bounds.Top, e.Bounds.Right, e.Bounds.Bottom);
|
||||
}
|
||||
|
||||
if (e.Font != null && e.Header != null)
|
||||
using (SolidBrush foreBrush = new(foreColor))
|
||||
{
|
||||
var format = new StringFormat();
|
||||
format.Alignment = (StringAlignment)e.Header.TextAlign;
|
||||
format.LineAlignment = StringAlignment.Center;
|
||||
|
||||
var paddedBounds = new Rectangle(e.Bounds.X + 2, e.Bounds.Y + 2, e.Bounds.Width - 4, e.Bounds.Height - 4);
|
||||
|
||||
e.Graphics.DrawString(e.Header?.Text, e.Font, foreBrush, paddedBounds, format);
|
||||
}
|
||||
}
|
||||
|
||||
private static void bodyDraw(object? _, DrawListViewItemEventArgs e)
|
||||
{
|
||||
e.DrawDefault = true;
|
||||
}
|
||||
|
||||
private void PluginList_Resize(object sender, EventArgs e)
|
||||
{
|
||||
FitColumns();
|
||||
}
|
||||
|
||||
private void FitColumns()
|
||||
{
|
||||
int totalWidth = 0;
|
||||
foreach (ColumnHeader col in PluginList.Columns)
|
||||
totalWidth += col.Width;
|
||||
|
||||
PluginList.Columns[3].Width += PluginList.Width - totalWidth;
|
||||
}
|
||||
|
||||
private void ReadAllButton_Click(object sender, EventArgs e)
|
||||
{
|
||||
LogMonitor.GetInstance.ReadAllJournals();
|
||||
}
|
||||
|
||||
private void PopupNotificationLabel_Click(object _, EventArgs e)
|
||||
{
|
||||
CorePanel.SuspendLayout();
|
||||
if (PopupNotificationLabel.Text[0] == '❯')
|
||||
{
|
||||
PopupNotificationLabel.Text = PopupNotificationLabel.Text.Replace('❯', '⌵');
|
||||
PopupSettingsPanel.Visible = true;
|
||||
AdjustPanelsBelow(PopupSettingsPanel, AdjustmentDirection.Down);
|
||||
}
|
||||
else
|
||||
{
|
||||
PopupNotificationLabel.Text = PopupNotificationLabel.Text.Replace('⌵', '❯');
|
||||
PopupSettingsPanel.Visible = false;
|
||||
AdjustPanelsBelow(PopupSettingsPanel, AdjustmentDirection.Up);
|
||||
}
|
||||
CorePanel.ResumeLayout();
|
||||
}
|
||||
|
||||
private void VoiceNotificationLabel_Click(object sender, EventArgs e)
|
||||
{
|
||||
CorePanel.SuspendLayout();
|
||||
if (VoiceNotificationLabel.Text[0] == '❯')
|
||||
{
|
||||
VoiceNotificationLabel.Text = VoiceNotificationLabel.Text.Replace('❯', '⌵');
|
||||
VoiceSettingsPanel.Visible = true;
|
||||
AdjustPanelsBelow(VoiceSettingsPanel, AdjustmentDirection.Down);
|
||||
}
|
||||
else
|
||||
{
|
||||
VoiceNotificationLabel.Text = VoiceNotificationLabel.Text.Replace('⌵', '❯');
|
||||
VoiceSettingsPanel.Visible = false;
|
||||
AdjustPanelsBelow(VoiceSettingsPanel, AdjustmentDirection.Up);
|
||||
}
|
||||
CorePanel.ResumeLayout();
|
||||
}
|
||||
|
||||
private void AdjustPanelsBelow(Control toggledControl, AdjustmentDirection adjustmentDirection)
|
||||
{
|
||||
var distance = adjustmentDirection == AdjustmentDirection.Down ? toggledControl.Height : -toggledControl.Height;
|
||||
foreach (Control control in CorePanel.Controls)
|
||||
{
|
||||
var loc = control.Location;
|
||||
if (loc.Y >= toggledControl.Location.Y && control != toggledControl)
|
||||
{
|
||||
loc.Y = control.Location.Y + distance;
|
||||
control.Location = loc;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
internal enum AdjustmentDirection
|
||||
{
|
||||
Up, Down
|
||||
}
|
||||
|
||||
#region Settings Changes
|
||||
|
||||
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();
|
||||
Properties.Core.Default.Save();
|
||||
}
|
||||
}
|
||||
|
||||
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
|
||||
|
||||
|
||||
}
|
||||
}
|
3662
ObservatoryCore/UI/CoreForm.resx
Normal file
3662
ObservatoryCore/UI/CoreForm.resx
Normal file
File diff suppressed because it is too large
Load Diff
103
ObservatoryCore/UI/DefaultSorter.cs
Normal file
103
ObservatoryCore/UI/DefaultSorter.cs
Normal file
@ -0,0 +1,103 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Observatory.UI
|
||||
{
|
||||
internal class DefaultSorter : IComparer
|
||||
{
|
||||
/// <summary>
|
||||
/// Specifies the column to be sorted
|
||||
/// </summary>
|
||||
private int ColumnToSort;
|
||||
/// <summary>
|
||||
/// Specifies the order in which to sort (i.e. 'Ascending').
|
||||
/// </summary>
|
||||
private SortOrder OrderOfSort;
|
||||
/// <summary>
|
||||
/// Case insensitive comparer object
|
||||
/// </summary>
|
||||
private CaseInsensitiveComparer ObjectCompare;
|
||||
|
||||
/// <summary>
|
||||
/// Class constructor. Initializes various elements
|
||||
/// </summary>
|
||||
public DefaultSorter()
|
||||
{
|
||||
// Initialize the column to '0'
|
||||
ColumnToSort = 0;
|
||||
|
||||
// Initialize the sort order to 'none'
|
||||
OrderOfSort = SortOrder.None;
|
||||
|
||||
// Initialize the CaseInsensitiveComparer object
|
||||
ObjectCompare = new CaseInsensitiveComparer();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// This method is inherited from the IComparer interface. It compares the two objects passed using a case insensitive comparison.
|
||||
/// </summary>
|
||||
/// <param name="x">First object to be compared</param>
|
||||
/// <param name="y">Second object to be compared</param>
|
||||
/// <returns>The result of the comparison. "0" if equal, negative if 'x' is less than 'y' and positive if 'x' is greater than 'y'</returns>
|
||||
public int Compare(object? x, object? y)
|
||||
{
|
||||
int compareResult;
|
||||
|
||||
ListViewItem? listviewX = (ListViewItem?)x;
|
||||
ListViewItem? listviewY = (ListViewItem?)y;
|
||||
|
||||
// Compare the two items
|
||||
compareResult = ObjectCompare.Compare(listviewX?.SubItems[ColumnToSort].Text, listviewY?.SubItems[ColumnToSort].Text);
|
||||
|
||||
// Calculate correct return value based on object comparison
|
||||
if (OrderOfSort == SortOrder.Ascending)
|
||||
{
|
||||
// Ascending sort is selected, return normal result of compare operation
|
||||
return compareResult;
|
||||
}
|
||||
else if (OrderOfSort == SortOrder.Descending)
|
||||
{
|
||||
// Descending sort is selected, return negative result of compare operation
|
||||
return (-compareResult);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Return '0' to indicate they are equal
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the number of the column to which to apply the sorting operation (Defaults to '0').
|
||||
/// </summary>
|
||||
public int SortColumn
|
||||
{
|
||||
set
|
||||
{
|
||||
ColumnToSort = value;
|
||||
}
|
||||
get
|
||||
{
|
||||
return ColumnToSort;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the order of sorting to apply (for example, 'Ascending' or 'Descending').
|
||||
/// </summary>
|
||||
public SortOrder Order
|
||||
{
|
||||
set
|
||||
{
|
||||
OrderOfSort = value;
|
||||
}
|
||||
get
|
||||
{
|
||||
return OrderOfSort;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -1,15 +0,0 @@
|
||||
<Application xmlns="https://github.com/avaloniaui"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:dialog="clr-namespace:Egorozh.ColorPicker.Dialog;assembly=Egorozh.ColorPicker.Avalonia.Dialog"
|
||||
xmlns:local="clr-namespace:Observatory.UI"
|
||||
x:Class="Observatory.UI.MainApplication">
|
||||
<Application.DataTemplates>
|
||||
<local:ViewLocator/>
|
||||
</Application.DataTemplates>
|
||||
<Application.Styles>
|
||||
<FluentTheme Mode="Dark"/>
|
||||
<StyleInclude Source="avares://Avalonia.Controls.DataGrid/Themes/Fluent.xaml"/>
|
||||
<StyleInclude Source="avares://Egorozh.ColorPicker.Avalonia.Dialog/Themes/Default.axaml" />
|
||||
<dialog:FluentColorPickerTheme Mode="Dark" />
|
||||
</Application.Styles>
|
||||
</Application>
|
@ -1,34 +0,0 @@
|
||||
using Avalonia;
|
||||
using Avalonia.Controls.ApplicationLifetimes;
|
||||
using Avalonia.Markup.Xaml;
|
||||
using Observatory.UI.ViewModels;
|
||||
|
||||
namespace Observatory.UI
|
||||
{
|
||||
public class MainApplication : Application
|
||||
{
|
||||
public override void Initialize()
|
||||
{
|
||||
AvaloniaXamlLoader.Load(this);
|
||||
}
|
||||
|
||||
public override void OnFrameworkInitializationCompleted()
|
||||
{
|
||||
if (ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktop)
|
||||
{
|
||||
var pluginManager = PluginManagement.PluginManager.GetInstance;
|
||||
desktop.MainWindow = new Views.MainWindow()
|
||||
{
|
||||
DataContext = new MainWindowViewModel(pluginManager)
|
||||
};
|
||||
|
||||
desktop.MainWindow.Closing += (o, e) =>
|
||||
{
|
||||
pluginManager.Shutdown();
|
||||
};
|
||||
}
|
||||
|
||||
base.OnFrameworkInitializationCompleted();
|
||||
}
|
||||
}
|
||||
}
|
@ -1,14 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Observatory.UI.Models
|
||||
{
|
||||
public class BasicUIModel
|
||||
{
|
||||
public string Time { get; set; }
|
||||
public string Description { get; set; }
|
||||
}
|
||||
}
|
@ -1,17 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using Avalonia.Controls;
|
||||
using Observatory.UI.ViewModels;
|
||||
|
||||
namespace Observatory.UI.Models
|
||||
{
|
||||
public class CoreModel
|
||||
{
|
||||
public string Name { get; set; }
|
||||
public ViewModelBase UI { get; set; }
|
||||
|
||||
}
|
||||
}
|
@ -1,12 +0,0 @@
|
||||
namespace Observatory.UI.Models
|
||||
{
|
||||
public class NotificationModel
|
||||
{
|
||||
public string Title { get; set; }
|
||||
public string Detail { get; set; }
|
||||
public string Colour { get; set; }
|
||||
public int Timeout { get; set; }
|
||||
public double XPos { get; set; }
|
||||
public double YPos { get; set; }
|
||||
}
|
||||
}
|
39
ObservatoryCore/UI/NotificationForm.Designer.cs
generated
Normal file
39
ObservatoryCore/UI/NotificationForm.Designer.cs
generated
Normal file
@ -0,0 +1,39 @@
|
||||
namespace Observatory.UI
|
||||
{
|
||||
partial class NotificationForm
|
||||
{
|
||||
/// <summary>
|
||||
/// Required designer variable.
|
||||
/// </summary>
|
||||
private System.ComponentModel.IContainer components = null;
|
||||
|
||||
/// <summary>
|
||||
/// Clean up any resources being used.
|
||||
/// </summary>
|
||||
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
|
||||
protected override void Dispose(bool disposing)
|
||||
{
|
||||
if (disposing && (components != null))
|
||||
{
|
||||
components.Dispose();
|
||||
}
|
||||
base.Dispose(disposing);
|
||||
}
|
||||
|
||||
#region Windows Form Designer generated code
|
||||
|
||||
/// <summary>
|
||||
/// Required method for Designer support - do not modify
|
||||
/// the contents of this method with the code editor.
|
||||
/// </summary>
|
||||
private void InitializeComponent()
|
||||
{
|
||||
this.components = new System.ComponentModel.Container();
|
||||
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
|
||||
this.ClientSize = new System.Drawing.Size(800, 450);
|
||||
this.Text = "NotificationForm";
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
22
ObservatoryCore/UI/NotificationForm.cs
Normal file
22
ObservatoryCore/UI/NotificationForm.cs
Normal file
@ -0,0 +1,22 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using System.Data;
|
||||
using System.Drawing;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows.Forms;
|
||||
|
||||
namespace Observatory.UI
|
||||
{
|
||||
public partial class NotificationForm : Form
|
||||
{
|
||||
public NotificationForm()
|
||||
{
|
||||
InitializeComponent();
|
||||
}
|
||||
|
||||
public Guid Guid;
|
||||
}
|
||||
}
|
120
ObservatoryCore/UI/NotificationForm.resx
Normal file
120
ObservatoryCore/UI/NotificationForm.resx
Normal file
@ -0,0 +1,120 @@
|
||||
<?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.
|
||||
-->
|
||||
<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">
|
||||
<xsd:complexType>
|
||||
<xsd:choice maxOccurs="unbounded">
|
||||
<xsd:element name="metadata">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" use="required" type="xsd:string" />
|
||||
<xsd:attribute name="type" type="xsd:string" />
|
||||
<xsd:attribute name="mimetype" type="xsd:string" />
|
||||
<xsd:attribute ref="xml:space" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="assembly">
|
||||
<xsd:complexType>
|
||||
<xsd:attribute name="alias" type="xsd:string" />
|
||||
<xsd:attribute name="name" type="xsd:string" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="data">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
|
||||
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
|
||||
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
|
||||
<xsd:attribute ref="xml:space" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="resheader">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" use="required" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
</xsd:choice>
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
</xsd:schema>
|
||||
<resheader name="resmimetype">
|
||||
<value>text/microsoft-resx</value>
|
||||
</resheader>
|
||||
<resheader name="version">
|
||||
<value>2.0</value>
|
||||
</resheader>
|
||||
<resheader name="reader">
|
||||
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
<resheader name="writer">
|
||||
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
</root>
|
126
ObservatoryCore/UI/PluginHelper.cs
Normal file
126
ObservatoryCore/UI/PluginHelper.cs
Normal file
@ -0,0 +1,126 @@
|
||||
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;
|
||||
|
||||
namespace Observatory.UI
|
||||
{
|
||||
internal class PluginHelper
|
||||
{
|
||||
internal static List<string> CreatePluginTabs(MenuStrip menu, IEnumerable<(IObservatoryWorker plugin, PluginManagement.PluginManager.PluginStatus signed)> plugins, Dictionary<object, Panel> uiPanels)
|
||||
{
|
||||
List<string> pluginList = new List<string>();
|
||||
foreach (var plugin in plugins)
|
||||
{
|
||||
AddPlugin(menu, plugin.plugin, plugin.signed, uiPanels);
|
||||
pluginList.Add(plugin.plugin.ShortName);
|
||||
}
|
||||
return pluginList;
|
||||
}
|
||||
|
||||
internal static List<string> CreatePluginTabs(MenuStrip menu, IEnumerable<(IObservatoryNotifier plugin, PluginManagement.PluginManager.PluginStatus signed)> plugins, Dictionary<object, Panel> uiPanels)
|
||||
{
|
||||
List<string> pluginList = new List<string>();
|
||||
foreach (var plugin in plugins)
|
||||
{
|
||||
AddPlugin(menu, plugin.plugin, plugin.signed, uiPanels);
|
||||
pluginList.Add(plugin.plugin.ShortName);
|
||||
}
|
||||
return pluginList;
|
||||
}
|
||||
|
||||
private static void AddPlugin(MenuStrip menu, IObservatoryPlugin plugin, PluginManagement.PluginManager.PluginStatus signed, Dictionary<object, Panel> uiPanels)
|
||||
{
|
||||
var newItem = new ToolStripMenuItem()
|
||||
{
|
||||
Text = plugin.ShortName,
|
||||
BackColor = menu.Items[0].BackColor,
|
||||
ForeColor = menu.Items[0].ForeColor,
|
||||
Font = menu.Items[0].Font,
|
||||
TextAlign = menu.Items[0].TextAlign
|
||||
};
|
||||
menu.Items.Add(newItem);
|
||||
|
||||
if (plugin.PluginUI.PluginUIType == Framework.PluginUI.UIType.Basic)
|
||||
uiPanels.Add(newItem, CreateBasicUI(plugin));
|
||||
}
|
||||
|
||||
private static Panel CreateBasicUI(IObservatoryPlugin plugin)
|
||||
{
|
||||
Panel panel = new();
|
||||
var columnSorter = new DefaultSorter();
|
||||
ListView listView = new()
|
||||
{
|
||||
View = View.Details,
|
||||
Location = new Point(0, 0),
|
||||
Size = panel.Size,
|
||||
Anchor = AnchorStyles.Left | AnchorStyles.Right | AnchorStyles.Bottom | AnchorStyles.Top,
|
||||
BackColor = Color.FromArgb(64, 64, 64),
|
||||
ForeColor = Color.LightGray,
|
||||
GridLines = true,
|
||||
ListViewItemSorter = columnSorter
|
||||
};
|
||||
|
||||
foreach (var property in plugin.PluginUI.DataGrid.First().GetType().GetProperties())
|
||||
{
|
||||
listView.Columns.Add(property.Name);
|
||||
}
|
||||
|
||||
listView.ColumnClick += (sender, e) =>
|
||||
{
|
||||
if (e.Column == columnSorter.SortColumn)
|
||||
{
|
||||
// Reverse the current sort direction for this column.
|
||||
if (columnSorter.Order == SortOrder.Ascending)
|
||||
{
|
||||
columnSorter.Order = SortOrder.Descending;
|
||||
}
|
||||
else
|
||||
{
|
||||
columnSorter.Order = SortOrder.Ascending;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Set the column number that is to be sorted; default to ascending.
|
||||
columnSorter.SortColumn = e.Column;
|
||||
columnSorter.Order = SortOrder.Ascending;
|
||||
}
|
||||
listView.Sort();
|
||||
};
|
||||
|
||||
panel.Controls.Add(listView);
|
||||
|
||||
plugin.PluginUI.DataGrid.CollectionChanged += (sender, e) =>
|
||||
{
|
||||
if (e.Action == System.Collections.Specialized.NotifyCollectionChangedAction.Add &&
|
||||
e.NewItems != null)
|
||||
{
|
||||
foreach (var newItem in e.NewItems)
|
||||
{
|
||||
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);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
return panel;
|
||||
}
|
||||
|
||||
internal static Panel CreatePluginSettings(IObservatoryPlugin plugin)
|
||||
{
|
||||
Panel panel = new Panel();
|
||||
|
||||
return panel;
|
||||
}
|
||||
}
|
||||
}
|
96
ObservatoryCore/UI/SettingsPanel.cs
Normal file
96
ObservatoryCore/UI/SettingsPanel.cs
Normal file
@ -0,0 +1,96 @@
|
||||
using Observatory.Framework;
|
||||
using Observatory.Framework.Interfaces;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Observatory.UI
|
||||
{
|
||||
internal class SettingsPanel : Panel
|
||||
{
|
||||
public Label Header;
|
||||
private IObservatoryPlugin _plugin;
|
||||
private Action<Control, CoreForm.AdjustmentDirection> _adjustPanelsBelow;
|
||||
|
||||
internal SettingsPanel(IObservatoryPlugin plugin, Action<Control, CoreForm.AdjustmentDirection> adjustPanelsBelow) : base()
|
||||
{
|
||||
Header = CreateHeader(plugin.Name);
|
||||
_plugin = plugin;
|
||||
_adjustPanelsBelow = adjustPanelsBelow;
|
||||
|
||||
// Filtered to only settings without SettingIgnore attribute
|
||||
var settings = PluginManagement.PluginManager.GetSettingDisplayNames(plugin).Where(s => !Attribute.IsDefined(s.Key, typeof (SettingIgnore)));
|
||||
CreateControls(settings);
|
||||
|
||||
}
|
||||
|
||||
private void CreateControls(IEnumerable<KeyValuePair<PropertyInfo, string>> settings)
|
||||
{
|
||||
int controlRow = 0;
|
||||
bool nextColumn = true;
|
||||
|
||||
// Handle bool (checkbox) settings first and keep them grouped together
|
||||
foreach (var setting in settings.Where(s => s.Key.PropertyType == typeof(bool)))
|
||||
{
|
||||
CheckBox checkBox = new()
|
||||
{
|
||||
Text = setting.Value,
|
||||
Checked = (bool?)setting.Key.GetValue(_plugin.Settings) ?? false
|
||||
};
|
||||
|
||||
checkBox.CheckedChanged += (object? _, EventArgs _) =>
|
||||
{
|
||||
setting.Key.SetValue(_plugin.Settings, checkBox.Checked);
|
||||
PluginManagement.PluginManager.GetInstance.SaveSettings(_plugin, _plugin.Settings);
|
||||
};
|
||||
|
||||
checkBox.Location = new Point(nextColumn ? 10 : 130, 3 + controlRow * 29);
|
||||
controlRow += nextColumn ? 0 : 1;
|
||||
nextColumn = !nextColumn;
|
||||
|
||||
Controls.Add(checkBox);
|
||||
}
|
||||
|
||||
// Then the rest
|
||||
foreach (var setting in settings.Where(s => s.Key.PropertyType != typeof(bool)))
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
private Label CreateHeader(string pluginName)
|
||||
{
|
||||
var headerLabel = new Label()
|
||||
{
|
||||
Text = "❯ " + pluginName,
|
||||
BorderStyle = BorderStyle.FixedSingle,
|
||||
ForeColor = Color.White
|
||||
};
|
||||
|
||||
headerLabel.Click += HeaderLabel_Click;
|
||||
|
||||
return headerLabel;
|
||||
}
|
||||
|
||||
private void HeaderLabel_Click(object? _, EventArgs e)
|
||||
{
|
||||
this.Parent?.SuspendLayout();
|
||||
if (Header.Text[0] == '❯')
|
||||
{
|
||||
Header.Text = Header.Text.Replace('❯', '⌵');
|
||||
this.Visible = true;
|
||||
_adjustPanelsBelow.Invoke(this, CoreForm.AdjustmentDirection.Down);
|
||||
}
|
||||
else
|
||||
{
|
||||
Header.Text = Header.Text.Replace('⌵', '❯');
|
||||
this.Visible = false;
|
||||
_adjustPanelsBelow.Invoke(this, CoreForm.AdjustmentDirection.Up);
|
||||
}
|
||||
this.Parent?.ResumeLayout();
|
||||
}
|
||||
}
|
||||
}
|
@ -1,31 +0,0 @@
|
||||
using Avalonia.Controls;
|
||||
using Avalonia.Controls.Templates;
|
||||
using Avalonia.Metadata;
|
||||
using Observatory.UI.Views;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Observatory.UI
|
||||
{
|
||||
public class TabTemplateSelector : IDataTemplate
|
||||
{
|
||||
public bool SupportsRecycling => false;
|
||||
|
||||
[Content]
|
||||
public Dictionary<string, IDataTemplate> Templates { get; } = new Dictionary<string, IDataTemplate>();
|
||||
|
||||
|
||||
public IControl Build(object param)
|
||||
{
|
||||
return new BasicUIView(); //Templates[param].Build(param);
|
||||
}
|
||||
|
||||
public bool Match(object data)
|
||||
{
|
||||
return data is BasicUIView;
|
||||
}
|
||||
}
|
||||
}
|
12
ObservatoryCore/UI/UIHelper.cs
Normal file
12
ObservatoryCore/UI/UIHelper.cs
Normal file
@ -0,0 +1,12 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Observatory.UI
|
||||
{
|
||||
internal class UIHelper
|
||||
{
|
||||
}
|
||||
}
|
@ -1,32 +0,0 @@
|
||||
using Avalonia.Controls;
|
||||
using Avalonia.Controls.Templates;
|
||||
using Observatory.UI.ViewModels;
|
||||
using System;
|
||||
|
||||
namespace Observatory.UI
|
||||
{
|
||||
public class ViewLocator : IDataTemplate
|
||||
{
|
||||
public bool SupportsRecycling => false;
|
||||
|
||||
public IControl Build(object data)
|
||||
{
|
||||
var name = data.GetType().FullName!.Replace("ViewModel", "View");
|
||||
var type = Type.GetType(name);
|
||||
|
||||
if (type != null)
|
||||
{
|
||||
return (Control)Activator.CreateInstance(type)!;
|
||||
}
|
||||
else
|
||||
{
|
||||
return new TextBlock { Text = "Not Found: " + name };
|
||||
}
|
||||
}
|
||||
|
||||
public bool Match(object data)
|
||||
{
|
||||
return data is ViewModelBase;
|
||||
}
|
||||
}
|
||||
}
|
@ -1,83 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Data;
|
||||
using System.Threading.Tasks;
|
||||
using System.Collections.ObjectModel;
|
||||
using Observatory.UI.Models;
|
||||
using ReactiveUI;
|
||||
using System.Reactive.Linq;
|
||||
using Observatory.Framework;
|
||||
using System.Collections.Specialized;
|
||||
|
||||
namespace Observatory.UI.ViewModels
|
||||
{
|
||||
public class BasicUIViewModel : ViewModelBase
|
||||
{
|
||||
private ObservableCollection<string> _headers;
|
||||
private ObservableCollection<string> _formats;
|
||||
private ObservableCollection<ObservableCollection<object>> _items;
|
||||
|
||||
public System.Collections.IList SelectedItems { get; set; }
|
||||
|
||||
|
||||
public ObservableCollection<string> Headers
|
||||
{
|
||||
get => _headers;
|
||||
set
|
||||
{
|
||||
_headers = value;
|
||||
_headers.CollectionChanged += (o, e) => this.RaisePropertyChanged(nameof(Headers));
|
||||
this.RaisePropertyChanged(nameof(Headers));
|
||||
}
|
||||
}
|
||||
|
||||
public ObservableCollection<string> Formats
|
||||
{
|
||||
get => _formats;
|
||||
set
|
||||
{
|
||||
_formats = value;
|
||||
_formats.CollectionChanged += (o, e) => this.RaisePropertyChanged(nameof(Formats));
|
||||
this.RaisePropertyChanged(nameof(Formats));
|
||||
}
|
||||
}
|
||||
|
||||
public ObservableCollection<ObservableCollection<object>> Items
|
||||
{
|
||||
get => _items;
|
||||
set
|
||||
{
|
||||
void raiseItemChanged(object o, NotifyCollectionChangedEventArgs e) { this.RaisePropertyChanged(nameof(Items)); }
|
||||
|
||||
_items = value;
|
||||
_items.CollectionChanged += raiseItemChanged;
|
||||
this.RaisePropertyChanged(nameof(Items));
|
||||
foreach (var itemColumn in value)
|
||||
{
|
||||
itemColumn.CollectionChanged += raiseItemChanged;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public BasicUIViewModel(BasicGrid basicGrid)
|
||||
{
|
||||
Headers = basicGrid.Headers;
|
||||
Formats = basicGrid.Formats;
|
||||
Items = basicGrid.Items;
|
||||
}
|
||||
|
||||
private PluginUI.UIType _uiType;
|
||||
|
||||
public PluginUI.UIType UIType
|
||||
{
|
||||
get => _uiType;
|
||||
set
|
||||
{
|
||||
_uiType = value;
|
||||
this.RaisePropertyChanged(nameof(UIType));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -1,310 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.Data;
|
||||
using System.Diagnostics;
|
||||
using System.Linq;
|
||||
using System.Net.Http;
|
||||
using Avalonia.Controls;
|
||||
using Avalonia.Controls.ApplicationLifetimes;
|
||||
using Observatory.Framework.Interfaces;
|
||||
using Observatory.UI.Models;
|
||||
using ReactiveUI;
|
||||
|
||||
namespace Observatory.UI.ViewModels
|
||||
{
|
||||
public class CoreViewModel : ViewModelBase
|
||||
{
|
||||
private readonly ObservableCollection<IObservatoryNotifier> notifiers;
|
||||
private readonly ObservableCollection<IObservatoryWorker> workers;
|
||||
private readonly ObservableCollection<CoreModel> tabs;
|
||||
private string toggleButtonText;
|
||||
private bool _UpdateAvailable;
|
||||
|
||||
public CoreViewModel(IEnumerable<(IObservatoryWorker plugin, PluginManagement.PluginManager.PluginStatus signed)> workers, IEnumerable<(IObservatoryNotifier plugin, PluginManagement.PluginManager.PluginStatus signed)> notifiers)
|
||||
{
|
||||
_UpdateAvailable = CheckUpdate();
|
||||
|
||||
this.notifiers = new ObservableCollection<IObservatoryNotifier>(notifiers.Select(p => p.plugin));
|
||||
this.workers = new ObservableCollection<IObservatoryWorker>(workers.Select(p => p.plugin));
|
||||
ToggleButtonText = "Start Monitor";
|
||||
tabs = new ObservableCollection<CoreModel>();
|
||||
|
||||
foreach(var worker in workers.Select(p => p.plugin))
|
||||
{
|
||||
if (worker.PluginUI.PluginUIType == Framework.PluginUI.UIType.Basic)
|
||||
{
|
||||
CoreModel coreModel = new();
|
||||
coreModel.Name = worker.ShortName;
|
||||
coreModel.UI = new BasicUIViewModel(worker.PluginUI.BasicGrid)
|
||||
{
|
||||
UIType = worker.PluginUI.PluginUIType
|
||||
};
|
||||
|
||||
tabs.Add(coreModel);
|
||||
}
|
||||
}
|
||||
|
||||
foreach(var notifier in notifiers.Select(p => p.plugin))
|
||||
{
|
||||
Panel notifierPanel = new();
|
||||
TextBlock notifierTextBlock = new();
|
||||
notifierTextBlock.Text = notifier.Name;
|
||||
notifierPanel.Children.Add(notifierTextBlock);
|
||||
//tabs.Add(new CoreModel() { Name = notifier.ShortName, UI = (ViewModelBase)notifier.UI });
|
||||
}
|
||||
|
||||
|
||||
tabs.Add(new CoreModel() { Name = "Core", UI = new BasicUIViewModel(new Framework.BasicGrid()) { UIType = Framework.PluginUI.UIType.Core } });
|
||||
|
||||
if (Properties.Core.Default.StartMonitor)
|
||||
ToggleMonitor();
|
||||
|
||||
if (Properties.Core.Default.StartReadAll)
|
||||
ReadAll();
|
||||
|
||||
}
|
||||
|
||||
public static void ReadAll()
|
||||
{
|
||||
LogMonitor.GetInstance.ReadAllJournals();
|
||||
}
|
||||
|
||||
public void ToggleMonitor()
|
||||
{
|
||||
var logMonitor = LogMonitor.GetInstance;
|
||||
|
||||
if (logMonitor.IsMonitoring())
|
||||
{
|
||||
logMonitor.Stop();
|
||||
ToggleButtonText = "Start Monitor";
|
||||
}
|
||||
else
|
||||
{
|
||||
logMonitor.Start();
|
||||
ToggleButtonText = "Stop Monitor";
|
||||
}
|
||||
}
|
||||
|
||||
public static void OpenGithub()
|
||||
{
|
||||
ProcessStartInfo githubOpen = new("https://github.com/Xjph/ObservatoryCore");
|
||||
githubOpen.UseShellExecute = true;
|
||||
Process.Start(githubOpen);
|
||||
}
|
||||
|
||||
public static void OpenDonate()
|
||||
{
|
||||
ProcessStartInfo donateOpen = new("https://paypal.me/eliteobservatory");
|
||||
donateOpen.UseShellExecute = true;
|
||||
Process.Start(donateOpen);
|
||||
}
|
||||
|
||||
public static void GetUpdate()
|
||||
{
|
||||
ProcessStartInfo githubOpen = new("https://github.com/Xjph/ObservatoryCore/releases");
|
||||
githubOpen.UseShellExecute = true;
|
||||
Process.Start(githubOpen);
|
||||
}
|
||||
|
||||
public async void ExportGrid()
|
||||
{
|
||||
try
|
||||
{
|
||||
var exportFolder = Properties.Core.Default.ExportFolder;
|
||||
|
||||
if (string.IsNullOrEmpty(exportFolder))
|
||||
{
|
||||
exportFolder = System.Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments);
|
||||
}
|
||||
|
||||
OpenFolderDialog openFolderDialog = new()
|
||||
{
|
||||
Directory = exportFolder
|
||||
};
|
||||
|
||||
var application = (IClassicDesktopStyleApplicationLifetime)Avalonia.Application.Current.ApplicationLifetime;
|
||||
|
||||
var selectedFolder = await openFolderDialog.ShowAsync(application.MainWindow);
|
||||
|
||||
if (!string.IsNullOrEmpty(selectedFolder))
|
||||
{
|
||||
Properties.Core.Default.ExportFolder = selectedFolder;
|
||||
Properties.Core.Default.Save();
|
||||
exportFolder = selectedFolder;
|
||||
|
||||
foreach (var tab in tabs.Where(t => t.Name != "Core"))
|
||||
{
|
||||
var ui = (BasicUIViewModel)tab.UI;
|
||||
List<object> selectedData;
|
||||
bool specificallySelected = ui.SelectedItems?.Count > 1;
|
||||
|
||||
if (specificallySelected)
|
||||
{
|
||||
selectedData = new();
|
||||
|
||||
foreach (var item in ui.SelectedItems)
|
||||
selectedData.Add(item);
|
||||
}
|
||||
else
|
||||
{
|
||||
selectedData = new(); // TODO: Make this work in new UI
|
||||
}
|
||||
|
||||
var columns = selectedData[0].GetType().GetProperties();
|
||||
Dictionary<string, int> colSize = new();
|
||||
Dictionary<string, List<string>> colContent = new();
|
||||
|
||||
foreach (var column in columns)
|
||||
{
|
||||
colSize.Add(column.Name, 0);
|
||||
colContent.Add(column.Name, new());
|
||||
}
|
||||
|
||||
foreach (var line in selectedData)
|
||||
{
|
||||
var lineType = line.GetType(); // some plugins have different line types, so don't move this out of loop
|
||||
foreach (var column in colContent)
|
||||
{
|
||||
var cellValue = lineType.GetProperty(column.Key)?.GetValue(line)?.ToString() ?? string.Empty;
|
||||
column.Value.Add(cellValue);
|
||||
if (colSize[column.Key] < cellValue.Length)
|
||||
colSize[column.Key] = cellValue.Length;
|
||||
}
|
||||
}
|
||||
|
||||
System.Text.StringBuilder exportData = new();
|
||||
|
||||
|
||||
foreach (var colTitle in colContent.Keys)
|
||||
{
|
||||
if (colSize[colTitle] < colTitle.Length)
|
||||
colSize[colTitle] = colTitle.Length;
|
||||
|
||||
exportData.Append(colTitle.PadRight(colSize[colTitle]) + " ");
|
||||
}
|
||||
exportData.AppendLine();
|
||||
|
||||
for (int i = 0; i < colContent.First().Value.Count; i++)
|
||||
{
|
||||
foreach (var column in colContent)
|
||||
{
|
||||
if (column.Value[i].Length > 0 && !char.IsNumber(column.Value[i][0]) && column.Value[i].Count(char.IsLetter) / (float)column.Value[i].Length > 0.25)
|
||||
exportData.Append(column.Value[i].PadRight(colSize[column.Key]) + " ");
|
||||
else
|
||||
exportData.Append(column.Value[i].PadLeft(colSize[column.Key]) + " ");
|
||||
}
|
||||
exportData.AppendLine();
|
||||
}
|
||||
|
||||
string exportPath = $"{exportFolder}{System.IO.Path.DirectorySeparatorChar}Observatory Export - {DateTime.UtcNow:yyyyMMdd-HHmmss} - {tab.Name}.txt";
|
||||
|
||||
System.IO.File.WriteAllText(exportPath, exportData.ToString());
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
ObservatoryCore.LogError(e, "while exporting data");
|
||||
ErrorReporter.ShowErrorPopup("Error encountered!",
|
||||
new List<(string, string)> { ("An error occurred while exporting; output may be missing or incomplete." + Environment.NewLine +
|
||||
"Please check the error log (found in your Documents folder) for more details and visit our discord to report it.", e.Message) });
|
||||
}
|
||||
}
|
||||
|
||||
public void ClearGrid()
|
||||
{
|
||||
foreach (var tab in tabs.Where(t => t.Name != "Core"))
|
||||
{
|
||||
var ui = (BasicUIViewModel)tab.UI;
|
||||
|
||||
ui.Items.Clear();
|
||||
|
||||
// For some reason UIType's change event will properly
|
||||
// redraw the grid, not BasicUIGrid's.
|
||||
ui.RaisePropertyChanged(nameof(ui.UIType));
|
||||
}
|
||||
}
|
||||
|
||||
public string ToggleButtonText
|
||||
{
|
||||
get => toggleButtonText;
|
||||
set
|
||||
{
|
||||
if (toggleButtonText != value)
|
||||
{
|
||||
toggleButtonText = value;
|
||||
this.RaisePropertyChanged(nameof(ToggleButtonText));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public ObservableCollection<IObservatoryWorker> Workers
|
||||
{
|
||||
get { return workers; }
|
||||
}
|
||||
|
||||
public ObservableCollection<IObservatoryNotifier> Notifiers
|
||||
{
|
||||
get { return notifiers; }
|
||||
}
|
||||
|
||||
public ObservableCollection<CoreModel> Tabs
|
||||
{
|
||||
get { return tabs; }
|
||||
}
|
||||
|
||||
private static bool CheckUpdate()
|
||||
{
|
||||
try
|
||||
{
|
||||
string releasesResponse;
|
||||
|
||||
var request = new HttpRequestMessage
|
||||
{
|
||||
Method = HttpMethod.Get,
|
||||
RequestUri = new Uri("https://api.github.com/repos/xjph/ObservatoryCore/releases"),
|
||||
Headers = { { "User-Agent", "Xjph/ObservatoryCore" } }
|
||||
};
|
||||
|
||||
releasesResponse = HttpClient.SendRequest(request).Content.ReadAsStringAsync().Result;
|
||||
|
||||
if (!string.IsNullOrEmpty(releasesResponse))
|
||||
{
|
||||
var releases = System.Text.Json.JsonDocument.Parse(releasesResponse).RootElement.EnumerateArray();
|
||||
|
||||
foreach (var release in releases)
|
||||
{
|
||||
var tag = release.GetProperty("tag_name").ToString();
|
||||
var verstrings = tag[1..].Split('.');
|
||||
var ver = verstrings.Select(verString => { _ = int.TryParse(verString, out int ver); return ver; }).ToArray();
|
||||
if (ver.Length == 4)
|
||||
{
|
||||
Version version = new(ver[0], ver[1], ver[2], ver[3]);
|
||||
if (version > System.Reflection.Assembly.GetEntryAssembly().GetName().Version)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private bool UpdateAvailable
|
||||
{
|
||||
get => _UpdateAvailable;
|
||||
set
|
||||
{
|
||||
this.RaiseAndSetIfChanged(ref _UpdateAvailable, value);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
@ -1,19 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
namespace Observatory.UI.ViewModels
|
||||
{
|
||||
public class MainWindowViewModel : ViewModelBase
|
||||
{
|
||||
public MainWindowViewModel(PluginManagement.PluginManager pluginManager)
|
||||
{
|
||||
core = new CoreViewModel(pluginManager.workerPlugins, pluginManager.notifyPlugins);
|
||||
|
||||
if (pluginManager.errorList.Any())
|
||||
ErrorReporter.ShowErrorPopup("Plugin Load Error", pluginManager.errorList);
|
||||
}
|
||||
|
||||
public CoreViewModel core { get; }
|
||||
}
|
||||
}
|
@ -1,24 +0,0 @@
|
||||
using Observatory.Framework;
|
||||
|
||||
namespace Observatory.UI.ViewModels
|
||||
{
|
||||
public class NotificationViewModel : ViewModelBase
|
||||
{
|
||||
public NotificationViewModel(NotificationArgs notificationArgs)
|
||||
{
|
||||
|
||||
Notification = new()
|
||||
{
|
||||
Title = notificationArgs.Title,
|
||||
Detail = notificationArgs.Detail,
|
||||
Timeout = notificationArgs.Timeout,
|
||||
XPos = notificationArgs.XPos,
|
||||
YPos = notificationArgs.YPos,
|
||||
Colour = Avalonia.Media.Color.FromUInt32(Properties.Core.Default.NativeNotifyColour).ToString()
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
public Models.NotificationModel Notification { get; set; }
|
||||
}
|
||||
}
|
@ -1,11 +0,0 @@
|
||||
using ReactiveUI;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
namespace Observatory.UI.ViewModels
|
||||
{
|
||||
public class ViewModelBase : ReactiveObject
|
||||
{
|
||||
}
|
||||
}
|
@ -1,10 +0,0 @@
|
||||
<UserControl xmlns="https://github.com/avaloniaui"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
|
||||
x:Class="Observatory.UI.Views.BasicUIView">
|
||||
<Panel Name="UIPanel">
|
||||
|
||||
</Panel>
|
||||
</UserControl>
|
File diff suppressed because it is too large
Load Diff
@ -1,108 +0,0 @@
|
||||
<UserControl xmlns="https://github.com/avaloniaui"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:vw="clr-namespace:Observatory.UI.Views"
|
||||
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
|
||||
x:Class="Observatory.UI.Views.CoreView">
|
||||
<UserControl.Styles>
|
||||
<Style Selector="Button.Hyperlink">
|
||||
<Setter Property="Background" Value="Transparent"/>
|
||||
<Setter Property="BorderThickness" Value="0,0,0,1"/>
|
||||
<Setter Property="BorderBrush" Value="White"/>
|
||||
<Setter Property="Padding" Value="0"/>
|
||||
<Setter Property="FontSize" Value="10"/>
|
||||
</Style>
|
||||
</UserControl.Styles>
|
||||
<Grid RowDefinitions="30,*,Auto">
|
||||
<TextBlock Grid.Row="0" VerticalAlignment="Center" Padding="10,0,0,0" Name="Title">
|
||||
Elite Observatory - v0
|
||||
</TextBlock>
|
||||
<TabControl Name="CoreTabs"
|
||||
Grid.Row="1" Grid.Column="1"
|
||||
VerticalAlignment="Stretch"
|
||||
TabStripPlacement="Left"
|
||||
Items="{Binding Tabs}"
|
||||
BorderBrush="Black"
|
||||
BorderThickness="1">
|
||||
<TabControl.ItemTemplate>
|
||||
<DataTemplate>
|
||||
<TabItem>
|
||||
<TabItem.Header>
|
||||
<TextBlock Text="{Binding Name}"/>
|
||||
</TabItem.Header>
|
||||
</TabItem>
|
||||
</DataTemplate>
|
||||
</TabControl.ItemTemplate>
|
||||
<TabControl.ContentTemplate>
|
||||
<DataTemplate>
|
||||
<vw:BasicUIView DataContext="{Binding UI}" UIType="{Binding UIType}"/>
|
||||
</DataTemplate>
|
||||
</TabControl.ContentTemplate>
|
||||
</TabControl>
|
||||
<Grid RowDefinitions="Auto,Auto" Grid.Row="2">
|
||||
<StackPanel Grid.Column="1" Height="50" VerticalAlignment="Bottom" Orientation="Vertical" HorizontalAlignment="Left">
|
||||
<Button
|
||||
Classes="Hyperlink"
|
||||
Name="github"
|
||||
Margin="10,0,0,5"
|
||||
Command="{Binding OpenGithub}"
|
||||
FontSize="15"
|
||||
Cursor="Hand">
|
||||
github
|
||||
</Button>
|
||||
<Button
|
||||
Classes="Hyperlink"
|
||||
Name="Donate"
|
||||
Margin="10,0,0,0"
|
||||
Command="{Binding OpenDonate}"
|
||||
FontSize="15"
|
||||
Cursor="Hand">
|
||||
Donate
|
||||
</Button>
|
||||
</StackPanel>
|
||||
<WrapPanel Grid.Column="2" Height="50" VerticalAlignment="Bottom" Orientation="Horizontal" HorizontalAlignment="Right">
|
||||
<Button
|
||||
Classes="Hyperlink"
|
||||
Name="update"
|
||||
Margin="0,0,10,0"
|
||||
FontSize="15"
|
||||
Command="{Binding GetUpdate}"
|
||||
IsVisible="{Binding UpdateAvailable}"
|
||||
IsEnabled="{Binding UpdateAvailable}"
|
||||
Cursor="Hand">
|
||||
Update Available
|
||||
</Button>
|
||||
<Button
|
||||
Name="export"
|
||||
Margin="10"
|
||||
FontSize="15"
|
||||
Command="{Binding ExportGrid}"
|
||||
Content="Export">
|
||||
Export
|
||||
</Button>
|
||||
<Button
|
||||
Name="clear"
|
||||
Margin="10"
|
||||
FontSize="15"
|
||||
Command="{Binding ClearGrid}"
|
||||
Content="Clear">
|
||||
Clear
|
||||
</Button>
|
||||
<Button
|
||||
Name="ToggleMonitor"
|
||||
Margin="10"
|
||||
Command="{Binding ToggleMonitor}"
|
||||
Content="{Binding ToggleButtonText}">
|
||||
Start Monitor
|
||||
</Button>
|
||||
<Button
|
||||
Name="ReadAll"
|
||||
Margin="10"
|
||||
Command="{Binding ReadAll}">
|
||||
Read All
|
||||
</Button>
|
||||
</WrapPanel>
|
||||
</Grid>
|
||||
</Grid>
|
||||
</UserControl>
|
@ -1,25 +0,0 @@
|
||||
using Avalonia;
|
||||
using Avalonia.Controls;
|
||||
using Avalonia.Markup.Xaml;
|
||||
using System.Linq;
|
||||
|
||||
namespace Observatory.UI.Views
|
||||
{
|
||||
public class CoreView : UserControl
|
||||
{
|
||||
public CoreView()
|
||||
{
|
||||
|
||||
InitializeComponent();
|
||||
|
||||
var titleBlock = this.Find<TextBlock>("Title");
|
||||
titleBlock.Text = "Elite Observatory Core - v" + System.Reflection.Assembly.GetEntryAssembly().GetName().Version.ToString();
|
||||
|
||||
}
|
||||
|
||||
private void InitializeComponent()
|
||||
{
|
||||
AvaloniaXamlLoader.Load(this);
|
||||
}
|
||||
}
|
||||
}
|
@ -1,12 +0,0 @@
|
||||
<Window xmlns="https://github.com/avaloniaui"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:views="clr-namespace:Observatory.UI.Views"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
|
||||
x:Class="Observatory.UI.Views.MainWindow"
|
||||
Title="Elite Observatory"
|
||||
ExtendClientAreaToDecorationsHint="True"
|
||||
Content="{Binding core}"
|
||||
Icon="/Assets/EOCIcon-Presized.ico">
|
||||
</Window>
|
@ -1,60 +0,0 @@
|
||||
using Avalonia;
|
||||
using Avalonia.Controls;
|
||||
using Avalonia.Markup.Xaml;
|
||||
|
||||
|
||||
namespace Observatory.UI.Views
|
||||
{
|
||||
public class MainWindow : Window
|
||||
{
|
||||
public MainWindow()
|
||||
{
|
||||
InitializeComponent();
|
||||
#if DEBUG
|
||||
this.AttachDevTools();
|
||||
#endif
|
||||
Height = Properties.Core.Default.MainWindowSize.Height;
|
||||
Width = Properties.Core.Default.MainWindowSize.Width;
|
||||
|
||||
var savedPosition = new System.Drawing.Point(Properties.Core.Default.MainWindowPosition.X, Properties.Core.Default.MainWindowPosition.Y);
|
||||
if (PointWithinDesktopWorkingArea(savedPosition))
|
||||
Position = new PixelPoint(Properties.Core.Default.MainWindowPosition.X, Properties.Core.Default.MainWindowPosition.Y);
|
||||
|
||||
Closing += (object sender, System.ComponentModel.CancelEventArgs e) =>
|
||||
{
|
||||
var size = new System.Drawing.Size((int)System.Math.Round(Width), (int)System.Math.Round(Height));
|
||||
Properties.Core.Default.MainWindowSize = size;
|
||||
|
||||
var position = new System.Drawing.Point(Position.X, Position.Y);
|
||||
if (PointWithinDesktopWorkingArea(position))
|
||||
Properties.Core.Default.MainWindowPosition = position;
|
||||
|
||||
Properties.Core.Default.Save();
|
||||
};
|
||||
}
|
||||
|
||||
private bool PointWithinDesktopWorkingArea(System.Drawing.Point position)
|
||||
{
|
||||
bool inBounds = false;
|
||||
|
||||
foreach (var screen in Screens.All)
|
||||
{
|
||||
if (screen.WorkingArea.TopLeft.X <= position.X
|
||||
&& screen.WorkingArea.TopLeft.Y <= position.Y
|
||||
&& screen.WorkingArea.BottomRight.X > position.X
|
||||
&& screen.WorkingArea.BottomRight.Y > position.Y)
|
||||
{
|
||||
inBounds = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return inBounds;
|
||||
}
|
||||
|
||||
private void InitializeComponent()
|
||||
{
|
||||
AvaloniaXamlLoader.Load(this);
|
||||
}
|
||||
}
|
||||
}
|
@ -1,41 +0,0 @@
|
||||
<Window xmlns="https://github.com/avaloniaui"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
mc:Ignorable="d" d:DesignWidth="400" d:DesignHeight="150"
|
||||
x:Class="Observatory.UI.Views.NotificationView"
|
||||
ExtendClientAreaToDecorationsHint="True"
|
||||
ExtendClientAreaChromeHints="NoChrome"
|
||||
ExtendClientAreaTitleBarHeightHint="-1"
|
||||
Title="Notification"
|
||||
Width="400" Height="150"
|
||||
Topmost="True"
|
||||
TransparencyLevelHint="AcrylicBlur"
|
||||
Background="Transparent"
|
||||
Focusable="False">
|
||||
<Panel DataContext="{Binding Notification}">
|
||||
<Border Name="TextBorder" BorderBrush="{Binding Colour}" BorderThickness="4">
|
||||
<StackPanel Name="TextPanel" Width="400">
|
||||
<TextBlock
|
||||
Name="Title"
|
||||
Padding="10"
|
||||
FontWeight="Normal"
|
||||
FontSize="30"
|
||||
Foreground="{Binding Colour}"
|
||||
Text="{Binding Title}">
|
||||
Title
|
||||
</TextBlock>
|
||||
<TextBlock
|
||||
Name="Detail"
|
||||
Padding="20,0"
|
||||
FontWeight="Normal"
|
||||
FontSize="20"
|
||||
TextWrapping="Wrap"
|
||||
Foreground="{Binding Colour}"
|
||||
Text="{Binding Detail}">
|
||||
Detail
|
||||
</TextBlock>
|
||||
</StackPanel>
|
||||
</Border>
|
||||
</Panel>
|
||||
</Window>
|
@ -1,267 +0,0 @@
|
||||
using Avalonia;
|
||||
using Avalonia.Controls;
|
||||
using Avalonia.Layout;
|
||||
using Avalonia.Markup.Xaml;
|
||||
using Observatory.UI.ViewModels;
|
||||
using System;
|
||||
using System.Reflection;
|
||||
using System.Timers;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace Observatory.UI.Views
|
||||
{
|
||||
public partial class NotificationView : Window
|
||||
{
|
||||
private readonly double scale;
|
||||
private readonly System.Timers.Timer timer;
|
||||
private readonly Guid guid;
|
||||
private bool defaultPosition = true;
|
||||
private PixelPoint originalPosition;
|
||||
|
||||
public NotificationView() : this(default)
|
||||
{ }
|
||||
|
||||
public NotificationView(Guid guid)
|
||||
{
|
||||
this.guid = guid;
|
||||
InitializeComponent();
|
||||
SystemDecorations = SystemDecorations.None;
|
||||
ShowActivated = false;
|
||||
ShowInTaskbar = false;
|
||||
MakeClickThrough(); //Platform specific, currently windows and Linux (X11) only.
|
||||
|
||||
this.DataContextChanged += NotificationView_DataContextChanged;
|
||||
scale = Properties.Core.Default.NativeNotifyScale / 100.0;
|
||||
|
||||
AdjustText();
|
||||
|
||||
AdjustPanel();
|
||||
|
||||
AdjustPosition();
|
||||
|
||||
timer = new();
|
||||
timer.Elapsed += CloseNotification;
|
||||
timer.Interval = Properties.Core.Default.NativeNotifyTimeout;
|
||||
timer.Start();
|
||||
|
||||
#if DEBUG
|
||||
this.AttachDevTools();
|
||||
#endif
|
||||
}
|
||||
|
||||
public Guid Guid { get => guid; }
|
||||
|
||||
public void AdjustOffset(bool increase)
|
||||
{
|
||||
if (defaultPosition)
|
||||
{
|
||||
if (increase || Position != originalPosition)
|
||||
{
|
||||
var corner = Properties.Core.Default.NativeNotifyCorner;
|
||||
|
||||
if ((corner >= 2 && increase) || (corner <= 1 && !increase))
|
||||
{
|
||||
Position += new PixelPoint(0, Convert.ToInt32(Height));
|
||||
}
|
||||
else
|
||||
{
|
||||
Position -= new PixelPoint(0, Convert.ToInt32(Height));
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public override void Show()
|
||||
{
|
||||
base.Show();
|
||||
|
||||
// Refresh the position when the window is opened (required
|
||||
// on Linux to show the notification in the right position)
|
||||
if (DataContext is NotificationViewModel nvm)
|
||||
{
|
||||
AdjustPosition(nvm.Notification.XPos / 100, nvm.Notification.YPos / 100);
|
||||
}
|
||||
}
|
||||
|
||||
private void NotificationView_DataContextChanged(object sender, EventArgs e)
|
||||
{
|
||||
var notification = ((NotificationViewModel)DataContext).Notification;
|
||||
|
||||
AdjustText();
|
||||
|
||||
AdjustPanel();
|
||||
|
||||
AdjustPosition(notification.XPos / 100, notification.YPos / 100);
|
||||
|
||||
if (notification.Timeout > 0)
|
||||
{
|
||||
timer.Stop();
|
||||
timer.Interval = notification.Timeout;
|
||||
timer.Start();
|
||||
}
|
||||
else if (notification.Timeout == 0)
|
||||
{
|
||||
timer.Stop();
|
||||
}
|
||||
}
|
||||
|
||||
private void AdjustText()
|
||||
{
|
||||
string font = Properties.Core.Default.NativeNotifyFont;
|
||||
var titleText = this.Find<TextBlock>("Title");
|
||||
var detailText = this.Find<TextBlock>("Detail");
|
||||
|
||||
if (font.Length > 0)
|
||||
{
|
||||
var fontFamily = new Avalonia.Media.FontFamily(font);
|
||||
|
||||
titleText.FontFamily = fontFamily;
|
||||
detailText.FontFamily = fontFamily;
|
||||
}
|
||||
|
||||
titleText.FontSize *= scale;
|
||||
detailText.FontSize *= scale;
|
||||
}
|
||||
|
||||
private void AdjustPanel()
|
||||
{
|
||||
var textPanel = this.Find<StackPanel>("TextPanel");
|
||||
Width *= scale;
|
||||
Height *= scale;
|
||||
textPanel.Width *= scale;
|
||||
textPanel.Height *= scale;
|
||||
|
||||
var textBorder = this.Find<Border>("TextBorder");
|
||||
textBorder.BorderThickness *= scale;
|
||||
}
|
||||
|
||||
private void AdjustPosition(double xOverride = -1.0, double yOverride = -1.0)
|
||||
{
|
||||
PixelRect screenBounds;
|
||||
int screen = Properties.Core.Default.NativeNotifyScreen;
|
||||
int corner = Properties.Core.Default.NativeNotifyCorner;
|
||||
|
||||
if (screen == -1 || screen > Screens.All.Count)
|
||||
if (Screens.All.Count == 1)
|
||||
screenBounds = Screens.All[0].Bounds;
|
||||
else
|
||||
screenBounds = Screens.Primary.Bounds;
|
||||
else
|
||||
screenBounds = Screens.All[screen - 1].Bounds;
|
||||
|
||||
double displayScale = LayoutHelper.GetLayoutScale(this);
|
||||
double scaleWidth = Width * displayScale;
|
||||
double scaleHeight = Height * displayScale;
|
||||
|
||||
if (xOverride >= 0 && yOverride >= 0)
|
||||
{
|
||||
defaultPosition = false;
|
||||
Position = screenBounds.TopLeft + new PixelPoint(Convert.ToInt32(screenBounds.Width * xOverride), Convert.ToInt32(screenBounds.Height * yOverride));
|
||||
}
|
||||
else
|
||||
{
|
||||
defaultPosition = true;
|
||||
switch (corner)
|
||||
{
|
||||
default:
|
||||
case 0:
|
||||
Position = screenBounds.BottomRight - new PixelPoint(Convert.ToInt32(scaleWidth) + 50, Convert.ToInt32(scaleHeight) + 50);
|
||||
break;
|
||||
case 1:
|
||||
Position = screenBounds.BottomLeft - new PixelPoint(-50, Convert.ToInt32(scaleHeight) + 50);
|
||||
break;
|
||||
case 2:
|
||||
Position = screenBounds.TopRight - new PixelPoint(Convert.ToInt32(scaleWidth) + 50, -50);
|
||||
break;
|
||||
case 3:
|
||||
Position = screenBounds.TopLeft + new PixelPoint(50, 50);
|
||||
break;
|
||||
}
|
||||
originalPosition = Position;
|
||||
}
|
||||
}
|
||||
|
||||
private void CloseNotification(object sender, System.Timers.ElapsedEventArgs e)
|
||||
{
|
||||
Avalonia.Threading.Dispatcher.UIThread.InvokeAsync(() =>
|
||||
{
|
||||
Close();
|
||||
});
|
||||
}
|
||||
|
||||
private void InitializeComponent()
|
||||
{
|
||||
AvaloniaXamlLoader.Load(this);
|
||||
}
|
||||
|
||||
private void MakeClickThrough()
|
||||
{
|
||||
if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
|
||||
{
|
||||
var style = GetWindowLong(this.PlatformImpl.Handle.Handle, GWL_EXSTYLE);
|
||||
|
||||
//PlatformImpl not part of formal Avalonia API and may not be available in future versions.
|
||||
SetWindowLong(this.PlatformImpl.Handle.Handle, GWL_EXSTYLE, style | WS_EX_LAYERED | WS_EX_TRANSPARENT);
|
||||
SetLayeredWindowAttributes(this.PlatformImpl.Handle.Handle, 0, 255, LWA_ALPHA);
|
||||
}
|
||||
else if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux))
|
||||
{
|
||||
// X11 stuff is not part of official API, we'll have to deal with reflection
|
||||
// This solution currently only supports the X11 window system which is used on most systems
|
||||
var type = this.PlatformImpl.GetType();
|
||||
if (type.FullName is not "Avalonia.X11.X11Window") return;
|
||||
|
||||
// Get the pointer to the X11 window
|
||||
var handlePropInfo = type.GetField("_handle", BindingFlags.NonPublic | BindingFlags.Instance);
|
||||
var handle = handlePropInfo?.GetValue(this.PlatformImpl);
|
||||
// Get the X11Info instance
|
||||
var x11PropInfo = type.GetField("_x11", BindingFlags.NonPublic | BindingFlags.Instance);
|
||||
var x11Info = x11PropInfo?.GetValue(this.PlatformImpl);
|
||||
// Get the pointer to the X11 display
|
||||
var displayPropInfo = x11Info?.GetType().GetProperty("Display");
|
||||
var display = displayPropInfo?.GetValue(x11Info);
|
||||
|
||||
if (display == null || handle == null) return;
|
||||
try
|
||||
{
|
||||
// Create a very tiny region
|
||||
var region = XFixesCreateRegion((IntPtr)display, IntPtr.Zero, 0);
|
||||
// Set the input shape of the window to our region
|
||||
XFixesSetWindowShapeRegion((IntPtr)display, (IntPtr)handle, ShapeInput, 0, 0, region);
|
||||
// Cleanup
|
||||
XFixesDestroyRegion((IntPtr)display, region);
|
||||
}
|
||||
catch
|
||||
{
|
||||
// libXfixes is not installed for some reason
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[DllImport("user32.dll", SetLastError = true)]
|
||||
static extern uint GetWindowLong(IntPtr hWnd, int nIndex);
|
||||
[DllImport("user32.dll", SetLastError = true)]
|
||||
static extern bool SetWindowPos(IntPtr hWnd, IntPtr hWndInsertAfter, int X, int Y, int cx, int cy, int uFlags);
|
||||
[DllImport("user32.dll")]
|
||||
static extern uint SetWindowLong(IntPtr hWnd, int nIndex, uint dwNewLong);
|
||||
[DllImport("user32.dll")]
|
||||
static extern bool SetLayeredWindowAttributes(IntPtr hwnd, uint crKey, byte bAlpha, uint dwFlags);
|
||||
|
||||
internal const int GWL_EXSTYLE = -20;
|
||||
internal const int WS_EX_LAYERED = 0x80000;
|
||||
internal const int LWA_ALPHA = 0x2;
|
||||
internal const int WS_EX_TRANSPARENT = 0x00000020;
|
||||
|
||||
[DllImport("libXfixes.so")]
|
||||
static extern IntPtr XFixesCreateRegion(IntPtr dpy, IntPtr rectangles, int nrectangles);
|
||||
|
||||
[DllImport("libXfixes.so")]
|
||||
static extern IntPtr XFixesSetWindowShapeRegion(IntPtr dpy, IntPtr win, int shape_kind, int x_off, int y_off, IntPtr region);
|
||||
|
||||
[DllImport("libXfixes.so")]
|
||||
static extern IntPtr XFixesDestroyRegion(IntPtr dpy, IntPtr region);
|
||||
|
||||
internal const int ShapeInput = 2;
|
||||
}
|
||||
}
|
@ -4,7 +4,7 @@ using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Observatory
|
||||
namespace Observatory.Utils
|
||||
{
|
||||
public static class ErrorReporter
|
||||
{
|
||||
@ -18,20 +18,7 @@ namespace Observatory
|
||||
displayMessage.AppendLine();
|
||||
displayMessage.Append("Full error details logged to ObservatoryErrorLog file in your documents folder.");
|
||||
|
||||
if (Avalonia.Application.Current.ApplicationLifetime is Avalonia.Controls.ApplicationLifetimes.IClassicDesktopStyleApplicationLifetime desktop)
|
||||
{
|
||||
Avalonia.Threading.Dispatcher.UIThread.InvokeAsync(() =>
|
||||
{
|
||||
var errorMessage = MessageBox.Avalonia.MessageBoxManager
|
||||
.GetMessageBoxStandardWindow(new MessageBox.Avalonia.DTO.MessageBoxStandardParams
|
||||
{
|
||||
ContentTitle = title,
|
||||
ContentMessage = displayMessage.ToString(),
|
||||
Topmost = true
|
||||
});
|
||||
errorMessage.Show();
|
||||
});
|
||||
}
|
||||
//TODO: Winform error popup
|
||||
|
||||
// Log entirety of errors out to file.
|
||||
var timestamp = DateTime.Now.ToString("G");
|
||||
@ -43,8 +30,8 @@ namespace Observatory
|
||||
errorLog.AppendLine();
|
||||
}
|
||||
|
||||
var docPath = System.Environment.GetFolderPath(System.Environment.SpecialFolder.MyDocuments);
|
||||
System.IO.File.AppendAllText(docPath + System.IO.Path.DirectorySeparatorChar + "ObservatoryErrorLog.txt", errorLog.ToString());
|
||||
var docPath = Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments);
|
||||
File.AppendAllText(docPath + Path.DirectorySeparatorChar + "ObservatoryErrorLog.txt", errorLog.ToString());
|
||||
|
||||
errorList.Clear();
|
||||
}
|
@ -1,7 +1,7 @@
|
||||
using System;
|
||||
using System.Net.Http;
|
||||
|
||||
namespace Observatory
|
||||
namespace Observatory.Utils
|
||||
{
|
||||
public sealed class HttpClient
|
||||
{
|
||||
@ -28,7 +28,7 @@ namespace Observatory
|
||||
return lazy.Value.SendAsync(request).Result;
|
||||
}
|
||||
|
||||
public static System.Threading.Tasks.Task<HttpResponseMessage> SendRequestAsync(HttpRequestMessage request)
|
||||
public static Task<HttpResponseMessage> SendRequestAsync(HttpRequestMessage request)
|
||||
{
|
||||
return lazy.Value.SendAsync(request);
|
||||
}
|
@ -6,7 +6,7 @@ using System.Text.Json;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
|
||||
namespace Observatory
|
||||
namespace Observatory.Utils
|
||||
{
|
||||
public class JournalReader
|
||||
{
|
||||
@ -26,7 +26,7 @@ namespace Observatory
|
||||
while ((eventType == string.Empty || timestamp == string.Empty) && reader.Read())
|
||||
{
|
||||
if (reader.TokenType == JsonTokenType.PropertyName)
|
||||
{
|
||||
{
|
||||
if (reader.GetString() == "event")
|
||||
{
|
||||
reader.Read();
|
||||
@ -58,7 +58,7 @@ namespace Observatory
|
||||
}
|
||||
|
||||
deserialized = (TJournal)Convert.ChangeType(invalidJson, typeof(TJournal));
|
||||
|
||||
|
||||
}
|
||||
//Journal potentially had invalid JSON for a brief period in 2017, check for it and remove.
|
||||
//TODO: Check if this gets handled by InvalidJson now.
|
@ -8,7 +8,7 @@ using System.Text.RegularExpressions;
|
||||
using Observatory.Framework;
|
||||
using Observatory.Framework.Files;
|
||||
|
||||
namespace Observatory
|
||||
namespace Observatory.Utils
|
||||
{
|
||||
class LogMonitor
|
||||
{
|
||||
@ -120,12 +120,12 @@ namespace Observatory
|
||||
|
||||
DirectoryInfo logDirectory = GetJournalFolder(Properties.Core.Default.JournalFolder);
|
||||
var files = GetJournalFilesOrdered(logDirectory);
|
||||
|
||||
|
||||
// Read at most the last two files (in case we were launched after the game and the latest
|
||||
// journal is mostly empty) but keeping only the lines since the last FSDJump.
|
||||
List<String> lastSystemLines = new();
|
||||
List<String> lastFileLines = new();
|
||||
string lastLoadGame = String.Empty;
|
||||
List<string> lastSystemLines = new();
|
||||
List<string> lastFileLines = new();
|
||||
string lastLoadGame = string.Empty;
|
||||
bool sawFSDJump = false;
|
||||
foreach (var file in files.Skip(Math.Max(files.Count() - 2, 0)))
|
||||
{
|
||||
@ -133,7 +133,7 @@ namespace Observatory
|
||||
foreach (var line in lines)
|
||||
{
|
||||
var eventType = JournalUtilities.GetEventType(line);
|
||||
if (eventType.Equals("FSDJump") || (eventType.Equals("CarrierJump") && line.Contains("\"Docked\":true")))
|
||||
if (eventType.Equals("FSDJump") || eventType.Equals("CarrierJump") && line.Contains("\"Docked\":true"))
|
||||
{
|
||||
// Reset, start collecting again.
|
||||
lastSystemLines.Clear();
|
||||
@ -162,7 +162,7 @@ namespace Observatory
|
||||
{
|
||||
// If we saw a LoadGame, insert it as well. This ensures odyssey biologicials are properly
|
||||
// counted/presented.
|
||||
if (!String.IsNullOrEmpty(lastLoadGame))
|
||||
if (!string.IsNullOrEmpty(lastLoadGame))
|
||||
{
|
||||
lastSystemLines.Insert(0, lastLoadGame);
|
||||
}
|
||||
@ -193,14 +193,14 @@ namespace Observatory
|
||||
private Dictionary<string, int> currentLine;
|
||||
private LogMonitorState currentState = LogMonitorState.Idle; // Change via #SetLogMonitorState
|
||||
private bool firstStartMonitor = true;
|
||||
private string[] EventsWithAncillaryFile = new string[]
|
||||
{
|
||||
"Cargo",
|
||||
"NavRoute",
|
||||
"Market",
|
||||
"Outfitting",
|
||||
"Shipyard",
|
||||
"Backpack",
|
||||
private string[] EventsWithAncillaryFile = new string[]
|
||||
{
|
||||
"Cargo",
|
||||
"NavRoute",
|
||||
"Market",
|
||||
"Outfitting",
|
||||
"Shipyard",
|
||||
"Backpack",
|
||||
"FCMaterials",
|
||||
"ModuleInfo",
|
||||
"ShipLocker"
|
||||
@ -218,7 +218,7 @@ namespace Observatory
|
||||
{
|
||||
PreviousState = oldState,
|
||||
NewState = newState
|
||||
});;
|
||||
}); ;
|
||||
|
||||
System.Diagnostics.Debug.WriteLine("LogMonitor State change: {0} -> {1}", oldState, newState);
|
||||
}
|
||||
@ -267,7 +267,7 @@ namespace Observatory
|
||||
else if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows) || RuntimeInformation.IsOSPlatform(OSPlatform.Linux))
|
||||
{
|
||||
string defaultJournalPath = RuntimeInformation.IsOSPlatform(OSPlatform.Linux)
|
||||
? Environment.GetFolderPath(Environment.SpecialFolder.UserProfile)
|
||||
? Environment.GetFolderPath(Environment.SpecialFolder.UserProfile)
|
||||
+ "/.steam/debian-installation/steamapps/compatdata/359320/pfx/drive_c/users/steamuser/Saved Games/Frontier Developments/Elite Dangerous"
|
||||
: GetSavedGamesPath() + @"\Frontier Developments\Elite Dangerous";
|
||||
|
||||
@ -290,7 +290,7 @@ namespace Observatory
|
||||
return logDirectory;
|
||||
}
|
||||
|
||||
private List<(Exception ex, string file, string line)> ProcessLines(List<String> lines, string file)
|
||||
private List<(Exception ex, string file, string line)> ProcessLines(List<string> lines, string file)
|
||||
{
|
||||
var readErrors = new List<(Exception ex, string file, string line)>();
|
||||
foreach (var line in lines)
|
||||
@ -309,7 +309,7 @@ namespace Observatory
|
||||
|
||||
private JournalEventArgs DeserializeToEventArgs(string eventType, string line)
|
||||
{
|
||||
|
||||
|
||||
var eventClass = journalTypes[eventType];
|
||||
MethodInfo journalRead = typeof(JournalReader).GetMethod(nameof(JournalReader.ObservatoryDeserializer));
|
||||
MethodInfo journalGeneric = journalRead.MakeGenericMethod(eventClass);
|
||||
@ -326,7 +326,7 @@ namespace Observatory
|
||||
}
|
||||
|
||||
var journalEvent = DeserializeToEventArgs(eventType, line);
|
||||
|
||||
|
||||
JournalEntry?.Invoke(this, journalEvent);
|
||||
|
||||
// Files are only valid if realtime, otherwise they will be stale or empty.
|
||||
@ -345,16 +345,16 @@ namespace Observatory
|
||||
// I have no idea what order Elite writes these files or if they're already written
|
||||
// by the time the journal updates.
|
||||
// Brief sleep to ensure the content is updated before we read it.
|
||||
|
||||
|
||||
// Some files are still locked by another process after 50ms.
|
||||
// Retry every 50ms for 0.5 seconds before giving up.
|
||||
|
||||
string fileContent = null;
|
||||
int retryCount = 0;
|
||||
|
||||
|
||||
while (fileContent == null && retryCount < 10)
|
||||
{
|
||||
System.Threading.Thread.Sleep(50);
|
||||
Thread.Sleep(50);
|
||||
try
|
||||
{
|
||||
using var fileStream = File.Open(journalWatcher.Path + Path.DirectorySeparatorChar + filename, FileMode.Open, FileAccess.Read, FileShare.ReadWrite);
|
||||
@ -389,7 +389,7 @@ namespace Observatory
|
||||
});
|
||||
|
||||
ErrorReporter.ShowErrorPopup($"Journal Read Error{(readErrors.Count > 1 ? "s" : "")}", errorList.ToList());
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@ -462,8 +462,8 @@ namespace Observatory
|
||||
{
|
||||
var journalFolder = GetJournalFolder();
|
||||
|
||||
await System.Threading.Tasks.Task.Run(() =>
|
||||
{
|
||||
await Task.Run(() =>
|
||||
{
|
||||
while (IsMonitoring())
|
||||
{
|
||||
var journals = GetJournalFilesOrdered(journalFolder);
|
||||
@ -475,7 +475,7 @@ namespace Observatory
|
||||
using FileStream stream = fileToPoke.Open(FileMode.Open, FileAccess.Read, FileShare.ReadWrite);
|
||||
stream.Close();
|
||||
}
|
||||
System.Threading.Thread.Sleep(250);
|
||||
Thread.Sleep(250);
|
||||
}
|
||||
});
|
||||
}
|
@ -1,23 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Observatory.Framework
|
||||
{
|
||||
public class BasicGrid
|
||||
{
|
||||
public BasicGrid()
|
||||
{
|
||||
Headers = new();
|
||||
Formats = new();
|
||||
Items = new();
|
||||
}
|
||||
|
||||
public readonly ObservableCollection<string> Headers;
|
||||
public readonly ObservableCollection<string> Formats;
|
||||
public readonly ObservableCollection<ObservableCollection<object>> Items;
|
||||
}
|
||||
}
|
@ -135,7 +135,7 @@ namespace Observatory.Framework.Interfaces
|
||||
/// <param name="notificationEventArgs">NotificationArgs object specifying notification content and behaviour.</param>
|
||||
/// <returns>Guid associated with the notification during its lifetime. Used as an argument with CancelNotification and UpdateNotification.</returns>
|
||||
public Guid SendNotification(NotificationArgs notificationEventArgs);
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Cancel or close an active notification.
|
||||
/// </summary>
|
||||
@ -154,7 +154,14 @@ namespace Observatory.Framework.Interfaces
|
||||
/// </summary>
|
||||
/// <param name="worker">Reference to the calling plugin's worker interface.</param>
|
||||
/// <param name="item">Grid item to be added. Object type should match original template item used to create the grid.</param>
|
||||
public void AddGridItem(IObservatoryWorker worker, List<object> item);
|
||||
public void AddGridItem(IObservatoryWorker worker, object item);
|
||||
|
||||
/// <summary>
|
||||
/// Add multiple items to the bottom of the basic UI grid.
|
||||
/// </summary>
|
||||
/// <param name="worker">Reference to the calling plugin's worker interface.</param>
|
||||
/// <param name="items">Grid items to be added. Object types should match original template item used to create the grid.</param>
|
||||
public void AddGridItems(IObservatoryWorker worker, IEnumerable<object> items);
|
||||
|
||||
/// <summary>
|
||||
/// Add multiple items to the bottom of the basic UI grid.
|
||||
@ -167,7 +174,8 @@ namespace Observatory.Framework.Interfaces
|
||||
/// Clears basic UI grid, removing all items.
|
||||
/// </summary>
|
||||
/// <param name="worker">Reference to the calling plugin's worker interface.</param>
|
||||
public void ClearGrid(IObservatoryWorker worker);
|
||||
/// <param name="templateItem">Template item used to re-initialise the grid.</param>
|
||||
public void ClearGrid(IObservatoryWorker worker, object templateItem);
|
||||
|
||||
/// <summary>
|
||||
/// Requests current Elite Dangerous status.json content.
|
||||
@ -185,7 +193,7 @@ namespace Observatory.Framework.Interfaces
|
||||
/// or pass it along to its collaborators.
|
||||
/// </summary>
|
||||
/// <param name="plugin">The calling plugin</param>
|
||||
public Action<Exception, String> GetPluginErrorLogger (IObservatoryPlugin plugin);
|
||||
public Action<Exception, String> GetPluginErrorLogger(IObservatoryPlugin plugin);
|
||||
|
||||
/// <summary>
|
||||
/// Perform an action on the current Avalonia UI thread.
|
||||
|
@ -1439,18 +1439,26 @@
|
||||
<param name="notificationId">Guid of notification to be updated.</param>
|
||||
<param name="notificationEventArgs">NotificationArgs object specifying updated notification content and behaviour.</param>
|
||||
</member>
|
||||
<member name="M:Observatory.Framework.Interfaces.IObservatoryCore.AddGridItem(Observatory.Framework.Interfaces.IObservatoryWorker,System.Collections.Generic.List{System.Object})">
|
||||
<member name="M:Observatory.Framework.Interfaces.IObservatoryCore.AddGridItem(Observatory.Framework.Interfaces.IObservatoryWorker,System.Object)">
|
||||
<summary>
|
||||
Add an item to the bottom of the basic UI grid.
|
||||
</summary>
|
||||
<param name="worker">Reference to the calling plugin's worker interface.</param>
|
||||
<param name="item">Grid item to be added. Object type should match original template item used to create the grid.</param>
|
||||
</member>
|
||||
<member name="M:Observatory.Framework.Interfaces.IObservatoryCore.ClearGrid(Observatory.Framework.Interfaces.IObservatoryWorker)">
|
||||
<member name="M:Observatory.Framework.Interfaces.IObservatoryCore.AddGridItems(Observatory.Framework.Interfaces.IObservatoryWorker,System.Collections.Generic.IEnumerable{System.Object})">
|
||||
<summary>
|
||||
Add multiple items to the bottom of the basic UI grid.
|
||||
</summary>
|
||||
<param name="worker">Reference to the calling plugin's worker interface.</param>
|
||||
<param name="items">Grid items to be added. Object types should match original template item used to create the grid.</param>
|
||||
</member>
|
||||
<member name="M:Observatory.Framework.Interfaces.IObservatoryCore.ClearGrid(Observatory.Framework.Interfaces.IObservatoryWorker,System.Object)">
|
||||
<summary>
|
||||
Clears basic UI grid, removing all items.
|
||||
</summary>
|
||||
<param name="worker">Reference to the calling plugin's worker interface.</param>
|
||||
<param name="templateItem">Template item used to re-initialise the grid.</param>
|
||||
</member>
|
||||
<member name="M:Observatory.Framework.Interfaces.IObservatoryCore.GetStatus">
|
||||
<summary>
|
||||
@ -1512,12 +1520,13 @@
|
||||
<para>(Untested/not implemented)</para>
|
||||
</summary>
|
||||
</member>
|
||||
<member name="F:Observatory.Framework.PluginUI.BasicGrid">
|
||||
<member name="F:Observatory.Framework.PluginUI.DataGrid">
|
||||
<summary>
|
||||
<para>>Two-dimensional collection of items to display in UI grid for UIType.Basic</para>
|
||||
<para>Collection bound to DataGrid used byu plugins with UIType.Basic.</para>
|
||||
<para>Objects in collection should be of a class defined within the plugin consisting of string properties.<br/>Each object is a single row, and the property names are used as column headers.</para>
|
||||
</summary>
|
||||
</member>
|
||||
<member name="M:Observatory.Framework.PluginUI.#ctor(Observatory.Framework.BasicGrid)">
|
||||
<member name="M:Observatory.Framework.PluginUI.#ctor(System.Collections.ObjectModel.ObservableCollection{System.Object})">
|
||||
<summary>
|
||||
Instantiate PluginUI of UIType.Basic.
|
||||
</summary>
|
||||
@ -1546,12 +1555,12 @@
|
||||
</member>
|
||||
<member name="F:Observatory.Framework.PluginUI.UIType.Basic">
|
||||
<summary>
|
||||
Simple DataGrid, to which items can be added or removed.
|
||||
Simple listview, to which items can be added or removed.
|
||||
</summary>
|
||||
</member>
|
||||
<member name="F:Observatory.Framework.PluginUI.UIType.Avalonia">
|
||||
<member name="F:Observatory.Framework.PluginUI.UIType.Panel">
|
||||
<summary>
|
||||
AvaloniaUI control which is placed in plugin tab.
|
||||
Panel control which is placed in plugin tab.
|
||||
</summary>
|
||||
</member>
|
||||
<member name="F:Observatory.Framework.PluginUI.UIType.Core">
|
||||
|
@ -23,9 +23,10 @@ namespace Observatory.Framework
|
||||
public object UI;
|
||||
|
||||
/// <summary>
|
||||
/// <para>>Two-dimensional collection of items to display in UI grid for UIType.Basic</para>
|
||||
/// <para>Collection bound to DataGrid used byu plugins with UIType.Basic.</para>
|
||||
/// <para>Objects in collection should be of a class defined within the plugin consisting of string properties.<br/>Each object is a single row, and the property names are used as column headers.</para>
|
||||
/// </summary>
|
||||
public BasicGrid BasicGrid;
|
||||
public ObservableCollection<object> DataGrid;
|
||||
|
||||
/// <summary>
|
||||
/// Instantiate PluginUI of UIType.Basic.
|
||||
@ -34,10 +35,10 @@ namespace Observatory.Framework
|
||||
/// <para>Collection bound to DataGrid used byu plugins with UIType.Basic.</para>
|
||||
/// <para>Objects in collection should be of a class defined within the plugin consisting of string properties.<br/>Each object is a single row, and the property names are used as column headers.</para>
|
||||
/// </param>
|
||||
public PluginUI(BasicGrid basicGrid)
|
||||
public PluginUI(ObservableCollection<object> DataGrid)
|
||||
{
|
||||
PluginUIType = UIType.Basic;
|
||||
BasicGrid = basicGrid;
|
||||
this.DataGrid = DataGrid;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@ -62,13 +63,13 @@ namespace Observatory.Framework
|
||||
/// </summary>
|
||||
None = 0,
|
||||
/// <summary>
|
||||
/// Simple DataGrid, to which items can be added or removed.
|
||||
/// Simple listview, to which items can be added or removed.
|
||||
/// </summary>
|
||||
Basic = 1,
|
||||
/// <summary>
|
||||
/// AvaloniaUI control which is placed in plugin tab.
|
||||
/// Panel control which is placed in plugin tab.
|
||||
/// </summary>
|
||||
Avalonia = 2,
|
||||
Panel = 2,
|
||||
/// <summary>
|
||||
/// UI used by Observatory Core settings tab.<br/>
|
||||
/// Not intended for use by plugins.
|
||||
|
Loading…
x
Reference in New Issue
Block a user