1
0
mirror of synced 2024-12-22 00:53:08 +01:00

Added Run Program plugin

Added Author and URL display in Plugins list
This commit is contained in:
Mark van Renswoude 2021-03-10 12:39:41 +01:00
parent 4974e57221
commit bc8396795c
18 changed files with 653 additions and 7 deletions

View File

@ -0,0 +1,91 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ProjectGuid>{BB1E8BA4-7965-4E46-B1BE-D2A7C491A204}</ProjectGuid>
<OutputType>Library</OutputType>
<AppDesignerFolder>Properties</AppDesignerFolder>
<RootNamespace>MassiveKnob.Plugin.RunProgram</RootNamespace>
<AssemblyName>MassiveKnob.Plugin.RunProgram</AssemblyName>
<TargetFrameworkVersion>v4.7.2</TargetFrameworkVersion>
<FileAlignment>512</FileAlignment>
<Deterministic>true</Deterministic>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>bin\Debug\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<DebugType>pdbonly</DebugType>
<Optimize>true</Optimize>
<OutputPath>bin\Release\</OutputPath>
<DefineConstants>TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<ItemGroup>
<Reference Include="PresentationCore" />
<Reference Include="PresentationFramework" />
<Reference Include="System" />
<Reference Include="System.Core" />
<Reference Include="System.Xaml" />
<Reference Include="System.Xml.Linq" />
<Reference Include="System.Data.DataSetExtensions" />
<Reference Include="Microsoft.CSharp" />
<Reference Include="System.Data" />
<Reference Include="System.Net.Http" />
<Reference Include="System.Xml" />
<Reference Include="WindowsBase" />
</ItemGroup>
<ItemGroup>
<Compile Include="MassiveKnobRunProgramPlugin.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="RunProgram\RunProgramSettingsView.xaml.cs">
<DependentUpon>RunProgramSettingsView.xaml</DependentUpon>
</Compile>
<Compile Include="RunProgram\RunProgramAction.cs" />
<Compile Include="RunProgram\RunProgramSettings.cs" />
<Compile Include="RunProgram\RunProgramSettingsViewModel.cs" />
<Compile Include="Strings.Designer.cs">
<DependentUpon>Strings.resx</DependentUpon>
<AutoGen>True</AutoGen>
<DesignTime>True</DesignTime>
</Compile>
</ItemGroup>
<ItemGroup>
<None Include="MassiveKnobPlugin.json">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None>
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\MassiveKnob.Plugin\MassiveKnob.Plugin.csproj">
<Project>{A1298BE4-1D23-416C-8C56-FC9264487A95}</Project>
<Name>MassiveKnob.Plugin</Name>
</ProjectReference>
</ItemGroup>
<ItemGroup>
<EmbeddedResource Include="Strings.resx">
<Generator>PublicResXFileCodeGenerator</Generator>
<LastGenOutput>Strings.Designer.cs</LastGenOutput>
</EmbeddedResource>
</ItemGroup>
<ItemGroup>
<PackageReference Include="System.Threading.Tasks.Extensions">
<Version>4.5.4</Version>
</PackageReference>
</ItemGroup>
<ItemGroup>
<Page Include="RunProgram\RunProgramSettingsView.xaml">
<Generator>MSBuild:Compile</Generator>
<SubType>Designer</SubType>
</Page>
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
</Project>

View File

@ -0,0 +1,3 @@
{
"EntryAssembly": "MassiveKnob.Plugin.RunProgram.dll"
}

View File

@ -0,0 +1,21 @@
using System;
using System.Collections.Generic;
using MassiveKnob.Plugin.RunProgram.RunProgram;
namespace MassiveKnob.Plugin.RunProgram
{
[MassiveKnobPlugin]
public class MassiveKnobRunProgramPlugin : IMassiveKnobActionPlugin
{
public Guid PluginId { get; } = new Guid("10537f2a-6876-48b8-8ef9-8d05f185fa62");
public string Name { get; } = Strings.PluginName;
public string Description { get; } = Strings.PluginDescription;
public string Author { get; } = "Mark van Renswoude <mark@x2software.net>";
public string Url { get; } = "https://www.github.com/MvRens/MassiveKnob/";
public IEnumerable<IMassiveKnobAction> Actions { get; } = new IMassiveKnobAction[]
{
new RunProgramAction()
};
}
}

View File

