Compare commits

...

15 Commits
2.3 ... 2.8

Author SHA1 Message Date
Frank Skare
b93972c7f7 - 2019-04-12 18:01:23 +02:00
Frank Skare
1bae00051b - 2019-04-12 16:12:12 +02:00
Frank Skare
b75bae3c38 2.6 2019-04-09 05:09:43 +02:00
Frank Skare
2e435dcdc0 2.6 2019-04-09 04:57:29 +02:00
Frank Skare
fec33056cb 2.5 2019-04-08 04:38:17 +02:00
Frank Skare
0836b63439 2.5 2019-04-08 04:22:09 +02:00
Frank Skare
2b5dbfa19f - 2019-04-07 02:39:39 +02:00
Frank Skare
b6072f03bf - 2019-04-07 00:29:04 +02:00
Frank Skare
4492a423b4 - 2019-04-06 16:03:46 +02:00
Frank Skare
39f6f4de0d - 2019-04-06 02:10:41 +02:00
Frank Skare
b16bcd0295 - 2019-04-05 15:49:01 +02:00
Frank Skare
1caa814c95 - 2019-04-04 19:48:00 +02:00
Frank Skare
bbf0f6e127 - 2019-04-04 19:43:41 +02:00
Frank Skare
22bd5a5999 - 2019-04-04 19:39:00 +02:00
Frank Skare
cb146c1cf1 - 2019-04-04 19:37:25 +02:00
58 changed files with 2143 additions and 537 deletions

View File

