Compare commits

...

58 Commits
2.6 ... 3.2

Author SHA1 Message Date
Frank Skare
f35ab46c3f - 2019-04-27 02:16:13 +02:00
Frank Skare
143934ca49 - 2019-04-27 02:06:04 +02:00
Frank Skare
669750eaf4 - 2019-04-27 01:56:51 +02:00
Frank Skare
cde8a6495a - 2019-04-27 01:55:53 +02:00
Frank Skare
c774d4d490 - 2019-04-27 01:53:26 +02:00
Frank Skare
55cafbcdbf - 2019-04-27 01:45:34 +02:00
Frank Skare
4f508f3af0 - 2019-04-27 01:38:55 +02:00
Frank Skare
8cea79e67f - 2019-04-27 01:32:20 +02:00
Frank Skare
c6c3a3e8fa - 2019-04-27 01:30:18 +02:00
Frank Skare
8c87ac0c47 - 2019-04-27 01:23:58 +02:00
Frank Skare
d777ca912a - 2019-04-26 11:22:07 +02:00
Frank Skare
c9ffbaa679 - 2019-04-25 10:33:21 +02:00
Frank Skare
1476059601 - 2019-04-25 10:30:47 +02:00
Frank Skare
757502e8bf - 2019-04-25 10:13:48 +02:00
Frank Skare
4bbf84532e - 2019-04-25 08:30:31 +02:00
Frank Skare
433d741c68 - 2019-04-25 08:04:49 +02:00
Frank Skare
8fdbe22dd8 - 2019-04-25 05:27:01 +02:00
Frank Skare
8bed98ded5 - 2019-04-25 05:24:42 +02:00
Frank Skare
4abfa73fba - 2019-04-25 05:03:43 +02:00
Frank Skare
b868d63946 - 2019-04-25 04:55:09 +02:00
Frank Skare
3bdb88787e - 2019-04-25 04:51:12 +02:00
Frank Skare
8b74abc2f6 - 2019-04-25 04:46:30 +02:00
Frank Skare
a516f9f947 - 2019-04-25 04:44:43 +02:00
Frank Skare
ecab31f108 - 2019-04-25 04:36:57 +02:00
Frank Skare
c5a5a09300 - 2019-04-25 04:33:32 +02:00
Frank Skare
5a2f5614a3 - 2019-04-25 03:43:48 +02:00
Frank Skare
5e0162f2c8 - 2019-04-25 03:41:12 +02:00
Frank Skare
14ba006de1 - 2019-04-25 00:11:55 +02:00
Frank Skare
8f7aa7db2d - 2019-04-24 23:59:34 +02:00
Frank Skare
3e70e8e5ea - 2019-04-24 20:26:41 +02:00
Frank Skare
36f5357ff7 - 2019-04-24 20:15:27 +02:00
Frank Skare
dc3b275291 - 2019-04-24 20:09:54 +02:00
Frank Skare
abc49f55d5 - 2019-04-24 19:41:55 +02:00
Frank Skare
40b9f21101 - 2019-04-23 17:00:28 +02:00
Frank Skare
164076e237 - 2019-04-23 16:57:44 +02:00
Frank Skare
b7d948f12d - 2019-04-23 16:56:34 +02:00
Frank Skare
22e4ba1824 - 2019-04-23 16:55:56 +02:00
Frank Skare
efd2ddf367 - 2019-04-23 16:23:06 +02:00
Frank Skare
2415e2ed43 - 2019-04-21 00:18:42 +02:00
Frank Skare
d5d26784e8 - 2019-04-21 00:04:39 +02:00
Frank Skare
6c1bad15f2 - 2019-04-21 00:00:48 +02:00
Frank Skare
5137e43aad - 2019-04-20 23:59:31 +02:00
Frank Skare
6fc0ebf9d5 - 2019-04-20 23:49:05 +02:00
Frank Skare
a0e30ff982 - 2019-04-20 23:27:14 +02:00
Frank Skare
c2a0d95851 - 2019-04-20 23:07:04 +02:00
Frank Skare
34d5d2fff5 - 2019-04-20 20:56:54 +02:00
Frank Skare
baa669fe1e - 2019-04-20 20:51:05 +02:00
Frank Skare
67ecebbf6b - 2019-04-20 04:34:44 +02:00
Frank Skare
e9a8b1962a - 2019-04-16 19:04:52 +02:00
Frank Skare
3ded1573f4 - 2019-04-16 18:46:24 +02:00
Frank Skare
d38adcfc70 - 2019-04-16 18:42:03 +02:00
Frank Skare
5f1f5b3811 - 2019-04-16 18:31:39 +02:00
Frank Skare
c18c70c2af - 2019-04-16 18:14:22 +02:00
Frank Skare
9cdd76e1ac - 2019-04-13 03:07:57 +02:00
Frank Skare
7db8a1e534 - 2019-04-13 03:05:07 +02:00
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
102 changed files with 2688 additions and 3592 deletions

View File

@@ -11,7 +11,7 @@ Public Class CSScriptAddon
Implements IAddon
Sub New()
Dim scriptDir = mp.mpvConfFolderPath + "scripts"
Dim scriptDir = mp.MpvConfFolder + "scripts"
If Not Directory.Exists(scriptDir) Then Return
Dim csFiles = Directory.GetFiles(scriptDir, "*.cs").ToList
csFiles.AddRange(Directory.GetFiles(Application.StartupPath + "\\Scripts", "*.cs"))

View File

@@ -1,10 +1,21 @@
MIT License
Copyright (c) 2017 stax76
Copyright (c) 2017-2019 Frank Skare (stax76)
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and ssociated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and ssociated documentation files (the "Software"),
to deal in the Software without restriction, including without limitation
the rights to use, copy, modify, merge, publish, distribute, sublicense,
and/or sell copies of the Software, and to permit persons to whom the
Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
The above copyright notice and this permission notice shall be included
in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH
THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

248
README.md
View File