@ -0,0 +1,36 @@
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
// General Information about an assembly is controlled through the following
// set of attributes. Change these attribute values to modify the information
// associated with an assembly.
[assembly: AssemblyTitle("MassiveKnob.Plugin.RunProgram")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("MassiveKnob.Plugin.RunProgram")]
[assembly: AssemblyCopyright("Copyright © 2021")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
// Setting ComVisible to false makes the types in this assembly not visible
// to COM components. If you need to access a type in this assembly from
// COM, set the ComVisible attribute to true on that type.
[assembly: ComVisible(false)]
// The following GUID is for the ID of the typelib if this project is exposed to COM
[assembly: Guid("bb1e8ba4-7965-4e46-b1be-d2a7c491a204")]
// Version information for an assembly consists of the following four values:
//
// Major Version
// Minor Version
// Build Number
// Revision
//
// You can specify all the values or you can default the Build and Revision Numbers
// by using the '*' as shown below:
// [assembly: AssemblyVersion("1.0.*")]
[assembly: AssemblyVersion("1.0.0.0")]
[assembly: AssemblyFileVersion("1.0.0.0")]

View File

@ -0,0 +1,81 @@
using System;
using System.Diagnostics;
using System.Threading.Tasks;
using System.Windows.Controls;
using Microsoft.Extensions.Logging;
namespace MassiveKnob.Plugin.RunProgram.RunProgram
{
public class RunProgramAction : IMassiveKnobAction
{
public Guid ActionId { get; } = new Guid("c3a79015-4b8f-414d-9682-02307de8639c");
public MassiveKnobActionType ActionType { get; } = MassiveKnobActionType.InputDigital;
public string Name { get; } = Strings.RunProgramName;
public string Description { get; } = Strings.RunProgramDescription;
public IMassiveKnobActionInstance Create(ILogger logger)
{
return new Instance(logger);
}
private class Instance : IMassiveKnobDigitalAction
{
private readonly ILogger logger;
private IMassiveKnobActionContext actionContext;
private RunProgramSettings settings;
public Instance(ILogger logger)
{
this.logger = logger;
}
public void Initialize(IMassiveKnobActionContext context)
{
actionContext = context;
settings = context.GetSettings<RunProgramSettings>();
}
public void Dispose()
{
}
public UserControl CreateSettingsControl()
{
var viewModel = new RunProgramSettingsViewModel(settings);
viewModel.PropertyChanged += (sender, args) =>
{
actionContext.SetSettings(settings);
};
return new RunProgramSettingsView(viewModel);
}
public ValueTask DigitalChanged(bool on)
{
if (!on)
return default;
if (string.IsNullOrEmpty(settings.Filename))
return default;
logger.LogInformation("Run program: filename = {filename}, arguments = {arguments}", settings.Filename, settings.Arguments);
Process.Start(new ProcessStartInfo
{
FileName = settings.Filename,
Arguments = settings.Arguments,
UseShellExecute = true,
Verb = "open"
});
return default;
}
}
}
}

View File

@ -0,0 +1,8 @@
namespace MassiveKnob.Plugin.RunProgram.RunProgram
{
public class RunProgramSettings
{
public string Filename { get; set; }
public string Arguments { get; set; }
}
}

View File

@ -0,0 +1,21 @@
<UserControl x:Class="MassiveKnob.Plugin.RunProgram.RunProgram.RunProgramSettingsView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:strings="clr-namespace:MassiveKnob.Plugin.RunProgram"
xmlns:runProgram="clr-namespace:MassiveKnob.Plugin.RunProgram.RunProgram"
mc:Ignorable="d"
d:DesignHeight="200" d:DesignWidth="800"
d:DataContext="{d:DesignInstance runProgram:RunProgramSettingsViewModel}">
<StackPanel Orientation="Vertical">
<TextBlock Text="{x:Static strings:Strings.SettingFilename}" />
<DockPanel>
<Button Click="ButtonBrowseClick" DockPanel.Dock="Right" Padding="4,0,4,0">...</Button>
<TextBox Text="{Binding Filename}" />
</DockPanel>
<TextBlock Text="{x:Static strings:Strings.SettingArguments}" Margin="0,8,0,0" />
<TextBox Text="{Binding Arguments}" />
</StackPanel>
</UserControl>

View File

@ -0,0 +1,27 @@
using System.Windows;
namespace MassiveKnob.Plugin.RunProgram.RunProgram
{
/// <summary>
/// Interaction logic for RunProgramSettingsView.xaml
/// </summary>
public partial class RunProgramSettingsView
{
public RunProgramSettingsView(RunProgramSettingsViewModel viewModel)
{
DataContext = viewModel;
InitializeComponent();
}
private void ButtonBrowseClick(object sender, RoutedEventArgs e)
{
var dialog = new Microsoft.Win32.OpenFileDialog
{
Filter = Strings.FilenameDialogFilter
};
if (dialog.ShowDialog().GetValueOrDefault())
((RunProgramSettingsViewModel) DataContext).Filename = dialog.FileName;
}
}
}

View File

@ -0,0 +1,53 @@
using System.ComponentModel;
using System.Runtime.CompilerServices;
namespace MassiveKnob.Plugin.RunProgram.RunProgram
{
public class RunProgramSettingsViewModel : INotifyPropertyChanged
{
private readonly RunProgramSettings settings;
// ReSharper disable UnusedMember.Global - used by WPF Binding
public string Filename
{
get => settings.Filename;
set
{
if (value == settings.Filename)
return;
settings.Filename = value;
OnPropertyChanged();
}
}
public string Arguments
{
get => settings.Arguments;
set
{
if (value == settings.Arguments)
return;
settings.Arguments = value;
OnPropertyChanged();
}
}
// ReSharper restore UnusedMember.Global
public RunProgramSettingsViewModel(RunProgramSettings settings)
{
this.settings = settings;
}
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
}

View File

@ -0,0 +1,126 @@
//------------------------------------------------------------------------------
// <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 MassiveKnob.Plugin.RunProgram {
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", "16.0.0.0")]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
public class Strings {
private static global::System.Resources.ResourceManager resourceMan;
private static global::System.Globalization.CultureInfo resourceCulture;
[global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
internal Strings() {
}
/// <summary>
/// Returns the cached ResourceManager instance used by this class.
/// </summary>
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
public static global::System.Resources.ResourceManager ResourceManager {
get {
if (object.ReferenceEquals(resourceMan, null)) {
global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("MassiveKnob.Plugin.RunProgram.Strings", typeof(Strings).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)]
public static global::System.Globalization.CultureInfo Culture {
get {
return resourceCulture;
}
set {
resourceCulture = value;
}
}
/// <summary>
/// Looks up a localized string similar to Executable files (*.exe, *.bat, *.cmd)|*.exe,*.bat,*.cmd|All files (*.*)|*.*.
/// </summary>
public static string FilenameDialogFilter {
get {
return ResourceManager.GetString("FilenameDialogFilter", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Provides an action to run an application when a button is pressed..
/// </summary>
public static string PluginDescription {
get {
return ResourceManager.GetString("PluginDescription", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Run Program.
/// </summary>
public static string PluginName {
get {
return ResourceManager.GetString("PluginName", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Runs an application when a button is pressed..
/// </summary>
public static string RunProgramDescription {
get {
return ResourceManager.GetString("RunProgramDescription", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Run program.
/// </summary>
public static string RunProgramName {
get {
return ResourceManager.GetString("RunProgramName", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Optional arguments passed to the executable.
/// </summary>
public static string SettingArguments {
get {
return ResourceManager.GetString("SettingArguments", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Executable, file or URL to open.
/// </summary>
public static string SettingFilename {
get {
return ResourceManager.GetString("SettingFilename", resourceCulture);
}
}
}
}

View File

@ -0,0 +1,141 @@
<?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>
<data name="FilenameDialogFilter" xml:space="preserve">
<value>Executable files (*.exe, *.bat, *.cmd)|*.exe,*.bat,*.cmd|All files (*.*)|*.*</value>
</data>
<data name="PluginDescription" xml:space="preserve">
<value>Provides an action to run an application when a button is pressed.</value>
</data>
<data name="PluginName" xml:space="preserve">
<value>Run Program</value>
</data>
<data name="RunProgramDescription" xml:space="preserve">
<value>Runs an application when a button is pressed.</value>
</data>
<data name="RunProgramName" xml:space="preserve">
<value>Run program</value>
</data>
<data name="SettingArguments" xml:space="preserve">
<value>Optional arguments passed to the executable</value>
</data>
<data name="SettingFilename" xml:space="preserve">
<value>Executable, file or URL to open</value>
</data>
</root>

View File

@ -1,7 +1,5 @@
using System;
// ReSharper disable UnusedMember.Global - public API
namespace MassiveKnob.Plugin
{
/// <summary>

View File

@ -21,6 +21,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MassiveKnob.Plugin.VoiceMee
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Voicemeeter", "VoicemeeterRemote\Voicemeeter\Voicemeeter.csproj", "{F35DD8E5-91FA-403E-B6F6-8D2B4AE84198}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MassiveKnob.Plugin.RunProgram", "MassiveKnob.Plugin.RunProgram\MassiveKnob.Plugin.RunProgram.csproj", "{BB1E8BA4-7965-4E46-B1BE-D2A7C491A204}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@ -63,6 +65,10 @@ Global
{F35DD8E5-91FA-403E-B6F6-8D2B4AE84198}.Debug|Any CPU.Build.0 = Debug|Any CPU
{F35DD8E5-91FA-403E-B6F6-8D2B4AE84198}.Release|Any CPU.ActiveCfg = Release|Any CPU
{F35DD8E5-91FA-403E-B6F6-8D2B4AE84198}.Release|Any CPU.Build.0 = Release|Any CPU
{BB1E8BA4-7965-4E46-B1BE-D2A7C491A204}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{BB1E8BA4-7965-4E46-B1BE-D2A7C491A204}.Debug|Any CPU.Build.0 = Debug|Any CPU
{BB1E8BA4-7965-4E46-B1BE-D2A7C491A204}.Release|Any CPU.ActiveCfg = Release|Any CPU
{BB1E8BA4-7965-4E46-B1BE-D2A7C491A204}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE

View File

@ -56,4 +56,15 @@
<Setter Property="TextWrapping" Value="Wrap" />
<Setter Property="Foreground" Value="#808080" />
</Style>
<Style TargetType="TextBlock" x:Key="PluginAuthor">
<Setter Property="TextTrimming" Value="CharacterEllipsis" />
<Setter Property="Margin" Value="0,8,0,0" />
</Style>
<Style TargetType="TextBlock" x:Key="PluginUrl">
<Setter Property="TextTrimming" Value="CharacterEllipsis" />
<Setter Property="Foreground" Value="Navy" />
<Setter Property="Margin" Value="0,0,0,8" />
</Style>
</ResourceDictionary>

View File

@ -21,6 +21,8 @@
<StackPanel Orientation="Vertical" Margin="0,0,0,24">
<TextBlock Text="{Binding Name}" Style="{StaticResource PluginName}" />
<TextBlock Text="{Binding Description}" Visibility="{Binding DescriptionVisibility}" Style="{StaticResource PluginDescription}" />
<TextBlock Text="{Binding Author}" Visibility="{Binding AuthorVisibility}" Style="{StaticResource PluginAuthor}" />
<TextBlock Text="{Binding Url}" Cursor="{x:Static Cursors.Hand}" MouseDown="UrlMouseDown" Visibility="{Binding UrlVisibility}" Style="{StaticResource PluginUrl}" />
<TextBlock Text="{Binding Filename}" Style="{StaticResource PluginFilename}" />
</StackPanel>
</DataTemplate>

View File

@ -1,4 +1,8 @@
using MassiveKnob.ViewModel.Settings;
using System.Diagnostics;
using System.Windows;
using System.Windows.Input;
using MassiveKnob.ViewModel;
using MassiveKnob.ViewModel.Settings;
namespace MassiveKnob.View.Settings
{
@ -12,5 +16,16 @@ namespace MassiveKnob.View.Settings
DataContext = viewModel;
InitializeComponent();
}
private void UrlMouseDown(object sender, MouseButtonEventArgs e)
{
var dataContext = ((FrameworkElement) e.Source).DataContext;
Process.Start(new ProcessStartInfo
{
FileName = ((PluginViewModel) dataContext).Url,
Verb = "open"
});
}
}
}

View File

@ -8,16 +8,22 @@ namespace MassiveKnob.ViewModel
public string Name { get; }
public string Description { get; }
public string Filename { get; }
public string Author { get; }
public string Url { get; }
public Visibility DescriptionVisibility => string.IsNullOrEmpty(Description) ? Visibility.Collapsed : Visibility.Visible;
public Visibility AuthorVisibility => string.IsNullOrEmpty(Author) ? Visibility.Collapsed : Visibility.Visible;
public Visibility UrlVisibility => string.IsNullOrEmpty(Url) ? Visibility.Collapsed : Visibility.Visible;
// ReSharper restore UnusedMember.Global
public PluginViewModel(string name, string description, string filename)
public PluginViewModel(string name, string description, string filename, string author, string url)
{
Name = name;
Description = description;
Filename = filename;
Author = author;
Url = url;
}
}
}

View File

@ -19,7 +19,7 @@ namespace MassiveKnob.ViewModel.Settings
return;
Plugins = pluginManager.GetPlugins()
.Select(p => new PluginViewModel(p.Plugin.Name, p.Plugin.Description, p.Filename))
.Select(p => new PluginViewModel(p.Plugin.Name, p.Plugin.Description, p.Filename, p.Plugin.Author, p.Plugin.Url))
.OrderBy(p => p.Name, StringComparer.CurrentCultureIgnoreCase)
.ToList();
}
@ -33,8 +33,8 @@ namespace MassiveKnob.ViewModel.Settings
{
Plugins = new[]
{
new PluginViewModel("Plugin without description", null, "D:\\Does\\Not\\Exist.dll"),
new PluginViewModel("Design-time plugin", "Fake plugin only visible at design-time.", "C:\\Does\\Not\\Exist.dll")
new PluginViewModel("Plugin without description", null, "D:\\Does\\Not\\Exist.dll", "Some Massive Knob <massive@knob.org>", "https://lmgtfy.app/?q=Massive+Knob"),
new PluginViewModel("Design-time plugin", "Fake plugin only visible at design-time.", "C:\\Does\\Not\\Exist.dll", null, null)
};
}
}