@@ -20,11 +20,11 @@ Table of contents
### Features ### Features
- Customizable context menu defined in the same file as the key bindings - Customizable context menu defined in the same file as the key bindings
- a searchable options dialog with modern UI - Searchable options dialog with modern UI as mpv compatible standalone application
- a searchable keyboard shortcut editor - Searchable input (key/mouse) binding editor with modern UI as mpv compatible standalone application
- Addon API for .NET languages - Rich addon API for .NET languages
- Scripting API for Python, C#, Lua, JavaScript and PowerShell - Rich scripting API for Python, C#, Lua, JavaScript and PowerShell
- mpv's OSC, IPC, conf files and more - mpv's OSC (on screen controller (play control bar)), IPC, conf files
### Screenshots ### Screenshots
@@ -70,22 +70,51 @@ https://github.com/stax76/mpv.net/wiki/Scripting-(CSharp,-Python,-JavaScript,-Lu
### Changelog ### Changelog
### 2.3 (2019-04-04) ### 2.8 (2019-04-12)
- dragging a youtube URL on mpv.net would still break something, it should work now - Win 7 dark-mode render issue fix
- when the main window gets focus/activation it will check the clibboard for a YouTube video and ask to play it
- libmpv updated
- changing to normal size from fullscreen resulted in a too large window in some circumstances
- some default key bindings and menu structure have changed and the input.conf file has a description added on top <https://github.com/stax76/mpv.net/blob/master/mpv.net/Resources/input.conf.txt>
- the file association code was completely rewriten, it's now contained within mpvnet.exe instead of a separate application and it adds a few more keys
- various new info added to the wiki: <https://github.com/stax76/mpv.net/wiki>
- On Top feature was implemented using mpv's native property 'ontop', default bindings at: <https://github.com/stax76/mpv.net/blob/master/mpv.net/Resources/input.conf.txt>
### 2.2 (2019-04-01) ### 2.7 (2019-04-12)
- messages boxes had always the info icon even if a different icon (error, warning, question) was intended - the autofit mpv property was added to the conf editor
- instead of silently do nothing on unknown commands there is now a error message listing available commands and showing the location of the default bindings, this helps when commands are removed or renamed - the routine that writes the mpv.conf file in the conf editor was completely rewritten
- there was a problem fixed that made the cursor hidden when it should be visible - the conf editor has a dedicated page for mpv.net specific settings,
- dragging a youtube URL on mpv.net would break certain input related features these settings are saved in the same folder as mpv.conf using mpvnet.conf as filename,
- there is now an installer with file extension registration (limited on Win 10) available the first setting there is dark-mode
- WM_APPCOMMAND media keys were not working in the input (shortcut) editor and there were no defaults for prev and next defined - new optional dark theme
[go to download page](https://github.com/stax76/mpv.net/releases)
### 2.6 (2019-04-09)
- on Win 7 controls in the conf editor were using a difficult too read too light color
- context menu renderer changed to look like Win 10 design, except colors are still system theme colors
### 2.5 (2019-04-08)
- in case the input conf don't contain a menu definition mpv.net creates the default menu instead no menu like before
- all message boxes were migrated to use the TaskDialog API
- an improvement in the previous release unfortunately introduced a bug
causing the conf editor not to save settings
### 2.4 (2019-04-06)
- new options added to the conf GUI editor: gpu-context, gpu-api, scale, cscale,
dscale, dither-depth, correct-downscaling, sigmoid-upscaling, deband
- the conf edit GUI has a 'Apply' feature added to write the conf to mpv.conf
without the need to close the conf edit GUI
- the input edit GUI shows a message box when a duplicate is detected and it has
a new feature to reduce the filter scope to eather of input, menu or command and
the editor writes always the same help on top of input.conf as it is found in the defaults
- the conf edit GUI was often starting out of working area bounds and is now starting with center screen
- the startup size was reduced and a issue was fixed that when the screen property
was defined for a screen that isn't connected the startup size wasn't applied
- added feature to load external audio and subtitle files in the menu under:
Open > Load external audio|subtitle files (default binding at:
[input.conf](https://github.com/stax76/mpv.net/blob/master/mpv.net/Resources/input.conf.txt))
- previously the conf edit GUI removed settings from the conf file if the setting
was set to the default, the new behavior is not to remove anything
- the autofit mpv property was partly implemented, you can use 'autofit = 50%' in mpv.conf or
'--autofit=50%' on the command line, WxH isn't implemented and only percent values are accepted.
There is a new wiki page explaining the mpv.net limitations compared to the original mpv:
[Limitations](https://github.com/stax76/mpv.net/wiki/Limitations)

13
VBNET/My Project/Application.Designer.vb generated Normal file
View File

@@ -0,0 +1,13 @@
'------------------------------------------------------------------------------
' <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>
'------------------------------------------------------------------------------
Option Strict On
Option Explicit On

View File

@@ -0,0 +1,10 @@
<?xml version="1.0" encoding="utf-8"?>
<MyApplicationData xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<MySubMain>false</MySubMain>
<SingleInstance>false</SingleInstance>
<ShutdownMode>0</ShutdownMode>
<EnableVisualStyles>true</EnableVisualStyles>
<AuthenticationMode>0</AuthenticationMode>
<ApplicationType>1</ApplicationType>
<SaveMySettingsOnExit>true</SaveMySettingsOnExit>
</MyApplicationData>

View File

@@ -0,0 +1,35 @@
Imports System
Imports System.Reflection
Imports 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.
' Review the values of the assembly attributes
<Assembly: AssemblyTitle("VBNET")>
<Assembly: AssemblyDescription("")>
<Assembly: AssemblyCompany("")>
<Assembly: AssemblyProduct("VBNET")>
<Assembly: AssemblyCopyright("Copyright © 2019")>
<Assembly: AssemblyTrademark("")>
<Assembly: ComVisible(False)>
'The following GUID is for the ID of the typelib if this project is exposed to COM
<Assembly: Guid("a5571ff4-12ae-4e1a-ad2b-863b07d1b952")>
' 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")>

62
VBNET/My Project/Resources.Designer.vb generated Normal file
View File

@@ -0,0 +1,62 @@
'------------------------------------------------------------------------------
' <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>
'------------------------------------------------------------------------------
Option Strict On
Option Explicit On
Namespace My.Resources
'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.
'''<summary>
''' A strongly-typed resource class, for looking up localized strings, etc.
'''</summary>
<Global.System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0"), _
Global.System.Diagnostics.DebuggerNonUserCodeAttribute(), _
Global.System.Runtime.CompilerServices.CompilerGeneratedAttribute(), _
Global.Microsoft.VisualBasic.HideModuleNameAttribute()> _
Friend Module Resources
Private resourceMan As Global.System.Resources.ResourceManager
Private resourceCulture As Global.System.Globalization.CultureInfo
'''<summary>
''' Returns the cached ResourceManager instance used by this class.
'''</summary>
<Global.System.ComponentModel.EditorBrowsableAttribute(Global.System.ComponentModel.EditorBrowsableState.Advanced)> _
Friend ReadOnly Property ResourceManager() As Global.System.Resources.ResourceManager
Get
If Object.ReferenceEquals(resourceMan, Nothing) Then
Dim temp As Global.System.Resources.ResourceManager = New Global.System.Resources.ResourceManager("VBNET.Resources", GetType(Resources).Assembly)
resourceMan = temp
End If
Return resourceMan
End Get
End Property
'''<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)> _
Friend Property Culture() As Global.System.Globalization.CultureInfo
Get
Return resourceCulture
End Get
Set(ByVal value As Global.System.Globalization.CultureInfo)
resourceCulture = value
End Set
End Property
End Module
End Namespace

View File

@@ -0,0 +1,117 @@
<?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.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: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" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
</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" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
</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=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
</root>

73
VBNET/My Project/Settings.Designer.vb generated Normal file
View File

@@ -0,0 +1,73 @@
'------------------------------------------------------------------------------
' <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>
'------------------------------------------------------------------------------
Option Strict On
Option Explicit On
Namespace My
<Global.System.Runtime.CompilerServices.CompilerGeneratedAttribute(), _
Global.System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "11.0.0.0"), _
Global.System.ComponentModel.EditorBrowsableAttribute(Global.System.ComponentModel.EditorBrowsableState.Advanced)> _
Partial Friend NotInheritable Class MySettings
Inherits Global.System.Configuration.ApplicationSettingsBase
Private Shared defaultInstance As MySettings = CType(Global.System.Configuration.ApplicationSettingsBase.Synchronized(New MySettings), MySettings)
#Region "My.Settings Auto-Save Functionality"
#If _MyType = "WindowsForms" Then
Private Shared addedHandler As Boolean
Private Shared addedHandlerLockObject As New Object
<Global.System.Diagnostics.DebuggerNonUserCodeAttribute(), Global.System.ComponentModel.EditorBrowsableAttribute(Global.System.ComponentModel.EditorBrowsableState.Advanced)> _
Private Shared Sub AutoSaveSettings(ByVal sender As Global.System.Object, ByVal e As Global.System.EventArgs)
If My.Application.SaveMySettingsOnExit Then
My.Settings.Save()
End If
End Sub
#End If
#End Region
Public Shared ReadOnly Property [Default]() As MySettings
Get
#If _MyType = "WindowsForms" Then
If Not addedHandler Then
SyncLock addedHandlerLockObject
If Not addedHandler Then
AddHandler My.Application.Shutdown, AddressOf AutoSaveSettings
addedHandler = True
End If
End SyncLock
End If
#End If
Return defaultInstance
End Get
End Property
End Class
End Namespace
Namespace My
<Global.Microsoft.VisualBasic.HideModuleNameAttribute(), _
Global.System.Diagnostics.DebuggerNonUserCodeAttribute(), _
Global.System.Runtime.CompilerServices.CompilerGeneratedAttribute()> _
Friend Module MySettingsProperty
<Global.System.ComponentModel.Design.HelpKeywordAttribute("My.Settings")> _
Friend ReadOnly Property Settings() As Global.VBNET.My.MySettings
Get
Return Global.VBNET.My.MySettings.Default
End Get
End Property
End Module
End Namespace

View File

@@ -0,0 +1,7 @@
<?xml version='1.0' encoding='utf-8'?>
<SettingsFile xmlns="http://schemas.microsoft.com/VisualStudio/2004/01/settings" CurrentProfile="(Default)" UseMySettingsClassName="true">
<Profiles>
<Profile Name="(Default)" />
</Profiles>
<Settings />
</SettingsFile>

678
VBNET/TaskDialog.vb Normal file
View File

@@ -0,0 +1,678 @@
Imports System.IO
Imports System.Reflection
Imports System.Runtime.InteropServices
Imports System.Text
Imports System.Text.RegularExpressions
Imports System.Threading
Public Delegate Function PFTASKDIALOGCALLBACK(hwnd As IntPtr,
msg As UInteger,
wParam As IntPtr,
lParam As IntPtr,
lpRefData As IntPtr) As Integer
Public Class Msg
Public Shared Property SupportURL As String
Public Shared Sub Show(mainInstruction As String, Optional content As String = Nothing)
Show(mainInstruction, content, MsgIcon.Info, MsgButtons.Ok)
End Sub
Public Shared Sub ShowError(mainInstruction As String, Optional content As String = Nothing)
If mainInstruction = "" Then mainInstruction = content
If mainInstruction = "" Then Exit Sub
Using td As New TaskDialog(Of String)
td.AllowCancel = False
If content = "" Then
If mainInstruction.Length < 80 Then
td.MainInstruction = mainInstruction
Else
td.Content = mainInstruction
End If
Else
td.MainInstruction = mainInstruction
td.Content = content
End If
td.MainIcon = MsgIcon.Error
td.Footer = "[copymsg Copy Message]"
If SupportURL <> "" Then td.Footer += $" [{SupportURL} Contact Support]"
td.Show()
End Using
End Sub
Public Shared Sub ShowException(e As Exception)
Try
Using td As New TaskDialog(Of String)
td.MainInstruction = e.GetType.Name
td.Content = e.Message
td.MainIcon = MsgIcon.Error
td.ExpandedInformation = e.ToString
td.Footer = "[copymsg Copy Message]"
If SupportURL <> "" Then td.Footer += $" [{SupportURL} Contact Support]"
td.Show()
End Using
Catch
MsgBox(e.GetType.Name + vbCrLf + vbCrLf + e.Message + vbCrLf + vbCrLf + e.ToString, MsgBoxStyle.Critical)
End Try
End Sub
Private Shared ShownMessages As String
Public Shared Sub ShowWarning(mainInstruction As String,
Optional content As String = Nothing,
Optional onlyOnce As Boolean = False)
If onlyOnce AndAlso ShownMessages?.Contains(mainInstruction + content) Then Exit Sub
Show(mainInstruction, content, MsgIcon.Warning, MsgButtons.Ok)
If onlyOnce Then ShownMessages += mainInstruction + content
End Sub
Public Shared Function ShowQuestion(mainInstruction As String,
Optional buttons As MsgButtons = MsgButtons.OkCancel) As MsgResult
Return Show(mainInstruction, Nothing, MsgIcon.None, buttons)
End Function
Public Shared Function ShowQuestion(mainInstruction As String,
content As String,
Optional buttons As MsgButtons = MsgButtons.OkCancel) As MsgResult
Return Show(mainInstruction, content, MsgIcon.None, buttons)
End Function
Public Shared Function Show(mainInstruction As String,
content As String,
icon As MsgIcon,
buttons As MsgButtons,
Optional defaultButton As MsgResult = MsgResult.None) As MsgResult
If mainInstruction Is Nothing Then mainInstruction = ""
Using td As New TaskDialog(Of MsgResult)
td.AllowCancel = False
td.DefaultButton = defaultButton
td.MainIcon = icon
If content Is Nothing Then
If mainInstruction.Length < 80 Then
td.MainInstruction = mainInstruction
Else
td.Content = mainInstruction
End If
Else
td.MainInstruction = mainInstruction
td.Content = content
End If
If buttons = MsgButtons.OkCancel Then
td.AddButton("OK", MsgResult.OK)
td.AddButton("Cancel", MsgResult.Cancel) 'don't use system language
Else
td.CommonButtons = buttons
End If
Return td.Show()
End Using
End Function
End Class
Public Class TaskDialog(Of T)
Inherits TaskDialogNative
Implements IDisposable
Private IdValueDic As New Dictionary(Of Integer, T)
Private IdTextDic As New Dictionary(Of Integer, String)
Private CommandLinkShieldList As New List(Of Integer)
Private ButtonArray As IntPtr, RadioButtonArray As IntPtr
Private Buttons As New List(Of TASKDIALOG_BUTTON)
Private RadioButtons As New List(Of TASKDIALOG_BUTTON)
Private Config As TASKDIALOGCONFIG
Sub New()
Config = New TASKDIALOGCONFIG()
Config.cbSize = CUInt(Marshal.SizeOf(Config))
Config.hwndParent = GetHandle()
Config.hInstance = IntPtr.Zero
Config.dwFlags = TASKDIALOG_FLAGS.TDF_ALLOW_DIALOG_CANCELLATION
Config.dwCommonButtons = MsgButtons.None
Config.MainIcon = New TASKDIALOGCONFIG_ICON_UNION(0)
Config.FooterIcon = New TASKDIALOGCONFIG_ICON_UNION(0)
Config.cxWidth = 0
Config.cButtons = 0
Config.cRadioButtons = 0
Config.pButtons = IntPtr.Zero
Config.pRadioButtons = IntPtr.Zero
Config.nDefaultButton = 0
Config.nDefaultRadioButton = 0
Config.pszWindowTitle = DirectCast(Assembly.GetEntryAssembly().GetCustomAttributes(GetType(AssemblyProductAttribute), True)(0), AssemblyProductAttribute).Product
Config.pszMainInstruction = ""
Config.pszContent = ""
Config.pszVerificationText = Nothing
Config.pszExpandedInformation = Nothing
Config.pszExpandedControlText = Nothing
Config.pszCollapsedControlText = Nothing
Config.pszFooter = Nothing
Config.pfCallback = New PFTASKDIALOGCALLBACK(AddressOf DialogProc)
End Sub
Function GetHandle() As IntPtr
Dim sb As New StringBuilder(260)
Dim foregroundHandle = GetForegroundWindow()
GetWindowModuleFileName(foregroundHandle, sb, 260)
If Path.GetFileName(sb.ToString.Replace(".vshost", "")) =
Path.GetFileName(System.Reflection.Assembly.GetEntryAssembly().Location) Then
Return foregroundHandle
End If
End Function
#Region "Constants"
Const TDE_CONTENT As Integer = 0
Const TDE_EXPANDED_INFORMATION As Integer = 1
Const TDE_FOOTER As Integer = 2
Const TDE_MAIN_INSTRUCTION As Integer = 3
Const TDN_CREATED As Integer = 0
Const TDN_NAVIGATED As Integer = 1
Const TDN_BUTTON_CLICKED As Integer = 2
Const TDN_HYPERLINK_CLICKED As Integer = 3
Const TDN_TIMER As Integer = 4
Const TDN_DESTROYED As Integer = 5
Const TDN_RADIO_BUTTON_CLICKED As Integer = 6
Const TDN_DIALOG_CONSTRUCTED As Integer = 7
Const TDN_VERIFICATION_CLICKED As Integer = 8
Const TDN_HELP As Integer = 9
Const TDN_EXPANDO_BUTTON_CLICKED As Integer = 10
Const TDM_NAVIGATE_PAGE As Integer = &H400 + 101
Const TDM_CLICK_BUTTON As Integer = &H400 + 102 'wParam = Button ID
Const TDM_SET_MARQUEE_PROGRESS_BAR As Integer = &H400 + 103 'wParam = 0 (nonMarque) wParam != 0 (Marquee)
Const TDM_SET_PROGRESS_BAR_STATE As Integer = &H400 + 104 'wParam = new progress state
Const TDM_SET_PROGRESS_BAR_RANGE As Integer = &H400 + 105 'lParam = MAKELPARAM(nMinRange, nMaxRange)
Const TDM_SET_PROGRESS_BAR_POS As Integer = &H400 + 106 'wParam = new position
Const TDM_SET_PROGRESS_BAR_MARQUEE As Integer = &H400 + 107 'wParam = 0 (stop marquee), wParam != 0 (start marquee), lparam = speed (milliseconds between repaints)
Const TDM_SET_ELEMENT_TEXT As Integer = &H400 + 108 'wParam = element (TASKDIALOG_ELEMENTS), lParam = new element text (LPCWSTR)
Const TDM_CLICK_RADIO_BUTTON As Integer = &H400 + 110 'wParam = Radio Button ID
Const TDM_ENABLE_BUTTON As Integer = &H400 + 111 'lParam = 0 (disable), lParam != 0 (enable), wParam = Button ID
Const TDM_ENABLE_RADIO_BUTTON As Integer = &H400 + 112 'lParam = 0 (disable), lParam != 0 (enable), wParam = Radio Button ID
Const TDM_CLICK_VERIFICATION As Integer = &H400 + 113 'wParam = 0 (unchecked), 1 (checked), lParam = 1 (set key focus)
Const TDM_UPDATE_ELEMENT_TEXT As Integer = &H400 + 114 'wParam = element (TASKDIALOG_ELEMENTS), lParam = new element text (LPCWSTR)
Const TDM_SET_BUTTON_ELEVATION_REQUIRED_STATE As Integer = &H400 + 115 'wParam = Button ID, lParam = 0 (elevation not required), lParam != 0 (elevation required)
Const TDM_UPDATE_ICON As Integer = &H400 + 116 'wParam = icon element (TASKDIALOG_ICON_ELEMENTS), lParam = new icon (hIcon if TDF_USE_HICON_* was set, PCWSTR otherwise)
#End Region
#Region "Properties"
Private AllowCancelValue As Boolean
WriteOnly Property AllowCancel() As Boolean
Set(Value As Boolean)
If Value Then
Config.dwFlags = Config.dwFlags Or TASKDIALOG_FLAGS.TDF_ALLOW_DIALOG_CANCELLATION
ElseIf (Config.dwFlags And TASKDIALOG_FLAGS.TDF_ALLOW_DIALOG_CANCELLATION) = TASKDIALOG_FLAGS.TDF_ALLOW_DIALOG_CANCELLATION Then
Config.dwFlags = Config.dwFlags Xor TASKDIALOG_FLAGS.TDF_ALLOW_DIALOG_CANCELLATION
End If
End Set
End Property
Property MainInstruction() As String
Get
Return Config.pszMainInstruction
End Get
Set(Value As String)
Config.pszMainInstruction = Value
End Set
End Property
Property Content() As String
Get
Return Config.pszContent
End Get
Set(Value As String)
Config.pszContent = ExpandWikiMarkup(Value)
End Set
End Property
Property ExpandedInformation() As String
Get
Return Config.pszExpandedInformation
End Get
Set(Value As String)
Config.pszExpandedInformation = ExpandWikiMarkup(Value)
End Set
End Property
Property VerificationText() As String
Get
Return Config.pszVerificationText
End Get
Set(Value As String)
Config.pszVerificationText = Value
End Set
End Property
Property DefaultButton() As MsgResult
Get
Return CType(Config.nDefaultButton, MsgResult)
End Get
Set(Value As MsgResult)
Config.nDefaultButton = Value
End Set
End Property
Property Footer() As String
Get
Return Config.pszFooter
End Get
Set(Value As String)
Config.pszFooter = ExpandWikiMarkup(Value)
End Set
End Property
WriteOnly Property MainIcon() As MsgIcon
Set(Value As MsgIcon)
Config.MainIcon = New TASKDIALOGCONFIG_ICON_UNION(Value)
End Set
End Property
Private SelectedIDValue As Integer = -1
Property SelectedID As Integer
Get
Return SelectedIDValue
End Get
Set(value As Integer)
For Each i In IdValueDic
If i.Key = value Then SelectedIDValue = value
Next
End Set
End Property
Private SelectedValueValue As T
Property SelectedValue() As T
Get
If IdValueDic.ContainsKey(SelectedID) Then Return IdValueDic(SelectedID)
Return SelectedValueValue
End Get
Set(value As T)
SelectedValueValue = value
End Set
End Property
Private SelectedTextValue As String
Property SelectedText() As String
Get
If IdTextDic.ContainsKey(SelectedID) Then Return IdTextDic(SelectedID)
Return SelectedTextValue
End Get
Set(value As String)
SelectedTextValue = value
End Set
End Property
Property CheckBoxChecked() As Boolean
Get
Return (Config.dwFlags And TASKDIALOG_FLAGS.TDF_VERIFICATION_FLAG_CHECKED) = TASKDIALOG_FLAGS.TDF_VERIFICATION_FLAG_CHECKED
End Get
Set(value As Boolean)
If value Then
Config.dwFlags = Config.dwFlags Or TASKDIALOG_FLAGS.TDF_VERIFICATION_FLAG_CHECKED
ElseIf CheckBoxChecked Then
Config.dwFlags = Config.dwFlags Xor TASKDIALOG_FLAGS.TDF_VERIFICATION_FLAG_CHECKED
End If
End Set
End Property
Private CommonButtonsValue As MsgButtons
Property CommonButtons() As MsgButtons
Get
Return Config.dwCommonButtons
End Get
Set(Value As MsgButtons)
Config.dwCommonButtons = Value
End Set
End Property
Private TimeoutValue As Integer
Property Timeout As Integer
Get
Return CInt(TimeoutValue / 1000)
End Get
Set(Value As Integer)
TimeoutValue = Value * 1000
If Value > 0 Then
Config.dwFlags = Config.dwFlags Or TASKDIALOG_FLAGS.TDF_CALLBACK_TIMER
End If
End Set
End Property
#End Region
#Region "Methods"
Sub AddButton(text As String, value As T)
Dim id = 1000 + IdValueDic.Count + 1
IdValueDic(id) = value
Buttons.Add(New TASKDIALOG_BUTTON(id, text))
End Sub
Function ExpandWikiMarkup(value As String) As String
If value.Contains("[") Then
Dim re As New Regex("\[(.*?) (.+?)\]")
Dim m = re.Match(value)
If m.Success Then
Config.dwFlags = Config.dwFlags Or TASKDIALOG_FLAGS.TDF_ENABLE_HYPERLINKS
value = re.Replace(value, "<a href=""$1"">$2</a>")
End If
End If
Return value
End Function
Sub AddCommandLink(text As String, Optional value As T = Nothing)
Dim id = 1000 + IdValueDic.Count + 1
Dim temp As Object = text
IdValueDic(id) = If(value Is Nothing, CType(temp, T), value)
IdTextDic(id) = text
Buttons.Add(New TASKDIALOG_BUTTON(id, text))
Config.dwFlags = Config.dwFlags Or TASKDIALOG_FLAGS.TDF_USE_COMMAND_LINKS
End Sub
Sub AddCommandLink(text As String,
description As String,
value As T,
Optional setShield As Boolean = False)
Dim id = 1000 + IdValueDic.Count + 1
IdValueDic(id) = value
If setShield Then CommandLinkShieldList.Add(id)
If description <> "" Then text = text + vbCrLf + description
Buttons.Add(New TASKDIALOG_BUTTON(id, text))
Config.dwFlags = Config.dwFlags Or TASKDIALOG_FLAGS.TDF_USE_COMMAND_LINKS
End Sub
Sub AddRadioButton(text As String, value As T)
Dim id = 1000 + IdValueDic.Count + 1
IdValueDic(id) = value
RadioButtons.Add(New TASKDIALOG_BUTTON(id, text))
End Sub
Function Show() As T
MarshalDialogControlStructs()
Dim isChecked As Boolean
Dim hr = TaskDialogIndirect(Config, Nothing, Nothing, isChecked)
CheckBoxChecked = isChecked
If hr < 0 Then Marshal.ThrowExceptionForHR(hr)
If TypeOf SelectedValue Is MsgResult Then SelectedValue = DirectCast(CObj(SelectedID), T)
Return SelectedValue
End Function
Private ExitTickCount As Integer
Private Function DialogProc(hwnd As IntPtr,
msg As UInteger,
wParam As IntPtr,
lParam As IntPtr,
lpRefData As IntPtr) As Integer
Select Case msg
Case TDN_BUTTON_CLICKED, TDN_RADIO_BUTTON_CLICKED
If TypeOf SelectedValue Is MsgResult Then
SelectedIDValue = wParam.ToInt32
Else
SelectedID = wParam.ToInt32
End If
Case TDN_TIMER
If ExitTickCount = 0 Then
ExitTickCount = Environment.TickCount + Timeout * 1000
End If
If Environment.TickCount > ExitTickCount Then
SendMessage(hwnd, TDM_CLICK_BUTTON, New IntPtr(MsgResult.OK), IntPtr.Zero)
End If
Case TDN_HYPERLINK_CLICKED
Dim url = Marshal.PtrToStringUni(lParam)
If url.StartsWith("mailto") OrElse url.StartsWith("http") Then
Process.Start(url)
ElseIf url = "copymsg" Then
Dim thread As New Thread(
New ThreadStart(Sub()
System.Windows.Forms.Clipboard.SetText(MainInstruction + vbCrLf + vbCrLf + Content + vbCrLf + vbCrLf + ExpandedInformation)
MsgBox("Message was copied to clipboard.",
MsgBoxStyle.Information,
DirectCast(Assembly.GetEntryAssembly().GetCustomAttributes(GetType(AssemblyProductAttribute), True)(0), AssemblyProductAttribute).Product)
End Sub))
thread.SetApartmentState(ApartmentState.STA)
thread.Start()
End If
Case TDN_CREATED
For Each i In CommandLinkShieldList
SendMessage(hwnd, TDM_SET_BUTTON_ELEVATION_REQUIRED_STATE, New IntPtr(i), New IntPtr(1))
Next
End Select
End Function
Private Sub MarshalDialogControlStructs()
If Not Buttons Is Nothing AndAlso Buttons.Count > 0 Then
ButtonArray = AllocateAndMarshalButtons(Buttons)
Config.pButtons = ButtonArray
Config.cButtons = CUInt(Buttons.Count)
End If
If Not RadioButtons Is Nothing AndAlso RadioButtons.Count > 0 Then
RadioButtonArray = AllocateAndMarshalButtons(RadioButtons)
Config.pRadioButtons = RadioButtonArray
Config.cRadioButtons = CUInt(RadioButtons.Count)
End If
End Sub
Private Shared Function AllocateAndMarshalButtons(structs As List(Of TASKDIALOG_BUTTON)) As IntPtr
Dim initialPtr = Marshal.AllocHGlobal(Marshal.SizeOf(GetType(TASKDIALOG_BUTTON)) * structs.Count)
Dim currentPtr = initialPtr
For Each button In structs
Marshal.StructureToPtr(button, currentPtr, False)
currentPtr = CType((currentPtr.ToInt64 + Marshal.SizeOf(button)), IntPtr)
Next
Return initialPtr
End Function
#End Region
#Region "IDispose Pattern"
Private disposed As Boolean
Sub Dispose() Implements IDisposable.Dispose
Dispose(True)
GC.SuppressFinalize(Me)
End Sub
Protected Overrides Sub Finalize()
Try
Dispose(False)
Finally
MyBase.Finalize()
End Try
End Sub
Protected Sub Dispose(disposing As Boolean)
If Not disposed Then
disposed = True
If ButtonArray <> IntPtr.Zero Then
Marshal.FreeHGlobal(ButtonArray)
ButtonArray = IntPtr.Zero
End If
If RadioButtonArray <> IntPtr.Zero Then
Marshal.FreeHGlobal(RadioButtonArray)
RadioButtonArray = IntPtr.Zero
End If
If disposing Then
End If
End If
End Sub
#End Region
End Class
Public Class TaskDialogNative
<DllImport("comctl32", CharSet:=CharSet.Unicode, SetLastError:=True)>
Shared Function TaskDialogIndirect(<[In]()> pTaskConfig As TASKDIALOGCONFIG, <Out()> ByRef pnButton As Integer, <Out()> ByRef pnRadioButton As Integer, <MarshalAs(UnmanagedType.Bool)> <Out()> ByRef pVerificationFlagChecked As Boolean) As Integer
End Function
<DllImport("user32.dll")>
Shared Function GetForegroundWindow() As IntPtr
End Function
<DllImport("user32.dll", CharSet:=CharSet.Unicode)>
Shared Function GetWindowModuleFileName(hwnd As IntPtr,
lpszFileName As StringBuilder,
cchFileNameMax As UInteger) As UInteger
End Function
<DllImport("user32.dll")>
Shared Function SendMessage(handle As IntPtr,
message As Int32,
wParam As IntPtr,
lParam As IntPtr) As IntPtr
End Function
<StructLayout(LayoutKind.Sequential, CharSet:=CharSet.Unicode, Pack:=4)>
Public Class TASKDIALOGCONFIG
Public cbSize As UInteger
Public hwndParent As IntPtr
Public hInstance As IntPtr
Public dwFlags As TASKDIALOG_FLAGS
Public dwCommonButtons As MsgButtons
<MarshalAs(UnmanagedType.LPWStr)>
Public pszWindowTitle As String
Public MainIcon As TASKDIALOGCONFIG_ICON_UNION
<MarshalAs(UnmanagedType.LPWStr)>
Public pszMainInstruction As String
<MarshalAs(UnmanagedType.LPWStr)>
Public pszContent As String
Public cButtons As UInteger
Public pButtons As IntPtr
Public nDefaultButton As Integer
Public cRadioButtons As UInteger
Public pRadioButtons As IntPtr
Public nDefaultRadioButton As Integer
<MarshalAs(UnmanagedType.LPWStr)>
Public pszVerificationText As String
<MarshalAs(UnmanagedType.LPWStr)>
Public pszExpandedInformation As String
<MarshalAs(UnmanagedType.LPWStr)>
Public pszExpandedControlText As String
<MarshalAs(UnmanagedType.LPWStr)>
Public pszCollapsedControlText As String
Public FooterIcon As TASKDIALOGCONFIG_ICON_UNION
<MarshalAs(UnmanagedType.LPWStr)>
Public pszFooter As String
Public pfCallback As PFTASKDIALOGCALLBACK
Public lpCallbackData As IntPtr
Public cxWidth As UInteger
End Class
Public Enum TASKDIALOG_FLAGS
NONE = 0
TDF_ENABLE_HYPERLINKS = &H1
TDF_USE_HICON_MAIN = &H2
TDF_USE_HICON_FOOTER = &H4
TDF_ALLOW_DIALOG_CANCELLATION = &H8
TDF_USE_COMMAND_LINKS = &H10
TDF_USE_COMMAND_LINKS_NO_ICON = &H20
TDF_EXPAND_FOOTER_AREA = &H40
TDF_EXPANDED_BY_DEFAULT = &H80
TDF_VERIFICATION_FLAG_CHECKED = &H100
TDF_SHOW_PROGRESS_BAR = &H200
TDF_SHOW_MARQUEE_PROGRESS_BAR = &H400
TDF_CALLBACK_TIMER = &H800
TDF_POSITION_RELATIVE_TO_WINDOW = &H1000
TDF_RTL_LAYOUT = &H2000
TDF_NO_DEFAULT_RADIO_BUTTON = &H4000
End Enum
<StructLayout(LayoutKind.Explicit, CharSet:=CharSet.Unicode)>
Public Structure TASKDIALOGCONFIG_ICON_UNION
Sub New(i As Integer)
spacer = IntPtr.Zero
pszIcon = 0
hMainIcon = i
End Sub
<FieldOffset(0)>
Public hMainIcon As Integer
<FieldOffset(0)>
Public pszIcon As Integer
<FieldOffset(0)>
Public spacer As IntPtr
End Structure
<StructLayout(LayoutKind.Sequential,
CharSet:=CharSet.Unicode, Pack:=4)>
Public Structure TASKDIALOG_BUTTON
Sub New(n As Integer, txt As String)
nButtonID = n
pszButtonText = txt
End Sub
Public nButtonID As Integer
<MarshalAs(UnmanagedType.LPWStr)>
Public pszButtonText As String
End Structure
End Class
Public Enum MsgButtons
None = &H0
Ok = &H1
Yes = &H2
No = &H4
Cancel = &H8
Retry = &H10
RetryCancel = Retry Or Cancel
Close = &H20
OkCancel = Ok Or Cancel
YesNo = Yes Or No
YesNoCancel = YesNo Or Cancel
End Enum
Public Enum MsgIcon
None = 0
Warning = 65535 'TD_WARNING_ICON
[Error] = 65534 'TD_ERROR_ICON
Info = 65533 'TD_INFORMATION_ICON
Shield = 65532 'TD_SHIELD_ICON
SecurityShieldBlue = 65531
SecurityWarning = 65530
SecurityError = 65529
SecuritySuccess = 65528
SecurityShieldGray = 65527
End Enum
Public Enum MsgResult
None = 0
OK = 1
Cancel = 2
Abort = 3
Retry = 4
Ignore = 5
Yes = 6
No = 7
End Enum

109
VBNET/VBNET.vbproj Normal file
View File

@@ -0,0 +1,109 @@
<?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>{A1D11294-05BF-4D77-B008-AECF1AA93C9F}</ProjectGuid>
<OutputType>Library</OutputType>
<RootNamespace>VBNET</RootNamespace>
<AssemblyName>VBNET</AssemblyName>
<FileAlignment>512</FileAlignment>
<MyType>Windows</MyType>
<TargetFrameworkVersion>v4.7.2</TargetFrameworkVersion>
<Deterministic>true</Deterministic>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<DefineDebug>true</DefineDebug>
<DefineTrace>true</DefineTrace>
<OutputPath>bin\Debug\</OutputPath>
<DocumentationFile>
</DocumentationFile>
<NoWarn>42353,42354,42355</NoWarn>
<WarningsAsErrors>41999,42016,42017,42018,42019,42020,42021,42022,42032,42036</WarningsAsErrors>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<DebugType>pdbonly</DebugType>
<DefineDebug>false</DefineDebug>
<DefineTrace>true</DefineTrace>
<Optimize>true</Optimize>
<OutputPath>bin\Release\</OutputPath>
<DocumentationFile>
</DocumentationFile>
<NoWarn>42353,42354,42355</NoWarn>
<WarningsAsErrors>41999,42016,42017,42018,42019,42020,42021,42022,42032,42036</WarningsAsErrors>
</PropertyGroup>
<PropertyGroup>
<OptionExplicit>On</OptionExplicit>
</PropertyGroup>
<PropertyGroup>
<OptionCompare>Binary</OptionCompare>
</PropertyGroup>
<PropertyGroup>
<OptionStrict>On</OptionStrict>
</PropertyGroup>
<PropertyGroup>
<OptionInfer>On</OptionInfer>
</PropertyGroup>
<ItemGroup>
<Reference Include="System" />
<Reference Include="System.Data" />
<Reference Include="System.Windows.Forms" />
<Reference Include="System.Xml" />
<Reference Include="System.Core" />
<Reference Include="System.Xml.Linq" />
<Reference Include="System.Data.DataSetExtensions" />
<Reference Include="System.Net.Http" />
</ItemGroup>
<ItemGroup>
<Import Include="Microsoft.VisualBasic" />
<Import Include="System" />
<Import Include="System.Collections" />
<Import Include="System.Collections.Generic" />
<Import Include="System.Data" />
<Import Include="System.Diagnostics" />
<Import Include="System.Linq" />
<Import Include="System.Xml.Linq" />
<Import Include="System.Threading.Tasks" />
</ItemGroup>
<ItemGroup>
<Compile Include="My Project\AssemblyInfo.vb" />
<Compile Include="My Project\Application.Designer.vb">
<AutoGen>True</AutoGen>
<DependentUpon>Application.myapp</DependentUpon>
</Compile>
<Compile Include="My Project\Resources.Designer.vb">
<AutoGen>True</AutoGen>
<DesignTime>True</DesignTime>
<DependentUpon>Resources.resx</DependentUpon>
</Compile>
<Compile Include="My Project\Settings.Designer.vb">
<AutoGen>True</AutoGen>
<DependentUpon>Settings.settings</DependentUpon>
<DesignTimeSharedInput>True</DesignTimeSharedInput>
</Compile>
<Compile Include="TaskDialog.vb" />
</ItemGroup>
<ItemGroup>
<EmbeddedResource Include="My Project\Resources.resx">
<Generator>VbMyResourcesResXFileCodeGenerator</Generator>
<LastGenOutput>Resources.Designer.vb</LastGenOutput>
<CustomToolNamespace>My.Resources</CustomToolNamespace>
<SubType>Designer</SubType>
</EmbeddedResource>
</ItemGroup>
<ItemGroup>
<None Include="My Project\Application.myapp">
<Generator>MyApplicationCodeGenerator</Generator>
<LastGenOutput>Application.Designer.vb</LastGenOutput>
</None>
<None Include="My Project\Settings.settings">
<Generator>SettingsSingleFileGenerator</Generator>
<CustomToolNamespace>My</CustomToolNamespace>
<LastGenOutput>Settings.Designer.vb</LastGenOutput>
</None>
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.VisualBasic.targets" />
</Project>

View File

@@ -1,7 +1,7 @@
Microsoft Visual Studio Solution File, Format Version 12.00 Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio 15 # Visual Studio Version 16
VisualStudioVersion = 15.0.26730.8 VisualStudioVersion = 16.0.28729.10
MinimumVisualStudioVersion = 10.0.40219.1 MinimumVisualStudioVersion = 10.0.40219.1
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "mpv.net", "mpv.net\mpv.net.csproj", "{1751F378-8EDF-4B62-BE6D-304C7C287089}" Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "mpv.net", "mpv.net\mpv.net.csproj", "{1751F378-8EDF-4B62-BE6D-304C7C287089}"
EndProject EndProject
@@ -9,6 +9,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "RatingAddon", "RatingAddon\
EndProject EndProject
Project("{F184B08F-C81C-45F6-A57F-5ABD9991F28F}") = "CSScriptAddon", "CSScriptAddon\CSScriptAddon.vbproj", "{71808A87-8B1C-4DF8-957C-D79C3B164CCA}" Project("{F184B08F-C81C-45F6-A57F-5ABD9991F28F}") = "CSScriptAddon", "CSScriptAddon\CSScriptAddon.vbproj", "{71808A87-8B1C-4DF8-957C-D79C3B164CCA}"
EndProject EndProject
Project("{F184B08F-C81C-45F6-A57F-5ABD9991F28F}") = "VBNET", "VBNET\VBNET.vbproj", "{A1D11294-05BF-4D77-B008-AECF1AA93C9F}"
EndProject
Global Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU Debug|Any CPU = Debug|Any CPU
@@ -55,6 +57,18 @@ Global
{71808A87-8B1C-4DF8-957C-D79C3B164CCA}.Release|x64.Build.0 = Release|Any CPU {71808A87-8B1C-4DF8-957C-D79C3B164CCA}.Release|x64.Build.0 = Release|Any CPU
{71808A87-8B1C-4DF8-957C-D79C3B164CCA}.Release|x86.ActiveCfg = Release|Any CPU {71808A87-8B1C-4DF8-957C-D79C3B164CCA}.Release|x86.ActiveCfg = Release|Any CPU
{71808A87-8B1C-4DF8-957C-D79C3B164CCA}.Release|x86.Build.0 = Release|Any CPU {71808A87-8B1C-4DF8-957C-D79C3B164CCA}.Release|x86.Build.0 = Release|Any CPU
{A1D11294-05BF-4D77-B008-AECF1AA93C9F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{A1D11294-05BF-4D77-B008-AECF1AA93C9F}.Debug|Any CPU.Build.0 = Debug|Any CPU
{A1D11294-05BF-4D77-B008-AECF1AA93C9F}.Debug|x64.ActiveCfg = Debug|Any CPU
{A1D11294-05BF-4D77-B008-AECF1AA93C9F}.Debug|x64.Build.0 = Debug|Any CPU
{A1D11294-05BF-4D77-B008-AECF1AA93C9F}.Debug|x86.ActiveCfg = Debug|Any CPU
{A1D11294-05BF-4D77-B008-AECF1AA93C9F}.Debug|x86.Build.0 = Debug|Any CPU
{A1D11294-05BF-4D77-B008-AECF1AA93C9F}.Release|Any CPU.ActiveCfg = Release|Any CPU
{A1D11294-05BF-4D77-B008-AECF1AA93C9F}.Release|Any CPU.Build.0 = Release|Any CPU
{A1D11294-05BF-4D77-B008-AECF1AA93C9F}.Release|x64.ActiveCfg = Release|Any CPU
{A1D11294-05BF-4D77-B008-AECF1AA93C9F}.Release|x64.Build.0 = Release|Any CPU
{A1D11294-05BF-4D77-B008-AECF1AA93C9F}.Release|x86.ActiveCfg = Release|Any CPU
{A1D11294-05BF-4D77-B008-AECF1AA93C9F}.Release|x86.Build.0 = Release|Any CPU
EndGlobalSection EndGlobalSection
GlobalSection(SolutionProperties) = preSolution GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE HideSolutionNode = FALSE

View File

@@ -5,6 +5,8 @@ using System.ComponentModel.Composition.Hosting;
using System.IO; using System.IO;
using System.Windows.Forms; using System.Windows.Forms;
using VBNET;
namespace mpvnet namespace mpvnet
{ {
public class Addon public class Addon
@@ -38,9 +40,9 @@ namespace mpvnet
CompositionContainer.ComposeParts(this); CompositionContainer.ComposeParts(this);
} }
} }
catch (Exception e) catch (Exception ex)
{ {
MainForm.Instance.ShowMsgBox(e.ToString(), MessageBoxIcon.Error); Msg.ShowException(ex);
} }
} }
} }

View File

@@ -3,8 +3,11 @@ using System.Collections.Generic;
using System.Diagnostics; using System.Diagnostics;
using System.IO; using System.IO;
using System.Reflection; using System.Reflection;
using System.Threading.Tasks;
using System.Windows.Forms; using System.Windows.Forms;
using VBNET;
namespace mpvnet namespace mpvnet
{ {
public class Command public class Command
@@ -53,7 +56,7 @@ namespace mpvnet
})); }));
} }
public static void open_config_folder(string[] args) public static void open_conf_folder(string[] args)
{ {
Process.Start(mp.mpvConfFolderPath); Process.Start(mp.mpvConfFolderPath);
} }
@@ -75,37 +78,12 @@ namespace mpvnet
if (File.Exists(fp)) if (File.Exists(fp))
Process.Start(fp); Process.Start(fp);
else else
if (MainForm.Instance.ShowMsgBox("Create history.txt file in config folder?\n\nmpv.net will write the date, time and filename of opened files to it.", MessageBoxIcon.Question) == DialogResult.OK) if (Msg.ShowQuestion("Create history.txt file in config folder?",
"mpv.net will write the date, time and filename of opened files to it.") == MsgResult.OK)
File.WriteAllText(fp, ""); File.WriteAllText(fp, "");
} }
public static void shell_execute(string[] args) public static void shell_execute(string[] args) => Process.Start(args[0]);
{
Process.Start(args[0]);
}
public static void set_setting(string[] args)
{
bool changed = false;
var lines = File.ReadAllLines(mp.mpvConfPath);
for (int i = 0; i < lines.Length; i++)
{
if (lines[i].Contains("=") &&
lines[i].Substring(0, lines[i].IndexOf("=")).Trim("# ".ToCharArray()) == args[0])
{
lines[i] = args[0] + " = " + args[1];
changed = true;
}
}
if (changed)
File.WriteAllText(mp.mpvConfPath, String.Join(Environment.NewLine, lines));
else
File.WriteAllText(mp.mpvConfPath, File.ReadAllText(mp.mpvConfPath) + Environment.NewLine + args[0] + " = " + args[1]);
MainForm.Instance.ShowMsgBox("Please restart mpv.net", MessageBoxIcon.Information);
}
public static void show_info(string[] args) public static void show_info(string[] args)
{ {
@@ -187,5 +165,35 @@ namespace mpvnet
mp.LoadURL(command); mp.LoadURL(command);
})); }));
} }
public static void load_sub(string[] args)
{
MainForm.Instance.BeginInvoke(new Action(() => {
using (var d = new OpenFileDialog())
{
d.InitialDirectory = Path.GetDirectoryName(mp.get_property_string("path", false));
d.Multiselect = true;
if (d.ShowDialog() == DialogResult.OK)
foreach (string i in d.FileNames)
mp.commandv("sub-add", i);
}
}));
}
public static void load_audio(string[] args)
{
MainForm.Instance.BeginInvoke(new Action(() => {
using (var d = new OpenFileDialog())
{
d.InitialDirectory = Path.GetDirectoryName(mp.get_property_string("path", false));
d.Multiselect = true;
if (d.ShowDialog() == DialogResult.OK)
foreach (string i in d.FileNames)
mp.commandv("audio-add", i);
}
}));
}
} }
} }

View File

@@ -45,7 +45,7 @@
this.AutoScaleDimensions = new System.Drawing.SizeF(288F, 288F); this.AutoScaleDimensions = new System.Drawing.SizeF(288F, 288F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Dpi; this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Dpi;
this.BackColor = System.Drawing.Color.Black; this.BackColor = System.Drawing.Color.Black;
this.ClientSize = new System.Drawing.Size(1012, 615); this.ClientSize = new System.Drawing.Size(606, 368);
this.Font = new System.Drawing.Font("Segoe UI", 9F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); this.Font = new System.Drawing.Font("Segoe UI", 9F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
this.Icon = ((System.Drawing.Icon)(resources.GetObject("$this.Icon"))); this.Icon = ((System.Drawing.Icon)(resources.GetObject("$this.Icon")));
this.Margin = new System.Windows.Forms.Padding(3, 4, 3, 4); this.Margin = new System.Windows.Forms.Padding(3, 4, 3, 4);

View File

@@ -5,6 +5,9 @@ using System.Runtime.InteropServices;
using System.Threading; using System.Threading;
using System.Windows.Forms; using System.Windows.Forms;
using System.Linq; using System.Linq;
using System.Collections.Generic;
using VBNET;
namespace mpvnet namespace mpvnet
{ {
@@ -16,6 +19,10 @@ namespace mpvnet
private Point LastCursorPosChanged; private Point LastCursorPosChanged;
private int LastCursorChangedTickCount; private int LastCursorChangedTickCount;
private bool IgnoreDpiChanged = true; private bool IgnoreDpiChanged = true;
private float MpvAutofit = 0.50f;
private bool MpvFullscreen;
private int MpvScreen = -1;
private string MpvNetDarkMode = "system";
public ContextMenuStripEx CMS; public ContextMenuStripEx CMS;
@@ -27,30 +34,37 @@ namespace mpvnet
{ {
AppDomain.CurrentDomain.UnhandledException += CurrentDomain_UnhandledException; AppDomain.CurrentDomain.UnhandledException += CurrentDomain_UnhandledException;
Application.ThreadException += Application_ThreadException; Application.ThreadException += Application_ThreadException;
Msg.SupportURL = "https://github.com/stax76/mpv.net#support";
Instance = this; Instance = this;
Hwnd = Handle; Hwnd = Handle;
MinimumSize = new Size(FontHeight * 16, FontHeight * 9);
Text += " " + Application.ProductVersion; Text += " " + Application.ProductVersion;
if (mp.mpvConf.ContainsKey("screen")) foreach (var i in mp.mpvConf)
SetScreen(Convert.ToInt32(mp.mpvConf["screen"])); ProcessMpvProperty(i.Key, i.Value);
else
SetScreen(Screen.PrimaryScreen);
ChangeFullscreen((mp.mpvConf.ContainsKey("fullscreen") && mp.mpvConf["fullscreen"] == "yes") || foreach (var i in mp.mpvNetConf)
(mp.mpvConf.ContainsKey("fs") && mp.mpvConf["fs"] == "yes")); ProcessMpvNetProperty(i.Key, i.Value);
ProcessCommandLineEarly(); ProcessCommandLineEarly();
if (MpvScreen == -1) MpvScreen = Array.IndexOf(Screen.AllScreens, Screen.PrimaryScreen);
SetScreen(MpvScreen);
ChangeFullscreen(MpvFullscreen);
} }
catch (Exception e) catch (Exception ex)
{ {
ShowMsgBox(e.ToString(), MessageBoxIcon.Error); Msg.ShowException(ex);
} }
} }
protected void SetScreen(int targetIndex) protected void SetScreen(int targetIndex)
{ {
Screen[] screens = Screen.AllScreens; Screen[] screens = Screen.AllScreens;
if (targetIndex < 0 || targetIndex > screens.Length - 1) return; if (targetIndex < 0) targetIndex = 0;
if (targetIndex > screens.Length - 1) targetIndex = screens.Length - 1;
SetScreen(screens[Array.IndexOf(screens, screens[targetIndex])]); SetScreen(screens[Array.IndexOf(screens, screens[targetIndex])]);
} }
@@ -66,7 +80,7 @@ namespace mpvnet
{ {
if (IsFullscreen || mp.VideoSize.Width == 0) return; if (IsFullscreen || mp.VideoSize.Width == 0) return;
Screen screen = Screen.FromControl(this); Screen screen = Screen.FromControl(this);
int height = Convert.ToInt32(screen.Bounds.Height * 0.6); int height = Convert.ToInt32(screen.Bounds.Height * MpvAutofit);
int width = Convert.ToInt32(height * mp.VideoSize.Width / (double)mp.VideoSize.Height); int width = Convert.ToInt32(height * mp.VideoSize.Width / (double)mp.VideoSize.Height);
Point middlePos = new Point(Left + Width / 2, Top + Height / 2); Point middlePos = new Point(Left + Width / 2, Top + Height / 2);
var rect = new Native.RECT(new Rectangle(screen.Bounds.X, screen.Bounds.Y, width, height)); var rect = new Native.RECT(new Rectangle(screen.Bounds.X, screen.Bounds.Y, width, height));
@@ -81,7 +95,7 @@ namespace mpvnet
if (IsFullscreen || mp.VideoSize.Width == 0) return; if (IsFullscreen || mp.VideoSize.Width == 0) return;
Screen screen = Screen.FromControl(this); Screen screen = Screen.FromControl(this);
int height = ClientSize.Height; int height = ClientSize.Height;
if (height > screen.Bounds.Height * 0.8) height = Convert.ToInt32(screen.Bounds.Height * 0.6); if (height > screen.Bounds.Height * 0.9) height = Convert.ToInt32(screen.Bounds.Height * MpvAutofit);
int width = Convert.ToInt32(height * mp.VideoSize.Width / (double)mp.VideoSize.Height); int width = Convert.ToInt32(height * mp.VideoSize.Width / (double)mp.VideoSize.Height);
Point middlePos = new Point(Left + Width / 2, Top + Height / 2); Point middlePos = new Point(Left + Width / 2, Top + Height / 2);
var rect = new Native.RECT(new Rectangle(screen.Bounds.X, screen.Bounds.Y, width, height)); var rect = new Native.RECT(new Rectangle(screen.Bounds.X, screen.Bounds.Y, width, height));
@@ -107,11 +121,8 @@ namespace mpvnet
{ {
string left = i.Substring(2, i.IndexOf("=") - 2); string left = i.Substring(2, i.IndexOf("=") - 2);
string right = i.Substring(left.Length + 3); string right = i.Substring(left.Length + 3);
ProcessMpvProperty(left, right);
if (left == "screen") ProcessMpvNetProperty(left, right);
SetScreen(Convert.ToInt32(right));
ChangeFullscreen((left == "fs" || left == "fullscreen") && right == "yes");
} }
else else
{ {
@@ -121,7 +132,7 @@ namespace mpvnet
{ {
case "fs": case "fs":
case "fullscreen": case "fullscreen":
ChangeFullscreen(true); MpvFullscreen = true;
break; break;
} }
} }
@@ -129,34 +140,87 @@ namespace mpvnet
} }
} }
void ProcessMpvProperty(string name, string value)
{
switch (name)
{
case "autofit":
if (value.Length == 3 && value.EndsWith("%"))
if (int.TryParse(value.Substring(0, 2), out int result))
MpvAutofit = result / 100f;
break;
case "fs":
case "fullscreen":
MpvFullscreen = value == "yes";
break;
case "screen":
MpvScreen = Convert.ToInt32(value);
break;
}
}
void ProcessMpvNetProperty(string name, string value)
{
switch (name)
{
case "dark-mode":
MpvNetDarkMode = value;
break;
}
}
public void BuildMenu() public void BuildMenu()
{ {
foreach (var i in File.ReadAllText(mp.InputConfPath).Split("\r\n".ToCharArray(), StringSplitOptions.RemoveEmptyEntries)) string content = File.ReadAllText(mp.InputConfPath);
List<string> lines = null;
Dictionary<string, string> commandInputDic = new Dictionary<string, string>();
if (content.Contains("#menu:"))
lines = content.Split("\r\n".ToCharArray()).ToList();
else
{
lines = Properties.Resources.input_conf.Split("\r\n".ToCharArray()).ToList();
foreach (string i in content.Split("\r\n".ToCharArray()))
{
string line = i.Trim();
if (line.StartsWith("#") || !line.Contains(" ")) continue;
string input = line.Substring(0, line.IndexOf(" ")).Trim();
string command = line.Substring(line.IndexOf(" ") + 1).Trim();
commandInputDic[command] = input;
}
}
foreach (string i in lines)
{ {
if (!i.Contains("#menu:")) continue; if (!i.Contains("#menu:")) continue;
var left = i.Substring(0, i.IndexOf("#menu:")).Trim(); string left = i.Substring(0, i.IndexOf("#menu:")).Trim();
if (left.StartsWith("#")) continue; if (left.StartsWith("#")) continue;
var cmd = left.Substring(left.IndexOf(" ") + 1).Trim(); string command = left.Substring(left.IndexOf(" ") + 1).Trim();
var menu = i.Substring(i.IndexOf("#menu:") + "#menu:".Length).Trim(); string menu = i.Substring(i.IndexOf("#menu:") + "#menu:".Length).Trim();
var key = left.Substring(0, left.IndexOf(" ")); string input = left.Substring(0, left.IndexOf(" "));
if (key == "_") key = ""; if (input == "_") input = "";
if (menu.Contains(";")) key = menu.Substring(0, menu.IndexOf(";")).Trim(); if (menu.Contains(";")) input = menu.Substring(0, menu.IndexOf(";")).Trim();
var path = menu.Substring(menu.IndexOf(";") + 1).Trim().Replace("&", "&&"); string path = menu.Substring(menu.IndexOf(";") + 1).Trim().Replace("&", "&&");
if (path == "" || cmd == "") continue; if (path == "" || command == "") continue;
if (commandInputDic.Count > 0)
if (commandInputDic.ContainsKey(command))
input = commandInputDic[command];
else
input = "";
var menuItem = CMS.Add(path, () => { var menuItem = CMS.Add(path, () => {
try try {
{ mp.command_string(command);
mp.command_string(cmd);
} }
catch (Exception e) catch (Exception ex) {
{ Msg.ShowException(ex);
ShowMsgBox(e.ToString(), MessageBoxIcon.Error);
} }
}); });
if (menuItem != null) if (menuItem != null)
menuItem.ShortcutKeyDisplayString = key.Replace("_","") + " "; menuItem.ShortcutKeyDisplayString = input.Replace("_","") + " ";
} }
} }
@@ -187,12 +251,12 @@ namespace mpvnet
private void Application_ThreadException(object sender, ThreadExceptionEventArgs e) private void Application_ThreadException(object sender, ThreadExceptionEventArgs e)
{ {
ShowMsgBox(e.Exception.ToString(), MessageBoxIcon.Error); Msg.ShowException(e.Exception);
} }
private void CurrentDomain_UnhandledException(object sender, UnhandledExceptionEventArgs e) private void CurrentDomain_UnhandledException(object sender, UnhandledExceptionEventArgs e)
{ {
ShowMsgBox(e.ExceptionObject.ToString(), MessageBoxIcon.Error); Msg.ShowError(e.ExceptionObject.ToString());
} }
private void mp_VideoSizeChanged() private void mp_VideoSizeChanged()
@@ -376,6 +440,8 @@ namespace mpvnet
protected override void OnShown(EventArgs e) protected override void OnShown(EventArgs e)
{ {
base.OnShown(e); base.OnShown(e);
if ((MpvNetDarkMode == "system" && Misc.IsDarkTheme) || MpvNetDarkMode == "always")
ToolStripRendererEx.ColorTheme = Color.Black;
CMS = new ContextMenuStripEx(components); CMS = new ContextMenuStripEx(components);
CMS.Opened += CMS_Opened; CMS.Opened += CMS_Opened;
ContextMenuStrip = CMS; ContextMenuStrip = CMS;
@@ -411,7 +477,7 @@ namespace mpvnet
if (clipboard.StartsWith("https://www.youtube.com/watch?") && LastURL != clipboard && Visible) if (clipboard.StartsWith("https://www.youtube.com/watch?") && LastURL != clipboard && Visible)
{ {
LastURL = clipboard; LastURL = clipboard;
if (ShowMsgBox("Play YouTube URL?", MessageBoxIcon.Question) == DialogResult.OK) if (Msg.ShowQuestion("Play YouTube URL?") == MsgResult.OK)
mp.LoadURL(clipboard); mp.LoadURL(clipboard);
} }
} }

View File

@@ -6,6 +6,7 @@ using System.Drawing.Text;
using Microsoft.Win32; using Microsoft.Win32;
using System.Windows.Forms; using System.Windows.Forms;
using System.Drawing; using System.Drawing;
using System.Diagnostics;
public class ContextMenuStripEx : ContextMenuStrip public class ContextMenuStripEx : ContextMenuStrip
{ {
@@ -168,10 +169,12 @@ public class MenuItemEx : ToolStripMenuItem
public class ToolStripRendererEx : ToolStripSystemRenderer public class ToolStripRendererEx : ToolStripSystemRenderer
{ {
public static Color ColorForeground { get; set; } = Color.Black;
public static Color ColorTheme { get; set; } = Color.Empty;
public static Color ColorChecked { get; set; } public static Color ColorChecked { get; set; }
public static Color ColorBorder { get; set; } public static Color ColorBorder { get; set; }
public static Color ColorTop { get; set; } public static Color ColorTop { get; set; }
public static Color ColorBottom { get; set; } public static Color ColorSelection { get; set; }
public static Color ColorBackground { get; set; } public static Color ColorBackground { get; set; }
public static Color ColorToolStrip1 { get; set; } public static Color ColorToolStrip1 { get; set; }
@@ -186,17 +189,28 @@ public class ToolStripRendererEx : ToolStripSystemRenderer
var argb = Convert.ToInt32(Registry.GetValue(@"HKEY_CURRENT_USER\Software\Microsoft\Windows\DWM", "ColorizationColor", 0)); var argb = Convert.ToInt32(Registry.GetValue(@"HKEY_CURRENT_USER\Software\Microsoft\Windows\DWM", "ColorizationColor", 0));
if (argb == 0) if (argb == 0)
argb = Color.LightBlue.ToArgb(); argb = Color.LightBlue.ToArgb();
if (ColorTheme == Color.Empty)
InitColors(Color.FromArgb(argb)); InitColors(Color.FromArgb(argb));
else
InitColors(ColorTheme);
} }
public static void InitColors(Color c) public static void InitColors(Color c)
{ {
ColorBorder = HSLColor.Convert(c).ToColorSetLuminosity(100); ColorBorder = HSLColor.Convert(c).ToColorSetLuminosity(100);
ColorChecked = HSLColor.Convert(c).ToColorSetLuminosity(200); ColorChecked = HSLColor.Convert(c).ToColorSetLuminosity(200);
ColorBottom = HSLColor.Convert(c).ToColorSetLuminosity(220); ColorSelection = HSLColor.Convert(c).ToColorSetLuminosity(180);
ColorBackground = HSLColor.Convert(c).ToColorSetLuminosity(230); ColorBackground = HSLColor.Convert(c).ToColorSetLuminosity(210);
ColorTop = HSLColor.Convert(c).ToColorSetLuminosity(240); ColorTop = HSLColor.Convert(c).ToColorSetLuminosity(240);
if (ColorTheme == Color.Black)
{
ColorBorder = Color.White;
ColorBackground = Color.FromArgb(50, 50, 50);
ColorSelection = Color.FromArgb(80, 80, 80);
ColorForeground = Color.White;
}
ColorToolStrip1 = ControlPaint.LightLight(ControlPaint.LightLight(ControlPaint.Light(ColorBorder, 1))); ColorToolStrip1 = ControlPaint.LightLight(ControlPaint.LightLight(ControlPaint.Light(ColorBorder, 1)));
ColorToolStrip2 = ControlPaint.LightLight(ControlPaint.LightLight(ControlPaint.Light(ColorBorder, 0.7f))); ColorToolStrip2 = ControlPaint.LightLight(ControlPaint.LightLight(ControlPaint.Light(ColorBorder, 0.7f)));
ColorToolStrip3 = ControlPaint.LightLight(ControlPaint.LightLight(ControlPaint.Light(ColorBorder, 0.1f))); ColorToolStrip3 = ControlPaint.LightLight(ControlPaint.LightLight(ControlPaint.Light(ColorBorder, 0.1f)));
@@ -205,7 +219,10 @@ public class ToolStripRendererEx : ToolStripSystemRenderer
protected override void OnRenderToolStripBorder(ToolStripRenderEventArgs e) protected override void OnRenderToolStripBorder(ToolStripRenderEventArgs e)
{ {
ControlPaint.DrawBorder(e.Graphics, e.AffectedBounds, Color.FromArgb(160, 175, 195), ButtonBorderStyle.Solid); Rectangle r = e.AffectedBounds;
r.Inflate(-1, -1);
ControlPaint.DrawBorder(e.Graphics, r, ColorBackground, ButtonBorderStyle.Solid);
ControlPaint.DrawBorder(e.Graphics, e.AffectedBounds, ColorBorder, ButtonBorderStyle.Solid);
} }
protected override void OnRenderItemText(ToolStripItemTextRenderEventArgs e) protected override void OnRenderItemText(ToolStripItemTextRenderEventArgs e)
@@ -222,6 +239,7 @@ public class ToolStripRendererEx : ToolStripSystemRenderer
else else
TextOffset = Convert.ToInt32(e.Item.Height * 0.2); TextOffset = Convert.ToInt32(e.Item.Height * 0.2);
e.TextColor = ColorForeground;
e.TextRectangle = new Rectangle(TextOffset, Convert.ToInt32((e.Item.Height - rect.Height) / 2.0), rect.Width, rect.Height); e.TextRectangle = new Rectangle(TextOffset, Convert.ToInt32((e.Item.Height - rect.Height) / 2.0), rect.Width, rect.Height);
} }
@@ -235,16 +253,13 @@ public class ToolStripRendererEx : ToolStripSystemRenderer
Rectangle r = new Rectangle(-1, -1, e.AffectedBounds.Width, e.AffectedBounds.Height); Rectangle r = new Rectangle(-1, -1, e.AffectedBounds.Width, e.AffectedBounds.Height);
using (SolidBrush b = new SolidBrush(ColorToolStrip2)) using (SolidBrush b = new SolidBrush(ColorToolStrip2))
{
e.Graphics.FillRectangle(b, r); e.Graphics.FillRectangle(b, r);
} }
} }
}
protected override void OnRenderMenuItemBackground(ToolStripItemRenderEventArgs e) protected override void OnRenderMenuItemBackground(ToolStripItemRenderEventArgs e)
{ {
e.Item.ForeColor = Color.Black; e.Item.ForeColor = Color.Black;
var r = new Rectangle(Point.Empty, e.Item.Size); var r = new Rectangle(Point.Empty, e.Item.Size);
var g = e.Graphics; var g = e.Graphics;
@@ -252,72 +267,34 @@ public class ToolStripRendererEx : ToolStripSystemRenderer
g.Clear(ColorBackground); g.Clear(ColorBackground);
if (e.Item.Selected && e.Item.Enabled) if (e.Item.Selected && e.Item.Enabled)
{
if (e.Item.Owner is MenuStrip)
DrawButton(e);
else
{ {
g.SmoothingMode = SmoothingMode.AntiAlias; g.SmoothingMode = SmoothingMode.AntiAlias;
var r2 = new Rectangle(r.X + 2, r.Y, r.Width - 4, r.Height - 1); var r2 = new Rectangle(r.X + 2, r.Y, r.Width - 4, r.Height - 1);
using (Pen pen = new Pen(ColorBorder))
{
g.DrawRectangle(pen, r2);
}
r2.Inflate(-1, -1); r2.Inflate(-1, -1);
using (SolidBrush b = new SolidBrush(ColorSelection))
using (SolidBrush b = new SolidBrush(ColorBottom))
{
g.FillRectangle(b, r2); g.FillRectangle(b, r2);
} }
} }
}
}
public void DrawButton(ToolStripItemRenderEventArgs e)
{
var gx = e.Graphics;
var rect = new Rectangle(Point.Empty, e.Item.Size);
var rect2 = new Rectangle(rect.X, rect.Y, rect.Width - 1, rect.Height - 1);
using (Pen pen = new Pen(ColorBorder))
gx.DrawRectangle(pen, rect2);
rect2.Inflate(-1, -1);
var tsb = e.Item as ToolStripButton;
if (tsb != null && tsb.Checked)
using (SolidBrush brush = new SolidBrush(ColorChecked))
gx.FillRectangle(brush, rect2);
else
using (SolidBrush brush = new SolidBrush(ColorBottom))
gx.FillRectangle(brush, rect2);
}
protected override void OnRenderDropDownButtonBackground(ToolStripItemRenderEventArgs e)
{
if (e.Item.Selected)
DrawButton(e);
}
protected override void OnRenderButtonBackground(ToolStripItemRenderEventArgs e)
{
var button = (ToolStripButton)e.Item;
if (e.Item.Selected || button.Checked)
DrawButton(e);
}
protected override void OnRenderArrow(ToolStripArrowRenderEventArgs e) protected override void OnRenderArrow(ToolStripArrowRenderEventArgs e)
{ {
var value = e.Direction == ArrowDirection.Down ? 0x36 : 0x34; if (e.Direction == ArrowDirection.Down) throw new NotImplementedException();
var s = Convert.ToChar(value).ToString(); float x1 = e.Item.Width - e.Item.Height * 0.6f;
var font = new Font("Marlett", e.Item.Font.Size - 2); float y1 = e.Item.Height * 0.25f;
var size = e.Graphics.MeasureString(s, font); float x2 = x1 + e.Item.Height * 0.25f;
var x = Convert.ToInt32(e.Item.Width - size.Width); float y2 = e.Item.Height / 2f;
var y = Convert.ToInt32((e.Item.Height - size.Height) / 2.0) + 1; float x3 = x1;
e.Graphics.DrawString(s, font, Brushes.Black, x, y); float y3 = e.Item.Height * 0.75f;
e.Graphics.SmoothingMode = SmoothingMode.HighQuality;
using (Brush b = new SolidBrush(ColorForeground))
{
using (Pen p = new Pen(b, Control.DefaultFont.Height / 20f))
{
e.Graphics.DrawLine(p, x1, y1, x2, y2);
e.Graphics.DrawLine(p, x2, y2, x3, y3);
}
}
} }
protected override void OnRenderItemCheck(ToolStripItemImageRenderEventArgs e) protected override void OnRenderItemCheck(ToolStripItemImageRenderEventArgs e)
@@ -327,26 +304,15 @@ public class ToolStripRendererEx : ToolStripSystemRenderer
} }
protected override void OnRenderSeparator(ToolStripSeparatorRenderEventArgs e) protected override void OnRenderSeparator(ToolStripSeparatorRenderEventArgs e)
{
if (e.Item.IsOnDropDown)
{ {
e.Graphics.Clear(ColorBackground); e.Graphics.Clear(ColorBackground);
int right = e.Item.Width - Convert.ToInt32(TextOffset / 5.0);
int top = e.Item.Height / 2; int top = e.Item.Height / 2;
top -= 1; top -= 1;
using (Pen p = new Pen(Color.Gray)) int offset = Convert.ToInt32(e.Item.Font.Height * 0.7);
e.Graphics.DrawLine(p, new Point(TextOffset, top), new Point(right, top)); using (Pen p = new Pen(ColorBorder))
}
else if (e.Vertical)
{
var bounds = e.Item.Bounds;
using (Pen p = new Pen(SystemColors.ControlDarkDark))
e.Graphics.DrawLine(p, e.Graphics.DrawLine(p,
Convert.ToInt32(bounds.Width / 2.0), new Point(offset, top),
Convert.ToInt32(bounds.Height * 0.15), new Point(e.Item.Width - offset, top));
Convert.ToInt32(bounds.Width / 2.0),
Convert.ToInt32(bounds.Height * 0.85));
}
} }
} }

View File

@@ -15,6 +15,14 @@ namespace mpvnet
public static string GetFilter(IEnumerable<string> values) => "*." + public static string GetFilter(IEnumerable<string> values) => "*." +
String.Join(";*.", values) + "|*." + String.Join(";*.", values) + "|All Files|*.*"; String.Join(";*.", values) + "|*." + String.Join(";*.", values) + "|All Files|*.*";
public static bool IsDarkTheme {
get {
object value = Registry.GetValue(@"HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Themes\Personalize", "AppsUseLightTheme", 1);
if (value is null) value = 1;
return (int)value == 0;
}
}
} }
public class StringLogicalComparer : IComparer, IComparer<string> public class StringLogicalComparer : IComparer, IComparer<string>
@@ -28,16 +36,6 @@ namespace mpvnet
int IComparer<string>.Compare(string x, string y) => IComparerOfString_Compare(x, y); int IComparer<string>.Compare(string x, string y) => IComparerOfString_Compare(x, y);
} }
public class OSVersion
{
public static float Windows7 { get; } = 6.1f;
public static float Windows8 { get; } = 6.2f;
public static float Windows81 { get; } = 6.3f;
public static float Windows10 { get; } = 10f;
public static float Current => Environment.OSVersion.Version.Major + Environment.OSVersion.Version.Minor / 10f;
}
public class FileAssociation public class FileAssociation
{ {
static string ExePath = Application.ExecutablePath; static string ExePath = Application.ExecutablePath;

View File

@@ -5,6 +5,7 @@ using System.Management.Automation.Runspaces;
using System.Reflection; using System.Reflection;
using System.Threading.Tasks; using System.Threading.Tasks;
using System.Windows.Forms; using System.Windows.Forms;
using VBNET;
namespace mpvnet namespace mpvnet
{ {
@@ -47,12 +48,12 @@ Using namespace System;
throw new Exception(); throw new Exception();
} }
} }
catch catch (Exception ex2)
{ {
MainForm.Instance.ShowMsgBox("PowerShell Setup Problem\n\nEnsure you have at least PowerShell 5.1 installed.", MessageBoxIcon.Error); Msg.ShowError("PowerShell Setup Problem\n\nEnsure you have at least PowerShell 5.1 installed.", ex2.ToString());
return null; return null;
} }
MainForm.Instance.ShowMsgBox(ex.ToString(), MessageBoxIcon.Error); Msg.ShowException(ex);
} }
} }
} }

View File

@@ -10,7 +10,7 @@ using System.Runtime.InteropServices;
[assembly: AssemblyConfiguration("")] [assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")] [assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("mpv.net")] [assembly: AssemblyProduct("mpv.net")]
[assembly: AssemblyCopyright("Copyright © 2017 stax76")] [assembly: AssemblyCopyright("Copyright © 2017-2019 stax76")]
[assembly: AssemblyTrademark("")] [assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")] [assembly: AssemblyCulture("")]
@@ -32,5 +32,5 @@ using System.Runtime.InteropServices;
// You can specify all the values or you can default the Build and Revision Numbers // You can specify all the values or you can default the Build and Revision Numbers
// by using the '*' as shown below: // by using the '*' as shown below:
// [assembly: AssemblyVersion("1.0.*")] // [assembly: AssemblyVersion("1.0.*")]
[assembly: AssemblyVersion("2.3.0.0")] [assembly: AssemblyVersion("2.8.0.0")]
[assembly: AssemblyFileVersion("2.3.0.0")] [assembly: AssemblyFileVersion("2.8.0.0")]

View File

@@ -61,16 +61,20 @@ namespace mpvnet.Properties {
} }
/// <summary> /// <summary>
/// Looks up a localized string similar to # mpv.net key bindings, mouse bindings and context menu configuration /// Looks up a localized string similar to
/// # This file defines the input (keys and mouse) bindings of mpv and mpv.net
/// # and it also defines the context menu of mpv.net. mpv.net has an input
/// # editor and an conf editor as alternatives to editing conf text files.
/// # The input and conf editors can be found in mpv.net&apos;s context menu at:
/// ///
/// o script-message mpv.net open-files #menu: O ; Open Files... /// # Settings &gt; Show Config Editor
/// _ ignore #menu: _ ; - /// # Settings &gt; Show Input Editor
/// Space cycle pause #menu: Space, Enter ; Play/Pause ///
/// Enter cycle pause /// # The defaults of this file can be found at:
/// s stop #menu: S ; Stop ///
/// _ ignore #menu: _ ; - /// # https://github.com/stax76/mpv.net/blob/master/mpv.net/Resources/input.conf.txt
/// f cycle fullscreen #menu: F ; Toggle Fullscreen ///
/// [rest of string was truncated]&quot;;. /// # the [rest of string was truncated]&quot;;.
/// </summary> /// </summary>
internal static string input_conf { internal static string input_conf {
get { get {
@@ -79,15 +83,20 @@ namespace mpvnet.Properties {
} }
/// <summary> /// <summary>
/// Looks up a localized string similar to input-ar-delay = 500 /// Looks up a localized string similar to
///# mpv manual: https://mpv.io/manual/master/
///
///# mpv.net mpv.conf defaults: https://github.com/stax76/mpv.net/blob/master/mpv.net/Resources/mpv.conf.txt
///
///input-ar-delay = 500
///input-ar-rate = 20 ///input-ar-rate = 20
///volume = 50 ///volume = 50
///hwdec = yes ///hwdec = yes
///vo = direct3d
///keep-open = yes ///keep-open = yes
///keep-open-pause = no ///keep-open-pause = no
///osd-playing-msg = &apos;${filename}&apos; ///osd-playing-msg = ${filename}
///screenshot-directory = ~~desktop/. ///screenshot-directory = ~~desktop/
///input-default-bindings = no.
/// </summary> /// </summary>
internal static string mpv_conf { internal static string mpv_conf {
get { get {

View File

@@ -3,7 +3,7 @@ using System.Reflection;
using System.Windows.Forms; using System.Windows.Forms;
using IronPython.Hosting; using IronPython.Hosting;
using Microsoft.Scripting.Hosting; using Microsoft.Scripting.Hosting;
using VBNET;
using PyRT = IronPython.Runtime; using PyRT = IronPython.Runtime;
namespace mpvnet namespace mpvnet
@@ -27,7 +27,7 @@ namespace mpvnet
} }
catch (Exception ex) catch (Exception ex)
{ {
MainForm.Instance.ShowMsgBox(ex.ToString(), MessageBoxIcon.Error); Msg.ShowException(ex);
} }
} }
} }

View File

@@ -1,7 +1,7 @@
# This file defines the input (keys and mouse) bindings of mpv and mpv.net # This file defines the input (keys and mouse) bindings of mpv and mpv.net
# and it also defines the context menu of mpv.net. mpv.net has a input # and it also defines the context menu of mpv.net. mpv.net has an input
# editor and a conf editor as alternatives to editing this file via texteditor. # editor and an conf editor as alternatives to editing conf text files.
# The input and conf editors can be found in mpv.net's context menu at: # The input and conf editors can be found in mpv.net's context menu at:
# Settings > Show Config Editor # Settings > Show Config Editor
@@ -26,11 +26,15 @@
o script-message mpv.net open-files #menu: Open > Open Files... o script-message mpv.net open-files #menu: Open > Open Files...
u script-message mpv.net open-url #menu: Open > Open URL... u script-message mpv.net open-url #menu: Open > Open URL...
_ ignore #menu: Open > -
Alt+a script-message mpv.net load-audio #menu: Open > Load external audio files...
Alt+s script-message mpv.net load-sub #menu: Open > Load external subtitle files...
_ ignore #menu: - _ ignore #menu: -
Space cycle pause #menu: Play/Pause Space cycle pause #menu: Play/Pause
s stop #menu: Stop s stop #menu: Stop
_ ignore #menu: - _ ignore #menu: -
f cycle fullscreen #menu: Toggle Fullscreen Enter cycle fullscreen #menu: Toggle Fullscreen
F11 playlist-prev #menu: Navigate > Previous F11 playlist-prev #menu: Navigate > Previous
F12 playlist-next #menu: Navigate > Next F12 playlist-next #menu: Navigate > Next
@@ -49,6 +53,7 @@
_ ignore #menu: Seek > - _ ignore #menu: Seek > -
Ctrl+Right no-osd seek 300 #menu: Seek > 5 min forward Ctrl+Right no-osd seek 300 #menu: Seek > 5 min forward
Ctrl+Left no-osd seek -300 #menu: Seek > 5 min backward Ctrl+Left no-osd seek -300 #menu: Seek > 5 min backward
Ctrl++ add video-zoom 0.1 #menu: Pan & Scan > Increase Size Ctrl++ add video-zoom 0.1 #menu: Pan & Scan > Increase Size
Ctrl+- add video-zoom -0.1 #menu: Pan & Scan > Decrease Size Ctrl+- add video-zoom -0.1 #menu: Pan & Scan > Decrease Size
_ ignore #menu: Pan & Scan > - _ ignore #menu: Pan & Scan > -
@@ -59,11 +64,12 @@
Ctrl+KP2 add video-pan-y 0.01 #menu: Pan & Scan > Move Down Ctrl+KP2 add video-pan-y 0.01 #menu: Pan & Scan > Move Down
_ ignore #menu: Pan & Scan > - _ ignore #menu: Pan & Scan > -
w add panscan -0.1 #menu: Pan & Scan > Decrease Height w add panscan -0.1 #menu: Pan & Scan > Decrease Height
W add panscan +0.1 #menu: Pan & Scan > Increase Height W add panscan 0.1 #menu: Pan & Scan > Increase Height
_ ignore #menu: Pan & Scan > - _ ignore #menu: Pan & Scan > -
Ctrl+BS set video-zoom 0; set video-pan-x 0; set video-pan-y 0 #menu: Pan & Scan > Reset Ctrl+BS set video-zoom 0; set video-pan-x 0; set video-pan-y 0 #menu: Pan & Scan > Reset
Ctrl+1 add contrast -1 #menu: Video > Decrease Contrast Ctrl+1 add contrast -1 #menu: Video > Decrease Contrast
Ctrl+2 add contrast 1 #menu: Video > Increase Contrast Ctrl+2 add contrast #menu: Video > Increase Contrast
_ ignore #menu: Video > - _ ignore #menu: Video > -
Ctrl+3 add brightness -1 #menu: Video > Decrease Brightness Ctrl+3 add brightness -1 #menu: Video > Decrease Brightness
Ctrl+4 add brightness 1 #menu: Video > Increase Brightness Ctrl+4 add brightness 1 #menu: Video > Increase Brightness
@@ -77,25 +83,29 @@
Ctrl+s async screenshot #menu: Video > Take Screenshot Ctrl+s async screenshot #menu: Video > Take Screenshot
d cycle deinterlace #menu: Video > Toggle Deinterlace d cycle deinterlace #menu: Video > Toggle Deinterlace
a cycle-values video-aspect "16:9" "4:3" "2.35:1" "-1" #menu: Video > Cycle Aspect Ratio a cycle-values video-aspect "16:9" "4:3" "2.35:1" "-1" #menu: Video > Cycle Aspect Ratio
KP7 cycle audio #menu: Audio > Cycle/Next KP7 cycle audio #menu: Audio > Cycle/Next
_ ignore #menu: Audio > - _ ignore #menu: Audio > -
KP6 add audio-delay 0.100 #menu: Audio > Delay +0.1 KP6 add audio-delay 0.100 #menu: Audio > Delay +0.1
KP9 add audio-delay -0.100 #menu: Audio > Delay -0.1 KP9 add audio-delay -0.100 #menu: Audio > Delay -0.1
KP8 cycle sub #menu: Subtitle > Cycle/Next KP8 cycle sub #menu: Subtitle > Cycle/Next
v cycle sub-visibility #menu: Subtitle > Toggle Visibility v cycle sub-visibility #menu: Subtitle > Toggle Visibility
_ ignore #menu: Subtitle > - _ ignore #menu: Subtitle > -
z add sub-delay -0.1 #menu: Subtitle > Delay -0.1 z add sub-delay -0.1 #menu: Subtitle > Delay -0.1
Z add sub-delay +0.1 #menu: Subtitle > Delay +0.1 Z add sub-delay 0.1 #menu: Subtitle > Delay +0.1
_ ignore #menu: Subtitle > - _ ignore #menu: Subtitle > -
r add sub-pos -1 #menu: Subtitle > Move Up r add sub-pos -1 #menu: Subtitle > Move Up
R add sub-pos +1 #menu: Subtitle > Move Down R add sub-pos +1 #menu: Subtitle > Move Down
_ ignore #menu: Subtitle > - _ ignore #menu: Subtitle > -
_ add sub-scale -0.1 #menu: Subtitle > Decrease Subtitle Font Size _ add sub-scale -0.1 #menu: Subtitle > Decrease Subtitle Font Size
_ add sub-scale +0.1 #menu: Subtitle > Increase Subtitle Font Size _ add sub-scale 0.1 #menu: Subtitle > Increase Subtitle Font Size
+ add volume 10 #menu: Volume > Up + add volume 10 #menu: Volume > Up
- add volume -10 #menu: Volume > Down - add volume -10 #menu: Volume > Down
_ ignore #menu: Volume > - _ ignore #menu: Volume > -
m cycle mute #menu: Volume > Mute m cycle mute #menu: Volume > Mute
[ multiply speed 0.9 #menu: Speed > -10% [ multiply speed 0.9 #menu: Speed > -10%
] multiply speed 1.1 #menu: Speed > +10% ] multiply speed 1.1 #menu: Speed > +10%
_ ignore #menu: Speed > - _ ignore #menu: Speed > -
@@ -103,6 +113,7 @@
} multiply speed 2.0 #menu: Speed > Double } multiply speed 2.0 #menu: Speed > Double
_ ignore #menu: Speed > - _ ignore #menu: Speed > -
BS set speed 1 #menu: Speed > Reset BS set speed 1 #menu: Speed > Reset
KP0 script-message rate-file 0 #menu: Addons > Rating > 0stars KP0 script-message rate-file 0 #menu: Addons > Rating > 0stars
KP1 script-message rate-file 1 #menu: Addons > Rating > 1stars KP1 script-message rate-file 1 #menu: Addons > Rating > 1stars
KP2 script-message rate-file 2 #menu: Addons > Rating > 2stars KP2 script-message rate-file 2 #menu: Addons > Rating > 2stars
@@ -115,20 +126,18 @@
i script-message mpv.net show-info #menu: View > File Info i script-message mpv.net show-info #menu: View > File Info
t script-binding stats/display-stats #menu: View > Show Statistics t script-binding stats/display-stats #menu: View > Show Statistics
T script-binding stats/display-stats-toggle #menu: View > Toggle Statistics T script-binding stats/display-stats-toggle #menu: View > Toggle Statistics
Del script-binding osc/visibility #menu: View > Toggle OSC Visibility
F8 show-text ${playlist} 5000 #menu: View > Show Playlist
F9 show-text ${track-list} 5000 #menu: View > Show Audio/Video/Subtitle List
_ script-message mpv.net set-setting hwdec yes #menu: Settings > Hardware Decoding > Enable
_ script-message mpv.net set-setting hwdec no #menu: Settings > Hardware Decoding > Disable
Ctrl+c script-message mpv.net show-conf-editor #menu: Settings > Show Config Editor Ctrl+c script-message mpv.net show-conf-editor #menu: Settings > Show Config Editor
Ctrl+i script-message mpv.net show-input-editor #menu: Settings > Show Input Editor Ctrl+i script-message mpv.net show-input-editor #menu: Settings > Show Input Editor
Ctrl+f script-message mpv.net open-config-folder #menu: Settings > Open Config Folder Ctrl+f script-message mpv.net open-conf-folder #menu: Settings > Open Config Folder
h script-message mpv.net show-history #menu: Tools > Show History h script-message mpv.net show-history #menu: Tools > Show History
l ab-loop #menu: Tools > Set/clear A-B loop points l ab-loop #menu: Tools > Set/clear A-B loop points
L cycle-values loop-file "inf" "no" #menu: Tools > Toggle Infinite Looping L cycle-values loop-file "inf" "no" #menu: Tools > Toggle infinite file looping
Del script-binding osc/visibility #menu: Tools > Toggle OSC Visibility
Ctrl+h cycle-values hwdec "auto" "no" #menu: Tools > Cycle Hardware Decoding Ctrl+h cycle-values hwdec "auto" "no" #menu: Tools > Cycle Hardware Decoding
F8 show-text ${playlist} 5000 #menu: Tools > Show Playlist
F9 show-text ${track-list} 5000 #menu: Tools > Show Audio/Video/Subtitle List
_ script-message mpv.net execute-mpv-command #menu: Tools > Execute mpv command... _ script-message mpv.net execute-mpv-command #menu: Tools > Execute mpv command...
_ script-message mpv.net shell-execute https://mpv.io/manual/stable/ #menu: Help > Show mpv manual _ script-message mpv.net shell-execute https://mpv.io/manual/stable/ #menu: Help > Show mpv manual
@@ -141,7 +150,6 @@
Q quit-watch-later #menu: Exit Watch Later Q quit-watch-later #menu: Exit Watch Later
> playlist-next > playlist-next
< playlist-prev < playlist-prev
Enter cycle pause
Power quit Power quit
Play cycle pause Play cycle pause
Pause cycle pause Pause cycle pause

View File

@@ -11,6 +11,7 @@ using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
using System.Windows.Forms; using System.Windows.Forms;
using VBNET;
using static mpvnet.libmpv; using static mpvnet.libmpv;
using static mpvnet.Native; using static mpvnet.Native;
@@ -60,6 +61,7 @@ namespace mpvnet
public static string mpvConfFolderPath = Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData) + "\\mpv\\"; public static string mpvConfFolderPath = Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData) + "\\mpv\\";
public static string InputConfPath = Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData) + "\\mpv\\input.conf"; public static string InputConfPath = Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData) + "\\mpv\\input.conf";
public static string mpvConfPath = Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData) + "\\mpv\\mpv.conf"; public static string mpvConfPath = Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData) + "\\mpv\\mpv.conf";
public static string mpvNetConfPath = Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData) + "\\mpv\\mpvnet.conf";
public static List<PythonScript> PythonScripts => new List<PythonScript>(); public static List<PythonScript> PythonScripts => new List<PythonScript>();
public static AutoResetEvent AutoResetEvent = new AutoResetEvent(false); public static AutoResetEvent AutoResetEvent = new AutoResetEvent(false);
@@ -80,6 +82,23 @@ namespace mpvnet
} }
} }
private static Dictionary<string, string> _mpvNetConf;
public static Dictionary<string, string> mpvNetConf {
get {
if (_mpvNetConf == null)
{
_mpvNetConf = new Dictionary<string, string>();
if (File.Exists(mpvNetConfPath))
foreach (string i in File.ReadAllLines(mpvNetConfPath))
if (i.Contains("=") && !i.StartsWith("#"))
_mpvNetConf[i.Substring(0, i.IndexOf("=")).Trim()] = i.Substring(i.IndexOf("=") + 1).Trim();
}
return _mpvNetConf;
}
}
public static void Init() public static void Init()
{ {
if (!Directory.Exists(mp.mpvConfFolderPath)) if (!Directory.Exists(mp.mpvConfFolderPath))
@@ -196,8 +215,6 @@ namespace mpvnet
break; break;
case mpv_event_id.MPV_EVENT_CLIENT_MESSAGE: case mpv_event_id.MPV_EVENT_CLIENT_MESSAGE:
if (ClientMessage != null) if (ClientMessage != null)
{
try
{ {
var client_messageData = (mpv_event_client_message)Marshal.PtrToStructure(evt.data, typeof(mpv_event_client_message)); var client_messageData = (mpv_event_client_message)Marshal.PtrToStructure(evt.data, typeof(mpv_event_client_message));
string[] args = NativeUtf8StrArray2ManagedStrArray(client_messageData.args, client_messageData.num_args); string[] args = NativeUtf8StrArray2ManagedStrArray(client_messageData.args, client_messageData.num_args);
@@ -218,16 +235,11 @@ namespace mpvnet
{ {
List<string> names = mpvnet.Command.Commands.Select((item) => item.Name).ToList(); List<string> names = mpvnet.Command.Commands.Select((item) => item.Name).ToList();
names.Sort(); names.Sort();
MainForm.Instance.ShowMsgBox($"No command '{args[1]}' found. Available commands are:\n\n{string.Join("\n", names)}\n\nHow to bind these commands can be seen in the default input bindings and menu definition located at:\n\nhttps://github.com/stax76/mpv.net/blob/master/mpv.net/Resources/input.conf.txt", MessageBoxIcon.Error); Msg.ShowError($"No command '{args[1]}' found.", $"Available commands are:\n\n{string.Join("\n", names)}\n\nHow to bind these commands can be seen in the [https://github.com/stax76/mpv.net/blob/master/mpv.net/Resources/input.conf.txt default input bindings and menu definition].");
} }
} }
ClientMessage?.Invoke(args); ClientMessage?.Invoke(args);
} }
catch (Exception ex)
{
MainForm.Instance.ShowMsgBox(ex.GetType().Name + "\n\n" + ex.ToString(), MessageBoxIcon.Error);
}
}
break; break;
case mpv_event_id.MPV_EVENT_VIDEO_RECONFIG: case mpv_event_id.MPV_EVENT_VIDEO_RECONFIG:
VideoReconfig?.Invoke(); VideoReconfig?.Invoke();
@@ -272,7 +284,7 @@ namespace mpvnet
} }
catch (Exception ex) catch (Exception ex)
{ {
MainForm.Instance.ShowMsgBox(ex.ToString(), MessageBoxIcon.Error); Msg.ShowException(ex);
} }
} }
} }
@@ -359,6 +371,8 @@ namespace mpvnet
} }
public static string get_property_string(string name, bool throwOnException = false) public static string get_property_string(string name, bool throwOnException = false)
{
try
{ {
int err = mpv_get_property(MpvHandle, GetUtf8Bytes(name), mpv_format.MPV_FORMAT_STRING, out IntPtr lpBuffer); int err = mpv_get_property(MpvHandle, GetUtf8Bytes(name), mpv_format.MPV_FORMAT_STRING, out IntPtr lpBuffer);
@@ -370,6 +384,12 @@ namespace mpvnet
return ret; return ret;
} }
catch (Exception ex)
{
if (throwOnException) throw ex;
return "";
}
}
public static int get_property_int(string name, bool throwOnException = false) public static int get_property_int(string name, bool throwOnException = false)
{ {

View File

@@ -25,6 +25,7 @@
<WarningLevel>4</WarningLevel> <WarningLevel>4</WarningLevel>
<Prefer32Bit>false</Prefer32Bit> <Prefer32Bit>false</Prefer32Bit>
<GenerateSerializationAssemblies>On</GenerateSerializationAssemblies> <GenerateSerializationAssemblies>On</GenerateSerializationAssemblies>
<LangVersion>7.3</LangVersion>
</PropertyGroup> </PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' "> <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<PlatformTarget>AnyCPU</PlatformTarget> <PlatformTarget>AnyCPU</PlatformTarget>
@@ -192,7 +193,12 @@
<Content Include="screenshot.jpg" /> <Content Include="screenshot.jpg" />
<Content Include="Resources\input.conf.txt" /> <Content Include="Resources\input.conf.txt" />
</ItemGroup> </ItemGroup>
<ItemGroup /> <ItemGroup>
<ProjectReference Include="..\VBNET\VBNET.vbproj">
<Project>{a1d11294-05bf-4d77-b008-aecf1aa93c9f}</Project>
<Name>VBNET</Name>
</ProjectReference>
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" /> <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<!-- To modify your build process, add your task inside one of the targets below and uncomment it. <!-- To modify your build process, add your task inside one of the targets below and uncomment it.
Other similar extension points exist, see Microsoft.Common.targets. Other similar extension points exist, see Microsoft.Common.targets.

View File

@@ -1,7 +1,7 @@
<Application x:Class="DynamicGUI.App" <Application x:Class="mpvConfEdit.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:DynamicGUI" xmlns:Controls="clr-namespace:Controls"
StartupUri="MainWindow.xaml"> StartupUri="MainWindow.xaml">
<Application.Resources> <Application.Resources>
<Style TargetType="TextBox"> <Style TargetType="TextBox">
@@ -19,7 +19,7 @@
<Setter Property="BorderBrush" TargetName="border" Value="#FF7EB4EA"/> <Setter Property="BorderBrush" TargetName="border" Value="#FF7EB4EA"/>
</Trigger> </Trigger>
<Trigger Property="IsFocused" Value="true"> <Trigger Property="IsFocused" Value="true">
<Setter Property="BorderBrush" TargetName="border" Value="{x:Static SystemParameters.WindowGlassBrush}"/> <Setter Property="BorderBrush" TargetName="border" Value="{x:Static Controls:Controls.ThemeBrush}"/>
</Trigger> </Trigger>
</ControlTemplate.Triggers> </ControlTemplate.Triggers>
</ControlTemplate> </ControlTemplate>

View File

@@ -1,6 +1,6 @@
using System.Windows; using System.Windows;
namespace DynamicGUI namespace mpvConfEdit
{ {
public partial class App : Application public partial class App : Application
{ {

18
mpvConfEdit/Controls.cs Normal file
View File

@@ -0,0 +1,18 @@
using System;
using System.Windows;
using System.Windows.Media;
namespace Controls
{
class Controls
{
public static Brush ThemeBrush {
get {
if (Environment.OSVersion.Version.Major < 10)
return new SolidColorBrush(Colors.DimGray);
else
return SystemParameters.WindowGlassBrush;
}
}
}
}

View File

@@ -54,7 +54,6 @@ namespace DynamicGUI
baseSetting.Filter = setting["filter"]; baseSetting.Filter = setting["filter"];
if (setting.HasKey("help")) baseSetting.Help = setting["help"]; if (setting.HasKey("help")) baseSetting.Help = setting["help"];
if (setting.HasKey("helpurl")) baseSetting.HelpURL = setting["helpurl"]; if (setting.HasKey("helpurl")) baseSetting.HelpURL = setting["helpurl"];
if (setting.HasKey("alias")) baseSetting.Alias = setting["alias"];
if (setting.HasKey("width")) baseSetting.Width = setting["width"]; if (setting.HasKey("width")) baseSetting.Width = setting["width"];
settingsList.Add(baseSetting); settingsList.Add(baseSetting);
} }
@@ -65,8 +64,9 @@ namespace DynamicGUI
public abstract class SettingBase public abstract class SettingBase
{ {
public string Name { get; set; } public string Name { get; set; }
public string Alias { get; set; } public string Value { get; set; }
public string Help { get; set; } public string Help { get; set; }
public string Default { get; set; }
public string HelpURL { get; set; } public string HelpURL { get; set; }
public string Filter { get; set; } public string Filter { get; set; }
public int Width { get; set; } public int Width { get; set; }
@@ -74,15 +74,11 @@ namespace DynamicGUI
public class StringSetting : SettingBase public class StringSetting : SettingBase
{ {
public string Default { get; set; }
public string Value { get; set; }
public bool IsFolder { get; set; } public bool IsFolder { get; set; }
} }
public class OptionSetting : SettingBase public class OptionSetting : SettingBase
{ {
public string Default { get; set; }
public string Value { get; set; }
public List<OptionSettingOption> Options = new List<OptionSettingOption>(); public List<OptionSettingOption> Options = new List<OptionSettingOption>();
} }

View File

@@ -8,18 +8,18 @@
d:DesignHeight="450" d:DesignWidth="800"> d:DesignHeight="450" d:DesignWidth="800">
<Grid Margin="20,0"> <Grid Margin="20,0">
<StackPanel> <StackPanel>
<TextBox x:Name="TitleTextBox" FontSize="24" Margin="0,10" BorderThickness="0" IsReadOnly="True" Foreground="{x:Static SystemParameters.WindowGlassBrush}"></TextBox> <TextBox x:Name="TitleTextBox" FontSize="24" Margin="0,10" BorderThickness="0" IsReadOnly="True" Foreground="{Binding Path=Foreground, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=Window}}" Background="{Binding Path=Background, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=Window}}"></TextBox>
<ItemsControl x:Name="ItemsControl"> <ItemsControl x:Name="ItemsControl">
<ItemsControl.ItemTemplate> <ItemsControl.ItemTemplate>
<DataTemplate> <DataTemplate>
<WrapPanel Orientation="Vertical"> <WrapPanel Orientation="Vertical">
<RadioButton x:Name="RadioButton" VerticalContentAlignment="Center" IsChecked="{Binding IsChecked}" GroupName="{Binding OptionSetting.Name}" Content="{Binding Text}" FontSize="16" FontWeight="Normal" VerticalAlignment="Top"></RadioButton> <RadioButton x:Name="RadioButton" VerticalContentAlignment="Center" IsChecked="{Binding IsChecked}" GroupName="{Binding OptionSetting.Name}" Content="{Binding Text}" FontSize="16" FontWeight="Normal" VerticalAlignment="Top" Foreground="{Binding Path=Foreground, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=Window}}"></RadioButton>
<TextBox x:Name="ItemHelpTextBox" TextWrapping="WrapWithOverflow" Text="{Binding Help}" Margin="10,0,0,0" BorderThickness="0" IsReadOnly="True" Padding="7,0,0,0" MinHeight="0"></TextBox> <TextBox x:Name="ItemHelpTextBox" TextWrapping="WrapWithOverflow" Text="{Binding Help}" Margin="10,0,0,0" BorderThickness="0" IsReadOnly="True" Padding="7,0,0,0" MinHeight="0" Foreground="{Binding Path=Foreground2, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=Window}}" Background="{Binding Path=Background, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=Window}}"></TextBox>
</WrapPanel> </WrapPanel>
</DataTemplate> </DataTemplate>
</ItemsControl.ItemTemplate> </ItemsControl.ItemTemplate>
</ItemsControl> </ItemsControl>
<TextBox x:Name="HelpTextBox" TextWrapping="WrapWithOverflow" BorderThickness="0" IsReadOnly="True" Margin="0,10,0,0"></TextBox> <TextBox x:Name="HelpTextBox" TextWrapping="WrapWithOverflow" BorderThickness="0" IsReadOnly="True" Margin="0,10,0,0" Foreground="{Binding Path=Foreground, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=UserControl}}" Background="{Binding Path=Background, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=UserControl}}"></TextBox>
<TextBlock x:Name="LinkTextBlock" Margin="0,10"> <TextBlock x:Name="LinkTextBlock" Margin="0,10">
<local:HyperlinkEx x:Name="Link"></local:HyperlinkEx> <local:HyperlinkEx x:Name="Link"></local:HyperlinkEx>
</TextBlock> </TextBlock>

View File

@@ -15,7 +15,6 @@ namespace DynamicGUI
HelpTextBox.Text = optionSetting.Help; HelpTextBox.Text = optionSetting.Help;
ItemsControl.ItemsSource = optionSetting.Options; ItemsControl.ItemsSource = optionSetting.Options;
Link.SetURL(optionSetting.HelpURL); Link.SetURL(optionSetting.HelpURL);
if (string.IsNullOrEmpty(optionSetting.HelpURL)) if (string.IsNullOrEmpty(optionSetting.HelpURL))
LinkTextBlock.Visibility = Visibility.Collapsed; LinkTextBlock.Visibility = Visibility.Collapsed;
} }

View File

@@ -9,16 +9,16 @@
d:DesignWidth="800" > d:DesignWidth="800" >
<Grid Margin="20,0"> <Grid Margin="20,0">
<StackPanel> <StackPanel>
<TextBox x:Name="TitleTextBox" FontSize="24" Margin="0,10" BorderThickness="0" IsReadOnly="True" Foreground="{x:Static SystemParameters.WindowGlassBrush}"></TextBox> <TextBox x:Name="TitleTextBox" FontSize="24" Margin="0,10" BorderThickness="0" IsReadOnly="True" Foreground="{Binding Path=Foreground, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=Window}}" Background="{Binding Path=Background, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=Window}}"></TextBox>
<Grid Margin="0,0,0,10"> <Grid Margin="0,0,0,10">
<Grid.ColumnDefinitions> <Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" /> <ColumnDefinition Width="Auto" />
<ColumnDefinition Width="Auto" /> <ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions> </Grid.ColumnDefinitions>
<TextBox x:Name="ValueTextBox" Text="{Binding Path=Text, ElementName=StringSettingControl1, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" Width="150" HorizontalAlignment="Left" Height="20"/> <TextBox x:Name="ValueTextBox" Text="{Binding Path=Text, ElementName=StringSettingControl1, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" Width="150" HorizontalAlignment="Left" Height="20" Foreground="{Binding Path=Foreground, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=Window}}" Background="{Binding Path=Background, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=Window}}"/>
<Button x:Name="Button" Height="20" Grid.Column="1" Visibility="{Binding Path=Text, ElementName=StringSettingControl1}" Margin="5,0,0,0" Width="20" Click="Button_Click">...</Button> <Button x:Name="Button" Height="20" Grid.Column="1" Visibility="{Binding Path=Text, ElementName=StringSettingControl1}" Margin="5,0,0,0" Width="20" Click="Button_Click">...</Button>
</Grid> </Grid>
<TextBox x:Name="HelpTextBox" TextWrapping="WrapWithOverflow" Margin="0,0,0,10" BorderThickness="0" IsReadOnly="True"></TextBox> <TextBox x:Name="HelpTextBox" TextWrapping="WrapWithOverflow" Margin="0,0,0,10" BorderThickness="0" IsReadOnly="True" Foreground="{Binding Path=Foreground, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=Window}}" Background="{Binding Path=Background, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=Window}}"></TextBox>
<TextBlock x:Name="LinkTextBlock" Margin="0,10"> <TextBlock x:Name="LinkTextBlock" Margin="0,10">
<local:HyperlinkEx x:Name="Link"></local:HyperlinkEx> <local:HyperlinkEx x:Name="Link"></local:HyperlinkEx>
</TextBlock> </TextBlock>

View File

@@ -19,7 +19,6 @@ namespace DynamicGUI
if (!StringSetting.IsFolder) if (!StringSetting.IsFolder)
Button.Visibility = Visibility.Hidden; Button.Visibility = Visibility.Hidden;
Link.SetURL(StringSetting.HelpURL); Link.SetURL(StringSetting.HelpURL);
if (string.IsNullOrEmpty(stringSetting.HelpURL)) if (string.IsNullOrEmpty(stringSetting.HelpURL))
LinkTextBlock.Visibility = Visibility.Collapsed; LinkTextBlock.Visibility = Visibility.Collapsed;
} }

View File

@@ -4,7 +4,7 @@
xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d" mc:Ignorable="d"
Height="500" Width="700" Loaded="MainWindow1_Loaded"> Height="500" Width="700" Loaded="MainWindow1_Loaded" WindowStartupLocation="CenterScreen">
<Grid> <Grid>
<Grid.RowDefinitions> <Grid.RowDefinitions>
<RowDefinition Height="Auto" /> <RowDefinition Height="Auto" />
@@ -14,12 +14,12 @@
<ColumnDefinition Width="10*" /> <ColumnDefinition Width="10*" />
<ColumnDefinition Width="60*" /> <ColumnDefinition Width="60*" />
</Grid.ColumnDefinitions> </Grid.ColumnDefinitions>
<Controls:SearchTextBoxUserControl x:Name="SearchControl" Width="300" Margin="0,0,0,10" Grid.ColumnSpan="2" /> <Controls:SearchTextBoxUserControl x:Name="SearchControl" Width="250" Margin="0,20,0,10" Grid.ColumnSpan="2" />
<ScrollViewer x:Name="MainScrollViewer" VerticalScrollBarVisibility="Auto" Grid.Row="1" Grid.Column="1"> <ScrollViewer x:Name="MainScrollViewer" VerticalScrollBarVisibility="Auto" Grid.Row="1" Grid.Column="1" Margin="0,0,0,10">
<StackPanel x:Name="MainStackPanel"></StackPanel> <StackPanel x:Name="MainStackPanel"></StackPanel>
</ScrollViewer> </ScrollViewer>
<StackPanel Margin="20,0,0,0" Grid.Row="1"> <StackPanel Margin="20,0,0,0" Grid.Row="1">
<ListBox x:Name="FilterListBox" ItemsSource="{Binding FilterStrings}" BorderThickness="0" SelectionChanged="ListBox_SelectionChanged" Foreground="{x:Static SystemParameters.WindowGlassBrush}"> <ListBox x:Name="FilterListBox" ItemsSource="{Binding FilterStrings}" BorderThickness="0" SelectionChanged="ListBox_SelectionChanged" Foreground="{x:Static Controls:Controls.ThemeBrush}" Background="{Binding Path=Background, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=Window}}">
<ListBox.ItemTemplate> <ListBox.ItemTemplate>
<DataTemplate> <DataTemplate>
<StackPanel Orientation="Horizontal"> <StackPanel Orientation="Horizontal">
@@ -28,9 +28,10 @@
</DataTemplate> </DataTemplate>
</ListBox.ItemTemplate> </ListBox.ItemTemplate>
</ListBox> </ListBox>
<TextBlock x:Name="OpenSettingsTextBlock" Margin="0,30,0,0" Cursor="Hand" TextWrapping="WrapWithOverflow" Foreground="{x:Static SystemParameters.WindowGlassBrush}" MouseUp="OpenSettingsTextBlock_MouseUp">Open settings folder</TextBlock> <TextBlock x:Name="OpenSettingsTextBlock" Margin="0,30,0,0" Cursor="Hand" TextWrapping="WrapWithOverflow" Foreground="{x:Static Controls:Controls.ThemeBrush}" MouseUp="OpenSettingsTextBlock_MouseUp">Open config folder</TextBlock>
<TextBlock x:Name="ShowManualTextBlock" Margin="0,15,0,0" Cursor="Hand" TextWrapping="WrapWithOverflow" Foreground="{x:Static SystemParameters.WindowGlassBrush}" MouseUp="ShowManualTextBlock_MouseUp">Show mpv manual</TextBlock> <TextBlock x:Name="ShowManualTextBlock" Margin="0,15,0,0" Cursor="Hand" TextWrapping="WrapWithOverflow" Foreground="{x:Static Controls:Controls.ThemeBrush}" MouseUp="ShowManualTextBlock_MouseUp">Show mpv manual</TextBlock>
<TextBlock x:Name="SupportTextBlock" Margin="0,15,0,0" Cursor="Hand" TextWrapping="WrapWithOverflow" Foreground="{x:Static SystemParameters.WindowGlassBrush}" MouseUp="SupportTextBlock_MouseUp">Show support forum</TextBlock> <TextBlock x:Name="SupportTextBlock" Margin="0,15,0,0" Cursor="Hand" TextWrapping="WrapWithOverflow" Foreground="{x:Static Controls:Controls.ThemeBrush}" MouseUp="SupportTextBlock_MouseUp">Show support forum</TextBlock>
<TextBlock x:Name="ApplyTextBlock" Margin="0,15,0,0" Cursor="Hand" TextWrapping="WrapWithOverflow" Foreground="{x:Static Controls:Controls.ThemeBrush}" MouseUp="ApplyTextBlock_MouseUp">Write config to disk</TextBlock>
</StackPanel> </StackPanel>
</Grid> </Grid>
</Window> </Window>

View File

@@ -8,15 +8,20 @@ using System.Reflection;
using System.Windows; using System.Windows;
using System.Windows.Controls; using System.Windows.Controls;
using System.Windows.Input; using System.Windows.Input;
using System.Windows.Media;
using DynamicGUI; using DynamicGUI;
using Microsoft.Win32;
namespace mpvConfEdit namespace mpvConfEdit
{ {
public partial class MainWindow : Window public partial class MainWindow : Window
{ {
public string mpvConfPath = Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData) + "\\mpv\\mpv.conf"; public string MpvConfPath = Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData) + "\\mpv\\mpv.conf";
private List<SettingBase> DynamicSettings = Settings.LoadSettings(Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().Location) + "\\mpvConfEdit.toml"); public string MpvNetConfPath = Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData) + "\\mpv\\mpvnet.conf";
private List<SettingBase> MpvSettingsDefinitions = Settings.LoadSettings(Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().Location) + "\\mpvConf.toml");
private List<SettingBase> MpvNetSettingsDefinitions = Settings.LoadSettings(Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().Location) + "\\mpvNetConf.toml");
public ObservableCollection<string> FilterStrings { get; } = new ObservableCollection<string>();
private Dictionary<string, Dictionary<string, string>> Comments = new Dictionary<string, Dictionary<string, string>>();
public MainWindow() public MainWindow()
{ {
@@ -24,31 +29,77 @@ namespace mpvConfEdit
DataContext = this; DataContext = this;
Title = (Assembly.GetExecutingAssembly().GetCustomAttributes(typeof(AssemblyProductAttribute), true)[0] as AssemblyProductAttribute).Product + " " + Assembly.GetExecutingAssembly().GetName().Version.ToString(); Title = (Assembly.GetExecutingAssembly().GetCustomAttributes(typeof(AssemblyProductAttribute), true)[0] as AssemblyProductAttribute).Product + " " + Assembly.GetExecutingAssembly().GetName().Version.ToString();
SearchControl.SearchTextBox.TextChanged += SearchTextBox_TextChanged; SearchControl.SearchTextBox.TextChanged += SearchTextBox_TextChanged;
LoadSettings(MpvSettingsDefinitions, MpvConf);
LoadSettings(MpvNetSettingsDefinitions, MpvNetConf);
SearchControl.Text = (string)Registry.GetValue(@"HKEY_CURRENT_USER\Software\mpv.net", "conf editor search", "");
SetDarkTheme();
}
foreach (var setting in DynamicSettings) public Brush Foreground2 {
get { return (Brush)GetValue(Foreground2Property); }
set { SetValue(Foreground2Property, value); }
}
public static readonly DependencyProperty Foreground2Property =
DependencyProperty.Register("Foreground2", typeof(Brush), typeof(MainWindow), new PropertyMetadata(Brushes.DarkSlateGray));
void SetDarkTheme()
{
string darkMode = MpvNetSettingsDefinitions.Where(item => item.Name == "dark-mode").First().Value;
object value = Registry.GetValue(@"HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Themes\Personalize", "AppsUseLightTheme", 1);
if (value is null) value = 1;
bool isDarkTheme = (int)value == 0;
if (!((darkMode == "system" && isDarkTheme) || darkMode == "always"))
return;
//Background = new SolidColorBrush(Colors.Black);
Foreground = Brushes.White;
Foreground2 = Brushes.Silver;
Background = Brushes.Black;
//foreach (var i in MainStackPanel.Children)
//{
// switch (i)
// {
// case OptionSettingControl c:
// c.Foreground = Brushes.White;
// c.Background = Brushes.Black;
// break;
// }
//}
}
private void LoadSettings(List<SettingBase> settingsDefinitions,
Dictionary<string, string> confSettings)
{
foreach (var setting in settingsDefinitions)
{ {
if (!FilterStrings.Contains(setting.Filter)) if (!FilterStrings.Contains(setting.Filter))
FilterStrings.Add(setting.Filter); FilterStrings.Add(setting.Filter);
foreach (var pair in mpvConf)
foreach (var pair in confSettings)
{ {
if (setting.Name == pair.Key || setting.Alias == pair.Key) if (setting.Name == pair.Key)
switch (setting)
{ {
case StringSetting s: setting.Value = pair.Value;
s.Value = pair.Value;
continue; continue;
case OptionSetting s:
s.Value = pair.Value;
break;
} }
} }
switch (setting) switch (setting)
{ {
case StringSetting s: case StringSetting s:
MainStackPanel.Children.Add(new StringSettingControl(s)); var sc = new StringSettingControl(s);
sc.TitleTextBox.Foreground = Controls.Controls.ThemeBrush;
MainStackPanel.Children.Add(sc);
break; break;
case OptionSetting s: case OptionSetting s:
MainStackPanel.Children.Add(new OptionSettingControl(s)); var oc = new OptionSettingControl(s);
oc.TitleTextBox.Foreground = Controls.Controls.ThemeBrush;
MainStackPanel.Children.Add(oc);
break; break;
} }
} }
@@ -56,105 +107,94 @@ namespace mpvConfEdit
private Dictionary<string, string> _mpvConf; private Dictionary<string, string> _mpvConf;
public Dictionary<string, string> mpvConf { public Dictionary<string, string> MpvConf {
get { get {
if (_mpvConf == null) if (_mpvConf == null) _mpvConf = LoadConf(MpvConfPath);
{
_mpvConf = new Dictionary<string, string>();
if (File.Exists(mpvConfPath))
foreach (var i in File.ReadAllLines(mpvConfPath))
if (i.Contains("=") && !i.Trim().StartsWith("#"))
{
int pos = i.IndexOf("=");
_mpvConf[i.Substring(0, pos).Trim()] = i.Substring(pos + 1).Trim();
}
}
return _mpvConf; return _mpvConf;
} }
} }
public ObservableCollection<string> FilterStrings { get; } = new ObservableCollection<string>(); private Dictionary<string, string> _mpvNetConf;
public Dictionary<string, string> MpvNetConf {
get {
if (_mpvNetConf == null) _mpvNetConf = LoadConf(MpvNetConfPath);
return _mpvNetConf;
}
}
private Dictionary<string, string> LoadConf(string filePath)
{
Dictionary<string, string> conf = new Dictionary<string, string>();
Comments[filePath] = new Dictionary<string, string>();
if (File.Exists(filePath))
{
foreach (string i in File.ReadAllLines(filePath))
{
if (i.Contains("="))
{
int pos = i.IndexOf("=");
string left = i.Substring(0, pos).Replace(" ", "").ToLower();
string right = i.Substring(pos + 1).Trim();
if (left.StartsWith("#"))
{
Comments[filePath][left.TrimStart("#".ToCharArray())] = right;
continue;
}
if (left == "fs") left = "fullscreen";
if (left == "loop") left = "loop-file";
conf[left] = right;
}
}
}
return conf;
}
protected override void OnClosed(EventArgs e) protected override void OnClosed(EventArgs e)
{ {
base.OnClosed(e); base.OnClosed(e);
WriteToDisk();
Registry.SetValue(@"HKEY_CURRENT_USER\Software\mpv.net", "conf editor search", SearchControl.Text);
}
foreach (var mpvSetting in DynamicSettings) void WriteToDisk()
{ {
switch (mpvSetting) WriteToDisk(MpvConfPath, MpvConf, MpvSettingsDefinitions);
WriteToDisk(MpvNetConfPath, MpvNetConf, MpvNetSettingsDefinitions);
MessageBox.Show("Changes will be available on next startup of mpv(.net).",
Title, MessageBoxButton.OK, MessageBoxImage.Information);
}
void WriteToDisk(string filePath,
Dictionary<string, string> confSettings,
List<SettingBase> settings)
{ {
case StringSetting s: string content = "";
if ((s.Value ?? "") != s.Default)
mpvConf[s.Name] = s.Value; foreach (var i in Comments[filePath])
else content += $"#{i.Key} = {i.Value}\r\n";
mpvConf.Remove(s.Name);
break; foreach (var setting in settings)
case OptionSetting s: {
if ((s.Value ?? "") != s.Default) if ((setting.Value ?? "") != setting.Default)
mpvConf[s.Name] = s.Value; confSettings[setting.Name] = setting.Value;
else
mpvConf.Remove(s.Name); if (confSettings.ContainsKey(setting.Name) &&
break; (setting.Value ?? "") == setting.Default ||
(setting.Value ?? "") == "")
{
confSettings.Remove(setting.Name);
} }
} }
if (!File.Exists(mpvConfPath)) foreach (var i in confSettings)
File.WriteAllText(mpvConfPath, ""); content = content + $"{i.Key} = {i.Value}\r\n";
List<string> lines = File.ReadAllLines(mpvConfPath).ToList(); File.WriteAllText(filePath, content);
foreach (var mpvSetting in DynamicSettings)
{
foreach (var line in lines.ToArray())
{
string test = line.Replace("#", "").Replace(" ", "");
if (test.StartsWith(mpvSetting.Alias + "="))
{
lines.Remove(line);
foreach (var pair in mpvConf.ToArray())
if (test.StartsWith(pair.Key + "="))
mpvConf.Remove(pair.Key);
}
}
}
foreach (var pair in mpvConf)
{
bool changed = false;
for (int i = 0; i < lines.Count; i++)
{
if (lines[i].Contains("=") &&
lines[i].Substring(0, lines[i].IndexOf("=")).Trim("# ".ToCharArray()) == pair.Key)
{
lines[i] = pair.Key + " = " + pair.Value;
changed = true;
}
}
if (!changed)
lines.Add(pair.Key + " = " + pair.Value);
}
foreach (var mpvSetting in DynamicSettings)
{
foreach (var line in lines.ToArray())
{
string test = line.Replace("#", "").Replace(" ", "");
if (test.StartsWith(mpvSetting.Name + "=") && !mpvConf.ContainsKey(mpvSetting.Name))
lines.Remove(line);
}
}
File.WriteAllText(mpvConfPath, String.Join(Environment.NewLine, lines));
foreach (Process process in Process.GetProcesses())
if (process.ProcessName == "mpvnet")
MessageBox.Show("Restart mpv.net in order to apply changed settings.", Title, MessageBoxButton.OK, MessageBoxImage.Information);
else if (process.ProcessName == "mpv")
MessageBox.Show("Restart mpv in order to apply changed settings.", Title, MessageBoxButton.OK, MessageBoxImage.Information);
} }
private void SearchTextBox_TextChanged(object sender, TextChangedEventArgs e) private void SearchTextBox_TextChanged(object sender, TextChangedEventArgs e)
@@ -198,7 +238,7 @@ namespace mpvConfEdit
private void OpenSettingsTextBlock_MouseUp(object sender, MouseButtonEventArgs e) private void OpenSettingsTextBlock_MouseUp(object sender, MouseButtonEventArgs e)
{ {
Process.Start(Path.GetDirectoryName(mpvConfPath)); Process.Start(Path.GetDirectoryName(MpvConfPath));
} }
private void ShowManualTextBlock_MouseUp(object sender, MouseButtonEventArgs e) private void ShowManualTextBlock_MouseUp(object sender, MouseButtonEventArgs e)
@@ -210,5 +250,10 @@ namespace mpvConfEdit
{ {
Process.Start("https://github.com/stax76/mpv.net#Support"); Process.Start("https://github.com/stax76/mpv.net#Support");
} }
private void ApplyTextBlock_MouseUp(object sender, MouseButtonEventArgs e)
{
WriteToDisk();
}
} }
} }

View File

@@ -12,7 +12,7 @@ using System.Windows;
[assembly: AssemblyConfiguration("")] [assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")] [assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("mpv(.net) conf edit")] [assembly: AssemblyProduct("mpv(.net) conf edit")]
[assembly: AssemblyCopyright("Copyright © stax76")] [assembly: AssemblyCopyright("Copyright © 2017-2019 stax76")]
[assembly: AssemblyTrademark("")] [assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")] [assembly: AssemblyCulture("")]
@@ -51,5 +51,5 @@ using System.Windows;
// You can specify all the values or you can default the Build and Revision Numbers // You can specify all the values or you can default the Build and Revision Numbers
// by using the '*' as shown below: // by using the '*' as shown below:
// [assembly: AssemblyVersion("1.0.*")] // [assembly: AssemblyVersion("1.0.*")]
[assembly: AssemblyVersion("1.1.0.0")] [assembly: AssemblyVersion("1.7.0.0")]
[assembly: AssemblyFileVersion("1.1.0.0")] [assembly: AssemblyFileVersion("1.7.0.0")]

View File

@@ -5,9 +5,9 @@
xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
mc:Ignorable="d" mc:Ignorable="d"
d:DesignHeight="450" d:DesignWidth="800"> d:DesignHeight="450" d:DesignWidth="800">
<Grid x:Name="SearchTextBoxUserControl1" Background="White"> <Grid x:Name="SearchTextBoxUserControl1" Background="{Binding Path=Background, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=Window}}">
<TextBlock x:Name="SearchTextBlock" Margin="5,2" Text="Find a setting" Foreground="LightSteelBlue" VerticalAlignment="Center" /> <TextBlock x:Name="HintTextBlock" Margin="5,2" Text="Find a setting" Foreground="LightSteelBlue" VerticalAlignment="Center" Background="{Binding Path=Background, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=Window}}" />
<TextBox Name="SearchTextBox" Height="25" Padding="1,2,0,0" BorderThickness="2" Background="Transparent" TextChanged="SearchTextBox_TextChanged" /> <TextBox Name="SearchTextBox" Height="25" Padding="1,2,0,0" BorderThickness="2" Background="Transparent" TextChanged="SearchTextBox_TextChanged" Foreground="{Binding Path=Foreground, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=Window}}" CaretBrush="{Binding Path=Foreground, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=Window}}" />
<Button x:Name="SearchClearButton" Background="Transparent" HorizontalAlignment="Right" Margin="2,0,4,0" FontSize="5" Width="17" Height="17" Visibility="Hidden" Click="SearchClearButton_Click"></Button> <Button x:Name="SearchClearButton" Background="Transparent" HorizontalAlignment="Right" Margin="2,0,4,0" FontSize="10" Width="17" Height="17" Visibility="Hidden" Click="SearchClearButton_Click" FontFamily="Marlett" Foreground="{Binding Path=Foreground2, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=Window}}">r</Button>
</Grid> </Grid>
</UserControl> </UserControl>

View File

@@ -21,7 +21,7 @@ namespace Controls
private void SearchTextBox_TextChanged(object sender, TextChangedEventArgs e) private void SearchTextBox_TextChanged(object sender, TextChangedEventArgs e)
{ {
SearchTextBlock.Text = SearchTextBox.Text == "" ? "Find a setting" : ""; HintTextBlock.Text = SearchTextBox.Text == "" ? "Find a setting" : "";
if (SearchTextBox.Text == "") if (SearchTextBox.Text == "")
SearchClearButton.Visibility = Visibility.Hidden; SearchClearButton.Visibility = Visibility.Hidden;

38
mpvConfEdit/app.manifest Normal file
View File

@@ -0,0 +1,38 @@
<?xml version="1.0" encoding="utf-8"?>
<assembly manifestVersion="1.0" xmlns="urn:schemas-microsoft-com:asm.v1">
<assemblyIdentity version="1.0.0.0" name="MyApplication.app"/>
<trustInfo xmlns="urn:schemas-microsoft-com:asm.v2">
<security>
<requestedPrivileges xmlns="urn:schemas-microsoft-com:asm.v3">
<!--
<requestedExecutionLevel level="asInvoker" uiAccess="false" />
<requestedExecutionLevel level="requireAdministrator" uiAccess="false" />
<requestedExecutionLevel level="highestAvailable" uiAccess="false" />
-->
<requestedExecutionLevel level="asInvoker" uiAccess="false" />
</requestedPrivileges>
</security>
</trustInfo>
<compatibility xmlns="urn:schemas-microsoft-com:compatibility.v1">
<application>
<!-- Windows 7 -->
<supportedOS Id="{35138b9a-5d96-4fbd-8e2d-a2440225f93a}" />
<!-- Windows 8 -->
<supportedOS Id="{4a2f28e3-53b9-4441-ba9c-d69d4a4a6e38}" />
<!-- Windows 8.1 -->
<supportedOS Id="{1f676c76-80e1-4239-95bb-83d0f6d0da78}" />
<!-- Windows 10 -->
<supportedOS Id="{8e0f7a12-bfb3-4fe8-b9a5-48fd50a15a9a}" />
</application>
</compatibility>
<application xmlns="urn:schemas-microsoft-com:asm.v3">
<windowsSettings>
<dpiAware xmlns="http://schemas.microsoft.com/SMI/2005/WindowsSettings">true</dpiAware>
</windowsSettings>
</application>
</assembly>

View File

@@ -19,6 +19,28 @@ options = [{ name = "no", help = "always use software decoding (Defaul
{ name = "crystalhd", help = "copies video back to system RAM (Any platform supported by hardware)" }, { name = "crystalhd", help = "copies video back to system RAM (Any platform supported by hardware)" },
{ name = "rkmpp", help = "requires --vo=gpu (some RockChip devices only)" }] { name = "rkmpp", help = "requires --vo=gpu (some RockChip devices only)" }]
[[settings]]
name = "gpu-api"
default = "auto"
filter = "Video"
help = "--gpu-api=<type> Controls which type of graphics APIs will be accepted."
options = [{ name = "auto", help = "Use any available API (Default)" },
{ name = "opengl", help = "Allow only OpenGL (requires OpenGL 2.1+ or GLES 2.0+)" },
{ name = "vulkan", help = "Allow only Vulkan (requires a valid/working --spirv-compiler)" },
{ name = "d3d11", help = "Allow only --gpu-context=d3d11" }]
[[settings]]
name = "gpu-context"
default = "auto"
filter = "Video"
help = "--gpu-context=<sys> The value auto (the default) selects the GPU context. You can also pass help to get a complete list of compiled in backends (sorted by autoprobe order)."
options = [{ name = "auto", help = "auto-select (Default)" },
{ name = "win", help = "Win32/WGL" },
{ name = "winvk", help = "VK_KHR_win32_surface" },
{ name = "angle", help = "Direct3D11 through the OpenGL ES translation layer ANGLE. This supports almost everything the win backend does (if the ANGLE build is new enough)." },
{ name = "dxinterop", help = "(experimental) Win32, using WGL for rendering and Direct3D 9Ex for presentation. Works on Nvidia and AMD. Newer Intel chips with the latest drivers may also work." },
{ name = "d3d11", help = "Win32, with native Direct3D 11 rendering." }]
[[settings]] [[settings]]
name = "vo" name = "vo"
default = "gpu" default = "gpu"
@@ -28,18 +50,134 @@ help = "--gpu=<mode> Video output drivers to be used. Default = gpu.\n\nFor more
options = [{ name = "gpu", help = "General purpose, customizable, GPU-accelerated video output driver. It supports extended scaling methods, dithering, color management, custom shaders, HDR, and more. (Default)" }, options = [{ name = "gpu", help = "General purpose, customizable, GPU-accelerated video output driver. It supports extended scaling methods, dithering, color management, custom shaders, HDR, and more. (Default)" },
{ name = "direct3d", help = "Video output driver that uses the Direct3D interface" }] { name = "direct3d", help = "Video output driver that uses the Direct3D interface" }]
[[settings]]
name = "video-sync"
default = "audio"
filter = "Video"
help = "--video-sync=<audio|...> How the player synchronizes audio and video.\n\nFor more information visit:"
helpurl = "https://mpv.io/manual/master/#options-video-sync"
options = [{ name = "audio" },
{ name = "display-resample" },
{ name = "display-resample-vdrop" },
{ name = "display-resample-desync" },
{ name = "display-vdrop" },
{ name = "display-adrop" },
{ name = "display-desync" },
{ name = "desync" }]
[[settings]]
name = "scale"
default = "bilinear"
filter = "Video"
help = "--scale=<filter> The GPU renderer filter function to use when upscaling video. There are some more filters, but most are not as useful. For a complete list, pass help as value, e.g.: mpv --scale=help"
options = [{ name = "bilinear", help = "Bilinear hardware texture filtering (fastest, very low quality). This is the default for compatibility reasons." },
{ name = "spline36", help = "Mid quality and speed. This is the default when using gpu-hq." },
{ name = "lanczos", help = "Lanczos scaling. Provides mid quality and speed. Generally worse than spline36, but it results in a slightly sharper image which is good for some content types. The number of taps can be controlled with scale-radius, but is best left unchanged. (This filter is an alias for sinc-windowed sinc)" },
{ name = "ewa_lanczos", help = "Elliptic weighted average Lanczos scaling. Also known as Jinc. Relatively slow, but very good quality. The radius can be controlled with scale-radius. Increasing the radius makes the filter sharper but adds more ringing. (This filter is an alias for jinc-windowed jinc)" },
{ name = "ewa_lanczossharp", help = "A slightly sharpened version of ewa_lanczos, preconfigured to use an ideal radius and parameter. If your hardware can run it, this is probably what you should use by default." },
{ name = "mitchell", help = "Mitchell-Netravali. The B and C parameters can be set with --scale-param1 and --scale-param2. This filter is very good at downscaling (see --dscale)." },
{ name = "oversample", help = "A version of nearest neighbour that (naively) oversamples pixels, so that pixels overlapping edges get linearly interpolated instead of rounded. This essentially removes the small imperfections and judder artifacts caused by nearest-neighbour interpolation, in exchange for adding some blur. This filter is good at temporal interpolation, and also known as \"smoothmotion\" (see --tscale)." },
{ name = "linear", help = "A --tscale filter." }]
[[settings]]
name = "cscale"
default = "bilinear"
filter = "Video"
help = "--cscale=<filter> As --scale, but for interpolating chroma information. If the image is not subsampled, this option is ignored entirely."
options = [{ name = "bilinear", help = "Bilinear hardware texture filtering (fastest, very low quality). This is the default for compatibility reasons." },
{ name = "spline36", help = "Mid quality and speed. This is the default when using gpu-hq." },
{ name = "lanczos", help = "Lanczos scaling. Provides mid quality and speed. Generally worse than spline36, but it results in a slightly sharper image which is good for some content types. The number of taps can be controlled with scale-radius, but is best left unchanged. (This filter is an alias for sinc-windowed sinc)" },
{ name = "ewa_lanczos", help = "Elliptic weighted average Lanczos scaling. Also known as Jinc. Relatively slow, but very good quality. The radius can be controlled with scale-radius. Increasing the radius makes the filter sharper but adds more ringing. (This filter is an alias for jinc-windowed jinc)" },
{ name = "ewa_lanczossharp", help = "A slightly sharpened version of ewa_lanczos, preconfigured to use an ideal radius and parameter. If your hardware can run it, this is probably what you should use by default." },
{ name = "mitchell", help = "Mitchell-Netravali. The B and C parameters can be set with --scale-param1 and --scale-param2. This filter is very good at downscaling (see --dscale)." },
{ name = "oversample", help = "A version of nearest neighbour that (naively) oversamples pixels, so that pixels overlapping edges get linearly interpolated instead of rounded. This essentially removes the small imperfections and judder artifacts caused by nearest-neighbour interpolation, in exchange for adding some blur. This filter is good at temporal interpolation, and also known as \"smoothmotion\" (see --tscale)." },
{ name = "linear", help = "A --tscale filter." }]
[[settings]]
name = "dscale"
default = "bilinear"
filter = "Video"
help = "--dscale=<filter> Like --scale, but apply these filters on downscaling instead. If this option is unset, the filter implied by --scale will be applied."
options = [{ name = "bilinear", help = "Bilinear hardware texture filtering (fastest, very low quality). This is the default for compatibility reasons." },
{ name = "spline36", help = "Mid quality and speed. This is the default when using gpu-hq." },
{ name = "lanczos", help = "Lanczos scaling. Provides mid quality and speed. Generally worse than spline36, but it results in a slightly sharper image which is good for some content types. The number of taps can be controlled with scale-radius, but is best left unchanged. (This filter is an alias for sinc-windowed sinc)" },
{ name = "ewa_lanczos", help = "Elliptic weighted average Lanczos scaling. Also known as Jinc. Relatively slow, but very good quality. The radius can be controlled with scale-radius. Increasing the radius makes the filter sharper but adds more ringing. (This filter is an alias for jinc-windowed jinc)" },
{ name = "ewa_lanczossharp", help = "A slightly sharpened version of ewa_lanczos, preconfigured to use an ideal radius and parameter. If your hardware can run it, this is probably what you should use by default." },
{ name = "mitchell", help = "Mitchell-Netravali. The B and C parameters can be set with --scale-param1 and --scale-param2. This filter is very good at downscaling (see --dscale)." },
{ name = "oversample", help = "A version of nearest neighbour that (naively) oversamples pixels, so that pixels overlapping edges get linearly interpolated instead of rounded. This essentially removes the small imperfections and judder artifacts caused by nearest-neighbour interpolation, in exchange for adding some blur. This filter is good at temporal interpolation, and also known as \"smoothmotion\" (see --tscale)." },
{ name = "linear", help = "A --tscale filter." }]
[[settings]]
name = "dither-depth"
default = "no"
filter = "Video"
help = "--dither-depth=<N|no|auto> Set dither target depth to N. Default: no. Note that the depth of the connected video display device cannot be detected. Often, LCD panels will do dithering on their own, which conflicts with this option and leads to ugly output."
options = [{ name = "no", help = "Disable any dithering done by mpv." },
{ name = "auto", help = "Automatic selection. If output bit depth cannot be detected, 8 bits per component are assumed." },
{ name = "8", help = "Dither to 8 bit output." }]
[[settings]]
name = "correct-downscaling"
default = "no"
filter = "Video"
help = "--correct-downscaling When using convolution based filters, extend the filter size when downscaling. Increases quality, but reduces performance while downscaling.\n\nThis will perform slightly sub-optimally for anamorphic video (but still better than without it) since it will extend the size to match only the milder of the scale factors between the axes."
options = [{ name = "yes" },
{ name = "no" }]
[[settings]]
name = "sigmoid-upscaling"
default = "no"
filter = "Video"
help = "--sigmoid-upscaling When upscaling, use a sigmoidal color transform to avoid emphasizing ringing artifacts. This also implies --linear-scaling."
options = [{ name = "yes" },
{ name = "no" }]
[[settings]]
name = "deband"
default = "no"
filter = "Video"
help = "--deband Enable the debanding algorithm. This greatly reduces the amount of visible banding, blocking and other quantization artifacts, at the expense of very slightly blurring some of the finest details. In practice, it's virtually always an improvement - the only reason to disable it would be for performance."
options = [{ name = "yes" },
{ name = "no" }]
[[settings]] [[settings]]
name = "volume" name = "volume"
default = "100" default = "100"
filter = "Audio" filter = "Audio"
help = "--volume=<integer> Set the startup volume. 0 means silence, 100 means no volume reduction or amplification. Negative values can be passed for compatibility, but are treated as 0. Since mpv 0.18.1, this always controls the internal mixer (aka \"softvol\"). Default: 100" help = "--volume=<integer> Set the startup volume. 0 means silence, 100 means no volume reduction or amplification. Negative values can be passed for compatibility, but are treated as 0. Since mpv 0.18.1, this always controls the internal mixer (aka \"softvol\"). Default: 100"
[[settings]]
name = "alang"
default = ""
filter = "Audio"
help = "--alang=<languagecode[,languagecode,...]> Specify a priority list of audio languages to use. Different container formats employ different language codes. DVDs use ISO 639-1 two-letter language codes, Matroska, MPEG-TS and NUT use ISO 639-2 three-letter language codes, while OGM uses a free-form identifier. See also --aid.\n\nExamples\n\nmpv dvd://1 --alang=hu,en chooses the Hungarian language track on a DVD and falls back on English if Hungarian is not available.\n\nmpv --alang=jpn example.mkv plays a Matroska file with Japanese audio."
[[settings]]
name = "audio-file-auto"
default = "no"
filter = "Audio"
help = "--audio-file-auto=<no|exact|fuzzy|all>, --no-audio-file-auto Load additional audio files matching the video filename. The parameter specifies how external audio files are matched."
options = [{ name = "no", help = "Don't automatically load external audio files (default)." },
{ name = "exact", help = "Load the media filename with audio file extension." },
{ name = "fuzzy", help = "Load all audio files containing media filename." },
{ name = "all", help = "Load all audio files in the current and --audio-file-paths directories." }]
[[settings]] [[settings]]
name = "slang" name = "slang"
default = "" default = ""
filter = "Subtitle" filter = "Subtitle"
help = "--slang=<languagecode[,languagecode,...]> Specify a priority list of subtitle languages to use. Different container formats employ different language codes. DVDs use ISO 639-1 two letter language codes, Matroska uses ISO 639-2 three letter language codes while OGM uses a free-form identifier. See also --sid." help = "--slang=<languagecode[,languagecode,...]> Specify a priority list of subtitle languages to use. Different container formats employ different language codes. DVDs use ISO 639-1 two letter language codes, Matroska uses ISO 639-2 three letter language codes while OGM uses a free-form identifier. See also --sid."
[[settings]]
name = "sub-auto"
default = "exact"
filter = "Subtitle"
help = "--sub-auto=<no|exact|fuzzy|all>, --no-sub-auto Load additional subtitle files matching the video filename. The parameter specifies how external subtitle files are matched. exact is enabled by default."
options = [{ name = "no", help = "Don't automatically load external subtitle files." },
{ name = "exact", help = "Load the media filename with subtitle file extension (Default)." },
{ name = "fuzzy", help = "Load all subs containing media filename." },
{ name = "all", help = "Load all subs in the current and --sub-file-paths directories." }]
[[settings]] [[settings]]
name = "screen" name = "screen"
default = "" default = ""
@@ -51,18 +189,31 @@ name = "osd-playing-msg"
default = "" default = ""
width = 300 width = 300
filter = "Screen" filter = "Screen"
help = "--osd-playing-msg=<value> Show a message on OSD when playback starts. The string is expanded for properties, e.g. --osd-playing-msg='file: ${filename}' will show the message file: followed by a space and the currently played filename.\n\nFor more information visit:" help = "--osd-playing-msg=<value> Show a message on OSD when playback starts. The string is expanded for properties, e.g. --osd-playing-msg='file: ${filename}' will show the message file: followed by a space and the currently played filename. For more information visit:"
helpurl = "https://mpv.io/manual/master/#property-expansion" helpurl = "https://mpv.io/manual/master/#property-expansion"
[[settings]] [[settings]]
name = "fullscreen" name = "fullscreen"
alias = "fs"
default = "no" default = "no"
filter = "Screen" filter = "Screen"
help = "--fullscreen=<yes|no>, fs=<yes|no> Start the player in fullscreen mode. Default: no." help = "--fullscreen=<yes|no>, fs=<yes|no> Start the player in fullscreen mode. Default: no."
options = [{ name = "yes" }, options = [{ name = "yes" },
{ name = "no" }] { name = "no" }]
[[settings]]
name = "screenshot-directory"
default = ""
width = 500
folder = true
filter = "Screen"
help = "--screenshot-directory=<value> Store screenshots in this directory. This path is joined with the filename generated by --screenshot-template. If the template filename is already absolute, the directory is ignored.\n\nIf the directory does not exist, it is created on the first screenshot. If it is not a directory, an error is generated when trying to write a screenshot.\n\nThis option is not set by default, and thus will write screenshots to the directory from which mpv was started. In pseudo-gui mode (see PSEUDO GUI MODE), this is set to the desktop."
[[settings]]
name = "autofit"
default = "50%"
filter = "Screen"
help = "--autofit=<percent value> Set the initial window size in percent. Please note that this setting is only partly implemented in mpv.net, accepted are only integer values with percent sign added. Default: 50%."
[[settings]] [[settings]]
name = "keep-open-pause" name = "keep-open-pause"
default = "yes" default = "yes"
@@ -82,7 +233,6 @@ options = [{ name = "yes", help = "Don't terminate if the current file is the
[[settings]] [[settings]]
name = "loop-file" name = "loop-file"
alias = "loop"
default = "" default = ""
filter = "Playback" filter = "Playback"
help = "--loop-file=<N|inf|no>, loop=<N|inf|no> Loop a single file N times. inf means forever, no means normal playback. For compatibility, --loop-file and --loop-file=yes are also accepted, and are the same as --loop-file=inf.\n\nThe difference to --loop-playlist is that this doesn't loop the playlist, just the file itself. If the playlist contains only a single file, the difference between the two option is that this option performs a seek on loop, instead of reloading the file.\n\n--loop is an alias for this option." help = "--loop-file=<N|inf|no>, loop=<N|inf|no> Loop a single file N times. inf means forever, no means normal playback. For compatibility, --loop-file and --loop-file=yes are also accepted, and are the same as --loop-file=inf.\n\nThe difference to --loop-playlist is that this doesn't loop the playlist, just the file itself. If the playlist contains only a single file, the difference between the two option is that this option performs a seek on loop, instead of reloading the file.\n\n--loop is an alias for this option."
@@ -95,14 +245,6 @@ help = "--save-position-on-quit=<yes|no> Always save the current playback positi
options = [{ name = "yes" }, options = [{ name = "yes" },
{ name = "no" }] { name = "no" }]
[[settings]]
name = "screenshot-directory"
default = ""
width = 500
folder = true
filter = "Screen"
help = "--screenshot-directory=<value> Store screenshots in this directory. This path is joined with the filename generated by --screenshot-template. If the template filename is already absolute, the directory is ignored.\n\nIf the directory does not exist, it is created on the first screenshot. If it is not a directory, an error is generated when trying to write a screenshot.\n\nThis option is not set by default, and thus will write screenshots to the directory from which mpv was started. In pseudo-gui mode (see PSEUDO GUI MODE), this is set to the desktop."
[[settings]] [[settings]]
name = "input-ar-delay" name = "input-ar-delay"
default = "" default = ""
@@ -115,12 +257,6 @@ default = ""
filter = "Input" filter = "Input"
help = "--input-ar-rate=<integer> Number of key presses to generate per second on autorepeat." help = "--input-ar-rate=<integer> Number of key presses to generate per second on autorepeat."
[[settings]]
name = "alang"
default = ""
filter = "Audio"
help = "--alang=<languagecode[,languagecode,...]> Specify a priority list of audio languages to use. Different container formats employ different language codes. DVDs use ISO 639-1 two-letter language codes, Matroska, MPEG-TS and NUT use ISO 639-2 three-letter language codes, while OGM uses a free-form identifier. See also --aid.\n\nExamples\n\nmpv dvd://1 --alang=hu,en chooses the Hungarian language track on a DVD and falls back on English if Hungarian is not available.\n\nmpv --alang=jpn example.mkv plays a Matroska file with Japanese audio."
[[settings]] [[settings]]
name = "hr-seek" name = "hr-seek"
default = "absolute" default = "absolute"
@@ -144,38 +280,3 @@ name = "loop-playlist"
default = "" default = ""
filter = "Playback" filter = "Playback"
help = "--loop-playlist=<N|inf|force|no>, --loop-playlist Loops playback N times. A value of 1 plays it one time (default), 2 two times, etc. inf means forever. no is the same as 1 and disables looping. If several files are specified on command line, the entire playlist is looped. --loop-playlist is the same as --loop-playlist=inf.\n\nThe force mode is like inf, but does not skip playlist entries which have been marked as failing. This means the player might waste CPU time trying to loop a file that doesn't exist. But it might be useful for playing webradios under very bad network conditions." help = "--loop-playlist=<N|inf|force|no>, --loop-playlist Loops playback N times. A value of 1 plays it one time (default), 2 two times, etc. inf means forever. no is the same as 1 and disables looping. If several files are specified on command line, the entire playlist is looped. --loop-playlist is the same as --loop-playlist=inf.\n\nThe force mode is like inf, but does not skip playlist entries which have been marked as failing. This means the player might waste CPU time trying to loop a file that doesn't exist. But it might be useful for playing webradios under very bad network conditions."
[[settings]]
name = "video-sync"
default = "audio"
filter = "Video"
help = "--video-sync=<audio|...> How the player synchronizes audio and video.\n\nFor more information visit:"
helpurl = "https://mpv.io/manual/master/#options-video-sync"
options = [{ name = "audio" },
{ name = "display-resample" },
{ name = "display-resample-vdrop" },
{ name = "display-resample-desync" },
{ name = "display-vdrop" },
{ name = "display-adrop" },
{ name = "display-desync" },
{ name = "desync" }]
[[settings]]
name = "audio-file-auto"
default = "no"
filter = "Audio"
help = "--audio-file-auto=<no|exact|fuzzy|all>, --no-audio-file-auto Load additional audio files matching the video filename. The parameter specifies how external audio files are matched."
options = [{ name = "no", help = "Don't automatically load external audio files (default)." },
{ name = "exact", help = "Load the media filename with audio file extension." },
{ name = "fuzzy", help = "Load all audio files containing media filename." },
{ name = "all", help = "Load all audio files in the current and --audio-file-paths directories." }]
[[settings]]
name = "sub-auto"
default = "exact"
filter = "Subtitle"
help = "--sub-auto=<no|exact|fuzzy|all>, --no-sub-auto Load additional subtitle files matching the video filename. The parameter specifies how external subtitle files are matched. exact is enabled by default."
options = [{ name = "no", help = "Don't automatically load external subtitle files." },
{ name = "exact", help = "Load the media filename with subtitle file extension (Default)." },
{ name = "fuzzy", help = "Load all subs containing media filename." },
{ name = "all", help = "Load all subs in the current and --sub-file-paths directories." }]

View File

@@ -44,9 +44,13 @@
<PropertyGroup> <PropertyGroup>
<ApplicationIcon>mpv.ico</ApplicationIcon> <ApplicationIcon>mpv.ico</ApplicationIcon>
</PropertyGroup> </PropertyGroup>
<PropertyGroup>
<ApplicationManifest>app.manifest</ApplicationManifest>
</PropertyGroup>
<ItemGroup> <ItemGroup>
<Reference Include="System" /> <Reference Include="System" />
<Reference Include="System.Data" /> <Reference Include="System.Data" />
<Reference Include="System.Drawing" />
<Reference Include="System.Windows.Forms" /> <Reference Include="System.Windows.Forms" />
<Reference Include="System.Xml" /> <Reference Include="System.Xml" />
<Reference Include="Microsoft.CSharp" /> <Reference Include="Microsoft.CSharp" />
@@ -66,6 +70,7 @@
<Generator>MSBuild:Compile</Generator> <Generator>MSBuild:Compile</Generator>
<SubType>Designer</SubType> <SubType>Designer</SubType>
</ApplicationDefinition> </ApplicationDefinition>
<Compile Include="Controls.cs" />
<Compile Include="DynamicGUI\DynamicGUI.cs" /> <Compile Include="DynamicGUI\DynamicGUI.cs" />
<Compile Include="DynamicGUI\OptionSettingControl.xaml.cs"> <Compile Include="DynamicGUI\OptionSettingControl.xaml.cs">
<DependentUpon>OptionSettingControl.xaml</DependentUpon> <DependentUpon>OptionSettingControl.xaml</DependentUpon>
@@ -120,6 +125,10 @@
<Generator>ResXFileCodeGenerator</Generator> <Generator>ResXFileCodeGenerator</Generator>
<LastGenOutput>Resources.Designer.cs</LastGenOutput> <LastGenOutput>Resources.Designer.cs</LastGenOutput>
</EmbeddedResource> </EmbeddedResource>
<None Include="app.manifest" />
<None Include="mpvNetConf.toml">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None>
<None Include="Properties\Settings.settings"> <None Include="Properties\Settings.settings">
<Generator>SettingsSingleFileGenerator</Generator> <Generator>SettingsSingleFileGenerator</Generator>
<LastGenOutput>Settings.Designer.cs</LastGenOutput> <LastGenOutput>Settings.Designer.cs</LastGenOutput>
@@ -129,7 +138,7 @@
<None Include="App.config" /> <None Include="App.config" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<None Include="mpvConfEdit.toml"> <None Include="mpvConf.toml">
<CopyToOutputDirectory>Always</CopyToOutputDirectory> <CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None> </None>
</ItemGroup> </ItemGroup>

View File

@@ -0,0 +1,8 @@
[[settings]]
name = "dark-mode"
default = "system"
filter = "mpv.net"
help = "Enables a dark theme."
options = [{ name = "always" },
{ name = "system" , help = "Windows 10+" },
{ name = "never" }]

View File

@@ -1,6 +1,41 @@
<?xml version="1.0" encoding="utf-8" ?> <?xml version="1.0" encoding="utf-8" ?>
<configuration> <configuration>
<configSections>
<sectionGroup name="userSettings" type="System.Configuration.UserSettingsGroup, System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" >
<section name="mpvInputEdit.Properties.Settings" type="System.Configuration.ClientSettingsSection, System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" allowExeDefinition="MachineToLocalUser" requirePermission="false" />
</sectionGroup>
</configSections>
<startup> <startup>
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.7.2" /> <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.7.2" />
</startup> </startup>
<userSettings>
<mpvInputEdit.Properties.Settings>
<setting name="input_conf_help" serializeAs="String">
<value> # This file defines the input (keys and mouse) bindings of mpv and mpv.net
# and it also defines the context menu of mpv.net. mpv.net has an input
# editor and an conf editor as alternatives to editing conf text files.
# The input and conf editors can be found in mpv.net's context menu at:
# Settings &gt; Show Config Editor
# Settings &gt; Show Input Editor
# The defaults of this file can be found at:
# https://github.com/stax76/mpv.net/blob/master/mpv.net/Resources/input.conf.txt
# the defaults of mpv can be found at:
# https://github.com/mpv-player/mpv/blob/master/etc/input.conf
# mpv.net's defaults of mpv.conf contain: 'input-default-bindings = no'
# which disables mpv's input defaults. Every line in this file begins with a
# space character to make it easier to do a text search, so if you want to know
# if 'o' has already a binding you can make a text search on ' o '.
# mpv input commands: https://github.com/stax76/mpv.net/wiki/mpv-input-commands
# mpv input keys: https://github.com/stax76/mpv.net/wiki/mpv-input-keys</value>
</setting>
</mpvInputEdit.Properties.Settings>
</userSettings>
</configuration> </configuration>

View File

@@ -1,7 +1,7 @@
<Application x:Class="mpvInputEdit.App" <Application x:Class="mpvInputEdit.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:mpvInputEdit" xmlns:Controls="clr-namespace:Controls"
StartupUri="MainWindow.xaml"> StartupUri="MainWindow.xaml">
<Application.Resources> <Application.Resources>
<Style TargetType="TextBox"> <Style TargetType="TextBox">
@@ -19,7 +19,7 @@
<Setter Property="BorderBrush" TargetName="border" Value="#FF7EB4EA"/> <Setter Property="BorderBrush" TargetName="border" Value="#FF7EB4EA"/>
</Trigger> </Trigger>
<Trigger Property="IsFocused" Value="true"> <Trigger Property="IsFocused" Value="true">
<Setter Property="BorderBrush" TargetName="border" Value="{x:Static SystemParameters.WindowGlassBrush}"/> <Setter Property="BorderBrush" TargetName="border" Value="{x:Static Controls:Controls.ThemeBrush}"/>
</Trigger> </Trigger>
</ControlTemplate.Triggers> </ControlTemplate.Triggers>
</ControlTemplate> </ControlTemplate>

View File

@@ -27,8 +27,8 @@ namespace mpvInputEdit
if (l.StartsWith("#")) continue; if (l.StartsWith("#")) continue;
if (!l.Contains(" ")) continue; if (!l.Contains(" ")) continue;
InputItem item = new InputItem(); InputItem item = new InputItem();
item.Key = l.Substring(0, l.IndexOf(" ")); item.Input = l.Substring(0, l.IndexOf(" "));
if (item.Key == "") continue; if (item.Input == "") continue;
l = l.Substring(l.IndexOf(" ") + 1); l = l.Substring(l.IndexOf(" ") + 1);
if (l.Contains("#menu:")) if (l.Contains("#menu:"))

18
mpvInputEdit/Controls.cs Normal file
View File

@@ -0,0 +1,18 @@
using System;
using System.Windows;
using System.Windows.Media;
namespace Controls
{
class Controls
{
public static Brush ThemeBrush {
get {
if (Environment.OSVersion.Version.Major < 10)
return new SolidColorBrush(Colors.DarkSlateGray);
else
return SystemParameters.WindowGlassBrush;
}
}
}
}

View File

@@ -277,18 +277,18 @@ namespace mpvInputEdit
{ {
HwndSource source = HwndSource.FromHwnd(new WindowInteropHelper(this).Handle); HwndSource source = HwndSource.FromHwnd(new WindowInteropHelper(this).Handle);
source.AddHook(new HwndSourceHook(WndProc)); source.AddHook(new HwndSourceHook(WndProc));
SetKey(InputItem.Key); SetKey(InputItem.Input);
} }
private void ConfirmButton_Click(object sender, RoutedEventArgs e) private void ConfirmButton_Click(object sender, RoutedEventArgs e)
{ {
InputItem.Key = NewKey; InputItem.Input = NewKey;
Close(); Close();
} }
private void ClearButton_Click(object sender, RoutedEventArgs e) private void ClearButton_Click(object sender, RoutedEventArgs e)
{ {
InputItem.Key = "_"; InputItem.Input = "_";
Close(); Close();
} }

View File

@@ -8,18 +8,18 @@
Loaded="Window_Loaded" Closed="Window_Closed"> Loaded="Window_Loaded" Closed="Window_Closed">
<Grid> <Grid>
<Grid.RowDefinitions> <Grid.RowDefinitions>
<RowDefinition Height="60" /> <RowDefinition Height="Auto" />
<RowDefinition Height="*" /> <RowDefinition Height="*" />
</Grid.RowDefinitions> </Grid.RowDefinitions>
<Controls:SearchTextBoxUserControl x:Name="SearchControl" Width="300" Margin="0,0,0,10" Grid.ColumnSpan="2" /> <Controls:SearchTextBoxUserControl x:Name="SearchControl" Width="300" Margin="0,20,0,20" Grid.ColumnSpan="2" />
<DataGrid Grid.Row="1" x:Name="DataGrid" AutoGenerateColumns="False" CellStyle="{StaticResource DataGrid_Font_Centering}"> <DataGrid Grid.Row="1" x:Name="DataGrid" CommandManager.PreviewCanExecute="DataGrid_PreviewCanExecute" AutoGenerateColumns="False" CellStyle="{StaticResource DataGrid_Font_Centering}">
<DataGrid.Columns> <DataGrid.Columns>
<DataGridTextColumn Header="Context Menu" Binding="{Binding Menu}"/> <DataGridTextColumn Header="Menu" Binding="{Binding Menu}"/>
<DataGridTemplateColumn Header="Input"> <DataGridTemplateColumn Header="Input">
<DataGridTemplateColumn.CellTemplate> <DataGridTemplateColumn.CellTemplate>
<DataTemplate> <DataTemplate>
<Button MinHeight="20" Click="ButtonClick"> <Button MinHeight="20" Click="ButtonClick">
<TextBlock Text="{Binding Key}"></TextBlock> <TextBlock Text="{Binding Input}"></TextBlock>
</Button> </Button>
</DataTemplate> </DataTemplate>
</DataGridTemplateColumn.CellTemplate> </DataGridTemplateColumn.CellTemplate>

View File

@@ -1,6 +1,6 @@
using System; using System;
using System.Collections.Generic;
using System.ComponentModel; using System.ComponentModel;
using System.Diagnostics;
using System.IO; using System.IO;
using System.Reflection; using System.Reflection;
using System.Windows; using System.Windows;
@@ -34,14 +34,25 @@ namespace mpvInputEdit
bool Filter(InputItem item) bool Filter(InputItem item)
{ {
string searchText = SearchControl.SearchTextBox.Text.ToLowerInvariant(); string searchText = SearchControl.SearchTextBox.Text.ToLower();
if (searchText == "") return true;
if (searchText == "") if (searchText.StartsWith("i ") || searchText.StartsWith("i:"))
return true; {
searchText = searchText.Substring(2).Trim();
if (item.Command.ToLower().Contains(searchText) || if (searchText.Length < 3)
return item.Input.ToLower().Replace("ctrl+", "").Replace("shift+", "").Replace("alt+", "").Contains(searchText);
else
return item.Input.ToLower().Contains(searchText);
}
else if (searchText.StartsWith("m ") || searchText.StartsWith("m:"))
return item.Menu.ToLower().Contains(searchText.Substring(2).Trim());
else if (searchText.StartsWith("c ") || searchText.StartsWith("c:"))
return item.Command.ToLower().Contains(searchText.Substring(2).Trim());
else if (item.Command.ToLower().Contains(searchText) ||
item.Menu.ToLower().Contains(searchText) || item.Menu.ToLower().Contains(searchText) ||
item.Key.ToLower().Contains(searchText)) item.Input.ToLower().Contains(searchText))
{ {
return true; return true;
} }
@@ -56,44 +67,33 @@ namespace mpvInputEdit
w.Owner = this; w.Owner = this;
w.InputItem = item; w.InputItem = item;
w.ShowDialog(); w.ShowDialog();
var items = new Dictionary<string, InputItem>();
foreach (InputItem i in App.InputItems)
if (items.ContainsKey(i.Input) && i.Input != "_")
MessageBox.Show($"Duplicate found:\n\n{i.Input}: {i.Menu}\n\n{items[i.Input].Input}: {items[i.Input].Menu}\n\nPlease note that you can chain multiple commands in the same line by using a semicolon as separator.", "Duplicate Found", MessageBoxButton.OK, MessageBoxImage.Warning);
else
items[i.Input] = i;
} }
private void Window_Loaded(object sender, RoutedEventArgs e) private void Window_Loaded(object sender, RoutedEventArgs e) => Keyboard.Focus(SearchControl.SearchTextBox);
{
Keyboard.Focus(SearchControl.SearchTextBox);
}
private void Grid_PreviewCanExecute(object sender, CanExecuteRoutedEventArgs e)
{
DataGrid grid = (DataGrid)sender;
if (e.Command == DataGrid.DeleteCommand)
{
if (MessageBox.Show($"Would you like to delete the selected item?\n\n{(grid.SelectedItem as InputItem).Menu}",
"Confirm Delete", MessageBoxButton.OKCancel) != MessageBoxResult.OK)
{
e.Handled = true;
}
}
}
private void Window_Closed(object sender, EventArgs e) private void Window_Closed(object sender, EventArgs e)
{ {
if (MessageBox.Show("Would you like to save changes?", "Confirm Save", MessageBoxButton.OKCancel) != MessageBoxResult.OK)
return;
var backupDir = Path.GetDirectoryName(App.InputConfPath) + "\\backup\\"; var backupDir = Path.GetDirectoryName(App.InputConfPath) + "\\backup\\";
if (!Directory.Exists(backupDir)) if (!Directory.Exists(backupDir))
Directory.CreateDirectory(backupDir); Directory.CreateDirectory(backupDir);
File.Copy(App.InputConfPath, backupDir + "input conf " + DateTime.Now.ToString("yyyy-MM-dd HH-mm") + ".conf"); if (File.Exists(App.InputConfPath))
File.Copy(App.InputConfPath, backupDir + "input conf " + DateTime.Now.ToString("yyyy-MM-dd HH-mm") + ".conf", true);
string text = ""; string text = "\r\n" + Properties.Settings.Default.input_conf_help + "\r\n\r\n";
foreach (InputItem item in App.InputItems) foreach (InputItem item in App.InputItems)
{ {
string line = " " + item.Key.PadRight(14); string line = " " + item.Input.PadRight(10);
if (item.Command.Trim() == "") if (item.Command.Trim() == "")
line += " ignore"; line += " ignore";
@@ -108,11 +108,17 @@ namespace mpvInputEdit
File.WriteAllText(App.InputConfPath, text); File.WriteAllText(App.InputConfPath, text);
foreach (Process process in Process.GetProcesses()) MessageBox.Show("Changes will be available on next mpv(.net) startup.",
if (process.ProcessName == "mpvnet") Title, MessageBoxButton.OK, MessageBoxImage.Information);
MessageBox.Show("Restart mpv.net in order to apply changed input bindings.", Title, MessageBoxButton.OK, MessageBoxImage.Information); }
else if (process.ProcessName == "mpv")
MessageBox.Show("Restart mpv in order to apply changed input bindings.", Title, MessageBoxButton.OK, MessageBoxImage.Information); private void DataGrid_PreviewCanExecute(object sender, CanExecuteRoutedEventArgs e)
{
DataGrid grid = (DataGrid)sender;
if (e.Command == DataGrid.DeleteCommand)
if (MessageBox.Show($"Confirm to delete: {(grid.SelectedItem as InputItem).Input} ({(grid.SelectedItem as InputItem).Menu})", "Confirm Delete", MessageBoxButton.OKCancel, MessageBoxImage.Question) != MessageBoxResult.OK)
e.Handled = true;
} }
} }
} }

View File

@@ -8,11 +8,11 @@ using System.Windows;
// set of attributes. Change these attribute values to modify the information // set of attributes. Change these attribute values to modify the information
// associated with an assembly. // associated with an assembly.
[assembly: AssemblyTitle("mpv(.net) input edit")] [assembly: AssemblyTitle("mpv(.net) input edit")]
[assembly: AssemblyDescription("mpv(.net) key bindings editor")] [assembly: AssemblyDescription("mpv(.net) key and mouse bindings editor")]
[assembly: AssemblyConfiguration("")] [assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")] [assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("mpv(.net) input edit")] [assembly: AssemblyProduct("mpv(.net) input edit")]
[assembly: AssemblyCopyright("Copyright © stax76")] [assembly: AssemblyCopyright("Copyright © 2017 stax76")]
[assembly: AssemblyTrademark("")] [assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")] [assembly: AssemblyCulture("")]
@@ -51,5 +51,5 @@ using System.Windows;
// You can specify all the values or you can default the Build and Revision Numbers // You can specify all the values or you can default the Build and Revision Numbers
// by using the '*' as shown below: // by using the '*' as shown below:
// [assembly: AssemblyVersion("1.0.*")] // [assembly: AssemblyVersion("1.0.*")]
[assembly: AssemblyVersion("1.1.0.0")] [assembly: AssemblyVersion("1.3.0.0")]
[assembly: AssemblyFileVersion("1.1.0.0")] [assembly: AssemblyFileVersion("1.3.0.0")]

View File

@@ -8,14 +8,12 @@
// </auto-generated> // </auto-generated>
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
namespace mpvInputEdit.Properties namespace mpvInputEdit.Properties {
{
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "11.0.0.0")] [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "16.0.0.0")]
internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase {
{
private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings()))); private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings())));
@@ -24,5 +22,40 @@ namespace mpvInputEdit.Properties
return defaultInstance; return defaultInstance;
} }
} }
[global::System.Configuration.UserScopedSettingAttribute()]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Configuration.DefaultSettingValueAttribute(@" # This file defines the input (keys and mouse) bindings of mpv and mpv.net
# and it also defines the context menu of mpv.net. mpv.net has an input
# editor and an conf editor as alternatives to editing conf text files.
# The input and conf editors can be found in mpv.net's context menu at:
# Settings > Show Config Editor
# Settings > Show Input Editor
# The defaults of this file can be found at:
# https://github.com/stax76/mpv.net/blob/master/mpv.net/Resources/input.conf.txt
# the defaults of mpv can be found at:
# https://github.com/mpv-player/mpv/blob/master/etc/input.conf
# mpv.net's defaults of mpv.conf contain: 'input-default-bindings = no'
# which disables mpv's input defaults. Every line in this file begins with a
# space character to make it easier to do a text search, so if you want to know
# if 'o' has already a binding you can make a text search on ' o '.
# mpv input commands: https://github.com/stax76/mpv.net/wiki/mpv-input-commands
# mpv input keys: https://github.com/stax76/mpv.net/wiki/mpv-input-keys")]
public string input_conf_help {
get {
return ((string)(this["input_conf_help"]));
}
set {
this["input_conf_help"] = value;
}
}
} }
} }

View File

@@ -1,7 +1,32 @@
<?xml version='1.0' encoding='utf-8'?> <?xml version='1.0' encoding='utf-8'?>
<SettingsFile xmlns="uri:settings" CurrentProfile="(Default)"> <SettingsFile xmlns="http://schemas.microsoft.com/VisualStudio/2004/01/settings" CurrentProfile="(Default)" GeneratedClassNamespace="mpvInputEdit.Properties" GeneratedClassName="Settings">
<Profiles> <Profiles />
<Profile Name="(Default)" /> <Settings>
</Profiles> <Setting Name="input_conf_help" Type="System.String" Scope="User">
<Settings /> <Value Profile="(Default)"> # This file defines the input (keys and mouse) bindings of mpv and mpv.net
# and it also defines the context menu of mpv.net. mpv.net has an input
# editor and an conf editor as alternatives to editing conf text files.
# The input and conf editors can be found in mpv.net's context menu at:
# Settings &gt; Show Config Editor
# Settings &gt; Show Input Editor
# The defaults of this file can be found at:
# https://github.com/stax76/mpv.net/blob/master/mpv.net/Resources/input.conf.txt
# the defaults of mpv can be found at:
# https://github.com/mpv-player/mpv/blob/master/etc/input.conf
# mpv.net's defaults of mpv.conf contain: 'input-default-bindings = no'
# which disables mpv's input defaults. Every line in this file begins with a
# space character to make it easier to do a text search, so if you want to know
# if 'o' has already a binding you can make a text search on ' o '.
# mpv input commands: https://github.com/stax76/mpv.net/wiki/mpv-input-commands
# mpv input keys: https://github.com/stax76/mpv.net/wiki/mpv-input-keys</Value>
</Setting>
</Settings>
</SettingsFile> </SettingsFile>

View File

@@ -6,7 +6,7 @@
mc:Ignorable="d" mc:Ignorable="d"
d:DesignHeight="450" d:DesignWidth="800"> d:DesignHeight="450" d:DesignWidth="800">
<Grid x:Name="SearchTextBoxUserControl1" Background="White"> <Grid x:Name="SearchTextBoxUserControl1" Background="White">
<TextBlock x:Name="SearchTextBlock" Margin="5,2" Text="Search" Foreground="LightSteelBlue" VerticalAlignment="Center" /> <TextBlock x:Name="SearchHintTextBlock" Margin="5,2" Text="Type ? to get help." Foreground="LightSteelBlue" VerticalAlignment="Center" />
<TextBox Name="SearchTextBox" Height="25" Padding="1,2,0,0" BorderThickness="2" Background="Transparent" TextChanged="SearchTextBox_TextChanged" /> <TextBox Name="SearchTextBox" Height="25" Padding="1,2,0,0" BorderThickness="2" Background="Transparent" TextChanged="SearchTextBox_TextChanged" />
<Button x:Name="SearchClearButton" Background="Transparent" HorizontalAlignment="Right" Margin="2,0,4,0" FontSize="5" Width="17" Height="17" Visibility="Hidden" Click="SearchClearButton_Click"></Button> <Button x:Name="SearchClearButton" Background="Transparent" HorizontalAlignment="Right" Margin="2,0,4,0" FontSize="5" Width="17" Height="17" Visibility="Hidden" Click="SearchClearButton_Click"></Button>
</Grid> </Grid>

View File

@@ -21,12 +21,15 @@ namespace Controls
private void SearchTextBox_TextChanged(object sender, TextChangedEventArgs e) private void SearchTextBox_TextChanged(object sender, TextChangedEventArgs e)
{ {
SearchTextBlock.Text = SearchTextBox.Text == "" ? "Search" : ""; SearchHintTextBlock.Text = SearchTextBox.Text == "" ? "Type ? to get help." : "";
if (SearchTextBox.Text == "") if (SearchTextBox.Text == "")
SearchClearButton.Visibility = Visibility.Hidden; SearchClearButton.Visibility = Visibility.Hidden;
else else
SearchClearButton.Visibility = Visibility.Visible; SearchClearButton.Visibility = Visibility.Visible;
if (SearchTextBox.Text == "?")
MessageBox.Show("Filtering works by searching in the Input, Menu and Command but it's possible to reduce the filter scope to either of Input, Menu or Command by prefixing as follows:\n\ni <input search>\ni: <input search>\n\nm <menu search>\nm: <menu search>\n\nc <command search>\nc: <command search>", "Filtering", MessageBoxButton.OK, MessageBoxImage.Information);
} }
} }
} }

38
mpvInputEdit/app.manifest Normal file
View File

@@ -0,0 +1,38 @@
<?xml version="1.0" encoding="utf-8"?>
<assembly manifestVersion="1.0" xmlns="urn:schemas-microsoft-com:asm.v1">
<assemblyIdentity version="1.0.0.0" name="MyApplication.app"/>
<trustInfo xmlns="urn:schemas-microsoft-com:asm.v2">
<security>
<requestedPrivileges xmlns="urn:schemas-microsoft-com:asm.v3">
<!--
<requestedExecutionLevel level="asInvoker" uiAccess="false" />
<requestedExecutionLevel level="requireAdministrator" uiAccess="false" />
<requestedExecutionLevel level="highestAvailable" uiAccess="false" />
-->
<requestedExecutionLevel level="asInvoker" uiAccess="false" />
</requestedPrivileges>
</security>
</trustInfo>
<compatibility xmlns="urn:schemas-microsoft-com:compatibility.v1">
<application>
<!-- Windows 7 -->
<supportedOS Id="{35138b9a-5d96-4fbd-8e2d-a2440225f93a}" />
<!-- Windows 8 -->
<supportedOS Id="{4a2f28e3-53b9-4441-ba9c-d69d4a4a6e38}" />
<!-- Windows 8.1 -->
<supportedOS Id="{1f676c76-80e1-4239-95bb-83d0f6d0da78}" />
<!-- Windows 10 -->
<supportedOS Id="{8e0f7a12-bfb3-4fe8-b9a5-48fd50a15a9a}" />
</application>
</compatibility>
<application xmlns="urn:schemas-microsoft-com:asm.v3">
<windowsSettings>
<dpiAware xmlns="http://schemas.microsoft.com/SMI/2005/WindowsSettings">true</dpiAware>
</windowsSettings>
</application>
</assembly>

View File

@@ -21,14 +21,12 @@ namespace mpvInputEdit
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
} }
private string _Key = ""; private string _Input = "";
public string Key { public string Input {
get { get => _Input;
return _Key;
}
set { set {
_Key = value; _Input = value;
NotifyPropertyChanged(); NotifyPropertyChanged();
} }
} }

View File

@@ -38,6 +38,9 @@
<PropertyGroup> <PropertyGroup>
<ApplicationIcon>mpv.ico</ApplicationIcon> <ApplicationIcon>mpv.ico</ApplicationIcon>
</PropertyGroup> </PropertyGroup>
<PropertyGroup>
<ApplicationManifest>app.manifest</ApplicationManifest>
</PropertyGroup>
<ItemGroup> <ItemGroup>
<Reference Include="System" /> <Reference Include="System" />
<Reference Include="System.Data" /> <Reference Include="System.Data" />
@@ -60,6 +63,7 @@
<Generator>MSBuild:Compile</Generator> <Generator>MSBuild:Compile</Generator>
<SubType>Designer</SubType> <SubType>Designer</SubType>
</ApplicationDefinition> </ApplicationDefinition>
<Compile Include="Controls.cs" />
<Compile Include="SearchTextBoxUserControl.xaml.cs"> <Compile Include="SearchTextBoxUserControl.xaml.cs">
<DependentUpon>SearchTextBoxUserControl.xaml</DependentUpon> <DependentUpon>SearchTextBoxUserControl.xaml</DependentUpon>
</Compile> </Compile>
@@ -106,6 +110,7 @@
<Generator>ResXFileCodeGenerator</Generator> <Generator>ResXFileCodeGenerator</Generator>
<LastGenOutput>Resources.Designer.cs</LastGenOutput> <LastGenOutput>Resources.Designer.cs</LastGenOutput>
</EmbeddedResource> </EmbeddedResource>
<None Include="app.manifest" />
<None Include="Properties\Settings.settings"> <None Include="Properties\Settings.settings">
<Generator>SettingsSingleFileGenerator</Generator> <Generator>SettingsSingleFileGenerator</Generator>
<LastGenOutput>Settings.Designer.cs</LastGenOutput> <LastGenOutput>Settings.Designer.cs</LastGenOutput>

View File

@@ -10,7 +10,7 @@ AppVersion={#MyAppVersion}
AppPublisher=stax76 AppPublisher=stax76
ArchitecturesInstallIn64BitMode=x64 ArchitecturesInstallIn64BitMode=x64
Compression=lzma2 Compression=lzma2
DefaultDirName={commonpf}\{#MyAppName} DefaultDirName={pf}\{#MyAppName}
OutputBaseFilename=mpvnet-{#MyAppVersion} OutputBaseFilename=mpvnet-{#MyAppVersion}
OutputDir=C:\Users\frank\Desktop OutputDir=C:\Users\frank\Desktop
DefaultGroupName={#MyAppName} DefaultGroupName={#MyAppName}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 194 KiB

After

Width:  |  Height:  |  Size: 193 KiB