@@ -1,10 +1,30 @@
# mpv.net
mpv.net is a libmpv based media player for Windows, it looks and works like mpv and also shares the same settings as mpv and therefore the mpv documentation applies.
mpv.net is a modern media player for Windows that looks and works just like [mpv](https://mpv.io).
mpv and mpv.net have a learning curve.
#### Based on libmpv
mpv manual: <https://mpv.io/manual/master/>
mpv.net is based on libmpv which offers a straightforward C API that was designed from the ground up to make mpv usable as a library and facilitate easy integration into other applications.
#### CLI options
mpv.net has a basic CLI parser to support mpv's [CLI options](https://mpv.io/manual/master/#options).
#### High quality video output
libmpv has an OpenGL based video output that is capable of many features loved by videophiles, such as video scaling with popular high quality algorithms, color management, frame timing, interpolation, HDR, and more.
#### On Screen Controller
mpv.net uses mpv's OSC offering play controls with a modern flat design.
#### GPU video decoding
libmpv leverages the FFmpeg hwaccel APIs to support DXVA2 video decoding acceleration.
#### Active development
mpv.net is under active development, focusing on user feedback. Want a feature? Post a [patch](https://github.com/stax76/mpv.net/pulls) or [request it](https://github.com/stax76/mpv.net/issues)!
Table of contents
-----------------
@@ -14,41 +34,76 @@ Table of contents
- [Context Menu](#context-menu)
- [Settings](#settings)
- [Scripting](#scripting)
- [Add-ons](#add-ons)
- [Architecture](#architecture)
- [Support](#support)
- [Links](#links)
- [Download](#download)
- [Changelog](#changelog)
### Features
- Customizable context menu defined in the same file as the key bindings
- Searchable options dialog with modern UI as mpv compatible standalone application
- Searchable input (key/mouse) binding editor with modern UI as mpv compatible standalone application
- Rich addon API for .NET languages
- Rich scripting API for Python, C#, Lua, JavaScript and PowerShell
- mpv's OSC (on screen controller (play control bar)), IPC, conf files
- Customizable context menu defined in the same file as the key bindings ([Screenshot](#context-menu))
- Searchable config dialog ([Screenshot](#config-editor))
- Searchable input (key/mouse) binding editor ([Screenshot](#input-editor))
- Searchable command palette to quickly launch commands and look for keys ([Screenshot](#command-palette))
- Modern UI with dark mode ([Screenshot](#config-editor))
- Addon/extension API for .NET languages
- Scripting API for Python, C#, Lua, JavaScript and PowerShell ([wiki](https://github.com/stax76/mpv.net/wiki/Scripting))
- mpv's OSC, CLI, IPC and conf files
### Screenshots
![](https://raw.githubusercontent.com/stax76/mpv.net/master/screenshots/mpvnet.png)
#### Main Window
![](https://raw.githubusercontent.com/stax76/mpv.net/master/screenshots/mpvConfEdit.png)
![](https://raw.githubusercontent.com/stax76/mpv.net/master/screenshots/Main.png)
![](https://raw.githubusercontent.com/stax76/mpv.net/master/screenshots/mpvInputEdit.png)
#### Context Menu
Context menu defined in the input.conf file with dark mode support.
![](https://raw.githubusercontent.com/stax76/mpv.net/master/screenshots/Menu.png)
#### Config Editor
A searchable config editor as alternative to edit the mpv.conf file manually.
![](https://raw.githubusercontent.com/stax76/mpv.net/master/screenshots/ConfEditor.png)
#### Input Editor
A searchable key and mouse binding editor.
![](https://raw.githubusercontent.com/stax76/mpv.net/master/screenshots/InputEditor.png)
#### Command Palette
Forgot where a command in the menu is located or what shortcut key it has?
Just press Ctrl+Shift+P and find it easily in the searchable command palette.
![](https://raw.githubusercontent.com/stax76/mpv.net/master/screenshots/CommandPalette.png)
### Context Menu
The context menu can be customized via input.conf file located at:
```
C:\Users\username\AppData\Roaming\mpv\input.conf
C:\Users\%username%\AppData\Roaming\mpv\input.conf
```
if it's missing mpv.net generates it with the following defaults:
<https://github.com/stax76/mpv.net/blob/master/mpv.net/Resources/input.conf.txt>
<https://github.com/stax76/mpv.net/blob/master/mpv.net/Resources/inputConf.txt>
input.conf defines mpv's key and mouse bindings and mpv.net uses comments to define the context menu.
### Settings
mpv.net shares the settings with mpv, settings can be edited in a settings dialog or in a config file called mpv.conf located at:
```
C:\Users\user\AppData\Roaming\mpv\mpv.conf
C:\Users\%username%\AppData\Roaming\mpv\mpv.conf
```
or alternativly at:
```
<startup>\portable_config\mpv.conf
```
if it's missing mpv.net generates it with the following defaults:
@@ -56,52 +111,147 @@ if it's missing mpv.net generates it with the following defaults:
### Scripting
Scripting is supported for Python, C#, Lua, JavaScript and PowerShell
Scripting is supported via Python, C#, Lua, JavaScript and PowerShell
https://github.com/stax76/mpv.net/wiki/Scripting-(CSharp,-Python,-JavaScript,-Lua,-PowerShell)
[Scripting wiki page](https://github.com/stax76/mpv.net/wiki/Scripting)
### Add-ons
Add-ons have to be located at:
C:\Users\\<user\>\AppData\Roaming\mpv\Addons\ExampleAddon\ExampleAddon.dll
\<startup\>\Addons\ExampleAddon\ExampleAddon.dll
\<startup\>\portable_config\Addons\ExampleAddon\ExampleAddon.dll
The add-on filename must end with 'Addon.dll'.
Examples:
[RatingAddon.cs](https://github.com/stax76/mpv.net/blob/master/RatingAddon/RatingAddon.cs)
[CSScriptAddon.vb](https://github.com/stax76/mpv.net/blob/master/CSScriptAddon/CSScriptAddon.vb)
### Architecture
mpv.net is written in C# 7.0 and runs on the .NET framework 4.7 or higher.
The Add-on implementation is based on the Managed Extensibility Framework,
the entire application code is accessible for add-ons and Python scripts.
Python scripting is implemented with IronPython which uses Python 2.7.
The main/video window is WinForms based, other windows are WPF based.
The config editor adds it's controls dynamically and uses TOML to define it's
content, there are only two simple types, StringSetting and OptionSetting.
mpv.net was started 2017 and consists of about 9000 lines of code.
Third party components are:
- libmpv
- MediaInfo
- Tommy (TOML parser)
- IronPython
### Support
<https://forum.doom9.org/showthread.php?t=174841>
[Support thread in Doom9 forum](https://forum.doom9.org/showthread.php?t=174841)
<https://forum.videohelp.com/threads/392514-mpv-net-a-extendable-media-player-for-windows>
[Support thread in VideoHelp forum](https://forum.videohelp.com/threads/392514-mpv-net-a-extendable-media-player-for-windows)
<https://github.com/stax76/mpv.net/issues>
[Issue tracker to report bugs and request features](https://github.com/stax76/mpv.net/issues)
### Links
mpv manual: <https://mpv.io/manual/master/>
mpv wiki: <https://github.com/mpv-player/mpv/wiki>
mpv.net wiki: <https://github.com/stax76/mpv.net/wiki>
mpv apps: <https://github.com/mpv-player/mpv/wiki/Applications-using-mpv>
mpv user scripts: <https://github.com/mpv-player/mpv/wiki/User-Scripts>
mpv default key bindings: <https://github.com/mpv-player/mpv/blob/master/etc/input.conf>
mpv.net default key bindings: <https://github.com/stax76/mpv.net/blob/master/mpv.net/Resources/inputConf.txt>
mpv download: <https://mpv.io/installation/>
mpv.net download: <https://github.com/stax76/mpv.net/releases>
mpv bugs and requests: <https://mpv.io/bug-reports/>
mpv.net bugs and requests: <https://github.com/stax76/mpv.net/issues>
### Download
<https://github.com/stax76/mpv.net/releases>
### Changelog
### 2.6 (2019-04-09)
### 3.2 (2019-0?-??)
- 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
- mpvInputEdit and mpvConfEdit were discontinued and merged into
mpvnet because separate apps were to difficult to work with
- portable mode: in case no config folder exists and the
startup folder has write access mpvnet will ask where
the config folder should be created (portable or appdata)
- there was an issue causing keys not working after a modal window was shown
- there was a crash when no script folder existed in the conf folder
- MediaInfo and youtube-dl were updated
- a new JavaScript example script was added to the wiki and the
script descriptions were improved. [Scripting Page](https://github.com/stax76/mpv.net/wiki/Scripting).
- greatly improved README.md file and github startpage
- About dialog added
- the input editor shows only a closing message if actually a change was made
- the input editor don't show menu separators any longer
- new Command Palette feature added. [Screenshot](https://github.com/stax76/mpv.net#command-palette), [Default input binding](https://github.com/stax76/mpv.net/blob/master/mpv.net/Resources/inputConf.txt#L141)
- the history feature had a bug causing files to be logged more than once
### 2.5 (2019-04-08)
### 3.1 (2019-04-23)
- 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
- the Tracks and Chapters menu are now only added if default bindings exist and
it's now possible to move the chapters menu to the top level by editing input.conf
- mpvnet supports now like mpv a portable settings directory. If a directory named portable_config
next to the mpvnet.exe exists, all config will be loaded and written in this directory.
- there is now a portable download in 7zip format.
[go to download page](https://github.com/stax76/mpv.net/releases)
### 3.0 (2019-04-20)
### 2.4 (2019-04-06)
- the history feature logs now only files that were opened longer than 90 seconds
- the default input command for cycling the audio tracks was replaced with an
mpv.net command that shows detailed track info and has no 'no audio' track. [Default binding](https://github.com/stax76/mpv.net/blob/master/mpv.net/Resources/inputConf.txt#L89).
- new website at <https://mpv-net.github.io/mpv.net-web-site/>
- the Tracks menu supports now MKV edition selection. [Default binding](https://github.com/stax76/mpv.net/blob/master/mpv.net/Resources/inputConf.txt#L106).
- the Navigate menu supports now chapter selection. [Default binding](https://github.com/stax76/mpv.net/blob/master/mpv.net/Resources/inputConf.txt#L57).
- opening the context menu was crashing if the default binding for Tracks was missing
- 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)
### 2.9 (2019-04-16)
- clicking the right top corner in full screen mode
closes the player but it did not work on all displays
- the info display was changed to display the filename on top
so it's not displayed in the middle of the screen
- on start up of the config editor all text is now selected in the
search text box so it's ready for a new search to be typed
- the config editor was changed to write the settings to disk
only if the settings were actually modified, also the message
that says that the settings will be available on next start
is now only shown if the settings were actually modified.
- there was an instance in the context menu where the sub menu
arrow was overlapping with the text
- in the input editor when only one character is entered in the
search text box the search is performed only in the input and
not in the command or menu
- in the input editor the routine that generates the input string
was completely rewritten because it was adding Shift where it
wasn't necessary (it took a huge amount of time to implement)
- the context menu has a new track menu where the active track
can be seen and selected, it shows video, audio and subtitle
tracks with various metadata. [Menu default definition](https://github.com/stax76/mpv.net/blob/master/mpv.net/Resources/inputConf.txt#L104).
The screenshots were updated showing the [new track menu](https://github.com/stax76/mpv.net#screenshots).

View File

@@ -10,7 +10,7 @@ namespace RatingAddon
[Export(typeof(IAddon))]
public class RatingAddon : IAddon
{
private Dictionary<string, int> Dic = new Dictionary<string, int>();
Dictionary<string, int> Dic = new Dictionary<string, int>();
public RatingAddon()
{
@@ -18,7 +18,7 @@ namespace RatingAddon
mp.Shutdown += mpv_Shutdown;
}
private void mpv_Shutdown()
void mpv_Shutdown()
{
foreach (var i in Dic)
{
@@ -44,7 +44,7 @@ namespace RatingAddon
}
}
private void mpv_ClientMessage(string[] args)
void mpv_ClientMessage(string[] args)
{
int rating;

View File

@@ -1,13 +0,0 @@
'------------------------------------------------------------------------------
' <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

@@ -1,10 +0,0 @@
<?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

@@ -1,35 +0,0 @@
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")>

View File

@@ -1,62 +0,0 @@
'------------------------------------------------------------------------------
' <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

@@ -1,117 +0,0 @@
<?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>

View File

@@ -1,73 +0,0 @@
'------------------------------------------------------------------------------
' <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

@@ -1,7 +0,0 @@
<?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>

View File

@@ -1,678 +0,0 @@
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

View File

@@ -1,109 +0,0 @@
<?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

@@ -9,8 +9,6 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "RatingAddon", "RatingAddon\
EndProject
Project("{F184B08F-C81C-45F6-A57F-5ABD9991F28F}") = "CSScriptAddon", "CSScriptAddon\CSScriptAddon.vbproj", "{71808A87-8B1C-4DF8-957C-D79C3B164CCA}"
EndProject
Project("{F184B08F-C81C-45F6-A57F-5ABD9991F28F}") = "VBNET", "VBNET\VBNET.vbproj", "{A1D11294-05BF-4D77-B008-AECF1AA93C9F}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@@ -57,18 +55,6 @@ Global
{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.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
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE

View File

@@ -5,7 +5,7 @@ using System.ComponentModel.Composition.Hosting;
using System.IO;
using System.Windows.Forms;
using VBNET;
using Sys;
namespace mpvnet
{
@@ -14,7 +14,7 @@ namespace mpvnet
[ImportMany]
public IEnumerable<IAddon> Addons = null;
private readonly CompositionContainer CompositionContainer;
readonly CompositionContainer CompositionContainer;
public Addon()
{
@@ -28,7 +28,7 @@ namespace mpvnet
foreach (string i in Directory.GetDirectories(dir))
catalog.Catalogs.Add(new DirectoryCatalog(i, "*Addon.dll"));
dir = mp.mpvConfFolderPath + "\\Addons";
dir = mp.MpvConfFolder + "\\Addons";
if (Directory.Exists(dir))
foreach (string i in Directory.GetDirectories(dir))

View File

@@ -2,11 +2,12 @@
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.Windows.Interop;
using VBNET;
using Sys;
namespace mpvnet
{
@@ -15,7 +16,7 @@ namespace mpvnet
public string Name { get; set; }
public Action<string[]> Action { get; set; }
private static List<Command> commands;
static List<Command> commands;
public static List<Command> Commands
{
@@ -58,22 +59,48 @@ namespace mpvnet
public static void open_conf_folder(string[] args)
{
Process.Start(mp.mpvConfFolderPath);
Process.Start(mp.MpvConfFolder);
}
public static void show_input_editor(string[] args)
{
Process.Start(Application.StartupPath + "\\mpvInputEdit.exe");
MainForm.Instance.Invoke(new Action(() => {
InputWindow w = new InputWindow();
new WindowInteropHelper(w).Owner = MainForm.Instance.Handle;
w.ShowDialog();
}));
}
public static void show_conf_editor(string[] args)
{
Process.Start(Application.StartupPath + "\\mpvConfEdit.exe");
MainForm.Instance.Invoke(new Action(() => {
ConfWindow w = new ConfWindow();
new WindowInteropHelper(w).Owner = MainForm.Instance.Handle;
w.ShowDialog();
}));
}
public static void show_about(string[] args)
{
MainForm.Instance.Invoke(new Action(() => {
AboutWindow w = new AboutWindow();
new WindowInteropHelper(w).Owner = MainForm.Instance.Handle;
w.ShowDialog();
}));
}
public static void show_command_palette(string[] args)
{
MainForm.Instance.Invoke(new Action(() => {
var w = new CommandPaletteWindow();
new WindowInteropHelper(w).Owner = MainForm.Instance.Handle;
w.ShowDialog();
}));
}
public static void show_history(string[] args)
{
var fp = mp.mpvConfFolderPath + "history.txt";
var fp = mp.MpvConfFolder + "history.txt";
if (File.Exists(fp))
Process.Start(fp);
@@ -83,41 +110,15 @@ namespace mpvnet
File.WriteAllText(fp, "");
}
public static void shell_execute(string[] args)
{
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]);
Msg.Show("Changed settings are available on next startup.");
}
public static void shell_execute(string[] args) => Process.Start(args[0]);
public static void show_info(string[] args)
{
try
{
var fileInfo = new FileInfo(mp.get_property_string("path"));
FileInfo fileInfo = new FileInfo(mp.get_property_string("path"));
using (var mediaInfo = new MediaInfo(fileInfo.FullName))
using (MediaInfo mediaInfo = new MediaInfo(fileInfo.FullName))
{
string width = mediaInfo.GetInfo(MediaInfoStreamKind.Video, "Width");
@@ -133,11 +134,11 @@ namespace mpvnet
string text = "";
if (performer != "") text += "Artist: " + performer + "\n";
if (title != "") text += "Title: " + title + "\n";
if (album != "") text += "Album: " + album + "\n";
if (genre != "") text += "Genre: " + genre + "\n";
if (date != "") text += "Year: " + date + "\n";
if (duration != "") text += "Length: " + duration + "\n";
if (title != "") text += "Title: " + title + "\n";
if (album != "") text += "Album: " + album + "\n";
if (genre != "") text += "Genre: " + genre + "\n";
if (date != "") text += "Year: " + date + "\n";
if (duration != "") text += "Length: " + duration + "\n";
mp.commandv("show-text", text, "5000");
}
@@ -151,17 +152,19 @@ namespace mpvnet
if (bitrate == "")
bitrate = "0";
var bitrate2 = Convert.ToDouble(bitrate) / 1000.0 / 1000.0;
var videoCodec = mp.get_property_string("video-format").ToUpper();
var filename = fileInfo.Name;
double bitrate2 = Convert.ToDouble(bitrate) / 1000.0 / 1000.0;
string videoCodec = mp.get_property_string("video-format").ToUpper();
string filename = fileInfo.Name;
var text =
string text = filename + "\n" +
FormatTime(position.TotalMinutes) + ":" +
FormatTime(position.Seconds) + " / " +
FormatTime(duration.TotalMinutes) + ":" +
FormatTime(duration.Seconds) + "\n" +
Convert.ToInt32(fileInfo.Length / 1024 / 1024).ToString() +
$" MB - {width} x {height}\n{videoCodec} - {bitrate2.ToString("f1")} Mb/s" + "\n" + filename;
$"{width} x {height}\n" +
$"{bitrate2.ToString("f1")} Mb/s\n" +
Convert.ToInt32(fileInfo.Length / 1024 / 1024).ToString() + " MB\n" +
$"{videoCodec}\n";
mp.commandv("show-text", text, "5000");
}
@@ -194,7 +197,7 @@ namespace mpvnet
public static void load_sub(string[] args)
{
MainForm.Instance.BeginInvoke(new Action(() => {
MainForm.Instance.Invoke(new Action(() => {
using (var d = new OpenFileDialog())
{
d.InitialDirectory = Path.GetDirectoryName(mp.get_property_string("path", false));
@@ -209,7 +212,7 @@ namespace mpvnet
public static void load_audio(string[] args)
{
MainForm.Instance.BeginInvoke(new Action(() => {
MainForm.Instance.Invoke(new Action(() => {
using (var d = new OpenFileDialog())
{
d.InitialDirectory = Path.GetDirectoryName(mp.get_property_string("path", false));
@@ -221,5 +224,22 @@ namespace mpvnet
}
}));
}
public static void cycle_audio(string[] args)
{
string filePath = mp.get_property_string("path", false);
if (!File.Exists(filePath)) return;
using (MediaInfo mi = new MediaInfo(filePath))
{
MediaTrack[] audTracks = mp.MediaTracks.Where(track => track.Type == "a").ToArray();
if (audTracks.Length < 2) return;
int aid = mp.get_property_int("aid");
aid += 1;
if (aid > audTracks.Length) aid = 1;
mp.commandv("set", "aid", aid.ToString());
mp.commandv("show-text", audTracks[aid - 1].Text.Substring(3), "5000");
}
}
}
}

View File

@@ -0,0 +1,13 @@
<UserControl x:Class="Controls.SearchTextBoxUserControl"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
mc:Ignorable="d"
d:DesignHeight="450" d:DesignWidth="800">
<Grid x:Name="SearchTextBoxUserControl1" Background="{Binding Path=Background, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=Window}}">
<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" 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="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>
</UserControl>

View File

@@ -13,6 +13,16 @@ namespace Controls
public string Text { get => SearchTextBox.Text; set => SearchTextBox.Text = value; }
private string _HintText;
public string HintText {
get => _HintText;
set {
_HintText = value;
UpdateControls();
}
}
private void SearchClearButton_Click(object sender, RoutedEventArgs e)
{
SearchTextBox.Text = "";
@@ -21,7 +31,12 @@ namespace Controls
private void SearchTextBox_TextChanged(object sender, TextChangedEventArgs e)
{
SearchTextBlock.Text = SearchTextBox.Text == "" ? "Find a setting" : "";
UpdateControls();
}
void UpdateControls()
{
HintTextBlock.Text = SearchTextBox.Text == "" ? HintText : "";
if (SearchTextBox.Text == "")
SearchClearButton.Visibility = Visibility.Hidden;

View File

@@ -4,16 +4,17 @@ using System.Diagnostics;
using System.IO;
using System.Windows.Documents;
using System.Windows.Navigation;
using Tommy;
namespace DynamicGUI
{
public class Settings
{
public static List<SettingBase> LoadSettings(string filepath)
public static List<SettingBase> LoadSettings(string content)
{
TomlTable table;
using (StreamReader reader = new StreamReader(File.OpenRead(filepath)))
using (StringReader reader = new StringReader(content))
table = TOML.Parse(reader);
List<SettingBase> settingsList = new List<SettingBase>();
@@ -27,6 +28,7 @@ namespace DynamicGUI
baseSetting = optionSetting;
optionSetting.Default = setting["default"];
optionSetting.Value = optionSetting.Default;
optionSetting.StartValue = optionSetting.Default;
foreach (TomlTable option in setting["options"])
{
@@ -54,7 +56,6 @@ namespace DynamicGUI
baseSetting.Filter = setting["filter"];
if (setting.HasKey("help")) baseSetting.Help = setting["help"];
if (setting.HasKey("helpurl")) baseSetting.HelpURL = setting["helpurl"];
if (setting.HasKey("alias")) baseSetting.Alias = setting["alias"];
if (setting.HasKey("width")) baseSetting.Width = setting["width"];
settingsList.Add(baseSetting);
}
@@ -65,8 +66,10 @@ namespace DynamicGUI
public abstract class SettingBase
{
public string Name { get; set; }
public string Alias { get; set; }
public string Value { get; set; }
public string StartValue { get; set; }
public string Help { get; set; }
public string Default { get; set; }
public string HelpURL { get; set; }
public string Filter { get; set; }
public int Width { get; set; }
@@ -74,15 +77,11 @@ namespace DynamicGUI
public class StringSetting : SettingBase
{
public string Default { get; set; }
public string Value { get; set; }
public bool IsFolder { get; set; }
}
public class OptionSetting : SettingBase
{
public string Default { get; set; }
public string Value { get; set; }
public List<OptionSettingOption> Options = new List<OptionSettingOption>();
}

View File

@@ -8,18 +8,18 @@
d:DesignHeight="450" d:DesignWidth="800">
<Grid Margin="20,0">
<StackPanel>
<TextBox x:Name="TitleTextBox" FontSize="24" Margin="0,10" BorderThickness="0" IsReadOnly="True"></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.ItemTemplate>
<DataTemplate>
<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>
<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>
<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" Foreground="{Binding Path=Foreground2, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=Window}}" Background="{Binding Path=Background, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=Window}}"></TextBox>
</WrapPanel>
</DataTemplate>
</ItemsControl.ItemTemplate>
</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">
<local:HyperlinkEx x:Name="Link"></local:HyperlinkEx>
</TextBlock>

View File

@@ -9,16 +9,16 @@
d:DesignWidth="800" >
<Grid Margin="20,0">
<StackPanel>
<TextBox x:Name="TitleTextBox" FontSize="24" Margin="0,10" BorderThickness="0" IsReadOnly="True"></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.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="Auto" />
</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>
</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">
<local:HyperlinkEx x:Name="Link"></local:HyperlinkEx>
</TextBlock>

View File

@@ -1,10 +0,0 @@
MIT License
Copyright (c) 2017 stax76
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and ssociated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

View File

@@ -6,24 +6,33 @@ using System.Threading;
using System.Windows.Forms;
using System.Linq;
using System.Collections.Generic;
using System.ComponentModel;
using System.Globalization;
using System.Diagnostics;
using VBNET;
using Sys;
namespace mpvnet
{
public partial class MainForm : Form
{
public static MainForm Instance { get; set; }
public static IntPtr Hwnd;
public static IntPtr Hwnd { get; set; }
private Point LastCursorPosChanged;
private int LastCursorChangedTickCount;
private bool IgnoreDpiChanged = true;
private float mpvAutofit = 0.42f;
private bool mpvFullscreen;
private int mpvScreen = -1;
public new ContextMenuStripEx ContextMenu { get; set; }
public ContextMenuStripEx CMS;
Point LastCursorPosChanged;
int LastCursorChangedTickCount;
bool IgnoreDpiChanged = true;
public string MpvNetDarkMode { get; set; } = "always";
public bool MpvFullscreen { get; set; }
public float MpvAutofit { get; set; } = 0.50f;
public int MpvScreen { get; set; } = -1;
public string MpvSid { get; set; } = "";
public string MpvAid { get; set; } = "";
public string MpvVid { get; set; } = "";
public int MpvEdition { get; set; }
public MainForm()
{
@@ -34,8 +43,9 @@ namespace mpvnet
AppDomain.CurrentDomain.UnhandledException += CurrentDomain_UnhandledException;
Application.ThreadException += Application_ThreadException;
Msg.SupportURL = "https://github.com/stax76/mpv.net#support";
Instance = this;
WPF.WPF.Init();
System.Windows.Application.Current.ShutdownMode = System.Windows.ShutdownMode.OnExplicitShutdown;
Hwnd = Handle;
MinimumSize = new Size(FontHeight * 16, FontHeight * 9);
Text += " " + Application.ProductVersion;
@@ -43,12 +53,15 @@ namespace mpvnet
foreach (var i in mp.mpvConf)
ProcessMpvProperty(i.Key, i.Value);
foreach (var i in mp.mpvNetConf)
ProcessMpvNetProperty(i.Key, i.Value);
ProcessCommandLineEarly();
if (mpvScreen == -1) mpvScreen = Array.IndexOf(Screen.AllScreens, Screen.PrimaryScreen);
SetScreen(mpvScreen);
if (MpvScreen == -1) MpvScreen = Array.IndexOf(Screen.AllScreens, Screen.PrimaryScreen);
SetScreen(MpvScreen);
ChangeFullscreen(mpvFullscreen);
ChangeFullscreen(MpvFullscreen);
}
catch (Exception ex)
{
@@ -56,6 +69,111 @@ namespace mpvnet
}
}
void ContextMenu_Opening(object sender, CancelEventArgs e)
{
lock (mp.MediaTracks)
{
MenuItem trackMenuItem = FindMenuItem("Track");
if (trackMenuItem != null)
{
trackMenuItem.DropDownItems.Clear();
MediaTrack[] audTracks = mp.MediaTracks.Where(track => track.Type == "a").ToArray();
MediaTrack[] subTracks = mp.MediaTracks.Where(track => track.Type == "s").ToArray();
MediaTrack[] vidTracks = mp.MediaTracks.Where(track => track.Type == "v").ToArray();
MediaTrack[] ediTracks = mp.MediaTracks.Where(track => track.Type == "e").ToArray();
foreach (MediaTrack track in vidTracks)
{
MenuItem mi = new MenuItem(track.Text);
mi.Action = () => { mp.commandv("set", "vid", track.ID.ToString()); };
mi.Checked = MpvVid == track.ID.ToString();
trackMenuItem.DropDownItems.Add(mi);
}
if (vidTracks.Length > 0)
trackMenuItem.DropDownItems.Add(new ToolStripSeparator());
foreach (MediaTrack track in audTracks)
{
MenuItem mi = new MenuItem(track.Text);
mi.Action = () => { mp.commandv("set", "aid", track.ID.ToString()); };
mi.Checked = MpvAid == track.ID.ToString();
trackMenuItem.DropDownItems.Add(mi);
}
if (subTracks.Length > 0)
trackMenuItem.DropDownItems.Add(new ToolStripSeparator());
foreach (MediaTrack track in subTracks)
{
MenuItem mi = new MenuItem(track.Text);
mi.Action = () => { mp.commandv("set", "sid", track.ID.ToString()); };
mi.Checked = MpvSid == track.ID.ToString();
trackMenuItem.DropDownItems.Add(mi);
}
if (subTracks.Length > 0)
{
MenuItem mi = new MenuItem("S: No subtitles");
mi.Action = () => { mp.commandv("set", "sid", "no"); };
mi.Checked = MpvSid == "no";
trackMenuItem.DropDownItems.Add(mi);
}
if (ediTracks.Length > 0)
trackMenuItem.DropDownItems.Add(new ToolStripSeparator());
foreach (MediaTrack track in ediTracks)
{
MenuItem mi = new MenuItem(track.Text);
mi.Action = () => { mp.commandv("set", "edition", track.ID.ToString()); };
mi.Checked = MpvEdition == track.ID;
trackMenuItem.DropDownItems.Add(mi);
}
}
}
lock (mp.Chapters)
{
MenuItem chaptersMenuItem = FindMenuItem("Chapters");
if (chaptersMenuItem != null)
{
chaptersMenuItem.DropDownItems.Clear();
foreach (var i in mp.Chapters)
{
MenuItem mi = new MenuItem(i.Key);
mi.ShortcutKeyDisplayString = TimeSpan.FromSeconds(i.Value).ToString().Substring(0, 8) + " ";
mi.Action = () => { mp.commandv("seek", i.Value.ToString(CultureInfo.InvariantCulture), "absolute"); };
chaptersMenuItem.DropDownItems.Add(mi);
}
}
}
}
public MenuItem FindMenuItem(string text) => FindMenuItem(text, ContextMenu.Items);
MenuItem FindMenuItem(string text, ToolStripItemCollection items)
{
foreach (var item in items)
{
if (item is MenuItem mi)
{
if (mi.Text.StartsWith(text) && mi.Text.Trim() == text)
return mi;
if (mi.DropDownItems.Count > 0)
{
MenuItem val = FindMenuItem(text, mi.DropDownItems);
if (val != null) return val;
}
}
}
return null;
}
protected void SetScreen(int targetIndex)
{
Screen[] screens = Screen.AllScreens;
@@ -76,7 +194,7 @@ namespace mpvnet
{
if (IsFullscreen || mp.VideoSize.Width == 0) return;
Screen screen = Screen.FromControl(this);
int height = Convert.ToInt32(screen.Bounds.Height * mpvAutofit);
int height = Convert.ToInt32(screen.Bounds.Height * MpvAutofit);
int width = Convert.ToInt32(height * mp.VideoSize.Width / (double)mp.VideoSize.Height);
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));
@@ -91,7 +209,7 @@ namespace mpvnet
if (IsFullscreen || mp.VideoSize.Width == 0) return;
Screen screen = Screen.FromControl(this);
int height = ClientSize.Height;
if (height > screen.Bounds.Height * 0.9) height = Convert.ToInt32(screen.Bounds.Height * mpvAutofit);
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);
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));
@@ -118,6 +236,7 @@ namespace mpvnet
string left = i.Substring(2, i.IndexOf("=") - 2);
string right = i.Substring(left.Length + 3);
ProcessMpvProperty(left, right);
ProcessMpvNetProperty(left, right);
}
else
{
@@ -127,7 +246,7 @@ namespace mpvnet
{
case "fs":
case "fullscreen":
mpvFullscreen = true;
MpvFullscreen = true;
break;
}
}
@@ -142,14 +261,24 @@ namespace mpvnet
case "autofit":
if (value.Length == 3 && value.EndsWith("%"))
if (int.TryParse(value.Substring(0, 2), out int result))
mpvAutofit = result / 100f;
MpvAutofit = result / 100f;
break;
case "fs":
case "fullscreen":
mpvFullscreen = value == "yes";
MpvFullscreen = value == "yes";
break;
case "screen":
mpvScreen = Convert.ToInt32(value);
MpvScreen = Convert.ToInt32(value);
break;
}
}
void ProcessMpvNetProperty(string name, string value)
{
switch (name)
{
case "dark-mode":
MpvNetDarkMode = value;
break;
}
}
@@ -164,7 +293,7 @@ namespace mpvnet
lines = content.Split("\r\n".ToCharArray()).ToList();
else
{
lines = Properties.Resources.input_conf.Split("\r\n".ToCharArray()).ToList();
lines = Properties.Resources.inputConf.Split("\r\n".ToCharArray()).ToList();
foreach (string i in content.Split("\r\n".ToCharArray()))
{
@@ -176,13 +305,13 @@ namespace mpvnet
}
}
foreach (string i in lines)
foreach (string line in lines)
{
if (!i.Contains("#menu:")) continue;
string left = i.Substring(0, i.IndexOf("#menu:")).Trim();
if (!line.Contains("#menu:")) continue;
string left = line.Substring(0, line.IndexOf("#menu:")).Trim();
if (left.StartsWith("#")) continue;
string command = left.Substring(left.IndexOf(" ") + 1).Trim();
string menu = i.Substring(i.IndexOf("#menu:") + "#menu:".Length).Trim();
string menu = line.Substring(line.IndexOf("#menu:") + "#menu:".Length).Trim();
string input = left.Substring(0, left.IndexOf(" "));
if (input == "_") input = "";
if (menu.Contains(";")) input = menu.Substring(0, menu.IndexOf(";")).Trim();
@@ -195,7 +324,7 @@ namespace mpvnet
else
input = "";
var menuItem = CMS.Add(path, () => {
MenuItem menuItem = ContextMenu.Add(path, () => {
try {
mp.command_string(command);
}
@@ -205,51 +334,34 @@ namespace mpvnet
});
if (menuItem != null)
menuItem.ShortcutKeyDisplayString = input.Replace("_","") + " ";
menuItem.ShortcutKeyDisplayString = input + " ";
}
}
private void CMS_Opened(object sender, EventArgs e) => CursorHelp.Show();
void ContextMenu_Opened(object sender, EventArgs e) => CursorHelp.Show();
private string LastHistory;
void mp_PlaybackRestart() => BeginInvoke(new Action(() => { Text = Path.GetFileName(mp.get_property_string("path")) + " - mpv.net " + Application.ProductVersion; }));
private void mp_PlaybackRestart()
{
var filename = mp.get_property_string("filename");
BeginInvoke(new Action(() => { Text = filename + " - mpv.net " + Application.ProductVersion; }));
var historyFilepath = mp.mpvConfFolderPath + "history.txt";
void Mp_Idle() => BeginInvoke(new Action(() => { Text = "mpv.net " + Application.ProductVersion; }));
if (LastHistory != filename && File.Exists(historyFilepath))
{
File.AppendAllText(historyFilepath, DateTime.Now.ToString() + " " +
Path.GetFileNameWithoutExtension(filename) + "\r\n");
LastHistory = filename;
}
}
void CM_Popup(object sender, EventArgs e) => CursorHelp.Show();
private void Mp_Idle()
{
BeginInvoke(new Action(() => { Text = "mpv.net " + Application.ProductVersion; }));
}
private void CM_Popup(object sender, EventArgs e) => CursorHelp.Show();
private void Application_ThreadException(object sender, ThreadExceptionEventArgs e)
void Application_ThreadException(object sender, ThreadExceptionEventArgs e)
{
Msg.ShowException(e.Exception);
}
private void CurrentDomain_UnhandledException(object sender, UnhandledExceptionEventArgs e)
void CurrentDomain_UnhandledException(object sender, UnhandledExceptionEventArgs e)
{
Msg.ShowError(e.ExceptionObject.ToString());
}
private void mp_VideoSizeChanged()
void mp_VideoSizeChanged()
{
BeginInvoke(new Action(() => SetFormPositionAndSizeKeepHeight()));
}
private void mp_Shutdown()
void mp_Shutdown()
{
BeginInvoke(new Action(() => Close()));
}
@@ -281,12 +393,16 @@ namespace mpvnet
protected override void WndProc(ref Message m)
{
//Debug.WriteLine(m);
switch (m.Msg)
{
case 0x0201: // WM_LBUTTONDOWN
case 0x0202: // WM_LBUTTONUP
case 0x0100: // WM_KEYDOWN
case 0x0101: // WM_KEYUP
case 0x0104: // WM_SYSKEYDOWN
case 0x0105: // WM_SYSKEYUP
case 0x020A: // WM_MOUSEWHEEL
if (mp.MpvWindowHandle != IntPtr.Zero)
Native.SendMessage(mp.MpvWindowHandle, m.Msg, m.WParam, m.LParam);
@@ -295,14 +411,6 @@ namespace mpvnet
if (mp.MpvWindowHandle != IntPtr.Zero)
Native.PostMessage(mp.MpvWindowHandle, m.Msg, m.WParam, m.LParam);
break;
case 0x0104: // WM_SYSKEYDOWN:
if (mp.MpvWindowHandle != IntPtr.Zero)
Native.SendMessage(mp.MpvWindowHandle, m.Msg, m.WParam, m.LParam);
break;
case 0x0105: // WM_SYSKEYUP:
if (mp.MpvWindowHandle != IntPtr.Zero)
Native.SendMessage(mp.MpvWindowHandle, m.Msg, m.WParam, m.LParam);
break;
case 0x203: // Native.WM.LBUTTONDBLCLK
if (!IsMouseInOSC())
mp.command_string("cycle fullscreen");
@@ -363,11 +471,7 @@ namespace mpvnet
Native.PostMessage(Handle, 0xA1 /* WM_NCLBUTTONDOWN */, HTCAPTION, IntPtr.Zero);
}
var sb = Screen.FromControl(this).Bounds;
var p1 = new Point(sb.Width, 0);
var p2 = PointToScreen(e.Location);
if (Math.Abs(p1.X - p2.X) < 10 && Math.Abs(p1.Y - p2.Y) < 10)
if (Width - e.Location.X < 10 && e.Location.Y < 10)
mp.commandv("quit");
}
@@ -380,12 +484,9 @@ namespace mpvnet
CursorHelp.Show();
}
bool IsMouseInOSC()
{
return PointToClient(Control.MousePosition).Y > ClientSize.Height * 0.9;
}
bool IsMouseInOSC() => PointToClient(Control.MousePosition).Y > ClientSize.Height * 0.9;
private void Timer_Tick(object sender, EventArgs e)
void Timer_Tick(object sender, EventArgs e)
{
if (CursorHelp.IsPosDifferent(LastCursorPosChanged))
{
@@ -394,7 +495,7 @@ namespace mpvnet
}
else if (Environment.TickCount - LastCursorChangedTickCount > 1500 &&
!IsMouseInOSC() && ClientRectangle.Contains(PointToClient(MousePosition)) &&
Form.ActiveForm == this && !CMS.Visible)
Form.ActiveForm == this && !ContextMenu.Visible)
{
CursorHelp.Hide();
}
@@ -414,6 +515,10 @@ namespace mpvnet
mp.Init();
mp.observe_property_bool("fullscreen", mpPropChangeFullscreen);
mp.observe_property_bool("ontop", mpPropChangeOnTop);
mp.observe_property_string("sid", mpPropChangeSid);
mp.observe_property_string("aid", mpPropChangeAid);
mp.observe_property_string("vid", mpPropChangeVid);
mp.observe_property_int("edition", mpPropChangeEdition);
mp.Shutdown += mp_Shutdown;
mp.VideoSizeChanged += mp_VideoSizeChanged;
mp.PlaybackRestart += mp_PlaybackRestart;
@@ -422,13 +527,24 @@ namespace mpvnet
void mpPropChangeOnTop(bool value) => BeginInvoke(new Action(() => TopMost = value));
void mpPropChangeAid(string value) => MpvAid = value;
void mpPropChangeSid(string value) => MpvSid = value;
void mpPropChangeVid(string value) => MpvVid = value;
void mpPropChangeEdition(int value) => MpvEdition = value;
protected override void OnShown(EventArgs e)
{
base.OnShown(e);
CMS = new ContextMenuStripEx(components);
CMS.Opened += CMS_Opened;
ContextMenuStrip = CMS;
if ((MpvNetDarkMode == "system" && Sys.IsDarkTheme) || MpvNetDarkMode == "always")
ToolStripRendererEx.ColorTheme = Color.Black;
ContextMenu = new ContextMenuStripEx(components);
ContextMenu.Opened += ContextMenu_Opened;
ContextMenu.Opening += ContextMenu_Opening;
BuildMenu();
ContextMenuStrip = ContextMenu;
IgnoreDpiChanged = false;
CheckYouTube();
}
@@ -452,15 +568,15 @@ namespace mpvnet
CheckYouTube();
}
private string LastURL;
void CheckYouTube()
{
string clipboard = Clipboard.GetText();
if (clipboard.StartsWith("https://www.youtube.com/watch?") && LastURL != clipboard && Visible)
if (clipboard.StartsWith("https://www.youtube.com/watch?") && RegistryHelp.GetValue("HKCU\\Software\\" + Application.ProductName, "LastYouTubeURL") != clipboard && Visible)
{
LastURL = clipboard;
if (Msg.ShowQuestion("Play YouTube URL?") == MsgResult.OK)
RegistryHelp.SetValue("HKCU\\Software\\" + Application.ProductName, "LastYouTubeURL", clipboard);
if (Msg.ShowQuestion("Play YouTube URL?", clipboard) == MsgResult.OK)
mp.LoadURL(clipboard);
}
}

View File

@@ -3,8 +3,8 @@ using System.Runtime.InteropServices;
public class MediaInfo : IDisposable
{
private IntPtr Handle;
private static bool Loaded;
IntPtr Handle;
static bool Loaded;
public MediaInfo(string sourcepath)
{
@@ -25,7 +25,24 @@ public class MediaInfo : IDisposable
return Marshal.PtrToStringUni(MediaInfo_Get(Handle, streamKind, 0, parameter, MediaInfoInfoKind.Text, MediaInfoInfoKind.Name));
}
private bool Disposed;
public int GetCount(MediaInfoStreamKind streamKind) => MediaInfo_Count_Get(Handle, streamKind, -1);
public string GetVideo(int streamNumber, string parameter)
{
return Marshal.PtrToStringUni(MediaInfo_Get(Handle, MediaInfoStreamKind.Video, streamNumber, parameter, MediaInfoInfoKind.Text, MediaInfoInfoKind.Name));
}
public string GetAudio(int streamNumber, string parameter)
{
return Marshal.PtrToStringUni(MediaInfo_Get(Handle, MediaInfoStreamKind.Audio, streamNumber, parameter, MediaInfoInfoKind.Text, MediaInfoInfoKind.Name));
}
public string GetText(int streamNumber, string parameter)
{
return Marshal.PtrToStringUni(MediaInfo_Get(Handle, MediaInfoStreamKind.Text, streamNumber, parameter, MediaInfoInfoKind.Text, MediaInfoInfoKind.Name));
}
bool Disposed;
public void Dispose()
{
@@ -37,28 +54,35 @@ public class MediaInfo : IDisposable
}
}
~MediaInfo()
{
Dispose();
}
~MediaInfo() { Dispose(); }
[DllImport("kernel32.dll", CharSet = CharSet.Unicode)]
private static extern IntPtr LoadLibrary(string path);
static extern IntPtr LoadLibrary(string path);
[DllImport("MediaInfo.dll")]
private static extern IntPtr MediaInfo_New();
static extern IntPtr MediaInfo_New();
[DllImport("MediaInfo.dll")]
private static extern void MediaInfo_Delete(IntPtr Handle);
static extern void MediaInfo_Delete(IntPtr handle);
[DllImport("MediaInfo.dll", CharSet = CharSet.Unicode)]
private static extern int MediaInfo_Open(IntPtr Handle, string FileName);
static extern int MediaInfo_Open(IntPtr handle, string fileName);
[DllImport("MediaInfo.dll")]
private static extern int MediaInfo_Close(IntPtr Handle);
static extern int MediaInfo_Close(IntPtr handle);
[DllImport("MediaInfo.dll", CharSet = CharSet.Unicode)]
private static extern IntPtr MediaInfo_Get(IntPtr Handle, MediaInfoStreamKind StreamKind, int StreamNumber, string Parameter, MediaInfoInfoKind KindOfInfo, MediaInfoInfoKind KindOfSearch);
static extern IntPtr MediaInfo_Get(IntPtr handle,
MediaInfoStreamKind streamKind,
int streamNumber,
string parameter,
MediaInfoInfoKind kindOfInfo,
MediaInfoInfoKind kindOfSearch);
[DllImport("MediaInfo.dll", CharSet = CharSet.Unicode)]
static extern int MediaInfo_Count_Get(IntPtr handle,
MediaInfoStreamKind streamKind,
int streamNumber);
}
public enum MediaInfoStreamKind
@@ -67,8 +91,10 @@ public enum MediaInfoStreamKind
Video,
Audio,
Text,
Chapters,
Image
Other,
Image,
Menu,
Max,
}
public enum MediaInfoInfoKind

View File

@@ -23,76 +23,66 @@ public class ContextMenuStripEx : ContextMenuStrip
Renderer = new ToolStripRendererEx();
}
public ActionMenuItem Add(string path)
public MenuItem Add(string path)
{
return Add(path, null);
}
public ActionMenuItem Add(string path, Action action)
public MenuItem Add(string path, Action action, bool enabled = true)
{
return Add(path, action, true);
}
public ActionMenuItem Add(string path, Action action, bool enabled)
{
var ret = ActionMenuItem.Add(Items, path, action);
if (ret == null)
return null;
MenuItem ret = MenuItem.Add(Items, path, action);
if (ret == null) return null;
ret.Enabled = enabled;
return ret;
}
public ActionMenuItem Add(string path, Action action, Func<bool> enabledFunc)
{
var ret = ActionMenuItem.Add(Items, path, action);
return ret;
}
}
public class ActionMenuItem : MenuItemEx
public class MenuItem : ToolStripMenuItem
{
private Action Action;
public Action Action { get; set; }
public ActionMenuItem()
public MenuItem()
{
}
public ActionMenuItem(string text, Action action)
public MenuItem(string text) : base(text)
{
this.Text = text;
this.Action = action;
}
public MenuItem(string text, Action action) : base(text)
{
Action = action;
}
protected override void OnClick(EventArgs e)
{
Application.DoEvents();
if (Action != null)
Action();
Action?.Invoke();
base.OnClick(e);
}
public static ActionMenuItem Add<T>(ToolStripItemCollection items, string path, Action<T> action, T value)
public static MenuItem Add<T>(ToolStripItemCollection items, string path, Action<T> action, T value)
{
return Add(items, path, () => action(value));
}
public static ActionMenuItem Add(ToolStripItemCollection items, string path, Action action)
public static MenuItem Add(ToolStripItemCollection items, string path, Action action)
{
var a = path.Split(new[] { " > ", " | " }, StringSplitOptions.RemoveEmptyEntries);
var l = items;
string[] a = path.Split(new[] { " > ", " | " }, StringSplitOptions.RemoveEmptyEntries);
var itemsCollection = items;
for (var x = 0; x <= a.Length - 1; x++)
for (int x = 0; x < a.Length; x++)
{
var found = false;
bool found = false;
foreach (var i in l.OfType<ToolStripMenuItem>())
foreach (var i in itemsCollection.OfType<ToolStripMenuItem>())
{
if (x < a.Length - 1)
{
if (i.Text == a[x] + " ")
if (i.Text == a[x] + " ")
{
found = true;
l = i.DropDownItems;
itemsCollection = i.DropDownItems;
}
}
}
@@ -102,54 +92,38 @@ public class ActionMenuItem : MenuItemEx
if (x == a.Length - 1)
{
if (a[x] == "-")
l.Add(new ToolStripSeparator());
itemsCollection.Add(new ToolStripSeparator());
else
{
ActionMenuItem item = new ActionMenuItem(a[x] + " ", action);
l.Add(item);
l = item.DropDownItems;
MenuItem item = new MenuItem(a[x] + " ", action);
itemsCollection.Add(item);
itemsCollection = item.DropDownItems;
return item;
}
}
else
{
ActionMenuItem item = new ActionMenuItem();
item.Text = a[x] + " ";
l.Add(item);
l = item.DropDownItems;
MenuItem item = new MenuItem();
item.Text = a[x] + " ";
itemsCollection.Add(item);
itemsCollection = item.DropDownItems;
}
}
}
return null;
}
}
public class MenuItemEx : ToolStripMenuItem
{
public static bool UseTooltips { get; set; }
public MenuItemEx()
{
}
public MenuItemEx(string text) : base(text)
{
}
public override Size GetPreferredSize(Size constrainingSize)
{
var ret = base.GetPreferredSize(constrainingSize);
ret.Height = Convert.ToInt32(Font.Height * 1.4);
return ret;
Size size = base.GetPreferredSize(constrainingSize);
size.Height = Convert.ToInt32(Font.Height * 1.4);
return size;
}
public void CloseAll(object item)
{
if (item is ToolStripItem)
{
var d = (ToolStripItem)item;
CloseAll(d.Owner);
}
CloseAll(((ToolStripItem)item).Owner);
if (item is ToolStripDropDown)
{
@@ -158,20 +132,16 @@ public class MenuItemEx : ToolStripMenuItem
CloseAll(d.OwnerItem);
}
}
protected override void OnClick(EventArgs e)
{
Application.DoEvents();
base.OnClick(e);
}
}
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 ColorBorder { 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 ColorToolStrip1 { get; set; }
@@ -179,24 +149,37 @@ public class ToolStripRendererEx : ToolStripSystemRenderer
public static Color ColorToolStrip3 { get; set; }
public static Color ColorToolStrip4 { get; set; }
private int TextOffset;
int TextOffset;
public ToolStripRendererEx()
{
var argb = Convert.ToInt32(Registry.GetValue(@"HKEY_CURRENT_USER\Software\Microsoft\Windows\DWM", "ColorizationColor", 0));
if (argb == 0)
argb = Color.LightBlue.ToArgb();
InitColors(Color.FromArgb(argb));
if (ColorTheme == Color.Empty)
InitColors(Color.FromArgb(argb));
else
InitColors(ColorTheme);
}
public static void InitColors(Color c)
{
ColorBorder = HSLColor.Convert(c).ToColorSetLuminosity(100);
ColorChecked = HSLColor.Convert(c).ToColorSetLuminosity(200);
ColorBottom = HSLColor.Convert(c).ToColorSetLuminosity(220);
ColorBackground = HSLColor.Convert(c).ToColorSetLuminosity(230);
ColorChecked = HSLColor.Convert(c).ToColorSetLuminosity(160);
ColorSelection = HSLColor.Convert(c).ToColorSetLuminosity(180);
ColorBackground = HSLColor.Convert(c).ToColorSetLuminosity(210);
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;
ColorChecked = Color.FromArgb(90, 90, 90);
}
ColorToolStrip1 = ControlPaint.LightLight(ControlPaint.LightLight(ControlPaint.Light(ColorBorder, 1)));
ColorToolStrip2 = ControlPaint.LightLight(ControlPaint.LightLight(ControlPaint.Light(ColorBorder, 0.7f)));
ColorToolStrip3 = ControlPaint.LightLight(ControlPaint.LightLight(ControlPaint.Light(ColorBorder, 0.1f)));
@@ -205,7 +188,10 @@ public class ToolStripRendererEx : ToolStripSystemRenderer
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)
@@ -222,6 +208,7 @@ public class ToolStripRendererEx : ToolStripSystemRenderer
else
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);
}
@@ -235,69 +222,27 @@ public class ToolStripRendererEx : ToolStripSystemRenderer
Rectangle r = new Rectangle(-1, -1, e.AffectedBounds.Width, e.AffectedBounds.Height);
using (SolidBrush b = new SolidBrush(ColorToolStrip2))
{
e.Graphics.FillRectangle(b, r);
}
}
}
protected override void OnRenderMenuItemBackground(ToolStripItemRenderEventArgs e)
{
e.Item.ForeColor = Color.Black;
var r = new Rectangle(Point.Empty, e.Item.Size);
var g = e.Graphics;
Rectangle rect = new Rectangle(Point.Empty, e.Item.Size);
if (!(e.Item.Owner is MenuStrip))
g.Clear(ColorBackground);
e.Graphics.Clear(ColorBackground);
if (e.Item.Selected && e.Item.Enabled)
{
if (e.Item.Owner is MenuStrip)
DrawButton(e);
else
{
g.SmoothingMode = SmoothingMode.AntiAlias;
var r2 = new Rectangle(r.X + 2, r.Y, r.Width - 4, r.Height - 1);
r2.Inflate(-1, -1);
using (SolidBrush b = new SolidBrush(ColorChecked))
g.FillRectangle(b, r2);
}
e.Graphics.SmoothingMode = SmoothingMode.AntiAlias;
rect = new Rectangle(rect.X + 2, rect.Y, rect.Width - 4, rect.Height - 1);
rect.Inflate(-1, -1);
using (SolidBrush b = new SolidBrush(ColorSelection))
e.Graphics.FillRectangle(b, rect);
}
}
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)
{
if (e.Direction == ArrowDirection.Down) throw new NotImplementedException();
@@ -309,40 +254,56 @@ public class ToolStripRendererEx : ToolStripSystemRenderer
float y3 = e.Item.Height * 0.75f;
e.Graphics.SmoothingMode = SmoothingMode.HighQuality;
using (Pen p = new Pen(Brushes.Black, Control.DefaultFont.Height / 20f))
using (Brush b = new SolidBrush(ColorForeground))
{
e.Graphics.DrawLine(p, x1, y1, x2, y2);
e.Graphics.DrawLine(p, x2, y2, x3, y3);
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)
{
int x = Convert.ToInt32(e.ImageRectangle.Height * 0.2);
e.Graphics.DrawImage(e.Image, new Point(x, x));
if (e.Item.GetType() != typeof(MenuItem))
return;
MenuItem item = e.Item as MenuItem;
e.Graphics.SmoothingMode = SmoothingMode.AntiAlias;
if (!item.Checked)
return;
Rectangle rect = new Rectangle(Point.Empty, e.Item.Size);
rect = new Rectangle(rect.X + 2, rect.Y, rect.Height - 1, rect.Height - 1);
rect.Inflate(-1, -1);
using (Brush brush = new SolidBrush(ColorChecked))
e.Graphics.FillRectangle(brush, rect);
float ellipseWidth = rect.Height / 3f;
RectangleF rectF = new RectangleF(rect.X + rect.Height / 2f - ellipseWidth / 2f,
rect.Y + rect.Height / 2f - ellipseWidth / 2f,
ellipseWidth,
ellipseWidth);
using (Brush brush = new SolidBrush(ColorForeground))
e.Graphics.FillEllipse(brush, rectF);
}
protected override void OnRenderSeparator(ToolStripSeparatorRenderEventArgs e)
{
if (e.Item.IsOnDropDown)
{
e.Graphics.Clear(ColorBackground);
int right = e.Item.Width - Convert.ToInt32(TextOffset / 5.0);
int top = e.Item.Height / 2;
top -= 1;
using (Pen p = new Pen(Color.Gray))
e.Graphics.DrawLine(p, new Point(TextOffset, top), new Point(right, top));
}
else if (e.Vertical)
{
var bounds = e.Item.Bounds;
using (Pen p = new Pen(SystemColors.ControlDarkDark))
e.Graphics.DrawLine(p,
Convert.ToInt32(bounds.Width / 2.0),
Convert.ToInt32(bounds.Height * 0.15),
Convert.ToInt32(bounds.Width / 2.0),
Convert.ToInt32(bounds.Height * 0.85));
}
e.Graphics.Clear(ColorBackground);
int top = e.Item.Height / 2;
top -= 1;
int offset = Convert.ToInt32(e.Item.Font.Height * 0.7);
using (Pen p = new Pen(ColorBorder))
e.Graphics.DrawLine(p,
new Point(offset, top),
new Point(e.Item.Width - offset, top));
}
}
@@ -360,31 +321,28 @@ public struct HSLColor
Luminosity = l;
}
private double hue;
double _Hue;
public int Hue
{
get => System.Convert.ToInt32(hue * 240);
set => hue = CheckRange(value / 240.0);
public int Hue {
get => System.Convert.ToInt32(_Hue * 240);
set => _Hue = CheckRange(value / 240.0);
}
private double saturation;
double _Saturation;
public int Saturation
{
get => System.Convert.ToInt32(saturation * 240);
set => saturation = CheckRange(value / 240.0);
public int Saturation {
get => System.Convert.ToInt32(_Saturation * 240);
set => _Saturation = CheckRange(value / 240.0);
}
private double luminosity;
double _Luminosity;
public int Luminosity
{
get => System.Convert.ToInt32(luminosity * 240);
set => luminosity = CheckRange(value / 240.0);
public int Luminosity {
get => System.Convert.ToInt32(_Luminosity * 240);
set => _Luminosity = CheckRange(value / 240.0);
}
private double CheckRange(double value)
double CheckRange(double value)
{
if (value < 0)
value = 0;
@@ -409,21 +367,21 @@ public struct HSLColor
{
double r = 0, g = 0, b = 0;
if (luminosity != 0)
if (_Luminosity != 0)
{
if (saturation == 0)
if (_Saturation == 0)
{
b = luminosity;
g = luminosity;
r = luminosity;
b = _Luminosity;
g = _Luminosity;
r = _Luminosity;
}
else
{
double temp2 = GetTemp2(this);
double temp1 = 2.0 * luminosity - temp2;
r = GetColorComponent(temp1, temp2, hue + 1.0 / 3.0);
g = GetColorComponent(temp1, temp2, hue);
b = GetColorComponent(temp1, temp2, hue - 1.0 / 3.0);
double temp1 = 2.0 * _Luminosity - temp2;
r = GetColorComponent(temp1, temp2, _Hue + 1.0 / 3.0);
g = GetColorComponent(temp1, temp2, _Hue);
b = GetColorComponent(temp1, temp2, _Hue - 1.0 / 3.0);
}
}
@@ -433,7 +391,7 @@ public struct HSLColor
System.Convert.ToInt32(255 * b));
}
private static double GetColorComponent(double temp1, double temp2, double temp3)
static double GetColorComponent(double temp1, double temp2, double temp3)
{
temp3 = MoveIntoRange(temp3);
@@ -447,7 +405,7 @@ public struct HSLColor
return temp1;
}
private static double MoveIntoRange(double temp3)
static double MoveIntoRange(double temp3)
{
if (temp3 < 0)
temp3 += 1;
@@ -456,14 +414,14 @@ public struct HSLColor
return temp3;
}
private static double GetTemp2(HSLColor hslColor)
static double GetTemp2(HSLColor hslColor)
{
double temp2;
if (hslColor.luminosity < 0.5)
temp2 = hslColor.luminosity * (1.0 + hslColor.saturation);
if (hslColor._Luminosity < 0.5)
temp2 = hslColor._Luminosity * (1.0 + hslColor._Saturation);
else
temp2 = hslColor.luminosity + hslColor.saturation - (hslColor.luminosity * hslColor.saturation);
temp2 = hslColor._Luminosity + hslColor._Saturation - (hslColor._Luminosity * hslColor._Saturation);
return temp2;
}
@@ -471,17 +429,17 @@ public struct HSLColor
public static HSLColor Convert(Color c)
{
HSLColor r = new HSLColor();
r.hue = c.GetHue() / 360.0;
r.luminosity = c.GetBrightness();
r.saturation = c.GetSaturation();
r._Hue = c.GetHue() / 360.0;
r._Luminosity = c.GetBrightness();
r._Saturation = c.GetSaturation();
return r;
}
public void SetRGB(int red, int green, int blue)
{
HSLColor hc = HSLColor.Convert(Color.FromArgb(red, green, blue));
hue = hc.hue;
saturation = hc.saturation;
luminosity = hc.luminosity;
_Hue = hc._Hue;
_Saturation = hc._Saturation;
_Luminosity = hc._Luminosity;
}
}

View File

@@ -1,12 +1,18 @@
using Microsoft.Win32;
using System;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Runtime.Serialization;
using System.Windows.Forms;
using Microsoft.Win32;
namespace mpvnet
{
public class Misc
@@ -17,6 +23,31 @@ namespace mpvnet
String.Join(";*.", values) + "|*." + String.Join(";*.", values) + "|All Files|*.*";
}
public class Sys
{
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 static bool IsDirectoryWritable(string dirPath)
{
try
{
using (FileStream fs = File.Create(Path.Combine(dirPath,
Path.GetRandomFileName()), 1, FileOptions.DeleteOnClose))
{ }
return true;
}
catch
{ }
return false;
}
}
public class StringLogicalComparer : IComparer, IComparer<string>
{
[DllImport("shlwapi.dll", CharSet = CharSet.Unicode)]
@@ -91,6 +122,15 @@ namespace mpvnet
rk.SetValue(name, value);
}
public static string GetValue(string path, string name)
{
using (RegistryKey rk = GetRootKey(path).OpenSubKey(path.Substring(5)))
if (rk != null)
return rk.GetValue(name, "").ToString();
else
return "";
}
public static void RemoveKey(string path)
{
GetRootKey(path).DeleteSubKeyTree(path.Substring(5), false);
@@ -114,4 +154,110 @@ namespace mpvnet
}
}
}
public class MediaTrack
{
public string Text { get; set; }
public string Type { get; set; }
public int ID { get; set; }
}
[Serializable]
public class CommandItem : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
public string Path { get; set; } = "";
public string Command { get; set; } = "";
public CommandItem() { }
public CommandItem(SerializationInfo info, StreamingContext context) { }
private void NotifyPropertyChanged([CallerMemberName] string propertyName = "")
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
private string _Input = "";
public string Input {
get => _Input;
set {
_Input = value;
NotifyPropertyChanged();
}
}
private static ObservableCollection<CommandItem> _Items;
public static ObservableCollection<CommandItem> Items {
get {
if (_Items is null)
{
_Items = new ObservableCollection<CommandItem>();
if (File.Exists(mp.InputConfPath))
{
foreach (string line in File.ReadAllLines(mp.InputConfPath))
{
string val = line.Trim();
if (val.StartsWith("#")) continue;
if (!val.Contains(" ")) continue;
CommandItem item = new CommandItem();
item.Input = val.Substring(0, val.IndexOf(" ")).Replace("_", "");
val = val.Substring(val.IndexOf(" ") + 1);
if (val.Contains("#menu:"))
{
item.Path = val.Substring(val.IndexOf("#menu:") + 6).Trim();
val = val.Substring(0, val.IndexOf("#menu:"));
if (item.Path.Contains(";"))
item.Path = item.Path.Substring(item.Path.IndexOf(";") + 1).Trim();
}
item.Command = val.Trim();
if (item.Command == "")
continue;
if (item.Command.ToLower() == "ignore")
item.Command = "";
_Items.Add(item);
}
}
}
return _Items;
}
}
}
public class CursorHelp
{
static bool IsVisible = true;
public static void Show()
{
if (!IsVisible)
{
Cursor.Show();
IsVisible = true;
}
}
public static void Hide()
{
if (IsVisible)
{
Cursor.Hide();
IsVisible = false;
}
}
public static bool IsPosDifferent(Point screenPos)
{
return
Math.Abs(screenPos.X - Control.MousePosition.X) > 10 ||
Math.Abs(screenPos.Y - Control.MousePosition.Y) > 10;
}
}
}

View File

@@ -1,8 +1,6 @@
using System;
using System.Drawing;
using System.IO;
using System.Runtime.InteropServices;
using System.Text;
namespace mpvnet
{
@@ -14,11 +12,11 @@ namespace mpvnet
[DllImport("user32.dll", CharSet = CharSet.Unicode)]
public static extern IntPtr FindWindowEx(IntPtr parentHandle, IntPtr childAfter, string lclassName, string windowTitle);
[DllImport("user32.dll", CharSet = CharSet.Auto)]
public static extern string SendMessage(IntPtr hWnd, int msg, IntPtr wParam, IntPtr lParam);
[DllImport("user32.dll", CharSet = CharSet.Unicode)]
public static extern IntPtr SendMessage(IntPtr hWnd, int msg, IntPtr wParam, IntPtr lParam);
[DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Auto)]
public static extern bool PostMessage(IntPtr hWnd, int Msg, IntPtr wParam, IntPtr lParam);
[DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
public static extern IntPtr PostMessage(IntPtr hWnd, int Msg, IntPtr wParam, IntPtr lParam);
[DllImport("user32.dll")]
public static extern void ReleaseCapture();

View File

@@ -4,8 +4,8 @@ using System.Threading;
using System.Management.Automation.Runspaces;
using System.Reflection;
using System.Threading.Tasks;
using System.Windows.Forms;
using VBNET;
using Sys;
namespace mpvnet
{

View File

@@ -10,7 +10,7 @@ using System.Runtime.InteropServices;
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("mpv.net")]
[assembly: AssemblyCopyright("Copyright © 2017 stax76")]
[assembly: AssemblyCopyright("Copyright © 2017-2019 stax76")]
[assembly: AssemblyTrademark("")]
[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
// by using the '*' as shown below:
// [assembly: AssemblyVersion("1.0.*")]
[assembly: AssemblyVersion("2.6.0.0")]
[assembly: AssemblyFileVersion("2.6.0.0")]
[assembly: AssemblyVersion("3.1.0.0")]
[assembly: AssemblyFileVersion("3.1.0.0")]

View File

@@ -60,47 +60,33 @@ namespace mpvnet.Properties {
}
}
/// <summary>
/// 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:
///
/// # 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 [rest of string was truncated]&quot;;.
/// </summary>
internal static string input_conf {
internal static string inputConf {
get {
return ResourceManager.GetString("input_conf", resourceCulture);
return ResourceManager.GetString("inputConf", resourceCulture);
}
}
/// <summary>
/// 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
///volume = 50
///hwdec = yes
///keep-open = yes
///keep-open-pause = no
///osd-playing-msg = ${filename}
///screenshot-directory = ~~desktop/
///input-default-bindings = no.
/// </summary>
internal static string mpv_conf {
internal static string inputConfHeader {
get {
return ResourceManager.GetString("mpv_conf", resourceCulture);
return ResourceManager.GetString("inputConfHeader", resourceCulture);
}
}
internal static string mpvConf {
get {
return ResourceManager.GetString("mpvConf", resourceCulture);
}
}
internal static string mpvConfToml {
get {
return ResourceManager.GetString("mpvConfToml", resourceCulture);
}
}
internal static string mpvNetConfToml {
get {
return ResourceManager.GetString("mpvNetConfToml", resourceCulture);
}
}
}

View File

@@ -118,10 +118,19 @@
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<assembly alias="System.Windows.Forms" name="System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" />
<data name="input_conf" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>..\Resources\input.conf.txt;System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089;Windows-1252</value>
<data name="inputConf" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>..\Resources\inputConf.txt;System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089;Windows-1252</value>
</data>
<data name="mpv_conf" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>..\Resources\mpv.conf.txt;System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089;utf-8</value>
<data name="inputConfHeader" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>..\Resources\inputConfHeader.txt;System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089;utf-8</value>
</data>
<data name="mpvConf" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>..\Resources\mpvConf.txt;System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089;utf-8</value>
</data>
<data name="mpvConfToml" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>..\Resources\mpvConfToml.txt;System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089;utf-8</value>
</data>
<data name="mpvNetConfToml" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>..\Resources\mpvNetConfToml.txt;System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089;utf-8</value>
</data>
</root>

View File

@@ -1,9 +1,9 @@
using System;
using System.Reflection;
using System.Windows.Forms;
using IronPython.Hosting;
using Microsoft.Scripting.Hosting;
using VBNET;
using IronPython.Hosting;
using Sys;
using PyRT = IronPython.Runtime;
namespace mpvnet

View File

@@ -1,15 +1,15 @@
# 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:
# editor and an config editor as alternative to editing conf text files.
# The input and config editor 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
# https://github.com/stax76/mpv.net/blob/master/mpv.net/Resources/inputConf.txt
# the defaults of mpv can be found at:
@@ -36,23 +36,25 @@
_ ignore #menu: -
Enter cycle fullscreen #menu: Toggle Fullscreen
F11 playlist-prev #menu: Navigate > Previous
F12 playlist-next #menu: Navigate > Next
F11 playlist-prev #menu: Navigate > Previous File
F12 playlist-next #menu: Navigate > Next File
_ ignore #menu: Navigate > -
PGUP add chapter 1 #menu: Navigate > Next Chapter
PGDWN add chapter -1 #menu: Navigate > Previous Chapter
. frame-step #menu: Seek > Next Frame
, frame-back-step #menu: Seek > Previous Frame
_ ignore #menu: Seek > -
Right no-osd seek 7 #menu: Seek > 7 sec forward
Left no-osd seek -7 #menu: Seek > 7 sec backward
_ ignore #menu: Seek > -
Up no-osd seek 40 #menu: Seek > 40 sec forward
Down no-osd seek -40 #menu: Seek > 40 sec backward
_ ignore #menu: Seek > -
Ctrl+Right no-osd seek 300 #menu: Seek > 5 min forward
Ctrl+Left no-osd seek -300 #menu: Seek > 5 min backward
_ ignore #menu: Navigate > -
. frame-step #menu: Navigate > Jump Next Frame
, frame-back-step #menu: Navigate > Jump Previous Frame
_ ignore #menu: Navigate > -
Right no-osd seek 7 #menu: Navigate > Jump 7 sec forward
Left no-osd seek -7 #menu: Navigate > Jump 7 sec backward
_ ignore #menu: Navigate > -
Up no-osd seek 40 #menu: Navigate > Jump 40 sec forward
Down no-osd seek -40 #menu: Navigate > Jump 40 sec backward
_ ignore #menu: Navigate > -
Ctrl+Right no-osd seek 300 #menu: Navigate > Jump 5 min forward
Ctrl+Left no-osd seek -300 #menu: Navigate > Jump 5 min backward
_ ignore #menu: Navigate > -
_ ignore #menu: Navigate > Chapters
Ctrl++ add video-zoom 0.1 #menu: Pan & Scan > Increase Size
Ctrl+- add video-zoom -0.1 #menu: Pan & Scan > Decrease Size
@@ -84,7 +86,7 @@
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
KP7 cycle audio #menu: Audio > Cycle/Next
KP7 script-message mpv.net cycle-audio #menu: Audio > Cycle/Next
_ ignore #menu: Audio > -
KP6 add audio-delay 0.100 #menu: Audio > Delay +0.1
KP9 add audio-delay -0.100 #menu: Audio > Delay -0.1
@@ -101,6 +103,8 @@
_ add sub-scale -0.1 #menu: Subtitle > Decrease Subtitle Font Size
_ add sub-scale 0.1 #menu: Subtitle > Increase Subtitle Font Size
_ ignore #menu: Track
+ add volume 10 #menu: Volume > Up
- add volume -10 #menu: Volume > Down
_ ignore #menu: Volume > -
@@ -114,42 +118,44 @@
_ ignore #menu: Speed > -
BS set speed 1 #menu: Speed > Reset
KP0 script-message rate-file 0 #menu: Addons > Rating > 0stars
KP1 script-message rate-file 1 #menu: Addons > Rating > 1stars
KP2 script-message rate-file 2 #menu: Addons > Rating > 2stars
KP3 script-message rate-file 3 #menu: Addons > Rating > 3stars
KP4 script-message rate-file 4 #menu: Addons > Rating > 4stars
KP5 script-message rate-file 5 #menu: Addons > Rating > 5stars
KP0 script-message rate-file 0 #menu: Extensions > Rating > 0stars
KP1 script-message rate-file 1 #menu: Extensions > Rating > 1stars
KP2 script-message rate-file 2 #menu: Extensions > Rating > 2stars
KP3 script-message rate-file 3 #menu: Extensions > Rating > 3stars
KP4 script-message rate-file 4 #menu: Extensions > Rating > 4stars
KP5 script-message rate-file 5 #menu: Extensions > Rating > 5stars
Ctrl+t set ontop yes #menu: View > On Top > Enable
Ctrl+T set ontop no #menu: View > On Top > Disable
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-toggle #menu: View > Toggle Statistics
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-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+i script-message mpv.net show-input-editor #menu: Settings > Show Input Editor
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
l ab-loop #menu: Tools > Set/clear A-B loop points
L cycle-values loop-file "inf" "no" #menu: Tools > Toggle Infinite Looping
Del script-binding osc/visibility #menu: Tools > Toggle OSC Visibility
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...
Ctrl+P script-message mpv.net show-command-palette #menu: Tools > Command Palette
h script-message mpv.net show-history #menu: Tools > Show History
l ab-loop #menu: Tools > Set/clear A-B loop points
L cycle-values loop-file "inf" "no" #menu: Tools > Toggle infinite file looping
Ctrl+h cycle-values hwdec "auto" "no" #menu: Tools > Cycle Hardware Decoding
_ 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://github.com/mpv-player/mpv/blob/master/etc/input.conf #menu: Help > Show mpv default keys
_ script-message mpv.net shell-execute https://github.com/stax76/mpv.net/blob/master/mpv.net/Resources/input.conf.txt #menu: Help > Show mpv.net default keys
_ script-message mpv.net shell-execute https://github.com/stax76/mpvnet #menu: Help > Show mpv.net web site
_ script-message mpv.net shell-execute https://github.com/stax76/mpv.net/blob/master/mpv.net/Resources/inputConf.txt #menu: Help > Show mpv.net default keys
_ script-message mpv.net shell-execute https://mpv-net.github.io/mpv.net-web-site/ #menu: Help > Show mpv.net web site
_ ignore #menu: Help > -
_ script-message mpv.net show-about #menu: Help > About mpv.net
_ ignore #menu: -
Esc quit #menu: Exit
Q quit-watch-later #menu: Exit Watch Later
> playlist-next
< playlist-prev
Power quit

View File

@@ -0,0 +1,25 @@
# 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 config editor as alternatives to editing conf text files.
# The input and config editor 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/inputConf.txt
# the defaults of mpv can be found at:
# https://github.com/mpv-player/mpv/blob/master/etc/inputConf
# 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

View File

@@ -1,7 +1,7 @@

# 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
# mpv.net mpv.conf defaults: https://github.com/stax76/mpv.net/blob/master/mpv.net/Resources/mpvConf.txt
input-ar-delay = 500
input-ar-rate = 20

View File

@@ -146,12 +146,38 @@ default = "100"
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"
[[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]]
name = "slang"
default = ""
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."
[[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]]
name = "screen"
default = ""
@@ -163,18 +189,31 @@ name = "osd-playing-msg"
default = ""
width = 300
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"
[[settings]]
name = "fullscreen"
alias = "fs"
default = "no"
filter = "Screen"
help = "--fullscreen=<yes|no>, fs=<yes|no> Start the player in fullscreen mode. Default: no."
options = [{ name = "yes" },
{ 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]]
name = "keep-open-pause"
default = "yes"
@@ -194,7 +233,6 @@ options = [{ name = "yes", help = "Don't terminate if the current file is the
[[settings]]
name = "loop-file"
alias = "loop"
default = ""
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."
@@ -207,14 +245,6 @@ help = "--save-position-on-quit=<yes|no> Always save the current playback positi
options = [{ name = "yes" },
{ 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 = "input-ar-delay"
default = ""
@@ -227,12 +257,6 @@ default = ""
filter = "Input"
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]]
name = "hr-seek"
default = "absolute"
@@ -256,23 +280,3 @@ name = "loop-playlist"
default = ""
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."
[[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

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

646
mpv.net/Sys/TaskDialog.cs Normal file
View File

@@ -0,0 +1,646 @@
using System;
using System.Runtime.InteropServices;
using System.Text;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Reflection;
using System.Text.RegularExpressions;
using System.Threading;
using System.Windows.Forms;
using Microsoft.VisualBasic.CompilerServices;
namespace Sys
{
public class Msg
{
private static string ShownMessages;
public static string SupportURL { get; set; }
public static void Show(string mainInstruction, string content = null)
{
Msg.Show(mainInstruction, content, MsgIcon.Info, MsgButtons.Ok, MsgResult.None);
}
public static void ShowError(string mainInstruction, string content = null)
{
using (TaskDialog<string> td = new TaskDialog<string>())
{
td.AllowCancel = false;
if (string.IsNullOrEmpty(content))
{
if (mainInstruction.Length < 80)
td.MainInstruction = mainInstruction;
else
td.Content = mainInstruction;
}
else
{
td.MainInstruction = mainInstruction;
td.Content = content;
}
td.MainIcon = MsgIcon.Error;
td.Footer = "[copymsg Copy Message]";
if (!string.IsNullOrEmpty(Msg.SupportURL))
td.Footer += $" [{SupportURL} Contact Support]";
td.Show();
}
}
public static void ShowException(Exception e)
{
try
{
using (TaskDialog<string> td = new TaskDialog<string>())
{
td.MainInstruction = e.GetType().Name;
td.Content = e.Message;
td.MainIcon = MsgIcon.Error;
td.ExpandedInformation = e.ToString();
td.Footer = "[copymsg Copy Message]";
if (!string.IsNullOrEmpty(Msg.SupportURL))
td.Footer += $" [{SupportURL} Contact Support]";
td.Show();
}
}
catch (Exception ex)
{
MessageBox.Show(ex.GetType().Name + "\n\n" + e.Message + "\n\n" + e.ToString(),
Application.ProductName, MessageBoxButtons.OK, MessageBoxIcon.Error);
}
}
public static void ShowWarning(string mainInstruction,
string content = null,
bool onlyOnce = false)
{
if (onlyOnce && Msg.ShownMessages != null &&
Msg.ShownMessages.Contains(mainInstruction + content))
return;
Msg.Show(mainInstruction, content, MsgIcon.Warning, MsgButtons.Ok, MsgResult.None);
if (!onlyOnce) return;
Msg.ShownMessages += mainInstruction + content;
}
public static MsgResult ShowQuestion(string mainInstruction,
MsgButtons buttons = MsgButtons.OkCancel)
{
return Msg.Show(mainInstruction, null, MsgIcon.None, buttons, MsgResult.None);
}
public static MsgResult ShowQuestion(string mainInstruction,
string content,
MsgButtons buttons = MsgButtons.OkCancel)
{
return Msg.Show(mainInstruction, content, MsgIcon.None, buttons, MsgResult.None);
}
public static MsgResult Show(string mainInstruction,
string content,
MsgIcon icon,
MsgButtons buttons,
MsgResult defaultButton = MsgResult.None)
{
using (TaskDialog<MsgResult> td = new TaskDialog<MsgResult>())
{
td.AllowCancel = false;
td.DefaultButton = defaultButton;
td.MainIcon = icon;
if (content == null)
{
if (mainInstruction.Length < 80)
td.MainInstruction = mainInstruction;
else
td.Content = mainInstruction;
}
else
{
td.MainInstruction = mainInstruction;
td.Content = content;
}
if (buttons == MsgButtons.OkCancel)
{
td.AddButton("OK", MsgResult.OK);
td.AddButton("Cancel", MsgResult.Cancel);
}
else
td.CommonButtons = buttons;
return td.Show();
}
}
}
public class TaskDialog<T> : TaskDialogNative, IDisposable
{
private Dictionary<int, T> IdValueDic;
private Dictionary<int, string> IdTextDic;
private List<int> CommandLinkShieldList;
private IntPtr ButtonArray;
private IntPtr RadioButtonArray;
private List<TaskDialogNative.TASKDIALOG_BUTTON> Buttons;
private List<TaskDialogNative.TASKDIALOG_BUTTON> RadioButtons;
private TaskDialogNative.TASKDIALOGCONFIG Config;
const int TDE_CONTENT = 0;
const int TDE_EXPANDED_INFORMATION = 1;
const int TDE_FOOTER = 2;
const int TDE_MAIN_INSTRUCTION = 3;
const int TDN_CREATED = 0;
const int TDN_NAVIGATED = 1;
const int TDN_BUTTON_CLICKED = 2;
const int TDN_HYPERLINK_CLICKED = 3;
const int TDN_TIMER = 4;
const int TDN_DESTROYED = 5;
const int TDN_RADIO_BUTTON_CLICKED = 6;
const int TDN_DIALOG_CONSTRUCTED = 7;
const int TDN_VERIFICATION_CLICKED = 8;
const int TDN_HELP = 9;
const int TDN_EXPANDO_BUTTON_CLICKED = 10;
const int TDM_NAVIGATE_PAGE = 1125;
const int TDM_CLICK_BUTTON = 1126;
const int TDM_SET_MARQUEE_PROGRESS_BAR = 1127;
const int TDM_SET_PROGRESS_BAR_STATE = 1128;
const int TDM_SET_PROGRESS_BAR_RANGE = 1129;
const int TDM_SET_PROGRESS_BAR_POS = 1130;
const int TDM_SET_PROGRESS_BAR_MARQUEE = 1131;
const int TDM_SET_ELEMENT_TEXT = 1132;
const int TDM_CLICK_RADIO_BUTTON = 1134;
const int TDM_ENABLE_BUTTON = 1135;
const int TDM_ENABLE_RADIO_BUTTON = 1136;
const int TDM_CLICK_VERIFICATION = 1137;
const int TDM_UPDATE_ELEMENT_TEXT = 1138;
const int TDM_SET_BUTTON_ELEVATION_REQUIRED_STATE = 1139;
const int TDM_UPDATE_ICON = 1140;
private T SelectedValueValue;
private string SelectedTextValue;
private int TimeoutValue;
private int ExitTickCount;
private bool disposed;
public TaskDialog()
{
IdValueDic = new Dictionary<int, T>();
IdTextDic = new Dictionary<int, string>();
CommandLinkShieldList = new List<int>();
Buttons = new List<TaskDialogNative.TASKDIALOG_BUTTON>();
RadioButtons = new List<TaskDialogNative.TASKDIALOG_BUTTON>();
_SelectedID = -1;
Config = new TaskDialogNative.TASKDIALOGCONFIG();
Config.cbSize = (uint)Marshal.SizeOf(Config);
Config.hwndParent = GetHandle();
Config.hInstance = IntPtr.Zero;
Config.dwFlags = TaskDialogNative.TASKDIALOG_FLAGS.TDF_ALLOW_DIALOG_CANCELLATION;
Config.dwCommonButtons = MsgButtons.None;
Config.MainIcon = new TaskDialogNative.TASKDIALOGCONFIG_ICON_UNION(0);
Config.FooterIcon = new TaskDialogNative.TASKDIALOGCONFIG_ICON_UNION(0);
Config.cxWidth = 0U;
Config.cButtons = 0U;
Config.cRadioButtons = 0U;
Config.pButtons = IntPtr.Zero;
Config.pRadioButtons = IntPtr.Zero;
Config.nDefaultButton = 0;
Config.nDefaultRadioButton = 0;
Config.pszWindowTitle = ((AssemblyProductAttribute)Assembly.GetEntryAssembly().GetCustomAttributes(typeof(AssemblyProductAttribute), true)[0]).Product;
Config.pszMainInstruction = "";
Config.pszContent = "";
Config.pfCallback = new PFTASKDIALOGCALLBACK(this.DialogProc);
}
public IntPtr GetHandle()
{
StringBuilder lpszFileName = new StringBuilder(260);
IntPtr foregroundWindow = TaskDialogNative.GetForegroundWindow();
TaskDialogNative.GetWindowModuleFileName(foregroundWindow, lpszFileName, 260U);
if (Path.GetFileName(lpszFileName.ToString().Replace(".vshost", "")) ==
Path.GetFileName(Assembly.GetEntryAssembly().Location))
return foregroundWindow;
return IntPtr.Zero;
}
public bool AllowCancel {
set {
if (value)
Config.dwFlags |= TaskDialogNative.TASKDIALOG_FLAGS.TDF_ALLOW_DIALOG_CANCELLATION;
else
Config.dwFlags ^= TaskDialogNative.TASKDIALOG_FLAGS.TDF_ALLOW_DIALOG_CANCELLATION;
}
}
public string MainInstruction {
get => Config.pszMainInstruction;
set => Config.pszMainInstruction = value;
}
public string Content {
get => Config.pszContent;
set => Config.pszContent = ExpandWikiMarkup(value);
}
public string ExpandedInformation {
get => Config.pszExpandedInformation;
set => Config.pszExpandedInformation = ExpandWikiMarkup(value);
}
public string VerificationText {
get => Config.pszVerificationText;
set => Config.pszVerificationText = value;
}
public MsgResult DefaultButton {
get => (MsgResult)Config.nDefaultButton;
set => Config.nDefaultButton = (int)value;
}
public string Footer {
get => Config.pszFooter;
set => Config.pszFooter = ExpandWikiMarkup(value);
}
public MsgIcon MainIcon {
set => Config.MainIcon = new TaskDialogNative.TASKDIALOGCONFIG_ICON_UNION((int)value);
}
private int _SelectedID;
public int SelectedID {
get => _SelectedID;
set {
foreach (var i in IdValueDic)
if (i.Key == value) _SelectedID = value;
}
}
public T SelectedValue {
get {
if (IdValueDic.ContainsKey(SelectedID))
return IdValueDic[SelectedID];
return SelectedValueValue;
}
set => SelectedValueValue = value;
}
public string SelectedText {
get {
if (IdTextDic.ContainsKey(SelectedID))
return IdTextDic[SelectedID];
return SelectedTextValue;
}
set => SelectedTextValue = value;
}
public bool CheckBoxChecked {
get => (Config.dwFlags & TaskDialogNative.TASKDIALOG_FLAGS.TDF_VERIFICATION_FLAG_CHECKED) == TaskDialogNative.TASKDIALOG_FLAGS.TDF_VERIFICATION_FLAG_CHECKED;
set {
if (value)
Config.dwFlags |= TaskDialogNative.TASKDIALOG_FLAGS.TDF_VERIFICATION_FLAG_CHECKED;
else
Config.dwFlags ^= TaskDialogNative.TASKDIALOG_FLAGS.TDF_VERIFICATION_FLAG_CHECKED;
}
}
public MsgButtons CommonButtons {
get => Config.dwCommonButtons;
set => Config.dwCommonButtons = value;
}
public int Timeout {
get => Convert.ToInt32(TimeoutValue / 1000.0);
set {
TimeoutValue = value * 1000;
Config.dwFlags |= TaskDialogNative.TASKDIALOG_FLAGS.TDF_CALLBACK_TIMER;
}
}
public void AddButton(string text, T value)
{
int n = 1000 + IdValueDic.Count + 1;
IdValueDic[n] = value;
Buttons.Add(new TaskDialogNative.TASKDIALOG_BUTTON(n, text));
}
public string ExpandWikiMarkup(string value)
{
if (value.Contains("["))
{
Regex regex = new Regex("\\[(.*?) (.+?)\\]");
if (regex.Match(value).Success)
{
Config.dwFlags |= TaskDialogNative.TASKDIALOG_FLAGS.TDF_ENABLE_HYPERLINKS;
value = regex.Replace(value, "<a href=\"$1\">$2</a>");
}
}
return value;
}
public void AddCommandLink(string text, T value)
{
int n = 1000 + IdValueDic.Count + 1;
IdValueDic[n] = value == null ? (T)(object)text : value;
IdTextDic[n] = text;
Buttons.Add(new TaskDialogNative.TASKDIALOG_BUTTON(n, text));
Config.dwFlags |= TaskDialogNative.TASKDIALOG_FLAGS.TDF_USE_COMMAND_LINKS;
}
public void AddCommandLink(string text, string description, T value, bool setShield = false)
{
int n = 1000 + IdValueDic.Count + 1;
IdValueDic[n] = value;
if (setShield) CommandLinkShieldList.Add(n);
if (!string.IsNullOrEmpty(description)) text += "\n" + description;
Buttons.Add(new TaskDialogNative.TASKDIALOG_BUTTON(n, text));
Config.dwFlags |= TaskDialogNative.TASKDIALOG_FLAGS.TDF_USE_COMMAND_LINKS;
}
public void AddRadioButton(string text, T value)
{
int n = 1000 + IdValueDic.Count + 1;
IdValueDic[n] = value;
RadioButtons.Add(new TaskDialogNative.TASKDIALOG_BUTTON(n, text));
}
public T Show()
{
MarshalDialogControlStructs();
TaskDialogNative.TASKDIALOGCONFIG config = Config;
int errorCode = TaskDialogNative.TaskDialogIndirect(config, out int dummy1, out int dummy2, out bool isChecked);
if (errorCode < 0) Marshal.ThrowExceptionForHR(errorCode);
CheckBoxChecked = isChecked;
if (SelectedValue is MsgResult) SelectedValue = (T)(object)SelectedID;
return SelectedValue;
}
public int DialogProc(IntPtr hwnd, uint msg, IntPtr wParam, IntPtr lParam, IntPtr lpRefData)
{
switch (msg)
{
case 0: //TDN_CREATED
foreach (var i in CommandLinkShieldList)
SendMessage(hwnd, TDM_SET_BUTTON_ELEVATION_REQUIRED_STATE, new IntPtr(i), new IntPtr(1));
break;
case 2: //TDN_BUTTON_CLICKED
case 6: //TDN_RADIO_BUTTON_CLICKED
if (SelectedValue is MsgResult)
_SelectedID = wParam.ToInt32();
else
SelectedID = wParam.ToInt32();
break;
case 3: //TDN_HYPERLINK_CLICKED
string stringUni = Marshal.PtrToStringUni(lParam);
if (stringUni.StartsWith("mailto") || stringUni.StartsWith("http"))
Process.Start(stringUni);
if (Operators.CompareString(stringUni, "copymsg", false) == 0)
{
Thread thread = new Thread((ThreadStart)(() => {
Clipboard.SetText(MainInstruction + "\r\n\r\n" + Content + "\r\n\r\n" + ExpandedInformation);
MessageBox.Show("Message was copied to clipboard.", Application.ProductName, MessageBoxButtons.OK, MessageBoxIcon.Information);
}));
thread.SetApartmentState(ApartmentState.STA);
thread.Start();
}
break;
case 4: //TDN_TIMER
if (ExitTickCount == 0) ExitTickCount = Environment.TickCount + Timeout * 1000;
if (Environment.TickCount > ExitTickCount)
TaskDialogNative.SendMessage(hwnd, 1126, new IntPtr(1), IntPtr.Zero);
break;
}
return 0;
}
public void MarshalDialogControlStructs()
{
if (Buttons != null && Buttons.Count > 0)
{
ButtonArray = TaskDialog<T>.AllocateAndMarshalButtons(Buttons);
Config.pButtons = ButtonArray;
Config.cButtons = (uint)Buttons.Count;
}
if (RadioButtons == null || RadioButtons.Count <= 0) return;
RadioButtonArray = TaskDialog<T>.AllocateAndMarshalButtons(RadioButtons);
Config.pRadioButtons = RadioButtonArray;
Config.cRadioButtons = (uint)RadioButtons.Count;
}
public static IntPtr AllocateAndMarshalButtons(List<TaskDialogNative.TASKDIALOG_BUTTON> structs)
{
var initialPtr = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(TASKDIALOG_BUTTON)) * structs.Count);
var currentPtr = initialPtr;
foreach (var button in structs)
{
Marshal.StructureToPtr(button, currentPtr, false);
currentPtr = (IntPtr)(currentPtr.ToInt64() + Marshal.SizeOf(button));
}
return initialPtr;
}
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
~TaskDialog()
{
Dispose(false);
}
protected void Dispose(bool disposing)
{
if (disposed) return;
disposed = true;
if (ButtonArray != IntPtr.Zero)
{
Marshal.FreeHGlobal(ButtonArray);
ButtonArray = IntPtr.Zero;
}
if (RadioButtonArray != IntPtr.Zero)
{
Marshal.FreeHGlobal(RadioButtonArray);
RadioButtonArray = IntPtr.Zero;
}
}
}
public delegate int PFTASKDIALOGCALLBACK(
IntPtr hwnd,
uint msg,
IntPtr wParam,
IntPtr lParam,
IntPtr lpRefData);
public class TaskDialogNative
{
[DllImport("comctl32", CharSet = CharSet.Unicode, SetLastError = true)]
public static extern int TaskDialogIndirect(
[In] TaskDialogNative.TASKDIALOGCONFIG pTaskConfig,
out int pnButton,
out int pnRadioButton,
[MarshalAs(UnmanagedType.Bool)] out bool pVerificationFlagChecked);
[DllImport("user32.dll")]
public static extern IntPtr GetForegroundWindow();
[DllImport("user32.dll", CharSet = CharSet.Unicode)]
public static extern uint GetWindowModuleFileName(
IntPtr hwnd,
StringBuilder lpszFileName,
uint cchFileNameMax);
[DllImport("user32.dll")]
public static extern IntPtr SendMessage(
IntPtr handle,
int message,
IntPtr wParam,
IntPtr lParam);
[StructLayout(LayoutKind.Sequential, Pack = 4, CharSet = CharSet.Unicode)]
public class TASKDIALOGCONFIG
{
public uint cbSize;
public IntPtr hwndParent;
public IntPtr hInstance;
public TaskDialogNative.TASKDIALOG_FLAGS dwFlags;
public MsgButtons dwCommonButtons;
[MarshalAs(UnmanagedType.LPWStr)]
public string pszWindowTitle;
public TaskDialogNative.TASKDIALOGCONFIG_ICON_UNION MainIcon;
[MarshalAs(UnmanagedType.LPWStr)]
public string pszMainInstruction;
[MarshalAs(UnmanagedType.LPWStr)]
public string pszContent;
public uint cButtons;
public IntPtr pButtons;
public int nDefaultButton;
public uint cRadioButtons;
public IntPtr pRadioButtons;
public int nDefaultRadioButton;
[MarshalAs(UnmanagedType.LPWStr)]
public string pszVerificationText;
[MarshalAs(UnmanagedType.LPWStr)]
public string pszExpandedInformation;
[MarshalAs(UnmanagedType.LPWStr)]
public string pszExpandedControlText;
[MarshalAs(UnmanagedType.LPWStr)]
public string pszCollapsedControlText;
public TaskDialogNative.TASKDIALOGCONFIG_ICON_UNION FooterIcon;
[MarshalAs(UnmanagedType.LPWStr)]
public string pszFooter;
public PFTASKDIALOGCALLBACK pfCallback;
public IntPtr lpCallbackData;
public uint cxWidth;
}
public enum TASKDIALOG_FLAGS
{
NONE = 0,
TDF_ENABLE_HYPERLINKS = 1,
TDF_USE_HICON_MAIN = 2,
TDF_USE_HICON_FOOTER = 4,
TDF_ALLOW_DIALOG_CANCELLATION = 8,
TDF_USE_COMMAND_LINKS = 16,
TDF_USE_COMMAND_LINKS_NO_ICON = 32,
TDF_EXPAND_FOOTER_AREA = 64,
TDF_EXPANDED_BY_DEFAULT = 128,
TDF_VERIFICATION_FLAG_CHECKED = 256,
TDF_SHOW_PROGRESS_BAR = 512,
TDF_SHOW_MARQUEE_PROGRESS_BAR = 1024,
TDF_CALLBACK_TIMER = 2048,
TDF_POSITION_RELATIVE_TO_WINDOW = 4096,
TDF_RTL_LAYOUT = 8192,
TDF_NO_DEFAULT_RADIO_BUTTON = 16384,
}
[StructLayout(LayoutKind.Explicit, CharSet = CharSet.Unicode)]
public struct TASKDIALOGCONFIG_ICON_UNION
{
[FieldOffset(0)]
public int hMainIcon;
[FieldOffset(0)]
public int pszIcon;
[FieldOffset(0)]
public IntPtr spacer;
public TASKDIALOGCONFIG_ICON_UNION(int i)
{
this = new TaskDialogNative.TASKDIALOGCONFIG_ICON_UNION();
spacer = IntPtr.Zero;
pszIcon = 0;
hMainIcon = i;
}
}
[StructLayout(LayoutKind.Sequential, Pack = 4, CharSet = CharSet.Unicode)]
public struct TASKDIALOG_BUTTON
{
public int nButtonID;
[MarshalAs(UnmanagedType.LPWStr)]
public string pszButtonText;
public TASKDIALOG_BUTTON(int n, string txt)
{
this = new TaskDialogNative.TASKDIALOG_BUTTON();
nButtonID = n;
pszButtonText = txt;
}
}
}
public enum MsgButtons
{
None = 0,
Ok = 1,
Yes = 2,
No = 4,
YesNo = 6,
Cancel = 8,
OkCancel = 9,
YesNoCancel = 14,
Retry = 16,
RetryCancel = 24,
Close = 32,
}
public enum MsgResult
{
None,
OK,
Cancel,
Abort,
Retry,
Ignore,
Yes,
No,
}
public enum MsgIcon
{
None = 0,
SecurityShieldGray = 65527,
SecuritySuccess = 65528,
SecurityError = 65529,
SecurityWarning = 65530,
SecurityShieldBlue = 65531,
Shield = 65532,
Info = 65533,
Error = 65534,
Warning = 65535,
}
}

View File

@@ -1,36 +0,0 @@
using System;
using System.Drawing;
using System.Windows.Forms;
namespace mpvnet
{
public class CursorHelp
{
static bool IsVisible = true;
public static void Show()
{
if (!IsVisible)
{
Cursor.Show();
IsVisible = true;
}
}
public static void Hide()
{
if (IsVisible)
{
Cursor.Hide();
IsVisible = false;
}
}
public static bool IsPosDifferent(Point screenPos)
{
return
Math.Abs(screenPos.X - Control.MousePosition.X) > 10 ||
Math.Abs(screenPos.Y - Control.MousePosition.Y) > 10;
}
}
}

View File

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

34
mpv.net/WPF/WPF.cs Normal file
View File

@@ -0,0 +1,34 @@
using System;
using System.Windows;
using System.Windows.Media;
namespace WPF
{
public class WPF
{
public static void Init()
{
EnsureApplicationResources();
}
public static void EnsureApplicationResources()
{
if (Application.Current == null)
{
new Application();
Application.Current.Resources.MergedDictionaries.Add(
Application.LoadComponent(new Uri("mpvnet;component/WPF/Resources.xaml",
UriKind.Relative)) as ResourceDictionary);
}
}
public static Brush ThemeBrush {
get {
if (Environment.OSVersion.Version.Major < 10)
return new SolidColorBrush(Colors.DarkSlateGray);
else
return SystemParameters.WindowGlassBrush;
}
}
}
}

View File

@@ -0,0 +1,17 @@
<Window x:Class="mpvnet.AboutWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d"
Title="About mpv.net" Height="230" Width="420" FontSize="16" ShowInTaskbar="False"
WindowStartupLocation="CenterOwner" ResizeMode="NoResize" PreviewKeyDown="Window_PreviewKeyDown">
<Grid>
<StackPanel HorizontalAlignment="Center" VerticalAlignment="Center">
<TextBlock FontSize="48" HorizontalAlignment="Center" Margin="0,0,0,10">mpv.net</TextBlock>
<TextBlock HorizontalAlignment="Center">Copyright (c) 2017-2019 Frank Skare (stax76)</TextBlock>
<TextBlock Name="Version" HorizontalAlignment="Center" />
<TextBlock HorizontalAlignment="Center" Margin="0,0,0,20">MIT License</TextBlock>
</StackPanel>
</Grid>
</Window>

View File

@@ -0,0 +1,20 @@
using System.Windows;
using System.Windows.Input;
namespace mpvnet
{
public partial class AboutWindow : Window
{
public AboutWindow()
{
InitializeComponent();
Version.Text = $"Version {System.Windows.Forms.Application.ProductVersion}";
Foreground = WPF.WPF.ThemeBrush;
}
private void Window_PreviewKeyDown(object sender, KeyEventArgs e)
{
Close();
}
}
}

View File

@@ -0,0 +1,35 @@
<Window x:Class="mpvnet.CommandPaletteWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d"
Title="Command Palette" Height="295" Width="400" ResizeMode="NoResize"
WindowStartupLocation="CenterOwner" Loaded="Window_Loaded" FontSize="13">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition></RowDefinition>
</Grid.RowDefinitions>
<TextBox Name="FilterTextBox" PreviewKeyDown="FilterTextBox_PreviewKeyDown" TextChanged="FilterTextBox_TextChanged"></TextBox>
<ListView Name="ListView" Grid.Row="1" MouseUp="ListView_MouseUp">
<ListView.ItemContainerStyle>
<Style TargetType="ListBoxItem">
<Setter Property="HorizontalContentAlignment" Value="Stretch"></Setter>
</Style>
</ListView.ItemContainerStyle>
<ListView.ItemTemplate>
<DataTemplate>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition />
<ColumnDefinition />
</Grid.ColumnDefinitions>
<TextBlock Text="{Binding Path}"></TextBlock>
<TextBlock Grid.Column="1" Text="{Binding Input}" HorizontalAlignment="Right"></TextBlock>
</Grid>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</Grid>
</Window>

View File

@@ -0,0 +1,109 @@
using System;
using System.ComponentModel;
using System.Windows;
using System.Windows.Data;
using System.Windows.Input;
using System.Windows.Interop;
namespace mpvnet
{
public partial class CommandPaletteWindow : Window
{
ICollectionView CollectionView;
public CommandPaletteWindow()
{
InitializeComponent();
CollectionViewSource collectionViewSource = new CollectionViewSource() { Source = CommandItem.Items };
CollectionView = collectionViewSource.View;
var yourCostumFilter = new Predicate<object>(item => Filter((CommandItem)item));
CollectionView.Filter = yourCostumFilter;
ListView.ItemsSource = CollectionView;
}
bool Filter(CommandItem item)
{
if (item.Command == "") return false;
string filter = FilterTextBox.Text.ToLower();
if (filter == "") return true;
if (item.Command.ToLower().Contains(filter) ||
item.Input.ToLower().Contains(filter) ||
item.Path.ToLower().Contains(filter))
return true;
return false;
}
private void Window_Loaded(object sender, RoutedEventArgs e)
{
HwndSource source = HwndSource.FromHwnd(new WindowInteropHelper(this).Handle);
source.AddHook(new HwndSourceHook(WndProc));
Keyboard.Focus(FilterTextBox);
SelectFirst();
}
void SelectFirst()
{
if (ListView.Items.Count > 0)
ListView.SelectedIndex = 0;
}
private IntPtr WndProc(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam, ref bool handled)
{
if (msg == 0x200 /*WM_MOUSEMOVE*/ && Mouse.LeftButton != MouseButtonState.Pressed)
handled = true;
return IntPtr.Zero;
}
private void FilterTextBox_PreviewKeyDown(object sender, KeyEventArgs e)
{
switch (e.Key)
{
case Key.Up:
{
int index = ListView.SelectedIndex;
index -= 1;
if (index < 0) index = 0;
ListView.SelectedIndex = index;
ListView.ScrollIntoView(ListView.SelectedItem);
}
break;
case Key.Down:
{
int index = ListView.SelectedIndex;
index += 1;
if (index > ListView.Items.Count - 1) index = ListView.Items.Count - 1;
ListView.SelectedIndex = index;
ListView.ScrollIntoView(ListView.SelectedItem);
}
break;
case Key.Escape:
Close();
break;
case Key.Enter:
Execute();
break;
}
}
void Execute()
{
if (ListView.SelectedItem != null)
{
CommandItem item = ListView.SelectedItem as CommandItem;
Close();
mp.command_string(item.Command);
}
}
private void ListView_MouseUp(object sender, MouseButtonEventArgs e)
{
Execute();
}
private void FilterTextBox_TextChanged(object sender, System.Windows.Controls.TextChangedEventArgs e)
{
CollectionView.Refresh();
SelectFirst();
}
}
}

View File

@@ -1,37 +1,37 @@
<Window xmlns:Controls="clr-namespace:Controls" x:Name="MainWindow1" x:Class="mpvConfEdit.MainWindow"
<Window xmlns:Controls="clr-namespace:Controls" x:Name="ConfWindow1" x:Class="mpvnet.ConfWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:WPF="clr-namespace:WPF"
mc:Ignorable="d"
Height="600" Width="800" Loaded="MainWindow1_Loaded" WindowStartupLocation="CenterScreen">
Height="500" Width="700" Loaded="ConfWindow1_Loaded" ShowInTaskbar="False"
WindowStartupLocation="CenterScreen" Title="Config Editor">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="4*" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="10*" />
<ColumnDefinition Width="60*" />
<ColumnDefinition Width="1*" />
<ColumnDefinition Width="6*" />
</Grid.ColumnDefinitions>
<Controls:SearchTextBoxUserControl x:Name="SearchControl" Width="300" Margin="0,20,0,10" Grid.ColumnSpan="2" />
<Controls:SearchTextBoxUserControl HintText="Find a setting" 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" Margin="0,0,0,10">
<StackPanel x:Name="MainStackPanel"></StackPanel>
</ScrollViewer>
<StackPanel Margin="20,0,0,0" Grid.Row="1">
<ListBox x:Name="FilterListBox" ItemsSource="{Binding FilterStrings}" BorderThickness="0" SelectionChanged="ListBox_SelectionChanged" Foreground="{x:Static Controls:Controls.ThemeBrush}">
<ListBox x:Name="FilterListBox" ItemsSource="{Binding FilterStrings}" BorderThickness="0" SelectionChanged="ListBox_SelectionChanged" Foreground="{x:Static WPF:WPF.ThemeBrush}" Background="{Binding Path=Background, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=Window}}">
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<TextBlock Text="{Binding}" FontSize="16" />
</StackPanel>
<TextBlock Text="{Binding}" FontSize="16" />
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
<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 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 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 mpv.conf</TextBlock>
<TextBlock x:Name="OpenSettingsTextBlock" Margin="0,30,0,0" Cursor="Hand" TextWrapping="WrapWithOverflow" Foreground="{x:Static WPF:WPF.ThemeBrush}" MouseUp="OpenSettingsTextBlock_MouseUp">Open config folder</TextBlock>
<TextBlock x:Name="ShowManualTextBlock" Margin="0,15,0,0" Cursor="Hand" TextWrapping="WrapWithOverflow" Foreground="{x:Static WPF:WPF.ThemeBrush}" MouseUp="ShowManualTextBlock_MouseUp">Show mpv manual</TextBlock>
<TextBlock x:Name="SupportTextBlock" Margin="0,15,0,0" Cursor="Hand" TextWrapping="WrapWithOverflow" Foreground="{x:Static WPF:WPF.ThemeBrush}" MouseUp="SupportTextBlock_MouseUp">Show support forum</TextBlock>
<TextBlock x:Name="ApplyTextBlock" Margin="0,15,0,0" Cursor="Hand" TextWrapping="WrapWithOverflow" Foreground="{x:Static WPF:WPF.ThemeBrush}" MouseUp="ApplyTextBlock_MouseUp">Write config to disk</TextBlock>
</StackPanel>
</Grid>
</Window>

View File

@@ -0,0 +1,259 @@
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
using System.Windows.Media;
using DynamicGUI;
using Microsoft.Win32;
namespace mpvnet
{
public partial class ConfWindow : Window
{
private List<SettingBase> MpvSettingsDefinitions = Settings.LoadSettings(Properties.Resources.mpvConfToml);
private List<SettingBase> MpvNetSettingsDefinitions = Settings.LoadSettings(Properties.Resources.mpvNetConfToml);
private Dictionary<string, Dictionary<string, string>> Comments = new Dictionary<string, Dictionary<string, string>>();
public ObservableCollection<string> FilterStrings { get; } = new ObservableCollection<string>();
public ConfWindow()
{
InitializeComponent();
DataContext = this;
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();
}
public Brush Foreground2 {
get { return (Brush)GetValue(Foreground2Property); }
set { SetValue(Foreground2Property, value); }
}
public static readonly DependencyProperty Foreground2Property =
DependencyProperty.Register("Foreground2", typeof(Brush), typeof(ConfWindow), 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;
Foreground = Brushes.White;
Foreground2 = Brushes.Silver;
Background = Brushes.Black;
}
private void LoadSettings(List<SettingBase> settingsDefinitions,
Dictionary<string, string> confSettings)
{
foreach (var setting in settingsDefinitions)
{
if (!FilterStrings.Contains(setting.Filter))
FilterStrings.Add(setting.Filter);
foreach (var pair in confSettings)
{
if (setting.Name == pair.Key)
{
setting.Value = pair.Value;
setting.StartValue = pair.Value;
continue;
}
}
switch (setting)
{
case StringSetting s:
var sc = new StringSettingControl(s);
sc.TitleTextBox.Foreground = WPF.WPF.ThemeBrush;
MainStackPanel.Children.Add(sc);
break;
case OptionSetting s:
var oc = new OptionSettingControl(s);
oc.TitleTextBox.Foreground = WPF.WPF.ThemeBrush;
MainStackPanel.Children.Add(oc);
break;
}
}
}
private Dictionary<string, string> _mpvConf;
public Dictionary<string, string> MpvConf {
get {
if (_mpvConf == null) _mpvConf = LoadConf(mp.MpvConfPath);
return _mpvConf;
}
}
private Dictionary<string, string> _mpvNetConf;
public Dictionary<string, string> MpvNetConf {
get {
if (_mpvNetConf == null) _mpvNetConf = LoadConf(mp.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)
{
base.OnClosed(e);
WriteToDisk();
Registry.SetValue(@"HKEY_CURRENT_USER\Software\mpv.net", "conf editor search", SearchControl.Text);
}
void WriteToDisk()
{
bool isDirty = false;
foreach (SettingBase i in MpvSettingsDefinitions)
if (i.StartValue != i.Value)
isDirty = true;
foreach (SettingBase i in MpvNetSettingsDefinitions)
if (i.StartValue != i.Value)
isDirty = true;
if (!isDirty)
return;
WriteToDisk(mp.MpvConfPath, MpvConf, MpvSettingsDefinitions);
WriteToDisk(mp.MpvNetConfPath, MpvNetConf, MpvNetSettingsDefinitions);
MessageBox.Show("Changes will be available on next mpv.net startup.",
Title, MessageBoxButton.OK, MessageBoxImage.Information);
}
void WriteToDisk(string filePath,
Dictionary<string, string> confSettings,
List<SettingBase> settings)
{
string content = "";
foreach (var i in Comments[filePath])
content += $"#{i.Key} = {i.Value}\r\n";
foreach (var setting in settings)
{
if ((setting.Value ?? "") != setting.Default)
confSettings[setting.Name] = setting.Value;
if (confSettings.ContainsKey(setting.Name) &&
(setting.Value ?? "") == setting.Default ||
(setting.Value ?? "") == "")
{
confSettings.Remove(setting.Name);
}
}
foreach (var i in confSettings)
content = content + $"{i.Key} = {i.Value}\r\n";
File.WriteAllText(filePath, content);
}
private void SearchTextBox_TextChanged(object sender, TextChangedEventArgs e)
{
string activeFilter = "";
foreach (var i in FilterStrings)
if (SearchControl.Text == i + ":")
activeFilter = i;
if (activeFilter == "")
{
foreach (UIElement i in MainStackPanel.Children)
if ((i as ISettingControl).Contains(SearchControl.Text))
i.Visibility = Visibility.Visible;
else
i.Visibility = Visibility.Collapsed;
FilterListBox.SelectedItem = null;
}
else
foreach (UIElement i in MainStackPanel.Children)
if ((i as ISettingControl).SettingBase.Filter == activeFilter)
i.Visibility = Visibility.Visible;
else
i.Visibility = Visibility.Collapsed;
MainScrollViewer.ScrollToTop();
}
private void ConfWindow1_Loaded(object sender, RoutedEventArgs e)
{
SearchControl.SearchTextBox.SelectAll();
Keyboard.Focus(SearchControl.SearchTextBox);
}
private void ListBox_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
if (e.AddedItems.Count > 0)
SearchControl.Text = e.AddedItems[0].ToString() + ":";
}
private void OpenSettingsTextBlock_MouseUp(object sender, MouseButtonEventArgs e)
{
Process.Start(Path.GetDirectoryName(mp.MpvConfPath));
}
private void ShowManualTextBlock_MouseUp(object sender, MouseButtonEventArgs e)
{
Process.Start("https://mpv.io/manual/master/");
}
private void SupportTextBlock_MouseUp(object sender, MouseButtonEventArgs e)
{
Process.Start("https://github.com/stax76/mpv.net#Support");
}
private void ApplyTextBlock_MouseUp(object sender, MouseButtonEventArgs e)
{
WriteToDisk();
}
}
}

View File

@@ -1,20 +1,33 @@
<Window xmlns:Controls="clr-namespace:Controls" x:Class="mpvInputEdit.MainWindow"
<Window xmlns:Controls="clr-namespace:Controls" x:Class="mpvnet.InputWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d"
Title="MainWindow" Height="500" Width="750" FontSize="13"
Loaded="Window_Loaded" Closed="Window_Closed">
Title="Input Editor" Height="500" Width="750" FontSize="13"
Loaded="Window_Loaded" Closed="Window_Closed" ShowInTaskbar="False">
<Window.Resources>
<Style x:Key="DataGrid_Font_Centering" TargetType="{x:Type DataGridCell}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type DataGridCell}">
<Grid Background="{TemplateBinding Background}">
<ContentPresenter VerticalAlignment="Center" />
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</Window.Resources>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<Controls:SearchTextBoxUserControl x:Name="SearchControl" Width="300" Margin="0,20,0,20" Grid.ColumnSpan="2" />
<Controls:SearchTextBoxUserControl HintText="Type ? to get help." x:Name="SearchControl" Width="300" Margin="0,20,0,20" Grid.ColumnSpan="2" />
<DataGrid Grid.Row="1" x:Name="DataGrid" CommandManager.PreviewCanExecute="DataGrid_PreviewCanExecute" AutoGenerateColumns="False" CellStyle="{StaticResource DataGrid_Font_Centering}">
<DataGrid.Columns>
<DataGridTextColumn Header="Menu" Binding="{Binding Menu}"/>
<DataGridTextColumn Header="Menu" Binding="{Binding Path}"/>
<DataGridTemplateColumn Header="Input">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>

View File

@@ -2,27 +2,27 @@
using System.Collections.Generic;
using System.ComponentModel;
using System.IO;
using System.Reflection;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Input;
namespace mpvInputEdit
namespace mpvnet
{
public partial class MainWindow : Window
public partial class InputWindow : Window
{
ICollectionView CollectionView;
string InitialInputConfContent;
public MainWindow()
public InputWindow()
{
InitializeComponent();
Title = (Assembly.GetExecutingAssembly().GetCustomAttributes(typeof(AssemblyProductAttribute), true)[0] as AssemblyProductAttribute).Product + " " + Assembly.GetExecutingAssembly().GetName().Version.ToString();
InitialInputConfContent = GetInputConfContent();
SearchControl.SearchTextBox.TextChanged += SearchTextBox_TextChanged;
DataGrid.SelectionMode = DataGridSelectionMode.Single;
CollectionViewSource collectionViewSource = new CollectionViewSource() { Source = App.InputItems };
CollectionViewSource collectionViewSource = new CollectionViewSource() { Source = CommandItem.Items };
CollectionView = collectionViewSource.View;
var yourCostumFilter = new Predicate<object>(item => Filter((InputItem)item));
var yourCostumFilter = new Predicate<object>(item => Filter((CommandItem)item));
CollectionView.Filter = yourCostumFilter;
DataGrid.ItemsSource = CollectionView;
}
@@ -30,16 +30,21 @@ namespace mpvInputEdit
private void SearchTextBox_TextChanged(object sender, TextChangedEventArgs e)
{
CollectionView.Refresh();
if (SearchControl.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>\n\nIf only one character is entered the search will be performed only in the input.", "Filtering", MessageBoxButton.OK, MessageBoxImage.Information);
}
bool Filter(InputItem item)
bool Filter(CommandItem item)
{
if (item.Command == "") return false;
string searchText = SearchControl.SearchTextBox.Text.ToLower();
if (searchText == "") return true;
if (searchText.StartsWith("i ") || searchText.StartsWith("i:"))
if (searchText.StartsWith("i ") || searchText.StartsWith("i:") || searchText.Length == 1)
{
searchText = searchText.Substring(2).Trim();
if (searchText.Length > 1)
searchText = searchText.Substring(2).Trim();
if (searchText.Length < 3)
return item.Input.ToLower().Replace("ctrl+", "").Replace("shift+", "").Replace("alt+", "").Contains(searchText);
@@ -47,11 +52,11 @@ namespace mpvInputEdit
return item.Input.ToLower().Contains(searchText);
}
else if (searchText.StartsWith("m ") || searchText.StartsWith("m:"))
return item.Menu.ToLower().Contains(searchText.Substring(2).Trim());
return item.Path.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.Path.ToLower().Contains(searchText) ||
item.Input.ToLower().Contains(searchText))
{
return true;
@@ -61,54 +66,51 @@ namespace mpvInputEdit
private void ButtonClick(object sender, RoutedEventArgs e)
{
InputItem item = ((Button)e.Source).DataContext as InputItem;
CommandItem item = ((Button)e.Source).DataContext as CommandItem;
if (item is null) return;
InputWindow w = new InputWindow();
LearnWindow w = new LearnWindow();
w.Owner = this;
w.InputItem = item;
w.ShowDialog();
var items = new Dictionary<string, InputItem>();
var items = new Dictionary<string, CommandItem>();
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);
foreach (CommandItem i in CommandItem.Items)
if (items.ContainsKey(i.Input) && i.Input != "")
MessageBox.Show($"Duplicate found:\n\n{i.Input}: {i.Path}\n\n{items[i.Input].Input}: {items[i.Input].Path}\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) => Keyboard.Focus(SearchControl.SearchTextBox);
private void Window_Closed(object sender, EventArgs e)
string GetInputConfContent()
{
var backupDir = Path.GetDirectoryName(App.InputConfPath) + "\\backup\\";
string text = Properties.Resources.inputConfHeader + "\r\n";
if (!Directory.Exists(backupDir))
Directory.CreateDirectory(backupDir);
if (File.Exists(App.InputConfPath))
File.Copy(App.InputConfPath, backupDir + "input conf " + DateTime.Now.ToString("yyyy-MM-dd HH-mm") + ".conf", true);
string text = "\r\n" + Properties.Settings.Default.input_conf_help + "\r\n\r\n";
foreach (InputItem item in App.InputItems)
foreach (CommandItem item in CommandItem.Items)
{
string line = " " + item.Input.PadRight(10);
string input = item.Input == "" ? "_" : item.Input;
string line = " " + input.PadRight(10);
if (item.Command.Trim() == "")
line += " ignore";
else
line += " " + item.Command.Trim();
if (item.Menu.Trim() != "")
line = line.PadRight(40) + " #menu: " + item.Menu;
if (item.Path.Trim() != "")
line = line.PadRight(40) + " #menu: " + item.Path;
text += line + "\r\n";
}
return text;
}
File.WriteAllText(App.InputConfPath, text);
MessageBox.Show("Changes will be available on next mpv(.net) startup.",
private void Window_Closed(object sender, EventArgs e)
{
if (InitialInputConfContent == GetInputConfContent()) return;
File.WriteAllText(mp.InputConfPath, GetInputConfContent());
MessageBox.Show("Changes will be available on next mpv.net startup.",
Title, MessageBoxButton.OK, MessageBoxImage.Information);
}
@@ -117,7 +119,7 @@ namespace mpvInputEdit
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)
if (MessageBox.Show($"Confirm to delete: {(grid.SelectedItem as CommandItem).Input} ({(grid.SelectedItem as CommandItem).Path})", "Confirm Delete", MessageBoxButton.OKCancel, MessageBoxImage.Question) != MessageBoxResult.OK)
e.Handled = true;
}
}

View File

@@ -1,4 +1,4 @@
<Window x:Class="mpvInputEdit.InputWindow"
<Window x:Class="mpvnet.LearnWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"

View File

@@ -1,20 +1,18 @@
using System;
using System.Diagnostics;
using System.Runtime.InteropServices;
using System.Windows;
using System.Windows.Input;
using System.Windows.Interop;
using WF = System.Windows.Forms;
namespace mpvInputEdit
namespace mpvnet
{
public partial class InputWindow : Window
public partial class LearnWindow : Window
{
string InputString = "";
public InputItem InputItem { get; set; }
public CommandItem InputItem { get; set; }
public string NewKey { get; set; } = "";
public InputWindow()
public LearnWindow()
{
InitializeComponent();
}
@@ -32,22 +30,21 @@ namespace mpvInputEdit
void OnKeyUp(WF.KeyEventArgs e)
{
if (e.KeyCode == WF.Keys.None) return;
char c = Convert.ToChar(e.KeyCode);
string text = InputString;
if (e.KeyCode == WF.Keys.ControlKey || e.KeyCode == WF.Keys.ShiftKey ||
e.KeyCode == WF.Keys.Menu)
{
return;
}
e.KeyCode == WF.Keys.Menu || e.KeyCode == WF.Keys.None)
if (text == "")
{
text = e.KeyCode.ToString();
if (text.Length == 1)
text = text.ToLowerInvariant();
}
return;
string text = "";
uint charValue = MapVirtualKey((uint)e.KeyCode, 2);
if (charValue == 0 || (charValue & 1 << 31) == 1 << 31)
text = e.KeyCode.ToString().Trim();
else
try {
text = Convert.ToChar(charValue).ToString().ToLower().Trim();
}
catch {}
for (int i = 0; i < 13; i++)
if ("D" + i.ToString() == text)
@@ -90,14 +87,6 @@ namespace mpvInputEdit
text = "Esc"; break;
case WF.Keys.PrintScreen:
text = "Print"; break;
case WF.Keys.Right:
text = "Right"; break;
case WF.Keys.Left:
text = "Left"; break;
case WF.Keys.Up:
text = "Up"; break;
case WF.Keys.Down:
text = "Down"; break;
case WF.Keys.Play:
text = "Play"; break;
case WF.Keys.Pause:
@@ -130,20 +119,24 @@ namespace mpvInputEdit
text = "Cancel"; break;
}
if (text == "#")
text = "Sharp";
bool shiftWasHandled = false;
bool isAlt = GetKeyState(18) < (short)0;
bool isAlt = GetKeyState(18) < (short)0;
bool isShift = GetKeyState(16) < (short)0;
bool isCtrl = GetKeyState(17) < (short)0;
bool isCtrl = GetKeyState(17) < (short)0;
if (!(isAlt && isCtrl && !isShift) && !(isShift && !isAlt && !isCtrl && !int.TryParse(text.Replace("F", ""), out int value)))
if (text.Length == 1 && isShift && text[0] != GetModifiedKey(text[0]))
{
if (isAlt) text = "Alt+" + text;
if (isShift) text = "Shift+" + text;
if (isCtrl) text = "Ctrl+" + text;
text = GetModifiedKey(text[0]).ToString();
shiftWasHandled = true;
}
if (text == "#") text = "Sharp";
if (isAlt) text = "Alt+" + text;
if (isShift && !shiftWasHandled) text = "Shift+" + text;
if (isCtrl) text = "Ctrl+" + text;
if (!string.IsNullOrEmpty(text))
SetKey(text);
}
@@ -151,17 +144,12 @@ namespace mpvInputEdit
void SetKey(string key)
{
NewKey = key;
MenuLabel.Content = InputItem.Menu;
MenuLabel.Content = InputItem.Path;
KeyLabel.Content = key;
}
void OnKeyPress(WF.KeyPressEventArgs e)
{
if (char.IsControl(e.KeyChar))
InputString = "";
else
InputString = e.KeyChar.ToString();
}
[DllImport("user32.dll")]
static extern uint MapVirtualKey(uint uCode, uint uMapType);
public static WF.Keys ModifierKeys {
get {
@@ -176,80 +164,78 @@ namespace mpvInputEdit
}
}
public static char GetModifiedKey(char c)
{
short vkKeyScanResult = VkKeyScan(c);
if (vkKeyScanResult == -1)
return c;
uint code = (uint)vkKeyScanResult & 0xff;
byte[] b = new byte[256];
b[0x10] = 0x80;
uint r;
if (1 != ToAscii(code, code, b, out r, 0))
return c;
return (char)r;
}
void ProcessKeyEventArgs(ref WF.Message m)
{
int WM_CHAR = 258, WM_SYSCHAR = 262, /*WM_KEYDOWN = 256, WM_SYSKEYDOWN = 260,*/
WM_KEYUP = 0x0101, WM_SYSKEYUP = 0x0105, WM_APPCOMMAND = 0x0319;
int WM_KEYUP = 0x0101, WM_SYSKEYUP = 0x0105, WM_APPCOMMAND = 0x0319;
IntPtr newWParam = IntPtr.Zero;
WF.KeyEventArgs ke = null;
WF.KeyPressEventArgs kpe = null;
if (m.Msg == WM_CHAR || m.Msg == WM_SYSCHAR)
if (m.Msg == WM_KEYUP || m.Msg == WM_SYSKEYUP)
OnKeyUp(new WF.KeyEventArgs((WF.Keys)(unchecked((int)(long)m.WParam)) | ModifierKeys));
else if (m.Msg == WM_APPCOMMAND)
{
kpe = new WF.KeyPressEventArgs(unchecked((char)(long)m.WParam));
OnKeyPress(kpe);
newWParam = (IntPtr)kpe.KeyChar;
}
else
{
ke = new WF.KeyEventArgs((WF.Keys)(unchecked((int)(long)m.WParam)) | ModifierKeys);
if (m.Msg == WM_KEYUP || m.Msg == WM_SYSKEYUP)
OnKeyUp(ke);
if (m.Msg == WM_APPCOMMAND)
switch ((AppCommand)(m.LParam.ToInt32() >> 16))
{
switch ((AppCommand)(m.LParam.ToInt32() >> 16))
{
case AppCommand.MEDIA_CHANNEL_DOWN:
SetKey("Channel_Down");
break;
case AppCommand.MEDIA_CHANNEL_UP:
SetKey("Channel_Up");
break;
case AppCommand.MEDIA_FAST_FORWARD:
SetKey("Forward");
break;
case AppCommand.MEDIA_REWIND:
SetKey("Rewind");
break;
case AppCommand.MEDIA_PAUSE:
SetKey("Pause");
break;
case AppCommand.MEDIA_PLAY:
SetKey("Play");
break;
case AppCommand.MEDIA_PLAY_PAUSE:
SetKey("PlayPause");
break;
case AppCommand.MEDIA_NEXTTRACK:
SetKey("Next");
break;
case AppCommand.MEDIA_PREVIOUSTRACK:
SetKey("Prev");
break;
case AppCommand.MEDIA_RECORD:
SetKey("Record");
break;
case AppCommand.MEDIA_STOP:
SetKey("Stop");
break;
case AppCommand.VolumeUp:
SetKey("Volume_Up");
break;
case AppCommand.VolumeDown:
SetKey("Volume_Down");
break;
case AppCommand.VolumeMute:
SetKey("Mute");
break;
}
case AppCommand.MEDIA_CHANNEL_DOWN:
SetKey("Channel_Down");
break;
case AppCommand.MEDIA_CHANNEL_UP:
SetKey("Channel_Up");
break;
case AppCommand.MEDIA_FAST_FORWARD:
SetKey("Forward");
break;
case AppCommand.MEDIA_REWIND:
SetKey("Rewind");
break;
case AppCommand.MEDIA_PAUSE:
SetKey("Pause");
break;
case AppCommand.MEDIA_PLAY:
SetKey("Play");
break;
case AppCommand.MEDIA_PLAY_PAUSE:
SetKey("PlayPause");
break;
case AppCommand.MEDIA_NEXTTRACK:
SetKey("Next");
break;
case AppCommand.MEDIA_PREVIOUSTRACK:
SetKey("Prev");
break;
case AppCommand.MEDIA_RECORD:
SetKey("Record");
break;
case AppCommand.MEDIA_STOP:
SetKey("Stop");
break;
case AppCommand.VolumeUp:
SetKey("Volume_Up");
break;
case AppCommand.VolumeDown:
SetKey("Volume_Down");
break;
case AppCommand.VolumeMute:
SetKey("Mute");
break;
}
}
if (kpe != null)
m.WParam = newWParam;
}
internal enum AppCommand
@@ -273,6 +259,16 @@ namespace mpvInputEdit
[DllImport("user32.dll", CharSet = CharSet.Auto)]
public static extern short GetKeyState(int keyCode);
[DllImport("user32.dll")]
static extern short VkKeyScan(char c);
[DllImport("user32.dll", SetLastError = true)]
static extern int ToAscii(uint uVirtKey,
uint uScanCode,
byte[] lpKeyState,
out uint lpChar,
uint flags);
private void Window_Loaded(object sender, RoutedEventArgs e)
{
HwndSource source = HwndSource.FromHwnd(new WindowInteropHelper(this).Handle);

View File

@@ -10,7 +10,9 @@ using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;
using VBNET;
using Sys;
using static mpvnet.libmpv;
using static mpvnet.Native;
@@ -52,18 +54,64 @@ namespace mpvnet
public static event Action QueueOverflow; // MPV_EVENT_QUEUE_OVERFLOW
public static event Action Hook; // MPV_EVENT_HOOK
public static IntPtr MpvHandle;
public static IntPtr MpvWindowHandle;
public static Addon Addon;
public static List<KeyValuePair<string, Action<bool>>> BoolPropChangeActions = new List<KeyValuePair<string, Action<bool>>>();
public static Size VideoSize = new Size(1920, 1080);
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 mpvConfPath = Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData) + "\\mpv\\mpv.conf";
public static List<PythonScript> PythonScripts => new List<PythonScript>();
public static AutoResetEvent AutoResetEvent = new AutoResetEvent(false);
public static IntPtr MpvHandle { get; set; }
public static IntPtr MpvWindowHandle { get; set; }
public static Addon Addon { get; set; }
public static List<KeyValuePair<string, Action<bool>>> BoolPropChangeActions { get; set; } = new List<KeyValuePair<string, Action<bool>>>();
public static List<KeyValuePair<string, Action<int>>> IntPropChangeActions { get; set; } = new List<KeyValuePair<string, Action<int>>>();
public static List<KeyValuePair<string, Action<string>>> StringPropChangeActions { get; set; } = new List<KeyValuePair<string, Action<string>>>();
public static Size VideoSize { get; set; } = new Size(1920, 1080);
public static List<PythonScript> PythonScripts { get; set; } = new List<PythonScript>();
public static AutoResetEvent AutoResetEvent { get; set; } = new AutoResetEvent(false);
public static List<MediaTrack> MediaTracks { get; set; } = new List<MediaTrack>();
public static List<KeyValuePair<string, double>> Chapters { get; set; } = new List<KeyValuePair<string, double>>();
private static Dictionary<string, string> _mpvConf;
public static string InputConfPath { get; } = MpvConfFolder + "\\input.conf";
public static string MpvConfPath { get; } = MpvConfFolder + "\\mpv.conf";
public static string MpvNetConfPath { get; } = MpvConfFolder + "\\mpvnet.conf";
static string _MpvConfFolder;
public static string MpvConfFolder {
get {
if (_MpvConfFolder == null)
{
string portableFolder = Application.StartupPath + "\\portable_config\\";
string appdataFolder = Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData) + "\\mpv\\";
if (!Directory.Exists(appdataFolder) && !Directory.Exists(portableFolder) &&
Sys.IsDirectoryWritable(Application.StartupPath))
{
using (TaskDialog<string> td = new TaskDialog<string>())
{
td.MainInstruction = "Choose a settings folder.";
td.Content = "[https://mpv.io/manual/master/#files-on-windows MPV documentation about files on Windows.]";
td.AddCommandLink("appdata", appdataFolder, appdataFolder);
td.AddCommandLink("portable", portableFolder, portableFolder);
td.AllowCancel = false;
_MpvConfFolder = td.Show();
}
}
else
if (Directory.Exists(portableFolder))
_MpvConfFolder = portableFolder;
else
_MpvConfFolder = appdataFolder;
if (string.IsNullOrEmpty(_MpvConfFolder)) _MpvConfFolder = appdataFolder;
if (!Directory.Exists(_MpvConfFolder)) Directory.CreateDirectory(_MpvConfFolder);
if (!File.Exists(_MpvConfFolder + "\\input.conf"))
File.WriteAllText(_MpvConfFolder + "\\input.conf", Properties.Resources.inputConf);
if (!File.Exists(_MpvConfFolder + "\\mpv.conf"))
File.WriteAllText(_MpvConfFolder + "\\mpv.conf", Properties.Resources.mpvConf);
}
return _MpvConfFolder;
}
}
static Dictionary<string, string> _mpvConf;
public static Dictionary<string, string> mpvConf {
get {
@@ -71,8 +119,8 @@ namespace mpvnet
{
_mpvConf = new Dictionary<string, string>();
if (File.Exists(mpvConfPath))
foreach (var i in File.ReadAllLines(mpvConfPath))
if (File.Exists(MpvConfPath))
foreach (var i in File.ReadAllLines(MpvConfPath))
if (i.Contains("=") && ! i.StartsWith("#"))
_mpvConf[i.Substring(0, i.IndexOf("=")).Trim()] = i.Substring(i.IndexOf("=") + 1).Trim();
}
@@ -80,17 +128,26 @@ namespace mpvnet
}
}
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()
{
if (!Directory.Exists(mp.mpvConfFolderPath))
Directory.CreateDirectory(mp.mpvConfFolderPath);
if (!File.Exists(mp.mpvConfPath))
File.WriteAllText(mp.mpvConfPath, Properties.Resources.mpv_conf);
if (!File.Exists(mp.InputConfPath))
File.WriteAllText(mp.InputConfPath, Properties.Resources.input_conf);
string dummy = MpvConfFolder;
LoadLibrary("mpv-1.dll");
MpvHandle = mpv_create();
set_property_string("input-default-bindings", "yes");
@@ -123,11 +180,12 @@ namespace mpvnet
if (Path.GetExtension(scriptPath) == ".ps1")
PowerShellScript.Init(scriptPath);
foreach (var scriptPath in Directory.GetFiles(mp.mpvConfFolderPath + "Scripts"))
if (Path.GetExtension(scriptPath) == ".py")
PythonScripts.Add(new PythonScript(File.ReadAllText(scriptPath)));
else if (Path.GetExtension(scriptPath) == ".ps1")
PowerShellScript.Init(scriptPath);
if (Directory.Exists(mp.MpvConfFolder + "Scripts"))
foreach (var scriptPath in Directory.GetFiles(mp.MpvConfFolder + "Scripts"))
if (Path.GetExtension(scriptPath) == ".py")
PythonScripts.Add(new PythonScript(File.ReadAllText(scriptPath)));
else if (Path.GetExtension(scriptPath) == ".ps1")
PowerShellScript.Init(scriptPath);
}
public static void EventLoop()
@@ -148,6 +206,7 @@ namespace mpvnet
{
case mpv_event_id.MPV_EVENT_SHUTDOWN:
Shutdown?.Invoke();
WriteHistory(null);
AutoResetEvent.Set();
return;
case mpv_event_id.MPV_EVENT_LOG_MESSAGE:
@@ -172,6 +231,7 @@ namespace mpvnet
case mpv_event_id.MPV_EVENT_FILE_LOADED:
FileLoaded?.Invoke();
LoadFolder();
WriteHistory(mp.get_property_string("path"));
break;
case mpv_event_id.MPV_EVENT_TRACKS_CHANGED:
TracksChanged?.Invoke();
@@ -195,32 +255,33 @@ namespace mpvnet
ScriptInputDispatch?.Invoke();
break;
case mpv_event_id.MPV_EVENT_CLIENT_MESSAGE:
if (ClientMessage != null)
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);
if (args != null && args.Length > 1 && args[0] == "mpv.net")
{
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);
bool found = false;
if (args != null && args.Length > 1 && args[0] == "mpv.net")
foreach (var i in mpvnet.Command.Commands)
{
bool found = false;
foreach (var i in mpvnet.Command.Commands)
if (args[1] == i.Name)
{
if (args[1] == i.Name)
{
found = true;
i.Action.Invoke(args.Skip(2).ToArray());
}
}
if (!found)
{
List<string> names = mpvnet.Command.Commands.Select((item) => item.Name).ToList();
names.Sort();
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].");
found = true;
i.Action.Invoke(args.Skip(2).ToArray());
MainForm.Instance.BeginInvoke(new Action(() => {
Message m = new Message() { Msg = 0x0202 }; // WM_LBUTTONUP
Native.SendMessage(MainForm.Instance.Handle, m.Msg, m.WParam, m.LParam);
}));
}
}
ClientMessage?.Invoke(args);
if (!found)
{
List<string> names = mpvnet.Command.Commands.Select((item) => item.Name).ToList();
names.Sort();
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/inputConf.txt default input bindings and menu definition].");
}
}
ClientMessage?.Invoke(args);
break;
case mpv_event_id.MPV_EVENT_VIDEO_RECONFIG:
VideoReconfig?.Invoke();
@@ -235,22 +296,34 @@ namespace mpvnet
Seek?.Invoke();
break;
case mpv_event_id.MPV_EVENT_PROPERTY_CHANGE:
var event_propertyData = (mpv_event_property)Marshal.PtrToStructure(evt.data, typeof(mpv_event_property));
var propData = (mpv_event_property)Marshal.PtrToStructure(evt.data, typeof(mpv_event_property));
if (event_propertyData.format == mpv_format.MPV_FORMAT_FLAG)
if (propData.format == mpv_format.MPV_FORMAT_FLAG)
foreach (var i in BoolPropChangeActions)
if (i.Key== event_propertyData.name)
i.Value.Invoke(Marshal.PtrToStructure<int>(event_propertyData.data) == 1);
if (i.Key== propData.name)
i.Value.Invoke(Marshal.PtrToStructure<int>(propData.data) == 1);
if (propData.format == mpv_format.MPV_FORMAT_STRING)
foreach (var i in StringPropChangeActions)
if (i.Key == propData.name)
i.Value.Invoke(StringFromNativeUtf8(Marshal.PtrToStructure<IntPtr>(propData.data)));
if (propData.format == mpv_format.MPV_FORMAT_INT64)
foreach (var i in IntPropChangeActions)
if (i.Key == propData.name)
i.Value.Invoke(Marshal.PtrToStructure<int>(propData.data));
break;
case mpv_event_id.MPV_EVENT_PLAYBACK_RESTART:
PlaybackRestart?.Invoke();
Size s = new Size(get_property_int("dwidth"), get_property_int("dheight"));
Size vidSize = new Size(get_property_int("dwidth"), get_property_int("dheight"));
if (VideoSize != s && s != Size.Empty)
if (VideoSize != vidSize && vidSize != Size.Empty)
{
VideoSize = s;
VideoSize = vidSize;
VideoSizeChanged?.Invoke();
}
Task.Run(new Action(() => ReadMetaData()));
break;
case mpv_event_id.MPV_EVENT_CHAPTER_CHANGE:
ChapterChange?.Invoke();
@@ -270,7 +343,7 @@ namespace mpvnet
}
}
private static List<PythonEventObject> PythonEventObjects = new List<PythonEventObject>();
static List<PythonEventObject> PythonEventObjects = new List<PythonEventObject>();
public static void register_event(string name, PyRT.PythonFunction pyFunc)
{
@@ -360,7 +433,7 @@ namespace mpvnet
if (err < 0 && throwOnException)
throw new Exception($"{name}: {(mpv_error)err}");
var ret = StringFromNativeUtf8(lpBuffer);
string ret = StringFromNativeUtf8(lpBuffer);
mpv_free(lpBuffer);
return ret;
@@ -412,6 +485,16 @@ namespace mpvnet
throw new Exception($"{name}: {(mpv_error)err}");
}
public static void observe_property_int(string name, Action<int> action)
{
int err = mpv_observe_property(MpvHandle, (ulong)action.GetHashCode(), name, mpv_format.MPV_FORMAT_INT64);
if (err < 0)
throw new Exception($"{name}: {(mpv_error)err}");
else
IntPropChangeActions.Add(new KeyValuePair<string, Action<int>>(name, action));
}
public static void observe_property_bool(string name, Action<bool> action)
{
int err = mpv_observe_property(MpvHandle, (ulong)action.GetHashCode(), name, mpv_format.MPV_FORMAT_FLAG);
@@ -422,16 +505,14 @@ namespace mpvnet
BoolPropChangeActions.Add(new KeyValuePair<string, Action<bool>>(name, action));
}
public static void unobserve_property_bool(string name, Action<bool> action)
public static void observe_property_string(string name, Action<string> action)
{
foreach (var i in BoolPropChangeActions.ToArray())
if (i.Value == action)
BoolPropChangeActions.Remove(i);
int err = mpv_unobserve_property(MpvHandle, (ulong)action.GetHashCode());
int err = mpv_observe_property(MpvHandle, (ulong)action.GetHashCode(), name, mpv_format.MPV_FORMAT_STRING);
if (err < 0)
throw new Exception($"{name}: {(mpv_error)err}");
else
StringPropChangeActions.Add(new KeyValuePair<string, Action<string>>(name, action));
}
protected static void ProcessCommandLine()
@@ -486,9 +567,9 @@ namespace mpvnet
mp.LoadFolder();
}
private static bool WasFolderLoaded;
static bool WasFolderLoaded;
public static void LoadFolder()
static void LoadFolder()
{
if (WasFolderLoaded)
return;
@@ -514,7 +595,7 @@ namespace mpvnet
WasFolderLoaded = true;
}
public static IntPtr AllocateUtf8IntPtrArrayWithSentinel(string[] arr, out IntPtr[] byteArrayPointers)
static IntPtr AllocateUtf8IntPtrArrayWithSentinel(string[] arr, out IntPtr[] byteArrayPointers)
{
int numberOfStrings = arr.Length + 1; // add extra element for extra null pointer last (sentinel)
byteArrayPointers = new IntPtr[numberOfStrings];
@@ -532,7 +613,7 @@ namespace mpvnet
return rootPointer;
}
public static string[] NativeUtf8StrArray2ManagedStrArray(IntPtr pUnmanagedStringArray, int StringCount)
static string[] NativeUtf8StrArray2ManagedStrArray(IntPtr pUnmanagedStringArray, int StringCount)
{
IntPtr[] pIntPtrArray = new IntPtr[StringCount];
string[] ManagedStringArray = new string[StringCount];
@@ -544,7 +625,7 @@ namespace mpvnet
return ManagedStringArray;
}
public static string StringFromNativeUtf8(IntPtr nativeUtf8)
static string StringFromNativeUtf8(IntPtr nativeUtf8)
{
int len = 0;
while (Marshal.ReadByte(nativeUtf8, len) != 0) ++len;
@@ -553,7 +634,124 @@ namespace mpvnet
return Encoding.UTF8.GetString(buffer);
}
public static byte[] GetUtf8Bytes(string s) => Encoding.UTF8.GetBytes(s + "\0");
static byte[] GetUtf8Bytes(string s) => Encoding.UTF8.GetBytes(s + "\0");
static string LastHistoryPath;
static DateTime LastHistoryStartDateTime;
static void WriteHistory(string filePath)
{
int totalMinutes = Convert.ToInt32((DateTime.Now - LastHistoryStartDateTime).TotalMinutes);
if (File.Exists(LastHistoryPath) && totalMinutes > 1)
{
string historyFilepath = mp.MpvConfFolder + "history.txt";
File.AppendAllText(historyFilepath, DateTime.Now.ToString().Substring(0, 16) +
" " + totalMinutes.ToString().PadLeft(3) + " " +
Path.GetFileNameWithoutExtension(LastHistoryPath) + "\r\n");
}
LastHistoryPath = filePath;
LastHistoryStartDateTime = DateTime.Now;
}
static void ReadMetaData()
{
lock (MediaTracks)
{
MediaTracks.Clear();
using (MediaInfo mi = new MediaInfo(mp.get_property_string("path")))
{
int count = mi.GetCount(MediaInfoStreamKind.Video);
for (int i = 0; i < count; i++)
{
MediaTrack track = new MediaTrack();
Add(track, mi.GetVideo(i, "Format"));
Add(track, mi.GetVideo(i, "Format_Profile"));
Add(track, mi.GetVideo(i, "Width") + "x" + mi.GetVideo(i, "Height"));
Add(track, mi.GetVideo(i, "FrameRate") + " FPS");
Add(track, mi.GetVideo(i, "Language/String"));
Add(track, mi.GetVideo(i, "Forced") == "Yes" ? "Forced" : "");
Add(track, mi.GetVideo(i, "Default") == "Yes" ? "Default" : "");
Add(track, mi.GetVideo(i, "Title"));
track.Text = "V: " + track.Text.Trim(" ,".ToCharArray());
track.Type = "v";
track.ID = i + 1;
MediaTracks.Add(track);
}
count = mi.GetCount(MediaInfoStreamKind.Audio);
for (int i = 0; i < count; i++)
{
MediaTrack track = new MediaTrack();
Add(track, mi.GetAudio(i, "Language/String"));
Add(track, mi.GetAudio(i, "Format"));
Add(track, mi.GetAudio(i, "Format_Profile"));
Add(track, mi.GetAudio(i, "BitRate/String"));
Add(track, mi.GetAudio(i, "Channel(s)/String"));
Add(track, mi.GetAudio(i, "SamplingRate/String"));
Add(track, mi.GetAudio(i, "Forced") == "Yes" ? "Forced" : "");
Add(track, mi.GetAudio(i, "Default") == "Yes" ? "Default" : "");
Add(track, mi.GetAudio(i, "Title"));
track.Text = "A: " + track.Text.Trim(" ,".ToCharArray());
track.Type = "a";
track.ID = i + 1;
MediaTracks.Add(track);
}
count = mi.GetCount(MediaInfoStreamKind.Text);
for (int i = 0; i < count; i++)
{
MediaTrack track = new MediaTrack();
Add(track, mi.GetText(i, "Language/String"));
Add(track, mi.GetText(i, "Format"));
Add(track, mi.GetText(i, "Format_Profile"));
Add(track, mi.GetText(i, "Forced") == "Yes" ? "Forced" : "");
Add(track, mi.GetText(i, "Default") == "Yes" ? "Default" : "");
Add(track, mi.GetText(i, "Title"));
track.Text = "S: " + track.Text.Trim(" ,".ToCharArray());
track.Type = "s";
track.ID = i + 1;
MediaTracks.Add(track);
}
count = get_property_int("edition-list/count");
for (int i = 0; i < count; i++)
{
MediaTrack track = new MediaTrack();
track.Text = "E: " + get_property_string($"edition-list/{i}/title");
track.Type = "e";
track.ID = i;
MediaTracks.Add(track);
}
void Add(MediaTrack track, string val)
{
if (!string.IsNullOrEmpty(val) && !(track.Text != null && track.Text.Contains(val)))
track.Text += " " + val + ",";
}
}
}
lock (Chapters)
{
Chapters.Clear();
int count = get_property_int("chapter-list/count");
for (int x = 0; x < count; x++)
{
string text = get_property_string($"chapter-list/{x}/title");
double time = get_property_number($"chapter-list/{x}/time");
Chapters.Add(new KeyValuePair<string, double>(text, time));
}
}
}
}
public enum EndFileEventMode

View File

@@ -120,6 +120,8 @@
<HintPath>IronPython\Microsoft.Scripting.dll</HintPath>
</Reference>
<Reference Include="Microsoft.VisualBasic" />
<Reference Include="PresentationCore" />
<Reference Include="PresentationFramework" />
<Reference Include="System" />
<Reference Include="System.ComponentModel.Composition" />
<Reference Include="System.Core" />
@@ -129,20 +131,49 @@
<HintPath>..\packages\Microsoft.PowerShell.5.ReferenceAssemblies.1.1.0\lib\net4\System.Management.Automation.dll</HintPath>
</Reference>
<Reference Include="System.Windows.Forms" />
<Reference Include="System.Xaml" />
<Reference Include="System.Xml" />
<Reference Include="WindowsBase" />
</ItemGroup>
<ItemGroup>
<Compile Include="Addon.cs" />
<Page Include="Controls\SearchTextBoxUserControl.xaml">
<Generator>MSBuild:Compile</Generator>
<SubType>Designer</SubType>
</Page>
<Page Include="Windows\AboutWindow.xaml">
<Generator>MSBuild:Compile</Generator>
<SubType>Designer</SubType>
</Page>
<Page Include="Windows\CommandPaletteWindow.xaml">
<Generator>MSBuild:Compile</Generator>
<SubType>Designer</SubType>
</Page>
<Page Include="WPF\Resources.xaml">
<SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator>
</Page>
<Compile Include="Controls\SearchTextBoxUserControl.xaml.cs">
<DependentUpon>SearchTextBoxUserControl.xaml</DependentUpon>
</Compile>
<Compile Include="DynamicGUI\DynamicGUI.cs" />
<Compile Include="DynamicGUI\OptionSettingControl.xaml.cs">
<DependentUpon>OptionSettingControl.xaml</DependentUpon>
</Compile>
<Compile Include="DynamicGUI\StringSettingControl.xaml.cs">
<DependentUpon>StringSettingControl.xaml</DependentUpon>
</Compile>
<Compile Include="DynamicGUI\Tommy.cs" />
<Compile Include="MediaInfo.cs" />
<Compile Include="Menu.cs">
<SubType>Component</SubType>
</Compile>
<Compile Include="PowerShellScript.cs" />
<Compile Include="Properties\Resources.Designer.cs">
<AutoGen>True</AutoGen>
<DesignTime>True</DesignTime>
<DependentUpon>Resources.resx</DependentUpon>
</Compile>
<Compile Include="PowerShellScript.cs" />
<Compile Include="PythonScript.cs" />
<Compile Include="libmpv.cs" />
<Compile Include="MainForm.cs">
@@ -158,8 +189,24 @@
<Compile Include="NativeHelp.cs" />
<Compile Include="Program.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="Sys\TaskDialog.cs" />
<Compile Include="Windows\CommandPaletteWindow.xaml.cs">
<DependentUpon>CommandPaletteWindow.xaml</DependentUpon>
</Compile>
<Compile Include="Windows\ConfWindow.xaml.cs">
<DependentUpon>ConfWindow.xaml</DependentUpon>
</Compile>
<Compile Include="Windows\AboutWindow.xaml.cs">
<DependentUpon>AboutWindow.xaml</DependentUpon>
</Compile>
<Compile Include="Windows\LearnWindow.xaml.cs">
<DependentUpon>LearnWindow.xaml</DependentUpon>
</Compile>
<Compile Include="Windows\InputWindow.xaml.cs">
<DependentUpon>InputWindow.xaml</DependentUpon>
</Compile>
<Compile Include="trash.cs" />
<Compile Include="UI.cs" />
<Compile Include="WPF\WPF.cs" />
<EmbeddedResource Include="MainForm.resx">
<DependentUpon>MainForm.cs</DependentUpon>
<SubType>Designer</SubType>
@@ -171,6 +218,7 @@
</EmbeddedResource>
<None Include="..\README.md">
<Link>README.md</Link>
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Include="app.manifest" />
<None Include="packages.config" />
@@ -183,21 +231,44 @@
<DependentUpon>Settings.settings</DependentUpon>
<DesignTimeSharedInput>True</DesignTimeSharedInput>
</Compile>
<Content Include="Resources\mpv.conf.txt" />
<Content Include="..\LICENSE.txt">
<Link>LICENSE.txt</Link>
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
<Content Include="Resources\mpvConf.txt" />
<Content Include="Resources\mpvConfToml.txt" />
<Content Include="Resources\mpvNetConfToml.txt" />
</ItemGroup>
<ItemGroup>
<None Include="App.config" />
</ItemGroup>
<ItemGroup>
<Content Include="mpv.ico" />
<Content Include="Resources\inputConfHeader.txt" />
<Content Include="screenshot.jpg" />
<Content Include="Resources\input.conf.txt" />
<Content Include="Resources\inputConf.txt" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\VBNET\VBNET.vbproj">
<Project>{a1d11294-05bf-4d77-b008-aecf1aa93c9f}</Project>
<Name>VBNET</Name>
</ProjectReference>
<Page Include="DynamicGUI\OptionSettingControl.xaml">
<Generator>MSBuild:Compile</Generator>
<SubType>Designer</SubType>
</Page>
<Page Include="DynamicGUI\StringSettingControl.xaml">
<Generator>MSBuild:Compile</Generator>
<SubType>Designer</SubType>
</Page>
<Page Include="Windows\ConfWindow.xaml">
<Generator>MSBuild:Compile</Generator>
<SubType>Designer</SubType>
</Page>
<Page Include="Windows\LearnWindow.xaml">
<Generator>MSBuild:Compile</Generator>
<SubType>Designer</SubType>
</Page>
<Page Include="Windows\InputWindow.xaml">
<Generator>MSBuild:Compile</Generator>
<SubType>Designer</SubType>
</Page>
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.

View File

@@ -1,6 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<startup>
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.7.2"/>
</startup>
</configuration>

View File

@@ -1,8 +0,0 @@
using System.Windows;
namespace mpvConfEdit
{
public partial class App : Application
{
}
}

View File

@@ -1,18 +0,0 @@
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

@@ -1,10 +0,0 @@
MIT License
Copyright (c) 2017 stax76
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and ssociated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

View File

@@ -1,218 +0,0 @@
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
using DynamicGUI;
namespace mpvConfEdit
{
public partial class MainWindow : Window
{
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 MainWindow()
{
InitializeComponent();
DataContext = this;
Title = (Assembly.GetExecutingAssembly().GetCustomAttributes(typeof(AssemblyProductAttribute), true)[0] as AssemblyProductAttribute).Product + " " + Assembly.GetExecutingAssembly().GetName().Version.ToString();
SearchControl.SearchTextBox.TextChanged += SearchTextBox_TextChanged;
foreach (var setting in DynamicSettings)
{
if (!FilterStrings.Contains(setting.Filter))
FilterStrings.Add(setting.Filter);
foreach (var pair in mpvConf)
{
if (setting.Name == pair.Key || setting.Alias == pair.Key)
switch (setting)
{
case StringSetting s:
s.Value = pair.Value;
continue;
case OptionSetting s:
s.Value = pair.Value;
break;
}
}
switch (setting)
{
case StringSetting s:
var sc = new StringSettingControl(s);
sc.TitleTextBox.Foreground = Controls.Controls.ThemeBrush;
MainStackPanel.Children.Add(sc);
break;
case OptionSetting s:
var oc = new OptionSettingControl(s);
oc.TitleTextBox.Foreground = Controls.Controls.ThemeBrush;
MainStackPanel.Children.Add(oc);
break;
}
}
}
private Dictionary<string, string> _mpvConf;
public Dictionary<string, string> mpvConf {
get {
if (_mpvConf == null)
{
_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;
}
}
public ObservableCollection<string> FilterStrings { get; } = new ObservableCollection<string>();
protected override void OnClosed(EventArgs e)
{
base.OnClosed(e);
WriteToDisk();
}
void WriteToDisk()
{
foreach (var mpvSetting in DynamicSettings)
{
switch (mpvSetting)
{
case StringSetting s:
if ((s.Value ?? "") != s.Default || mpvConf.ContainsKey(s.Name) || mpvConf.ContainsKey(s.Alias ?? ""))
mpvConf[s.Name] = s.Value;
break;
case OptionSetting s:
if ((s.Value ?? "") != s.Default || mpvConf.ContainsKey(s.Name) || mpvConf.ContainsKey(s.Alias ?? ""))
mpvConf[s.Name] = s.Value;
break;
}
}
if (!File.Exists(mpvConfPath))
File.WriteAllText(mpvConfPath, "");
List<string> lines = File.ReadAllLines(mpvConfPath).ToList();
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));
MessageBox.Show("Changes will be available on next startup of mpv(.net).",
Title, MessageBoxButton.OK, MessageBoxImage.Information);
}
private void SearchTextBox_TextChanged(object sender, TextChangedEventArgs e)
{
string activeFilter = "";
foreach (var i in FilterStrings)
if (SearchControl.Text == i + ":")
activeFilter = i;
if (activeFilter == "")
{
foreach (UIElement i in MainStackPanel.Children)
if ((i as ISettingControl).Contains(SearchControl.Text))
i.Visibility = Visibility.Visible;
else
i.Visibility = Visibility.Collapsed;
FilterListBox.SelectedItem = null;
}
else
foreach (UIElement i in MainStackPanel.Children)
if ((i as ISettingControl).SettingBase.Filter == activeFilter)
i.Visibility = Visibility.Visible;
else
i.Visibility = Visibility.Collapsed;
MainScrollViewer.ScrollToTop();
}
private void MainWindow1_Loaded(object sender, RoutedEventArgs e)
{
Keyboard.Focus(SearchControl.SearchTextBox);
}
private void ListBox_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
if (e.AddedItems.Count > 0)
SearchControl.Text = e.AddedItems[0].ToString() + ":";
}
private void OpenSettingsTextBlock_MouseUp(object sender, MouseButtonEventArgs e)
{
Process.Start(Path.GetDirectoryName(mpvConfPath));
}
private void ShowManualTextBlock_MouseUp(object sender, MouseButtonEventArgs e)
{
Process.Start("https://mpv.io/manual/master/");
}
private void SupportTextBlock_MouseUp(object sender, MouseButtonEventArgs e)
{
Process.Start("https://github.com/stax76/mpv.net#Support");
}
private void ApplyTextBlock_MouseUp(object sender, MouseButtonEventArgs e)
{
WriteToDisk();
}
}
}

View File

@@ -1,55 +0,0 @@
using System.Reflection;
using System.Resources;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Windows;
// General Information about an assembly is controlled through the following
// set of attributes. Change these attribute values to modify the information
// associated with an assembly.
[assembly: AssemblyTitle("mpv(.net) conf edit")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("mpv(.net) conf edit")]
[assembly: AssemblyCopyright("Copyright © 2017 stax76")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
// Setting ComVisible to false makes the types in this assembly not visible
// to COM components. If you need to access a type in this assembly from
// COM, set the ComVisible attribute to true on that type.
[assembly: ComVisible(false)]
//In order to begin building localizable applications, set
//<UICulture>CultureYouAreCodingWith</UICulture> in your .csproj file
//inside a <PropertyGroup>. For example, if you are using US english
//in your source files, set the <UICulture> to en-US. Then uncomment
//the NeutralResourceLanguage attribute below. Update the "en-US" in
//the line below to match the UICulture setting in the project file.
//[assembly: NeutralResourcesLanguage("en-US", UltimateResourceFallbackLocation.Satellite)]
[assembly: ThemeInfo(
ResourceDictionaryLocation.None, //where theme specific resource dictionaries are located
//(used if a resource is not found in the page,
// or application resource dictionaries)
ResourceDictionaryLocation.SourceAssembly //where the generic resource dictionary is located
//(used if a resource is not found in the page,
// app, or any theme specific resource dictionaries)
)]
// 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.4.0.0")]
[assembly: AssemblyFileVersion("1.4.0.0")]

View File

@@ -1,63 +0,0 @@
//------------------------------------------------------------------------------
// <auto-generated>
// This code was generated by a tool.
// Runtime Version:4.0.30319.42000
//
// Changes to this file may cause incorrect behavior and will be lost if
// the code is regenerated.
// </auto-generated>
//------------------------------------------------------------------------------
namespace mpvConfEdit.Properties {
using System;
/// <summary>
/// A strongly-typed resource class, for looking up localized strings, etc.
/// </summary>
// This class was auto-generated by the StronglyTypedResourceBuilder
// class via a tool like ResGen or Visual Studio.
// To add or remove a member, edit your .ResX file then rerun ResGen
// with the /str option, or rebuild your VS project.
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "16.0.0.0")]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
internal class Resources {
private static global::System.Resources.ResourceManager resourceMan;
private static global::System.Globalization.CultureInfo resourceCulture;
[global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
internal Resources() {
}
/// <summary>
/// Returns the cached ResourceManager instance used by this class.
/// </summary>
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
internal static global::System.Resources.ResourceManager ResourceManager {
get {
if (object.ReferenceEquals(resourceMan, null)) {
global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("mpvConfEdit.Properties.Resources", typeof(Resources).Assembly);
resourceMan = temp;
}
return resourceMan;
}
}
/// <summary>
/// Overrides the current thread's CurrentUICulture property for all
/// resource lookups using this strongly typed resource class.
/// </summary>
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
internal static global::System.Globalization.CultureInfo Culture {
get {
return resourceCulture;
}
set {
resourceCulture = value;
}
}
}
}

View File

@@ -1,117 +0,0 @@
<?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>

View File

@@ -1,26 +0,0 @@
//------------------------------------------------------------------------------
// <auto-generated>
// This code was generated by a tool.
// Runtime Version:4.0.30319.42000
//
// Changes to this file may cause incorrect behavior and will be lost if
// the code is regenerated.
// </auto-generated>
//------------------------------------------------------------------------------
namespace mpvConfEdit.Properties {
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "16.0.0.0")]
internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase {
private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings())));
public static Settings Default {
get {
return defaultInstance;
}
}
}
}

View File

@@ -1,7 +0,0 @@
<?xml version='1.0' encoding='utf-8'?>
<SettingsFile xmlns="uri:settings" CurrentProfile="(Default)">
<Profiles>
<Profile Name="(Default)" />
</Profiles>
<Settings />
</SettingsFile>

View File

@@ -1,13 +0,0 @@
<UserControl x:Class="Controls.SearchTextBoxUserControl"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
mc:Ignorable="d"
d:DesignHeight="450" d:DesignWidth="800">
<Grid x:Name="SearchTextBoxUserControl1" Background="White">
<TextBlock x:Name="SearchTextBlock" Margin="5,2" Text="Find a setting" Foreground="LightSteelBlue" VerticalAlignment="Center" />
<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>
</Grid>
</UserControl>

View File

@@ -1,38 +0,0 @@
<?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>

Binary file not shown.

Before

Width:  |  Height:  |  Size: 264 KiB

View File

@@ -1,145 +0,0 @@
<?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>{C4FEAA45-001D-4DC8-8BFA-621527326D09}</ProjectGuid>
<OutputType>WinExe</OutputType>
<RootNamespace>mpvConfEdit</RootNamespace>
<AssemblyName>mpvConfEdit</AssemblyName>
<TargetFrameworkVersion>v4.7.2</TargetFrameworkVersion>
<FileAlignment>512</FileAlignment>
<ProjectTypeGuids>{60dc8134-eba5-43b8-bcc9-bb4bc16c2548};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids>
<WarningLevel>4</WarningLevel>
<AutoGenerateBindingRedirects>true</AutoGenerateBindingRedirects>
<Deterministic>true</Deterministic>
<TargetFrameworkProfile />
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<PlatformTarget>AnyCPU</PlatformTarget>
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>..\mpv.net\bin\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<LangVersion>8.0</LangVersion>
<NullableReferenceTypes>true</NullableReferenceTypes>
<NullableContextOptions>enable</NullableContextOptions>
<Prefer32Bit>false</Prefer32Bit>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<PlatformTarget>AnyCPU</PlatformTarget>
<DebugType>pdbonly</DebugType>
<Optimize>true</Optimize>
<OutputPath>..\mpv.net\bin\</OutputPath>
<DefineConstants>TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<Prefer32Bit>false</Prefer32Bit>
<LangVersion>8.0</LangVersion>
</PropertyGroup>
<PropertyGroup>
<ApplicationIcon>mpv.ico</ApplicationIcon>
</PropertyGroup>
<PropertyGroup>
<ApplicationManifest>app.manifest</ApplicationManifest>
</PropertyGroup>
<ItemGroup>
<Reference Include="System" />
<Reference Include="System.Data" />
<Reference Include="System.Windows.Forms" />
<Reference Include="System.Xml" />
<Reference Include="Microsoft.CSharp" />
<Reference Include="System.Core" />
<Reference Include="System.Xml.Linq" />
<Reference Include="System.Data.DataSetExtensions" />
<Reference Include="System.Net.Http" />
<Reference Include="System.Xaml">
<RequiredTargetFramework>4.0</RequiredTargetFramework>
</Reference>
<Reference Include="WindowsBase" />
<Reference Include="PresentationCore" />
<Reference Include="PresentationFramework" />
</ItemGroup>
<ItemGroup>
<ApplicationDefinition Include="App.xaml">
<Generator>MSBuild:Compile</Generator>
<SubType>Designer</SubType>
</ApplicationDefinition>
<Compile Include="Controls.cs" />
<Compile Include="DynamicGUI\DynamicGUI.cs" />
<Compile Include="DynamicGUI\OptionSettingControl.xaml.cs">
<DependentUpon>OptionSettingControl.xaml</DependentUpon>
</Compile>
<Compile Include="DynamicGUI\StringSettingControl.xaml.cs">
<DependentUpon>StringSettingControl.xaml</DependentUpon>
</Compile>
<Compile Include="DynamicGUI\Tommy.cs" />
<Compile Include="SearchTextBoxUserControl.xaml.cs">
<DependentUpon>SearchTextBoxUserControl.xaml</DependentUpon>
</Compile>
<Page Include="DynamicGUI\OptionSettingControl.xaml">
<SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator>
</Page>
<Page Include="DynamicGUI\StringSettingControl.xaml">
<SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator>
</Page>
<Page Include="MainWindow.xaml">
<Generator>MSBuild:Compile</Generator>
<SubType>Designer</SubType>
</Page>
<Compile Include="App.xaml.cs">
<DependentUpon>App.xaml</DependentUpon>
<SubType>Code</SubType>
</Compile>
<Compile Include="MainWindow.xaml.cs">
<DependentUpon>MainWindow.xaml</DependentUpon>
<SubType>Code</SubType>
</Compile>
<Page Include="SearchTextBoxUserControl.xaml">
<SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator>
</Page>
</ItemGroup>
<ItemGroup>
<Compile Include="Properties\AssemblyInfo.cs">
<SubType>Code</SubType>
</Compile>
<Compile Include="Properties\Resources.Designer.cs">
<AutoGen>True</AutoGen>
<DesignTime>True</DesignTime>
<DependentUpon>Resources.resx</DependentUpon>
</Compile>
<Compile Include="Properties\Settings.Designer.cs">
<AutoGen>True</AutoGen>
<DependentUpon>Settings.settings</DependentUpon>
<DesignTimeSharedInput>True</DesignTimeSharedInput>
</Compile>
<EmbeddedResource Include="Properties\Resources.resx">
<Generator>ResXFileCodeGenerator</Generator>
<LastGenOutput>Resources.Designer.cs</LastGenOutput>
</EmbeddedResource>
<None Include="app.manifest" />
<None Include="Properties\Settings.settings">
<Generator>SettingsSingleFileGenerator</Generator>
<LastGenOutput>Settings.Designer.cs</LastGenOutput>
</None>
</ItemGroup>
<ItemGroup>
<None Include="App.config" />
</ItemGroup>
<ItemGroup>
<None Include="mpvConfEdit.toml">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None>
</ItemGroup>
<ItemGroup>
<Resource Include="mpv.ico" />
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
</Project>

View File

@@ -1,25 +0,0 @@
Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 16
VisualStudioVersion = 16.0.28714.193
MinimumVisualStudioVersion = 10.0.40219.1
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "mpvConfEdit", "mpvConfEdit.csproj", "{C4FEAA45-001D-4DC8-8BFA-621527326D09}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Release|Any CPU = Release|Any CPU
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{C4FEAA45-001D-4DC8-8BFA-621527326D09}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{C4FEAA45-001D-4DC8-8BFA-621527326D09}.Debug|Any CPU.Build.0 = Debug|Any CPU
{C4FEAA45-001D-4DC8-8BFA-621527326D09}.Release|Any CPU.ActiveCfg = Release|Any CPU
{C4FEAA45-001D-4DC8-8BFA-621527326D09}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {959F2890-E1FC-47A2-856C-A42F8C955D15}
EndGlobalSection
EndGlobal

View File

@@ -1,41 +0,0 @@
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<configSections>
<sectionGroup name="userSettings" type="System.Configuration.UserSettingsGroup, System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" >
<section name="mpvInputEdit.Properties.Settings" type="System.Configuration.ClientSettingsSection, System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" allowExeDefinition="MachineToLocalUser" requirePermission="false" />
</sectionGroup>
</configSections>
<startup>
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.7.2" />
</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>

View File

@@ -1,42 +0,0 @@
<Application x:Class="mpvInputEdit.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:Controls="clr-namespace:Controls"
StartupUri="MainWindow.xaml">
<Application.Resources>
<Style TargetType="TextBox">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type TextBox}">
<Border x:Name="border" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" Background="{TemplateBinding Background}" SnapsToDevicePixels="True">
<ScrollViewer x:Name="PART_ContentHost" Focusable="false" HorizontalScrollBarVisibility="Hidden" VerticalScrollBarVisibility="Hidden"/>
</Border>
<ControlTemplate.Triggers>
<Trigger Property="IsEnabled" Value="false">
<Setter Property="Opacity" TargetName="border" Value="0.56"/>
</Trigger>
<Trigger Property="IsMouseOver" Value="true">
<Setter Property="BorderBrush" TargetName="border" Value="#FF7EB4EA"/>
</Trigger>
<Trigger Property="IsFocused" Value="true">
<Setter Property="BorderBrush" TargetName="border" Value="{x:Static Controls:Controls.ThemeBrush}"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<Style x:Key="DataGrid_Font_Centering"
TargetType="{x:Type DataGridCell}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type DataGridCell}">
<Grid Background="{TemplateBinding Background}">
<ContentPresenter VerticalAlignment="Center" />
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</Application.Resources>
</Application>

View File

@@ -1,56 +0,0 @@
using System;
using System.Collections.ObjectModel;
using System.IO;
using System.Windows;
namespace mpvInputEdit
{
public partial class App : Application
{
public static string InputConfPath { get; } = Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData) + "\\mpv\\input.conf";
private static ObservableCollection<InputItem> _InputItems;
public static ObservableCollection<InputItem> InputItems
{
get
{
if (_InputItems is null)
{
_InputItems = new ObservableCollection<InputItem>();
if (File.Exists(InputConfPath))
{
foreach (string line in File.ReadAllLines(InputConfPath))
{
string l = line.Trim();
if (l.StartsWith("#")) continue;
if (!l.Contains(" ")) continue;
InputItem item = new InputItem();
item.Input = l.Substring(0, l.IndexOf(" "));
if (item.Input == "") continue;
l = l.Substring(l.IndexOf(" ") + 1);
if (l.Contains("#menu:"))
{
item.Menu = l.Substring(l.IndexOf("#menu:") + 6).Trim();
l = l.Substring(0, l.IndexOf("#menu:"));
if (item.Menu.Contains(";"))
item.Menu = item.Menu.Substring(item.Menu.IndexOf(";") + 1).Trim();
}
item.Command = l.Trim();
if (item.Command == "")
continue;
if (item.Command.ToLower() == "ignore")
item.Command = "";
_InputItems.Add(item);
}
}
}
return _InputItems;
}
}
}
}

View File

@@ -1,18 +0,0 @@
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

@@ -1,10 +0,0 @@
MIT License
Copyright (c) 2017 stax76
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and ssociated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

View File

@@ -1,55 +0,0 @@
using System.Reflection;
using System.Resources;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Windows;
// General Information about an assembly is controlled through the following
// set of attributes. Change these attribute values to modify the information
// associated with an assembly.
[assembly: AssemblyTitle("mpv(.net) input edit")]
[assembly: AssemblyDescription("mpv(.net) key and mouse bindings editor")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("mpv(.net) input edit")]
[assembly: AssemblyCopyright("Copyright © 2017 stax76")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
// Setting ComVisible to false makes the types in this assembly not visible
// to COM components. If you need to access a type in this assembly from
// COM, set the ComVisible attribute to true on that type.
[assembly: ComVisible(false)]
//In order to begin building localizable applications, set
//<UICulture>CultureYouAreCodingWith</UICulture> in your .csproj file
//inside a <PropertyGroup>. For example, if you are using US english
//in your source files, set the <UICulture> to en-US. Then uncomment
//the NeutralResourceLanguage attribute below. Update the "en-US" in
//the line below to match the UICulture setting in the project file.
//[assembly: NeutralResourcesLanguage("en-US", UltimateResourceFallbackLocation.Satellite)]
[assembly: ThemeInfo(
ResourceDictionaryLocation.None, //where theme specific resource dictionaries are located
//(used if a resource is not found in the page,
// or application resource dictionaries)
ResourceDictionaryLocation.SourceAssembly //where the generic resource dictionary is located
//(used if a resource is not found in the page,
// app, or any theme specific resource dictionaries)
)]
// 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.3.0.0")]
[assembly: AssemblyFileVersion("1.3.0.0")]

View File

@@ -1,66 +0,0 @@
//------------------------------------------------------------------------------
// <auto-generated>
// This code was generated by a tool.
// Runtime Version:4.0.30319.42000
//
// Changes to this file may cause incorrect behavior and will be lost if
// the code is regenerated.
// </auto-generated>
//------------------------------------------------------------------------------
namespace mpvInputEdit.Properties
{
/// <summary>
/// A strongly-typed resource class, for looking up localized strings, etc.
/// </summary>
// This class was auto-generated by the StronglyTypedResourceBuilder
// class via a tool like ResGen or Visual Studio.
// To add or remove a member, edit your .ResX file then rerun ResGen
// with the /str option, or rebuild your VS project.
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
internal class Resources
{
private static global::System.Resources.ResourceManager resourceMan;
private static global::System.Globalization.CultureInfo resourceCulture;
[global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
internal Resources()
{
}
/// <summary>
/// Returns the cached ResourceManager instance used by this class.
/// </summary>
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
internal static global::System.Resources.ResourceManager ResourceManager {
get {
if ((resourceMan == null))
{
global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("mpvInputEdit.Properties.Resources", typeof(Resources).Assembly);
resourceMan = temp;
}
return resourceMan;
}
}
/// <summary>
/// Overrides the current thread's CurrentUICulture property for all
/// resource lookups using this strongly typed resource class.
/// </summary>
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
internal static global::System.Globalization.CultureInfo Culture {
get {
return resourceCulture;
}
set {
resourceCulture = value;
}
}
}
}

View File

@@ -1,117 +0,0 @@
<?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>

View File

@@ -1,61 +0,0 @@
//------------------------------------------------------------------------------
// <auto-generated>
// This code was generated by a tool.
// Runtime Version:4.0.30319.42000
//
// Changes to this file may cause incorrect behavior and will be lost if
// the code is regenerated.
// </auto-generated>
//------------------------------------------------------------------------------
namespace mpvInputEdit.Properties {
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "16.0.0.0")]
internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase {
private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings())));
public static Settings Default {
get {
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,32 +0,0 @@
<?xml version='1.0' encoding='utf-8'?>
<SettingsFile xmlns="http://schemas.microsoft.com/VisualStudio/2004/01/settings" CurrentProfile="(Default)" GeneratedClassNamespace="mpvInputEdit.Properties" GeneratedClassName="Settings">
<Profiles />
<Settings>
<Setting Name="input_conf_help" Type="System.String" Scope="User">
<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>

View File

@@ -1,13 +0,0 @@
<UserControl x:Class="Controls.SearchTextBoxUserControl"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
mc:Ignorable="d"
d:DesignHeight="450" d:DesignWidth="800">
<Grid x:Name="SearchTextBoxUserControl1" Background="White">
<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" />
<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>
</UserControl>

View File

@@ -1,35 +0,0 @@
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
namespace Controls
{
public partial class SearchTextBoxUserControl : UserControl
{
public SearchTextBoxUserControl()
{
InitializeComponent();
}
public string Text { get => SearchTextBox.Text; set => SearchTextBox.Text = value; }
private void SearchClearButton_Click(object sender, RoutedEventArgs e)
{
SearchTextBox.Text = "";
Keyboard.Focus(SearchTextBox);
}
private void SearchTextBox_TextChanged(object sender, TextChangedEventArgs e)
{
SearchHintTextBlock.Text = SearchTextBox.Text == "" ? "Type ? to get help." : "";
if (SearchTextBox.Text == "")
SearchClearButton.Visibility = Visibility.Hidden;
else
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);
}
}
}

View File

@@ -1,38 +0,0 @@
<?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

@@ -1,34 +0,0 @@
using System;
using System.ComponentModel;
using System.Runtime.CompilerServices;
using System.Runtime.Serialization;
namespace mpvInputEdit
{
[Serializable]
public class InputItem : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
public string Menu { get; set; } = "";
public string Command { get; set; } = "";
public InputItem() { }
public InputItem(SerializationInfo info, StreamingContext context) {}
private void NotifyPropertyChanged([CallerMemberName] string propertyName = "")
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
private string _Input = "";
public string Input {
get => _Input;
set {
_Input = value;
NotifyPropertyChanged();
}
}
}
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 264 KiB

View File

@@ -1,126 +0,0 @@
<?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>{635F8308-9F79-4BCC-B839-75FCEF8588AE}</ProjectGuid>
<OutputType>WinExe</OutputType>
<RootNamespace>mpvInputEdit</RootNamespace>
<AssemblyName>mpvInputEdit</AssemblyName>
<TargetFrameworkVersion>v4.7.2</TargetFrameworkVersion>
<FileAlignment>512</FileAlignment>
<ProjectTypeGuids>{60dc8134-eba5-43b8-bcc9-bb4bc16c2548};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids>
<WarningLevel>4</WarningLevel>
<AutoGenerateBindingRedirects>true</AutoGenerateBindingRedirects>
<Deterministic>true</Deterministic>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<PlatformTarget>AnyCPU</PlatformTarget>
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>..\mpv.net\bin\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<Prefer32Bit>false</Prefer32Bit>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<PlatformTarget>AnyCPU</PlatformTarget>
<DebugType>pdbonly</DebugType>
<Optimize>true</Optimize>
<OutputPath>..\mpv.net\bin\</OutputPath>
<DefineConstants>TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<PropertyGroup>
<ApplicationIcon>mpv.ico</ApplicationIcon>
</PropertyGroup>
<PropertyGroup>
<ApplicationManifest>app.manifest</ApplicationManifest>
</PropertyGroup>
<ItemGroup>
<Reference Include="System" />
<Reference Include="System.Data" />
<Reference Include="System.Windows.Forms" />
<Reference Include="System.Xml" />
<Reference Include="Microsoft.CSharp" />
<Reference Include="System.Core" />
<Reference Include="System.Xml.Linq" />
<Reference Include="System.Data.DataSetExtensions" />
<Reference Include="System.Net.Http" />
<Reference Include="System.Xaml">
<RequiredTargetFramework>4.0</RequiredTargetFramework>
</Reference>
<Reference Include="WindowsBase" />
<Reference Include="PresentationCore" />
<Reference Include="PresentationFramework" />
</ItemGroup>
<ItemGroup>
<ApplicationDefinition Include="App.xaml">
<Generator>MSBuild:Compile</Generator>
<SubType>Designer</SubType>
</ApplicationDefinition>
<Compile Include="Controls.cs" />
<Compile Include="SearchTextBoxUserControl.xaml.cs">
<DependentUpon>SearchTextBoxUserControl.xaml</DependentUpon>
</Compile>
<Page Include="InputWindow.xaml">
<SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator>
</Page>
<Page Include="MainWindow.xaml">
<Generator>MSBuild:Compile</Generator>
<SubType>Designer</SubType>
</Page>
<Compile Include="App.xaml.cs">
<DependentUpon>App.xaml</DependentUpon>
<SubType>Code</SubType>
</Compile>
<Compile Include="InputWindow.xaml.cs">
<DependentUpon>InputWindow.xaml</DependentUpon>
</Compile>
<Compile Include="MainWindow.xaml.cs">
<DependentUpon>MainWindow.xaml</DependentUpon>
<SubType>Code</SubType>
</Compile>
<Page Include="SearchTextBoxUserControl.xaml">
<Generator>MSBuild:Compile</Generator>
<SubType>Designer</SubType>
</Page>
</ItemGroup>
<ItemGroup>
<Compile Include="misc.cs" />
<Compile Include="Properties\AssemblyInfo.cs">
<SubType>Code</SubType>
</Compile>
<Compile Include="Properties\Resources.Designer.cs">
<AutoGen>True</AutoGen>
<DesignTime>True</DesignTime>
<DependentUpon>Resources.resx</DependentUpon>
</Compile>
<Compile Include="Properties\Settings.Designer.cs">
<AutoGen>True</AutoGen>
<DependentUpon>Settings.settings</DependentUpon>
<DesignTimeSharedInput>True</DesignTimeSharedInput>
</Compile>
<EmbeddedResource Include="Properties\Resources.resx">
<Generator>ResXFileCodeGenerator</Generator>
<LastGenOutput>Resources.Designer.cs</LastGenOutput>
</EmbeddedResource>
<None Include="app.manifest" />
<None Include="Properties\Settings.settings">
<Generator>SettingsSingleFileGenerator</Generator>
<LastGenOutput>Settings.Designer.cs</LastGenOutput>
</None>
</ItemGroup>
<ItemGroup>
<None Include="App.config" />
</ItemGroup>
<ItemGroup>
<Resource Include="mpv.ico" />
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
</Project>

View File

@@ -1,25 +0,0 @@
Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 16
VisualStudioVersion = 16.0.28721.148
MinimumVisualStudioVersion = 10.0.40219.1
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "mpvInputEdit", "mpvInputEdit.csproj", "{635F8308-9F79-4BCC-B839-75FCEF8588AE}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Release|Any CPU = Release|Any CPU
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{635F8308-9F79-4BCC-B839-75FCEF8588AE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{635F8308-9F79-4BCC-B839-75FCEF8588AE}.Debug|Any CPU.Build.0 = Debug|Any CPU
{635F8308-9F79-4BCC-B839-75FCEF8588AE}.Release|Any CPU.ActiveCfg = Release|Any CPU
{635F8308-9F79-4BCC-B839-75FCEF8588AE}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {492E8273-D465-496D-BA18-DC8CEC9EAD70}
EndGlobalSection
EndGlobal

7
release.ps1 Normal file
View File

@@ -0,0 +1,7 @@
$scriptDir = Split-Path -Path $PSCommandPath -Parent
$exePath = $scriptDir + "\mpv.net\bin\mpvnet.exe"
$version = [Diagnostics.FileVersionInfo]::GetVersionInfo($exePath).FileVersion
$desktopDir = [Environment]::GetFolderPath("Desktop")
$targetDir = $desktopDir + "\mpv.net-" + $version
Copy-Item $scriptDir\mpv.net\bin $targetDir -Recurse -Exclude System.Management.Automation.xml -Force
& "C:\Program Files\7-Zip\7z.exe" a -t7z -mx9 "$targetDir.7z" -r "$targetDir\*"

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 MiB

BIN
screenshots/ConfEditor.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 238 KiB

BIN
screenshots/InputEditor.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 277 KiB

BIN
screenshots/Main.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.9 MiB

BIN
screenshots/Menu.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 214 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 193 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 130 KiB

View File

@@ -1,16 +0,0 @@
using mpvnet;
class Script
{
public Script()
{
var fs = mp.get_property_string("fullscreen");
mp.commandv("show-text", "fullscreen: " + fs);
mp.observe_property_bool("fullscreen", FullscreenChange);
}
void FullscreenChange(bool val)
{
mp.commandv("show-text", "fullscreen: " + val.ToString());
}
}

View File

@@ -1,31 +0,0 @@
// when seeking displays position and
// duration like so: 70:00 / 80:00
// which is different from mpv which
// uses 01:10:00 / 01:20:00
function add_zero(val)
{
val = Math.round(val);
return val > 9 ? "" + val : "0" + val;
}
function format(val)
{
var sec = Math.round(val);
if (sec < 0)
sec = 0;
pos_min_floor = Math.floor(sec / 60);
sec_rest = sec - pos_min_floor * 60;
return add_zero(pos_min_floor) + ":" + add_zero(sec_rest);
}
function on_seek(_)
{
mp.commandv("show-text",
format(mp.get_property_number("time-pos")) + " / " +
format(mp.get_property_number("duration")));
}
mp.register_event("seek", on_seek);

View File

@@ -1,2 +0,0 @@
$position = [mp]::get_property_number("time-pos");
[mp]::commandv("show-text", $position.ToString() + " seconds")

Some files were not shown because too many files have changed in this diff Show More